diff --git a/api/core/tools/provider/_position.yaml b/api/core/tools/provider/_position.yaml
index 25d9f403a0..b804089570 100644
--- a/api/core/tools/provider/_position.yaml
+++ b/api/core/tools/provider/_position.yaml
@@ -30,5 +30,7 @@
- dingtalk
- feishu
- feishu_base
+- feishu_document
+- feishu_message
- slack
- tianditu
diff --git a/api/core/tools/provider/builtin/feishu_document/_assets/icon.svg b/api/core/tools/provider/builtin/feishu_document/_assets/icon.svg
new file mode 100644
index 0000000000..5a0a6416b3
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/_assets/icon.svg
@@ -0,0 +1,9 @@
+
+
+
diff --git a/api/core/tools/provider/builtin/feishu_document/feishu_document.py b/api/core/tools/provider/builtin/feishu_document/feishu_document.py
new file mode 100644
index 0000000000..c4f8f26e2c
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/feishu_document.py
@@ -0,0 +1,15 @@
+from core.tools.errors import ToolProviderCredentialValidationError
+from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
+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')
+ 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))
\ No newline at end of file
diff --git a/api/core/tools/provider/builtin/feishu_document/feishu_document.yaml b/api/core/tools/provider/builtin/feishu_document/feishu_document.yaml
new file mode 100644
index 0000000000..8eaa6b2704
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/feishu_document.yaml
@@ -0,0 +1,34 @@
+identity:
+ author: Doug Lea
+ name: feishu_document
+ label:
+ en_US: Lark Cloud Document
+ zh_Hans: 飞书云文档
+ description:
+ en_US: Lark Cloud Document
+ zh_Hans: 飞书云文档
+ icon: icon.svg
+ tags:
+ - social
+ - productivity
+credentials_for_provider:
+ app_id:
+ type: text-input
+ required: true
+ label:
+ en_US: APP ID
+ placeholder:
+ en_US: Please input your feishu app id
+ zh_Hans: 请输入你的飞书 app id
+ help:
+ en_US: Get your app_id and app_secret from Feishu
+ zh_Hans: 从飞书获取您的 app_id 和 app_secret
+ url: https://open.feishu.cn
+ app_secret:
+ type: secret-input
+ required: true
+ label:
+ en_US: APP Secret
+ placeholder:
+ en_US: Please input your app secret
+ zh_Hans: 请输入你的飞书 app secret
diff --git a/api/core/tools/provider/builtin/feishu_document/tools/create_document.py b/api/core/tools/provider/builtin/feishu_document/tools/create_document.py
new file mode 100644
index 0000000000..0ff82e621b
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/tools/create_document.py
@@ -0,0 +1,19 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+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')
+ client = FeishuRequest(app_id, app_secret)
+
+ 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)
diff --git a/api/core/tools/provider/builtin/feishu_document/tools/create_document.yaml b/api/core/tools/provider/builtin/feishu_document/tools/create_document.yaml
new file mode 100644
index 0000000000..ddf2729f0e
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/tools/create_document.yaml
@@ -0,0 +1,47 @@
+identity:
+ name: create_document
+ author: Doug Lea
+ label:
+ en_US: Create Lark document
+ zh_Hans: 创建飞书文档
+description:
+ human:
+ en_US: Create Lark document
+ zh_Hans: 创建飞书文档,支持创建空文档和带内容的文档,支持 markdown 语法创建。
+ llm: A tool for creating Feishu documents.
+parameters:
+ - name: title
+ type: string
+ required: false
+ label:
+ en_US: Document title
+ zh_Hans: 文档标题
+ human_description:
+ en_US: Document title, only supports plain text content.
+ zh_Hans: 文档标题,只支持纯文本内容。
+ llm_description: 文档标题,只支持纯文本内容,可以为空。
+ form: llm
+
+ - name: content
+ type: string
+ required: false
+ label:
+ en_US: Document content
+ zh_Hans: 文档内容
+ human_description:
+ en_US: Document content, supports markdown syntax, can be empty.
+ zh_Hans: 文档内容,支持 markdown 语法,可以为空。
+ llm_description: 文档内容,支持 markdown 语法,可以为空。
+ form: llm
+
+ - name: folder_token
+ type: string
+ required: false
+ label:
+ en_US: folder_token
+ zh_Hans: 文档所在文件夹的 Token
+ human_description:
+ en_US: The token of the folder where the document is located. If it is not passed or is empty, it means the root directory.
+ zh_Hans: 文档所在文件夹的 Token,不传或传空表示根目录。
+ llm_description: 文档所在文件夹的 Token,不传或传空表示根目录。
+ form: llm
diff --git a/api/core/tools/provider/builtin/feishu_document/tools/get_document_raw_content.py b/api/core/tools/provider/builtin/feishu_document/tools/get_document_raw_content.py
new file mode 100644
index 0000000000..16ef90908b
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/tools/get_document_raw_content.py
@@ -0,0 +1,17 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+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')
+ client = FeishuRequest(app_id, app_secret)
+
+ document_id = tool_parameters.get('document_id')
+
+ res = client.get_document_raw_content(document_id)
+ return self.create_json_message(res)
\ No newline at end of file
diff --git a/api/core/tools/provider/builtin/feishu_document/tools/get_document_raw_content.yaml b/api/core/tools/provider/builtin/feishu_document/tools/get_document_raw_content.yaml
new file mode 100644
index 0000000000..e5b0937e03
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/tools/get_document_raw_content.yaml
@@ -0,0 +1,23 @@
+identity:
+ name: get_document_raw_content
+ author: Doug Lea
+ label:
+ en_US: Get Document Raw Content
+ zh_Hans: 获取文档纯文本内容
+description:
+ human:
+ en_US: Get document raw content
+ zh_Hans: 获取文档纯文本内容
+ llm: A tool for getting the plain text content of Feishu documents
+parameters:
+ - name: document_id
+ type: string
+ required: true
+ label:
+ en_US: document_id
+ zh_Hans: 飞书文档的唯一标识
+ human_description:
+ en_US: Unique ID of Feishu document document_id
+ zh_Hans: 飞书文档的唯一标识 document_id
+ llm_description: 飞书文档的唯一标识 document_id
+ form: llm
diff --git a/api/core/tools/provider/builtin/feishu_document/tools/list_document_block.py b/api/core/tools/provider/builtin/feishu_document/tools/list_document_block.py
new file mode 100644
index 0000000000..97d17bdb04
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/tools/list_document_block.py
@@ -0,0 +1,19 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+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')
+ 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', '')
+
+ res = client.list_document_block(document_id, page_token, page_size)
+ return self.create_json_message(res)
diff --git a/api/core/tools/provider/builtin/feishu_document/tools/list_document_block.yaml b/api/core/tools/provider/builtin/feishu_document/tools/list_document_block.yaml
new file mode 100644
index 0000000000..d51e5a837c
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/tools/list_document_block.yaml
@@ -0,0 +1,48 @@
+identity:
+ name: list_document_block
+ author: Doug Lea
+ label:
+ en_US: List Document Block
+ zh_Hans: 获取飞书文档所有块
+description:
+ human:
+ en_US: List document block
+ zh_Hans: 获取飞书文档所有块的富文本内容并分页返回。
+ llm: A tool to get all blocks of Feishu documents
+parameters:
+ - name: document_id
+ type: string
+ required: true
+ label:
+ en_US: document_id
+ zh_Hans: 飞书文档的唯一标识
+ human_description:
+ en_US: Unique ID of Feishu document document_id
+ zh_Hans: 飞书文档的唯一标识 document_id
+ llm_description: 飞书文档的唯一标识 document_id
+ form: llm
+
+ - name: page_size
+ type: number
+ required: false
+ default: 500
+ label:
+ en_US: page_size
+ zh_Hans: 分页大小
+ human_description:
+ en_US: Paging size, the default and maximum value is 500.
+ zh_Hans: 分页大小, 默认值和最大值为 500。
+ llm_description: 分页大小, 表示一次请求最多返回多少条数据,默认值和最大值为 500。
+ form: llm
+
+ - name: page_token
+ type: string
+ required: false
+ label:
+ en_US: page_token
+ zh_Hans: 分页标记
+ human_description:
+ en_US: Pagination tag, used to paginate query results so that more items can be obtained in the next traversal.
+ zh_Hans: 分页标记,用于分页查询结果,以便下次遍历时获取更多项。
+ llm_description: 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的 page_token,下次遍历可采用该 page_token 获取查询结果。
+ form: llm
diff --git a/api/core/tools/provider/builtin/feishu_document/tools/write_document.py b/api/core/tools/provider/builtin/feishu_document/tools/write_document.py
new file mode 100644
index 0000000000..914a44dce6
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/tools/write_document.py
@@ -0,0 +1,19 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+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')
+ client = FeishuRequest(app_id, app_secret)
+
+ 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)
diff --git a/api/core/tools/provider/builtin/feishu_document/tools/write_document.yaml b/api/core/tools/provider/builtin/feishu_document/tools/write_document.yaml
new file mode 100644
index 0000000000..8ee219d4a7
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_document/tools/write_document.yaml
@@ -0,0 +1,56 @@
+identity:
+ name: write_document
+ author: Doug Lea
+ label:
+ en_US: Write Document
+ zh_Hans: 在飞书文档中新增内容
+description:
+ human:
+ en_US: Adding new content to Lark documents
+ zh_Hans: 在飞书文档中新增内容
+ llm: A tool for adding new content to Lark documents.
+parameters:
+ - name: document_id
+ type: string
+ required: true
+ label:
+ en_US: document_id
+ zh_Hans: 飞书文档的唯一标识
+ human_description:
+ en_US: Unique ID of Feishu document document_id
+ zh_Hans: 飞书文档的唯一标识 document_id
+ llm_description: 飞书文档的唯一标识 document_id
+ form: llm
+
+ - name: content
+ type: string
+ required: true
+ label:
+ en_US: document content
+ zh_Hans: 文档内容
+ human_description:
+ en_US: Document content, supports markdown syntax, can be empty.
+ zh_Hans: 文档内容,支持 markdown 语法,可以为空。
+ llm_description:
+ form: llm
+
+ - name: position
+ type: select
+ required: true
+ default: start
+ label:
+ en_US: Choose where to add content
+ zh_Hans: 选择添加内容的位置
+ human_description:
+ en_US: Please fill in start or end to add content at the beginning or end of the document respectively.
+ zh_Hans: 请填入 start 或 end, 分别表示在文档开头(start)或结尾(end)添加内容。
+ form: llm
+ options:
+ - value: start
+ label:
+ en_US: start
+ zh_Hans: 在文档开头添加内容
+ - value: end
+ label:
+ en_US: end
+ zh_Hans: 在文档结尾添加内容
diff --git a/api/core/tools/provider/builtin/feishu_message/_assets/icon.svg b/api/core/tools/provider/builtin/feishu_message/_assets/icon.svg
new file mode 100644
index 0000000000..222a1571f9
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_message/_assets/icon.svg
@@ -0,0 +1,19 @@
+
+
+
diff --git a/api/core/tools/provider/builtin/feishu_message/feishu_message.py b/api/core/tools/provider/builtin/feishu_message/feishu_message.py
new file mode 100644
index 0000000000..6d7fed330c
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_message/feishu_message.py
@@ -0,0 +1,15 @@
+from core.tools.errors import ToolProviderCredentialValidationError
+from core.tools.provider.builtin_tool_provider import BuiltinToolProviderController
+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')
+ 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))
\ No newline at end of file
diff --git a/api/core/tools/provider/builtin/feishu_message/feishu_message.yaml b/api/core/tools/provider/builtin/feishu_message/feishu_message.yaml
new file mode 100644
index 0000000000..1bd8953ddd
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_message/feishu_message.yaml
@@ -0,0 +1,34 @@
+identity:
+ author: Doug Lea
+ name: feishu_message
+ label:
+ en_US: Lark Message
+ zh_Hans: 飞书消息
+ description:
+ en_US: Lark Message
+ zh_Hans: 飞书消息
+ icon: icon.svg
+ tags:
+ - social
+ - productivity
+credentials_for_provider:
+ app_id:
+ type: text-input
+ required: true
+ label:
+ en_US: APP ID
+ placeholder:
+ en_US: Please input your feishu app id
+ zh_Hans: 请输入你的飞书 app id
+ help:
+ en_US: Get your app_id and app_secret from Feishu
+ zh_Hans: 从飞书获取您的 app_id 和 app_secret
+ url: https://open.feishu.cn
+ app_secret:
+ type: secret-input
+ required: true
+ label:
+ en_US: APP Secret
+ placeholder:
+ en_US: Please input your app secret
+ zh_Hans: 请输入你的飞书 app secret
diff --git a/api/core/tools/provider/builtin/feishu_message/tools/send_bot_message.py b/api/core/tools/provider/builtin/feishu_message/tools/send_bot_message.py
new file mode 100644
index 0000000000..74f6866ba3
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_message/tools/send_bot_message.py
@@ -0,0 +1,20 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+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')
+ 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')
+
+ res = client.send_bot_message(receive_id_type, receive_id, msg_type, content)
+ return self.create_json_message(res)
diff --git a/api/core/tools/provider/builtin/feishu_message/tools/send_bot_message.yaml b/api/core/tools/provider/builtin/feishu_message/tools/send_bot_message.yaml
new file mode 100644
index 0000000000..6e398b18ab
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_message/tools/send_bot_message.yaml
@@ -0,0 +1,91 @@
+identity:
+ name: send_bot_message
+ author: Doug Lea
+ label:
+ en_US: Send Bot Message
+ zh_Hans: 发送飞书应用消息
+description:
+ human:
+ en_US: Send bot message
+ zh_Hans: 发送飞书应用消息
+ llm: A tool for sending Feishu application messages.
+parameters:
+ - name: receive_id_type
+ type: select
+ required: true
+ options:
+ - value: open_id
+ label:
+ en_US: open id
+ zh_Hans: open id
+ - value: union_id
+ label:
+ en_US: union id
+ zh_Hans: union id
+ - value: user_id
+ label:
+ en_US: user id
+ zh_Hans: user id
+ - value: email
+ label:
+ en_US: email
+ zh_Hans: email
+ - value: chat_id
+ label:
+ en_US: chat id
+ zh_Hans: chat id
+ label:
+ en_US: User ID Type
+ zh_Hans: 用户 ID 类型
+ human_description:
+ en_US: User ID Type
+ zh_Hans: 用户 ID 类型,可选值有 open_id、union_id、user_id、email、chat_id。
+ llm_description: 用户 ID 类型,可选值有 open_id、union_id、user_id、email、chat_id。
+ form: llm
+
+ - name: receive_id
+ type: string
+ required: true
+ label:
+ en_US: Receive Id
+ zh_Hans: 消息接收者的 ID
+ human_description:
+ en_US: The ID of the message receiver. The ID type should correspond to the query parameter receive_id_type.
+ zh_Hans: 消息接收者的 ID,ID 类型应与查询参数 receive_id_type 对应。
+ llm_description: 消息接收者的 ID,ID 类型应与查询参数 receive_id_type 对应。
+ form: llm
+
+ - name: msg_type
+ type: string
+ required: true
+ options:
+ - value: text
+ label:
+ en_US: text
+ zh_Hans: 文本
+ - value: interactive
+ label:
+ en_US: message card
+ zh_Hans: 消息卡片
+ label:
+ en_US: Message type
+ zh_Hans: 消息类型
+ human_description:
+ en_US: Message type, optional values are, text (text), interactive (message card).
+ zh_Hans: 消息类型,可选值有:text(文本)、interactive(消息卡片)。
+ llm_description: 消息类型,可选值有:text(文本)、interactive(消息卡片)。
+ form: llm
+
+ - name: content
+ type: string
+ required: true
+ label:
+ en_US: Message content
+ zh_Hans: 消息内容
+ human_description:
+ en_US: Message content
+ zh_Hans: |
+ 消息内容,JSON 结构序列化后的字符串。不同 msg_type 对应不同内容,
+ 具体格式说明参考:https://open.larkoffice.com/document/server-docs/im-v1/message-content-description/create_json
+ llm_description: 消息内容,JSON 结构序列化后的字符串。不同 msg_type 对应不同内容。
+ form: llm
diff --git a/api/core/tools/provider/builtin/feishu_message/tools/send_webhook_message.py b/api/core/tools/provider/builtin/feishu_message/tools/send_webhook_message.py
new file mode 100644
index 0000000000..7159f59ffa
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_message/tools/send_webhook_message.py
@@ -0,0 +1,19 @@
+from typing import Any
+
+from core.tools.entities.tool_entities import ToolInvokeMessage
+from core.tools.tool.builtin_tool import BuiltinTool
+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')
+ client = FeishuRequest(app_id, app_secret)
+
+ 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)
diff --git a/api/core/tools/provider/builtin/feishu_message/tools/send_webhook_message.yaml b/api/core/tools/provider/builtin/feishu_message/tools/send_webhook_message.yaml
new file mode 100644
index 0000000000..8b39ce4874
--- /dev/null
+++ b/api/core/tools/provider/builtin/feishu_message/tools/send_webhook_message.yaml
@@ -0,0 +1,58 @@
+identity:
+ name: send_webhook_message
+ author: Doug Lea
+ label:
+ en_US: Send Webhook Message
+ zh_Hans: 使用自定义机器人发送飞书消息
+description:
+ human:
+ en_US: Send webhook message
+ zh_Hans: 使用自定义机器人发送飞书消息
+ llm: A tool for sending Lark messages using a custom robot.
+parameters:
+ - name: webhook
+ type: string
+ required: true
+ label:
+ en_US: webhook
+ zh_Hans: webhook 的地址
+ human_description:
+ en_US: The address of the webhook
+ zh_Hans: webhook 的地址
+ llm_description: webhook 的地址
+ form: llm
+
+ - name: msg_type
+ type: string
+ required: true
+ options:
+ - value: text
+ label:
+ en_US: text
+ zh_Hans: 文本
+ - value: interactive
+ label:
+ en_US: message card
+ zh_Hans: 消息卡片
+ label:
+ en_US: Message type
+ zh_Hans: 消息类型
+ human_description:
+ en_US: Message type, optional values are, text (text), interactive (message card).
+ zh_Hans: 消息类型,可选值有:text(文本)、interactive(消息卡片)。
+ llm_description: 消息类型,可选值有:text(文本)、interactive(消息卡片)。
+ form: llm
+
+ - name: content
+ type: string
+ required: true
+ label:
+ en_US: Message content
+ zh_Hans: 消息内容
+ human_description:
+ en_US: Message content
+ zh_Hans: |
+ 消息内容,JSON 结构序列化后的字符串。不同 msg_type 对应不同内容,
+ 具体格式说明参考:https://open.larkoffice.com/document/server-docs/im-v1/message-content-description/create_json
+ llm_description: 消息内容,JSON 结构序列化后的字符串。不同 msg_type 对应不同内容。
+ form: llm
diff --git a/api/core/tools/utils/feishu_api_utils.py b/api/core/tools/utils/feishu_api_utils.py
new file mode 100644
index 0000000000..e6b288868f
--- /dev/null
+++ b/api/core/tools/utils/feishu_api_utils.py
@@ -0,0 +1,143 @@
+import httpx
+
+from extensions.ext_redis import redis_client
+
+
+class FeishuRequest:
+ def __init__(self, app_id: str, app_secret: str):
+ self.app_id = app_id
+ self.app_secret = app_secret
+
+ @property
+ def tenant_access_token(self):
+ feishu_tenant_access_token = f"tools:{self.app_id}:feishu_tenant_access_token"
+ if redis_client.exists(feishu_tenant_access_token):
+ return redis_client.get(feishu_tenant_access_token).decode()
+ res = self.get_tenant_access_token(self.app_id, self.app_secret)
+ redis_client.setex(feishu_tenant_access_token, res.get("expire"), res.get("tenant_access_token"))
+ return res.get("tenant_access_token")
+
+ def _send_request(self, url: str, method: str = "post", require_token: bool = True, payload: dict = None,
+ params: dict = None):
+ headers = {
+ "Content-Type": "application/json",
+ "user-agent": "Dify",
+ }
+ if require_token:
+ headers["tenant-access-token"] = f"{self.tenant_access_token}"
+ res = httpx.request(method=method, url=url, headers=headers, json=payload, params=params, timeout=30).json()
+ if res.get("code") != 0:
+ raise Exception(res)
+ return res
+
+ def get_tenant_access_token(self, app_id: str, app_secret: str) -> dict:
+ """
+ API url: https://open.feishu.cn/document/server-docs/authentication-management/access-token/tenant_access_token_internal
+ Example Response:
+ {
+ "code": 0,
+ "msg": "ok",
+ "tenant_access_token": "t-caecc734c2e3328a62489fe0648c4b98779515d3",
+ "expire": 7200
+ }
+ """
+ url = "https://lark-plugin-api.solutionsuite.cn/lark-plugin/access_token/get_tenant_access_token"
+ payload = {
+ "app_id": app_id,
+ "app_secret": app_secret
+ }
+ res = self._send_request(url, require_token=False, payload=payload)
+ return res
+
+ def create_document(self, title: str, content: str, folder_token: str) -> dict:
+ """
+ API url: https://open.larkoffice.com/document/server-docs/docs/docs/docx-v1/document/create
+ Example Response:
+ {
+ "data": {
+ "title": "title",
+ "url": "https://svi136aogf123.feishu.cn/docx/VWbvd4fEdoW0WSxaY1McQTz8n7d",
+ "type": "docx",
+ "token": "VWbvd4fEdoW0WSxaY1McQTz8n7d"
+ },
+ "log_id": "021721281231575fdbddc0200ff00060a9258ec0000103df61b5d",
+ "code": 0,
+ "msg": "创建飞书文档成功,请查看"
+ }
+ """
+ url = "https://lark-plugin-api.solutionsuite.cn/lark-plugin/document/create_document"
+ payload = {
+ "title": title,
+ "content": content,
+ "folder_token": folder_token,
+ }
+ res = self._send_request(url, payload=payload)
+ return res.get("data")
+
+ def write_document(self, document_id: str, content: str, position: str = "start") -> dict:
+ url = "https://lark-plugin-api.solutionsuite.cn/lark-plugin/document/write_document"
+ payload = {
+ "document_id": document_id,
+ "content": content,
+ "position": position
+ }
+ res = self._send_request(url, payload=payload)
+ return res.get("data")
+
+ def get_document_raw_content(self, document_id: str) -> dict:
+ """
+ API url: https://open.larkoffice.com/document/server-docs/docs/docs/docx-v1/document/raw_content
+ Example Response:
+ {
+ "code": 0,
+ "msg": "success",
+ "data": {
+ "content": "云文档\n多人实时协同,插入一切元素。不仅是在线文档,更是强大的创作和互动工具\n云文档:专为协作而生\n"
+ }
+ }
+ """
+ params = {
+ "document_id": document_id,
+ }
+ url = "https://lark-plugin-api.solutionsuite.cn/lark-plugin/document/get_document_raw_content"
+ res = self._send_request(url, method="get", params=params)
+ return res.get("data").get("content")
+
+ def list_document_block(self, document_id: str, page_token: str, page_size: int = 500) -> dict:
+ """
+ API url: https://open.larkoffice.com/document/server-docs/docs/docs/docx-v1/document/list
+ """
+ url = "https://lark-plugin-api.solutionsuite.cn/lark-plugin/document/list_document_block"
+ params = {
+ "document_id": document_id,
+ "page_size": page_size,
+ "page_token": page_token,
+ }
+ res = self._send_request(url, method="get", params=params)
+ return res.get("data")
+
+ def send_bot_message(self, receive_id_type: str, receive_id: str, msg_type: str, content: str) -> dict:
+ """
+ API url: https://open.larkoffice.com/document/server-docs/im-v1/message/create
+ """
+ url = "https://lark-plugin-api.solutionsuite.cn/lark-plugin/message/send_bot_message"
+ params = {
+ "receive_id_type": receive_id_type,
+ }
+ payload = {
+ "receive_id": receive_id,
+ "msg_type": msg_type,
+ "content": content,
+ }
+ res = self._send_request(url, params=params, payload=payload)
+ return res.get("data")
+
+ def send_webhook_message(self, webhook: str, msg_type: str, content: str) -> dict:
+ url = "https://lark-plugin-api.solutionsuite.cn/lark-plugin/message/send_webhook_message"
+ payload = {
+ "webhook": webhook,
+ "msg_type": msg_type,
+ "content": content,
+ }
+ res = self._send_request(url, require_token=False, payload=payload)
+ return res