chore(api/core): apply ruff reformatting (#7624)
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
|
||||
from core.tools.entities.common_entities import I18nObject
|
||||
from core.tools.entities.tool_bundle import ApiToolBundle
|
||||
from core.tools.entities.tool_entities import (
|
||||
@@ -18,85 +17,69 @@ class ApiToolProviderController(ToolProviderController):
|
||||
provider_id: str
|
||||
|
||||
@staticmethod
|
||||
def from_db(db_provider: ApiToolProvider, auth_type: ApiProviderAuthType) -> 'ApiToolProviderController':
|
||||
def from_db(db_provider: ApiToolProvider, auth_type: ApiProviderAuthType) -> "ApiToolProviderController":
|
||||
credentials_schema = {
|
||||
'auth_type': ToolProviderCredentials(
|
||||
name='auth_type',
|
||||
"auth_type": ToolProviderCredentials(
|
||||
name="auth_type",
|
||||
required=True,
|
||||
type=ToolProviderCredentials.CredentialsType.SELECT,
|
||||
options=[
|
||||
ToolCredentialsOption(value='none', label=I18nObject(en_US='None', zh_Hans='无')),
|
||||
ToolCredentialsOption(value='api_key', label=I18nObject(en_US='api_key', zh_Hans='api_key'))
|
||||
ToolCredentialsOption(value="none", label=I18nObject(en_US="None", zh_Hans="无")),
|
||||
ToolCredentialsOption(value="api_key", label=I18nObject(en_US="api_key", zh_Hans="api_key")),
|
||||
],
|
||||
default='none',
|
||||
help=I18nObject(
|
||||
en_US='The auth type of the api provider',
|
||||
zh_Hans='api provider 的认证类型'
|
||||
)
|
||||
default="none",
|
||||
help=I18nObject(en_US="The auth type of the api provider", zh_Hans="api provider 的认证类型"),
|
||||
)
|
||||
}
|
||||
if auth_type == ApiProviderAuthType.API_KEY:
|
||||
credentials_schema = {
|
||||
**credentials_schema,
|
||||
'api_key_header': ToolProviderCredentials(
|
||||
name='api_key_header',
|
||||
"api_key_header": ToolProviderCredentials(
|
||||
name="api_key_header",
|
||||
required=False,
|
||||
default='api_key',
|
||||
default="api_key",
|
||||
type=ToolProviderCredentials.CredentialsType.TEXT_INPUT,
|
||||
help=I18nObject(
|
||||
en_US='The header name of the api key',
|
||||
zh_Hans='携带 api key 的 header 名称'
|
||||
)
|
||||
help=I18nObject(en_US="The header name of the api key", zh_Hans="携带 api key 的 header 名称"),
|
||||
),
|
||||
'api_key_value': ToolProviderCredentials(
|
||||
name='api_key_value',
|
||||
"api_key_value": ToolProviderCredentials(
|
||||
name="api_key_value",
|
||||
required=True,
|
||||
type=ToolProviderCredentials.CredentialsType.SECRET_INPUT,
|
||||
help=I18nObject(
|
||||
en_US='The api key',
|
||||
zh_Hans='api key的值'
|
||||
)
|
||||
help=I18nObject(en_US="The api key", zh_Hans="api key的值"),
|
||||
),
|
||||
'api_key_header_prefix': ToolProviderCredentials(
|
||||
name='api_key_header_prefix',
|
||||
"api_key_header_prefix": ToolProviderCredentials(
|
||||
name="api_key_header_prefix",
|
||||
required=False,
|
||||
default='basic',
|
||||
default="basic",
|
||||
type=ToolProviderCredentials.CredentialsType.SELECT,
|
||||
help=I18nObject(
|
||||
en_US='The prefix of the api key header',
|
||||
zh_Hans='api key header 的前缀'
|
||||
),
|
||||
help=I18nObject(en_US="The prefix of the api key header", zh_Hans="api key header 的前缀"),
|
||||
options=[
|
||||
ToolCredentialsOption(value='basic', label=I18nObject(en_US='Basic', zh_Hans='Basic')),
|
||||
ToolCredentialsOption(value='bearer', label=I18nObject(en_US='Bearer', zh_Hans='Bearer')),
|
||||
ToolCredentialsOption(value='custom', label=I18nObject(en_US='Custom', zh_Hans='Custom'))
|
||||
]
|
||||
)
|
||||
ToolCredentialsOption(value="basic", label=I18nObject(en_US="Basic", zh_Hans="Basic")),
|
||||
ToolCredentialsOption(value="bearer", label=I18nObject(en_US="Bearer", zh_Hans="Bearer")),
|
||||
ToolCredentialsOption(value="custom", label=I18nObject(en_US="Custom", zh_Hans="Custom")),
|
||||
],
|
||||
),
|
||||
}
|
||||
elif auth_type == ApiProviderAuthType.NONE:
|
||||
pass
|
||||
else:
|
||||
raise ValueError(f'invalid auth type {auth_type}')
|
||||
raise ValueError(f"invalid auth type {auth_type}")
|
||||
|
||||
user_name = db_provider.user.name if db_provider.user_id else ''
|
||||
user_name = db_provider.user.name if db_provider.user_id else ""
|
||||
|
||||
return ApiToolProviderController(**{
|
||||
'identity': {
|
||||
'author': user_name,
|
||||
'name': db_provider.name,
|
||||
'label': {
|
||||
'en_US': db_provider.name,
|
||||
'zh_Hans': db_provider.name
|
||||
return ApiToolProviderController(
|
||||
**{
|
||||
"identity": {
|
||||
"author": user_name,
|
||||
"name": db_provider.name,
|
||||
"label": {"en_US": db_provider.name, "zh_Hans": db_provider.name},
|
||||
"description": {"en_US": db_provider.description, "zh_Hans": db_provider.description},
|
||||
"icon": db_provider.icon,
|
||||
},
|
||||
'description': {
|
||||
'en_US': db_provider.description,
|
||||
'zh_Hans': db_provider.description
|
||||
},
|
||||
'icon': db_provider.icon,
|
||||
},
|
||||
'credentials_schema': credentials_schema,
|
||||
'provider_id': db_provider.id or '',
|
||||
})
|
||||
"credentials_schema": credentials_schema,
|
||||
"provider_id": db_provider.id or "",
|
||||
}
|
||||
)
|
||||
|
||||
@property
|
||||
def provider_type(self) -> ToolProviderType:
|
||||
@@ -104,39 +87,35 @@ class ApiToolProviderController(ToolProviderController):
|
||||
|
||||
def _parse_tool_bundle(self, tool_bundle: ApiToolBundle) -> ApiTool:
|
||||
"""
|
||||
parse tool bundle to tool
|
||||
parse tool bundle to tool
|
||||
|
||||
:param tool_bundle: the tool bundle
|
||||
:return: the tool
|
||||
:param tool_bundle: the tool bundle
|
||||
:return: the tool
|
||||
"""
|
||||
return ApiTool(**{
|
||||
'api_bundle': tool_bundle,
|
||||
'identity' : {
|
||||
'author': tool_bundle.author,
|
||||
'name': tool_bundle.operation_id,
|
||||
'label': {
|
||||
'en_US': tool_bundle.operation_id,
|
||||
'zh_Hans': tool_bundle.operation_id
|
||||
return ApiTool(
|
||||
**{
|
||||
"api_bundle": tool_bundle,
|
||||
"identity": {
|
||||
"author": tool_bundle.author,
|
||||
"name": tool_bundle.operation_id,
|
||||
"label": {"en_US": tool_bundle.operation_id, "zh_Hans": tool_bundle.operation_id},
|
||||
"icon": self.identity.icon,
|
||||
"provider": self.provider_id,
|
||||
},
|
||||
'icon': self.identity.icon,
|
||||
'provider': self.provider_id,
|
||||
},
|
||||
'description': {
|
||||
'human': {
|
||||
'en_US': tool_bundle.summary or '',
|
||||
'zh_Hans': tool_bundle.summary or ''
|
||||
"description": {
|
||||
"human": {"en_US": tool_bundle.summary or "", "zh_Hans": tool_bundle.summary or ""},
|
||||
"llm": tool_bundle.summary or "",
|
||||
},
|
||||
'llm': tool_bundle.summary or ''
|
||||
},
|
||||
'parameters' : tool_bundle.parameters if tool_bundle.parameters else [],
|
||||
})
|
||||
"parameters": tool_bundle.parameters if tool_bundle.parameters else [],
|
||||
}
|
||||
)
|
||||
|
||||
def load_bundled_tools(self, tools: list[ApiToolBundle]) -> list[ApiTool]:
|
||||
"""
|
||||
load bundled tools
|
||||
load bundled tools
|
||||
|
||||
:param tools: the bundled tools
|
||||
:return: the tools
|
||||
:param tools: the bundled tools
|
||||
:return: the tools
|
||||
"""
|
||||
self.tools = [self._parse_tool_bundle(tool) for tool in tools]
|
||||
|
||||
@@ -144,22 +123,23 @@ class ApiToolProviderController(ToolProviderController):
|
||||
|
||||
def get_tools(self, user_id: str, tenant_id: str) -> list[ApiTool]:
|
||||
"""
|
||||
fetch tools from database
|
||||
fetch tools from database
|
||||
|
||||
:param user_id: the user id
|
||||
:param tenant_id: the tenant id
|
||||
:return: the tools
|
||||
:param user_id: the user id
|
||||
:param tenant_id: the tenant id
|
||||
:return: the tools
|
||||
"""
|
||||
if self.tools is not None:
|
||||
return self.tools
|
||||
|
||||
|
||||
tools: list[Tool] = []
|
||||
|
||||
# get tenant api providers
|
||||
db_providers: list[ApiToolProvider] = db.session.query(ApiToolProvider).filter(
|
||||
ApiToolProvider.tenant_id == tenant_id,
|
||||
ApiToolProvider.name == self.identity.name
|
||||
).all()
|
||||
db_providers: list[ApiToolProvider] = (
|
||||
db.session.query(ApiToolProvider)
|
||||
.filter(ApiToolProvider.tenant_id == tenant_id, ApiToolProvider.name == self.identity.name)
|
||||
.all()
|
||||
)
|
||||
|
||||
if db_providers and len(db_providers) != 0:
|
||||
for db_provider in db_providers:
|
||||
@@ -167,16 +147,16 @@ class ApiToolProviderController(ToolProviderController):
|
||||
assistant_tool = self._parse_tool_bundle(tool)
|
||||
assistant_tool.is_team_authorization = True
|
||||
tools.append(assistant_tool)
|
||||
|
||||
|
||||
self.tools = tools
|
||||
return tools
|
||||
|
||||
|
||||
def get_tool(self, tool_name: str) -> ApiTool:
|
||||
"""
|
||||
get tool by name
|
||||
get tool by name
|
||||
|
||||
:param tool_name: the name of the tool
|
||||
:return: the tool
|
||||
:param tool_name: the name of the tool
|
||||
:return: the tool
|
||||
"""
|
||||
if self.tools is None:
|
||||
self.get_tools()
|
||||
@@ -185,4 +165,4 @@ class ApiToolProviderController(ToolProviderController):
|
||||
if tool.identity.name == tool_name:
|
||||
return tool
|
||||
|
||||
raise ValueError(f'tool {tool_name} not found')
|
||||
raise ValueError(f"tool {tool_name} not found")
|
||||
|
@@ -11,11 +11,12 @@ from models.tools import PublishedAppTool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AppToolProviderEntity(ToolProviderController):
|
||||
@property
|
||||
def provider_type(self) -> ToolProviderType:
|
||||
return ToolProviderType.APP
|
||||
|
||||
|
||||
def _validate_credentials(self, tool_name: str, credentials: dict[str, Any]) -> None:
|
||||
pass
|
||||
|
||||
@@ -23,9 +24,13 @@ class AppToolProviderEntity(ToolProviderController):
|
||||
pass
|
||||
|
||||
def get_tools(self, user_id: str) -> list[Tool]:
|
||||
db_tools: list[PublishedAppTool] = db.session.query(PublishedAppTool).filter(
|
||||
PublishedAppTool.user_id == user_id,
|
||||
).all()
|
||||
db_tools: list[PublishedAppTool] = (
|
||||
db.session.query(PublishedAppTool)
|
||||
.filter(
|
||||
PublishedAppTool.user_id == user_id,
|
||||
)
|
||||
.all()
|
||||
)
|
||||
|
||||
if not db_tools or len(db_tools) == 0:
|
||||
return []
|
||||
@@ -34,23 +39,17 @@ class AppToolProviderEntity(ToolProviderController):
|
||||
|
||||
for db_tool in db_tools:
|
||||
tool = {
|
||||
'identity': {
|
||||
'author': db_tool.author,
|
||||
'name': db_tool.tool_name,
|
||||
'label': {
|
||||
'en_US': db_tool.tool_name,
|
||||
'zh_Hans': db_tool.tool_name
|
||||
},
|
||||
'icon': ''
|
||||
"identity": {
|
||||
"author": db_tool.author,
|
||||
"name": db_tool.tool_name,
|
||||
"label": {"en_US": db_tool.tool_name, "zh_Hans": db_tool.tool_name},
|
||||
"icon": "",
|
||||
},
|
||||
'description': {
|
||||
'human': {
|
||||
'en_US': db_tool.description_i18n.en_US,
|
||||
'zh_Hans': db_tool.description_i18n.zh_Hans
|
||||
},
|
||||
'llm': db_tool.llm_description
|
||||
"description": {
|
||||
"human": {"en_US": db_tool.description_i18n.en_US, "zh_Hans": db_tool.description_i18n.zh_Hans},
|
||||
"llm": db_tool.llm_description,
|
||||
},
|
||||
'parameters': []
|
||||
"parameters": [],
|
||||
}
|
||||
# get app from db
|
||||
app: App = db_tool.app
|
||||
@@ -64,52 +63,41 @@ class AppToolProviderEntity(ToolProviderController):
|
||||
for input_form in user_input_form_list:
|
||||
# get type
|
||||
form_type = input_form.keys()[0]
|
||||
default = input_form[form_type]['default']
|
||||
required = input_form[form_type]['required']
|
||||
label = input_form[form_type]['label']
|
||||
variable_name = input_form[form_type]['variable_name']
|
||||
options = input_form[form_type].get('options', [])
|
||||
if form_type == 'paragraph' or form_type == 'text-input':
|
||||
tool['parameters'].append(ToolParameter(
|
||||
name=variable_name,
|
||||
label=I18nObject(
|
||||
en_US=label,
|
||||
zh_Hans=label
|
||||
),
|
||||
human_description=I18nObject(
|
||||
en_US=label,
|
||||
zh_Hans=label
|
||||
),
|
||||
llm_description=label,
|
||||
form=ToolParameter.ToolParameterForm.FORM,
|
||||
type=ToolParameter.ToolParameterType.STRING,
|
||||
required=required,
|
||||
default=default
|
||||
))
|
||||
elif form_type == 'select':
|
||||
tool['parameters'].append(ToolParameter(
|
||||
name=variable_name,
|
||||
label=I18nObject(
|
||||
en_US=label,
|
||||
zh_Hans=label
|
||||
),
|
||||
human_description=I18nObject(
|
||||
en_US=label,
|
||||
zh_Hans=label
|
||||
),
|
||||
llm_description=label,
|
||||
form=ToolParameter.ToolParameterForm.FORM,
|
||||
type=ToolParameter.ToolParameterType.SELECT,
|
||||
required=required,
|
||||
default=default,
|
||||
options=[ToolParameterOption(
|
||||
value=option,
|
||||
label=I18nObject(
|
||||
en_US=option,
|
||||
zh_Hans=option
|
||||
)
|
||||
) for option in options]
|
||||
))
|
||||
default = input_form[form_type]["default"]
|
||||
required = input_form[form_type]["required"]
|
||||
label = input_form[form_type]["label"]
|
||||
variable_name = input_form[form_type]["variable_name"]
|
||||
options = input_form[form_type].get("options", [])
|
||||
if form_type == "paragraph" or form_type == "text-input":
|
||||
tool["parameters"].append(
|
||||
ToolParameter(
|
||||
name=variable_name,
|
||||
label=I18nObject(en_US=label, zh_Hans=label),
|
||||
human_description=I18nObject(en_US=label, zh_Hans=label),
|
||||
llm_description=label,
|
||||
form=ToolParameter.ToolParameterForm.FORM,
|
||||
type=ToolParameter.ToolParameterType.STRING,
|
||||
required=required,
|
||||
default=default,
|
||||
)
|
||||
)
|
||||
elif form_type == "select":
|
||||
tool["parameters"].append(
|
||||
ToolParameter(
|
||||
name=variable_name,
|
||||
label=I18nObject(en_US=label, zh_Hans=label),
|
||||
human_description=I18nObject(en_US=label, zh_Hans=label),
|
||||
llm_description=label,
|
||||
form=ToolParameter.ToolParameterForm.FORM,
|
||||
type=ToolParameter.ToolParameterType.SELECT,
|
||||
required=required,
|
||||
default=default,
|
||||
options=[
|
||||
ToolParameterOption(value=option, label=I18nObject(en_US=option, zh_Hans=option))
|
||||
for option in options
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
tools.append(Tool(**tool))
|
||||
return tools
|
||||
return tools
|
||||
|
@@ -10,7 +10,7 @@ class BuiltinToolProviderSort:
|
||||
@classmethod
|
||||
def sort(cls, providers: list[UserToolProvider]) -> list[UserToolProvider]:
|
||||
if not cls._position:
|
||||
cls._position = get_tool_position_map(os.path.join(os.path.dirname(__file__), '..'))
|
||||
cls._position = get_tool_position_map(os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
def name_func(provider: UserToolProvider) -> str:
|
||||
return provider.name
|
||||
|
@@ -6,6 +6,6 @@ from core.tools.provider.builtin_tool_provider import BuiltinToolProviderControl
|
||||
class AIPPTProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict) -> None:
|
||||
try:
|
||||
AIPPTGenerateTool._get_api_token(credentials, user_id='__dify_system__')
|
||||
AIPPTGenerateTool._get_api_token(credentials, user_id="__dify_system__")
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -20,16 +20,16 @@ class AIPPTGenerateTool(BuiltinTool):
|
||||
A tool for generating a ppt
|
||||
"""
|
||||
|
||||
_api_base_url = URL('https://co.aippt.cn/api')
|
||||
_api_base_url = URL("https://co.aippt.cn/api")
|
||||
_api_token_cache = {}
|
||||
_api_token_cache_lock:Optional[Lock] = None
|
||||
_api_token_cache_lock: Optional[Lock] = None
|
||||
_style_cache = {}
|
||||
_style_cache_lock:Optional[Lock] = None
|
||||
_style_cache_lock: Optional[Lock] = None
|
||||
|
||||
_task = {}
|
||||
_task_type_map = {
|
||||
'auto': 1,
|
||||
'markdown': 7,
|
||||
"auto": 1,
|
||||
"markdown": 7,
|
||||
}
|
||||
|
||||
def __init__(self, **kwargs: Any):
|
||||
@@ -48,65 +48,55 @@ class AIPPTGenerateTool(BuiltinTool):
|
||||
Returns:
|
||||
ToolInvokeMessage | list[ToolInvokeMessage]: The result of the tool invocation, which can be a single message or a list of messages.
|
||||
"""
|
||||
title = tool_parameters.get('title', '')
|
||||
title = tool_parameters.get("title", "")
|
||||
if not title:
|
||||
return self.create_text_message('Please provide a title for the ppt')
|
||||
|
||||
model = tool_parameters.get('model', 'aippt')
|
||||
return self.create_text_message("Please provide a title for the ppt")
|
||||
|
||||
model = tool_parameters.get("model", "aippt")
|
||||
if not model:
|
||||
return self.create_text_message('Please provide a model for the ppt')
|
||||
|
||||
outline = tool_parameters.get('outline', '')
|
||||
return self.create_text_message("Please provide a model for the ppt")
|
||||
|
||||
outline = tool_parameters.get("outline", "")
|
||||
|
||||
# create task
|
||||
task_id = self._create_task(
|
||||
type=self._task_type_map['auto' if not outline else 'markdown'],
|
||||
type=self._task_type_map["auto" if not outline else "markdown"],
|
||||
title=title,
|
||||
content=outline,
|
||||
user_id=user_id
|
||||
user_id=user_id,
|
||||
)
|
||||
|
||||
# get suit
|
||||
color = tool_parameters.get('color')
|
||||
style = tool_parameters.get('style')
|
||||
color = tool_parameters.get("color")
|
||||
style = tool_parameters.get("style")
|
||||
|
||||
if color == '__default__':
|
||||
color_id = ''
|
||||
if color == "__default__":
|
||||
color_id = ""
|
||||
else:
|
||||
color_id = int(color.split('-')[1])
|
||||
color_id = int(color.split("-")[1])
|
||||
|
||||
if style == '__default__':
|
||||
style_id = ''
|
||||
if style == "__default__":
|
||||
style_id = ""
|
||||
else:
|
||||
style_id = int(style.split('-')[1])
|
||||
style_id = int(style.split("-")[1])
|
||||
|
||||
suit_id = self._get_suit(style_id=style_id, colour_id=color_id)
|
||||
|
||||
# generate outline
|
||||
if not outline:
|
||||
self._generate_outline(
|
||||
task_id=task_id,
|
||||
model=model,
|
||||
user_id=user_id
|
||||
)
|
||||
self._generate_outline(task_id=task_id, model=model, user_id=user_id)
|
||||
|
||||
# generate content
|
||||
self._generate_content(
|
||||
task_id=task_id,
|
||||
model=model,
|
||||
user_id=user_id
|
||||
)
|
||||
self._generate_content(task_id=task_id, model=model, user_id=user_id)
|
||||
|
||||
# generate ppt
|
||||
_, ppt_url = self._generate_ppt(
|
||||
task_id=task_id,
|
||||
suit_id=suit_id,
|
||||
user_id=user_id
|
||||
)
|
||||
_, ppt_url = self._generate_ppt(task_id=task_id, suit_id=suit_id, user_id=user_id)
|
||||
|
||||
return self.create_text_message('''the ppt has been created successfully,'''
|
||||
f'''the ppt url is {ppt_url}'''
|
||||
'''please give the ppt url to user and direct user to download it.''')
|
||||
return self.create_text_message(
|
||||
"""the ppt has been created successfully,"""
|
||||
f"""the ppt url is {ppt_url}"""
|
||||
"""please give the ppt url to user and direct user to download it."""
|
||||
)
|
||||
|
||||
def _create_task(self, type: int, title: str, content: str, user_id: str) -> str:
|
||||
"""
|
||||
@@ -119,129 +109,121 @@ class AIPPTGenerateTool(BuiltinTool):
|
||||
:return: the task ID
|
||||
"""
|
||||
headers = {
|
||||
'x-channel': '',
|
||||
'x-api-key': self.runtime.credentials['aippt_access_key'],
|
||||
'x-token': self._get_api_token(credentials=self.runtime.credentials, user_id=user_id),
|
||||
"x-channel": "",
|
||||
"x-api-key": self.runtime.credentials["aippt_access_key"],
|
||||
"x-token": self._get_api_token(credentials=self.runtime.credentials, user_id=user_id),
|
||||
}
|
||||
response = post(
|
||||
str(self._api_base_url / 'ai' / 'chat' / 'v2' / 'task'),
|
||||
str(self._api_base_url / "ai" / "chat" / "v2" / "task"),
|
||||
headers=headers,
|
||||
files={
|
||||
'type': ('', str(type)),
|
||||
'title': ('', title),
|
||||
'content': ('', content)
|
||||
}
|
||||
files={"type": ("", str(type)), "title": ("", title), "content": ("", content)},
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f'Failed to connect to aippt: {response.text}')
|
||||
|
||||
raise Exception(f"Failed to connect to aippt: {response.text}")
|
||||
|
||||
response = response.json()
|
||||
if response.get('code') != 0:
|
||||
if response.get("code") != 0:
|
||||
raise Exception(f'Failed to create task: {response.get("msg")}')
|
||||
|
||||
return response.get('data', {}).get('id')
|
||||
|
||||
return response.get("data", {}).get("id")
|
||||
|
||||
def _generate_outline(self, task_id: str, model: str, user_id: str) -> str:
|
||||
api_url = self._api_base_url / 'ai' / 'chat' / 'outline' if model == 'aippt' else \
|
||||
self._api_base_url / 'ai' / 'chat' / 'wx' / 'outline'
|
||||
api_url %= {'task_id': task_id}
|
||||
api_url = (
|
||||
self._api_base_url / "ai" / "chat" / "outline"
|
||||
if model == "aippt"
|
||||
else self._api_base_url / "ai" / "chat" / "wx" / "outline"
|
||||
)
|
||||
api_url %= {"task_id": task_id}
|
||||
|
||||
headers = {
|
||||
'x-channel': '',
|
||||
'x-api-key': self.runtime.credentials['aippt_access_key'],
|
||||
'x-token': self._get_api_token(credentials=self.runtime.credentials, user_id=user_id),
|
||||
"x-channel": "",
|
||||
"x-api-key": self.runtime.credentials["aippt_access_key"],
|
||||
"x-token": self._get_api_token(credentials=self.runtime.credentials, user_id=user_id),
|
||||
}
|
||||
|
||||
response = requests_get(
|
||||
url=api_url,
|
||||
headers=headers,
|
||||
stream=True,
|
||||
timeout=(10, 60)
|
||||
)
|
||||
response = requests_get(url=api_url, headers=headers, stream=True, timeout=(10, 60))
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f'Failed to connect to aippt: {response.text}')
|
||||
|
||||
outline = ''
|
||||
for chunk in response.iter_lines(delimiter=b'\n\n'):
|
||||
raise Exception(f"Failed to connect to aippt: {response.text}")
|
||||
|
||||
outline = ""
|
||||
for chunk in response.iter_lines(delimiter=b"\n\n"):
|
||||
if not chunk:
|
||||
continue
|
||||
|
||||
event = ''
|
||||
lines = chunk.decode('utf-8').split('\n')
|
||||
|
||||
event = ""
|
||||
lines = chunk.decode("utf-8").split("\n")
|
||||
for line in lines:
|
||||
if line.startswith('event:'):
|
||||
if line.startswith("event:"):
|
||||
event = line[6:]
|
||||
elif line.startswith('data:'):
|
||||
elif line.startswith("data:"):
|
||||
data = line[5:]
|
||||
if event == 'message':
|
||||
if event == "message":
|
||||
try:
|
||||
data = json_loads(data)
|
||||
outline += data.get('content', '')
|
||||
outline += data.get("content", "")
|
||||
except Exception as e:
|
||||
pass
|
||||
elif event == 'close':
|
||||
elif event == "close":
|
||||
break
|
||||
elif event == 'error' or event == 'filter':
|
||||
raise Exception(f'Failed to generate outline: {data}')
|
||||
|
||||
elif event == "error" or event == "filter":
|
||||
raise Exception(f"Failed to generate outline: {data}")
|
||||
|
||||
return outline
|
||||
|
||||
|
||||
def _generate_content(self, task_id: str, model: str, user_id: str) -> str:
|
||||
api_url = self._api_base_url / 'ai' / 'chat' / 'content' if model == 'aippt' else \
|
||||
self._api_base_url / 'ai' / 'chat' / 'wx' / 'content'
|
||||
api_url %= {'task_id': task_id}
|
||||
api_url = (
|
||||
self._api_base_url / "ai" / "chat" / "content"
|
||||
if model == "aippt"
|
||||
else self._api_base_url / "ai" / "chat" / "wx" / "content"
|
||||
)
|
||||
api_url %= {"task_id": task_id}
|
||||
|
||||
headers = {
|
||||
'x-channel': '',
|
||||
'x-api-key': self.runtime.credentials['aippt_access_key'],
|
||||
'x-token': self._get_api_token(credentials=self.runtime.credentials, user_id=user_id),
|
||||
"x-channel": "",
|
||||
"x-api-key": self.runtime.credentials["aippt_access_key"],
|
||||
"x-token": self._get_api_token(credentials=self.runtime.credentials, user_id=user_id),
|
||||
}
|
||||
|
||||
response = requests_get(
|
||||
url=api_url,
|
||||
headers=headers,
|
||||
stream=True,
|
||||
timeout=(10, 60)
|
||||
)
|
||||
response = requests_get(url=api_url, headers=headers, stream=True, timeout=(10, 60))
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f'Failed to connect to aippt: {response.text}')
|
||||
|
||||
if model == 'aippt':
|
||||
content = ''
|
||||
for chunk in response.iter_lines(delimiter=b'\n\n'):
|
||||
raise Exception(f"Failed to connect to aippt: {response.text}")
|
||||
|
||||
if model == "aippt":
|
||||
content = ""
|
||||
for chunk in response.iter_lines(delimiter=b"\n\n"):
|
||||
if not chunk:
|
||||
continue
|
||||
|
||||
event = ''
|
||||
lines = chunk.decode('utf-8').split('\n')
|
||||
|
||||
event = ""
|
||||
lines = chunk.decode("utf-8").split("\n")
|
||||
for line in lines:
|
||||
if line.startswith('event:'):
|
||||
if line.startswith("event:"):
|
||||
event = line[6:]
|
||||
elif line.startswith('data:'):
|
||||
elif line.startswith("data:"):
|
||||
data = line[5:]
|
||||
if event == 'message':
|
||||
if event == "message":
|
||||
try:
|
||||
data = json_loads(data)
|
||||
content += data.get('content', '')
|
||||
content += data.get("content", "")
|
||||
except Exception as e:
|
||||
pass
|
||||
elif event == 'close':
|
||||
elif event == "close":
|
||||
break
|
||||
elif event == 'error' or event == 'filter':
|
||||
raise Exception(f'Failed to generate content: {data}')
|
||||
|
||||
elif event == "error" or event == "filter":
|
||||
raise Exception(f"Failed to generate content: {data}")
|
||||
|
||||
return content
|
||||
elif model == 'wenxin':
|
||||
elif model == "wenxin":
|
||||
response = response.json()
|
||||
if response.get('code') != 0:
|
||||
if response.get("code") != 0:
|
||||
raise Exception(f'Failed to generate content: {response.get("msg")}')
|
||||
|
||||
return response.get('data', '')
|
||||
|
||||
return ''
|
||||
|
||||
return response.get("data", "")
|
||||
|
||||
return ""
|
||||
|
||||
def _generate_ppt(self, task_id: str, suit_id: int, user_id) -> tuple[str, str]:
|
||||
"""
|
||||
@@ -252,83 +234,73 @@ class AIPPTGenerateTool(BuiltinTool):
|
||||
:return: the cover url of the ppt and the ppt url
|
||||
"""
|
||||
headers = {
|
||||
'x-channel': '',
|
||||
'x-api-key': self.runtime.credentials['aippt_access_key'],
|
||||
'x-token': self._get_api_token(credentials=self.runtime.credentials, user_id=user_id),
|
||||
"x-channel": "",
|
||||
"x-api-key": self.runtime.credentials["aippt_access_key"],
|
||||
"x-token": self._get_api_token(credentials=self.runtime.credentials, user_id=user_id),
|
||||
}
|
||||
|
||||
response = post(
|
||||
str(self._api_base_url / 'design' / 'v2' / 'save'),
|
||||
str(self._api_base_url / "design" / "v2" / "save"),
|
||||
headers=headers,
|
||||
data={
|
||||
'task_id': task_id,
|
||||
'template_id': suit_id
|
||||
}
|
||||
data={"task_id": task_id, "template_id": suit_id},
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f'Failed to connect to aippt: {response.text}')
|
||||
|
||||
raise Exception(f"Failed to connect to aippt: {response.text}")
|
||||
|
||||
response = response.json()
|
||||
if response.get('code') != 0:
|
||||
if response.get("code") != 0:
|
||||
raise Exception(f'Failed to generate ppt: {response.get("msg")}')
|
||||
|
||||
id = response.get('data', {}).get('id')
|
||||
cover_url = response.get('data', {}).get('cover_url')
|
||||
|
||||
id = response.get("data", {}).get("id")
|
||||
cover_url = response.get("data", {}).get("cover_url")
|
||||
|
||||
response = post(
|
||||
str(self._api_base_url / 'download' / 'export' / 'file'),
|
||||
str(self._api_base_url / "download" / "export" / "file"),
|
||||
headers=headers,
|
||||
data={
|
||||
'id': id,
|
||||
'format': 'ppt',
|
||||
'files_to_zip': False,
|
||||
'edit': True
|
||||
}
|
||||
data={"id": id, "format": "ppt", "files_to_zip": False, "edit": True},
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f'Failed to connect to aippt: {response.text}')
|
||||
|
||||
raise Exception(f"Failed to connect to aippt: {response.text}")
|
||||
|
||||
response = response.json()
|
||||
if response.get('code') != 0:
|
||||
if response.get("code") != 0:
|
||||
raise Exception(f'Failed to generate ppt: {response.get("msg")}')
|
||||
|
||||
export_code = response.get('data')
|
||||
|
||||
export_code = response.get("data")
|
||||
if not export_code:
|
||||
raise Exception('Failed to generate ppt, the export code is empty')
|
||||
|
||||
raise Exception("Failed to generate ppt, the export code is empty")
|
||||
|
||||
current_iteration = 0
|
||||
while current_iteration < 50:
|
||||
# get ppt url
|
||||
response = post(
|
||||
str(self._api_base_url / 'download' / 'export' / 'file' / 'result'),
|
||||
str(self._api_base_url / "download" / "export" / "file" / "result"),
|
||||
headers=headers,
|
||||
data={
|
||||
'task_key': export_code
|
||||
}
|
||||
data={"task_key": export_code},
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f'Failed to connect to aippt: {response.text}')
|
||||
|
||||
raise Exception(f"Failed to connect to aippt: {response.text}")
|
||||
|
||||
response = response.json()
|
||||
if response.get('code') != 0:
|
||||
if response.get("code") != 0:
|
||||
raise Exception(f'Failed to generate ppt: {response.get("msg")}')
|
||||
|
||||
if response.get('msg') == '导出中':
|
||||
|
||||
if response.get("msg") == "导出中":
|
||||
current_iteration += 1
|
||||
sleep(2)
|
||||
continue
|
||||
|
||||
ppt_url = response.get('data', [])
|
||||
|
||||
ppt_url = response.get("data", [])
|
||||
if len(ppt_url) == 0:
|
||||
raise Exception('Failed to generate ppt, the ppt url is empty')
|
||||
|
||||
raise Exception("Failed to generate ppt, the ppt url is empty")
|
||||
|
||||
return cover_url, ppt_url[0]
|
||||
|
||||
raise Exception('Failed to generate ppt, the export is timeout')
|
||||
|
||||
|
||||
raise Exception("Failed to generate ppt, the export is timeout")
|
||||
|
||||
@classmethod
|
||||
def _get_api_token(cls, credentials: dict[str, str], user_id: str) -> str:
|
||||
"""
|
||||
@@ -337,53 +309,43 @@ class AIPPTGenerateTool(BuiltinTool):
|
||||
:param credentials: the credentials
|
||||
:return: the API token
|
||||
"""
|
||||
access_key = credentials['aippt_access_key']
|
||||
secret_key = credentials['aippt_secret_key']
|
||||
access_key = credentials["aippt_access_key"]
|
||||
secret_key = credentials["aippt_secret_key"]
|
||||
|
||||
cache_key = f'{access_key}#@#{user_id}'
|
||||
cache_key = f"{access_key}#@#{user_id}"
|
||||
|
||||
with cls._api_token_cache_lock:
|
||||
# clear expired tokens
|
||||
now = time()
|
||||
for key in list(cls._api_token_cache.keys()):
|
||||
if cls._api_token_cache[key]['expire'] < now:
|
||||
if cls._api_token_cache[key]["expire"] < now:
|
||||
del cls._api_token_cache[key]
|
||||
|
||||
if cache_key in cls._api_token_cache:
|
||||
return cls._api_token_cache[cache_key]['token']
|
||||
|
||||
return cls._api_token_cache[cache_key]["token"]
|
||||
|
||||
# get token
|
||||
headers = {
|
||||
'x-api-key': access_key,
|
||||
'x-timestamp': str(int(now)),
|
||||
'x-signature': cls._calculate_sign(access_key, secret_key, int(now))
|
||||
"x-api-key": access_key,
|
||||
"x-timestamp": str(int(now)),
|
||||
"x-signature": cls._calculate_sign(access_key, secret_key, int(now)),
|
||||
}
|
||||
|
||||
param = {
|
||||
'uid': user_id,
|
||||
'channel': ''
|
||||
}
|
||||
param = {"uid": user_id, "channel": ""}
|
||||
|
||||
response = get(
|
||||
str(cls._api_base_url / 'grant' / 'token'),
|
||||
params=param,
|
||||
headers=headers
|
||||
)
|
||||
response = get(str(cls._api_base_url / "grant" / "token"), params=param, headers=headers)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f'Failed to connect to aippt: {response.text}')
|
||||
raise Exception(f"Failed to connect to aippt: {response.text}")
|
||||
response = response.json()
|
||||
if response.get('code') != 0:
|
||||
if response.get("code") != 0:
|
||||
raise Exception(f'Failed to connect to aippt: {response.get("msg")}')
|
||||
|
||||
token = response.get('data', {}).get('token')
|
||||
expire = response.get('data', {}).get('time_expire')
|
||||
|
||||
token = response.get("data", {}).get("token")
|
||||
expire = response.get("data", {}).get("time_expire")
|
||||
|
||||
with cls._api_token_cache_lock:
|
||||
cls._api_token_cache[cache_key] = {
|
||||
'token': token,
|
||||
'expire': now + expire
|
||||
}
|
||||
cls._api_token_cache[cache_key] = {"token": token, "expire": now + expire}
|
||||
|
||||
return token
|
||||
|
||||
@@ -391,11 +353,9 @@ class AIPPTGenerateTool(BuiltinTool):
|
||||
def _calculate_sign(cls, access_key: str, secret_key: str, timestamp: int) -> str:
|
||||
return b64encode(
|
||||
hmac_new(
|
||||
key=secret_key.encode('utf-8'),
|
||||
msg=f'GET@/api/grant/token/@{timestamp}'.encode(),
|
||||
digestmod=sha1
|
||||
key=secret_key.encode("utf-8"), msg=f"GET@/api/grant/token/@{timestamp}".encode(), digestmod=sha1
|
||||
).digest()
|
||||
).decode('utf-8')
|
||||
).decode("utf-8")
|
||||
|
||||
@classmethod
|
||||
def _get_styles(cls, credentials: dict[str, str], user_id: str) -> tuple[list[dict], list[dict]]:
|
||||
@@ -408,47 +368,46 @@ class AIPPTGenerateTool(BuiltinTool):
|
||||
# clear expired styles
|
||||
now = time()
|
||||
for key in list(cls._style_cache.keys()):
|
||||
if cls._style_cache[key]['expire'] < now:
|
||||
if cls._style_cache[key]["expire"] < now:
|
||||
del cls._style_cache[key]
|
||||
|
||||
key = f'{credentials["aippt_access_key"]}#@#{user_id}'
|
||||
if key in cls._style_cache:
|
||||
return cls._style_cache[key]['colors'], cls._style_cache[key]['styles']
|
||||
return cls._style_cache[key]["colors"], cls._style_cache[key]["styles"]
|
||||
|
||||
headers = {
|
||||
'x-channel': '',
|
||||
'x-api-key': credentials['aippt_access_key'],
|
||||
'x-token': cls._get_api_token(credentials=credentials, user_id=user_id)
|
||||
"x-channel": "",
|
||||
"x-api-key": credentials["aippt_access_key"],
|
||||
"x-token": cls._get_api_token(credentials=credentials, user_id=user_id),
|
||||
}
|
||||
response = get(
|
||||
str(cls._api_base_url / 'template_component' / 'suit' / 'select'),
|
||||
headers=headers
|
||||
)
|
||||
response = get(str(cls._api_base_url / "template_component" / "suit" / "select"), headers=headers)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f'Failed to connect to aippt: {response.text}')
|
||||
|
||||
raise Exception(f"Failed to connect to aippt: {response.text}")
|
||||
|
||||
response = response.json()
|
||||
|
||||
if response.get('code') != 0:
|
||||
if response.get("code") != 0:
|
||||
raise Exception(f'Failed to connect to aippt: {response.get("msg")}')
|
||||
|
||||
colors = [{
|
||||
'id': f'id-{item.get("id")}',
|
||||
'name': item.get('name'),
|
||||
'en_name': item.get('en_name', item.get('name')),
|
||||
} for item in response.get('data', {}).get('colour') or []]
|
||||
styles = [{
|
||||
'id': f'id-{item.get("id")}',
|
||||
'name': item.get('title'),
|
||||
} for item in response.get('data', {}).get('suit_style') or []]
|
||||
|
||||
colors = [
|
||||
{
|
||||
"id": f'id-{item.get("id")}',
|
||||
"name": item.get("name"),
|
||||
"en_name": item.get("en_name", item.get("name")),
|
||||
}
|
||||
for item in response.get("data", {}).get("colour") or []
|
||||
]
|
||||
styles = [
|
||||
{
|
||||
"id": f'id-{item.get("id")}',
|
||||
"name": item.get("title"),
|
||||
}
|
||||
for item in response.get("data", {}).get("suit_style") or []
|
||||
]
|
||||
|
||||
with cls._style_cache_lock:
|
||||
cls._style_cache[key] = {
|
||||
'colors': colors,
|
||||
'styles': styles,
|
||||
'expire': now + 60 * 60
|
||||
}
|
||||
cls._style_cache[key] = {"colors": colors, "styles": styles, "expire": now + 60 * 60}
|
||||
|
||||
return colors, styles
|
||||
|
||||
@@ -459,44 +418,39 @@ class AIPPTGenerateTool(BuiltinTool):
|
||||
:param credentials: the credentials
|
||||
:return: Tuple[list[dict[id, color]], list[dict[id, style]]
|
||||
"""
|
||||
if not self.runtime.credentials.get('aippt_access_key') or not self.runtime.credentials.get('aippt_secret_key'):
|
||||
raise Exception('Please provide aippt credentials')
|
||||
if not self.runtime.credentials.get("aippt_access_key") or not self.runtime.credentials.get("aippt_secret_key"):
|
||||
raise Exception("Please provide aippt credentials")
|
||||
|
||||
return self._get_styles(credentials=self.runtime.credentials, user_id=user_id)
|
||||
|
||||
|
||||
def _get_suit(self, style_id: int, colour_id: int) -> int:
|
||||
"""
|
||||
Get suit
|
||||
"""
|
||||
headers = {
|
||||
'x-channel': '',
|
||||
'x-api-key': self.runtime.credentials['aippt_access_key'],
|
||||
'x-token': self._get_api_token(credentials=self.runtime.credentials, user_id='__dify_system__')
|
||||
"x-channel": "",
|
||||
"x-api-key": self.runtime.credentials["aippt_access_key"],
|
||||
"x-token": self._get_api_token(credentials=self.runtime.credentials, user_id="__dify_system__"),
|
||||
}
|
||||
response = get(
|
||||
str(self._api_base_url / 'template_component' / 'suit' / 'search'),
|
||||
str(self._api_base_url / "template_component" / "suit" / "search"),
|
||||
headers=headers,
|
||||
params={
|
||||
'style_id': style_id,
|
||||
'colour_id': colour_id,
|
||||
'page': 1,
|
||||
'page_size': 1
|
||||
}
|
||||
params={"style_id": style_id, "colour_id": colour_id, "page": 1, "page_size": 1},
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f'Failed to connect to aippt: {response.text}')
|
||||
|
||||
raise Exception(f"Failed to connect to aippt: {response.text}")
|
||||
|
||||
response = response.json()
|
||||
|
||||
if response.get('code') != 0:
|
||||
if response.get("code") != 0:
|
||||
raise Exception(f'Failed to connect to aippt: {response.get("msg")}')
|
||||
|
||||
if len(response.get('data', {}).get('list') or []) > 0:
|
||||
return response.get('data', {}).get('list')[0].get('id')
|
||||
|
||||
raise Exception('Failed to get suit, the suit does not exist, please check the style and color')
|
||||
|
||||
|
||||
if len(response.get("data", {}).get("list") or []) > 0:
|
||||
return response.get("data", {}).get("list")[0].get("id")
|
||||
|
||||
raise Exception("Failed to get suit, the suit does not exist, please check the style and color")
|
||||
|
||||
def get_runtime_parameters(self) -> list[ToolParameter]:
|
||||
"""
|
||||
Get runtime parameters
|
||||
@@ -504,43 +458,40 @@ class AIPPTGenerateTool(BuiltinTool):
|
||||
Override this method to add runtime parameters to the tool.
|
||||
"""
|
||||
try:
|
||||
colors, styles = self.get_styles(user_id='__dify_system__')
|
||||
colors, styles = self.get_styles(user_id="__dify_system__")
|
||||
except Exception as e:
|
||||
colors, styles = [
|
||||
{'id': '-1', 'name': '__default__', 'en_name': '__default__'}
|
||||
], [
|
||||
{'id': '-1', 'name': '__default__', 'en_name': '__default__'}
|
||||
]
|
||||
colors, styles = (
|
||||
[{"id": "-1", "name": "__default__", "en_name": "__default__"}],
|
||||
[{"id": "-1", "name": "__default__", "en_name": "__default__"}],
|
||||
)
|
||||
|
||||
return [
|
||||
ToolParameter(
|
||||
name='color',
|
||||
label=I18nObject(zh_Hans='颜色', en_US='Color'),
|
||||
human_description=I18nObject(zh_Hans='颜色', en_US='Color'),
|
||||
name="color",
|
||||
label=I18nObject(zh_Hans="颜色", en_US="Color"),
|
||||
human_description=I18nObject(zh_Hans="颜色", en_US="Color"),
|
||||
type=ToolParameter.ToolParameterType.SELECT,
|
||||
form=ToolParameter.ToolParameterForm.FORM,
|
||||
required=False,
|
||||
default=colors[0]['id'],
|
||||
default=colors[0]["id"],
|
||||
options=[
|
||||
ToolParameterOption(
|
||||
value=color['id'],
|
||||
label=I18nObject(zh_Hans=color['name'], en_US=color['en_name'])
|
||||
) for color in colors
|
||||
]
|
||||
value=color["id"], label=I18nObject(zh_Hans=color["name"], en_US=color["en_name"])
|
||||
)
|
||||
for color in colors
|
||||
],
|
||||
),
|
||||
ToolParameter(
|
||||
name='style',
|
||||
label=I18nObject(zh_Hans='风格', en_US='Style'),
|
||||
human_description=I18nObject(zh_Hans='风格', en_US='Style'),
|
||||
name="style",
|
||||
label=I18nObject(zh_Hans="风格", en_US="Style"),
|
||||
human_description=I18nObject(zh_Hans="风格", en_US="Style"),
|
||||
type=ToolParameter.ToolParameterType.SELECT,
|
||||
form=ToolParameter.ToolParameterForm.FORM,
|
||||
required=False,
|
||||
default=styles[0]['id'],
|
||||
default=styles[0]["id"],
|
||||
options=[
|
||||
ToolParameterOption(
|
||||
value=style['id'],
|
||||
label=I18nObject(zh_Hans=style['name'], en_US=style['name'])
|
||||
) for style in styles
|
||||
]
|
||||
ToolParameterOption(value=style["id"], label=I18nObject(zh_Hans=style["name"], en_US=style["name"]))
|
||||
for style in styles
|
||||
],
|
||||
),
|
||||
]
|
||||
]
|
||||
|
@@ -13,7 +13,7 @@ class AlphaVantageProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"code": "AAPL", # Apple Inc.
|
||||
},
|
||||
|
@@ -9,17 +9,16 @@ ALPHAVANTAGE_API_URL = "https://www.alphavantage.co/query"
|
||||
|
||||
|
||||
class QueryStockTool(BuiltinTool):
|
||||
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
stock_code = tool_parameters.get('code', '')
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
stock_code = tool_parameters.get("code", "")
|
||||
if not stock_code:
|
||||
return self.create_text_message('Please tell me your stock code')
|
||||
return self.create_text_message("Please tell me your stock code")
|
||||
|
||||
if 'api_key' not in self.runtime.credentials or not self.runtime.credentials.get('api_key'):
|
||||
if "api_key" not in self.runtime.credentials or not self.runtime.credentials.get("api_key"):
|
||||
return self.create_text_message("Alpha Vantage API key is required.")
|
||||
|
||||
params = {
|
||||
@@ -27,7 +26,7 @@ class QueryStockTool(BuiltinTool):
|
||||
"symbol": stock_code,
|
||||
"outputsize": "compact",
|
||||
"datatype": "json",
|
||||
"apikey": self.runtime.credentials['api_key']
|
||||
"apikey": self.runtime.credentials["api_key"],
|
||||
}
|
||||
response = requests.get(url=ALPHAVANTAGE_API_URL, params=params)
|
||||
response.raise_for_status()
|
||||
@@ -35,15 +34,15 @@ class QueryStockTool(BuiltinTool):
|
||||
return self.create_json_message(result)
|
||||
|
||||
def _handle_response(self, response: dict[str, Any]) -> dict[str, Any]:
|
||||
result = response.get('Time Series (Daily)', {})
|
||||
result = response.get("Time Series (Daily)", {})
|
||||
if not result:
|
||||
return {}
|
||||
stock_result = {}
|
||||
for k, v in result.items():
|
||||
stock_result[k] = {}
|
||||
stock_result[k]['open'] = v.get('1. open')
|
||||
stock_result[k]['high'] = v.get('2. high')
|
||||
stock_result[k]['low'] = v.get('3. low')
|
||||
stock_result[k]['close'] = v.get('4. close')
|
||||
stock_result[k]['volume'] = v.get('5. volume')
|
||||
stock_result[k]["open"] = v.get("1. open")
|
||||
stock_result[k]["high"] = v.get("2. high")
|
||||
stock_result[k]["low"] = v.get("3. low")
|
||||
stock_result[k]["close"] = v.get("4. close")
|
||||
stock_result[k]["volume"] = v.get("5. volume")
|
||||
return stock_result
|
||||
|
@@ -11,11 +11,10 @@ class ArxivProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"query": "John Doe",
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -8,6 +8,8 @@ from core.tools.entities.tool_entities import ToolInvokeMessage
|
||||
from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ArxivAPIWrapper(BaseModel):
|
||||
"""Wrapper around ArxivAPI.
|
||||
|
||||
@@ -86,11 +88,13 @@ class ArxivAPIWrapper(BaseModel):
|
||||
|
||||
class ArxivSearchInput(BaseModel):
|
||||
query: str = Field(..., description="Search query.")
|
||||
|
||||
|
||||
|
||||
class ArxivSearchTool(BuiltinTool):
|
||||
"""
|
||||
A tool for searching articles on Arxiv.
|
||||
"""
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage | list[ToolInvokeMessage]:
|
||||
"""
|
||||
Invokes the Arxiv search tool with the given user ID and tool parameters.
|
||||
@@ -102,13 +106,13 @@ class ArxivSearchTool(BuiltinTool):
|
||||
Returns:
|
||||
ToolInvokeMessage | list[ToolInvokeMessage]: The result of the tool invocation, which can be a single message or a list of messages.
|
||||
"""
|
||||
query = tool_parameters.get('query', '')
|
||||
query = tool_parameters.get("query", "")
|
||||
|
||||
if not query:
|
||||
return self.create_text_message('Please input query')
|
||||
|
||||
return self.create_text_message("Please input query")
|
||||
|
||||
arxiv = ArxivAPIWrapper()
|
||||
|
||||
|
||||
response = arxiv.run(query)
|
||||
|
||||
|
||||
return self.create_text_message(self.summary(user_id=user_id, content=response))
|
||||
|
@@ -11,15 +11,14 @@ class SageMakerProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"sagemaker_endpoint" : "",
|
||||
"sagemaker_endpoint": "",
|
||||
"query": "misaka mikoto",
|
||||
"candidate_texts" : "hello$$$hello world",
|
||||
"topk" : 5,
|
||||
"aws_region" : ""
|
||||
"candidate_texts": "hello$$$hello world",
|
||||
"topk": 5,
|
||||
"aws_region": "",
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -12,6 +12,7 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuardrailParameters(BaseModel):
|
||||
guardrail_id: str = Field(..., description="The identifier of the guardrail")
|
||||
guardrail_version: str = Field(..., description="The version of the guardrail")
|
||||
@@ -19,35 +20,35 @@ class GuardrailParameters(BaseModel):
|
||||
text: str = Field(..., description="The text to apply the guardrail to")
|
||||
aws_region: str = Field(..., description="AWS region for the Bedrock client")
|
||||
|
||||
|
||||
class ApplyGuardrailTool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
Invoke the ApplyGuardrail tool
|
||||
"""
|
||||
try:
|
||||
# Validate and parse input parameters
|
||||
params = GuardrailParameters(**tool_parameters)
|
||||
|
||||
|
||||
# Initialize AWS client
|
||||
bedrock_client = boto3.client('bedrock-runtime', region_name=params.aws_region)
|
||||
bedrock_client = boto3.client("bedrock-runtime", region_name=params.aws_region)
|
||||
|
||||
# Apply guardrail
|
||||
response = bedrock_client.apply_guardrail(
|
||||
guardrailIdentifier=params.guardrail_id,
|
||||
guardrailVersion=params.guardrail_version,
|
||||
source=params.source,
|
||||
content=[{"text": {"text": params.text}}]
|
||||
content=[{"text": {"text": params.text}}],
|
||||
)
|
||||
|
||||
|
||||
logger.info(f"Raw response from AWS: {json.dumps(response, indent=2)}")
|
||||
|
||||
# Check for empty response
|
||||
if not response:
|
||||
return self.create_text_message(text="Received empty response from AWS Bedrock.")
|
||||
|
||||
|
||||
# Process the result
|
||||
action = response.get("action", "No action specified")
|
||||
outputs = response.get("outputs", [])
|
||||
@@ -58,9 +59,11 @@ class ApplyGuardrailTool(BuiltinTool):
|
||||
formatted_assessments = []
|
||||
for assessment in assessments:
|
||||
for policy_type, policy_data in assessment.items():
|
||||
if isinstance(policy_data, dict) and 'topics' in policy_data:
|
||||
for topic in policy_data['topics']:
|
||||
formatted_assessments.append(f"Policy: {policy_type}, Topic: {topic['name']}, Type: {topic['type']}, Action: {topic['action']}")
|
||||
if isinstance(policy_data, dict) and "topics" in policy_data:
|
||||
for topic in policy_data["topics"]:
|
||||
formatted_assessments.append(
|
||||
f"Policy: {policy_type}, Topic: {topic['name']}, Type: {topic['type']}, Action: {topic['action']}"
|
||||
)
|
||||
else:
|
||||
formatted_assessments.append(f"Policy: {policy_type}, Data: {policy_data}")
|
||||
|
||||
@@ -68,19 +71,19 @@ class ApplyGuardrailTool(BuiltinTool):
|
||||
result += f"Output: {output}\n "
|
||||
if formatted_assessments:
|
||||
result += "Assessments:\n " + "\n ".join(formatted_assessments) + "\n "
|
||||
# result += f"Full response: {json.dumps(response, indent=2, ensure_ascii=False)}"
|
||||
# result += f"Full response: {json.dumps(response, indent=2, ensure_ascii=False)}"
|
||||
|
||||
return self.create_text_message(text=result)
|
||||
|
||||
except BotoCoreError as e:
|
||||
error_message = f'AWS service error: {str(e)}'
|
||||
error_message = f"AWS service error: {str(e)}"
|
||||
logger.error(error_message, exc_info=True)
|
||||
return self.create_text_message(text=error_message)
|
||||
except json.JSONDecodeError as e:
|
||||
error_message = f'JSON parsing error: {str(e)}'
|
||||
error_message = f"JSON parsing error: {str(e)}"
|
||||
logger.error(error_message, exc_info=True)
|
||||
return self.create_text_message(text=error_message)
|
||||
except Exception as e:
|
||||
error_message = f'An unexpected error occurred: {str(e)}'
|
||||
error_message = f"An unexpected error occurred: {str(e)}"
|
||||
logger.error(error_message, exc_info=True)
|
||||
return self.create_text_message(text=error_message)
|
||||
return self.create_text_message(text=error_message)
|
||||
|
@@ -11,78 +11,81 @@ class LambdaTranslateUtilsTool(BuiltinTool):
|
||||
lambda_client: Any = None
|
||||
|
||||
def _invoke_lambda(self, text_content, src_lang, dest_lang, model_id, dictionary_name, request_type, lambda_name):
|
||||
msg = {
|
||||
"src_content":text_content,
|
||||
"src_lang": src_lang,
|
||||
"dest_lang":dest_lang,
|
||||
msg = {
|
||||
"src_content": text_content,
|
||||
"src_lang": src_lang,
|
||||
"dest_lang": dest_lang,
|
||||
"dictionary_id": dictionary_name,
|
||||
"request_type" : request_type,
|
||||
"model_id" : model_id
|
||||
"request_type": request_type,
|
||||
"model_id": model_id,
|
||||
}
|
||||
|
||||
invoke_response = self.lambda_client.invoke(FunctionName=lambda_name,
|
||||
InvocationType='RequestResponse',
|
||||
Payload=json.dumps(msg))
|
||||
response_body = invoke_response['Payload']
|
||||
invoke_response = self.lambda_client.invoke(
|
||||
FunctionName=lambda_name, InvocationType="RequestResponse", Payload=json.dumps(msg)
|
||||
)
|
||||
response_body = invoke_response["Payload"]
|
||||
|
||||
response_str = response_body.read().decode("unicode_escape")
|
||||
|
||||
return response_str
|
||||
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
line = 0
|
||||
try:
|
||||
if not self.lambda_client:
|
||||
aws_region = tool_parameters.get('aws_region')
|
||||
aws_region = tool_parameters.get("aws_region")
|
||||
if aws_region:
|
||||
self.lambda_client = boto3.client("lambda", region_name=aws_region)
|
||||
else:
|
||||
self.lambda_client = boto3.client("lambda")
|
||||
|
||||
line = 1
|
||||
text_content = tool_parameters.get('text_content', '')
|
||||
text_content = tool_parameters.get("text_content", "")
|
||||
if not text_content:
|
||||
return self.create_text_message('Please input text_content')
|
||||
|
||||
return self.create_text_message("Please input text_content")
|
||||
|
||||
line = 2
|
||||
src_lang = tool_parameters.get('src_lang', '')
|
||||
src_lang = tool_parameters.get("src_lang", "")
|
||||
if not src_lang:
|
||||
return self.create_text_message('Please input src_lang')
|
||||
|
||||
return self.create_text_message("Please input src_lang")
|
||||
|
||||
line = 3
|
||||
dest_lang = tool_parameters.get('dest_lang', '')
|
||||
dest_lang = tool_parameters.get("dest_lang", "")
|
||||
if not dest_lang:
|
||||
return self.create_text_message('Please input dest_lang')
|
||||
|
||||
return self.create_text_message("Please input dest_lang")
|
||||
|
||||
line = 4
|
||||
lambda_name = tool_parameters.get('lambda_name', '')
|
||||
lambda_name = tool_parameters.get("lambda_name", "")
|
||||
if not lambda_name:
|
||||
return self.create_text_message('Please input lambda_name')
|
||||
|
||||
return self.create_text_message("Please input lambda_name")
|
||||
|
||||
line = 5
|
||||
request_type = tool_parameters.get('request_type', '')
|
||||
request_type = tool_parameters.get("request_type", "")
|
||||
if not request_type:
|
||||
return self.create_text_message('Please input request_type')
|
||||
|
||||
return self.create_text_message("Please input request_type")
|
||||
|
||||
line = 6
|
||||
model_id = tool_parameters.get('model_id', '')
|
||||
model_id = tool_parameters.get("model_id", "")
|
||||
if not model_id:
|
||||
return self.create_text_message('Please input model_id')
|
||||
return self.create_text_message("Please input model_id")
|
||||
|
||||
line = 7
|
||||
dictionary_name = tool_parameters.get('dictionary_name', '')
|
||||
dictionary_name = tool_parameters.get("dictionary_name", "")
|
||||
if not dictionary_name:
|
||||
return self.create_text_message('Please input dictionary_name')
|
||||
|
||||
result = self._invoke_lambda(text_content, src_lang, dest_lang, model_id, dictionary_name, request_type, lambda_name)
|
||||
return self.create_text_message("Please input dictionary_name")
|
||||
|
||||
result = self._invoke_lambda(
|
||||
text_content, src_lang, dest_lang, model_id, dictionary_name, request_type, lambda_name
|
||||
)
|
||||
|
||||
return self.create_text_message(text=result)
|
||||
|
||||
except Exception as e:
|
||||
return self.create_text_message(f'Exception {str(e)}, line : {line}')
|
||||
return self.create_text_message(f"Exception {str(e)}, line : {line}")
|
||||
|
@@ -18,54 +18,53 @@ class LambdaYamlToJsonTool(BuiltinTool):
|
||||
lambda_client: Any = None
|
||||
|
||||
def _invoke_lambda(self, lambda_name: str, yaml_content: str) -> str:
|
||||
msg = {
|
||||
"body": yaml_content
|
||||
}
|
||||
msg = {"body": yaml_content}
|
||||
logger.info(json.dumps(msg))
|
||||
|
||||
invoke_response = self.lambda_client.invoke(FunctionName=lambda_name,
|
||||
InvocationType='RequestResponse',
|
||||
Payload=json.dumps(msg))
|
||||
response_body = invoke_response['Payload']
|
||||
invoke_response = self.lambda_client.invoke(
|
||||
FunctionName=lambda_name, InvocationType="RequestResponse", Payload=json.dumps(msg)
|
||||
)
|
||||
response_body = invoke_response["Payload"]
|
||||
|
||||
response_str = response_body.read().decode("utf-8")
|
||||
resp_json = json.loads(response_str)
|
||||
|
||||
logger.info(resp_json)
|
||||
if resp_json['statusCode'] != 200:
|
||||
if resp_json["statusCode"] != 200:
|
||||
raise Exception(f"Invalid status code: {response_str}")
|
||||
|
||||
return resp_json['body']
|
||||
return resp_json["body"]
|
||||
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
try:
|
||||
if not self.lambda_client:
|
||||
aws_region = tool_parameters.get('aws_region') # todo: move aws_region out, and update client region
|
||||
aws_region = tool_parameters.get("aws_region") # todo: move aws_region out, and update client region
|
||||
if aws_region:
|
||||
self.lambda_client = boto3.client("lambda", region_name=aws_region)
|
||||
else:
|
||||
self.lambda_client = boto3.client("lambda")
|
||||
|
||||
yaml_content = tool_parameters.get('yaml_content', '')
|
||||
yaml_content = tool_parameters.get("yaml_content", "")
|
||||
if not yaml_content:
|
||||
return self.create_text_message('Please input yaml_content')
|
||||
return self.create_text_message("Please input yaml_content")
|
||||
|
||||
lambda_name = tool_parameters.get('lambda_name', '')
|
||||
lambda_name = tool_parameters.get("lambda_name", "")
|
||||
if not lambda_name:
|
||||
return self.create_text_message('Please input lambda_name')
|
||||
logger.debug(f'{json.dumps(tool_parameters, indent=2, ensure_ascii=False)}')
|
||||
|
||||
return self.create_text_message("Please input lambda_name")
|
||||
logger.debug(f"{json.dumps(tool_parameters, indent=2, ensure_ascii=False)}")
|
||||
|
||||
result = self._invoke_lambda(lambda_name, yaml_content)
|
||||
logger.debug(result)
|
||||
|
||||
|
||||
return self.create_text_message(result)
|
||||
except Exception as e:
|
||||
return self.create_text_message(f'Exception: {str(e)}')
|
||||
return self.create_text_message(f"Exception: {str(e)}")
|
||||
|
||||
console_handler.flush()
|
||||
console_handler.flush()
|
||||
|
@@ -9,37 +9,33 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
class SageMakerReRankTool(BuiltinTool):
|
||||
sagemaker_client: Any = None
|
||||
sagemaker_endpoint:str = None
|
||||
topk:int = None
|
||||
sagemaker_endpoint: str = None
|
||||
topk: int = None
|
||||
|
||||
def _sagemaker_rerank(self, query_input: str, docs: list[str], rerank_endpoint:str):
|
||||
inputs = [query_input]*len(docs)
|
||||
def _sagemaker_rerank(self, query_input: str, docs: list[str], rerank_endpoint: str):
|
||||
inputs = [query_input] * len(docs)
|
||||
response_model = self.sagemaker_client.invoke_endpoint(
|
||||
EndpointName=rerank_endpoint,
|
||||
Body=json.dumps(
|
||||
{
|
||||
"inputs": inputs,
|
||||
"docs": docs
|
||||
}
|
||||
),
|
||||
Body=json.dumps({"inputs": inputs, "docs": docs}),
|
||||
ContentType="application/json",
|
||||
)
|
||||
json_str = response_model['Body'].read().decode('utf8')
|
||||
json_str = response_model["Body"].read().decode("utf8")
|
||||
json_obj = json.loads(json_str)
|
||||
scores = json_obj['scores']
|
||||
scores = json_obj["scores"]
|
||||
return scores if isinstance(scores, list) else [scores]
|
||||
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
line = 0
|
||||
try:
|
||||
if not self.sagemaker_client:
|
||||
aws_region = tool_parameters.get('aws_region')
|
||||
aws_region = tool_parameters.get("aws_region")
|
||||
if aws_region:
|
||||
self.sagemaker_client = boto3.client("sagemaker-runtime", region_name=aws_region)
|
||||
else:
|
||||
@@ -47,25 +43,25 @@ class SageMakerReRankTool(BuiltinTool):
|
||||
|
||||
line = 1
|
||||
if not self.sagemaker_endpoint:
|
||||
self.sagemaker_endpoint = tool_parameters.get('sagemaker_endpoint')
|
||||
self.sagemaker_endpoint = tool_parameters.get("sagemaker_endpoint")
|
||||
|
||||
line = 2
|
||||
if not self.topk:
|
||||
self.topk = tool_parameters.get('topk', 5)
|
||||
self.topk = tool_parameters.get("topk", 5)
|
||||
|
||||
line = 3
|
||||
query = tool_parameters.get('query', '')
|
||||
query = tool_parameters.get("query", "")
|
||||
if not query:
|
||||
return self.create_text_message('Please input query')
|
||||
|
||||
return self.create_text_message("Please input query")
|
||||
|
||||
line = 4
|
||||
candidate_texts = tool_parameters.get('candidate_texts')
|
||||
candidate_texts = tool_parameters.get("candidate_texts")
|
||||
if not candidate_texts:
|
||||
return self.create_text_message('Please input candidate_texts')
|
||||
|
||||
return self.create_text_message("Please input candidate_texts")
|
||||
|
||||
line = 5
|
||||
candidate_docs = json.loads(candidate_texts)
|
||||
docs = [ item.get('content') for item in candidate_docs ]
|
||||
docs = [item.get("content") for item in candidate_docs]
|
||||
|
||||
line = 6
|
||||
scores = self._sagemaker_rerank(query_input=query, docs=docs, rerank_endpoint=self.sagemaker_endpoint)
|
||||
@@ -75,10 +71,10 @@ class SageMakerReRankTool(BuiltinTool):
|
||||
candidate_docs[idx]["score"] = scores[idx]
|
||||
|
||||
line = 8
|
||||
sorted_candidate_docs = sorted(candidate_docs, key=lambda x: x['score'], reverse=True)
|
||||
sorted_candidate_docs = sorted(candidate_docs, key=lambda x: x["score"], reverse=True)
|
||||
|
||||
line = 9
|
||||
return [ self.create_json_message(res) for res in sorted_candidate_docs[:self.topk] ]
|
||||
|
||||
return [self.create_json_message(res) for res in sorted_candidate_docs[: self.topk]]
|
||||
|
||||
except Exception as e:
|
||||
return self.create_text_message(f'Exception {str(e)}, line : {line}')
|
||||
return self.create_text_message(f"Exception {str(e)}, line : {line}")
|
||||
|
@@ -14,82 +14,88 @@ class TTSModelType(Enum):
|
||||
CloneVoice_CrossLingual = "CloneVoice_CrossLingual"
|
||||
InstructVoice = "InstructVoice"
|
||||
|
||||
|
||||
class SageMakerTTSTool(BuiltinTool):
|
||||
sagemaker_client: Any = None
|
||||
sagemaker_endpoint:str = None
|
||||
s3_client : Any = None
|
||||
comprehend_client : Any = None
|
||||
sagemaker_endpoint: str = None
|
||||
s3_client: Any = None
|
||||
comprehend_client: Any = None
|
||||
|
||||
def _detect_lang_code(self, content:str, map_dict:dict=None):
|
||||
map_dict = {
|
||||
"zh" : "<|zh|>",
|
||||
"en" : "<|en|>",
|
||||
"ja" : "<|jp|>",
|
||||
"zh-TW" : "<|yue|>",
|
||||
"ko" : "<|ko|>"
|
||||
}
|
||||
def _detect_lang_code(self, content: str, map_dict: dict = None):
|
||||
map_dict = {"zh": "<|zh|>", "en": "<|en|>", "ja": "<|jp|>", "zh-TW": "<|yue|>", "ko": "<|ko|>"}
|
||||
|
||||
response = self.comprehend_client.detect_dominant_language(Text=content)
|
||||
language_code = response['Languages'][0]['LanguageCode']
|
||||
return map_dict.get(language_code, '<|zh|>')
|
||||
language_code = response["Languages"][0]["LanguageCode"]
|
||||
return map_dict.get(language_code, "<|zh|>")
|
||||
|
||||
def _build_tts_payload(self, model_type:str, content_text:str, model_role:str, prompt_text:str, prompt_audio:str, instruct_text:str):
|
||||
def _build_tts_payload(
|
||||
self,
|
||||
model_type: str,
|
||||
content_text: str,
|
||||
model_role: str,
|
||||
prompt_text: str,
|
||||
prompt_audio: str,
|
||||
instruct_text: str,
|
||||
):
|
||||
if model_type == TTSModelType.PresetVoice.value and model_role:
|
||||
return { "tts_text" : content_text, "role" : model_role }
|
||||
return {"tts_text": content_text, "role": model_role}
|
||||
if model_type == TTSModelType.CloneVoice.value and prompt_text and prompt_audio:
|
||||
return { "tts_text" : content_text, "prompt_text": prompt_text, "prompt_audio" : prompt_audio }
|
||||
if model_type == TTSModelType.CloneVoice_CrossLingual.value and prompt_audio:
|
||||
return {"tts_text": content_text, "prompt_text": prompt_text, "prompt_audio": prompt_audio}
|
||||
if model_type == TTSModelType.CloneVoice_CrossLingual.value and prompt_audio:
|
||||
lang_tag = self._detect_lang_code(content_text)
|
||||
return { "tts_text" : f"{content_text}", "prompt_audio" : prompt_audio, "lang_tag" : lang_tag }
|
||||
if model_type == TTSModelType.InstructVoice.value and instruct_text and model_role:
|
||||
return { "tts_text" : content_text, "role" : model_role, "instruct_text" : instruct_text }
|
||||
return {"tts_text": f"{content_text}", "prompt_audio": prompt_audio, "lang_tag": lang_tag}
|
||||
if model_type == TTSModelType.InstructVoice.value and instruct_text and model_role:
|
||||
return {"tts_text": content_text, "role": model_role, "instruct_text": instruct_text}
|
||||
|
||||
raise RuntimeError(f"Invalid params for {model_type}")
|
||||
|
||||
def _invoke_sagemaker(self, payload:dict, endpoint:str):
|
||||
def _invoke_sagemaker(self, payload: dict, endpoint: str):
|
||||
response_model = self.sagemaker_client.invoke_endpoint(
|
||||
EndpointName=endpoint,
|
||||
Body=json.dumps(payload),
|
||||
ContentType="application/json",
|
||||
)
|
||||
json_str = response_model['Body'].read().decode('utf8')
|
||||
json_str = response_model["Body"].read().decode("utf8")
|
||||
json_obj = json.loads(json_str)
|
||||
return json_obj
|
||||
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
try:
|
||||
if not self.sagemaker_client:
|
||||
aws_region = tool_parameters.get('aws_region')
|
||||
aws_region = tool_parameters.get("aws_region")
|
||||
if aws_region:
|
||||
self.sagemaker_client = boto3.client("sagemaker-runtime", region_name=aws_region)
|
||||
self.s3_client = boto3.client("s3", region_name=aws_region)
|
||||
self.comprehend_client = boto3.client('comprehend', region_name=aws_region)
|
||||
self.comprehend_client = boto3.client("comprehend", region_name=aws_region)
|
||||
else:
|
||||
self.sagemaker_client = boto3.client("sagemaker-runtime")
|
||||
self.s3_client = boto3.client("s3")
|
||||
self.comprehend_client = boto3.client('comprehend')
|
||||
self.comprehend_client = boto3.client("comprehend")
|
||||
|
||||
if not self.sagemaker_endpoint:
|
||||
self.sagemaker_endpoint = tool_parameters.get('sagemaker_endpoint')
|
||||
self.sagemaker_endpoint = tool_parameters.get("sagemaker_endpoint")
|
||||
|
||||
tts_text = tool_parameters.get('tts_text')
|
||||
tts_infer_type = tool_parameters.get('tts_infer_type')
|
||||
tts_text = tool_parameters.get("tts_text")
|
||||
tts_infer_type = tool_parameters.get("tts_infer_type")
|
||||
|
||||
voice = tool_parameters.get('voice')
|
||||
mock_voice_audio = tool_parameters.get('mock_voice_audio')
|
||||
mock_voice_text = tool_parameters.get('mock_voice_text')
|
||||
voice_instruct_prompt = tool_parameters.get('voice_instruct_prompt')
|
||||
payload = self._build_tts_payload(tts_infer_type, tts_text, voice, mock_voice_text, mock_voice_audio, voice_instruct_prompt)
|
||||
voice = tool_parameters.get("voice")
|
||||
mock_voice_audio = tool_parameters.get("mock_voice_audio")
|
||||
mock_voice_text = tool_parameters.get("mock_voice_text")
|
||||
voice_instruct_prompt = tool_parameters.get("voice_instruct_prompt")
|
||||
payload = self._build_tts_payload(
|
||||
tts_infer_type, tts_text, voice, mock_voice_text, mock_voice_audio, voice_instruct_prompt
|
||||
)
|
||||
|
||||
result = self._invoke_sagemaker(payload, self.sagemaker_endpoint)
|
||||
|
||||
return self.create_text_message(text=result['s3_presign_url'])
|
||||
|
||||
return self.create_text_message(text=result["s3_presign_url"])
|
||||
|
||||
except Exception as e:
|
||||
return self.create_text_message(f'Exception {str(e)}')
|
||||
return self.create_text_message(f"Exception {str(e)}")
|
||||
|
@@ -13,12 +13,8 @@ class AzureDALLEProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
tool_parameters={
|
||||
"prompt": "cute girl, blue eyes, white hair, anime style",
|
||||
"size": "square",
|
||||
"n": 1
|
||||
},
|
||||
user_id="",
|
||||
tool_parameters={"prompt": "cute girl, blue eyes, white hair, anime style", "size": "square", "n": 1},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -9,47 +9,48 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class DallE3Tool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
client = AzureOpenAI(
|
||||
api_version=self.runtime.credentials['azure_openai_api_version'],
|
||||
azure_endpoint=self.runtime.credentials['azure_openai_base_url'],
|
||||
api_key=self.runtime.credentials['azure_openai_api_key'],
|
||||
api_version=self.runtime.credentials["azure_openai_api_version"],
|
||||
azure_endpoint=self.runtime.credentials["azure_openai_base_url"],
|
||||
api_key=self.runtime.credentials["azure_openai_api_key"],
|
||||
)
|
||||
|
||||
SIZE_MAPPING = {
|
||||
'square': '1024x1024',
|
||||
'vertical': '1024x1792',
|
||||
'horizontal': '1792x1024',
|
||||
"square": "1024x1024",
|
||||
"vertical": "1024x1792",
|
||||
"horizontal": "1792x1024",
|
||||
}
|
||||
|
||||
# prompt
|
||||
prompt = tool_parameters.get('prompt', '')
|
||||
prompt = tool_parameters.get("prompt", "")
|
||||
if not prompt:
|
||||
return self.create_text_message('Please input prompt')
|
||||
return self.create_text_message("Please input prompt")
|
||||
# get size
|
||||
size = SIZE_MAPPING[tool_parameters.get('size', 'square')]
|
||||
size = SIZE_MAPPING[tool_parameters.get("size", "square")]
|
||||
# get n
|
||||
n = tool_parameters.get('n', 1)
|
||||
n = tool_parameters.get("n", 1)
|
||||
# get quality
|
||||
quality = tool_parameters.get('quality', 'standard')
|
||||
if quality not in ['standard', 'hd']:
|
||||
return self.create_text_message('Invalid quality')
|
||||
quality = tool_parameters.get("quality", "standard")
|
||||
if quality not in ["standard", "hd"]:
|
||||
return self.create_text_message("Invalid quality")
|
||||
# get style
|
||||
style = tool_parameters.get('style', 'vivid')
|
||||
if style not in ['natural', 'vivid']:
|
||||
return self.create_text_message('Invalid style')
|
||||
style = tool_parameters.get("style", "vivid")
|
||||
if style not in ["natural", "vivid"]:
|
||||
return self.create_text_message("Invalid style")
|
||||
# set extra body
|
||||
seed_id = tool_parameters.get('seed_id', self._generate_random_id(8))
|
||||
extra_body = {'seed': seed_id}
|
||||
seed_id = tool_parameters.get("seed_id", self._generate_random_id(8))
|
||||
extra_body = {"seed": seed_id}
|
||||
|
||||
# call openapi dalle3
|
||||
model = self.runtime.credentials['azure_openai_api_model_name']
|
||||
model = self.runtime.credentials["azure_openai_api_model_name"]
|
||||
response = client.images.generate(
|
||||
prompt=prompt,
|
||||
model=model,
|
||||
@@ -58,21 +59,25 @@ class DallE3Tool(BuiltinTool):
|
||||
extra_body=extra_body,
|
||||
style=style,
|
||||
quality=quality,
|
||||
response_format='b64_json'
|
||||
response_format="b64_json",
|
||||
)
|
||||
|
||||
result = []
|
||||
|
||||
for image in response.data:
|
||||
result.append(self.create_blob_message(blob=b64decode(image.b64_json),
|
||||
meta={'mime_type': 'image/png'},
|
||||
save_as=self.VARIABLE_KEY.IMAGE.value))
|
||||
result.append(self.create_text_message(f'\nGenerate image source to Seed ID: {seed_id}'))
|
||||
result.append(
|
||||
self.create_blob_message(
|
||||
blob=b64decode(image.b64_json),
|
||||
meta={"mime_type": "image/png"},
|
||||
save_as=self.VARIABLE_KEY.IMAGE.value,
|
||||
)
|
||||
)
|
||||
result.append(self.create_text_message(f"\nGenerate image source to Seed ID: {seed_id}"))
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _generate_random_id(length=8):
|
||||
characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
random_id = ''.join(random.choices(characters, k=length))
|
||||
characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
random_id = "".join(random.choices(characters, k=length))
|
||||
return random_id
|
||||
|
@@ -8,142 +8,135 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class BingSearchTool(BuiltinTool):
|
||||
url: str = 'https://api.bing.microsoft.com/v7.0/search'
|
||||
url: str = "https://api.bing.microsoft.com/v7.0/search"
|
||||
|
||||
def _invoke_bing(self,
|
||||
user_id: str,
|
||||
server_url: str,
|
||||
subscription_key: str, query: str, limit: int,
|
||||
result_type: str, market: str, lang: str,
|
||||
filters: list[str]) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke_bing(
|
||||
self,
|
||||
user_id: str,
|
||||
server_url: str,
|
||||
subscription_key: str,
|
||||
query: str,
|
||||
limit: int,
|
||||
result_type: str,
|
||||
market: str,
|
||||
lang: str,
|
||||
filters: list[str],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke bing search
|
||||
invoke bing search
|
||||
"""
|
||||
market_code = f'{lang}-{market}'
|
||||
accept_language = f'{lang},{market_code};q=0.9'
|
||||
headers = {
|
||||
'Ocp-Apim-Subscription-Key': subscription_key,
|
||||
'Accept-Language': accept_language
|
||||
}
|
||||
market_code = f"{lang}-{market}"
|
||||
accept_language = f"{lang},{market_code};q=0.9"
|
||||
headers = {"Ocp-Apim-Subscription-Key": subscription_key, "Accept-Language": accept_language}
|
||||
|
||||
query = quote(query)
|
||||
server_url = f'{server_url}?q={query}&mkt={market_code}&count={limit}&responseFilter={",".join(filters)}'
|
||||
response = get(server_url, headers=headers)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f'Error {response.status_code}: {response.text}')
|
||||
|
||||
response = response.json()
|
||||
search_results = response['webPages']['value'][:limit] if 'webPages' in response else []
|
||||
related_searches = response['relatedSearches']['value'] if 'relatedSearches' in response else []
|
||||
entities = response['entities']['value'] if 'entities' in response else []
|
||||
news = response['news']['value'] if 'news' in response else []
|
||||
computation = response['computation']['value'] if 'computation' in response else None
|
||||
raise Exception(f"Error {response.status_code}: {response.text}")
|
||||
|
||||
if result_type == 'link':
|
||||
response = response.json()
|
||||
search_results = response["webPages"]["value"][:limit] if "webPages" in response else []
|
||||
related_searches = response["relatedSearches"]["value"] if "relatedSearches" in response else []
|
||||
entities = response["entities"]["value"] if "entities" in response else []
|
||||
news = response["news"]["value"] if "news" in response else []
|
||||
computation = response["computation"]["value"] if "computation" in response else None
|
||||
|
||||
if result_type == "link":
|
||||
results = []
|
||||
if search_results:
|
||||
for result in search_results:
|
||||
url = f': {result["url"]}' if "url" in result else ""
|
||||
results.append(self.create_text_message(
|
||||
text=f'{result["name"]}{url}'
|
||||
))
|
||||
|
||||
results.append(self.create_text_message(text=f'{result["name"]}{url}'))
|
||||
|
||||
if entities:
|
||||
for entity in entities:
|
||||
url = f': {entity["url"]}' if "url" in entity else ""
|
||||
results.append(self.create_text_message(
|
||||
text=f'{entity.get("name", "")}{url}'
|
||||
))
|
||||
results.append(self.create_text_message(text=f'{entity.get("name", "")}{url}'))
|
||||
|
||||
if news:
|
||||
for news_item in news:
|
||||
url = f': {news_item["url"]}' if "url" in news_item else ""
|
||||
results.append(self.create_text_message(
|
||||
text=f'{news_item.get("name", "")}{url}'
|
||||
))
|
||||
results.append(self.create_text_message(text=f'{news_item.get("name", "")}{url}'))
|
||||
|
||||
if related_searches:
|
||||
for related in related_searches:
|
||||
url = f': {related["displayText"]}' if "displayText" in related else ""
|
||||
results.append(self.create_text_message(
|
||||
text=f'{related.get("displayText", "")}{url}'
|
||||
))
|
||||
|
||||
results.append(self.create_text_message(text=f'{related.get("displayText", "")}{url}'))
|
||||
|
||||
return results
|
||||
else:
|
||||
# construct text
|
||||
text = ''
|
||||
text = ""
|
||||
if search_results:
|
||||
for i, result in enumerate(search_results):
|
||||
text += f'{i+1}: {result.get("name", "")} - {result.get("snippet", "")}\n'
|
||||
|
||||
if computation and 'expression' in computation and 'value' in computation:
|
||||
text += '\nComputation:\n'
|
||||
if computation and "expression" in computation and "value" in computation:
|
||||
text += "\nComputation:\n"
|
||||
text += f'{computation["expression"]} = {computation["value"]}\n'
|
||||
|
||||
if entities:
|
||||
text += '\nEntities:\n'
|
||||
text += "\nEntities:\n"
|
||||
for entity in entities:
|
||||
url = f'- {entity["url"]}' if "url" in entity else ""
|
||||
text += f'{entity.get("name", "")}{url}\n'
|
||||
|
||||
if news:
|
||||
text += '\nNews:\n'
|
||||
text += "\nNews:\n"
|
||||
for news_item in news:
|
||||
url = f'- {news_item["url"]}' if "url" in news_item else ""
|
||||
text += f'{news_item.get("name", "")}{url}\n'
|
||||
|
||||
if related_searches:
|
||||
text += '\n\nRelated Searches:\n'
|
||||
text += "\n\nRelated Searches:\n"
|
||||
for related in related_searches:
|
||||
url = f'- {related["webSearchUrl"]}' if "webSearchUrl" in related else ""
|
||||
text += f'{related.get("displayText", "")}{url}\n'
|
||||
|
||||
return self.create_text_message(text=self.summary(user_id=user_id, content=text))
|
||||
|
||||
|
||||
def validate_credentials(self, credentials: dict[str, Any], tool_parameters: dict[str, Any]) -> None:
|
||||
key = credentials.get('subscription_key')
|
||||
key = credentials.get("subscription_key")
|
||||
if not key:
|
||||
raise Exception('subscription_key is required')
|
||||
|
||||
server_url = credentials.get('server_url')
|
||||
raise Exception("subscription_key is required")
|
||||
|
||||
server_url = credentials.get("server_url")
|
||||
if not server_url:
|
||||
server_url = self.url
|
||||
|
||||
query = tool_parameters.get('query')
|
||||
query = tool_parameters.get("query")
|
||||
if not query:
|
||||
raise Exception('query is required')
|
||||
|
||||
limit = min(tool_parameters.get('limit', 5), 10)
|
||||
result_type = tool_parameters.get('result_type', 'text') or 'text'
|
||||
raise Exception("query is required")
|
||||
|
||||
market = tool_parameters.get('market', 'US')
|
||||
lang = tool_parameters.get('language', 'en')
|
||||
limit = min(tool_parameters.get("limit", 5), 10)
|
||||
result_type = tool_parameters.get("result_type", "text") or "text"
|
||||
|
||||
market = tool_parameters.get("market", "US")
|
||||
lang = tool_parameters.get("language", "en")
|
||||
filter = []
|
||||
|
||||
if credentials.get('allow_entities', False):
|
||||
filter.append('Entities')
|
||||
if credentials.get("allow_entities", False):
|
||||
filter.append("Entities")
|
||||
|
||||
if credentials.get('allow_computation', False):
|
||||
filter.append('Computation')
|
||||
if credentials.get("allow_computation", False):
|
||||
filter.append("Computation")
|
||||
|
||||
if credentials.get('allow_news', False):
|
||||
filter.append('News')
|
||||
if credentials.get("allow_news", False):
|
||||
filter.append("News")
|
||||
|
||||
if credentials.get('allow_related_searches', False):
|
||||
filter.append('RelatedSearches')
|
||||
if credentials.get("allow_related_searches", False):
|
||||
filter.append("RelatedSearches")
|
||||
|
||||
if credentials.get('allow_web_pages', False):
|
||||
filter.append('WebPages')
|
||||
if credentials.get("allow_web_pages", False):
|
||||
filter.append("WebPages")
|
||||
|
||||
if not filter:
|
||||
raise Exception('At least one filter is required')
|
||||
|
||||
raise Exception("At least one filter is required")
|
||||
|
||||
self._invoke_bing(
|
||||
user_id='test',
|
||||
user_id="test",
|
||||
server_url=server_url,
|
||||
subscription_key=key,
|
||||
query=query,
|
||||
@@ -151,50 +144,51 @@ class BingSearchTool(BuiltinTool):
|
||||
result_type=result_type,
|
||||
market=market,
|
||||
lang=lang,
|
||||
filters=filter
|
||||
filters=filter,
|
||||
)
|
||||
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
|
||||
key = self.runtime.credentials.get('subscription_key', None)
|
||||
key = self.runtime.credentials.get("subscription_key", None)
|
||||
if not key:
|
||||
raise Exception('subscription_key is required')
|
||||
|
||||
server_url = self.runtime.credentials.get('server_url', None)
|
||||
raise Exception("subscription_key is required")
|
||||
|
||||
server_url = self.runtime.credentials.get("server_url", None)
|
||||
if not server_url:
|
||||
server_url = self.url
|
||||
|
||||
query = tool_parameters.get('query')
|
||||
|
||||
query = tool_parameters.get("query")
|
||||
if not query:
|
||||
raise Exception('query is required')
|
||||
|
||||
limit = min(tool_parameters.get('limit', 5), 10)
|
||||
result_type = tool_parameters.get('result_type', 'text') or 'text'
|
||||
|
||||
market = tool_parameters.get('market', 'US')
|
||||
lang = tool_parameters.get('language', 'en')
|
||||
raise Exception("query is required")
|
||||
|
||||
limit = min(tool_parameters.get("limit", 5), 10)
|
||||
result_type = tool_parameters.get("result_type", "text") or "text"
|
||||
|
||||
market = tool_parameters.get("market", "US")
|
||||
lang = tool_parameters.get("language", "en")
|
||||
filter = []
|
||||
|
||||
if tool_parameters.get('enable_computation', False):
|
||||
filter.append('Computation')
|
||||
if tool_parameters.get('enable_entities', False):
|
||||
filter.append('Entities')
|
||||
if tool_parameters.get('enable_news', False):
|
||||
filter.append('News')
|
||||
if tool_parameters.get('enable_related_search', False):
|
||||
filter.append('RelatedSearches')
|
||||
if tool_parameters.get('enable_webpages', False):
|
||||
filter.append('WebPages')
|
||||
if tool_parameters.get("enable_computation", False):
|
||||
filter.append("Computation")
|
||||
if tool_parameters.get("enable_entities", False):
|
||||
filter.append("Entities")
|
||||
if tool_parameters.get("enable_news", False):
|
||||
filter.append("News")
|
||||
if tool_parameters.get("enable_related_search", False):
|
||||
filter.append("RelatedSearches")
|
||||
if tool_parameters.get("enable_webpages", False):
|
||||
filter.append("WebPages")
|
||||
|
||||
if not filter:
|
||||
raise Exception('At least one filter is required')
|
||||
|
||||
raise Exception("At least one filter is required")
|
||||
|
||||
return self._invoke_bing(
|
||||
user_id=user_id,
|
||||
server_url=server_url,
|
||||
@@ -204,5 +198,5 @@ class BingSearchTool(BuiltinTool):
|
||||
result_type=result_type,
|
||||
market=market,
|
||||
lang=lang,
|
||||
filters=filter
|
||||
)
|
||||
filters=filter,
|
||||
)
|
||||
|
@@ -13,11 +13,10 @@ class BraveProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"query": "Sachin Tendulkar",
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -37,7 +37,7 @@ class BraveSearchWrapper(BaseModel):
|
||||
for item in web_search_results
|
||||
]
|
||||
return json.dumps(final_results)
|
||||
|
||||
|
||||
def _search_request(self, query: str) -> list[dict]:
|
||||
headers = {
|
||||
"X-Subscription-Token": self.api_key,
|
||||
@@ -55,6 +55,7 @@ class BraveSearchWrapper(BaseModel):
|
||||
|
||||
return response.json().get("web", {}).get("results", [])
|
||||
|
||||
|
||||
class BraveSearch(BaseModel):
|
||||
"""Tool that queries the BraveSearch."""
|
||||
|
||||
@@ -67,9 +68,7 @@ class BraveSearch(BaseModel):
|
||||
search_wrapper: BraveSearchWrapper
|
||||
|
||||
@classmethod
|
||||
def from_api_key(
|
||||
cls, api_key: str, search_kwargs: Optional[dict] = None, **kwargs: Any
|
||||
) -> "BraveSearch":
|
||||
def from_api_key(cls, api_key: str, search_kwargs: Optional[dict] = None, **kwargs: Any) -> "BraveSearch":
|
||||
"""Create a tool from an api key.
|
||||
|
||||
Args:
|
||||
@@ -90,6 +89,7 @@ class BraveSearch(BaseModel):
|
||||
"""Use the tool."""
|
||||
return self.search_wrapper.run(query)
|
||||
|
||||
|
||||
class BraveSearchTool(BuiltinTool):
|
||||
"""
|
||||
Tool for performing a search using Brave search engine.
|
||||
@@ -106,12 +106,12 @@ class BraveSearchTool(BuiltinTool):
|
||||
Returns:
|
||||
ToolInvokeMessage | list[ToolInvokeMessage]: The result of the tool invocation.
|
||||
"""
|
||||
query = tool_parameters.get('query', '')
|
||||
count = tool_parameters.get('count', 3)
|
||||
api_key = self.runtime.credentials['brave_search_api_key']
|
||||
query = tool_parameters.get("query", "")
|
||||
count = tool_parameters.get("count", 3)
|
||||
api_key = self.runtime.credentials["brave_search_api_key"]
|
||||
|
||||
if not query:
|
||||
return self.create_text_message('Please input query')
|
||||
return self.create_text_message("Please input query")
|
||||
|
||||
tool = BraveSearch.from_api_key(api_key=api_key, search_kwargs={"count": count})
|
||||
|
||||
@@ -121,4 +121,3 @@ class BraveSearchTool(BuiltinTool):
|
||||
return self.create_text_message(f"No results found for '{query}' in Tavily")
|
||||
else:
|
||||
return self.create_text_message(text=results)
|
||||
|
||||
|
@@ -7,16 +7,34 @@ from core.tools.provider.builtin.chart.tools.line import LinearChartTool
|
||||
from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
|
||||
|
||||
# use a business theme
|
||||
plt.style.use('seaborn-v0_8-darkgrid')
|
||||
plt.rcParams['axes.unicode_minus'] = False
|
||||
plt.style.use("seaborn-v0_8-darkgrid")
|
||||
plt.rcParams["axes.unicode_minus"] = False
|
||||
|
||||
|
||||
def init_fonts():
|
||||
fonts = findSystemFonts()
|
||||
|
||||
popular_unicode_fonts = [
|
||||
'Arial Unicode MS', 'DejaVu Sans', 'DejaVu Sans Mono', 'DejaVu Serif', 'FreeMono', 'FreeSans', 'FreeSerif',
|
||||
'Liberation Mono', 'Liberation Sans', 'Liberation Serif', 'Noto Mono', 'Noto Sans', 'Noto Serif', 'Open Sans',
|
||||
'Roboto', 'Source Code Pro', 'Source Sans Pro', 'Source Serif Pro', 'Ubuntu', 'Ubuntu Mono'
|
||||
"Arial Unicode MS",
|
||||
"DejaVu Sans",
|
||||
"DejaVu Sans Mono",
|
||||
"DejaVu Serif",
|
||||
"FreeMono",
|
||||
"FreeSans",
|
||||
"FreeSerif",
|
||||
"Liberation Mono",
|
||||
"Liberation Sans",
|
||||
"Liberation Serif",
|
||||
"Noto Mono",
|
||||
"Noto Sans",
|
||||
"Noto Serif",
|
||||
"Open Sans",
|
||||
"Roboto",
|
||||
"Source Code Pro",
|
||||
"Source Sans Pro",
|
||||
"Source Serif Pro",
|
||||
"Ubuntu",
|
||||
"Ubuntu Mono",
|
||||
]
|
||||
|
||||
supported_fonts = []
|
||||
@@ -25,21 +43,23 @@ def init_fonts():
|
||||
try:
|
||||
font = TTFont(font_path)
|
||||
# get family name
|
||||
family_name = font['name'].getName(1, 3, 1).toUnicode()
|
||||
family_name = font["name"].getName(1, 3, 1).toUnicode()
|
||||
if family_name in popular_unicode_fonts:
|
||||
supported_fonts.append(family_name)
|
||||
except:
|
||||
pass
|
||||
|
||||
plt.rcParams['font.family'] = 'sans-serif'
|
||||
plt.rcParams["font.family"] = "sans-serif"
|
||||
# sort by order of popular_unicode_fonts
|
||||
for font in popular_unicode_fonts:
|
||||
if font in supported_fonts:
|
||||
plt.rcParams['font.sans-serif'] = font
|
||||
plt.rcParams["font.sans-serif"] = font
|
||||
break
|
||||
|
||||
|
||||
|
||||
init_fonts()
|
||||
|
||||
|
||||
class ChartProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict) -> None:
|
||||
try:
|
||||
@@ -48,11 +68,10 @@ class ChartProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"data": "1,3,5,7,9,2,4,6,8,10",
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -8,12 +8,13 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class BarChartTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) \
|
||||
-> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
data = tool_parameters.get('data', '')
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
data = tool_parameters.get("data", "")
|
||||
if not data:
|
||||
return self.create_text_message('Please input data')
|
||||
data = data.split(';')
|
||||
return self.create_text_message("Please input data")
|
||||
data = data.split(";")
|
||||
|
||||
# if all data is int, convert to int
|
||||
if all(i.isdigit() for i in data):
|
||||
@@ -21,29 +22,27 @@ class BarChartTool(BuiltinTool):
|
||||
else:
|
||||
data = [float(i) for i in data]
|
||||
|
||||
axis = tool_parameters.get('x_axis') or None
|
||||
axis = tool_parameters.get("x_axis") or None
|
||||
if axis:
|
||||
axis = axis.split(';')
|
||||
axis = axis.split(";")
|
||||
if len(axis) != len(data):
|
||||
axis = None
|
||||
|
||||
flg, ax = plt.subplots(figsize=(10, 8))
|
||||
|
||||
if axis:
|
||||
axis = [label[:10] + '...' if len(label) > 10 else label for label in axis]
|
||||
ax.set_xticklabels(axis, rotation=45, ha='right')
|
||||
axis = [label[:10] + "..." if len(label) > 10 else label for label in axis]
|
||||
ax.set_xticklabels(axis, rotation=45, ha="right")
|
||||
ax.bar(axis, data)
|
||||
else:
|
||||
ax.bar(range(len(data)), data)
|
||||
|
||||
buf = io.BytesIO()
|
||||
flg.savefig(buf, format='png')
|
||||
flg.savefig(buf, format="png")
|
||||
buf.seek(0)
|
||||
plt.close(flg)
|
||||
|
||||
return [
|
||||
self.create_text_message('the bar chart is saved as an image.'),
|
||||
self.create_blob_message(blob=buf.read(),
|
||||
meta={'mime_type': 'image/png'})
|
||||
self.create_text_message("the bar chart is saved as an image."),
|
||||
self.create_blob_message(blob=buf.read(), meta={"mime_type": "image/png"}),
|
||||
]
|
||||
|
@@ -8,18 +8,19 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class LinearChartTool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
data = tool_parameters.get('data', '')
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
data = tool_parameters.get("data", "")
|
||||
if not data:
|
||||
return self.create_text_message('Please input data')
|
||||
data = data.split(';')
|
||||
return self.create_text_message("Please input data")
|
||||
data = data.split(";")
|
||||
|
||||
axis = tool_parameters.get('x_axis') or None
|
||||
axis = tool_parameters.get("x_axis") or None
|
||||
if axis:
|
||||
axis = axis.split(';')
|
||||
axis = axis.split(";")
|
||||
if len(axis) != len(data):
|
||||
axis = None
|
||||
|
||||
@@ -32,20 +33,18 @@ class LinearChartTool(BuiltinTool):
|
||||
flg, ax = plt.subplots(figsize=(10, 8))
|
||||
|
||||
if axis:
|
||||
axis = [label[:10] + '...' if len(label) > 10 else label for label in axis]
|
||||
ax.set_xticklabels(axis, rotation=45, ha='right')
|
||||
axis = [label[:10] + "..." if len(label) > 10 else label for label in axis]
|
||||
ax.set_xticklabels(axis, rotation=45, ha="right")
|
||||
ax.plot(axis, data)
|
||||
else:
|
||||
ax.plot(data)
|
||||
|
||||
buf = io.BytesIO()
|
||||
flg.savefig(buf, format='png')
|
||||
flg.savefig(buf, format="png")
|
||||
buf.seek(0)
|
||||
plt.close(flg)
|
||||
|
||||
return [
|
||||
self.create_text_message('the linear chart is saved as an image.'),
|
||||
self.create_blob_message(blob=buf.read(),
|
||||
meta={'mime_type': 'image/png'})
|
||||
self.create_text_message("the linear chart is saved as an image."),
|
||||
self.create_blob_message(blob=buf.read(), meta={"mime_type": "image/png"}),
|
||||
]
|
||||
|
@@ -8,15 +8,16 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class PieChartTool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
data = tool_parameters.get('data', '')
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
data = tool_parameters.get("data", "")
|
||||
if not data:
|
||||
return self.create_text_message('Please input data')
|
||||
data = data.split(';')
|
||||
categories = tool_parameters.get('categories') or None
|
||||
return self.create_text_message("Please input data")
|
||||
data = data.split(";")
|
||||
categories = tool_parameters.get("categories") or None
|
||||
|
||||
# if all data is int, convert to int
|
||||
if all(i.isdigit() for i in data):
|
||||
@@ -27,7 +28,7 @@ class PieChartTool(BuiltinTool):
|
||||
flg, ax = plt.subplots()
|
||||
|
||||
if categories:
|
||||
categories = categories.split(';')
|
||||
categories = categories.split(";")
|
||||
if len(categories) != len(data):
|
||||
categories = None
|
||||
|
||||
@@ -37,12 +38,11 @@ class PieChartTool(BuiltinTool):
|
||||
ax.pie(data)
|
||||
|
||||
buf = io.BytesIO()
|
||||
flg.savefig(buf, format='png')
|
||||
flg.savefig(buf, format="png")
|
||||
buf.seek(0)
|
||||
plt.close(flg)
|
||||
|
||||
return [
|
||||
self.create_text_message('the pie chart is saved as an image.'),
|
||||
self.create_blob_message(blob=buf.read(),
|
||||
meta={'mime_type': 'image/png'})
|
||||
]
|
||||
self.create_text_message("the pie chart is saved as an image."),
|
||||
self.create_blob_message(blob=buf.read(), meta={"mime_type": "image/png"}),
|
||||
]
|
||||
|
@@ -8,15 +8,15 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
class SimpleCode(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage | list[ToolInvokeMessage]:
|
||||
"""
|
||||
invoke simple code
|
||||
invoke simple code
|
||||
"""
|
||||
|
||||
language = tool_parameters.get('language', CodeLanguage.PYTHON3)
|
||||
code = tool_parameters.get('code', '')
|
||||
language = tool_parameters.get("language", CodeLanguage.PYTHON3)
|
||||
code = tool_parameters.get("code", "")
|
||||
|
||||
if language not in [CodeLanguage.PYTHON3, CodeLanguage.JAVASCRIPT]:
|
||||
raise ValueError(f'Only python3 and javascript are supported, not {language}')
|
||||
|
||||
result = CodeExecutor.execute_code(language, '', code)
|
||||
raise ValueError(f"Only python3 and javascript are supported, not {language}")
|
||||
|
||||
return self.create_text_message(result)
|
||||
result = CodeExecutor.execute_code(language, "", code)
|
||||
|
||||
return self.create_text_message(result)
|
||||
|
@@ -1,4 +1,5 @@
|
||||
""" Provide the input parameters type for the cogview provider class """
|
||||
"""Provide the input parameters type for the cogview provider class"""
|
||||
|
||||
from typing import Any
|
||||
|
||||
from core.tools.errors import ToolProviderCredentialValidationError
|
||||
@@ -7,7 +8,8 @@ from core.tools.provider.builtin_tool_provider import BuiltinToolProviderControl
|
||||
|
||||
|
||||
class COGVIEWProvider(BuiltinToolProviderController):
|
||||
""" cogview provider """
|
||||
"""cogview provider"""
|
||||
|
||||
def _validate_credentials(self, credentials: dict[str, Any]) -> None:
|
||||
try:
|
||||
CogView3Tool().fork_tool_runtime(
|
||||
@@ -15,13 +17,12 @@ class COGVIEWProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"prompt": "一个城市在水晶瓶中欢快生活的场景,水彩画风格,展现出微观与珠宝般的美丽。",
|
||||
"size": "square",
|
||||
"n": 1
|
||||
"n": 1,
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e)) from e
|
||||
|
@@ -7,43 +7,42 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class CogView3Tool(BuiltinTool):
|
||||
""" CogView3 Tool """
|
||||
"""CogView3 Tool"""
|
||||
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
Invoke CogView3 tool
|
||||
"""
|
||||
client = ZhipuAI(
|
||||
base_url=self.runtime.credentials['zhipuai_base_url'],
|
||||
api_key=self.runtime.credentials['zhipuai_api_key'],
|
||||
base_url=self.runtime.credentials["zhipuai_base_url"],
|
||||
api_key=self.runtime.credentials["zhipuai_api_key"],
|
||||
)
|
||||
size_mapping = {
|
||||
'square': '1024x1024',
|
||||
'vertical': '1024x1792',
|
||||
'horizontal': '1792x1024',
|
||||
"square": "1024x1024",
|
||||
"vertical": "1024x1792",
|
||||
"horizontal": "1792x1024",
|
||||
}
|
||||
# prompt
|
||||
prompt = tool_parameters.get('prompt', '')
|
||||
prompt = tool_parameters.get("prompt", "")
|
||||
if not prompt:
|
||||
return self.create_text_message('Please input prompt')
|
||||
return self.create_text_message("Please input prompt")
|
||||
# get size
|
||||
size = size_mapping[tool_parameters.get('size', 'square')]
|
||||
size = size_mapping[tool_parameters.get("size", "square")]
|
||||
# get n
|
||||
n = tool_parameters.get('n', 1)
|
||||
n = tool_parameters.get("n", 1)
|
||||
# get quality
|
||||
quality = tool_parameters.get('quality', 'standard')
|
||||
if quality not in ['standard', 'hd']:
|
||||
return self.create_text_message('Invalid quality')
|
||||
quality = tool_parameters.get("quality", "standard")
|
||||
if quality not in ["standard", "hd"]:
|
||||
return self.create_text_message("Invalid quality")
|
||||
# get style
|
||||
style = tool_parameters.get('style', 'vivid')
|
||||
if style not in ['natural', 'vivid']:
|
||||
return self.create_text_message('Invalid style')
|
||||
style = tool_parameters.get("style", "vivid")
|
||||
if style not in ["natural", "vivid"]:
|
||||
return self.create_text_message("Invalid style")
|
||||
# set extra body
|
||||
seed_id = tool_parameters.get('seed_id', self._generate_random_id(8))
|
||||
extra_body = {'seed': seed_id}
|
||||
seed_id = tool_parameters.get("seed_id", self._generate_random_id(8))
|
||||
extra_body = {"seed": seed_id}
|
||||
response = client.images.generations(
|
||||
prompt=prompt,
|
||||
model="cogview-3",
|
||||
@@ -52,18 +51,22 @@ class CogView3Tool(BuiltinTool):
|
||||
extra_body=extra_body,
|
||||
style=style,
|
||||
quality=quality,
|
||||
response_format='b64_json'
|
||||
response_format="b64_json",
|
||||
)
|
||||
result = []
|
||||
for image in response.data:
|
||||
result.append(self.create_image_message(image=image.url))
|
||||
result.append(self.create_json_message({
|
||||
"url": image.url,
|
||||
}))
|
||||
result.append(
|
||||
self.create_json_message(
|
||||
{
|
||||
"url": image.url,
|
||||
}
|
||||
)
|
||||
)
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def _generate_random_id(length=8):
|
||||
characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
random_id = ''.join(random.choices(characters, k=length))
|
||||
characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
random_id = "".join(random.choices(characters, k=length))
|
||||
return random_id
|
||||
|
@@ -11,9 +11,9 @@ class CrossRefProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"doi": '10.1007/s00894-022-05373-8',
|
||||
"doi": "10.1007/s00894-022-05373-8",
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
|
@@ -11,15 +11,18 @@ class CrossRefQueryDOITool(BuiltinTool):
|
||||
"""
|
||||
Tool for querying the metadata of a publication using its DOI.
|
||||
"""
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
doi = tool_parameters.get('doi')
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
doi = tool_parameters.get("doi")
|
||||
if not doi:
|
||||
raise ToolParameterValidationError('doi is required.')
|
||||
raise ToolParameterValidationError("doi is required.")
|
||||
# doc: https://github.com/CrossRef/rest-api-doc
|
||||
url = f"https://api.crossref.org/works/{doi}"
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
response = response.json()
|
||||
message = response.get('message', {})
|
||||
message = response.get("message", {})
|
||||
|
||||
return self.create_json_message(message)
|
||||
|
@@ -12,16 +12,16 @@ def convert_time_str_to_seconds(time_str: str) -> int:
|
||||
Convert a time string to seconds.
|
||||
example: 1s -> 1, 1m30s -> 90, 1h30m -> 5400, 1h30m30s -> 5430
|
||||
"""
|
||||
time_str = time_str.lower().strip().replace(' ', '')
|
||||
time_str = time_str.lower().strip().replace(" ", "")
|
||||
seconds = 0
|
||||
if 'h' in time_str:
|
||||
hours, time_str = time_str.split('h')
|
||||
if "h" in time_str:
|
||||
hours, time_str = time_str.split("h")
|
||||
seconds += int(hours) * 3600
|
||||
if 'm' in time_str:
|
||||
minutes, time_str = time_str.split('m')
|
||||
if "m" in time_str:
|
||||
minutes, time_str = time_str.split("m")
|
||||
seconds += int(minutes) * 60
|
||||
if 's' in time_str:
|
||||
seconds += int(time_str.replace('s', ''))
|
||||
if "s" in time_str:
|
||||
seconds += int(time_str.replace("s", ""))
|
||||
return seconds
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ class CrossRefQueryTitleAPI:
|
||||
Tool for querying the metadata of a publication using its title.
|
||||
Crossref API doc: https://github.com/CrossRef/rest-api-doc
|
||||
"""
|
||||
|
||||
query_url_template: str = "https://api.crossref.org/works?query.bibliographic={query}&rows={rows}&offset={offset}&sort={sort}&order={order}&mailto={mailto}"
|
||||
rate_limit: int = 50
|
||||
rate_interval: float = 1
|
||||
@@ -38,7 +39,15 @@ class CrossRefQueryTitleAPI:
|
||||
def __init__(self, mailto: str):
|
||||
self.mailto = mailto
|
||||
|
||||
def _query(self, query: str, rows: int = 5, offset: int = 0, sort: str = 'relevance', order: str = 'desc', fuzzy_query: bool = False) -> list[dict]:
|
||||
def _query(
|
||||
self,
|
||||
query: str,
|
||||
rows: int = 5,
|
||||
offset: int = 0,
|
||||
sort: str = "relevance",
|
||||
order: str = "desc",
|
||||
fuzzy_query: bool = False,
|
||||
) -> list[dict]:
|
||||
"""
|
||||
Query the metadata of a publication using its title.
|
||||
:param query: the title of the publication
|
||||
@@ -47,33 +56,37 @@ class CrossRefQueryTitleAPI:
|
||||
:param order: the sort order
|
||||
:param fuzzy_query: whether to return all items that match the query
|
||||
"""
|
||||
url = self.query_url_template.format(query=query, rows=rows, offset=offset, sort=sort, order=order, mailto=self.mailto)
|
||||
url = self.query_url_template.format(
|
||||
query=query, rows=rows, offset=offset, sort=sort, order=order, mailto=self.mailto
|
||||
)
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
rate_limit = int(response.headers['x-ratelimit-limit'])
|
||||
rate_limit = int(response.headers["x-ratelimit-limit"])
|
||||
# convert time string to seconds
|
||||
rate_interval = convert_time_str_to_seconds(response.headers['x-ratelimit-interval'])
|
||||
rate_interval = convert_time_str_to_seconds(response.headers["x-ratelimit-interval"])
|
||||
|
||||
self.rate_limit = rate_limit
|
||||
self.rate_interval = rate_interval
|
||||
|
||||
response = response.json()
|
||||
if response['status'] != 'ok':
|
||||
if response["status"] != "ok":
|
||||
return []
|
||||
|
||||
message = response['message']
|
||||
message = response["message"]
|
||||
if fuzzy_query:
|
||||
# fuzzy query return all items
|
||||
return message['items']
|
||||
return message["items"]
|
||||
else:
|
||||
for paper in message['items']:
|
||||
title = paper['title'][0]
|
||||
for paper in message["items"]:
|
||||
title = paper["title"][0]
|
||||
if title.lower() != query.lower():
|
||||
continue
|
||||
return [paper]
|
||||
return []
|
||||
|
||||
def query(self, query: str, rows: int = 5, sort: str = 'relevance', order: str = 'desc', fuzzy_query: bool = False) -> list[dict]:
|
||||
def query(
|
||||
self, query: str, rows: int = 5, sort: str = "relevance", order: str = "desc", fuzzy_query: bool = False
|
||||
) -> list[dict]:
|
||||
"""
|
||||
Query the metadata of a publication using its title.
|
||||
:param query: the title of the publication
|
||||
@@ -89,7 +102,14 @@ class CrossRefQueryTitleAPI:
|
||||
results = []
|
||||
|
||||
for i in range(query_times):
|
||||
result = self._query(query, rows=self.rate_limit, offset=i * self.rate_limit, sort=sort, order=order, fuzzy_query=fuzzy_query)
|
||||
result = self._query(
|
||||
query,
|
||||
rows=self.rate_limit,
|
||||
offset=i * self.rate_limit,
|
||||
sort=sort,
|
||||
order=order,
|
||||
fuzzy_query=fuzzy_query,
|
||||
)
|
||||
if fuzzy_query:
|
||||
results.extend(result)
|
||||
else:
|
||||
@@ -107,13 +127,16 @@ class CrossRefQueryTitleTool(BuiltinTool):
|
||||
"""
|
||||
Tool for querying the metadata of a publication using its title.
|
||||
"""
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
query = tool_parameters.get('query')
|
||||
fuzzy_query = tool_parameters.get('fuzzy_query', False)
|
||||
rows = tool_parameters.get('rows', 3)
|
||||
sort = tool_parameters.get('sort', 'relevance')
|
||||
order = tool_parameters.get('order', 'desc')
|
||||
mailto = self.runtime.credentials['mailto']
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
query = tool_parameters.get("query")
|
||||
fuzzy_query = tool_parameters.get("fuzzy_query", False)
|
||||
rows = tool_parameters.get("rows", 3)
|
||||
sort = tool_parameters.get("sort", "relevance")
|
||||
order = tool_parameters.get("order", "desc")
|
||||
mailto = self.runtime.credentials["mailto"]
|
||||
|
||||
result = CrossRefQueryTitleAPI(mailto).query(query, rows, sort, order, fuzzy_query)
|
||||
|
||||
|
@@ -13,13 +13,8 @@ class DALLEProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
tool_parameters={
|
||||
"prompt": "cute girl, blue eyes, white hair, anime style",
|
||||
"size": "small",
|
||||
"n": 1
|
||||
},
|
||||
user_id="",
|
||||
tool_parameters={"prompt": "cute girl, blue eyes, white hair, anime style", "size": "small", "n": 1},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -9,59 +9,58 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class DallE2Tool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
openai_organization = self.runtime.credentials.get('openai_organization_id', None)
|
||||
openai_organization = self.runtime.credentials.get("openai_organization_id", None)
|
||||
if not openai_organization:
|
||||
openai_organization = None
|
||||
openai_base_url = self.runtime.credentials.get('openai_base_url', None)
|
||||
openai_base_url = self.runtime.credentials.get("openai_base_url", None)
|
||||
if not openai_base_url:
|
||||
openai_base_url = None
|
||||
else:
|
||||
openai_base_url = str(URL(openai_base_url) / 'v1')
|
||||
openai_base_url = str(URL(openai_base_url) / "v1")
|
||||
|
||||
client = OpenAI(
|
||||
api_key=self.runtime.credentials['openai_api_key'],
|
||||
api_key=self.runtime.credentials["openai_api_key"],
|
||||
base_url=openai_base_url,
|
||||
organization=openai_organization
|
||||
organization=openai_organization,
|
||||
)
|
||||
|
||||
SIZE_MAPPING = {
|
||||
'small': '256x256',
|
||||
'medium': '512x512',
|
||||
'large': '1024x1024',
|
||||
"small": "256x256",
|
||||
"medium": "512x512",
|
||||
"large": "1024x1024",
|
||||
}
|
||||
|
||||
# prompt
|
||||
prompt = tool_parameters.get('prompt', '')
|
||||
prompt = tool_parameters.get("prompt", "")
|
||||
if not prompt:
|
||||
return self.create_text_message('Please input prompt')
|
||||
|
||||
return self.create_text_message("Please input prompt")
|
||||
|
||||
# get size
|
||||
size = SIZE_MAPPING[tool_parameters.get('size', 'large')]
|
||||
size = SIZE_MAPPING[tool_parameters.get("size", "large")]
|
||||
|
||||
# get n
|
||||
n = tool_parameters.get('n', 1)
|
||||
n = tool_parameters.get("n", 1)
|
||||
|
||||
# call openapi dalle2
|
||||
response = client.images.generate(
|
||||
prompt=prompt,
|
||||
model='dall-e-2',
|
||||
size=size,
|
||||
n=n,
|
||||
response_format='b64_json'
|
||||
)
|
||||
response = client.images.generate(prompt=prompt, model="dall-e-2", size=size, n=n, response_format="b64_json")
|
||||
|
||||
result = []
|
||||
|
||||
for image in response.data:
|
||||
result.append(self.create_blob_message(blob=b64decode(image.b64_json),
|
||||
meta={ 'mime_type': 'image/png' },
|
||||
save_as=self.VARIABLE_KEY.IMAGE.value))
|
||||
result.append(
|
||||
self.create_blob_message(
|
||||
blob=b64decode(image.b64_json),
|
||||
meta={"mime_type": "image/png"},
|
||||
save_as=self.VARIABLE_KEY.IMAGE.value,
|
||||
)
|
||||
)
|
||||
|
||||
return result
|
||||
|
@@ -10,69 +10,64 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class DallE3Tool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
openai_organization = self.runtime.credentials.get('openai_organization_id', None)
|
||||
openai_organization = self.runtime.credentials.get("openai_organization_id", None)
|
||||
if not openai_organization:
|
||||
openai_organization = None
|
||||
openai_base_url = self.runtime.credentials.get('openai_base_url', None)
|
||||
openai_base_url = self.runtime.credentials.get("openai_base_url", None)
|
||||
if not openai_base_url:
|
||||
openai_base_url = None
|
||||
else:
|
||||
openai_base_url = str(URL(openai_base_url) / 'v1')
|
||||
openai_base_url = str(URL(openai_base_url) / "v1")
|
||||
|
||||
client = OpenAI(
|
||||
api_key=self.runtime.credentials['openai_api_key'],
|
||||
api_key=self.runtime.credentials["openai_api_key"],
|
||||
base_url=openai_base_url,
|
||||
organization=openai_organization
|
||||
organization=openai_organization,
|
||||
)
|
||||
|
||||
SIZE_MAPPING = {
|
||||
'square': '1024x1024',
|
||||
'vertical': '1024x1792',
|
||||
'horizontal': '1792x1024',
|
||||
"square": "1024x1024",
|
||||
"vertical": "1024x1792",
|
||||
"horizontal": "1792x1024",
|
||||
}
|
||||
|
||||
# prompt
|
||||
prompt = tool_parameters.get('prompt', '')
|
||||
prompt = tool_parameters.get("prompt", "")
|
||||
if not prompt:
|
||||
return self.create_text_message('Please input prompt')
|
||||
return self.create_text_message("Please input prompt")
|
||||
# get size
|
||||
size = SIZE_MAPPING[tool_parameters.get('size', 'square')]
|
||||
size = SIZE_MAPPING[tool_parameters.get("size", "square")]
|
||||
# get n
|
||||
n = tool_parameters.get('n', 1)
|
||||
n = tool_parameters.get("n", 1)
|
||||
# get quality
|
||||
quality = tool_parameters.get('quality', 'standard')
|
||||
if quality not in ['standard', 'hd']:
|
||||
return self.create_text_message('Invalid quality')
|
||||
quality = tool_parameters.get("quality", "standard")
|
||||
if quality not in ["standard", "hd"]:
|
||||
return self.create_text_message("Invalid quality")
|
||||
# get style
|
||||
style = tool_parameters.get('style', 'vivid')
|
||||
if style not in ['natural', 'vivid']:
|
||||
return self.create_text_message('Invalid style')
|
||||
style = tool_parameters.get("style", "vivid")
|
||||
if style not in ["natural", "vivid"]:
|
||||
return self.create_text_message("Invalid style")
|
||||
|
||||
# call openapi dalle3
|
||||
response = client.images.generate(
|
||||
prompt=prompt,
|
||||
model='dall-e-3',
|
||||
size=size,
|
||||
n=n,
|
||||
style=style,
|
||||
quality=quality,
|
||||
response_format='b64_json'
|
||||
prompt=prompt, model="dall-e-3", size=size, n=n, style=style, quality=quality, response_format="b64_json"
|
||||
)
|
||||
|
||||
result = []
|
||||
|
||||
for image in response.data:
|
||||
mime_type, blob_image = DallE3Tool._decode_image(image.b64_json)
|
||||
blob_message = self.create_blob_message(blob=blob_image,
|
||||
meta={'mime_type': mime_type},
|
||||
save_as=self.VARIABLE_KEY.IMAGE.value)
|
||||
blob_message = self.create_blob_message(
|
||||
blob=blob_image, meta={"mime_type": mime_type}, save_as=self.VARIABLE_KEY.IMAGE.value
|
||||
)
|
||||
result.append(blob_message)
|
||||
return result
|
||||
|
||||
@@ -86,7 +81,7 @@ class DallE3Tool(BuiltinTool):
|
||||
:return: A tuple containing the MIME type and the decoded image bytes
|
||||
"""
|
||||
if DallE3Tool._is_plain_base64(base64_image):
|
||||
return 'image/png', base64.b64decode(base64_image)
|
||||
return "image/png", base64.b64decode(base64_image)
|
||||
else:
|
||||
return DallE3Tool._extract_mime_and_data(base64_image)
|
||||
|
||||
@@ -98,7 +93,7 @@ class DallE3Tool(BuiltinTool):
|
||||
:param encoded_str: Base64 encoded image string
|
||||
:return: True if the string is plain base64, False otherwise
|
||||
"""
|
||||
return not encoded_str.startswith('data:image')
|
||||
return not encoded_str.startswith("data:image")
|
||||
|
||||
@staticmethod
|
||||
def _extract_mime_and_data(encoded_str: str) -> tuple[str, bytes]:
|
||||
@@ -108,13 +103,13 @@ class DallE3Tool(BuiltinTool):
|
||||
:param encoded_str: Base64 encoded image string with MIME type prefix
|
||||
:return: A tuple containing the MIME type and the decoded image bytes
|
||||
"""
|
||||
mime_type = encoded_str.split(';')[0].split(':')[1]
|
||||
image_data_base64 = encoded_str.split(',')[1]
|
||||
mime_type = encoded_str.split(";")[0].split(":")[1]
|
||||
image_data_base64 = encoded_str.split(",")[1]
|
||||
decoded_data = base64.b64decode(image_data_base64)
|
||||
return mime_type, decoded_data
|
||||
|
||||
@staticmethod
|
||||
def _generate_random_id(length=8):
|
||||
characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
|
||||
random_id = ''.join(random.choices(characters, k=length))
|
||||
characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||
random_id = "".join(random.choices(characters, k=length))
|
||||
return random_id
|
||||
|
@@ -11,7 +11,7 @@ class DevDocsProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"doc": "python~3.12",
|
||||
"topic": "library/code",
|
||||
@@ -19,4 +19,3 @@ class DevDocsProvider(BuiltinToolProviderController):
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -13,7 +13,9 @@ class SearchDevDocsInput(BaseModel):
|
||||
|
||||
|
||||
class SearchDevDocsTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
Invokes the DevDocs search tool with the given user ID and tool parameters.
|
||||
|
||||
@@ -24,13 +26,13 @@ class SearchDevDocsTool(BuiltinTool):
|
||||
Returns:
|
||||
ToolInvokeMessage | list[ToolInvokeMessage]: The result of the tool invocation, which can be a single message or a list of messages.
|
||||
"""
|
||||
doc = tool_parameters.get('doc', '')
|
||||
topic = tool_parameters.get('topic', '')
|
||||
doc = tool_parameters.get("doc", "")
|
||||
topic = tool_parameters.get("topic", "")
|
||||
|
||||
if not doc:
|
||||
return self.create_text_message('Please provide the documentation name.')
|
||||
return self.create_text_message("Please provide the documentation name.")
|
||||
if not topic:
|
||||
return self.create_text_message('Please provide the topic path.')
|
||||
return self.create_text_message("Please provide the topic path.")
|
||||
|
||||
url = f"https://documents.devdocs.io/{doc}/{topic}.html"
|
||||
response = requests.get(url)
|
||||
@@ -39,4 +41,6 @@ class SearchDevDocsTool(BuiltinTool):
|
||||
content = response.text
|
||||
return self.create_text_message(self.summary(user_id=user_id, content=content))
|
||||
else:
|
||||
return self.create_text_message(f"Failed to retrieve the documentation. Status code: {response.status_code}")
|
||||
return self.create_text_message(
|
||||
f"Failed to retrieve the documentation. Status code: {response.status_code}"
|
||||
)
|
||||
|
@@ -7,15 +7,12 @@ class DIDProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict) -> None:
|
||||
try:
|
||||
# Example validation using the D-ID talks tool
|
||||
TalksTool().fork_tool_runtime(
|
||||
runtime={"credentials": credentials}
|
||||
).invoke(
|
||||
user_id='',
|
||||
TalksTool().fork_tool_runtime(runtime={"credentials": credentials}).invoke(
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"source_url": "https://www.d-id.com/wp-content/uploads/2023/11/Hero-image-1.png",
|
||||
"text_input": "Hello, welcome to use D-ID tool in Dify",
|
||||
}
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -12,14 +12,14 @@ logger = logging.getLogger(__name__)
|
||||
class DIDApp:
|
||||
def __init__(self, api_key: str | None = None, base_url: str | None = None):
|
||||
self.api_key = api_key
|
||||
self.base_url = base_url or 'https://api.d-id.com'
|
||||
self.base_url = base_url or "https://api.d-id.com"
|
||||
if not self.api_key:
|
||||
raise ValueError('API key is required')
|
||||
raise ValueError("API key is required")
|
||||
|
||||
def _prepare_headers(self, idempotency_key: str | None = None):
|
||||
headers = {'Content-Type': 'application/json', 'Authorization': f'Basic {self.api_key}'}
|
||||
headers = {"Content-Type": "application/json", "Authorization": f"Basic {self.api_key}"}
|
||||
if idempotency_key:
|
||||
headers['Idempotency-Key'] = idempotency_key
|
||||
headers["Idempotency-Key"] = idempotency_key
|
||||
return headers
|
||||
|
||||
def _request(
|
||||
@@ -44,44 +44,44 @@ class DIDApp:
|
||||
return None
|
||||
|
||||
def talks(self, wait: bool = True, poll_interval: int = 5, idempotency_key: str | None = None, **kwargs):
|
||||
endpoint = f'{self.base_url}/talks'
|
||||
endpoint = f"{self.base_url}/talks"
|
||||
headers = self._prepare_headers(idempotency_key)
|
||||
data = kwargs['params']
|
||||
logger.debug(f'Send request to {endpoint=} body={data}')
|
||||
response = self._request('POST', endpoint, data, headers)
|
||||
data = kwargs["params"]
|
||||
logger.debug(f"Send request to {endpoint=} body={data}")
|
||||
response = self._request("POST", endpoint, data, headers)
|
||||
if response is None:
|
||||
raise HTTPError('Failed to initiate D-ID talks after multiple retries')
|
||||
id: str = response['id']
|
||||
raise HTTPError("Failed to initiate D-ID talks after multiple retries")
|
||||
id: str = response["id"]
|
||||
if wait:
|
||||
return self._monitor_job_status(id=id, target='talks', poll_interval=poll_interval)
|
||||
return self._monitor_job_status(id=id, target="talks", poll_interval=poll_interval)
|
||||
return id
|
||||
|
||||
def animations(self, wait: bool = True, poll_interval: int = 5, idempotency_key: str | None = None, **kwargs):
|
||||
endpoint = f'{self.base_url}/animations'
|
||||
endpoint = f"{self.base_url}/animations"
|
||||
headers = self._prepare_headers(idempotency_key)
|
||||
data = kwargs['params']
|
||||
logger.debug(f'Send request to {endpoint=} body={data}')
|
||||
response = self._request('POST', endpoint, data, headers)
|
||||
data = kwargs["params"]
|
||||
logger.debug(f"Send request to {endpoint=} body={data}")
|
||||
response = self._request("POST", endpoint, data, headers)
|
||||
if response is None:
|
||||
raise HTTPError('Failed to initiate D-ID talks after multiple retries')
|
||||
id: str = response['id']
|
||||
raise HTTPError("Failed to initiate D-ID talks after multiple retries")
|
||||
id: str = response["id"]
|
||||
if wait:
|
||||
return self._monitor_job_status(target='animations', id=id, poll_interval=poll_interval)
|
||||
return self._monitor_job_status(target="animations", id=id, poll_interval=poll_interval)
|
||||
return id
|
||||
|
||||
def check_did_status(self, target: str, id: str):
|
||||
endpoint = f'{self.base_url}/{target}/{id}'
|
||||
endpoint = f"{self.base_url}/{target}/{id}"
|
||||
headers = self._prepare_headers()
|
||||
response = self._request('GET', endpoint, headers=headers)
|
||||
response = self._request("GET", endpoint, headers=headers)
|
||||
if response is None:
|
||||
raise HTTPError(f'Failed to check status for talks {id} after multiple retries')
|
||||
raise HTTPError(f"Failed to check status for talks {id} after multiple retries")
|
||||
return response
|
||||
|
||||
def _monitor_job_status(self, target: str, id: str, poll_interval: int):
|
||||
while True:
|
||||
status = self.check_did_status(target=target, id=id)
|
||||
if status['status'] == 'done':
|
||||
if status["status"] == "done":
|
||||
return status
|
||||
elif status['status'] == 'error' or status['status'] == 'rejected':
|
||||
elif status["status"] == "error" or status["status"] == "rejected":
|
||||
raise HTTPError(f'Talks {id} failed: {status["status"]} {status.get("error",{}).get("description")}')
|
||||
time.sleep(poll_interval)
|
||||
|
@@ -10,33 +10,33 @@ class AnimationsTool(BuiltinTool):
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
app = DIDApp(api_key=self.runtime.credentials['did_api_key'], base_url=self.runtime.credentials['base_url'])
|
||||
app = DIDApp(api_key=self.runtime.credentials["did_api_key"], base_url=self.runtime.credentials["base_url"])
|
||||
|
||||
driver_expressions_str = tool_parameters.get('driver_expressions')
|
||||
driver_expressions_str = tool_parameters.get("driver_expressions")
|
||||
driver_expressions = json.loads(driver_expressions_str) if driver_expressions_str else None
|
||||
|
||||
config = {
|
||||
'stitch': tool_parameters.get('stitch', True),
|
||||
'mute': tool_parameters.get('mute'),
|
||||
'result_format': tool_parameters.get('result_format') or 'mp4',
|
||||
"stitch": tool_parameters.get("stitch", True),
|
||||
"mute": tool_parameters.get("mute"),
|
||||
"result_format": tool_parameters.get("result_format") or "mp4",
|
||||
}
|
||||
config = {k: v for k, v in config.items() if v is not None and v != ''}
|
||||
config = {k: v for k, v in config.items() if v is not None and v != ""}
|
||||
|
||||
options = {
|
||||
'source_url': tool_parameters['source_url'],
|
||||
'driver_url': tool_parameters.get('driver_url'),
|
||||
'config': config,
|
||||
"source_url": tool_parameters["source_url"],
|
||||
"driver_url": tool_parameters.get("driver_url"),
|
||||
"config": config,
|
||||
}
|
||||
options = {k: v for k, v in options.items() if v is not None and v != ''}
|
||||
options = {k: v for k, v in options.items() if v is not None and v != ""}
|
||||
|
||||
if not options.get('source_url'):
|
||||
raise ValueError('Source URL is required')
|
||||
if not options.get("source_url"):
|
||||
raise ValueError("Source URL is required")
|
||||
|
||||
if config.get('logo_url'):
|
||||
if not config.get('logo_x'):
|
||||
raise ValueError('Logo X position is required when logo URL is provided')
|
||||
if not config.get('logo_y'):
|
||||
raise ValueError('Logo Y position is required when logo URL is provided')
|
||||
if config.get("logo_url"):
|
||||
if not config.get("logo_x"):
|
||||
raise ValueError("Logo X position is required when logo URL is provided")
|
||||
if not config.get("logo_y"):
|
||||
raise ValueError("Logo Y position is required when logo URL is provided")
|
||||
|
||||
animations_result = app.animations(params=options, wait=True)
|
||||
|
||||
@@ -44,6 +44,6 @@ class AnimationsTool(BuiltinTool):
|
||||
animations_result = json.dumps(animations_result, ensure_ascii=False, indent=4)
|
||||
|
||||
if not animations_result:
|
||||
return self.create_text_message('D-ID animations request failed.')
|
||||
return self.create_text_message("D-ID animations request failed.")
|
||||
|
||||
return self.create_text_message(animations_result)
|
||||
|
@@ -10,49 +10,49 @@ class TalksTool(BuiltinTool):
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
app = DIDApp(api_key=self.runtime.credentials['did_api_key'], base_url=self.runtime.credentials['base_url'])
|
||||
app = DIDApp(api_key=self.runtime.credentials["did_api_key"], base_url=self.runtime.credentials["base_url"])
|
||||
|
||||
driver_expressions_str = tool_parameters.get('driver_expressions')
|
||||
driver_expressions_str = tool_parameters.get("driver_expressions")
|
||||
driver_expressions = json.loads(driver_expressions_str) if driver_expressions_str else None
|
||||
|
||||
script = {
|
||||
'type': tool_parameters.get('script_type') or 'text',
|
||||
'input': tool_parameters.get('text_input'),
|
||||
'audio_url': tool_parameters.get('audio_url'),
|
||||
'reduce_noise': tool_parameters.get('audio_reduce_noise', False),
|
||||
"type": tool_parameters.get("script_type") or "text",
|
||||
"input": tool_parameters.get("text_input"),
|
||||
"audio_url": tool_parameters.get("audio_url"),
|
||||
"reduce_noise": tool_parameters.get("audio_reduce_noise", False),
|
||||
}
|
||||
script = {k: v for k, v in script.items() if v is not None and v != ''}
|
||||
script = {k: v for k, v in script.items() if v is not None and v != ""}
|
||||
config = {
|
||||
'stitch': tool_parameters.get('stitch', True),
|
||||
'sharpen': tool_parameters.get('sharpen'),
|
||||
'fluent': tool_parameters.get('fluent'),
|
||||
'result_format': tool_parameters.get('result_format') or 'mp4',
|
||||
'pad_audio': tool_parameters.get('pad_audio'),
|
||||
'driver_expressions': driver_expressions,
|
||||
"stitch": tool_parameters.get("stitch", True),
|
||||
"sharpen": tool_parameters.get("sharpen"),
|
||||
"fluent": tool_parameters.get("fluent"),
|
||||
"result_format": tool_parameters.get("result_format") or "mp4",
|
||||
"pad_audio": tool_parameters.get("pad_audio"),
|
||||
"driver_expressions": driver_expressions,
|
||||
}
|
||||
config = {k: v for k, v in config.items() if v is not None and v != ''}
|
||||
config = {k: v for k, v in config.items() if v is not None and v != ""}
|
||||
|
||||
options = {
|
||||
'source_url': tool_parameters['source_url'],
|
||||
'driver_url': tool_parameters.get('driver_url'),
|
||||
'script': script,
|
||||
'config': config,
|
||||
"source_url": tool_parameters["source_url"],
|
||||
"driver_url": tool_parameters.get("driver_url"),
|
||||
"script": script,
|
||||
"config": config,
|
||||
}
|
||||
options = {k: v for k, v in options.items() if v is not None and v != ''}
|
||||
options = {k: v for k, v in options.items() if v is not None and v != ""}
|
||||
|
||||
if not options.get('source_url'):
|
||||
raise ValueError('Source URL is required')
|
||||
if not options.get("source_url"):
|
||||
raise ValueError("Source URL is required")
|
||||
|
||||
if script.get('type') == 'audio':
|
||||
script.pop('input', None)
|
||||
if not script.get('audio_url'):
|
||||
raise ValueError('Audio URL is required for audio script type')
|
||||
if script.get("type") == "audio":
|
||||
script.pop("input", None)
|
||||
if not script.get("audio_url"):
|
||||
raise ValueError("Audio URL is required for audio script type")
|
||||
|
||||
if script.get('type') == 'text':
|
||||
script.pop('audio_url', None)
|
||||
script.pop('reduce_noise', None)
|
||||
if not script.get('input'):
|
||||
raise ValueError('Text input is required for text script type')
|
||||
if script.get("type") == "text":
|
||||
script.pop("audio_url", None)
|
||||
script.pop("reduce_noise", None)
|
||||
if not script.get("input"):
|
||||
raise ValueError("Text input is required for text script type")
|
||||
|
||||
talks_result = app.talks(params=options, wait=True)
|
||||
|
||||
@@ -60,6 +60,6 @@ class TalksTool(BuiltinTool):
|
||||
talks_result = json.dumps(talks_result, ensure_ascii=False, indent=4)
|
||||
|
||||
if not talks_result:
|
||||
return self.create_text_message('D-ID talks request failed.')
|
||||
return self.create_text_message("D-ID talks request failed.")
|
||||
|
||||
return self.create_text_message(talks_result)
|
||||
|
@@ -13,38 +13,43 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class DingTalkGroupBotTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
Dingtalk custom group robot API docs:
|
||||
https://open.dingtalk.com/document/orgapp/custom-robot-access
|
||||
invoke tools
|
||||
Dingtalk custom group robot API docs:
|
||||
https://open.dingtalk.com/document/orgapp/custom-robot-access
|
||||
"""
|
||||
content = tool_parameters.get('content')
|
||||
content = tool_parameters.get("content")
|
||||
if not content:
|
||||
return self.create_text_message('Invalid parameter content')
|
||||
return self.create_text_message("Invalid parameter content")
|
||||
|
||||
access_token = tool_parameters.get('access_token')
|
||||
access_token = tool_parameters.get("access_token")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token. '
|
||||
'Regarding information about security details,'
|
||||
'please refer to the DingTalk docs:'
|
||||
'https://open.dingtalk.com/document/robots/customize-robot-security-settings')
|
||||
return self.create_text_message(
|
||||
"Invalid parameter access_token. "
|
||||
"Regarding information about security details,"
|
||||
"please refer to the DingTalk docs:"
|
||||
"https://open.dingtalk.com/document/robots/customize-robot-security-settings"
|
||||
)
|
||||
|
||||
sign_secret = tool_parameters.get('sign_secret')
|
||||
sign_secret = tool_parameters.get("sign_secret")
|
||||
if not sign_secret:
|
||||
return self.create_text_message('Invalid parameter sign_secret. '
|
||||
'Regarding information about security details,'
|
||||
'please refer to the DingTalk docs:'
|
||||
'https://open.dingtalk.com/document/robots/customize-robot-security-settings')
|
||||
return self.create_text_message(
|
||||
"Invalid parameter sign_secret. "
|
||||
"Regarding information about security details,"
|
||||
"please refer to the DingTalk docs:"
|
||||
"https://open.dingtalk.com/document/robots/customize-robot-security-settings"
|
||||
)
|
||||
|
||||
msgtype = 'text'
|
||||
api_url = 'https://oapi.dingtalk.com/robot/send'
|
||||
msgtype = "text"
|
||||
api_url = "https://oapi.dingtalk.com/robot/send"
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
params = {
|
||||
'access_token': access_token,
|
||||
"access_token": access_token,
|
||||
}
|
||||
|
||||
self._apply_security_mechanism(params, sign_secret)
|
||||
@@ -53,7 +58,7 @@ class DingTalkGroupBotTool(BuiltinTool):
|
||||
"msgtype": msgtype,
|
||||
"text": {
|
||||
"content": content,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
try:
|
||||
@@ -62,7 +67,8 @@ class DingTalkGroupBotTool(BuiltinTool):
|
||||
return self.create_text_message("Text message sent successfully")
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to send the text message, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to send the text message, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to send message to group chat bot. {}".format(e))
|
||||
|
||||
@@ -70,14 +76,14 @@ class DingTalkGroupBotTool(BuiltinTool):
|
||||
def _apply_security_mechanism(params: dict[str, Any], sign_secret: str):
|
||||
try:
|
||||
timestamp = str(round(time.time() * 1000))
|
||||
secret_enc = sign_secret.encode('utf-8')
|
||||
string_to_sign = f'{timestamp}\n{sign_secret}'
|
||||
string_to_sign_enc = string_to_sign.encode('utf-8')
|
||||
secret_enc = sign_secret.encode("utf-8")
|
||||
string_to_sign = f"{timestamp}\n{sign_secret}"
|
||||
string_to_sign_enc = string_to_sign.encode("utf-8")
|
||||
hmac_code = hmac.new(secret_enc, string_to_sign_enc, digestmod=hashlib.sha256).digest()
|
||||
sign = urllib.parse.quote_plus(base64.b64encode(hmac_code))
|
||||
|
||||
params['timestamp'] = timestamp
|
||||
params['sign'] = sign
|
||||
params["timestamp"] = timestamp
|
||||
params["sign"] = sign
|
||||
except Exception:
|
||||
msg = "Failed to apply security mechanism to the request."
|
||||
logging.exception(msg)
|
||||
|
@@ -11,11 +11,10 @@ class DuckDuckGoProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"query": "John Doe",
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -13,8 +13,8 @@ class DuckDuckGoAITool(BuiltinTool):
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
|
||||
query_dict = {
|
||||
"keywords": tool_parameters.get('query'),
|
||||
"model": tool_parameters.get('model'),
|
||||
"keywords": tool_parameters.get("query"),
|
||||
"model": tool_parameters.get("model"),
|
||||
}
|
||||
response = DDGS().chat(**query_dict)
|
||||
return self.create_text_message(text=response)
|
||||
|
@@ -14,18 +14,17 @@ class DuckDuckGoImageSearchTool(BuiltinTool):
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> list[ToolInvokeMessage]:
|
||||
query_dict = {
|
||||
"keywords": tool_parameters.get('query'),
|
||||
"timelimit": tool_parameters.get('timelimit'),
|
||||
"size": tool_parameters.get('size'),
|
||||
"max_results": tool_parameters.get('max_results'),
|
||||
"keywords": tool_parameters.get("query"),
|
||||
"timelimit": tool_parameters.get("timelimit"),
|
||||
"size": tool_parameters.get("size"),
|
||||
"max_results": tool_parameters.get("max_results"),
|
||||
}
|
||||
response = DDGS().images(**query_dict)
|
||||
result = []
|
||||
for res in response:
|
||||
res['transfer_method'] = FileTransferMethod.REMOTE_URL
|
||||
msg = ToolInvokeMessage(type=ToolInvokeMessage.MessageType.IMAGE_LINK,
|
||||
message=res.get('image'),
|
||||
save_as='',
|
||||
meta=res)
|
||||
res["transfer_method"] = FileTransferMethod.REMOTE_URL
|
||||
msg = ToolInvokeMessage(
|
||||
type=ToolInvokeMessage.MessageType.IMAGE_LINK, message=res.get("image"), save_as="", meta=res
|
||||
)
|
||||
result.append(msg)
|
||||
return result
|
||||
|
@@ -21,10 +21,11 @@ class DuckDuckGoSearchTool(BuiltinTool):
|
||||
"""
|
||||
Tool for performing a search using DuckDuckGo search engine.
|
||||
"""
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage | list[ToolInvokeMessage]:
|
||||
query = tool_parameters.get('query')
|
||||
max_results = tool_parameters.get('max_results', 5)
|
||||
require_summary = tool_parameters.get('require_summary', False)
|
||||
query = tool_parameters.get("query")
|
||||
max_results = tool_parameters.get("max_results", 5)
|
||||
require_summary = tool_parameters.get("require_summary", False)
|
||||
response = DDGS().text(query, max_results=max_results)
|
||||
if require_summary:
|
||||
results = "\n".join([res.get("body") for res in response])
|
||||
@@ -34,7 +35,11 @@ class DuckDuckGoSearchTool(BuiltinTool):
|
||||
|
||||
def summary_results(self, user_id: str, content: str, query: str) -> str:
|
||||
prompt = SUMMARY_PROMPT.format(query=query, content=content)
|
||||
summary = self.invoke_model(user_id=user_id, prompt_messages=[
|
||||
SystemPromptMessage(content=prompt),
|
||||
], stop=[])
|
||||
summary = self.invoke_model(
|
||||
user_id=user_id,
|
||||
prompt_messages=[
|
||||
SystemPromptMessage(content=prompt),
|
||||
],
|
||||
stop=[],
|
||||
)
|
||||
return summary.message.content
|
||||
|
@@ -13,8 +13,8 @@ class DuckDuckGoTranslateTool(BuiltinTool):
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
|
||||
query_dict = {
|
||||
"keywords": tool_parameters.get('query'),
|
||||
"to": tool_parameters.get('translate_to'),
|
||||
"keywords": tool_parameters.get("query"),
|
||||
"to": tool_parameters.get("translate_to"),
|
||||
}
|
||||
response = DDGS().translate(**query_dict)[0].get('translated', 'Unable to translate!')
|
||||
response = DDGS().translate(**query_dict)[0].get("translated", "Unable to translate!")
|
||||
return self.create_text_message(text=response)
|
||||
|
@@ -8,35 +8,35 @@ from core.tools.utils.uuid_utils import is_valid_uuid
|
||||
|
||||
|
||||
class FeishuGroupBotTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
API document: https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot
|
||||
invoke tools
|
||||
API document: https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot
|
||||
"""
|
||||
|
||||
url = "https://open.feishu.cn/open-apis/bot/v2/hook"
|
||||
|
||||
content = tool_parameters.get('content', '')
|
||||
content = tool_parameters.get("content", "")
|
||||
if not content:
|
||||
return self.create_text_message('Invalid parameter content')
|
||||
return self.create_text_message("Invalid parameter content")
|
||||
|
||||
hook_key = tool_parameters.get('hook_key', '')
|
||||
hook_key = tool_parameters.get("hook_key", "")
|
||||
if not is_valid_uuid(hook_key):
|
||||
return self.create_text_message(
|
||||
f'Invalid parameter hook_key ${hook_key}, not a valid UUID')
|
||||
return self.create_text_message(f"Invalid parameter hook_key ${hook_key}, not a valid UUID")
|
||||
|
||||
msg_type = 'text'
|
||||
api_url = f'{url}/{hook_key}'
|
||||
msg_type = "text"
|
||||
api_url = f"{url}/{hook_key}"
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
params = {}
|
||||
payload = {
|
||||
"msg_type": msg_type,
|
||||
"content": {
|
||||
"text": content,
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
try:
|
||||
@@ -45,6 +45,7 @@ class FeishuGroupBotTool(BuiltinTool):
|
||||
return self.create_text_message("Text message sent successfully")
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to send the text message, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to send the text message, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to send message to group chat bot. {}".format(e))
|
||||
return self.create_text_message("Failed to send message to group chat bot. {}".format(e))
|
||||
|
@@ -5,4 +5,4 @@ from core.tools.provider.builtin_tool_provider import BuiltinToolProviderControl
|
||||
class FeishuBaseProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict) -> None:
|
||||
GetTenantAccessTokenTool()
|
||||
pass
|
||||
pass
|
||||
|
@@ -8,45 +8,49 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class AddBaseRecordTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records"
|
||||
|
||||
access_token = tool_parameters.get('Authorization', '')
|
||||
access_token = tool_parameters.get("Authorization", "")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token')
|
||||
return self.create_text_message("Invalid parameter access_token")
|
||||
|
||||
app_token = tool_parameters.get('app_token', '')
|
||||
app_token = tool_parameters.get("app_token", "")
|
||||
if not app_token:
|
||||
return self.create_text_message('Invalid parameter app_token')
|
||||
return self.create_text_message("Invalid parameter app_token")
|
||||
|
||||
table_id = tool_parameters.get('table_id', '')
|
||||
table_id = tool_parameters.get("table_id", "")
|
||||
if not table_id:
|
||||
return self.create_text_message('Invalid parameter table_id')
|
||||
return self.create_text_message("Invalid parameter table_id")
|
||||
|
||||
fields = tool_parameters.get('fields', '')
|
||||
fields = tool_parameters.get("fields", "")
|
||||
if not fields:
|
||||
return self.create_text_message('Invalid parameter fields')
|
||||
return self.create_text_message("Invalid parameter fields")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f"Bearer {access_token}",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
}
|
||||
|
||||
params = {}
|
||||
payload = {
|
||||
"fields": json.loads(fields)
|
||||
}
|
||||
payload = {"fields": json.loads(fields)}
|
||||
|
||||
try:
|
||||
res = httpx.post(url.format(app_token=app_token, table_id=table_id), headers=headers, params=params,
|
||||
json=payload, timeout=30)
|
||||
res = httpx.post(
|
||||
url.format(app_token=app_token, table_id=table_id),
|
||||
headers=headers,
|
||||
params=params,
|
||||
json=payload,
|
||||
timeout=30,
|
||||
)
|
||||
res_json = res.json()
|
||||
if res.is_success:
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to add base record, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to add base record, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to add base record. {}".format(e))
|
||||
|
@@ -8,28 +8,25 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class CreateBaseTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/bitable/v1/apps"
|
||||
|
||||
access_token = tool_parameters.get('Authorization', '')
|
||||
access_token = tool_parameters.get("Authorization", "")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token')
|
||||
return self.create_text_message("Invalid parameter access_token")
|
||||
|
||||
name = tool_parameters.get('name', '')
|
||||
folder_token = tool_parameters.get('folder_token', '')
|
||||
name = tool_parameters.get("name", "")
|
||||
folder_token = tool_parameters.get("folder_token", "")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f"Bearer {access_token}",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
}
|
||||
|
||||
params = {}
|
||||
payload = {
|
||||
"name": name,
|
||||
"folder_token": folder_token
|
||||
}
|
||||
payload = {"name": name, "folder_token": folder_token}
|
||||
|
||||
try:
|
||||
res = httpx.post(url, headers=headers, params=params, json=payload, timeout=30)
|
||||
@@ -38,6 +35,7 @@ class CreateBaseTool(BuiltinTool):
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to create base, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to create base, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to create base. {}".format(e))
|
||||
|
@@ -8,37 +8,32 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class CreateBaseTableTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables"
|
||||
|
||||
access_token = tool_parameters.get('Authorization', '')
|
||||
access_token = tool_parameters.get("Authorization", "")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token')
|
||||
return self.create_text_message("Invalid parameter access_token")
|
||||
|
||||
app_token = tool_parameters.get('app_token', '')
|
||||
app_token = tool_parameters.get("app_token", "")
|
||||
if not app_token:
|
||||
return self.create_text_message('Invalid parameter app_token')
|
||||
return self.create_text_message("Invalid parameter app_token")
|
||||
|
||||
name = tool_parameters.get('name', '')
|
||||
name = tool_parameters.get("name", "")
|
||||
|
||||
fields = tool_parameters.get('fields', '')
|
||||
fields = tool_parameters.get("fields", "")
|
||||
if not fields:
|
||||
return self.create_text_message('Invalid parameter fields')
|
||||
return self.create_text_message("Invalid parameter fields")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f"Bearer {access_token}",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
}
|
||||
|
||||
params = {}
|
||||
payload = {
|
||||
"table": {
|
||||
"name": name,
|
||||
"fields": json.loads(fields)
|
||||
}
|
||||
}
|
||||
payload = {"table": {"name": name, "fields": json.loads(fields)}}
|
||||
|
||||
try:
|
||||
res = httpx.post(url.format(app_token=app_token), headers=headers, params=params, json=payload, timeout=30)
|
||||
@@ -47,6 +42,7 @@ class CreateBaseTableTool(BuiltinTool):
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to create base table, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to create base table, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to create base table. {}".format(e))
|
||||
|
@@ -8,45 +8,49 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class DeleteBaseRecordsTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/batch_delete"
|
||||
|
||||
access_token = tool_parameters.get('Authorization', '')
|
||||
access_token = tool_parameters.get("Authorization", "")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token')
|
||||
return self.create_text_message("Invalid parameter access_token")
|
||||
|
||||
app_token = tool_parameters.get('app_token', '')
|
||||
app_token = tool_parameters.get("app_token", "")
|
||||
if not app_token:
|
||||
return self.create_text_message('Invalid parameter app_token')
|
||||
return self.create_text_message("Invalid parameter app_token")
|
||||
|
||||
table_id = tool_parameters.get('table_id', '')
|
||||
table_id = tool_parameters.get("table_id", "")
|
||||
if not table_id:
|
||||
return self.create_text_message('Invalid parameter table_id')
|
||||
return self.create_text_message("Invalid parameter table_id")
|
||||
|
||||
record_ids = tool_parameters.get('record_ids', '')
|
||||
record_ids = tool_parameters.get("record_ids", "")
|
||||
if not record_ids:
|
||||
return self.create_text_message('Invalid parameter record_ids')
|
||||
return self.create_text_message("Invalid parameter record_ids")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f"Bearer {access_token}",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
}
|
||||
|
||||
params = {}
|
||||
payload = {
|
||||
"records": json.loads(record_ids)
|
||||
}
|
||||
payload = {"records": json.loads(record_ids)}
|
||||
|
||||
try:
|
||||
res = httpx.post(url.format(app_token=app_token, table_id=table_id), headers=headers, params=params,
|
||||
json=payload, timeout=30)
|
||||
res = httpx.post(
|
||||
url.format(app_token=app_token, table_id=table_id),
|
||||
headers=headers,
|
||||
params=params,
|
||||
json=payload,
|
||||
timeout=30,
|
||||
)
|
||||
res_json = res.json()
|
||||
if res.is_success:
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to delete base records, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to delete base records, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to delete base records. {}".format(e))
|
||||
|
@@ -8,32 +8,30 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class DeleteBaseTablesTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/batch_delete"
|
||||
|
||||
access_token = tool_parameters.get('Authorization', '')
|
||||
access_token = tool_parameters.get("Authorization", "")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token')
|
||||
return self.create_text_message("Invalid parameter access_token")
|
||||
|
||||
app_token = tool_parameters.get('app_token', '')
|
||||
app_token = tool_parameters.get("app_token", "")
|
||||
if not app_token:
|
||||
return self.create_text_message('Invalid parameter app_token')
|
||||
return self.create_text_message("Invalid parameter app_token")
|
||||
|
||||
table_ids = tool_parameters.get('table_ids', '')
|
||||
table_ids = tool_parameters.get("table_ids", "")
|
||||
if not table_ids:
|
||||
return self.create_text_message('Invalid parameter table_ids')
|
||||
return self.create_text_message("Invalid parameter table_ids")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f"Bearer {access_token}",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
}
|
||||
|
||||
params = {}
|
||||
payload = {
|
||||
"table_ids": json.loads(table_ids)
|
||||
}
|
||||
payload = {"table_ids": json.loads(table_ids)}
|
||||
|
||||
try:
|
||||
res = httpx.post(url.format(app_token=app_token), headers=headers, params=params, json=payload, timeout=30)
|
||||
@@ -42,6 +40,7 @@ class DeleteBaseTablesTool(BuiltinTool):
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to delete base tables, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to delete base tables, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to delete base tables. {}".format(e))
|
||||
|
@@ -8,22 +8,22 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class GetBaseInfoTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}"
|
||||
|
||||
access_token = tool_parameters.get('Authorization', '')
|
||||
access_token = tool_parameters.get("Authorization", "")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token')
|
||||
return self.create_text_message("Invalid parameter access_token")
|
||||
|
||||
app_token = tool_parameters.get('app_token', '')
|
||||
app_token = tool_parameters.get("app_token", "")
|
||||
if not app_token:
|
||||
return self.create_text_message('Invalid parameter app_token')
|
||||
return self.create_text_message("Invalid parameter app_token")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f"Bearer {access_token}",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
}
|
||||
|
||||
try:
|
||||
@@ -33,6 +33,7 @@ class GetBaseInfoTool(BuiltinTool):
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to get base info, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to get base info, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to get base info. {}".format(e))
|
||||
|
@@ -8,27 +8,24 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class GetTenantAccessTokenTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal"
|
||||
|
||||
app_id = tool_parameters.get('app_id', '')
|
||||
app_id = tool_parameters.get("app_id", "")
|
||||
if not app_id:
|
||||
return self.create_text_message('Invalid parameter app_id')
|
||||
return self.create_text_message("Invalid parameter app_id")
|
||||
|
||||
app_secret = tool_parameters.get('app_secret', '')
|
||||
app_secret = tool_parameters.get("app_secret", "")
|
||||
if not app_secret:
|
||||
return self.create_text_message('Invalid parameter app_secret')
|
||||
return self.create_text_message("Invalid parameter app_secret")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
params = {}
|
||||
payload = {
|
||||
"app_id": app_id,
|
||||
"app_secret": app_secret
|
||||
}
|
||||
payload = {"app_id": app_id, "app_secret": app_secret}
|
||||
|
||||
"""
|
||||
{
|
||||
@@ -45,6 +42,7 @@ class GetTenantAccessTokenTool(BuiltinTool):
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to get tenant access token, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to get tenant access token, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to get tenant access token. {}".format(e))
|
||||
|
@@ -8,31 +8,31 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class ListBaseRecordsTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/search"
|
||||
|
||||
access_token = tool_parameters.get('Authorization', '')
|
||||
access_token = tool_parameters.get("Authorization", "")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token')
|
||||
return self.create_text_message("Invalid parameter access_token")
|
||||
|
||||
app_token = tool_parameters.get('app_token', '')
|
||||
app_token = tool_parameters.get("app_token", "")
|
||||
if not app_token:
|
||||
return self.create_text_message('Invalid parameter app_token')
|
||||
return self.create_text_message("Invalid parameter app_token")
|
||||
|
||||
table_id = tool_parameters.get('table_id', '')
|
||||
table_id = tool_parameters.get("table_id", "")
|
||||
if not table_id:
|
||||
return self.create_text_message('Invalid parameter table_id')
|
||||
return self.create_text_message("Invalid parameter table_id")
|
||||
|
||||
page_token = tool_parameters.get('page_token', '')
|
||||
page_size = tool_parameters.get('page_size', '')
|
||||
sort_condition = tool_parameters.get('sort_condition', '')
|
||||
filter_condition = tool_parameters.get('filter_condition', '')
|
||||
page_token = tool_parameters.get("page_token", "")
|
||||
page_size = tool_parameters.get("page_size", "")
|
||||
sort_condition = tool_parameters.get("sort_condition", "")
|
||||
filter_condition = tool_parameters.get("filter_condition", "")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f"Bearer {access_token}",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
}
|
||||
|
||||
params = {
|
||||
@@ -40,22 +40,26 @@ class ListBaseRecordsTool(BuiltinTool):
|
||||
"page_size": page_size,
|
||||
}
|
||||
|
||||
payload = {
|
||||
"automatic_fields": True
|
||||
}
|
||||
payload = {"automatic_fields": True}
|
||||
if sort_condition:
|
||||
payload["sort"] = json.loads(sort_condition)
|
||||
if filter_condition:
|
||||
payload["filter"] = json.loads(filter_condition)
|
||||
|
||||
try:
|
||||
res = httpx.post(url.format(app_token=app_token, table_id=table_id), headers=headers, params=params,
|
||||
json=payload, timeout=30)
|
||||
res = httpx.post(
|
||||
url.format(app_token=app_token, table_id=table_id),
|
||||
headers=headers,
|
||||
params=params,
|
||||
json=payload,
|
||||
timeout=30,
|
||||
)
|
||||
res_json = res.json()
|
||||
if res.is_success:
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to list base records, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to list base records, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to list base records. {}".format(e))
|
||||
|
@@ -8,25 +8,25 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class ListBaseTablesTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables"
|
||||
|
||||
access_token = tool_parameters.get('Authorization', '')
|
||||
access_token = tool_parameters.get("Authorization", "")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token')
|
||||
return self.create_text_message("Invalid parameter access_token")
|
||||
|
||||
app_token = tool_parameters.get('app_token', '')
|
||||
app_token = tool_parameters.get("app_token", "")
|
||||
if not app_token:
|
||||
return self.create_text_message('Invalid parameter app_token')
|
||||
return self.create_text_message("Invalid parameter app_token")
|
||||
|
||||
page_token = tool_parameters.get('page_token', '')
|
||||
page_size = tool_parameters.get('page_size', '')
|
||||
page_token = tool_parameters.get("page_token", "")
|
||||
page_size = tool_parameters.get("page_size", "")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f"Bearer {access_token}",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
}
|
||||
|
||||
params = {
|
||||
@@ -41,6 +41,7 @@ class ListBaseTablesTool(BuiltinTool):
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to list base tables, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to list base tables, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to list base tables. {}".format(e))
|
||||
|
@@ -8,40 +8,42 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class ReadBaseRecordTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/{record_id}"
|
||||
|
||||
access_token = tool_parameters.get('Authorization', '')
|
||||
access_token = tool_parameters.get("Authorization", "")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token')
|
||||
return self.create_text_message("Invalid parameter access_token")
|
||||
|
||||
app_token = tool_parameters.get('app_token', '')
|
||||
app_token = tool_parameters.get("app_token", "")
|
||||
if not app_token:
|
||||
return self.create_text_message('Invalid parameter app_token')
|
||||
return self.create_text_message("Invalid parameter app_token")
|
||||
|
||||
table_id = tool_parameters.get('table_id', '')
|
||||
table_id = tool_parameters.get("table_id", "")
|
||||
if not table_id:
|
||||
return self.create_text_message('Invalid parameter table_id')
|
||||
return self.create_text_message("Invalid parameter table_id")
|
||||
|
||||
record_id = tool_parameters.get('record_id', '')
|
||||
record_id = tool_parameters.get("record_id", "")
|
||||
if not record_id:
|
||||
return self.create_text_message('Invalid parameter record_id')
|
||||
return self.create_text_message("Invalid parameter record_id")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f"Bearer {access_token}",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
}
|
||||
|
||||
try:
|
||||
res = httpx.get(url.format(app_token=app_token, table_id=table_id, record_id=record_id), headers=headers,
|
||||
timeout=30)
|
||||
res = httpx.get(
|
||||
url.format(app_token=app_token, table_id=table_id, record_id=record_id), headers=headers, timeout=30
|
||||
)
|
||||
res_json = res.json()
|
||||
if res.is_success:
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to read base record, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to read base record, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to read base record. {}".format(e))
|
||||
|
@@ -8,49 +8,53 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class UpdateBaseRecordTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
url = "https://open.feishu.cn/open-apis/bitable/v1/apps/{app_token}/tables/{table_id}/records/{record_id}"
|
||||
|
||||
access_token = tool_parameters.get('Authorization', '')
|
||||
access_token = tool_parameters.get("Authorization", "")
|
||||
if not access_token:
|
||||
return self.create_text_message('Invalid parameter access_token')
|
||||
return self.create_text_message("Invalid parameter access_token")
|
||||
|
||||
app_token = tool_parameters.get('app_token', '')
|
||||
app_token = tool_parameters.get("app_token", "")
|
||||
if not app_token:
|
||||
return self.create_text_message('Invalid parameter app_token')
|
||||
return self.create_text_message("Invalid parameter app_token")
|
||||
|
||||
table_id = tool_parameters.get('table_id', '')
|
||||
table_id = tool_parameters.get("table_id", "")
|
||||
if not table_id:
|
||||
return self.create_text_message('Invalid parameter table_id')
|
||||
return self.create_text_message("Invalid parameter table_id")
|
||||
|
||||
record_id = tool_parameters.get('record_id', '')
|
||||
record_id = tool_parameters.get("record_id", "")
|
||||
if not record_id:
|
||||
return self.create_text_message('Invalid parameter record_id')
|
||||
return self.create_text_message("Invalid parameter record_id")
|
||||
|
||||
fields = tool_parameters.get('fields', '')
|
||||
fields = tool_parameters.get("fields", "")
|
||||
if not fields:
|
||||
return self.create_text_message('Invalid parameter fields')
|
||||
return self.create_text_message("Invalid parameter fields")
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f"Bearer {access_token}",
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {access_token}",
|
||||
}
|
||||
|
||||
params = {}
|
||||
payload = {
|
||||
"fields": json.loads(fields)
|
||||
}
|
||||
payload = {"fields": json.loads(fields)}
|
||||
|
||||
try:
|
||||
res = httpx.put(url.format(app_token=app_token, table_id=table_id, record_id=record_id), headers=headers,
|
||||
params=params, json=payload, timeout=30)
|
||||
res = httpx.put(
|
||||
url.format(app_token=app_token, table_id=table_id, record_id=record_id),
|
||||
headers=headers,
|
||||
params=params,
|
||||
json=payload,
|
||||
timeout=30,
|
||||
)
|
||||
res_json = res.json()
|
||||
if res.is_success:
|
||||
return self.create_text_message(text=json.dumps(res_json))
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to update base record, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to update base record, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to update base record. {}".format(e))
|
||||
|
@@ -5,11 +5,11 @@ from core.tools.utils.feishu_api_utils import FeishuRequest
|
||||
|
||||
class FeishuDocumentProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict) -> None:
|
||||
app_id = credentials.get('app_id')
|
||||
app_secret = credentials.get('app_secret')
|
||||
app_id = credentials.get("app_id")
|
||||
app_secret = credentials.get("app_secret")
|
||||
if not app_id or not app_secret:
|
||||
raise ToolProviderCredentialValidationError("app_id and app_secret is required")
|
||||
try:
|
||||
assert FeishuRequest(app_id, app_secret).tenant_access_token is not None
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -7,13 +7,13 @@ from core.tools.utils.feishu_api_utils import FeishuRequest
|
||||
|
||||
class CreateDocumentTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
|
||||
app_id = self.runtime.credentials.get('app_id')
|
||||
app_secret = self.runtime.credentials.get('app_secret')
|
||||
app_id = self.runtime.credentials.get("app_id")
|
||||
app_secret = self.runtime.credentials.get("app_secret")
|
||||
client = FeishuRequest(app_id, app_secret)
|
||||
|
||||
title = tool_parameters.get('title')
|
||||
content = tool_parameters.get('content')
|
||||
folder_token = tool_parameters.get('folder_token')
|
||||
title = tool_parameters.get("title")
|
||||
content = tool_parameters.get("content")
|
||||
folder_token = tool_parameters.get("folder_token")
|
||||
|
||||
res = client.create_document(title, content, folder_token)
|
||||
return self.create_json_message(res)
|
||||
|
@@ -7,11 +7,11 @@ from core.tools.utils.feishu_api_utils import FeishuRequest
|
||||
|
||||
class GetDocumentRawContentTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
|
||||
app_id = self.runtime.credentials.get('app_id')
|
||||
app_secret = self.runtime.credentials.get('app_secret')
|
||||
app_id = self.runtime.credentials.get("app_id")
|
||||
app_secret = self.runtime.credentials.get("app_secret")
|
||||
client = FeishuRequest(app_id, app_secret)
|
||||
|
||||
document_id = tool_parameters.get('document_id')
|
||||
document_id = tool_parameters.get("document_id")
|
||||
|
||||
res = client.get_document_raw_content(document_id)
|
||||
return self.create_json_message(res)
|
||||
return self.create_json_message(res)
|
||||
|
@@ -7,13 +7,13 @@ from core.tools.utils.feishu_api_utils import FeishuRequest
|
||||
|
||||
class ListDocumentBlockTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
|
||||
app_id = self.runtime.credentials.get('app_id')
|
||||
app_secret = self.runtime.credentials.get('app_secret')
|
||||
app_id = self.runtime.credentials.get("app_id")
|
||||
app_secret = self.runtime.credentials.get("app_secret")
|
||||
client = FeishuRequest(app_id, app_secret)
|
||||
|
||||
document_id = tool_parameters.get('document_id')
|
||||
page_size = tool_parameters.get('page_size', 500)
|
||||
page_token = tool_parameters.get('page_token', '')
|
||||
document_id = tool_parameters.get("document_id")
|
||||
page_size = tool_parameters.get("page_size", 500)
|
||||
page_token = tool_parameters.get("page_token", "")
|
||||
|
||||
res = client.list_document_block(document_id, page_token, page_size)
|
||||
return self.create_json_message(res)
|
||||
|
@@ -7,13 +7,13 @@ from core.tools.utils.feishu_api_utils import FeishuRequest
|
||||
|
||||
class CreateDocumentTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
|
||||
app_id = self.runtime.credentials.get('app_id')
|
||||
app_secret = self.runtime.credentials.get('app_secret')
|
||||
app_id = self.runtime.credentials.get("app_id")
|
||||
app_secret = self.runtime.credentials.get("app_secret")
|
||||
client = FeishuRequest(app_id, app_secret)
|
||||
|
||||
document_id = tool_parameters.get('document_id')
|
||||
content = tool_parameters.get('content')
|
||||
position = tool_parameters.get('position')
|
||||
document_id = tool_parameters.get("document_id")
|
||||
content = tool_parameters.get("content")
|
||||
position = tool_parameters.get("position")
|
||||
|
||||
res = client.write_document(document_id, content, position)
|
||||
return self.create_json_message(res)
|
||||
|
@@ -5,11 +5,11 @@ from core.tools.utils.feishu_api_utils import FeishuRequest
|
||||
|
||||
class FeishuMessageProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict) -> None:
|
||||
app_id = credentials.get('app_id')
|
||||
app_secret = credentials.get('app_secret')
|
||||
app_id = credentials.get("app_id")
|
||||
app_secret = credentials.get("app_secret")
|
||||
if not app_id or not app_secret:
|
||||
raise ToolProviderCredentialValidationError("app_id and app_secret is required")
|
||||
try:
|
||||
assert FeishuRequest(app_id, app_secret).tenant_access_token is not None
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -7,14 +7,14 @@ from core.tools.utils.feishu_api_utils import FeishuRequest
|
||||
|
||||
class SendBotMessageTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
|
||||
app_id = self.runtime.credentials.get('app_id')
|
||||
app_secret = self.runtime.credentials.get('app_secret')
|
||||
app_id = self.runtime.credentials.get("app_id")
|
||||
app_secret = self.runtime.credentials.get("app_secret")
|
||||
client = FeishuRequest(app_id, app_secret)
|
||||
|
||||
receive_id_type = tool_parameters.get('receive_id_type')
|
||||
receive_id = tool_parameters.get('receive_id')
|
||||
msg_type = tool_parameters.get('msg_type')
|
||||
content = tool_parameters.get('content')
|
||||
receive_id_type = tool_parameters.get("receive_id_type")
|
||||
receive_id = tool_parameters.get("receive_id")
|
||||
msg_type = tool_parameters.get("msg_type")
|
||||
content = tool_parameters.get("content")
|
||||
|
||||
res = client.send_bot_message(receive_id_type, receive_id, msg_type, content)
|
||||
return self.create_json_message(res)
|
||||
|
@@ -6,14 +6,14 @@ from core.tools.utils.feishu_api_utils import FeishuRequest
|
||||
|
||||
|
||||
class SendWebhookMessageTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) ->ToolInvokeMessage:
|
||||
app_id = self.runtime.credentials.get('app_id')
|
||||
app_secret = self.runtime.credentials.get('app_secret')
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
|
||||
app_id = self.runtime.credentials.get("app_id")
|
||||
app_secret = self.runtime.credentials.get("app_secret")
|
||||
client = FeishuRequest(app_id, app_secret)
|
||||
|
||||
webhook = tool_parameters.get('webhook')
|
||||
msg_type = tool_parameters.get('msg_type')
|
||||
content = tool_parameters.get('content')
|
||||
webhook = tool_parameters.get("webhook")
|
||||
msg_type = tool_parameters.get("msg_type")
|
||||
content = tool_parameters.get("content")
|
||||
|
||||
res = client.send_webhook_message(webhook, msg_type, content)
|
||||
return self.create_json_message(res)
|
||||
|
@@ -7,15 +7,8 @@ class FirecrawlProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict) -> None:
|
||||
try:
|
||||
# Example validation using the ScrapeTool, only scraping title for minimize content
|
||||
ScrapeTool().fork_tool_runtime(
|
||||
runtime={"credentials": credentials}
|
||||
).invoke(
|
||||
user_id='',
|
||||
tool_parameters={
|
||||
"url": "https://google.com",
|
||||
"onlyIncludeTags": 'title'
|
||||
}
|
||||
ScrapeTool().fork_tool_runtime(runtime={"credentials": credentials}).invoke(
|
||||
user_id="", tool_parameters={"url": "https://google.com", "onlyIncludeTags": "title"}
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -13,27 +13,24 @@ logger = logging.getLogger(__name__)
|
||||
class FirecrawlApp:
|
||||
def __init__(self, api_key: str | None = None, base_url: str | None = None):
|
||||
self.api_key = api_key
|
||||
self.base_url = base_url or 'https://api.firecrawl.dev'
|
||||
self.base_url = base_url or "https://api.firecrawl.dev"
|
||||
if not self.api_key:
|
||||
raise ValueError("API key is required")
|
||||
|
||||
def _prepare_headers(self, idempotency_key: str | None = None):
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f'Bearer {self.api_key}'
|
||||
}
|
||||
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}"}
|
||||
if idempotency_key:
|
||||
headers['Idempotency-Key'] = idempotency_key
|
||||
headers["Idempotency-Key"] = idempotency_key
|
||||
return headers
|
||||
|
||||
def _request(
|
||||
self,
|
||||
method: str,
|
||||
url: str,
|
||||
data: Mapping[str, Any] | None = None,
|
||||
headers: Mapping[str, str] | None = None,
|
||||
retries: int = 3,
|
||||
backoff_factor: float = 0.3,
|
||||
self,
|
||||
method: str,
|
||||
url: str,
|
||||
data: Mapping[str, Any] | None = None,
|
||||
headers: Mapping[str, str] | None = None,
|
||||
retries: int = 3,
|
||||
backoff_factor: float = 0.3,
|
||||
) -> Mapping[str, Any] | None:
|
||||
if not headers:
|
||||
headers = self._prepare_headers()
|
||||
@@ -44,54 +41,54 @@ class FirecrawlApp:
|
||||
return response.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
if i < retries - 1:
|
||||
time.sleep(backoff_factor * (2 ** i))
|
||||
time.sleep(backoff_factor * (2**i))
|
||||
else:
|
||||
raise
|
||||
return None
|
||||
|
||||
def scrape_url(self, url: str, **kwargs):
|
||||
endpoint = f'{self.base_url}/v0/scrape'
|
||||
data = {'url': url, **kwargs}
|
||||
endpoint = f"{self.base_url}/v0/scrape"
|
||||
data = {"url": url, **kwargs}
|
||||
logger.debug(f"Sent request to {endpoint=} body={data}")
|
||||
response = self._request('POST', endpoint, data)
|
||||
response = self._request("POST", endpoint, data)
|
||||
if response is None:
|
||||
raise HTTPError("Failed to scrape URL after multiple retries")
|
||||
return response
|
||||
|
||||
def search(self, query: str, **kwargs):
|
||||
endpoint = f'{self.base_url}/v0/search'
|
||||
data = {'query': query, **kwargs}
|
||||
endpoint = f"{self.base_url}/v0/search"
|
||||
data = {"query": query, **kwargs}
|
||||
logger.debug(f"Sent request to {endpoint=} body={data}")
|
||||
response = self._request('POST', endpoint, data)
|
||||
response = self._request("POST", endpoint, data)
|
||||
if response is None:
|
||||
raise HTTPError("Failed to perform search after multiple retries")
|
||||
return response
|
||||
|
||||
def crawl_url(
|
||||
self, url: str, wait: bool = True, poll_interval: int = 5, idempotency_key: str | None = None, **kwargs
|
||||
self, url: str, wait: bool = True, poll_interval: int = 5, idempotency_key: str | None = None, **kwargs
|
||||
):
|
||||
endpoint = f'{self.base_url}/v0/crawl'
|
||||
endpoint = f"{self.base_url}/v0/crawl"
|
||||
headers = self._prepare_headers(idempotency_key)
|
||||
data = {'url': url, **kwargs}
|
||||
data = {"url": url, **kwargs}
|
||||
logger.debug(f"Sent request to {endpoint=} body={data}")
|
||||
response = self._request('POST', endpoint, data, headers)
|
||||
response = self._request("POST", endpoint, data, headers)
|
||||
if response is None:
|
||||
raise HTTPError("Failed to initiate crawl after multiple retries")
|
||||
job_id: str = response['jobId']
|
||||
job_id: str = response["jobId"]
|
||||
if wait:
|
||||
return self._monitor_job_status(job_id=job_id, poll_interval=poll_interval)
|
||||
return response
|
||||
|
||||
def check_crawl_status(self, job_id: str):
|
||||
endpoint = f'{self.base_url}/v0/crawl/status/{job_id}'
|
||||
response = self._request('GET', endpoint)
|
||||
endpoint = f"{self.base_url}/v0/crawl/status/{job_id}"
|
||||
response = self._request("GET", endpoint)
|
||||
if response is None:
|
||||
raise HTTPError(f"Failed to check status for job {job_id} after multiple retries")
|
||||
return response
|
||||
|
||||
def cancel_crawl_job(self, job_id: str):
|
||||
endpoint = f'{self.base_url}/v0/crawl/cancel/{job_id}'
|
||||
response = self._request('DELETE', endpoint)
|
||||
endpoint = f"{self.base_url}/v0/crawl/cancel/{job_id}"
|
||||
response = self._request("DELETE", endpoint)
|
||||
if response is None:
|
||||
raise HTTPError(f"Failed to cancel job {job_id} after multiple retries")
|
||||
return response
|
||||
@@ -99,9 +96,9 @@ class FirecrawlApp:
|
||||
def _monitor_job_status(self, job_id: str, poll_interval: int):
|
||||
while True:
|
||||
status = self.check_crawl_status(job_id)
|
||||
if status['status'] == 'completed':
|
||||
if status["status"] == "completed":
|
||||
return status
|
||||
elif status['status'] == 'failed':
|
||||
elif status["status"] == "failed":
|
||||
raise HTTPError(f'Job {job_id} failed: {status["error"]}')
|
||||
time.sleep(poll_interval)
|
||||
|
||||
@@ -109,7 +106,7 @@ class FirecrawlApp:
|
||||
def get_array_params(tool_parameters: dict[str, Any], key):
|
||||
param = tool_parameters.get(key)
|
||||
if param:
|
||||
return param.split(',')
|
||||
return param.split(",")
|
||||
|
||||
|
||||
def get_json_params(tool_parameters: dict[str, Any], key):
|
||||
|
@@ -11,38 +11,36 @@ class CrawlTool(BuiltinTool):
|
||||
the crawlerOptions and pageOptions comes from doc here:
|
||||
https://docs.firecrawl.dev/api-reference/endpoint/crawl
|
||||
"""
|
||||
app = FirecrawlApp(api_key=self.runtime.credentials['firecrawl_api_key'],
|
||||
base_url=self.runtime.credentials['base_url'])
|
||||
app = FirecrawlApp(
|
||||
api_key=self.runtime.credentials["firecrawl_api_key"], base_url=self.runtime.credentials["base_url"]
|
||||
)
|
||||
crawlerOptions = {}
|
||||
pageOptions = {}
|
||||
|
||||
wait_for_results = tool_parameters.get('wait_for_results', True)
|
||||
wait_for_results = tool_parameters.get("wait_for_results", True)
|
||||
|
||||
crawlerOptions['excludes'] = get_array_params(tool_parameters, 'excludes')
|
||||
crawlerOptions['includes'] = get_array_params(tool_parameters, 'includes')
|
||||
crawlerOptions['returnOnlyUrls'] = tool_parameters.get('returnOnlyUrls', False)
|
||||
crawlerOptions['maxDepth'] = tool_parameters.get('maxDepth')
|
||||
crawlerOptions['mode'] = tool_parameters.get('mode')
|
||||
crawlerOptions['ignoreSitemap'] = tool_parameters.get('ignoreSitemap', False)
|
||||
crawlerOptions['limit'] = tool_parameters.get('limit', 5)
|
||||
crawlerOptions['allowBackwardCrawling'] = tool_parameters.get('allowBackwardCrawling', False)
|
||||
crawlerOptions['allowExternalContentLinks'] = tool_parameters.get('allowExternalContentLinks', False)
|
||||
crawlerOptions["excludes"] = get_array_params(tool_parameters, "excludes")
|
||||
crawlerOptions["includes"] = get_array_params(tool_parameters, "includes")
|
||||
crawlerOptions["returnOnlyUrls"] = tool_parameters.get("returnOnlyUrls", False)
|
||||
crawlerOptions["maxDepth"] = tool_parameters.get("maxDepth")
|
||||
crawlerOptions["mode"] = tool_parameters.get("mode")
|
||||
crawlerOptions["ignoreSitemap"] = tool_parameters.get("ignoreSitemap", False)
|
||||
crawlerOptions["limit"] = tool_parameters.get("limit", 5)
|
||||
crawlerOptions["allowBackwardCrawling"] = tool_parameters.get("allowBackwardCrawling", False)
|
||||
crawlerOptions["allowExternalContentLinks"] = tool_parameters.get("allowExternalContentLinks", False)
|
||||
|
||||
pageOptions['headers'] = get_json_params(tool_parameters, 'headers')
|
||||
pageOptions['includeHtml'] = tool_parameters.get('includeHtml', False)
|
||||
pageOptions['includeRawHtml'] = tool_parameters.get('includeRawHtml', False)
|
||||
pageOptions['onlyIncludeTags'] = get_array_params(tool_parameters, 'onlyIncludeTags')
|
||||
pageOptions['removeTags'] = get_array_params(tool_parameters, 'removeTags')
|
||||
pageOptions['onlyMainContent'] = tool_parameters.get('onlyMainContent', False)
|
||||
pageOptions['replaceAllPathsWithAbsolutePaths'] = tool_parameters.get('replaceAllPathsWithAbsolutePaths', False)
|
||||
pageOptions['screenshot'] = tool_parameters.get('screenshot', False)
|
||||
pageOptions['waitFor'] = tool_parameters.get('waitFor', 0)
|
||||
pageOptions["headers"] = get_json_params(tool_parameters, "headers")
|
||||
pageOptions["includeHtml"] = tool_parameters.get("includeHtml", False)
|
||||
pageOptions["includeRawHtml"] = tool_parameters.get("includeRawHtml", False)
|
||||
pageOptions["onlyIncludeTags"] = get_array_params(tool_parameters, "onlyIncludeTags")
|
||||
pageOptions["removeTags"] = get_array_params(tool_parameters, "removeTags")
|
||||
pageOptions["onlyMainContent"] = tool_parameters.get("onlyMainContent", False)
|
||||
pageOptions["replaceAllPathsWithAbsolutePaths"] = tool_parameters.get("replaceAllPathsWithAbsolutePaths", False)
|
||||
pageOptions["screenshot"] = tool_parameters.get("screenshot", False)
|
||||
pageOptions["waitFor"] = tool_parameters.get("waitFor", 0)
|
||||
|
||||
crawl_result = app.crawl_url(
|
||||
url=tool_parameters['url'],
|
||||
wait=wait_for_results,
|
||||
crawlerOptions=crawlerOptions,
|
||||
pageOptions=pageOptions
|
||||
url=tool_parameters["url"], wait=wait_for_results, crawlerOptions=crawlerOptions, pageOptions=pageOptions
|
||||
)
|
||||
|
||||
return self.create_json_message(crawl_result)
|
||||
|
@@ -7,14 +7,15 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
class CrawlJobTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
|
||||
app = FirecrawlApp(api_key=self.runtime.credentials['firecrawl_api_key'],
|
||||
base_url=self.runtime.credentials['base_url'])
|
||||
operation = tool_parameters.get('operation', 'get')
|
||||
if operation == 'get':
|
||||
result = app.check_crawl_status(job_id=tool_parameters['job_id'])
|
||||
elif operation == 'cancel':
|
||||
result = app.cancel_crawl_job(job_id=tool_parameters['job_id'])
|
||||
app = FirecrawlApp(
|
||||
api_key=self.runtime.credentials["firecrawl_api_key"], base_url=self.runtime.credentials["base_url"]
|
||||
)
|
||||
operation = tool_parameters.get("operation", "get")
|
||||
if operation == "get":
|
||||
result = app.check_crawl_status(job_id=tool_parameters["job_id"])
|
||||
elif operation == "cancel":
|
||||
result = app.cancel_crawl_job(job_id=tool_parameters["job_id"])
|
||||
else:
|
||||
raise ValueError(f'Invalid operation: {operation}')
|
||||
raise ValueError(f"Invalid operation: {operation}")
|
||||
|
||||
return self.create_json_message(result)
|
||||
|
@@ -6,34 +6,34 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class ScrapeTool(BuiltinTool):
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> ToolInvokeMessage:
|
||||
"""
|
||||
the pageOptions and extractorOptions comes from doc here:
|
||||
https://docs.firecrawl.dev/api-reference/endpoint/scrape
|
||||
"""
|
||||
app = FirecrawlApp(api_key=self.runtime.credentials['firecrawl_api_key'],
|
||||
base_url=self.runtime.credentials['base_url'])
|
||||
app = FirecrawlApp(
|
||||
api_key=self.runtime.credentials["firecrawl_api_key"], base_url=self.runtime.credentials["base_url"]
|
||||
)
|
||||
|
||||
pageOptions = {}
|
||||
extractorOptions = {}
|
||||
|
||||
pageOptions['headers'] = get_json_params(tool_parameters, 'headers')
|
||||
pageOptions['includeHtml'] = tool_parameters.get('includeHtml', False)
|
||||
pageOptions['includeRawHtml'] = tool_parameters.get('includeRawHtml', False)
|
||||
pageOptions['onlyIncludeTags'] = get_array_params(tool_parameters, 'onlyIncludeTags')
|
||||
pageOptions['removeTags'] = get_array_params(tool_parameters, 'removeTags')
|
||||
pageOptions['onlyMainContent'] = tool_parameters.get('onlyMainContent', False)
|
||||
pageOptions['replaceAllPathsWithAbsolutePaths'] = tool_parameters.get('replaceAllPathsWithAbsolutePaths', False)
|
||||
pageOptions['screenshot'] = tool_parameters.get('screenshot', False)
|
||||
pageOptions['waitFor'] = tool_parameters.get('waitFor', 0)
|
||||
pageOptions["headers"] = get_json_params(tool_parameters, "headers")
|
||||
pageOptions["includeHtml"] = tool_parameters.get("includeHtml", False)
|
||||
pageOptions["includeRawHtml"] = tool_parameters.get("includeRawHtml", False)
|
||||
pageOptions["onlyIncludeTags"] = get_array_params(tool_parameters, "onlyIncludeTags")
|
||||
pageOptions["removeTags"] = get_array_params(tool_parameters, "removeTags")
|
||||
pageOptions["onlyMainContent"] = tool_parameters.get("onlyMainContent", False)
|
||||
pageOptions["replaceAllPathsWithAbsolutePaths"] = tool_parameters.get("replaceAllPathsWithAbsolutePaths", False)
|
||||
pageOptions["screenshot"] = tool_parameters.get("screenshot", False)
|
||||
pageOptions["waitFor"] = tool_parameters.get("waitFor", 0)
|
||||
|
||||
extractorOptions['mode'] = tool_parameters.get('mode', '')
|
||||
extractorOptions['extractionPrompt'] = tool_parameters.get('extractionPrompt', '')
|
||||
extractorOptions['extractionSchema'] = get_json_params(tool_parameters, 'extractionSchema')
|
||||
extractorOptions["mode"] = tool_parameters.get("mode", "")
|
||||
extractorOptions["extractionPrompt"] = tool_parameters.get("extractionPrompt", "")
|
||||
extractorOptions["extractionSchema"] = get_json_params(tool_parameters, "extractionSchema")
|
||||
|
||||
crawl_result = app.scrape_url(url=tool_parameters['url'],
|
||||
pageOptions=pageOptions,
|
||||
extractorOptions=extractorOptions)
|
||||
crawl_result = app.scrape_url(
|
||||
url=tool_parameters["url"], pageOptions=pageOptions, extractorOptions=extractorOptions
|
||||
)
|
||||
|
||||
return self.create_json_message(crawl_result)
|
||||
|
@@ -11,18 +11,17 @@ class SearchTool(BuiltinTool):
|
||||
the pageOptions and searchOptions comes from doc here:
|
||||
https://docs.firecrawl.dev/api-reference/endpoint/search
|
||||
"""
|
||||
app = FirecrawlApp(api_key=self.runtime.credentials['firecrawl_api_key'],
|
||||
base_url=self.runtime.credentials['base_url'])
|
||||
app = FirecrawlApp(
|
||||
api_key=self.runtime.credentials["firecrawl_api_key"], base_url=self.runtime.credentials["base_url"]
|
||||
)
|
||||
pageOptions = {}
|
||||
pageOptions['onlyMainContent'] = tool_parameters.get('onlyMainContent', False)
|
||||
pageOptions['fetchPageContent'] = tool_parameters.get('fetchPageContent', True)
|
||||
pageOptions['includeHtml'] = tool_parameters.get('includeHtml', False)
|
||||
pageOptions['includeRawHtml'] = tool_parameters.get('includeRawHtml', False)
|
||||
searchOptions = {'limit': tool_parameters.get('limit')}
|
||||
pageOptions["onlyMainContent"] = tool_parameters.get("onlyMainContent", False)
|
||||
pageOptions["fetchPageContent"] = tool_parameters.get("fetchPageContent", True)
|
||||
pageOptions["includeHtml"] = tool_parameters.get("includeHtml", False)
|
||||
pageOptions["includeRawHtml"] = tool_parameters.get("includeRawHtml", False)
|
||||
searchOptions = {"limit": tool_parameters.get("limit")}
|
||||
search_result = app.search(
|
||||
query=tool_parameters['keyword'],
|
||||
pageOptions=pageOptions,
|
||||
searchOptions=searchOptions
|
||||
query=tool_parameters["keyword"], pageOptions=pageOptions, searchOptions=searchOptions
|
||||
)
|
||||
|
||||
return self.create_json_message(search_result)
|
||||
|
@@ -9,17 +9,19 @@ from core.tools.provider.builtin_tool_provider import BuiltinToolProviderControl
|
||||
class GaodeProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict) -> None:
|
||||
try:
|
||||
if 'api_key' not in credentials or not credentials.get('api_key'):
|
||||
if "api_key" not in credentials or not credentials.get("api_key"):
|
||||
raise ToolProviderCredentialValidationError("Gaode API key is required.")
|
||||
|
||||
try:
|
||||
response = requests.get(url="https://restapi.amap.com/v3/geocode/geo?address={address}&key={apikey}"
|
||||
"".format(address=urllib.parse.quote('广东省广州市天河区广州塔'),
|
||||
apikey=credentials.get('api_key')))
|
||||
if response.status_code == 200 and (response.json()).get('info') == 'OK':
|
||||
response = requests.get(
|
||||
url="https://restapi.amap.com/v3/geocode/geo?address={address}&key={apikey}" "".format(
|
||||
address=urllib.parse.quote("广东省广州市天河区广州塔"), apikey=credentials.get("api_key")
|
||||
)
|
||||
)
|
||||
if response.status_code == 200 and (response.json()).get("info") == "OK":
|
||||
pass
|
||||
else:
|
||||
raise ToolProviderCredentialValidationError((response.json()).get('info'))
|
||||
raise ToolProviderCredentialValidationError((response.json()).get("info"))
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError("Gaode API Key is invalid. {}".format(e))
|
||||
except Exception as e:
|
||||
|
@@ -8,50 +8,57 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class GaodeRepositoriesTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
city = tool_parameters.get('city', '')
|
||||
city = tool_parameters.get("city", "")
|
||||
if not city:
|
||||
return self.create_text_message('Please tell me your city')
|
||||
return self.create_text_message("Please tell me your city")
|
||||
|
||||
if 'api_key' not in self.runtime.credentials or not self.runtime.credentials.get('api_key'):
|
||||
if "api_key" not in self.runtime.credentials or not self.runtime.credentials.get("api_key"):
|
||||
return self.create_text_message("Gaode API key is required.")
|
||||
|
||||
try:
|
||||
s = requests.session()
|
||||
api_domain = 'https://restapi.amap.com/v3'
|
||||
city_response = s.request(method='GET', headers={"Content-Type": "application/json; charset=utf-8"},
|
||||
url="{url}/config/district?keywords={keywords}"
|
||||
"&subdistrict=0&extensions=base&key={apikey}"
|
||||
"".format(url=api_domain, keywords=city,
|
||||
apikey=self.runtime.credentials.get('api_key')))
|
||||
api_domain = "https://restapi.amap.com/v3"
|
||||
city_response = s.request(
|
||||
method="GET",
|
||||
headers={"Content-Type": "application/json; charset=utf-8"},
|
||||
url="{url}/config/district?keywords={keywords}" "&subdistrict=0&extensions=base&key={apikey}" "".format(
|
||||
url=api_domain, keywords=city, apikey=self.runtime.credentials.get("api_key")
|
||||
),
|
||||
)
|
||||
City_data = city_response.json()
|
||||
if city_response.status_code == 200 and City_data.get('info') == 'OK':
|
||||
if len(City_data.get('districts')) > 0:
|
||||
CityCode = City_data['districts'][0]['adcode']
|
||||
weatherInfo_response = s.request(method='GET',
|
||||
url="{url}/weather/weatherInfo?city={citycode}&extensions=all&key={apikey}&output=json"
|
||||
"".format(url=api_domain, citycode=CityCode,
|
||||
apikey=self.runtime.credentials.get('api_key')))
|
||||
if city_response.status_code == 200 and City_data.get("info") == "OK":
|
||||
if len(City_data.get("districts")) > 0:
|
||||
CityCode = City_data["districts"][0]["adcode"]
|
||||
weatherInfo_response = s.request(
|
||||
method="GET",
|
||||
url="{url}/weather/weatherInfo?city={citycode}&extensions=all&key={apikey}&output=json"
|
||||
"".format(url=api_domain, citycode=CityCode, apikey=self.runtime.credentials.get("api_key")),
|
||||
)
|
||||
weatherInfo_data = weatherInfo_response.json()
|
||||
if weatherInfo_response.status_code == 200 and weatherInfo_data.get('info') == 'OK':
|
||||
if weatherInfo_response.status_code == 200 and weatherInfo_data.get("info") == "OK":
|
||||
contents = []
|
||||
if len(weatherInfo_data.get('forecasts')) > 0:
|
||||
for item in weatherInfo_data['forecasts'][0]['casts']:
|
||||
if len(weatherInfo_data.get("forecasts")) > 0:
|
||||
for item in weatherInfo_data["forecasts"][0]["casts"]:
|
||||
content = {}
|
||||
content['date'] = item.get('date')
|
||||
content['week'] = item.get('week')
|
||||
content['dayweather'] = item.get('dayweather')
|
||||
content['daytemp_float'] = item.get('daytemp_float')
|
||||
content['daywind'] = item.get('daywind')
|
||||
content['nightweather'] = item.get('nightweather')
|
||||
content['nighttemp_float'] = item.get('nighttemp_float')
|
||||
content["date"] = item.get("date")
|
||||
content["week"] = item.get("week")
|
||||
content["dayweather"] = item.get("dayweather")
|
||||
content["daytemp_float"] = item.get("daytemp_float")
|
||||
content["daywind"] = item.get("daywind")
|
||||
content["nightweather"] = item.get("nightweather")
|
||||
content["nighttemp_float"] = item.get("nighttemp_float")
|
||||
contents.append(content)
|
||||
s.close()
|
||||
return self.create_text_message(self.summary(user_id=user_id, content=json.dumps(contents, ensure_ascii=False)))
|
||||
return self.create_text_message(
|
||||
self.summary(user_id=user_id, content=json.dumps(contents, ensure_ascii=False))
|
||||
)
|
||||
s.close()
|
||||
return self.create_text_message(f'No weather information for {city} was found.')
|
||||
return self.create_text_message(f"No weather information for {city} was found.")
|
||||
except Exception as e:
|
||||
return self.create_text_message("Gaode API Key and Api Version is invalid. {}".format(e))
|
||||
|
@@ -7,16 +7,13 @@ class GetImgAIProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict) -> None:
|
||||
try:
|
||||
# Example validation using the text2image tool
|
||||
Text2ImageTool().fork_tool_runtime(
|
||||
runtime={"credentials": credentials}
|
||||
).invoke(
|
||||
user_id='',
|
||||
Text2ImageTool().fork_tool_runtime(runtime={"credentials": credentials}).invoke(
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"prompt": "A fire egg",
|
||||
"response_format": "url",
|
||||
"style": "photorealism",
|
||||
}
|
||||
},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -8,18 +8,16 @@ from requests.exceptions import HTTPError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GetImgAIApp:
|
||||
def __init__(self, api_key: str | None = None, base_url: str | None = None):
|
||||
self.api_key = api_key
|
||||
self.base_url = base_url or 'https://api.getimg.ai/v1'
|
||||
self.base_url = base_url or "https://api.getimg.ai/v1"
|
||||
if not self.api_key:
|
||||
raise ValueError("API key is required")
|
||||
|
||||
def _prepare_headers(self):
|
||||
headers = {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f'Bearer {self.api_key}'
|
||||
}
|
||||
headers = {"Content-Type": "application/json", "Authorization": f"Bearer {self.api_key}"}
|
||||
return headers
|
||||
|
||||
def _request(
|
||||
@@ -38,22 +36,20 @@ class GetImgAIApp:
|
||||
return response.json()
|
||||
except requests.exceptions.RequestException as e:
|
||||
if i < retries - 1 and isinstance(e, HTTPError) and e.response.status_code >= 500:
|
||||
time.sleep(backoff_factor * (2 ** i))
|
||||
time.sleep(backoff_factor * (2**i))
|
||||
else:
|
||||
raise
|
||||
return None
|
||||
|
||||
def text2image(
|
||||
self, mode: str, **kwargs
|
||||
):
|
||||
data = kwargs['params']
|
||||
if not data.get('prompt'):
|
||||
def text2image(self, mode: str, **kwargs):
|
||||
data = kwargs["params"]
|
||||
if not data.get("prompt"):
|
||||
raise ValueError("Prompt is required")
|
||||
|
||||
endpoint = f'{self.base_url}/{mode}/text-to-image'
|
||||
endpoint = f"{self.base_url}/{mode}/text-to-image"
|
||||
headers = self._prepare_headers()
|
||||
logger.debug(f"Send request to {endpoint=} body={data}")
|
||||
response = self._request('POST', endpoint, data, headers)
|
||||
response = self._request("POST", endpoint, data, headers)
|
||||
if response is None:
|
||||
raise HTTPError("Failed to initiate getimg.ai after multiple retries")
|
||||
return response
|
||||
|
@@ -7,28 +7,28 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class Text2ImageTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
app = GetImgAIApp(api_key=self.runtime.credentials['getimg_api_key'], base_url=self.runtime.credentials['base_url'])
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
app = GetImgAIApp(
|
||||
api_key=self.runtime.credentials["getimg_api_key"], base_url=self.runtime.credentials["base_url"]
|
||||
)
|
||||
|
||||
options = {
|
||||
'style': tool_parameters.get('style'),
|
||||
'prompt': tool_parameters.get('prompt'),
|
||||
'aspect_ratio': tool_parameters.get('aspect_ratio'),
|
||||
'output_format': tool_parameters.get('output_format', 'jpeg'),
|
||||
'response_format': tool_parameters.get('response_format', 'url'),
|
||||
'width': tool_parameters.get('width'),
|
||||
'height': tool_parameters.get('height'),
|
||||
'steps': tool_parameters.get('steps'),
|
||||
'negative_prompt': tool_parameters.get('negative_prompt'),
|
||||
'prompt_2': tool_parameters.get('prompt_2'),
|
||||
"style": tool_parameters.get("style"),
|
||||
"prompt": tool_parameters.get("prompt"),
|
||||
"aspect_ratio": tool_parameters.get("aspect_ratio"),
|
||||
"output_format": tool_parameters.get("output_format", "jpeg"),
|
||||
"response_format": tool_parameters.get("response_format", "url"),
|
||||
"width": tool_parameters.get("width"),
|
||||
"height": tool_parameters.get("height"),
|
||||
"steps": tool_parameters.get("steps"),
|
||||
"negative_prompt": tool_parameters.get("negative_prompt"),
|
||||
"prompt_2": tool_parameters.get("prompt_2"),
|
||||
}
|
||||
options = {k: v for k, v in options.items() if v}
|
||||
|
||||
text2image_result = app.text2image(
|
||||
mode=tool_parameters.get('mode', 'essential-v2'),
|
||||
params=options,
|
||||
wait=True
|
||||
)
|
||||
text2image_result = app.text2image(mode=tool_parameters.get("mode", "essential-v2"), params=options, wait=True)
|
||||
|
||||
if not isinstance(text2image_result, str):
|
||||
text2image_result = json.dumps(text2image_result, ensure_ascii=False, indent=4)
|
||||
|
@@ -7,25 +7,25 @@ from core.tools.provider.builtin_tool_provider import BuiltinToolProviderControl
|
||||
class GithubProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict) -> None:
|
||||
try:
|
||||
if 'access_tokens' not in credentials or not credentials.get('access_tokens'):
|
||||
if "access_tokens" not in credentials or not credentials.get("access_tokens"):
|
||||
raise ToolProviderCredentialValidationError("Github API Access Tokens is required.")
|
||||
if 'api_version' not in credentials or not credentials.get('api_version'):
|
||||
api_version = '2022-11-28'
|
||||
if "api_version" not in credentials or not credentials.get("api_version"):
|
||||
api_version = "2022-11-28"
|
||||
else:
|
||||
api_version = credentials.get('api_version')
|
||||
api_version = credentials.get("api_version")
|
||||
|
||||
try:
|
||||
headers = {
|
||||
"Content-Type": "application/vnd.github+json",
|
||||
"Authorization": f"Bearer {credentials.get('access_tokens')}",
|
||||
"X-GitHub-Api-Version": api_version
|
||||
"X-GitHub-Api-Version": api_version,
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
url="https://api.github.com/search/users?q={account}".format(account='charli117'),
|
||||
headers=headers)
|
||||
url="https://api.github.com/search/users?q={account}".format(account="charli117"), headers=headers
|
||||
)
|
||||
if response.status_code != 200:
|
||||
raise ToolProviderCredentialValidationError((response.json()).get('message'))
|
||||
raise ToolProviderCredentialValidationError((response.json()).get("message"))
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError("Github API Key and Api Version is invalid. {}".format(e))
|
||||
except Exception as e:
|
||||
|
@@ -10,53 +10,61 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class GithubRepositoriesTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
top_n = tool_parameters.get('top_n', 5)
|
||||
query = tool_parameters.get('query', '')
|
||||
top_n = tool_parameters.get("top_n", 5)
|
||||
query = tool_parameters.get("query", "")
|
||||
if not query:
|
||||
return self.create_text_message('Please input symbol')
|
||||
return self.create_text_message("Please input symbol")
|
||||
|
||||
if 'access_tokens' not in self.runtime.credentials or not self.runtime.credentials.get('access_tokens'):
|
||||
if "access_tokens" not in self.runtime.credentials or not self.runtime.credentials.get("access_tokens"):
|
||||
return self.create_text_message("Github API Access Tokens is required.")
|
||||
if 'api_version' not in self.runtime.credentials or not self.runtime.credentials.get('api_version'):
|
||||
api_version = '2022-11-28'
|
||||
if "api_version" not in self.runtime.credentials or not self.runtime.credentials.get("api_version"):
|
||||
api_version = "2022-11-28"
|
||||
else:
|
||||
api_version = self.runtime.credentials.get('api_version')
|
||||
api_version = self.runtime.credentials.get("api_version")
|
||||
|
||||
try:
|
||||
headers = {
|
||||
"Content-Type": "application/vnd.github+json",
|
||||
"Authorization": f"Bearer {self.runtime.credentials.get('access_tokens')}",
|
||||
"X-GitHub-Api-Version": api_version
|
||||
"X-GitHub-Api-Version": api_version,
|
||||
}
|
||||
s = requests.session()
|
||||
api_domain = 'https://api.github.com'
|
||||
response = s.request(method='GET', headers=headers,
|
||||
url=f"{api_domain}/search/repositories?"
|
||||
f"q={quote(query)}&sort=stars&per_page={top_n}&order=desc")
|
||||
api_domain = "https://api.github.com"
|
||||
response = s.request(
|
||||
method="GET",
|
||||
headers=headers,
|
||||
url=f"{api_domain}/search/repositories?" f"q={quote(query)}&sort=stars&per_page={top_n}&order=desc",
|
||||
)
|
||||
response_data = response.json()
|
||||
if response.status_code == 200 and isinstance(response_data.get('items'), list):
|
||||
if response.status_code == 200 and isinstance(response_data.get("items"), list):
|
||||
contents = []
|
||||
if len(response_data.get('items')) > 0:
|
||||
for item in response_data.get('items'):
|
||||
if len(response_data.get("items")) > 0:
|
||||
for item in response_data.get("items"):
|
||||
content = {}
|
||||
updated_at_object = datetime.strptime(item['updated_at'], "%Y-%m-%dT%H:%M:%SZ")
|
||||
content['owner'] = item['owner']['login']
|
||||
content['name'] = item['name']
|
||||
content['description'] = item['description'][:100] + '...' if len(item['description']) > 100 else item['description']
|
||||
content['url'] = item['html_url']
|
||||
content['star'] = item['watchers']
|
||||
content['forks'] = item['forks']
|
||||
content['updated'] = updated_at_object.strftime("%Y-%m-%d")
|
||||
updated_at_object = datetime.strptime(item["updated_at"], "%Y-%m-%dT%H:%M:%SZ")
|
||||
content["owner"] = item["owner"]["login"]
|
||||
content["name"] = item["name"]
|
||||
content["description"] = (
|
||||
item["description"][:100] + "..." if len(item["description"]) > 100 else item["description"]
|
||||
)
|
||||
content["url"] = item["html_url"]
|
||||
content["star"] = item["watchers"]
|
||||
content["forks"] = item["forks"]
|
||||
content["updated"] = updated_at_object.strftime("%Y-%m-%d")
|
||||
contents.append(content)
|
||||
s.close()
|
||||
return self.create_text_message(self.summary(user_id=user_id, content=json.dumps(contents, ensure_ascii=False)))
|
||||
return self.create_text_message(
|
||||
self.summary(user_id=user_id, content=json.dumps(contents, ensure_ascii=False))
|
||||
)
|
||||
else:
|
||||
return self.create_text_message(f'No items related to {query} were found.')
|
||||
return self.create_text_message(f"No items related to {query} were found.")
|
||||
else:
|
||||
return self.create_text_message((response.json()).get('message'))
|
||||
return self.create_text_message((response.json()).get("message"))
|
||||
except Exception as e:
|
||||
return self.create_text_message("Github API Key and Api Version is invalid. {}".format(e))
|
||||
|
@@ -9,13 +9,13 @@ from core.tools.provider.builtin_tool_provider import BuiltinToolProviderControl
|
||||
class GitlabProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict[str, Any]) -> None:
|
||||
try:
|
||||
if 'access_tokens' not in credentials or not credentials.get('access_tokens'):
|
||||
if "access_tokens" not in credentials or not credentials.get("access_tokens"):
|
||||
raise ToolProviderCredentialValidationError("Gitlab Access Tokens is required.")
|
||||
|
||||
if 'site_url' not in credentials or not credentials.get('site_url'):
|
||||
site_url = 'https://gitlab.com'
|
||||
|
||||
if "site_url" not in credentials or not credentials.get("site_url"):
|
||||
site_url = "https://gitlab.com"
|
||||
else:
|
||||
site_url = credentials.get('site_url')
|
||||
site_url = credentials.get("site_url")
|
||||
|
||||
try:
|
||||
headers = {
|
||||
@@ -23,12 +23,10 @@ class GitlabProvider(BuiltinToolProviderController):
|
||||
"Authorization": f"Bearer {credentials.get('access_tokens')}",
|
||||
}
|
||||
|
||||
response = requests.get(
|
||||
url= f"{site_url}/api/v4/user",
|
||||
headers=headers)
|
||||
response = requests.get(url=f"{site_url}/api/v4/user", headers=headers)
|
||||
if response.status_code != 200:
|
||||
raise ToolProviderCredentialValidationError((response.json()).get('message'))
|
||||
raise ToolProviderCredentialValidationError((response.json()).get("message"))
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError("Gitlab Access Tokens is invalid. {}".format(e))
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -9,39 +9,47 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class GitlabCommitsTool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
project = tool_parameters.get('project', '')
|
||||
employee = tool_parameters.get('employee', '')
|
||||
start_time = tool_parameters.get('start_time', '')
|
||||
end_time = tool_parameters.get('end_time', '')
|
||||
change_type = tool_parameters.get('change_type', 'all')
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
project = tool_parameters.get("project", "")
|
||||
employee = tool_parameters.get("employee", "")
|
||||
start_time = tool_parameters.get("start_time", "")
|
||||
end_time = tool_parameters.get("end_time", "")
|
||||
change_type = tool_parameters.get("change_type", "all")
|
||||
|
||||
if not project:
|
||||
return self.create_text_message('Project is required')
|
||||
return self.create_text_message("Project is required")
|
||||
|
||||
if not start_time:
|
||||
start_time = (datetime.utcnow() - timedelta(days=1)).isoformat()
|
||||
if not end_time:
|
||||
end_time = datetime.utcnow().isoformat()
|
||||
|
||||
access_token = self.runtime.credentials.get('access_tokens')
|
||||
site_url = self.runtime.credentials.get('site_url')
|
||||
access_token = self.runtime.credentials.get("access_tokens")
|
||||
site_url = self.runtime.credentials.get("site_url")
|
||||
|
||||
if 'access_tokens' not in self.runtime.credentials or not self.runtime.credentials.get('access_tokens'):
|
||||
if "access_tokens" not in self.runtime.credentials or not self.runtime.credentials.get("access_tokens"):
|
||||
return self.create_text_message("Gitlab API Access Tokens is required.")
|
||||
if 'site_url' not in self.runtime.credentials or not self.runtime.credentials.get('site_url'):
|
||||
site_url = 'https://gitlab.com'
|
||||
|
||||
if "site_url" not in self.runtime.credentials or not self.runtime.credentials.get("site_url"):
|
||||
site_url = "https://gitlab.com"
|
||||
|
||||
# Get commit content
|
||||
result = self.fetch(user_id, site_url, access_token, project, employee, start_time, end_time, change_type)
|
||||
|
||||
return [self.create_json_message(item) for item in result]
|
||||
|
||||
def fetch(self,user_id: str, site_url: str, access_token: str, project: str, employee: str = None, start_time: str = '', end_time: str = '', change_type: str = '') -> list[dict[str, Any]]:
|
||||
|
||||
def fetch(
|
||||
self,
|
||||
user_id: str,
|
||||
site_url: str,
|
||||
access_token: str,
|
||||
project: str,
|
||||
employee: str = None,
|
||||
start_time: str = "",
|
||||
end_time: str = "",
|
||||
change_type: str = "",
|
||||
) -> list[dict[str, Any]]:
|
||||
domain = site_url
|
||||
headers = {"PRIVATE-TOKEN": access_token}
|
||||
results = []
|
||||
@@ -53,59 +61,66 @@ class GitlabCommitsTool(BuiltinTool):
|
||||
response.raise_for_status()
|
||||
projects = response.json()
|
||||
|
||||
filtered_projects = [p for p in projects if project == "*" or p['name'] == project]
|
||||
filtered_projects = [p for p in projects if project == "*" or p["name"] == project]
|
||||
|
||||
for project in filtered_projects:
|
||||
project_id = project['id']
|
||||
project_name = project['name']
|
||||
project_id = project["id"]
|
||||
project_name = project["name"]
|
||||
print(f"Project: {project_name}")
|
||||
|
||||
# Get all of project commits
|
||||
commits_url = f"{domain}/api/v4/projects/{project_id}/repository/commits"
|
||||
params = {
|
||||
'since': start_time,
|
||||
'until': end_time
|
||||
}
|
||||
params = {"since": start_time, "until": end_time}
|
||||
if employee:
|
||||
params['author'] = employee
|
||||
params["author"] = employee
|
||||
|
||||
commits_response = requests.get(commits_url, headers=headers, params=params)
|
||||
commits_response.raise_for_status()
|
||||
commits = commits_response.json()
|
||||
|
||||
for commit in commits:
|
||||
commit_sha = commit['id']
|
||||
author_name = commit['author_name']
|
||||
commit_sha = commit["id"]
|
||||
author_name = commit["author_name"]
|
||||
|
||||
diff_url = f"{domain}/api/v4/projects/{project_id}/repository/commits/{commit_sha}/diff"
|
||||
diff_response = requests.get(diff_url, headers=headers)
|
||||
diff_response.raise_for_status()
|
||||
diffs = diff_response.json()
|
||||
|
||||
|
||||
for diff in diffs:
|
||||
# Calculate code lines of changed
|
||||
added_lines = diff['diff'].count('\n+')
|
||||
removed_lines = diff['diff'].count('\n-')
|
||||
added_lines = diff["diff"].count("\n+")
|
||||
removed_lines = diff["diff"].count("\n-")
|
||||
total_changes = added_lines + removed_lines
|
||||
|
||||
if change_type == "new":
|
||||
if added_lines > 1:
|
||||
final_code = ''.join([line[1:] for line in diff['diff'].split('\n') if line.startswith('+') and not line.startswith('+++')])
|
||||
results.append({
|
||||
"commit_sha": commit_sha,
|
||||
"author_name": author_name,
|
||||
"diff": final_code
|
||||
})
|
||||
final_code = "".join(
|
||||
[
|
||||
line[1:]
|
||||
for line in diff["diff"].split("\n")
|
||||
if line.startswith("+") and not line.startswith("+++")
|
||||
]
|
||||
)
|
||||
results.append(
|
||||
{"commit_sha": commit_sha, "author_name": author_name, "diff": final_code}
|
||||
)
|
||||
else:
|
||||
if total_changes > 1:
|
||||
final_code = ''.join([line[1:] for line in diff['diff'].split('\n') if (line.startswith('+') or line.startswith('-')) and not line.startswith('+++') and not line.startswith('---')])
|
||||
final_code = "".join(
|
||||
[
|
||||
line[1:]
|
||||
for line in diff["diff"].split("\n")
|
||||
if (line.startswith("+") or line.startswith("-"))
|
||||
and not line.startswith("+++")
|
||||
and not line.startswith("---")
|
||||
]
|
||||
)
|
||||
final_code_escaped = json.dumps(final_code)[1:-1] # Escape the final code
|
||||
results.append({
|
||||
"commit_sha": commit_sha,
|
||||
"author_name": author_name,
|
||||
"diff": final_code_escaped
|
||||
})
|
||||
results.append(
|
||||
{"commit_sha": commit_sha, "author_name": author_name, "diff": final_code_escaped}
|
||||
)
|
||||
except requests.RequestException as e:
|
||||
print(f"Error fetching data from GitLab: {e}")
|
||||
|
||||
return results
|
||||
|
||||
return results
|
||||
|
@@ -7,32 +7,29 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class GitlabFilesTool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
project = tool_parameters.get('project', '')
|
||||
branch = tool_parameters.get('branch', '')
|
||||
path = tool_parameters.get('path', '')
|
||||
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
project = tool_parameters.get("project", "")
|
||||
branch = tool_parameters.get("branch", "")
|
||||
path = tool_parameters.get("path", "")
|
||||
|
||||
if not project:
|
||||
return self.create_text_message('Project is required')
|
||||
return self.create_text_message("Project is required")
|
||||
if not branch:
|
||||
return self.create_text_message('Branch is required')
|
||||
return self.create_text_message("Branch is required")
|
||||
|
||||
if not path:
|
||||
return self.create_text_message('Path is required')
|
||||
return self.create_text_message("Path is required")
|
||||
|
||||
access_token = self.runtime.credentials.get('access_tokens')
|
||||
site_url = self.runtime.credentials.get('site_url')
|
||||
access_token = self.runtime.credentials.get("access_tokens")
|
||||
site_url = self.runtime.credentials.get("site_url")
|
||||
|
||||
if 'access_tokens' not in self.runtime.credentials or not self.runtime.credentials.get('access_tokens'):
|
||||
if "access_tokens" not in self.runtime.credentials or not self.runtime.credentials.get("access_tokens"):
|
||||
return self.create_text_message("Gitlab API Access Tokens is required.")
|
||||
if 'site_url' not in self.runtime.credentials or not self.runtime.credentials.get('site_url'):
|
||||
site_url = 'https://gitlab.com'
|
||||
|
||||
if "site_url" not in self.runtime.credentials or not self.runtime.credentials.get("site_url"):
|
||||
site_url = "https://gitlab.com"
|
||||
|
||||
# Get project ID from project name
|
||||
project_id = self.get_project_id(site_url, access_token, project)
|
||||
if not project_id:
|
||||
@@ -42,9 +39,9 @@ class GitlabFilesTool(BuiltinTool):
|
||||
result = self.fetch(user_id, project_id, site_url, access_token, branch, path)
|
||||
|
||||
return [self.create_json_message(item) for item in result]
|
||||
|
||||
|
||||
def extract_project_name_and_path(self, path: str) -> tuple[str, str]:
|
||||
parts = path.split('/', 1)
|
||||
parts = path.split("/", 1)
|
||||
if len(parts) < 2:
|
||||
return None, None
|
||||
return parts[0], parts[1]
|
||||
@@ -57,13 +54,15 @@ class GitlabFilesTool(BuiltinTool):
|
||||
response.raise_for_status()
|
||||
projects = response.json()
|
||||
for project in projects:
|
||||
if project['name'] == project_name:
|
||||
return project['id']
|
||||
if project["name"] == project_name:
|
||||
return project["id"]
|
||||
except requests.RequestException as e:
|
||||
print(f"Error fetching project ID from GitLab: {e}")
|
||||
return None
|
||||
|
||||
def fetch(self,user_id: str, project_id: str, site_url: str, access_token: str, branch: str, path: str = None) -> list[dict[str, Any]]:
|
||||
|
||||
def fetch(
|
||||
self, user_id: str, project_id: str, site_url: str, access_token: str, branch: str, path: str = None
|
||||
) -> list[dict[str, Any]]:
|
||||
domain = site_url
|
||||
headers = {"PRIVATE-TOKEN": access_token}
|
||||
results = []
|
||||
@@ -76,20 +75,16 @@ class GitlabFilesTool(BuiltinTool):
|
||||
items = response.json()
|
||||
|
||||
for item in items:
|
||||
item_path = item['path']
|
||||
if item['type'] == 'tree': # It's a directory
|
||||
item_path = item["path"]
|
||||
if item["type"] == "tree": # It's a directory
|
||||
results.extend(self.fetch(project_id, site_url, access_token, branch, item_path))
|
||||
else: # It's a file
|
||||
file_url = f"{domain}/api/v4/projects/{project_id}/repository/files/{item_path}/raw?ref={branch}"
|
||||
file_response = requests.get(file_url, headers=headers)
|
||||
file_response.raise_for_status()
|
||||
file_content = file_response.text
|
||||
results.append({
|
||||
"path": item_path,
|
||||
"branch": branch,
|
||||
"content": file_content
|
||||
})
|
||||
results.append({"path": item_path, "branch": branch, "content": file_content})
|
||||
except requests.RequestException as e:
|
||||
print(f"Error fetching data from GitLab: {e}")
|
||||
|
||||
return results
|
||||
|
||||
return results
|
||||
|
@@ -13,12 +13,8 @@ class GoogleProvider(BuiltinToolProviderController):
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
tool_parameters={
|
||||
"query": "test",
|
||||
"result_type": "link"
|
||||
},
|
||||
user_id="",
|
||||
tool_parameters={"query": "test", "result_type": "link"},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -9,7 +9,6 @@ SERP_API_URL = "https://serpapi.com/search"
|
||||
|
||||
|
||||
class GoogleSearchTool(BuiltinTool):
|
||||
|
||||
def _parse_response(self, response: dict) -> dict:
|
||||
result = {}
|
||||
if "knowledge_graph" in response:
|
||||
@@ -17,25 +16,23 @@ class GoogleSearchTool(BuiltinTool):
|
||||
result["description"] = response["knowledge_graph"].get("description", "")
|
||||
if "organic_results" in response:
|
||||
result["organic_results"] = [
|
||||
{
|
||||
"title": item.get("title", ""),
|
||||
"link": item.get("link", ""),
|
||||
"snippet": item.get("snippet", "")
|
||||
}
|
||||
{"title": item.get("title", ""), "link": item.get("link", ""), "snippet": item.get("snippet", "")}
|
||||
for item in response["organic_results"]
|
||||
]
|
||||
return result
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
params = {
|
||||
"api_key": self.runtime.credentials['serpapi_api_key'],
|
||||
"q": tool_parameters['query'],
|
||||
"api_key": self.runtime.credentials["serpapi_api_key"],
|
||||
"q": tool_parameters["query"],
|
||||
"engine": "google",
|
||||
"google_domain": "google.com",
|
||||
"gl": "us",
|
||||
"hl": "en"
|
||||
"hl": "en",
|
||||
}
|
||||
response = requests.get(url=SERP_API_URL, params=params)
|
||||
response.raise_for_status()
|
||||
|
@@ -8,10 +8,6 @@ from core.tools.provider.builtin_tool_provider import BuiltinToolProviderControl
|
||||
class JsonExtractProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict[str, Any]) -> None:
|
||||
try:
|
||||
GoogleTranslate().invoke(user_id='',
|
||||
tool_parameters={
|
||||
"content": "这是一段测试文本",
|
||||
"dest": "en"
|
||||
})
|
||||
GoogleTranslate().invoke(user_id="", tool_parameters={"content": "这是一段测试文本", "dest": "en"})
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -7,46 +7,40 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class GoogleTranslate(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
content = tool_parameters.get('content', '')
|
||||
content = tool_parameters.get("content", "")
|
||||
if not content:
|
||||
return self.create_text_message('Invalid parameter content')
|
||||
return self.create_text_message("Invalid parameter content")
|
||||
|
||||
dest = tool_parameters.get('dest', '')
|
||||
dest = tool_parameters.get("dest", "")
|
||||
if not dest:
|
||||
return self.create_text_message('Invalid parameter destination language')
|
||||
return self.create_text_message("Invalid parameter destination language")
|
||||
|
||||
try:
|
||||
result = self._translate(content, dest)
|
||||
return self.create_text_message(str(result))
|
||||
except Exception:
|
||||
return self.create_text_message('Translation service error, please check the network')
|
||||
return self.create_text_message("Translation service error, please check the network")
|
||||
|
||||
def _translate(self, content: str, dest: str) -> str:
|
||||
try:
|
||||
url = "https://translate.googleapis.com/translate_a/single"
|
||||
params = {
|
||||
"client": "gtx",
|
||||
"sl": "auto",
|
||||
"tl": dest,
|
||||
"dt": "t",
|
||||
"q": content
|
||||
}
|
||||
params = {"client": "gtx", "sl": "auto", "tl": dest, "dt": "t", "q": content}
|
||||
|
||||
headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
||||
}
|
||||
|
||||
response_json = requests.get(
|
||||
url, params=params, headers=headers).json()
|
||||
response_json = requests.get(url, params=params, headers=headers).json()
|
||||
result = response_json[0]
|
||||
translated_text = ''.join([item[0] for item in result if item[0]])
|
||||
translated_text = "".join([item[0] for item in result if item[0]])
|
||||
return str(translated_text)
|
||||
except Exception as e:
|
||||
return str(e)
|
||||
|
@@ -5,4 +5,4 @@ from core.tools.provider.builtin_tool_provider import BuiltinToolProviderControl
|
||||
|
||||
class HapProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict[str, Any]) -> None:
|
||||
pass
|
||||
pass
|
||||
|
@@ -8,41 +8,40 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class AddWorksheetRecordTool(BuiltinTool):
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
appkey = tool_parameters.get('appkey', '')
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
appkey = tool_parameters.get("appkey", "")
|
||||
if not appkey:
|
||||
return self.create_text_message('Invalid parameter App Key')
|
||||
sign = tool_parameters.get('sign', '')
|
||||
return self.create_text_message("Invalid parameter App Key")
|
||||
sign = tool_parameters.get("sign", "")
|
||||
if not sign:
|
||||
return self.create_text_message('Invalid parameter Sign')
|
||||
worksheet_id = tool_parameters.get('worksheet_id', '')
|
||||
return self.create_text_message("Invalid parameter Sign")
|
||||
worksheet_id = tool_parameters.get("worksheet_id", "")
|
||||
if not worksheet_id:
|
||||
return self.create_text_message('Invalid parameter Worksheet ID')
|
||||
record_data = tool_parameters.get('record_data', '')
|
||||
return self.create_text_message("Invalid parameter Worksheet ID")
|
||||
record_data = tool_parameters.get("record_data", "")
|
||||
if not record_data:
|
||||
return self.create_text_message('Invalid parameter Record Row Data')
|
||||
|
||||
host = tool_parameters.get('host', '')
|
||||
return self.create_text_message("Invalid parameter Record Row Data")
|
||||
|
||||
host = tool_parameters.get("host", "")
|
||||
if not host:
|
||||
host = 'https://api.mingdao.com'
|
||||
host = "https://api.mingdao.com"
|
||||
elif not host.startswith(("http://", "https://")):
|
||||
return self.create_text_message('Invalid parameter Host Address')
|
||||
return self.create_text_message("Invalid parameter Host Address")
|
||||
else:
|
||||
host = f"{host[:-1] if host.endswith('/') else host}/api"
|
||||
|
||||
url = f"{host}/v2/open/worksheet/addRow"
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
payload = {"appKey": appkey, "sign": sign, "worksheetId": worksheet_id}
|
||||
|
||||
try:
|
||||
payload['controls'] = json.loads(record_data)
|
||||
payload["controls"] = json.loads(record_data)
|
||||
res = httpx.post(url, headers=headers, json=payload, timeout=60)
|
||||
res.raise_for_status()
|
||||
res_json = res.json()
|
||||
if res_json.get('error_code') != 1:
|
||||
if res_json.get("error_code") != 1:
|
||||
return self.create_text_message(f"Failed to add the new record. {res_json['error_msg']}")
|
||||
return self.create_text_message(f"New record added successfully. The record ID is {res_json['data']}.")
|
||||
except httpx.RequestError as e:
|
||||
|
@@ -7,43 +7,42 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class DeleteWorksheetRecordTool(BuiltinTool):
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
appkey = tool_parameters.get('appkey', '')
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
appkey = tool_parameters.get("appkey", "")
|
||||
if not appkey:
|
||||
return self.create_text_message('Invalid parameter App Key')
|
||||
sign = tool_parameters.get('sign', '')
|
||||
return self.create_text_message("Invalid parameter App Key")
|
||||
sign = tool_parameters.get("sign", "")
|
||||
if not sign:
|
||||
return self.create_text_message('Invalid parameter Sign')
|
||||
worksheet_id = tool_parameters.get('worksheet_id', '')
|
||||
return self.create_text_message("Invalid parameter Sign")
|
||||
worksheet_id = tool_parameters.get("worksheet_id", "")
|
||||
if not worksheet_id:
|
||||
return self.create_text_message('Invalid parameter Worksheet ID')
|
||||
row_id = tool_parameters.get('row_id', '')
|
||||
return self.create_text_message("Invalid parameter Worksheet ID")
|
||||
row_id = tool_parameters.get("row_id", "")
|
||||
if not row_id:
|
||||
return self.create_text_message('Invalid parameter Record Row ID')
|
||||
|
||||
host = tool_parameters.get('host', '')
|
||||
return self.create_text_message("Invalid parameter Record Row ID")
|
||||
|
||||
host = tool_parameters.get("host", "")
|
||||
if not host:
|
||||
host = 'https://api.mingdao.com'
|
||||
host = "https://api.mingdao.com"
|
||||
elif not host.startswith(("http://", "https://")):
|
||||
return self.create_text_message('Invalid parameter Host Address')
|
||||
return self.create_text_message("Invalid parameter Host Address")
|
||||
else:
|
||||
host = f"{host[:-1] if host.endswith('/') else host}/api"
|
||||
|
||||
url = f"{host}/v2/open/worksheet/deleteRow"
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
payload = {"appKey": appkey, "sign": sign, "worksheetId": worksheet_id, "rowId": row_id}
|
||||
|
||||
try:
|
||||
res = httpx.post(url, headers=headers, json=payload, timeout=30)
|
||||
res.raise_for_status()
|
||||
res_json = res.json()
|
||||
if res_json.get('error_code') != 1:
|
||||
if res_json.get("error_code") != 1:
|
||||
return self.create_text_message(f"Failed to delete the record. {res_json['error_msg']}")
|
||||
return self.create_text_message("Successfully deleted the record.")
|
||||
except httpx.RequestError as e:
|
||||
return self.create_text_message(f"Failed to delete the record, request error: {e}")
|
||||
except Exception as e:
|
||||
return self.create_text_message(f"Failed to delete the record, unexpected error: {e}")
|
||||
return self.create_text_message(f"Failed to delete the record, unexpected error: {e}")
|
||||
|
@@ -8,43 +8,42 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class GetWorksheetFieldsTool(BuiltinTool):
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
appkey = tool_parameters.get('appkey', '')
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
appkey = tool_parameters.get("appkey", "")
|
||||
if not appkey:
|
||||
return self.create_text_message('Invalid parameter App Key')
|
||||
sign = tool_parameters.get('sign', '')
|
||||
return self.create_text_message("Invalid parameter App Key")
|
||||
sign = tool_parameters.get("sign", "")
|
||||
if not sign:
|
||||
return self.create_text_message('Invalid parameter Sign')
|
||||
worksheet_id = tool_parameters.get('worksheet_id', '')
|
||||
return self.create_text_message("Invalid parameter Sign")
|
||||
worksheet_id = tool_parameters.get("worksheet_id", "")
|
||||
if not worksheet_id:
|
||||
return self.create_text_message('Invalid parameter Worksheet ID')
|
||||
|
||||
host = tool_parameters.get('host', '')
|
||||
return self.create_text_message("Invalid parameter Worksheet ID")
|
||||
|
||||
host = tool_parameters.get("host", "")
|
||||
if not host:
|
||||
host = 'https://api.mingdao.com'
|
||||
host = "https://api.mingdao.com"
|
||||
elif not host.startswith(("http://", "https://")):
|
||||
return self.create_text_message('Invalid parameter Host Address')
|
||||
return self.create_text_message("Invalid parameter Host Address")
|
||||
else:
|
||||
host = f"{host[:-1] if host.endswith('/') else host}/api"
|
||||
|
||||
url = f"{host}/v2/open/worksheet/getWorksheetInfo"
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
payload = {"appKey": appkey, "sign": sign, "worksheetId": worksheet_id}
|
||||
|
||||
try:
|
||||
res = httpx.post(url, headers=headers, json=payload, timeout=60)
|
||||
res.raise_for_status()
|
||||
res_json = res.json()
|
||||
if res_json.get('error_code') != 1:
|
||||
if res_json.get("error_code") != 1:
|
||||
return self.create_text_message(f"Failed to get the worksheet information. {res_json['error_msg']}")
|
||||
|
||||
fields_json, fields_table = self.get_controls(res_json['data']['controls'])
|
||||
result_type = tool_parameters.get('result_type', 'table')
|
||||
|
||||
fields_json, fields_table = self.get_controls(res_json["data"]["controls"])
|
||||
result_type = tool_parameters.get("result_type", "table")
|
||||
return self.create_text_message(
|
||||
text=json.dumps(fields_json, ensure_ascii=False) if result_type == 'json' else fields_table
|
||||
text=json.dumps(fields_json, ensure_ascii=False) if result_type == "json" else fields_table
|
||||
)
|
||||
except httpx.RequestError as e:
|
||||
return self.create_text_message(f"Failed to get the worksheet information, request error: {e}")
|
||||
@@ -88,61 +87,65 @@ class GetWorksheetFieldsTool(BuiltinTool):
|
||||
50: "Text",
|
||||
51: "Query Record",
|
||||
}
|
||||
return field_type_map.get(field_type_id, '')
|
||||
return field_type_map.get(field_type_id, "")
|
||||
|
||||
def get_controls(self, controls: list) -> dict:
|
||||
fields = []
|
||||
fields_list = ['|fieldId|fieldName|fieldType|fieldTypeId|description|options|','|'+'---|'*6]
|
||||
fields_list = ["|fieldId|fieldName|fieldType|fieldTypeId|description|options|", "|" + "---|" * 6]
|
||||
for control in controls:
|
||||
if control['type'] in self._get_ignore_types():
|
||||
if control["type"] in self._get_ignore_types():
|
||||
continue
|
||||
field_type_id = control['type']
|
||||
field_type = self.get_field_type_by_id(control['type'])
|
||||
field_type_id = control["type"]
|
||||
field_type = self.get_field_type_by_id(control["type"])
|
||||
if field_type_id == 30:
|
||||
source_type = control['sourceControl']['type']
|
||||
source_type = control["sourceControl"]["type"]
|
||||
if source_type in self._get_ignore_types():
|
||||
continue
|
||||
else:
|
||||
field_type_id = source_type
|
||||
field_type = self.get_field_type_by_id(source_type)
|
||||
field = {
|
||||
'id': control['controlId'],
|
||||
'name': control['controlName'],
|
||||
'type': field_type,
|
||||
'typeId': field_type_id,
|
||||
'description': control['remark'].replace('\n', ' ').replace('\t', ' '),
|
||||
'options': self._extract_options(control),
|
||||
"id": control["controlId"],
|
||||
"name": control["controlName"],
|
||||
"type": field_type,
|
||||
"typeId": field_type_id,
|
||||
"description": control["remark"].replace("\n", " ").replace("\t", " "),
|
||||
"options": self._extract_options(control),
|
||||
}
|
||||
fields.append(field)
|
||||
fields_list.append(f"|{field['id']}|{field['name']}|{field['type']}|{field['typeId']}|{field['description']}|{field['options'] if field['options'] else ''}|")
|
||||
fields_list.append(
|
||||
f"|{field['id']}|{field['name']}|{field['type']}|{field['typeId']}|{field['description']}|{field['options'] if field['options'] else ''}|"
|
||||
)
|
||||
|
||||
fields.append({
|
||||
'id': 'ctime',
|
||||
'name': 'Created Time',
|
||||
'type': self.get_field_type_by_id(16),
|
||||
'typeId': 16,
|
||||
'description': '',
|
||||
'options': []
|
||||
})
|
||||
fields.append(
|
||||
{
|
||||
"id": "ctime",
|
||||
"name": "Created Time",
|
||||
"type": self.get_field_type_by_id(16),
|
||||
"typeId": 16,
|
||||
"description": "",
|
||||
"options": [],
|
||||
}
|
||||
)
|
||||
fields_list.append("|ctime|Created Time|Date|16|||")
|
||||
return fields, '\n'.join(fields_list)
|
||||
return fields, "\n".join(fields_list)
|
||||
|
||||
def _extract_options(self, control: dict) -> list:
|
||||
options = []
|
||||
if control['type'] in [9, 10, 11]:
|
||||
options.extend([{"key": opt['key'], "value": opt['value']} for opt in control.get('options', [])])
|
||||
elif control['type'] in [28, 36]:
|
||||
itemnames = control['advancedSetting'].get('itemnames')
|
||||
if itemnames and itemnames.startswith('[{'):
|
||||
if control["type"] in [9, 10, 11]:
|
||||
options.extend([{"key": opt["key"], "value": opt["value"]} for opt in control.get("options", [])])
|
||||
elif control["type"] in [28, 36]:
|
||||
itemnames = control["advancedSetting"].get("itemnames")
|
||||
if itemnames and itemnames.startswith("[{"):
|
||||
try:
|
||||
options = json.loads(itemnames)
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
elif control['type'] == 30:
|
||||
source_type = control['sourceControl']['type']
|
||||
elif control["type"] == 30:
|
||||
source_type = control["sourceControl"]["type"]
|
||||
if source_type not in self._get_ignore_types():
|
||||
options.extend([{"key": opt['key'], "value": opt['value']} for opt in control.get('options', [])])
|
||||
options.extend([{"key": opt["key"], "value": opt["value"]} for opt in control.get("options", [])])
|
||||
return options
|
||||
|
||||
|
||||
def _get_ignore_types(self):
|
||||
return {14, 21, 22, 34, 42, 43, 45, 47, 49, 10010}
|
||||
return {14, 21, 22, 34, 42, 43, 45, 47, 49, 10010}
|
||||
|
@@ -8,64 +8,66 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class GetWorksheetPivotDataTool(BuiltinTool):
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
appkey = tool_parameters.get('appkey', '')
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
appkey = tool_parameters.get("appkey", "")
|
||||
if not appkey:
|
||||
return self.create_text_message('Invalid parameter App Key')
|
||||
sign = tool_parameters.get('sign', '')
|
||||
return self.create_text_message("Invalid parameter App Key")
|
||||
sign = tool_parameters.get("sign", "")
|
||||
if not sign:
|
||||
return self.create_text_message('Invalid parameter Sign')
|
||||
worksheet_id = tool_parameters.get('worksheet_id', '')
|
||||
return self.create_text_message("Invalid parameter Sign")
|
||||
worksheet_id = tool_parameters.get("worksheet_id", "")
|
||||
if not worksheet_id:
|
||||
return self.create_text_message('Invalid parameter Worksheet ID')
|
||||
x_column_fields = tool_parameters.get('x_column_fields', '')
|
||||
if not x_column_fields or not x_column_fields.startswith('['):
|
||||
return self.create_text_message('Invalid parameter Column Fields')
|
||||
y_row_fields = tool_parameters.get('y_row_fields', '')
|
||||
if y_row_fields and not y_row_fields.strip().startswith('['):
|
||||
return self.create_text_message('Invalid parameter Row Fields')
|
||||
return self.create_text_message("Invalid parameter Worksheet ID")
|
||||
x_column_fields = tool_parameters.get("x_column_fields", "")
|
||||
if not x_column_fields or not x_column_fields.startswith("["):
|
||||
return self.create_text_message("Invalid parameter Column Fields")
|
||||
y_row_fields = tool_parameters.get("y_row_fields", "")
|
||||
if y_row_fields and not y_row_fields.strip().startswith("["):
|
||||
return self.create_text_message("Invalid parameter Row Fields")
|
||||
elif not y_row_fields:
|
||||
y_row_fields = '[]'
|
||||
value_fields = tool_parameters.get('value_fields', '')
|
||||
if not value_fields or not value_fields.strip().startswith('['):
|
||||
return self.create_text_message('Invalid parameter Value Fields')
|
||||
|
||||
host = tool_parameters.get('host', '')
|
||||
y_row_fields = "[]"
|
||||
value_fields = tool_parameters.get("value_fields", "")
|
||||
if not value_fields or not value_fields.strip().startswith("["):
|
||||
return self.create_text_message("Invalid parameter Value Fields")
|
||||
|
||||
host = tool_parameters.get("host", "")
|
||||
if not host:
|
||||
host = 'https://api.mingdao.com'
|
||||
host = "https://api.mingdao.com"
|
||||
elif not host.startswith(("http://", "https://")):
|
||||
return self.create_text_message('Invalid parameter Host Address')
|
||||
return self.create_text_message("Invalid parameter Host Address")
|
||||
else:
|
||||
host = f"{host[:-1] if host.endswith('/') else host}/api"
|
||||
|
||||
url = f"{host}/report/getPivotData"
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
payload = {"appKey": appkey, "sign": sign, "worksheetId": worksheet_id, "options": {"showTotal": True}}
|
||||
|
||||
try:
|
||||
x_column_fields = json.loads(x_column_fields)
|
||||
payload['columns'] = x_column_fields
|
||||
payload["columns"] = x_column_fields
|
||||
y_row_fields = json.loads(y_row_fields)
|
||||
if y_row_fields: payload['rows'] = y_row_fields
|
||||
if y_row_fields:
|
||||
payload["rows"] = y_row_fields
|
||||
value_fields = json.loads(value_fields)
|
||||
payload['values'] = value_fields
|
||||
sort_fields = tool_parameters.get('sort_fields', '')
|
||||
if not sort_fields: sort_fields = '[]'
|
||||
payload["values"] = value_fields
|
||||
sort_fields = tool_parameters.get("sort_fields", "")
|
||||
if not sort_fields:
|
||||
sort_fields = "[]"
|
||||
sort_fields = json.loads(sort_fields)
|
||||
if sort_fields: payload['options']['sort'] = sort_fields
|
||||
if sort_fields:
|
||||
payload["options"]["sort"] = sort_fields
|
||||
res = httpx.post(url, headers=headers, json=payload, timeout=60)
|
||||
res.raise_for_status()
|
||||
res_json = res.json()
|
||||
if res_json.get('status') != 1:
|
||||
if res_json.get("status") != 1:
|
||||
return self.create_text_message(f"Failed to get the worksheet pivot data. {res_json['msg']}")
|
||||
|
||||
pivot_json = self.generate_pivot_json(res_json['data'])
|
||||
pivot_table = self.generate_pivot_table(res_json['data'])
|
||||
result_type = tool_parameters.get('result_type', '')
|
||||
text = pivot_table if result_type == 'table' else json.dumps(pivot_json, ensure_ascii=False)
|
||||
|
||||
pivot_json = self.generate_pivot_json(res_json["data"])
|
||||
pivot_table = self.generate_pivot_table(res_json["data"])
|
||||
result_type = tool_parameters.get("result_type", "")
|
||||
text = pivot_table if result_type == "table" else json.dumps(pivot_json, ensure_ascii=False)
|
||||
return self.create_text_message(text)
|
||||
except httpx.RequestError as e:
|
||||
return self.create_text_message(f"Failed to get the worksheet pivot data, request error: {e}")
|
||||
@@ -75,27 +77,31 @@ class GetWorksheetPivotDataTool(BuiltinTool):
|
||||
return self.create_text_message(f"Failed to get the worksheet pivot data, unexpected error: {e}")
|
||||
|
||||
def generate_pivot_table(self, data: dict[str, Any]) -> str:
|
||||
columns = data['metadata']['columns']
|
||||
rows = data['metadata']['rows']
|
||||
values = data['metadata']['values']
|
||||
columns = data["metadata"]["columns"]
|
||||
rows = data["metadata"]["rows"]
|
||||
values = data["metadata"]["values"]
|
||||
|
||||
rows_data = data['data']
|
||||
rows_data = data["data"]
|
||||
|
||||
header = ([row['displayName'] for row in rows] if rows else []) + [column['displayName'] for column in columns] + [value['displayName'] for value in values]
|
||||
line = (['---'] * len(rows) if rows else []) + ['---'] * len(columns) + ['--:'] * len(values)
|
||||
header = (
|
||||
([row["displayName"] for row in rows] if rows else [])
|
||||
+ [column["displayName"] for column in columns]
|
||||
+ [value["displayName"] for value in values]
|
||||
)
|
||||
line = (["---"] * len(rows) if rows else []) + ["---"] * len(columns) + ["--:"] * len(values)
|
||||
|
||||
table = [header, line]
|
||||
for row in rows_data:
|
||||
row_data = [self.replace_pipe(row['rows'][r['controlId']]) for r in rows] if rows else []
|
||||
row_data.extend([self.replace_pipe(row['columns'][column['controlId']]) for column in columns])
|
||||
row_data.extend([self.replace_pipe(str(row['values'][value['controlId']])) for value in values])
|
||||
row_data = [self.replace_pipe(row["rows"][r["controlId"]]) for r in rows] if rows else []
|
||||
row_data.extend([self.replace_pipe(row["columns"][column["controlId"]]) for column in columns])
|
||||
row_data.extend([self.replace_pipe(str(row["values"][value["controlId"]])) for value in values])
|
||||
table.append(row_data)
|
||||
|
||||
return '\n'.join([('|'+'|'.join(row) +'|') for row in table])
|
||||
|
||||
return "\n".join([("|" + "|".join(row) + "|") for row in table])
|
||||
|
||||
def replace_pipe(self, text: str) -> str:
|
||||
return text.replace('|', '▏').replace('\n', ' ')
|
||||
|
||||
return text.replace("|", "▏").replace("\n", " ")
|
||||
|
||||
def generate_pivot_json(self, data: dict[str, Any]) -> dict:
|
||||
fields = {
|
||||
"x-axis": [
|
||||
@@ -103,13 +109,14 @@ class GetWorksheetPivotDataTool(BuiltinTool):
|
||||
for column in data["metadata"]["columns"]
|
||||
],
|
||||
"y-axis": [
|
||||
{"fieldId": row["controlId"], "fieldName": row["displayName"]}
|
||||
for row in data["metadata"]["rows"]
|
||||
] if data["metadata"]["rows"] else [],
|
||||
{"fieldId": row["controlId"], "fieldName": row["displayName"]} for row in data["metadata"]["rows"]
|
||||
]
|
||||
if data["metadata"]["rows"]
|
||||
else [],
|
||||
"values": [
|
||||
{"fieldId": value["controlId"], "fieldName": value["displayName"]}
|
||||
for value in data["metadata"]["values"]
|
||||
]
|
||||
],
|
||||
}
|
||||
# fields = ([
|
||||
# {"fieldId": row["controlId"], "fieldName": row["displayName"]}
|
||||
@@ -127,4 +134,4 @@ class GetWorksheetPivotDataTool(BuiltinTool):
|
||||
row_data.update(row["columns"])
|
||||
row_data.update(row["values"])
|
||||
rows.append(row_data)
|
||||
return {"fields": fields, "rows": rows, "summary": data["metadata"]["totalRow"]}
|
||||
return {"fields": fields, "rows": rows, "summary": data["metadata"]["totalRow"]}
|
||||
|
@@ -9,152 +9,173 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class ListWorksheetRecordsTool(BuiltinTool):
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
appkey = tool_parameters.get('appkey', '')
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
appkey = tool_parameters.get("appkey", "")
|
||||
if not appkey:
|
||||
return self.create_text_message('Invalid parameter App Key')
|
||||
return self.create_text_message("Invalid parameter App Key")
|
||||
|
||||
sign = tool_parameters.get('sign', '')
|
||||
sign = tool_parameters.get("sign", "")
|
||||
if not sign:
|
||||
return self.create_text_message('Invalid parameter Sign')
|
||||
return self.create_text_message("Invalid parameter Sign")
|
||||
|
||||
worksheet_id = tool_parameters.get('worksheet_id', '')
|
||||
worksheet_id = tool_parameters.get("worksheet_id", "")
|
||||
if not worksheet_id:
|
||||
return self.create_text_message('Invalid parameter Worksheet ID')
|
||||
return self.create_text_message("Invalid parameter Worksheet ID")
|
||||
|
||||
host = tool_parameters.get('host', '')
|
||||
host = tool_parameters.get("host", "")
|
||||
if not host:
|
||||
host = 'https://api.mingdao.com'
|
||||
host = "https://api.mingdao.com"
|
||||
elif not (host.startswith("http://") or host.startswith("https://")):
|
||||
return self.create_text_message('Invalid parameter Host Address')
|
||||
return self.create_text_message("Invalid parameter Host Address")
|
||||
else:
|
||||
host = f"{host[:-1] if host.endswith('/') else host}/api"
|
||||
|
||||
|
||||
url_fields = f"{host}/v2/open/worksheet/getWorksheetInfo"
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
payload = {"appKey": appkey, "sign": sign, "worksheetId": worksheet_id}
|
||||
|
||||
field_ids = tool_parameters.get('field_ids', '')
|
||||
field_ids = tool_parameters.get("field_ids", "")
|
||||
|
||||
try:
|
||||
res = httpx.post(url_fields, headers=headers, json=payload, timeout=30)
|
||||
res_json = res.json()
|
||||
if res.is_success:
|
||||
if res_json['error_code'] != 1:
|
||||
return self.create_text_message("Failed to get the worksheet information. {}".format(res_json['error_msg']))
|
||||
if res_json["error_code"] != 1:
|
||||
return self.create_text_message(
|
||||
"Failed to get the worksheet information. {}".format(res_json["error_msg"])
|
||||
)
|
||||
else:
|
||||
worksheet_name = res_json['data']['name']
|
||||
fields, schema, table_header = self.get_schema(res_json['data']['controls'], field_ids)
|
||||
worksheet_name = res_json["data"]["name"]
|
||||
fields, schema, table_header = self.get_schema(res_json["data"]["controls"], field_ids)
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to get the worksheet information, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to get the worksheet information, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to get the worksheet information, something went wrong: {}".format(e))
|
||||
return self.create_text_message(
|
||||
"Failed to get the worksheet information, something went wrong: {}".format(e)
|
||||
)
|
||||
|
||||
if field_ids:
|
||||
payload['controls'] = [v.strip() for v in field_ids.split(',')] if field_ids else []
|
||||
filters = tool_parameters.get('filters', '')
|
||||
payload["controls"] = [v.strip() for v in field_ids.split(",")] if field_ids else []
|
||||
filters = tool_parameters.get("filters", "")
|
||||
if filters:
|
||||
payload['filters'] = json.loads(filters)
|
||||
sort_id = tool_parameters.get('sort_id', '')
|
||||
sort_is_asc = tool_parameters.get('sort_is_asc', False)
|
||||
payload["filters"] = json.loads(filters)
|
||||
sort_id = tool_parameters.get("sort_id", "")
|
||||
sort_is_asc = tool_parameters.get("sort_is_asc", False)
|
||||
if sort_id:
|
||||
payload['sortId'] = sort_id
|
||||
payload['isAsc'] = sort_is_asc
|
||||
limit = tool_parameters.get('limit', 50)
|
||||
payload['pageSize'] = limit
|
||||
page_index = tool_parameters.get('page_index', 1)
|
||||
payload['pageIndex'] = page_index
|
||||
payload['useControlId'] = True
|
||||
payload['listType'] = 1
|
||||
payload["sortId"] = sort_id
|
||||
payload["isAsc"] = sort_is_asc
|
||||
limit = tool_parameters.get("limit", 50)
|
||||
payload["pageSize"] = limit
|
||||
page_index = tool_parameters.get("page_index", 1)
|
||||
payload["pageIndex"] = page_index
|
||||
payload["useControlId"] = True
|
||||
payload["listType"] = 1
|
||||
|
||||
url = f"{host}/v2/open/worksheet/getFilterRows"
|
||||
try:
|
||||
res = httpx.post(url, headers=headers, json=payload, timeout=90)
|
||||
res_json = res.json()
|
||||
if res.is_success:
|
||||
if res_json['error_code'] != 1:
|
||||
return self.create_text_message("Failed to get the records. {}".format(res_json['error_msg']))
|
||||
if res_json["error_code"] != 1:
|
||||
return self.create_text_message("Failed to get the records. {}".format(res_json["error_msg"]))
|
||||
else:
|
||||
result = {
|
||||
"fields": fields,
|
||||
"rows": [],
|
||||
"total": res_json.get("data", {}).get("total"),
|
||||
"payload": {key: payload[key] for key in ['worksheetId', 'controls', 'filters', 'sortId', 'isAsc', 'pageSize', 'pageIndex'] if key in payload}
|
||||
"payload": {
|
||||
key: payload[key]
|
||||
for key in [
|
||||
"worksheetId",
|
||||
"controls",
|
||||
"filters",
|
||||
"sortId",
|
||||
"isAsc",
|
||||
"pageSize",
|
||||
"pageIndex",
|
||||
]
|
||||
if key in payload
|
||||
},
|
||||
}
|
||||
rows = res_json.get("data", {}).get("rows", [])
|
||||
result_type = tool_parameters.get('result_type', '')
|
||||
if not result_type: result_type = 'table'
|
||||
if result_type == 'json':
|
||||
result_type = tool_parameters.get("result_type", "")
|
||||
if not result_type:
|
||||
result_type = "table"
|
||||
if result_type == "json":
|
||||
for row in rows:
|
||||
result['rows'].append(self.get_row_field_value(row, schema))
|
||||
result["rows"].append(self.get_row_field_value(row, schema))
|
||||
return self.create_text_message(json.dumps(result, ensure_ascii=False))
|
||||
else:
|
||||
result_text = f"Found {result['total']} rows in worksheet \"{worksheet_name}\"."
|
||||
if result['total'] > 0:
|
||||
if result["total"] > 0:
|
||||
result_text += f" The following are {result['total'] if result['total'] < limit else limit} pieces of data presented in a table format:\n\n{table_header}"
|
||||
for row in rows:
|
||||
result_values = []
|
||||
for f in fields:
|
||||
result_values.append(self.handle_value_type(row[f['fieldId']], schema[f['fieldId']]))
|
||||
result_text += '\n|'+'|'.join(result_values)+'|'
|
||||
result_values.append(
|
||||
self.handle_value_type(row[f["fieldId"]], schema[f["fieldId"]])
|
||||
)
|
||||
result_text += "\n|" + "|".join(result_values) + "|"
|
||||
return self.create_text_message(result_text)
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to get the records, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to get the records, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to get the records, something went wrong: {}".format(e))
|
||||
|
||||
|
||||
def get_row_field_value(self, row: dict, schema: dict):
|
||||
row_value = {"rowid": row["rowid"]}
|
||||
for field in schema:
|
||||
row_value[field] = self.handle_value_type(row[field], schema[field])
|
||||
return row_value
|
||||
|
||||
|
||||
def get_schema(self, controls: list, fieldids: str):
|
||||
allow_fields = {v.strip() for v in fieldids.split(',')} if fieldids else set()
|
||||
def get_schema(self, controls: list, fieldids: str):
|
||||
allow_fields = {v.strip() for v in fieldids.split(",")} if fieldids else set()
|
||||
fields = []
|
||||
schema = {}
|
||||
field_names = []
|
||||
for control in controls:
|
||||
control_type_id = self.get_real_type_id(control)
|
||||
if (control_type_id in self._get_ignore_types()) or (allow_fields and not control['controlId'] in allow_fields):
|
||||
if (control_type_id in self._get_ignore_types()) or (
|
||||
allow_fields and not control["controlId"] in allow_fields
|
||||
):
|
||||
continue
|
||||
else:
|
||||
fields.append({'fieldId': control['controlId'], 'fieldName': control['controlName']})
|
||||
schema[control['controlId']] = {'typeId': control_type_id, 'options': self.set_option(control)}
|
||||
field_names.append(control['controlName'])
|
||||
if (not allow_fields or ('ctime' in allow_fields)):
|
||||
fields.append({'fieldId': 'ctime', 'fieldName': 'Created Time'})
|
||||
schema['ctime'] = {'typeId': 16, 'options': {}}
|
||||
fields.append({"fieldId": control["controlId"], "fieldName": control["controlName"]})
|
||||
schema[control["controlId"]] = {"typeId": control_type_id, "options": self.set_option(control)}
|
||||
field_names.append(control["controlName"])
|
||||
if not allow_fields or ("ctime" in allow_fields):
|
||||
fields.append({"fieldId": "ctime", "fieldName": "Created Time"})
|
||||
schema["ctime"] = {"typeId": 16, "options": {}}
|
||||
field_names.append("Created Time")
|
||||
fields.append({'fieldId':'rowid', 'fieldName': 'Record Row ID'})
|
||||
schema['rowid'] = {'typeId': 2, 'options': {}}
|
||||
fields.append({"fieldId": "rowid", "fieldName": "Record Row ID"})
|
||||
schema["rowid"] = {"typeId": 2, "options": {}}
|
||||
field_names.append("Record Row ID")
|
||||
return fields, schema, '|'+'|'.join(field_names)+'|\n|'+'---|'*len(field_names)
|
||||
|
||||
return fields, schema, "|" + "|".join(field_names) + "|\n|" + "---|" * len(field_names)
|
||||
|
||||
def get_real_type_id(self, control: dict) -> int:
|
||||
return control['sourceControlType'] if control['type'] == 30 else control['type']
|
||||
|
||||
return control["sourceControlType"] if control["type"] == 30 else control["type"]
|
||||
|
||||
def set_option(self, control: dict) -> dict:
|
||||
options = {}
|
||||
if control.get('options'):
|
||||
options = {option['key']: option['value'] for option in control['options']}
|
||||
elif control.get('advancedSetting', {}).get('itemnames'):
|
||||
if control.get("options"):
|
||||
options = {option["key"]: option["value"] for option in control["options"]}
|
||||
elif control.get("advancedSetting", {}).get("itemnames"):
|
||||
try:
|
||||
itemnames = json.loads(control['advancedSetting']['itemnames'])
|
||||
options = {item['key']: item['value'] for item in itemnames}
|
||||
itemnames = json.loads(control["advancedSetting"]["itemnames"])
|
||||
options = {item["key"]: item["value"] for item in itemnames}
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
return options
|
||||
|
||||
def _get_ignore_types(self):
|
||||
return {14, 21, 22, 34, 42, 43, 45, 47, 49, 10010}
|
||||
|
||||
|
||||
def handle_value_type(self, value, field):
|
||||
type_id = field.get("typeId")
|
||||
if type_id == 10:
|
||||
@@ -167,33 +188,33 @@ class ListWorksheetRecordsTool(BuiltinTool):
|
||||
value = self.parse_cascade_or_associated(field, value)
|
||||
elif type_id == 40:
|
||||
value = self.parse_location(value)
|
||||
return self.rich_text_to_plain_text(value) if value else ''
|
||||
return self.rich_text_to_plain_text(value) if value else ""
|
||||
|
||||
def process_value(self, value):
|
||||
if isinstance(value, str):
|
||||
if value.startswith("[{\"accountId\""):
|
||||
if value.startswith('[{"accountId"'):
|
||||
value = json.loads(value)
|
||||
value = ', '.join([item['fullname'] for item in value])
|
||||
elif value.startswith("[{\"departmentId\""):
|
||||
value = ", ".join([item["fullname"] for item in value])
|
||||
elif value.startswith('[{"departmentId"'):
|
||||
value = json.loads(value)
|
||||
value = '、'.join([item['departmentName'] for item in value])
|
||||
elif value.startswith("[{\"organizeId\""):
|
||||
value = "、".join([item["departmentName"] for item in value])
|
||||
elif value.startswith('[{"organizeId"'):
|
||||
value = json.loads(value)
|
||||
value = '、'.join([item['organizeName'] for item in value])
|
||||
elif value.startswith("[{\"file_id\""):
|
||||
value = ''
|
||||
elif value == '[]':
|
||||
value = ''
|
||||
elif hasattr(value, 'accountId'):
|
||||
value = value['fullname']
|
||||
value = "、".join([item["organizeName"] for item in value])
|
||||
elif value.startswith('[{"file_id"'):
|
||||
value = ""
|
||||
elif value == "[]":
|
||||
value = ""
|
||||
elif hasattr(value, "accountId"):
|
||||
value = value["fullname"]
|
||||
return value
|
||||
|
||||
def parse_cascade_or_associated(self, field, value):
|
||||
if (field['typeId'] == 35 and value.startswith('[')) or (field['typeId'] == 29 and value.startswith('[{')):
|
||||
if (field["typeId"] == 35 and value.startswith("[")) or (field["typeId"] == 29 and value.startswith("[{")):
|
||||
value = json.loads(value)
|
||||
value = value[0]['name'] if len(value) > 0 else ''
|
||||
value = value[0]["name"] if len(value) > 0 else ""
|
||||
else:
|
||||
value = ''
|
||||
value = ""
|
||||
return value
|
||||
|
||||
def parse_location(self, value):
|
||||
@@ -205,5 +226,5 @@ class ListWorksheetRecordsTool(BuiltinTool):
|
||||
return value
|
||||
|
||||
def rich_text_to_plain_text(self, rich_text):
|
||||
text = re.sub(r'<[^>]+>', '', rich_text) if '<' in rich_text else rich_text
|
||||
return text.replace("|", "▏").replace("\n", " ")
|
||||
text = re.sub(r"<[^>]+>", "", rich_text) if "<" in rich_text else rich_text
|
||||
return text.replace("|", "▏").replace("\n", " ")
|
||||
|
@@ -8,75 +8,76 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class ListWorksheetsTool(BuiltinTool):
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
appkey = tool_parameters.get('appkey', '')
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
appkey = tool_parameters.get("appkey", "")
|
||||
if not appkey:
|
||||
return self.create_text_message('Invalid parameter App Key')
|
||||
sign = tool_parameters.get('sign', '')
|
||||
return self.create_text_message("Invalid parameter App Key")
|
||||
sign = tool_parameters.get("sign", "")
|
||||
if not sign:
|
||||
return self.create_text_message('Invalid parameter Sign')
|
||||
|
||||
host = tool_parameters.get('host', '')
|
||||
return self.create_text_message("Invalid parameter Sign")
|
||||
|
||||
host = tool_parameters.get("host", "")
|
||||
if not host:
|
||||
host = 'https://api.mingdao.com'
|
||||
host = "https://api.mingdao.com"
|
||||
elif not (host.startswith("http://") or host.startswith("https://")):
|
||||
return self.create_text_message('Invalid parameter Host Address')
|
||||
return self.create_text_message("Invalid parameter Host Address")
|
||||
else:
|
||||
host = f"{host[:-1] if host.endswith('/') else host}/api"
|
||||
url = f"{host}/v1/open/app/get"
|
||||
|
||||
result_type = tool_parameters.get('result_type', '')
|
||||
result_type = tool_parameters.get("result_type", "")
|
||||
if not result_type:
|
||||
result_type = 'table'
|
||||
result_type = "table"
|
||||
|
||||
headers = { 'Content-Type': 'application/json' }
|
||||
params = { "appKey": appkey, "sign": sign, }
|
||||
headers = {"Content-Type": "application/json"}
|
||||
params = {
|
||||
"appKey": appkey,
|
||||
"sign": sign,
|
||||
}
|
||||
try:
|
||||
res = httpx.get(url, headers=headers, params=params, timeout=30)
|
||||
res_json = res.json()
|
||||
if res.is_success:
|
||||
if res_json['error_code'] != 1:
|
||||
return self.create_text_message("Failed to access the application. {}".format(res_json['error_msg']))
|
||||
if res_json["error_code"] != 1:
|
||||
return self.create_text_message(
|
||||
"Failed to access the application. {}".format(res_json["error_msg"])
|
||||
)
|
||||
else:
|
||||
if result_type == 'json':
|
||||
if result_type == "json":
|
||||
worksheets = []
|
||||
for section in res_json['data']['sections']:
|
||||
for section in res_json["data"]["sections"]:
|
||||
worksheets.extend(self._extract_worksheets(section, result_type))
|
||||
return self.create_text_message(text=json.dumps(worksheets, ensure_ascii=False))
|
||||
else:
|
||||
worksheets = '|worksheetId|worksheetName|description|\n|---|---|---|'
|
||||
for section in res_json['data']['sections']:
|
||||
worksheets = "|worksheetId|worksheetName|description|\n|---|---|---|"
|
||||
for section in res_json["data"]["sections"]:
|
||||
worksheets += self._extract_worksheets(section, result_type)
|
||||
return self.create_text_message(worksheets)
|
||||
|
||||
else:
|
||||
return self.create_text_message(
|
||||
f"Failed to list worksheets, status code: {res.status_code}, response: {res.text}")
|
||||
f"Failed to list worksheets, status code: {res.status_code}, response: {res.text}"
|
||||
)
|
||||
except Exception as e:
|
||||
return self.create_text_message("Failed to list worksheets, something went wrong: {}".format(e))
|
||||
|
||||
def _extract_worksheets(self, section, type):
|
||||
items = []
|
||||
tables = ''
|
||||
for item in section.get('items', []):
|
||||
if item.get('type') == 0 and (not 'notes' in item or item.get('notes') != 'NO'):
|
||||
if type == 'json':
|
||||
filtered_item = {
|
||||
'id': item['id'],
|
||||
'name': item['name'],
|
||||
'notes': item.get('notes', '')
|
||||
}
|
||||
tables = ""
|
||||
for item in section.get("items", []):
|
||||
if item.get("type") == 0 and (not "notes" in item or item.get("notes") != "NO"):
|
||||
if type == "json":
|
||||
filtered_item = {"id": item["id"], "name": item["name"], "notes": item.get("notes", "")}
|
||||
items.append(filtered_item)
|
||||
else:
|
||||
tables += f"\n|{item['id']}|{item['name']}|{item.get('notes', '')}|"
|
||||
|
||||
for child_section in section.get('childSections', []):
|
||||
if type == 'json':
|
||||
items.extend(self._extract_worksheets(child_section, 'json'))
|
||||
for child_section in section.get("childSections", []):
|
||||
if type == "json":
|
||||
items.extend(self._extract_worksheets(child_section, "json"))
|
||||
else:
|
||||
tables += self._extract_worksheets(child_section, 'table')
|
||||
|
||||
return items if type == 'json' else tables
|
||||
tables += self._extract_worksheets(child_section, "table")
|
||||
|
||||
return items if type == "json" else tables
|
||||
|
@@ -8,44 +8,43 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class UpdateWorksheetRecordTool(BuiltinTool):
|
||||
|
||||
def _invoke(self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
|
||||
appkey = tool_parameters.get('appkey', '')
|
||||
def _invoke(
|
||||
self, user_id: str, tool_parameters: dict[str, Any]
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
appkey = tool_parameters.get("appkey", "")
|
||||
if not appkey:
|
||||
return self.create_text_message('Invalid parameter App Key')
|
||||
sign = tool_parameters.get('sign', '')
|
||||
return self.create_text_message("Invalid parameter App Key")
|
||||
sign = tool_parameters.get("sign", "")
|
||||
if not sign:
|
||||
return self.create_text_message('Invalid parameter Sign')
|
||||
worksheet_id = tool_parameters.get('worksheet_id', '')
|
||||
return self.create_text_message("Invalid parameter Sign")
|
||||
worksheet_id = tool_parameters.get("worksheet_id", "")
|
||||
if not worksheet_id:
|
||||
return self.create_text_message('Invalid parameter Worksheet ID')
|
||||
row_id = tool_parameters.get('row_id', '')
|
||||
return self.create_text_message("Invalid parameter Worksheet ID")
|
||||
row_id = tool_parameters.get("row_id", "")
|
||||
if not row_id:
|
||||
return self.create_text_message('Invalid parameter Record Row ID')
|
||||
record_data = tool_parameters.get('record_data', '')
|
||||
return self.create_text_message("Invalid parameter Record Row ID")
|
||||
record_data = tool_parameters.get("record_data", "")
|
||||
if not record_data:
|
||||
return self.create_text_message('Invalid parameter Record Row Data')
|
||||
|
||||
host = tool_parameters.get('host', '')
|
||||
return self.create_text_message("Invalid parameter Record Row Data")
|
||||
|
||||
host = tool_parameters.get("host", "")
|
||||
if not host:
|
||||
host = 'https://api.mingdao.com'
|
||||
host = "https://api.mingdao.com"
|
||||
elif not host.startswith(("http://", "https://")):
|
||||
return self.create_text_message('Invalid parameter Host Address')
|
||||
return self.create_text_message("Invalid parameter Host Address")
|
||||
else:
|
||||
host = f"{host[:-1] if host.endswith('/') else host}/api"
|
||||
|
||||
url = f"{host}/v2/open/worksheet/editRow"
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
payload = {"appKey": appkey, "sign": sign, "worksheetId": worksheet_id, "rowId": row_id}
|
||||
|
||||
try:
|
||||
payload['controls'] = json.loads(record_data)
|
||||
payload["controls"] = json.loads(record_data)
|
||||
res = httpx.post(url, headers=headers, json=payload, timeout=60)
|
||||
res.raise_for_status()
|
||||
res_json = res.json()
|
||||
if res_json.get('error_code') != 1:
|
||||
if res_json.get("error_code") != 1:
|
||||
return self.create_text_message(f"Failed to update the record. {res_json['error_msg']}")
|
||||
return self.create_text_message("Record updated successfully.")
|
||||
except httpx.RequestError as e:
|
||||
|
@@ -10,27 +10,29 @@ from core.tools.provider.builtin_tool_provider import BuiltinToolProviderControl
|
||||
class GoogleProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict[str, Any]) -> None:
|
||||
try:
|
||||
if credentials['api_key'] is None:
|
||||
credentials['api_key'] = ''
|
||||
if credentials["api_key"] is None:
|
||||
credentials["api_key"] = ""
|
||||
else:
|
||||
result = JinaReaderTool().fork_tool_runtime(
|
||||
runtime={
|
||||
"credentials": credentials,
|
||||
}
|
||||
).invoke(
|
||||
user_id='',
|
||||
tool_parameters={
|
||||
"url": "https://example.com",
|
||||
},
|
||||
)[0]
|
||||
result = (
|
||||
JinaReaderTool()
|
||||
.fork_tool_runtime(
|
||||
runtime={
|
||||
"credentials": credentials,
|
||||
}
|
||||
)
|
||||
.invoke(
|
||||
user_id="",
|
||||
tool_parameters={
|
||||
"url": "https://example.com",
|
||||
},
|
||||
)[0]
|
||||
)
|
||||
|
||||
message = json.loads(result.message)
|
||||
if message['code'] != 200:
|
||||
raise ToolProviderCredentialValidationError(message['message'])
|
||||
if message["code"] != 200:
|
||||
raise ToolProviderCredentialValidationError(message["message"])
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
||||
|
||||
def _get_tool_labels(self) -> list[ToolLabelEnum]:
|
||||
return [
|
||||
ToolLabelEnum.SEARCH, ToolLabelEnum.PRODUCTIVITY
|
||||
]
|
||||
return [ToolLabelEnum.SEARCH, ToolLabelEnum.PRODUCTIVITY]
|
||||
|
@@ -9,26 +9,25 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class JinaReaderTool(BuiltinTool):
|
||||
_jina_reader_endpoint = 'https://r.jina.ai/'
|
||||
_jina_reader_endpoint = "https://r.jina.ai/"
|
||||
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
invoke tools
|
||||
invoke tools
|
||||
"""
|
||||
url = tool_parameters['url']
|
||||
url = tool_parameters["url"]
|
||||
|
||||
headers = {
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
headers = {"Accept": "application/json"}
|
||||
|
||||
if 'api_key' in self.runtime.credentials and self.runtime.credentials.get('api_key'):
|
||||
headers['Authorization'] = "Bearer " + self.runtime.credentials.get('api_key')
|
||||
if "api_key" in self.runtime.credentials and self.runtime.credentials.get("api_key"):
|
||||
headers["Authorization"] = "Bearer " + self.runtime.credentials.get("api_key")
|
||||
|
||||
request_params = tool_parameters.get('request_params')
|
||||
if request_params is not None and request_params != '':
|
||||
request_params = tool_parameters.get("request_params")
|
||||
if request_params is not None and request_params != "":
|
||||
try:
|
||||
request_params = json.loads(request_params)
|
||||
if not isinstance(request_params, dict):
|
||||
@@ -36,40 +35,40 @@ class JinaReaderTool(BuiltinTool):
|
||||
except (json.JSONDecodeError, ValueError) as e:
|
||||
raise ValueError(f"Invalid request_params: {e}")
|
||||
|
||||
target_selector = tool_parameters.get('target_selector')
|
||||
if target_selector is not None and target_selector != '':
|
||||
headers['X-Target-Selector'] = target_selector
|
||||
target_selector = tool_parameters.get("target_selector")
|
||||
if target_selector is not None and target_selector != "":
|
||||
headers["X-Target-Selector"] = target_selector
|
||||
|
||||
wait_for_selector = tool_parameters.get('wait_for_selector')
|
||||
if wait_for_selector is not None and wait_for_selector != '':
|
||||
headers['X-Wait-For-Selector'] = wait_for_selector
|
||||
wait_for_selector = tool_parameters.get("wait_for_selector")
|
||||
if wait_for_selector is not None and wait_for_selector != "":
|
||||
headers["X-Wait-For-Selector"] = wait_for_selector
|
||||
|
||||
if tool_parameters.get('image_caption', False):
|
||||
headers['X-With-Generated-Alt'] = 'true'
|
||||
if tool_parameters.get("image_caption", False):
|
||||
headers["X-With-Generated-Alt"] = "true"
|
||||
|
||||
if tool_parameters.get('gather_all_links_at_the_end', False):
|
||||
headers['X-With-Links-Summary'] = 'true'
|
||||
if tool_parameters.get("gather_all_links_at_the_end", False):
|
||||
headers["X-With-Links-Summary"] = "true"
|
||||
|
||||
if tool_parameters.get('gather_all_images_at_the_end', False):
|
||||
headers['X-With-Images-Summary'] = 'true'
|
||||
if tool_parameters.get("gather_all_images_at_the_end", False):
|
||||
headers["X-With-Images-Summary"] = "true"
|
||||
|
||||
proxy_server = tool_parameters.get('proxy_server')
|
||||
if proxy_server is not None and proxy_server != '':
|
||||
headers['X-Proxy-Url'] = proxy_server
|
||||
proxy_server = tool_parameters.get("proxy_server")
|
||||
if proxy_server is not None and proxy_server != "":
|
||||
headers["X-Proxy-Url"] = proxy_server
|
||||
|
||||
if tool_parameters.get('no_cache', False):
|
||||
headers['X-No-Cache'] = 'true'
|
||||
if tool_parameters.get("no_cache", False):
|
||||
headers["X-No-Cache"] = "true"
|
||||
|
||||
max_retries = tool_parameters.get('max_retries', 3)
|
||||
max_retries = tool_parameters.get("max_retries", 3)
|
||||
response = ssrf_proxy.get(
|
||||
str(URL(self._jina_reader_endpoint + url)),
|
||||
headers=headers,
|
||||
params=request_params,
|
||||
timeout=(10, 60),
|
||||
max_retries=max_retries
|
||||
max_retries=max_retries,
|
||||
)
|
||||
|
||||
if tool_parameters.get('summary', False):
|
||||
if tool_parameters.get("summary", False):
|
||||
return self.create_text_message(self.summary(user_id, response.text))
|
||||
|
||||
return self.create_text_message(response.text)
|
||||
|
@@ -8,44 +8,39 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class JinaSearchTool(BuiltinTool):
|
||||
_jina_search_endpoint = 'https://s.jina.ai/'
|
||||
_jina_search_endpoint = "https://s.jina.ai/"
|
||||
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
query = tool_parameters['query']
|
||||
query = tool_parameters["query"]
|
||||
|
||||
headers = {
|
||||
'Accept': 'application/json'
|
||||
}
|
||||
headers = {"Accept": "application/json"}
|
||||
|
||||
if 'api_key' in self.runtime.credentials and self.runtime.credentials.get('api_key'):
|
||||
headers['Authorization'] = "Bearer " + self.runtime.credentials.get('api_key')
|
||||
if "api_key" in self.runtime.credentials and self.runtime.credentials.get("api_key"):
|
||||
headers["Authorization"] = "Bearer " + self.runtime.credentials.get("api_key")
|
||||
|
||||
if tool_parameters.get('image_caption', False):
|
||||
headers['X-With-Generated-Alt'] = 'true'
|
||||
if tool_parameters.get("image_caption", False):
|
||||
headers["X-With-Generated-Alt"] = "true"
|
||||
|
||||
if tool_parameters.get('gather_all_links_at_the_end', False):
|
||||
headers['X-With-Links-Summary'] = 'true'
|
||||
if tool_parameters.get("gather_all_links_at_the_end", False):
|
||||
headers["X-With-Links-Summary"] = "true"
|
||||
|
||||
if tool_parameters.get('gather_all_images_at_the_end', False):
|
||||
headers['X-With-Images-Summary'] = 'true'
|
||||
if tool_parameters.get("gather_all_images_at_the_end", False):
|
||||
headers["X-With-Images-Summary"] = "true"
|
||||
|
||||
proxy_server = tool_parameters.get('proxy_server')
|
||||
if proxy_server is not None and proxy_server != '':
|
||||
headers['X-Proxy-Url'] = proxy_server
|
||||
proxy_server = tool_parameters.get("proxy_server")
|
||||
if proxy_server is not None and proxy_server != "":
|
||||
headers["X-Proxy-Url"] = proxy_server
|
||||
|
||||
if tool_parameters.get('no_cache', False):
|
||||
headers['X-No-Cache'] = 'true'
|
||||
if tool_parameters.get("no_cache", False):
|
||||
headers["X-No-Cache"] = "true"
|
||||
|
||||
max_retries = tool_parameters.get('max_retries', 3)
|
||||
max_retries = tool_parameters.get("max_retries", 3)
|
||||
response = ssrf_proxy.get(
|
||||
str(URL(self._jina_search_endpoint + query)),
|
||||
headers=headers,
|
||||
timeout=(10, 60),
|
||||
max_retries=max_retries
|
||||
str(URL(self._jina_search_endpoint + query)), headers=headers, timeout=(10, 60), max_retries=max_retries
|
||||
)
|
||||
|
||||
return self.create_text_message(response.text)
|
||||
|
@@ -6,33 +6,29 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class JinaTokenizerTool(BuiltinTool):
|
||||
_jina_tokenizer_endpoint = 'https://tokenize.jina.ai/'
|
||||
_jina_tokenizer_endpoint = "https://tokenize.jina.ai/"
|
||||
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> ToolInvokeMessage:
|
||||
content = tool_parameters['content']
|
||||
body = {
|
||||
"content": content
|
||||
}
|
||||
content = tool_parameters["content"]
|
||||
body = {"content": content}
|
||||
|
||||
headers = {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
headers = {"Content-Type": "application/json"}
|
||||
|
||||
if 'api_key' in self.runtime.credentials and self.runtime.credentials.get('api_key'):
|
||||
headers['Authorization'] = "Bearer " + self.runtime.credentials.get('api_key')
|
||||
if "api_key" in self.runtime.credentials and self.runtime.credentials.get("api_key"):
|
||||
headers["Authorization"] = "Bearer " + self.runtime.credentials.get("api_key")
|
||||
|
||||
if tool_parameters.get('return_chunks', False):
|
||||
body['return_chunks'] = True
|
||||
|
||||
if tool_parameters.get('return_tokens', False):
|
||||
body['return_tokens'] = True
|
||||
|
||||
if tokenizer := tool_parameters.get('tokenizer'):
|
||||
body['tokenizer'] = tokenizer
|
||||
if tool_parameters.get("return_chunks", False):
|
||||
body["return_chunks"] = True
|
||||
|
||||
if tool_parameters.get("return_tokens", False):
|
||||
body["return_tokens"] = True
|
||||
|
||||
if tokenizer := tool_parameters.get("tokenizer"):
|
||||
body["tokenizer"] = tokenizer
|
||||
|
||||
response = ssrf_proxy.post(
|
||||
self._jina_tokenizer_endpoint,
|
||||
|
@@ -8,10 +8,9 @@ from core.tools.provider.builtin_tool_provider import BuiltinToolProviderControl
|
||||
class JsonExtractProvider(BuiltinToolProviderController):
|
||||
def _validate_credentials(self, credentials: dict[str, Any]) -> None:
|
||||
try:
|
||||
JSONParseTool().invoke(user_id='',
|
||||
tool_parameters={
|
||||
'content': '{"name": "John", "age": 30, "city": "New York"}',
|
||||
'json_filter': '$.name'
|
||||
})
|
||||
JSONParseTool().invoke(
|
||||
user_id="",
|
||||
tool_parameters={"content": '{"name": "John", "age": 30, "city": "New York"}', "json_filter": "$.name"},
|
||||
)
|
||||
except Exception as e:
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
raise ToolProviderCredentialValidationError(str(e))
|
||||
|
@@ -8,34 +8,35 @@ from core.tools.tool.builtin_tool import BuiltinTool
|
||||
|
||||
|
||||
class JSONDeleteTool(BuiltinTool):
|
||||
def _invoke(self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
def _invoke(
|
||||
self,
|
||||
user_id: str,
|
||||
tool_parameters: dict[str, Any],
|
||||
) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]:
|
||||
"""
|
||||
Invoke the JSON delete tool
|
||||
"""
|
||||
# Get content
|
||||
content = tool_parameters.get('content', '')
|
||||
content = tool_parameters.get("content", "")
|
||||
if not content:
|
||||
return self.create_text_message('Invalid parameter content')
|
||||
return self.create_text_message("Invalid parameter content")
|
||||
|
||||
# Get query
|
||||
query = tool_parameters.get('query', '')
|
||||
query = tool_parameters.get("query", "")
|
||||
if not query:
|
||||
return self.create_text_message('Invalid parameter query')
|
||||
return self.create_text_message("Invalid parameter query")
|
||||
|
||||
ensure_ascii = tool_parameters.get('ensure_ascii', True)
|
||||
ensure_ascii = tool_parameters.get("ensure_ascii", True)
|
||||
try:
|
||||
result = self._delete(content, query, ensure_ascii)
|
||||
return self.create_text_message(str(result))
|
||||
except Exception as e:
|
||||
return self.create_text_message(f'Failed to delete JSON content: {str(e)}')
|
||||
return self.create_text_message(f"Failed to delete JSON content: {str(e)}")
|
||||
|
||||
def _delete(self, origin_json: str, query: str, ensure_ascii: bool) -> str:
|
||||
try:
|
||||
input_data = json.loads(origin_json)
|
||||
expr = parse('$.' + query.lstrip('$.')) # Ensure query path starts with $
|
||||
expr = parse("$." + query.lstrip("$.")) # Ensure query path starts with $
|
||||
|
||||
matches = expr.find(input_data)
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user