AstrBot 4.5.1__py3-none-any.whl → 4.5.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- astrbot/api/__init__.py +10 -11
- astrbot/api/event/__init__.py +5 -6
- astrbot/api/event/filter/__init__.py +37 -36
- astrbot/api/platform/__init__.py +7 -8
- astrbot/api/provider/__init__.py +7 -7
- astrbot/api/star/__init__.py +3 -4
- astrbot/api/util/__init__.py +2 -2
- astrbot/cli/__main__.py +5 -5
- astrbot/cli/commands/__init__.py +3 -3
- astrbot/cli/commands/cmd_conf.py +19 -16
- astrbot/cli/commands/cmd_init.py +3 -2
- astrbot/cli/commands/cmd_plug.py +8 -10
- astrbot/cli/commands/cmd_run.py +5 -6
- astrbot/cli/utils/__init__.py +6 -6
- astrbot/cli/utils/basic.py +14 -14
- astrbot/cli/utils/plugin.py +24 -15
- astrbot/cli/utils/version_comparator.py +10 -12
- astrbot/core/__init__.py +8 -6
- astrbot/core/agent/agent.py +3 -2
- astrbot/core/agent/handoff.py +6 -2
- astrbot/core/agent/hooks.py +9 -6
- astrbot/core/agent/mcp_client.py +50 -15
- astrbot/core/agent/message.py +168 -0
- astrbot/core/agent/response.py +2 -1
- astrbot/core/agent/run_context.py +2 -3
- astrbot/core/agent/runners/base.py +10 -13
- astrbot/core/agent/runners/tool_loop_agent_runner.py +52 -51
- astrbot/core/agent/tool.py +60 -41
- astrbot/core/agent/tool_executor.py +9 -3
- astrbot/core/astr_agent_context.py +3 -1
- astrbot/core/astrbot_config_mgr.py +29 -9
- astrbot/core/config/__init__.py +2 -2
- astrbot/core/config/astrbot_config.py +28 -26
- astrbot/core/config/default.py +4 -6
- astrbot/core/conversation_mgr.py +105 -36
- astrbot/core/core_lifecycle.py +68 -54
- astrbot/core/db/__init__.py +33 -18
- astrbot/core/db/migration/helper.py +12 -10
- astrbot/core/db/migration/migra_3_to_4.py +53 -34
- astrbot/core/db/migration/migra_45_to_46.py +1 -1
- astrbot/core/db/migration/shared_preferences_v3.py +2 -1
- astrbot/core/db/migration/sqlite_v3.py +26 -23
- astrbot/core/db/po.py +27 -18
- astrbot/core/db/sqlite.py +74 -45
- astrbot/core/db/vec_db/base.py +10 -14
- astrbot/core/db/vec_db/faiss_impl/document_storage.py +90 -77
- astrbot/core/db/vec_db/faiss_impl/embedding_storage.py +9 -3
- astrbot/core/db/vec_db/faiss_impl/vec_db.py +36 -31
- astrbot/core/event_bus.py +8 -6
- astrbot/core/file_token_service.py +6 -5
- astrbot/core/initial_loader.py +7 -5
- astrbot/core/knowledge_base/chunking/__init__.py +1 -3
- astrbot/core/knowledge_base/chunking/base.py +1 -0
- astrbot/core/knowledge_base/chunking/fixed_size.py +2 -0
- astrbot/core/knowledge_base/chunking/recursive.py +16 -10
- astrbot/core/knowledge_base/kb_db_sqlite.py +50 -48
- astrbot/core/knowledge_base/kb_helper.py +30 -17
- astrbot/core/knowledge_base/kb_mgr.py +6 -7
- astrbot/core/knowledge_base/models.py +10 -4
- astrbot/core/knowledge_base/parsers/__init__.py +3 -5
- astrbot/core/knowledge_base/parsers/base.py +1 -0
- astrbot/core/knowledge_base/parsers/markitdown_parser.py +2 -1
- astrbot/core/knowledge_base/parsers/pdf_parser.py +2 -1
- astrbot/core/knowledge_base/parsers/text_parser.py +1 -0
- astrbot/core/knowledge_base/parsers/util.py +1 -1
- astrbot/core/knowledge_base/retrieval/__init__.py +6 -8
- astrbot/core/knowledge_base/retrieval/manager.py +17 -14
- astrbot/core/knowledge_base/retrieval/rank_fusion.py +7 -3
- astrbot/core/knowledge_base/retrieval/sparse_retriever.py +11 -5
- astrbot/core/log.py +21 -13
- astrbot/core/message/components.py +123 -217
- astrbot/core/message/message_event_result.py +24 -24
- astrbot/core/persona_mgr.py +20 -11
- astrbot/core/pipeline/__init__.py +7 -7
- astrbot/core/pipeline/content_safety_check/stage.py +13 -9
- astrbot/core/pipeline/content_safety_check/strategies/__init__.py +1 -2
- astrbot/core/pipeline/content_safety_check/strategies/baidu_aip.py +12 -13
- astrbot/core/pipeline/content_safety_check/strategies/keywords.py +1 -0
- astrbot/core/pipeline/content_safety_check/strategies/strategy.py +6 -6
- astrbot/core/pipeline/context.py +4 -1
- astrbot/core/pipeline/context_utils.py +77 -7
- astrbot/core/pipeline/preprocess_stage/stage.py +12 -9
- astrbot/core/pipeline/process_stage/method/llm_request.py +125 -72
- astrbot/core/pipeline/process_stage/method/star_request.py +19 -17
- astrbot/core/pipeline/process_stage/stage.py +13 -10
- astrbot/core/pipeline/process_stage/utils.py +6 -5
- astrbot/core/pipeline/rate_limit_check/stage.py +37 -36
- astrbot/core/pipeline/respond/stage.py +23 -20
- astrbot/core/pipeline/result_decorate/stage.py +31 -23
- astrbot/core/pipeline/scheduler.py +12 -8
- astrbot/core/pipeline/session_status_check/stage.py +12 -8
- astrbot/core/pipeline/stage.py +10 -4
- astrbot/core/pipeline/waking_check/stage.py +24 -18
- astrbot/core/pipeline/whitelist_check/stage.py +10 -7
- astrbot/core/platform/__init__.py +6 -6
- astrbot/core/platform/astr_message_event.py +76 -110
- astrbot/core/platform/astrbot_message.py +11 -13
- astrbot/core/platform/manager.py +16 -15
- astrbot/core/platform/message_session.py +5 -3
- astrbot/core/platform/platform.py +16 -24
- astrbot/core/platform/platform_metadata.py +4 -4
- astrbot/core/platform/register.py +8 -8
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +23 -15
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +51 -33
- astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +42 -27
- astrbot/core/platform/sources/dingtalk/dingtalk_event.py +7 -3
- astrbot/core/platform/sources/discord/client.py +9 -6
- astrbot/core/platform/sources/discord/components.py +18 -14
- astrbot/core/platform/sources/discord/discord_platform_adapter.py +45 -30
- astrbot/core/platform/sources/discord/discord_platform_event.py +38 -30
- astrbot/core/platform/sources/lark/lark_adapter.py +23 -17
- astrbot/core/platform/sources/lark/lark_event.py +21 -14
- astrbot/core/platform/sources/misskey/misskey_adapter.py +107 -67
- astrbot/core/platform/sources/misskey/misskey_api.py +153 -129
- astrbot/core/platform/sources/misskey/misskey_event.py +20 -15
- astrbot/core/platform/sources/misskey/misskey_utils.py +74 -62
- astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +63 -44
- astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +41 -26
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +36 -17
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_event.py +3 -1
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_server.py +12 -7
- astrbot/core/platform/sources/satori/satori_adapter.py +56 -38
- astrbot/core/platform/sources/satori/satori_event.py +34 -25
- astrbot/core/platform/sources/slack/client.py +11 -9
- astrbot/core/platform/sources/slack/slack_adapter.py +52 -36
- astrbot/core/platform/sources/slack/slack_event.py +34 -24
- astrbot/core/platform/sources/telegram/tg_adapter.py +38 -18
- astrbot/core/platform/sources/telegram/tg_event.py +32 -18
- astrbot/core/platform/sources/webchat/webchat_adapter.py +27 -17
- astrbot/core/platform/sources/webchat/webchat_event.py +14 -10
- astrbot/core/platform/sources/wechatpadpro/wechatpadpro_adapter.py +115 -120
- astrbot/core/platform/sources/wechatpadpro/wechatpadpro_message_event.py +9 -8
- astrbot/core/platform/sources/wechatpadpro/xml_data_parser.py +15 -16
- astrbot/core/platform/sources/wecom/wecom_adapter.py +35 -18
- astrbot/core/platform/sources/wecom/wecom_event.py +55 -48
- astrbot/core/platform/sources/wecom/wecom_kf.py +34 -44
- astrbot/core/platform/sources/wecom/wecom_kf_message.py +26 -10
- astrbot/core/platform/sources/wecom_ai_bot/WXBizJsonMsgCrypt.py +18 -10
- astrbot/core/platform/sources/wecom_ai_bot/__init__.py +3 -5
- astrbot/core/platform/sources/wecom_ai_bot/ierror.py +0 -1
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_adapter.py +61 -37
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_api.py +67 -28
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_event.py +8 -9
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_queue_mgr.py +18 -9
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_server.py +14 -12
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_utils.py +22 -12
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +40 -26
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py +47 -45
- astrbot/core/platform_message_history_mgr.py +5 -3
- astrbot/core/provider/__init__.py +2 -3
- astrbot/core/provider/entites.py +8 -8
- astrbot/core/provider/entities.py +61 -75
- astrbot/core/provider/func_tool_manager.py +59 -55
- astrbot/core/provider/manager.py +32 -22
- astrbot/core/provider/provider.py +72 -46
- astrbot/core/provider/register.py +7 -7
- astrbot/core/provider/sources/anthropic_source.py +48 -30
- astrbot/core/provider/sources/azure_tts_source.py +17 -13
- astrbot/core/provider/sources/coze_api_client.py +27 -17
- astrbot/core/provider/sources/coze_source.py +104 -87
- astrbot/core/provider/sources/dashscope_source.py +18 -11
- astrbot/core/provider/sources/dashscope_tts.py +36 -23
- astrbot/core/provider/sources/dify_source.py +25 -20
- astrbot/core/provider/sources/edge_tts_source.py +21 -17
- astrbot/core/provider/sources/fishaudio_tts_api_source.py +22 -14
- astrbot/core/provider/sources/gemini_embedding_source.py +12 -13
- astrbot/core/provider/sources/gemini_source.py +72 -58
- astrbot/core/provider/sources/gemini_tts_source.py +8 -6
- astrbot/core/provider/sources/gsv_selfhosted_source.py +17 -14
- astrbot/core/provider/sources/gsvi_tts_source.py +11 -7
- astrbot/core/provider/sources/minimax_tts_api_source.py +50 -40
- astrbot/core/provider/sources/openai_embedding_source.py +6 -8
- astrbot/core/provider/sources/openai_source.py +77 -69
- astrbot/core/provider/sources/openai_tts_api_source.py +14 -6
- astrbot/core/provider/sources/sensevoice_selfhosted_source.py +13 -11
- astrbot/core/provider/sources/vllm_rerank_source.py +10 -4
- astrbot/core/provider/sources/volcengine_tts.py +38 -31
- astrbot/core/provider/sources/whisper_api_source.py +14 -12
- astrbot/core/provider/sources/whisper_selfhosted_source.py +15 -11
- astrbot/core/provider/sources/xinference_rerank_source.py +16 -8
- astrbot/core/provider/sources/xinference_stt_provider.py +35 -25
- astrbot/core/star/__init__.py +16 -11
- astrbot/core/star/config.py +10 -15
- astrbot/core/star/context.py +97 -75
- astrbot/core/star/filter/__init__.py +4 -3
- astrbot/core/star/filter/command.py +30 -28
- astrbot/core/star/filter/command_group.py +27 -24
- astrbot/core/star/filter/custom_filter.py +6 -5
- astrbot/core/star/filter/event_message_type.py +4 -2
- astrbot/core/star/filter/permission.py +4 -2
- astrbot/core/star/filter/platform_adapter_type.py +4 -2
- astrbot/core/star/filter/regex.py +4 -2
- astrbot/core/star/register/__init__.py +19 -19
- astrbot/core/star/register/star.py +6 -2
- astrbot/core/star/register/star_handler.py +96 -73
- astrbot/core/star/session_llm_manager.py +48 -14
- astrbot/core/star/session_plugin_manager.py +29 -15
- astrbot/core/star/star.py +1 -2
- astrbot/core/star/star_handler.py +13 -8
- astrbot/core/star/star_manager.py +151 -59
- astrbot/core/star/star_tools.py +44 -37
- astrbot/core/star/updator.py +10 -10
- astrbot/core/umop_config_router.py +10 -4
- astrbot/core/updator.py +13 -5
- astrbot/core/utils/astrbot_path.py +3 -5
- astrbot/core/utils/dify_api_client.py +33 -15
- astrbot/core/utils/io.py +66 -42
- astrbot/core/utils/log_pipe.py +1 -1
- astrbot/core/utils/metrics.py +7 -7
- astrbot/core/utils/path_util.py +15 -16
- astrbot/core/utils/pip_installer.py +5 -5
- astrbot/core/utils/session_waiter.py +19 -20
- astrbot/core/utils/shared_preferences.py +45 -20
- astrbot/core/utils/t2i/__init__.py +4 -1
- astrbot/core/utils/t2i/network_strategy.py +35 -26
- astrbot/core/utils/t2i/renderer.py +11 -5
- astrbot/core/utils/t2i/template_manager.py +14 -15
- astrbot/core/utils/tencent_record_helper.py +19 -13
- astrbot/core/utils/version_comparator.py +10 -13
- astrbot/core/zip_updator.py +43 -40
- astrbot/dashboard/routes/__init__.py +18 -18
- astrbot/dashboard/routes/auth.py +10 -8
- astrbot/dashboard/routes/chat.py +30 -21
- astrbot/dashboard/routes/config.py +92 -75
- astrbot/dashboard/routes/conversation.py +46 -39
- astrbot/dashboard/routes/file.py +4 -2
- astrbot/dashboard/routes/knowledge_base.py +47 -40
- astrbot/dashboard/routes/log.py +9 -4
- astrbot/dashboard/routes/persona.py +19 -16
- astrbot/dashboard/routes/plugin.py +69 -55
- astrbot/dashboard/routes/route.py +3 -1
- astrbot/dashboard/routes/session_management.py +130 -116
- astrbot/dashboard/routes/stat.py +34 -34
- astrbot/dashboard/routes/t2i.py +15 -12
- astrbot/dashboard/routes/tools.py +56 -53
- astrbot/dashboard/routes/update.py +32 -28
- astrbot/dashboard/server.py +30 -26
- astrbot/dashboard/utils.py +8 -4
- {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/METADATA +2 -1
- astrbot-4.5.3.dist-info/RECORD +261 -0
- astrbot-4.5.1.dist-info/RECORD +0 -260
- {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/WHEEL +0 -0
- {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/entry_points.txt +0 -0
- {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
The MIT License (MIT)
|
|
1
|
+
"""The MIT License (MIT)
|
|
3
2
|
|
|
4
3
|
Copyright (c) 2014-2020 messense
|
|
5
4
|
|
|
@@ -23,13 +22,11 @@ SOFTWARE.
|
|
|
23
22
|
"""
|
|
24
23
|
|
|
25
24
|
from optionaldict import optionaldict
|
|
26
|
-
|
|
27
25
|
from wechatpy.client.api.base import BaseWeChatAPI
|
|
28
26
|
|
|
29
27
|
|
|
30
28
|
class WeChatKFMessage(BaseWeChatAPI):
|
|
31
|
-
"""
|
|
32
|
-
发送微信客服消息
|
|
29
|
+
"""发送微信客服消息
|
|
33
30
|
|
|
34
31
|
https://work.weixin.qq.com/api/doc/90000/90135/94677
|
|
35
32
|
|
|
@@ -46,8 +43,7 @@ class WeChatKFMessage(BaseWeChatAPI):
|
|
|
46
43
|
"""
|
|
47
44
|
|
|
48
45
|
def send(self, user_id, open_kfid, msgid="", msg=None):
|
|
49
|
-
"""
|
|
50
|
-
当微信客户处于“新接入待处理”或“由智能助手接待”状态下,可调用该接口给用户发送消息。
|
|
46
|
+
"""当微信客户处于“新接入待处理”或“由智能助手接待”状态下,可调用该接口给用户发送消息。
|
|
51
47
|
注意仅当微信客户在主动发送消息给客服后的48小时内,企业可发送消息给客户,最多可发送5条消息;若用户继续发送消息,企业可再次下发消息。
|
|
52
48
|
支持发送消息类型:文本、图片、语音、视频、文件、图文、小程序、菜单消息、地理位置。
|
|
53
49
|
|
|
@@ -127,7 +123,13 @@ class WeChatKFMessage(BaseWeChatAPI):
|
|
|
127
123
|
)
|
|
128
124
|
|
|
129
125
|
def send_msgmenu(
|
|
130
|
-
self,
|
|
126
|
+
self,
|
|
127
|
+
user_id,
|
|
128
|
+
open_kfid,
|
|
129
|
+
head_content,
|
|
130
|
+
menu_list,
|
|
131
|
+
tail_content,
|
|
132
|
+
msgid="",
|
|
131
133
|
):
|
|
132
134
|
return self.send(
|
|
133
135
|
user_id,
|
|
@@ -144,7 +146,14 @@ class WeChatKFMessage(BaseWeChatAPI):
|
|
|
144
146
|
)
|
|
145
147
|
|
|
146
148
|
def send_location(
|
|
147
|
-
self,
|
|
149
|
+
self,
|
|
150
|
+
user_id,
|
|
151
|
+
open_kfid,
|
|
152
|
+
name,
|
|
153
|
+
address,
|
|
154
|
+
latitude,
|
|
155
|
+
longitude,
|
|
156
|
+
msgid="",
|
|
148
157
|
):
|
|
149
158
|
return self.send(
|
|
150
159
|
user_id,
|
|
@@ -162,7 +171,14 @@ class WeChatKFMessage(BaseWeChatAPI):
|
|
|
162
171
|
)
|
|
163
172
|
|
|
164
173
|
def send_miniprogram(
|
|
165
|
-
self,
|
|
174
|
+
self,
|
|
175
|
+
user_id,
|
|
176
|
+
open_kfid,
|
|
177
|
+
appid,
|
|
178
|
+
title,
|
|
179
|
+
thumb_media_id,
|
|
180
|
+
pagepath,
|
|
181
|
+
msgid="",
|
|
166
182
|
):
|
|
167
183
|
return self.send(
|
|
168
184
|
user_id,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
|
-
# -*- encoding:utf-8 -*-
|
|
3
2
|
|
|
4
3
|
"""对企业微信发送给企业后台的消息加解密示例代码.
|
|
5
4
|
@copyright: Copyright (c) 1998-2020 Tencent Inc.
|
|
@@ -7,15 +6,16 @@
|
|
|
7
6
|
"""
|
|
8
7
|
# ------------------------------------------------------------------------
|
|
9
8
|
|
|
10
|
-
import logging
|
|
11
9
|
import base64
|
|
12
|
-
import random
|
|
13
10
|
import hashlib
|
|
14
|
-
import
|
|
11
|
+
import json
|
|
12
|
+
import logging
|
|
13
|
+
import secrets
|
|
14
|
+
import socket
|
|
15
15
|
import struct
|
|
16
|
+
import time
|
|
17
|
+
|
|
16
18
|
from Crypto.Cipher import AES
|
|
17
|
-
import socket
|
|
18
|
-
import json
|
|
19
19
|
|
|
20
20
|
from . import ierror
|
|
21
21
|
|
|
@@ -31,7 +31,7 @@ class FormatException(Exception):
|
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
def throw_exception(message, exception_class=FormatException):
|
|
34
|
-
"""
|
|
34
|
+
"""My define raise exception function"""
|
|
35
35
|
raise exception_class(message)
|
|
36
36
|
|
|
37
37
|
|
|
@@ -136,9 +136,15 @@ class PKCS7Encoder:
|
|
|
136
136
|
return decrypted[:-pad]
|
|
137
137
|
|
|
138
138
|
|
|
139
|
-
class Prpcrypt
|
|
139
|
+
class Prpcrypt:
|
|
140
140
|
"""提供接收和推送给企业微信消息的加解密接口"""
|
|
141
141
|
|
|
142
|
+
# 16位随机字符串的范围常量
|
|
143
|
+
# randbelow(RANDOM_RANGE) 返回 [0, 8999999999999999](两端都包含,即包含0和8999999999999999)
|
|
144
|
+
# 加上 MIN_RANDOM_VALUE 后得到 [1000000000000000, 9999999999999999](两端都包含)即16位数字
|
|
145
|
+
MIN_RANDOM_VALUE = 1000000000000000 # 最小值: 1000000000000000 (16位)
|
|
146
|
+
RANDOM_RANGE = 9000000000000000 # 范围大小: 确保最大值为 9999999999999999 (16位)
|
|
147
|
+
|
|
142
148
|
def __init__(self, key):
|
|
143
149
|
# self.key = base64.b64decode(key+"=")
|
|
144
150
|
self.key = key
|
|
@@ -207,10 +213,12 @@ class Prpcrypt(object):
|
|
|
207
213
|
"""随机生成16位字符串
|
|
208
214
|
@return: 16位字符串
|
|
209
215
|
"""
|
|
210
|
-
return str(
|
|
216
|
+
return str(
|
|
217
|
+
secrets.randbelow(self.RANDOM_RANGE) + self.MIN_RANDOM_VALUE
|
|
218
|
+
).encode()
|
|
211
219
|
|
|
212
220
|
|
|
213
|
-
class WXBizJsonMsgCrypt
|
|
221
|
+
class WXBizJsonMsgCrypt:
|
|
214
222
|
# 构造函数
|
|
215
223
|
def __init__(self, sToken, sEncodingAESKey, sReceiveId):
|
|
216
224
|
try:
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
"""
|
|
2
|
-
企业微信智能机器人平台适配器包
|
|
3
|
-
"""
|
|
1
|
+
"""企业微信智能机器人平台适配器包"""
|
|
4
2
|
|
|
5
3
|
from .wecomai_adapter import WecomAIBotAdapter
|
|
6
4
|
from .wecomai_api import WecomAIBotAPIClient
|
|
@@ -9,9 +7,9 @@ from .wecomai_server import WecomAIBotServer
|
|
|
9
7
|
from .wecomai_utils import WecomAIBotConstants
|
|
10
8
|
|
|
11
9
|
__all__ = [
|
|
12
|
-
"WecomAIBotAdapter",
|
|
13
10
|
"WecomAIBotAPIClient",
|
|
11
|
+
"WecomAIBotAdapter",
|
|
12
|
+
"WecomAIBotConstants",
|
|
14
13
|
"WecomAIBotMessageEvent",
|
|
15
14
|
"WecomAIBotServer",
|
|
16
|
-
"WecomAIBotConstants",
|
|
17
15
|
]
|
|
@@ -1,38 +1,37 @@
|
|
|
1
|
-
"""
|
|
2
|
-
企业微信智能机器人平台适配器
|
|
1
|
+
"""企业微信智能机器人平台适配器
|
|
3
2
|
基于企业微信智能机器人 API 的消息平台适配器,支持 HTTP 回调
|
|
4
3
|
参考webchat_adapter.py的队列机制,实现异步消息处理和流式响应
|
|
5
4
|
"""
|
|
6
5
|
|
|
7
|
-
import time
|
|
8
6
|
import asyncio
|
|
9
|
-
import uuid
|
|
10
|
-
import hashlib
|
|
11
7
|
import base64
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
import hashlib
|
|
9
|
+
import time
|
|
10
|
+
import uuid
|
|
11
|
+
from collections.abc import Awaitable, Callable
|
|
12
|
+
from typing import Any
|
|
14
13
|
|
|
14
|
+
from astrbot.api import logger
|
|
15
|
+
from astrbot.api.event import MessageChain
|
|
16
|
+
from astrbot.api.message_components import At, Image, Plain
|
|
15
17
|
from astrbot.api.platform import (
|
|
16
|
-
Platform,
|
|
17
18
|
AstrBotMessage,
|
|
18
19
|
MessageMember,
|
|
19
20
|
MessageType,
|
|
21
|
+
Platform,
|
|
20
22
|
PlatformMetadata,
|
|
21
23
|
)
|
|
22
|
-
from astrbot.api.event import MessageChain
|
|
23
|
-
from astrbot.api.message_components import Plain, At, Image
|
|
24
|
-
from astrbot.api import logger
|
|
25
24
|
from astrbot.core.platform.astr_message_event import MessageSesion
|
|
26
|
-
from ...register import register_platform_adapter
|
|
27
25
|
|
|
26
|
+
from ...register import register_platform_adapter
|
|
28
27
|
from .wecomai_api import (
|
|
29
28
|
WecomAIBotAPIClient,
|
|
30
29
|
WecomAIBotMessageParser,
|
|
31
30
|
WecomAIBotStreamMessageBuilder,
|
|
32
31
|
)
|
|
33
32
|
from .wecomai_event import WecomAIBotMessageEvent
|
|
33
|
+
from .wecomai_queue_mgr import WecomAIQueueMgr, wecomai_queue_mgr
|
|
34
34
|
from .wecomai_server import WecomAIBotServer
|
|
35
|
-
from .wecomai_queue_mgr import wecomai_queue_mgr, WecomAIQueueMgr
|
|
36
35
|
from .wecomai_utils import (
|
|
37
36
|
WecomAIBotConstants,
|
|
38
37
|
format_session_id,
|
|
@@ -45,7 +44,9 @@ class WecomAIQueueListener:
|
|
|
45
44
|
"""企业微信智能机器人队列监听器,参考webchat的QueueListener设计"""
|
|
46
45
|
|
|
47
46
|
def __init__(
|
|
48
|
-
self,
|
|
47
|
+
self,
|
|
48
|
+
queue_mgr: WecomAIQueueMgr,
|
|
49
|
+
callback: Callable[[dict], Awaitable[None]],
|
|
49
50
|
) -> None:
|
|
50
51
|
self.queue_mgr = queue_mgr
|
|
51
52
|
self.callback = callback
|
|
@@ -90,13 +91,17 @@ class WecomAIQueueListener:
|
|
|
90
91
|
|
|
91
92
|
|
|
92
93
|
@register_platform_adapter(
|
|
93
|
-
"wecom_ai_bot",
|
|
94
|
+
"wecom_ai_bot",
|
|
95
|
+
"企业微信智能机器人适配器,支持 HTTP 回调接收消息",
|
|
94
96
|
)
|
|
95
97
|
class WecomAIBotAdapter(Platform):
|
|
96
98
|
"""企业微信智能机器人适配器"""
|
|
97
99
|
|
|
98
100
|
def __init__(
|
|
99
|
-
self,
|
|
101
|
+
self,
|
|
102
|
+
platform_config: dict,
|
|
103
|
+
platform_settings: dict,
|
|
104
|
+
event_queue: asyncio.Queue,
|
|
100
105
|
) -> None:
|
|
101
106
|
super().__init__(event_queue)
|
|
102
107
|
|
|
@@ -110,10 +115,12 @@ class WecomAIBotAdapter(Platform):
|
|
|
110
115
|
self.host = self.config.get("callback_server_host", "0.0.0.0")
|
|
111
116
|
self.bot_name = self.config.get("wecom_ai_bot_name", "")
|
|
112
117
|
self.initial_respond_text = self.config.get(
|
|
113
|
-
"wecomaibot_init_respond_text",
|
|
118
|
+
"wecomaibot_init_respond_text",
|
|
119
|
+
"💭 思考中...",
|
|
114
120
|
)
|
|
115
121
|
self.friend_message_welcome_text = self.config.get(
|
|
116
|
-
"wecomaibot_friend_message_welcome_text",
|
|
122
|
+
"wecomaibot_friend_message_welcome_text",
|
|
123
|
+
"",
|
|
117
124
|
)
|
|
118
125
|
|
|
119
126
|
# 平台元数据
|
|
@@ -139,7 +146,8 @@ class WecomAIBotAdapter(Platform):
|
|
|
139
146
|
|
|
140
147
|
# 队列监听器
|
|
141
148
|
self.queue_listener = WecomAIQueueListener(
|
|
142
|
-
wecomai_queue_mgr,
|
|
149
|
+
wecomai_queue_mgr,
|
|
150
|
+
self._handle_queued_message,
|
|
143
151
|
)
|
|
144
152
|
|
|
145
153
|
async def _handle_queued_message(self, data: dict):
|
|
@@ -151,8 +159,10 @@ class WecomAIBotAdapter(Platform):
|
|
|
151
159
|
logger.error(f"处理队列消息时发生异常: {e}")
|
|
152
160
|
|
|
153
161
|
async def _process_message(
|
|
154
|
-
self,
|
|
155
|
-
|
|
162
|
+
self,
|
|
163
|
+
message_data: dict[str, Any],
|
|
164
|
+
callback_params: dict[str, str],
|
|
165
|
+
) -> str | None:
|
|
156
166
|
"""处理接收到的消息
|
|
157
167
|
|
|
158
168
|
Args:
|
|
@@ -161,6 +171,7 @@ class WecomAIBotAdapter(Platform):
|
|
|
161
171
|
|
|
162
172
|
Returns:
|
|
163
173
|
加密后的响应消息,无需响应时返回 None
|
|
174
|
+
|
|
164
175
|
"""
|
|
165
176
|
msgtype = message_data.get("msgtype")
|
|
166
177
|
if not msgtype:
|
|
@@ -173,15 +184,22 @@ class WecomAIBotAdapter(Platform):
|
|
|
173
184
|
# create a brand-new unique stream_id for this message session
|
|
174
185
|
stream_id = f"{session_id}_{generate_random_string(10)}"
|
|
175
186
|
await self._enqueue_message(
|
|
176
|
-
message_data,
|
|
187
|
+
message_data,
|
|
188
|
+
callback_params,
|
|
189
|
+
stream_id,
|
|
190
|
+
session_id,
|
|
177
191
|
)
|
|
178
192
|
wecomai_queue_mgr.set_pending_response(stream_id, callback_params)
|
|
179
193
|
|
|
180
194
|
resp = WecomAIBotStreamMessageBuilder.make_text_stream(
|
|
181
|
-
stream_id,
|
|
195
|
+
stream_id,
|
|
196
|
+
self.initial_respond_text,
|
|
197
|
+
False,
|
|
182
198
|
)
|
|
183
199
|
return await self.api_client.encrypt_message(
|
|
184
|
-
resp,
|
|
200
|
+
resp,
|
|
201
|
+
callback_params["nonce"],
|
|
202
|
+
callback_params["timestamp"],
|
|
185
203
|
)
|
|
186
204
|
except Exception as e:
|
|
187
205
|
logger.error("处理消息时发生异常: %s", e)
|
|
@@ -194,7 +212,9 @@ class WecomAIBotAdapter(Platform):
|
|
|
194
212
|
|
|
195
213
|
# 返回结束标志,告诉微信服务器流已结束
|
|
196
214
|
end_message = WecomAIBotStreamMessageBuilder.make_text_stream(
|
|
197
|
-
stream_id,
|
|
215
|
+
stream_id,
|
|
216
|
+
"",
|
|
217
|
+
True,
|
|
198
218
|
)
|
|
199
219
|
resp = await self.api_client.encrypt_message(
|
|
200
220
|
end_message,
|
|
@@ -205,7 +225,7 @@ class WecomAIBotAdapter(Platform):
|
|
|
205
225
|
queue = wecomai_queue_mgr.get_or_create_back_queue(stream_id)
|
|
206
226
|
if queue.empty():
|
|
207
227
|
logger.debug(
|
|
208
|
-
f"No new messages in back queue for stream_id: {stream_id}"
|
|
228
|
+
f"No new messages in back queue for stream_id: {stream_id}",
|
|
209
229
|
)
|
|
210
230
|
return None
|
|
211
231
|
|
|
@@ -227,7 +247,7 @@ class WecomAIBotAdapter(Platform):
|
|
|
227
247
|
else:
|
|
228
248
|
pass
|
|
229
249
|
logger.debug(
|
|
230
|
-
f"Aggregated content: {latest_plain_content}, image: {len(image_base64)}, finish: {finish}"
|
|
250
|
+
f"Aggregated content: {latest_plain_content}, image: {len(image_base64)}, finish: {finish}",
|
|
231
251
|
)
|
|
232
252
|
if latest_plain_content or image_base64:
|
|
233
253
|
msg_items = []
|
|
@@ -240,12 +260,15 @@ class WecomAIBotAdapter(Platform):
|
|
|
240
260
|
{
|
|
241
261
|
"msgtype": WecomAIBotConstants.MSG_TYPE_IMAGE,
|
|
242
262
|
"image": {"base64": img_b64, "md5": img_md5},
|
|
243
|
-
}
|
|
263
|
+
},
|
|
244
264
|
)
|
|
245
265
|
image_base64 = []
|
|
246
266
|
|
|
247
267
|
plain_message = WecomAIBotStreamMessageBuilder.make_mixed_stream(
|
|
248
|
-
stream_id,
|
|
268
|
+
stream_id,
|
|
269
|
+
latest_plain_content,
|
|
270
|
+
msg_items,
|
|
271
|
+
finish,
|
|
249
272
|
)
|
|
250
273
|
encrypted_message = await self.api_client.encrypt_message(
|
|
251
274
|
plain_message,
|
|
@@ -254,7 +277,7 @@ class WecomAIBotAdapter(Platform):
|
|
|
254
277
|
)
|
|
255
278
|
if encrypted_message:
|
|
256
279
|
logger.debug(
|
|
257
|
-
f"Stream message sent successfully, stream_id: {stream_id}"
|
|
280
|
+
f"Stream message sent successfully, stream_id: {stream_id}",
|
|
258
281
|
)
|
|
259
282
|
else:
|
|
260
283
|
logger.error("消息加密失败")
|
|
@@ -266,7 +289,7 @@ class WecomAIBotAdapter(Platform):
|
|
|
266
289
|
# 用户进入会话,发送欢迎消息
|
|
267
290
|
try:
|
|
268
291
|
resp = WecomAIBotStreamMessageBuilder.make_text(
|
|
269
|
-
self.friend_message_welcome_text
|
|
292
|
+
self.friend_message_welcome_text,
|
|
270
293
|
)
|
|
271
294
|
return await self.api_client.encrypt_message(
|
|
272
295
|
resp,
|
|
@@ -276,17 +299,16 @@ class WecomAIBotAdapter(Platform):
|
|
|
276
299
|
except Exception as e:
|
|
277
300
|
logger.error("处理欢迎消息时发生异常: %s", e)
|
|
278
301
|
return None
|
|
279
|
-
pass
|
|
280
302
|
|
|
281
|
-
def _extract_session_id(self, message_data:
|
|
303
|
+
def _extract_session_id(self, message_data: dict[str, Any]) -> str:
|
|
282
304
|
"""从消息数据中提取会话ID"""
|
|
283
305
|
user_id = message_data.get("from", {}).get("userid", "default_user")
|
|
284
306
|
return format_session_id("wecomai", user_id)
|
|
285
307
|
|
|
286
308
|
async def _enqueue_message(
|
|
287
309
|
self,
|
|
288
|
-
message_data:
|
|
289
|
-
callback_params:
|
|
310
|
+
message_data: dict[str, Any],
|
|
311
|
+
callback_params: dict[str, str],
|
|
290
312
|
stream_id: str,
|
|
291
313
|
session_id: str,
|
|
292
314
|
):
|
|
@@ -320,7 +342,7 @@ class WecomAIBotAdapter(Platform):
|
|
|
320
342
|
content = WecomAIBotMessageParser.parse_text_message(message_data)
|
|
321
343
|
elif msgtype == WecomAIBotConstants.MSG_TYPE_IMAGE:
|
|
322
344
|
_img_url_to_process.append(
|
|
323
|
-
WecomAIBotMessageParser.parse_image_message(message_data)
|
|
345
|
+
WecomAIBotMessageParser.parse_image_message(message_data),
|
|
324
346
|
)
|
|
325
347
|
elif msgtype == WecomAIBotConstants.MSG_TYPE_MIXED:
|
|
326
348
|
# 提取混合消息中的文本内容
|
|
@@ -390,7 +412,9 @@ class WecomAIBotAdapter(Platform):
|
|
|
390
412
|
return abm
|
|
391
413
|
|
|
392
414
|
async def send_by_session(
|
|
393
|
-
self,
|
|
415
|
+
self,
|
|
416
|
+
session: MessageSesion,
|
|
417
|
+
message_chain: MessageChain,
|
|
394
418
|
):
|
|
395
419
|
"""通过会话发送消息"""
|
|
396
420
|
# 企业微信智能机器人主要通过回调响应,这里记录日志
|