From f82a64d149b001ac2b875bf5142acce0da7f5265 Mon Sep 17 00:00:00 2001 From: Bowen Liang Date: Tue, 12 Mar 2024 13:45:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20add=20DingTalk(=E9=92=89=E9=92=89)=20to?= =?UTF-8?q?ol=20for=20sending=20message=20to=20chat=20group=20bot=20via=20?= =?UTF-8?q?webhook=20(#2693)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/core/tools/provider/_position.yaml | 1 + .../builtin/dingtalk/_assets/icon.svg | 7 ++ .../provider/builtin/dingtalk/dingtalk.py | 8 ++ .../provider/builtin/dingtalk/dingtalk.yaml | 13 +++ .../dingtalk/tools/dingtalk_group_bot.py | 83 +++++++++++++++++++ .../dingtalk/tools/dingtalk_group_bot.yaml | 52 ++++++++++++ 6 files changed, 164 insertions(+) create mode 100644 api/core/tools/provider/builtin/dingtalk/_assets/icon.svg create mode 100644 api/core/tools/provider/builtin/dingtalk/dingtalk.py create mode 100644 api/core/tools/provider/builtin/dingtalk/dingtalk.yaml create mode 100644 api/core/tools/provider/builtin/dingtalk/tools/dingtalk_group_bot.py create mode 100644 api/core/tools/provider/builtin/dingtalk/tools/dingtalk_group_bot.yaml diff --git a/api/core/tools/provider/_position.yaml b/api/core/tools/provider/_position.yaml index ece9dbe1596851..a69f37618e6116 100644 --- a/api/core/tools/provider/_position.yaml +++ b/api/core/tools/provider/_position.yaml @@ -24,3 +24,4 @@ - gaode - wecom - qrcode +- dingtalk diff --git a/api/core/tools/provider/builtin/dingtalk/_assets/icon.svg b/api/core/tools/provider/builtin/dingtalk/_assets/icon.svg new file mode 100644 index 00000000000000..b60653b7a59409 --- /dev/null +++ b/api/core/tools/provider/builtin/dingtalk/_assets/icon.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/api/core/tools/provider/builtin/dingtalk/dingtalk.py b/api/core/tools/provider/builtin/dingtalk/dingtalk.py new file mode 100644 index 00000000000000..be1d5e099c2246 --- /dev/null +++ b/api/core/tools/provider/builtin/dingtalk/dingtalk.py @@ -0,0 +1,8 @@ +from core.tools.provider.builtin.dingtalk.tools.dingtalk_group_bot import DingTalkGroupBotTool +from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController + + +class DingTalkProvider(BuiltinToolProviderController): + def _validate_credentials(self, credentials: dict) -> None: + DingTalkGroupBotTool() + pass diff --git a/api/core/tools/provider/builtin/dingtalk/dingtalk.yaml b/api/core/tools/provider/builtin/dingtalk/dingtalk.yaml new file mode 100644 index 00000000000000..ebe2e4fbafcb13 --- /dev/null +++ b/api/core/tools/provider/builtin/dingtalk/dingtalk.yaml @@ -0,0 +1,13 @@ +identity: + author: Bowen Liang + name: dingtalk + label: + en_US: DingTalk + zh_Hans: 钉钉 + pt_BR: DingTalk + description: + en_US: DingTalk group robot + zh_Hans: 钉钉群机器人 + pt_BR: DingTalk group robot + icon: icon.svg +credentials_for_provider: diff --git a/api/core/tools/provider/builtin/dingtalk/tools/dingtalk_group_bot.py b/api/core/tools/provider/builtin/dingtalk/tools/dingtalk_group_bot.py new file mode 100644 index 00000000000000..c247c3bd6bcff0 --- /dev/null +++ b/api/core/tools/provider/builtin/dingtalk/tools/dingtalk_group_bot.py @@ -0,0 +1,83 @@ +import base64 +import hashlib +import hmac +import logging +import time +import urllib.parse +from typing import Any, Union + +import httpx + +from core.tools.entities.tool_entities import ToolInvokeMessage +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]]: + """ + invoke tools + Dingtalk custom group robot API docs: + https://open.dingtalk.com/document/orgapp/custom-robot-access + """ + content = tool_parameters.get('content') + if not content: + return self.create_text_message('Invalid parameter content') + + 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') + + 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') + + msgtype = 'text' + api_url = 'https://oapi.dingtalk.com/robot/send' + headers = { + 'Content-Type': 'application/json', + } + params = { + 'access_token': access_token, + } + + self._apply_security_mechanism(params, sign_secret) + + payload = { + "msgtype": msgtype, + "text": { + "content": content, + } + } + + try: + res = httpx.post(api_url, headers=headers, params=params, json=payload) + if res.is_success: + 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}") + except Exception as e: + return self.create_text_message("Failed to send message to group chat bot. {}".format(e)) + + @staticmethod + 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') + 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 + except Exception: + msg = "Failed to apply security mechanism to the request." + logging.exception(msg) diff --git a/api/core/tools/provider/builtin/dingtalk/tools/dingtalk_group_bot.yaml b/api/core/tools/provider/builtin/dingtalk/tools/dingtalk_group_bot.yaml new file mode 100644 index 00000000000000..dc8a90b7193903 --- /dev/null +++ b/api/core/tools/provider/builtin/dingtalk/tools/dingtalk_group_bot.yaml @@ -0,0 +1,52 @@ +identity: + name: dingtalk_group_bot + author: Bowen Liang + label: + en_US: Send Group Message + zh_Hans: 发送群消息 + pt_BR: Send Group Message + icon: icon.svg +description: + human: + en_US: Sending a group message on DingTalk via the webhook of group bot + zh_Hans: 通过钉钉的群机器人webhook发送群消息 + pt_BR: Sending a group message on DingTalk via the webhook of group bot + llm: A tool for sending messages to a chat group on DingTalk(钉钉) . +parameters: + - name: access_token + type: secret-input + required: true + label: + en_US: access token + zh_Hans: access token + pt_BR: access token + human_description: + en_US: access_token in the group robot webhook + zh_Hans: 群自定义机器人webhook中access_token字段的值 + pt_BR: access_token in the group robot webhook + form: form + - name: sign_secret + type: secret-input + required: true + label: + en_US: secret key for signing + zh_Hans: 加签秘钥 + pt_BR: secret key for signing + human_description: + en_US: secret key for signing + zh_Hans: 加签秘钥 + pt_BR: secret key for signing + form: form + - name: content + type: string + required: true + label: + en_US: content + zh_Hans: 消息内容 + pt_BR: content + human_description: + en_US: Content to sent to the group. + zh_Hans: 群消息文本 + pt_BR: Content to sent to the group. + llm_description: Content of the message + form: llm