From 8807d880dc50a540e74463c5c05ef277ef4bb57e Mon Sep 17 00:00:00 2001 From: Junyan Qin <1010553892@qq.com> Date: Fri, 23 Aug 2024 19:16:30 +0800 Subject: [PATCH] Feat: add OneBot protocol tool (#7583) --- .../provider/builtin/onebot/_assets/icon.ico | Bin 0 -> 38078 bytes .../tools/provider/builtin/onebot/onebot.py | 12 ++++ .../tools/provider/builtin/onebot/onebot.yaml | 35 ++++++++++ .../provider/builtin/onebot/tools/__init__.py | 0 .../builtin/onebot/tools/send_group_msg.py | 62 ++++++++++++++++++ .../builtin/onebot/tools/send_group_msg.yaml | 46 +++++++++++++ .../builtin/onebot/tools/send_private_msg.py | 61 +++++++++++++++++ .../onebot/tools/send_private_msg.yaml | 46 +++++++++++++ 8 files changed, 262 insertions(+) create mode 100644 api/core/tools/provider/builtin/onebot/_assets/icon.ico create mode 100644 api/core/tools/provider/builtin/onebot/onebot.py create mode 100644 api/core/tools/provider/builtin/onebot/onebot.yaml create mode 100644 api/core/tools/provider/builtin/onebot/tools/__init__.py create mode 100644 api/core/tools/provider/builtin/onebot/tools/send_group_msg.py create mode 100644 api/core/tools/provider/builtin/onebot/tools/send_group_msg.yaml create mode 100644 api/core/tools/provider/builtin/onebot/tools/send_private_msg.py create mode 100644 api/core/tools/provider/builtin/onebot/tools/send_private_msg.yaml diff --git a/api/core/tools/provider/builtin/onebot/_assets/icon.ico b/api/core/tools/provider/builtin/onebot/_assets/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..1b07e965b9910b4b006bc112378a8ba0306895a8 GIT binary patch literal 38078 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 literal 0 HcmV?d00001 diff --git a/api/core/tools/provider/builtin/onebot/onebot.py b/api/core/tools/provider/builtin/onebot/onebot.py new file mode 100644 index 0000000000..42f321e919 --- /dev/null +++ b/api/core/tools/provider/builtin/onebot/onebot.py @@ -0,0 +1,12 @@ +from typing import Any + +from core.tools.errors import ToolProviderCredentialValidationError +from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController + + +class OneBotProvider(BuiltinToolProviderController): + + def _validate_credentials(self, credentials: dict[str, Any]) -> None: + + if not credentials.get("ob11_http_url"): + raise ToolProviderCredentialValidationError('OneBot HTTP URL is required.') diff --git a/api/core/tools/provider/builtin/onebot/onebot.yaml b/api/core/tools/provider/builtin/onebot/onebot.yaml new file mode 100644 index 0000000000..1922adc4de --- /dev/null +++ b/api/core/tools/provider/builtin/onebot/onebot.yaml @@ -0,0 +1,35 @@ +identity: + author: RockChinQ + name: onebot + label: + en_US: OneBot v11 Protocol + zh_Hans: OneBot v11 协议 + description: + en_US: Unofficial OneBot v11 Protocol Tool + zh_Hans: 非官方 OneBot v11 协议工具 + icon: icon.ico +credentials_for_provider: + ob11_http_url: + type: text-input + required: true + label: + en_US: HTTP URL + zh_Hans: HTTP URL + description: + en_US: Forward HTTP URL of OneBot v11 + zh_Hans: OneBot v11 正向 HTTP URL + help: + en_US: Fill this with the HTTP URL of your OneBot server + zh_Hans: 请在你的 OneBot 协议端开启 正向 HTTP 并填写其 URL + access_token: + type: secret-input + required: false + label: + en_US: Access Token + zh_Hans: 访问令牌 + description: + en_US: Access Token for OneBot v11 Protocol + zh_Hans: OneBot 协议访问令牌 + help: + en_US: Fill this if you set a access token in your OneBot server + zh_Hans: 如果你在 OneBot 服务器中设置了 access token,请填写此项 diff --git a/api/core/tools/provider/builtin/onebot/tools/__init__.py b/api/core/tools/provider/builtin/onebot/tools/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/api/core/tools/provider/builtin/onebot/tools/send_group_msg.py b/api/core/tools/provider/builtin/onebot/tools/send_group_msg.py new file mode 100644 index 0000000000..802bb7b610 --- /dev/null +++ b/api/core/tools/provider/builtin/onebot/tools/send_group_msg.py @@ -0,0 +1,62 @@ +from typing import Any, Union + +import requests + +from core.tools.entities.tool_entities import ToolInvokeMessage +from core.tools.tool.builtin_tool import BuiltinTool + + +class SendGroupMsg(BuiltinTool): + """OneBot v11 Tool: Send Group Message""" + + def _invoke( + self, + user_id: str, + tool_parameters: dict[str, Any] + ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]: + + # Get parameters + send_group_id = tool_parameters.get('group_id', '') + + message = tool_parameters.get('message', '') + if not message: + return self.create_json_message( + { + 'error': 'Message is empty.' + } + ) + + auto_escape = tool_parameters.get('auto_escape', False) + + try: + + resp = requests.post( + f'{self.runtime.credentials['ob11_http_url']}/send_group_msg', + json={ + 'group_id': send_group_id, + 'message': message, + 'auto_escape': auto_escape + }, + headers={ + 'Authorization': 'Bearer ' + self.runtime.credentials['access_token'] + } + ) + + if resp.status_code != 200: + return self.create_json_message( + { + 'error': f'Failed to send group message: {resp.text}' + } + ) + + return self.create_json_message( + { + 'response': resp.json() + } + ) + except Exception as e: + return self.create_json_message( + { + 'error': f'Failed to send group message: {e}' + } + ) diff --git a/api/core/tools/provider/builtin/onebot/tools/send_group_msg.yaml b/api/core/tools/provider/builtin/onebot/tools/send_group_msg.yaml new file mode 100644 index 0000000000..64beaa8545 --- /dev/null +++ b/api/core/tools/provider/builtin/onebot/tools/send_group_msg.yaml @@ -0,0 +1,46 @@ +identity: + name: send_group_msg + author: RockChinQ + label: + en_US: Send Group Message + zh_Hans: 发送群消息 +description: + human: + en_US: Send a message to a group + zh_Hans: 发送消息到群聊 + llm: A tool for sending a message segment to a group +parameters: + - name: group_id + type: number + required: true + label: + en_US: Target Group ID + zh_Hans: 目标群 ID + human_description: + en_US: The group ID of the target group + zh_Hans: 目标群的群 ID + llm_description: The group ID of the target group + form: llm + - name: message + type: string + required: true + label: + en_US: Message + zh_Hans: 消息 + human_description: + en_US: The message to send + zh_Hans: 要发送的消息。支持 CQ码(需要同时设置 auto_escape 为 true) + llm_description: The message to send + form: llm + - name: auto_escape + type: boolean + required: false + default: false + label: + en_US: Auto Escape + zh_Hans: 自动转义 + human_description: + en_US: If true, the message will be treated as a CQ code for parsing, otherwise it will be treated as plain text for direct sending. Since Dify currently does not support passing Object-format message chains, developers can send complex message components through CQ codes. + zh_Hans: 若为 true 则会把 message 视为 CQ 码解析,否则视为 纯文本 直接发送。由于 Dify 目前不支持传入 Object格式 的消息,故开发者可以通过 CQ 码来发送复杂消息组件。 + llm_description: If true, the message will be treated as a CQ code for parsing, otherwise it will be treated as plain text for direct sending. + form: form diff --git a/api/core/tools/provider/builtin/onebot/tools/send_private_msg.py b/api/core/tools/provider/builtin/onebot/tools/send_private_msg.py new file mode 100644 index 0000000000..a11c7a46c0 --- /dev/null +++ b/api/core/tools/provider/builtin/onebot/tools/send_private_msg.py @@ -0,0 +1,61 @@ +from typing import Any, Union + +import requests + +from core.tools.entities.tool_entities import ToolInvokeMessage +from core.tools.tool.builtin_tool import BuiltinTool + + +class SendPrivateMsg(BuiltinTool): + """OneBot v11 Tool: Send Private Message""" + + def _invoke( + self, + user_id: str, + tool_parameters: dict[str, Any] + ) -> Union[ToolInvokeMessage, list[ToolInvokeMessage]]: + + # Get parameters + send_user_id = tool_parameters.get('user_id', '') + + message = tool_parameters.get('message', '') + if not message: + return self.create_json_message( + { + 'error': 'Message is empty.' + } + ) + + auto_escape = tool_parameters.get('auto_escape', False) + + try: + resp = requests.post( + f'{self.runtime.credentials['ob11_http_url']}/send_private_msg', + json={ + 'user_id': send_user_id, + 'message': message, + 'auto_escape': auto_escape + }, + headers={ + 'Authorization': 'Bearer ' + self.runtime.credentials['access_token'] + } + ) + + if resp.status_code != 200: + return self.create_json_message( + { + 'error': f'Failed to send private message: {resp.text}' + } + ) + + return self.create_json_message( + { + 'response': resp.json() + } + ) + except Exception as e: + return self.create_json_message( + { + 'error': f'Failed to send private message: {e}' + } + ) \ No newline at end of file diff --git a/api/core/tools/provider/builtin/onebot/tools/send_private_msg.yaml b/api/core/tools/provider/builtin/onebot/tools/send_private_msg.yaml new file mode 100644 index 0000000000..8200ce4a83 --- /dev/null +++ b/api/core/tools/provider/builtin/onebot/tools/send_private_msg.yaml @@ -0,0 +1,46 @@ +identity: + name: send_private_msg + author: RockChinQ + label: + en_US: Send Private Message + zh_Hans: 发送私聊消息 +description: + human: + en_US: Send a private message to a user + zh_Hans: 发送私聊消息给用户 + llm: A tool for sending a message segment to a user in private chat +parameters: + - name: user_id + type: number + required: true + label: + en_US: Target User ID + zh_Hans: 目标用户 ID + human_description: + en_US: The user ID of the target user + zh_Hans: 目标用户的用户 ID + llm_description: The user ID of the target user + form: llm + - name: message + type: string + required: true + label: + en_US: Message + zh_Hans: 消息 + human_description: + en_US: The message to send + zh_Hans: 要发送的消息。支持 CQ码(需要同时设置 auto_escape 为 true) + llm_description: The message to send + form: llm + - name: auto_escape + type: boolean + required: false + default: false + label: + en_US: Auto Escape + zh_Hans: 自动转义 + human_description: + en_US: If true, the message will be treated as a CQ code for parsing, otherwise it will be treated as plain text for direct sending. Since Dify currently does not support passing Object-format message chains, developers can send complex message components through CQ codes. + zh_Hans: 若为 true 则会把 message 视为 CQ 码解析,否则视为 纯文本 直接发送。由于 Dify 目前不支持传入 Object格式 的消息,故开发者可以通过 CQ 码来发送复杂消息组件。 + llm_description: If true, the message will be treated as a CQ code for parsing, otherwise it will be treated as plain text for direct sending. + form: form