feat: Add tools for open weather search and image generation using the Spark API. (#2845)

This commit is contained in:
Onelevenvy
2024-03-18 16:22:48 +08:00
committed by GitHub
parent 4502436c47
commit cb79a90031
13 changed files with 513 additions and 2 deletions

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.6547 16.7993C21.3111 18.0034 20.7384 19.0938 20.0054 20.048C18.9058 21.4111 15.1261 21.4111 12.8583 20.8204C10.4072 20.1616 8.6433 18.6395 8.50586 18.5259C9.46797 19.2756 10.6821 19.7072 12.0107 19.7072C15.1948 19.7072 17.7605 17.1174 17.7605 13.9368C17.7605 12.9826 17.5314 12.0966 17.119 11.3015C17.0961 11.2561 17.1419 11.2106 17.1649 11.2333C18.9745 11.5287 22.571 13.2098 21.6547 16.7993Z" fill="#2751D0"/>
<path d="M21.9994 12.7773C21.9994 12.8454 21.9306 12.8682 21.8848 12.8C21.0372 11.0053 19.5483 10.46 17.7615 10.0511C16.4099 9.75577 15.5166 9.3014 15.1271 9.09694C15.0355 9.0515 14.9668 8.98335 14.8751 8.93791C12.0575 7.23404 12.0117 4.30339 12.0117 4.30339V0.0550813C12.0117 0.00964486 12.0804 -0.0130733 12.1034 0.0096449L18.7694 6.50706L19.2734 6.98414C20.7394 8.52898 21.7474 10.5509 21.9994 12.7773Z" fill="#D82F20"/>
<path d="M20.0052 20.0462C18.1726 22.4316 15.2863 23.9992 12.0334 23.9992C6.48985 23.9992 2 19.501 2 13.9577C2 11.2543 3.05374 8.8234 4.7947 7.00594L5.29866 6.50614L9.65107 2.25783C9.69688 2.2124 9.7656 2.25783 9.7427 2.30327C9.67397 2.59861 9.55944 3.28015 9.62816 4.18888C9.71979 5.25664 10.0634 6.68789 11.0713 8.27817C11.6898 9.27777 12.5832 10.3228 13.8202 11.4133C13.9577 11.5496 14.118 11.6632 14.2784 11.7995C14.8281 12.3674 15.1488 13.1171 15.1488 13.9577C15.1488 15.6616 13.7515 17.0474 12.0563 17.0474C11.3233 17.0474 10.659 16.7975 10.1321 16.3659C10.0863 16.3204 10.1321 16.2523 10.1779 16.275C10.2925 16.2977 10.407 16.3204 10.5215 16.3204C11.1171 16.3204 11.6211 15.8433 11.6211 15.2299C11.6211 14.8665 11.4378 14.5257 11.163 14.3439C10.4299 13.7533 9.81142 13.1853 9.28455 12.6173C8.55151 11.8222 8.00174 11.0498 7.61231 10.3001C6.81055 11.2997 6.30659 12.5492 6.30659 13.935C6.30659 15.7979 7.17707 17.4563 8.55152 18.5014C8.68896 18.615 10.4528 20.1371 12.9039 20.7959C15.1259 21.432 18.9057 21.4093 20.0052 20.0462Z" fill="#69C5F4"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1,40 @@
import json
from core.tools.errors import ToolProviderCredentialValidationError
from core.tools.provider.builtin.spark.tools.spark_img_generation import spark_response
from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
class SparkProvider(BuiltinToolProviderController):
def _validate_credentials(self, credentials: dict) -> None:
try:
if "APPID" not in credentials or not credentials.get("APPID"):
raise ToolProviderCredentialValidationError("APPID is required.")
if "APISecret" not in credentials or not credentials.get("APISecret"):
raise ToolProviderCredentialValidationError("APISecret is required.")
if "APIKey" not in credentials or not credentials.get("APIKey"):
raise ToolProviderCredentialValidationError("APIKey is required.")
appid = credentials.get("APPID")
apisecret = credentials.get("APISecret")
apikey = credentials.get("APIKey")
prompt = "a cute black dog"
try:
response = spark_response(prompt, appid, apikey, apisecret)
data = json.loads(response)
code = data["header"]["code"]
if code == 0:
# 0 success
pass
else:
raise ToolProviderCredentialValidationError(
"image generate error, code:{}".format(code)
)
except Exception as e:
raise ToolProviderCredentialValidationError(
"APPID APISecret APIKey is invalid. {}".format(e)
)
except Exception as e:
raise ToolProviderCredentialValidationError(str(e))

View File

@@ -0,0 +1,59 @@
identity:
author: Onelevenvy
name: spark
label:
en_US: Spark
zh_Hans: 讯飞星火
pt_BR: Spark
description:
en_US: Spark Platform Toolkit
zh_Hans: 讯飞星火平台工具
pt_BR: Pacote de Ferramentas da Plataforma Spark
icon: icon.svg
credentials_for_provider:
APPID:
type: secret-input
required: true
label:
en_US: Spark APPID
zh_Hans: APPID
pt_BR: Spark APPID
help:
en_US: Please input your APPID
zh_Hans: 请输入你的 APPID
pt_BR: Please input your APPID
placeholder:
en_US: Please input your APPID
zh_Hans: 请输入你的 APPID
pt_BR: Please input your APPID
APISecret:
type: secret-input
required: true
label:
en_US: Spark APISecret
zh_Hans: APISecret
pt_BR: Spark APISecret
help:
en_US: Please input your Spark APISecret
zh_Hans: 请输入你的 APISecret
pt_BR: Please input your Spark APISecret
placeholder:
en_US: Please input your Spark APISecret
zh_Hans: 请输入你的 APISecret
pt_BR: Please input your Spark APISecret
APIKey:
type: secret-input
required: true
label:
en_US: Spark APIKey
zh_Hans: APIKey
pt_BR: Spark APIKey
help:
en_US: Please input your Spark APIKey
zh_Hans: 请输入你的 APIKey
pt_BR: Please input your Spark APIKey
placeholder:
en_US: Please input your Spark APIKey
zh_Hans: 请输入你的 APIKey
pt_BR: Please input Spark APIKey
url: https://console.xfyun.cn/services

View File

@@ -0,0 +1,154 @@
import base64
import hashlib
import hmac
import json
from base64 import b64decode
from datetime import datetime
from time import mktime
from typing import Any, Union
from urllib.parse import urlencode
from wsgiref.handlers import format_date_time
import requests
from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.tool.builtin_tool import BuiltinTool
class AssembleHeaderException(Exception):
def __init__(self, msg):
self.message = msg
class Url:
def __init__(this, host, path, schema):
this.host = host
this.path = path
this.schema = schema
# calculate sha256 and encode to base64
def sha256base64(data):
sha256 = hashlib.sha256()
sha256.update(data)
digest = base64.b64encode(sha256.digest()).decode(encoding="utf-8")
return digest
def parse_url(requset_url):
stidx = requset_url.index("://")
host = requset_url[stidx + 3 :]
schema = requset_url[: stidx + 3]
edidx = host.index("/")
if edidx <= 0:
raise AssembleHeaderException("invalid request url:" + requset_url)
path = host[edidx:]
host = host[:edidx]
u = Url(host, path, schema)
return u
def assemble_ws_auth_url(requset_url, method="GET", api_key="", api_secret=""):
u = parse_url(requset_url)
host = u.host
path = u.path
now = datetime.now()
date = format_date_time(mktime(now.timetuple()))
signature_origin = "host: {}\ndate: {}\n{} {} HTTP/1.1".format(
host, date, method, path
)
signature_sha = hmac.new(
api_secret.encode("utf-8"),
signature_origin.encode("utf-8"),
digestmod=hashlib.sha256,
).digest()
signature_sha = base64.b64encode(signature_sha).decode(encoding="utf-8")
authorization_origin = f'api_key="{api_key}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature_sha}"'
authorization = base64.b64encode(authorization_origin.encode("utf-8")).decode(
encoding="utf-8"
)
values = {"host": host, "date": date, "authorization": authorization}
return requset_url + "?" + urlencode(values)
def get_body(appid, text):
body = {
"header": {"app_id": appid, "uid": "123456789"},
"parameter": {
"chat": {"domain": "general", "temperature": 0.5, "max_tokens": 4096}
},
"payload": {"message": {"text": [{"role": "user", "content": text}]}},
}
return body
def spark_response(text, appid, apikey, apisecret):
host = "http://spark-api.cn-huabei-1.xf-yun.com/v2.1/tti"
url = assemble_ws_auth_url(
host, method="POST", api_key=apikey, api_secret=apisecret
)
content = get_body(appid, text)
response = requests.post(
url, json=content, headers={"content-type": "application/json"}
).text
return response
class SparkImgGeneratorTool(BuiltinTool):
def _invoke(
self,
user_id: str,
tool_parameters: dict[str, Any],
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
"""
invoke tools
"""
if "APPID" not in self.runtime.credentials or not self.runtime.credentials.get(
"APPID"
):
return self.create_text_message("APPID is required.")
if (
"APISecret" not in self.runtime.credentials
or not self.runtime.credentials.get("APISecret")
):
return self.create_text_message("APISecret is required.")
if (
"APIKey" not in self.runtime.credentials
or not self.runtime.credentials.get("APIKey")
):
return self.create_text_message("APIKey is required.")
prompt = tool_parameters.get("prompt", "")
if not prompt:
return self.create_text_message("Please input prompt")
res = self.img_generation(prompt)
result = []
for image in res:
result.append(
self.create_blob_message(
blob=b64decode(image["base64_image"]),
meta={"mime_type": "image/png"},
save_as=self.VARIABLE_KEY.IMAGE.value,
)
)
return result
def img_generation(self, prompt):
response = spark_response(
text=prompt,
appid=self.runtime.credentials.get("APPID"),
apikey=self.runtime.credentials.get("APIKey"),
apisecret=self.runtime.credentials.get("APISecret"),
)
data = json.loads(response)
code = data["header"]["code"]
if code != 0:
return self.create_text_message(f"error: {code}, {data}")
else:
text = data["payload"]["choices"]["text"]
image_content = text[0]
image_base = image_content["content"]
json_data = {"base64_image": image_base}
return [json_data]

View File

@@ -0,0 +1,36 @@
identity:
name: spark_img_generation
author: Onelevenvy
label:
en_US: Spark Image Generation
zh_Hans: 图片生成
pt_BR: Geração de imagens Spark
icon: icon.svg
description:
en_US: Spark Image Generation
zh_Hans: 图片生成
pt_BR: Geração de imagens Spark
description:
human:
en_US: Generate images based on user input, with image generation API
provided by Spark
zh_Hans: 根据用户的输入生成图片由讯飞星火提供图片生成api
pt_BR: Gerar imagens com base na entrada do usuário, com API de geração
de imagem fornecida pela Spark
llm: spark_img_generation is a tool used to generate images from text
parameters:
- name: prompt
type: string
required: true
label:
en_US: Prompt
zh_Hans: 提示词
pt_BR: Prompt
human_description:
en_US: Image prompt
zh_Hans: 图像提示词
pt_BR: Image prompt
llm_description: Image prompt of spark_img_generation tooll, you should
describe the image you want to generate as a list of words as possible
as detailed
form: llm