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.
Files changed (244) hide show
  1. astrbot/api/__init__.py +10 -11
  2. astrbot/api/event/__init__.py +5 -6
  3. astrbot/api/event/filter/__init__.py +37 -36
  4. astrbot/api/platform/__init__.py +7 -8
  5. astrbot/api/provider/__init__.py +7 -7
  6. astrbot/api/star/__init__.py +3 -4
  7. astrbot/api/util/__init__.py +2 -2
  8. astrbot/cli/__main__.py +5 -5
  9. astrbot/cli/commands/__init__.py +3 -3
  10. astrbot/cli/commands/cmd_conf.py +19 -16
  11. astrbot/cli/commands/cmd_init.py +3 -2
  12. astrbot/cli/commands/cmd_plug.py +8 -10
  13. astrbot/cli/commands/cmd_run.py +5 -6
  14. astrbot/cli/utils/__init__.py +6 -6
  15. astrbot/cli/utils/basic.py +14 -14
  16. astrbot/cli/utils/plugin.py +24 -15
  17. astrbot/cli/utils/version_comparator.py +10 -12
  18. astrbot/core/__init__.py +8 -6
  19. astrbot/core/agent/agent.py +3 -2
  20. astrbot/core/agent/handoff.py +6 -2
  21. astrbot/core/agent/hooks.py +9 -6
  22. astrbot/core/agent/mcp_client.py +50 -15
  23. astrbot/core/agent/message.py +168 -0
  24. astrbot/core/agent/response.py +2 -1
  25. astrbot/core/agent/run_context.py +2 -3
  26. astrbot/core/agent/runners/base.py +10 -13
  27. astrbot/core/agent/runners/tool_loop_agent_runner.py +52 -51
  28. astrbot/core/agent/tool.py +60 -41
  29. astrbot/core/agent/tool_executor.py +9 -3
  30. astrbot/core/astr_agent_context.py +3 -1
  31. astrbot/core/astrbot_config_mgr.py +29 -9
  32. astrbot/core/config/__init__.py +2 -2
  33. astrbot/core/config/astrbot_config.py +28 -26
  34. astrbot/core/config/default.py +4 -6
  35. astrbot/core/conversation_mgr.py +105 -36
  36. astrbot/core/core_lifecycle.py +68 -54
  37. astrbot/core/db/__init__.py +33 -18
  38. astrbot/core/db/migration/helper.py +12 -10
  39. astrbot/core/db/migration/migra_3_to_4.py +53 -34
  40. astrbot/core/db/migration/migra_45_to_46.py +1 -1
  41. astrbot/core/db/migration/shared_preferences_v3.py +2 -1
  42. astrbot/core/db/migration/sqlite_v3.py +26 -23
  43. astrbot/core/db/po.py +27 -18
  44. astrbot/core/db/sqlite.py +74 -45
  45. astrbot/core/db/vec_db/base.py +10 -14
  46. astrbot/core/db/vec_db/faiss_impl/document_storage.py +90 -77
  47. astrbot/core/db/vec_db/faiss_impl/embedding_storage.py +9 -3
  48. astrbot/core/db/vec_db/faiss_impl/vec_db.py +36 -31
  49. astrbot/core/event_bus.py +8 -6
  50. astrbot/core/file_token_service.py +6 -5
  51. astrbot/core/initial_loader.py +7 -5
  52. astrbot/core/knowledge_base/chunking/__init__.py +1 -3
  53. astrbot/core/knowledge_base/chunking/base.py +1 -0
  54. astrbot/core/knowledge_base/chunking/fixed_size.py +2 -0
  55. astrbot/core/knowledge_base/chunking/recursive.py +16 -10
  56. astrbot/core/knowledge_base/kb_db_sqlite.py +50 -48
  57. astrbot/core/knowledge_base/kb_helper.py +30 -17
  58. astrbot/core/knowledge_base/kb_mgr.py +6 -7
  59. astrbot/core/knowledge_base/models.py +10 -4
  60. astrbot/core/knowledge_base/parsers/__init__.py +3 -5
  61. astrbot/core/knowledge_base/parsers/base.py +1 -0
  62. astrbot/core/knowledge_base/parsers/markitdown_parser.py +2 -1
  63. astrbot/core/knowledge_base/parsers/pdf_parser.py +2 -1
  64. astrbot/core/knowledge_base/parsers/text_parser.py +1 -0
  65. astrbot/core/knowledge_base/parsers/util.py +1 -1
  66. astrbot/core/knowledge_base/retrieval/__init__.py +6 -8
  67. astrbot/core/knowledge_base/retrieval/manager.py +17 -14
  68. astrbot/core/knowledge_base/retrieval/rank_fusion.py +7 -3
  69. astrbot/core/knowledge_base/retrieval/sparse_retriever.py +11 -5
  70. astrbot/core/log.py +21 -13
  71. astrbot/core/message/components.py +123 -217
  72. astrbot/core/message/message_event_result.py +24 -24
  73. astrbot/core/persona_mgr.py +20 -11
  74. astrbot/core/pipeline/__init__.py +7 -7
  75. astrbot/core/pipeline/content_safety_check/stage.py +13 -9
  76. astrbot/core/pipeline/content_safety_check/strategies/__init__.py +1 -2
  77. astrbot/core/pipeline/content_safety_check/strategies/baidu_aip.py +12 -13
  78. astrbot/core/pipeline/content_safety_check/strategies/keywords.py +1 -0
  79. astrbot/core/pipeline/content_safety_check/strategies/strategy.py +6 -6
  80. astrbot/core/pipeline/context.py +4 -1
  81. astrbot/core/pipeline/context_utils.py +77 -7
  82. astrbot/core/pipeline/preprocess_stage/stage.py +12 -9
  83. astrbot/core/pipeline/process_stage/method/llm_request.py +125 -72
  84. astrbot/core/pipeline/process_stage/method/star_request.py +19 -17
  85. astrbot/core/pipeline/process_stage/stage.py +13 -10
  86. astrbot/core/pipeline/process_stage/utils.py +6 -5
  87. astrbot/core/pipeline/rate_limit_check/stage.py +37 -36
  88. astrbot/core/pipeline/respond/stage.py +23 -20
  89. astrbot/core/pipeline/result_decorate/stage.py +31 -23
  90. astrbot/core/pipeline/scheduler.py +12 -8
  91. astrbot/core/pipeline/session_status_check/stage.py +12 -8
  92. astrbot/core/pipeline/stage.py +10 -4
  93. astrbot/core/pipeline/waking_check/stage.py +24 -18
  94. astrbot/core/pipeline/whitelist_check/stage.py +10 -7
  95. astrbot/core/platform/__init__.py +6 -6
  96. astrbot/core/platform/astr_message_event.py +76 -110
  97. astrbot/core/platform/astrbot_message.py +11 -13
  98. astrbot/core/platform/manager.py +16 -15
  99. astrbot/core/platform/message_session.py +5 -3
  100. astrbot/core/platform/platform.py +16 -24
  101. astrbot/core/platform/platform_metadata.py +4 -4
  102. astrbot/core/platform/register.py +8 -8
  103. astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +23 -15
  104. astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +51 -33
  105. astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +42 -27
  106. astrbot/core/platform/sources/dingtalk/dingtalk_event.py +7 -3
  107. astrbot/core/platform/sources/discord/client.py +9 -6
  108. astrbot/core/platform/sources/discord/components.py +18 -14
  109. astrbot/core/platform/sources/discord/discord_platform_adapter.py +45 -30
  110. astrbot/core/platform/sources/discord/discord_platform_event.py +38 -30
  111. astrbot/core/platform/sources/lark/lark_adapter.py +23 -17
  112. astrbot/core/platform/sources/lark/lark_event.py +21 -14
  113. astrbot/core/platform/sources/misskey/misskey_adapter.py +107 -67
  114. astrbot/core/platform/sources/misskey/misskey_api.py +153 -129
  115. astrbot/core/platform/sources/misskey/misskey_event.py +20 -15
  116. astrbot/core/platform/sources/misskey/misskey_utils.py +74 -62
  117. astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +63 -44
  118. astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +41 -26
  119. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +36 -17
  120. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_event.py +3 -1
  121. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_server.py +12 -7
  122. astrbot/core/platform/sources/satori/satori_adapter.py +56 -38
  123. astrbot/core/platform/sources/satori/satori_event.py +34 -25
  124. astrbot/core/platform/sources/slack/client.py +11 -9
  125. astrbot/core/platform/sources/slack/slack_adapter.py +52 -36
  126. astrbot/core/platform/sources/slack/slack_event.py +34 -24
  127. astrbot/core/platform/sources/telegram/tg_adapter.py +38 -18
  128. astrbot/core/platform/sources/telegram/tg_event.py +32 -18
  129. astrbot/core/platform/sources/webchat/webchat_adapter.py +27 -17
  130. astrbot/core/platform/sources/webchat/webchat_event.py +14 -10
  131. astrbot/core/platform/sources/wechatpadpro/wechatpadpro_adapter.py +115 -120
  132. astrbot/core/platform/sources/wechatpadpro/wechatpadpro_message_event.py +9 -8
  133. astrbot/core/platform/sources/wechatpadpro/xml_data_parser.py +15 -16
  134. astrbot/core/platform/sources/wecom/wecom_adapter.py +35 -18
  135. astrbot/core/platform/sources/wecom/wecom_event.py +55 -48
  136. astrbot/core/platform/sources/wecom/wecom_kf.py +34 -44
  137. astrbot/core/platform/sources/wecom/wecom_kf_message.py +26 -10
  138. astrbot/core/platform/sources/wecom_ai_bot/WXBizJsonMsgCrypt.py +18 -10
  139. astrbot/core/platform/sources/wecom_ai_bot/__init__.py +3 -5
  140. astrbot/core/platform/sources/wecom_ai_bot/ierror.py +0 -1
  141. astrbot/core/platform/sources/wecom_ai_bot/wecomai_adapter.py +61 -37
  142. astrbot/core/platform/sources/wecom_ai_bot/wecomai_api.py +67 -28
  143. astrbot/core/platform/sources/wecom_ai_bot/wecomai_event.py +8 -9
  144. astrbot/core/platform/sources/wecom_ai_bot/wecomai_queue_mgr.py +18 -9
  145. astrbot/core/platform/sources/wecom_ai_bot/wecomai_server.py +14 -12
  146. astrbot/core/platform/sources/wecom_ai_bot/wecomai_utils.py +22 -12
  147. astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +40 -26
  148. astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py +47 -45
  149. astrbot/core/platform_message_history_mgr.py +5 -3
  150. astrbot/core/provider/__init__.py +2 -3
  151. astrbot/core/provider/entites.py +8 -8
  152. astrbot/core/provider/entities.py +61 -75
  153. astrbot/core/provider/func_tool_manager.py +59 -55
  154. astrbot/core/provider/manager.py +32 -22
  155. astrbot/core/provider/provider.py +72 -46
  156. astrbot/core/provider/register.py +7 -7
  157. astrbot/core/provider/sources/anthropic_source.py +48 -30
  158. astrbot/core/provider/sources/azure_tts_source.py +17 -13
  159. astrbot/core/provider/sources/coze_api_client.py +27 -17
  160. astrbot/core/provider/sources/coze_source.py +104 -87
  161. astrbot/core/provider/sources/dashscope_source.py +18 -11
  162. astrbot/core/provider/sources/dashscope_tts.py +36 -23
  163. astrbot/core/provider/sources/dify_source.py +25 -20
  164. astrbot/core/provider/sources/edge_tts_source.py +21 -17
  165. astrbot/core/provider/sources/fishaudio_tts_api_source.py +22 -14
  166. astrbot/core/provider/sources/gemini_embedding_source.py +12 -13
  167. astrbot/core/provider/sources/gemini_source.py +72 -58
  168. astrbot/core/provider/sources/gemini_tts_source.py +8 -6
  169. astrbot/core/provider/sources/gsv_selfhosted_source.py +17 -14
  170. astrbot/core/provider/sources/gsvi_tts_source.py +11 -7
  171. astrbot/core/provider/sources/minimax_tts_api_source.py +50 -40
  172. astrbot/core/provider/sources/openai_embedding_source.py +6 -8
  173. astrbot/core/provider/sources/openai_source.py +77 -69
  174. astrbot/core/provider/sources/openai_tts_api_source.py +14 -6
  175. astrbot/core/provider/sources/sensevoice_selfhosted_source.py +13 -11
  176. astrbot/core/provider/sources/vllm_rerank_source.py +10 -4
  177. astrbot/core/provider/sources/volcengine_tts.py +38 -31
  178. astrbot/core/provider/sources/whisper_api_source.py +14 -12
  179. astrbot/core/provider/sources/whisper_selfhosted_source.py +15 -11
  180. astrbot/core/provider/sources/xinference_rerank_source.py +16 -8
  181. astrbot/core/provider/sources/xinference_stt_provider.py +35 -25
  182. astrbot/core/star/__init__.py +16 -11
  183. astrbot/core/star/config.py +10 -15
  184. astrbot/core/star/context.py +97 -75
  185. astrbot/core/star/filter/__init__.py +4 -3
  186. astrbot/core/star/filter/command.py +30 -28
  187. astrbot/core/star/filter/command_group.py +27 -24
  188. astrbot/core/star/filter/custom_filter.py +6 -5
  189. astrbot/core/star/filter/event_message_type.py +4 -2
  190. astrbot/core/star/filter/permission.py +4 -2
  191. astrbot/core/star/filter/platform_adapter_type.py +4 -2
  192. astrbot/core/star/filter/regex.py +4 -2
  193. astrbot/core/star/register/__init__.py +19 -19
  194. astrbot/core/star/register/star.py +6 -2
  195. astrbot/core/star/register/star_handler.py +96 -73
  196. astrbot/core/star/session_llm_manager.py +48 -14
  197. astrbot/core/star/session_plugin_manager.py +29 -15
  198. astrbot/core/star/star.py +1 -2
  199. astrbot/core/star/star_handler.py +13 -8
  200. astrbot/core/star/star_manager.py +151 -59
  201. astrbot/core/star/star_tools.py +44 -37
  202. astrbot/core/star/updator.py +10 -10
  203. astrbot/core/umop_config_router.py +10 -4
  204. astrbot/core/updator.py +13 -5
  205. astrbot/core/utils/astrbot_path.py +3 -5
  206. astrbot/core/utils/dify_api_client.py +33 -15
  207. astrbot/core/utils/io.py +66 -42
  208. astrbot/core/utils/log_pipe.py +1 -1
  209. astrbot/core/utils/metrics.py +7 -7
  210. astrbot/core/utils/path_util.py +15 -16
  211. astrbot/core/utils/pip_installer.py +5 -5
  212. astrbot/core/utils/session_waiter.py +19 -20
  213. astrbot/core/utils/shared_preferences.py +45 -20
  214. astrbot/core/utils/t2i/__init__.py +4 -1
  215. astrbot/core/utils/t2i/network_strategy.py +35 -26
  216. astrbot/core/utils/t2i/renderer.py +11 -5
  217. astrbot/core/utils/t2i/template_manager.py +14 -15
  218. astrbot/core/utils/tencent_record_helper.py +19 -13
  219. astrbot/core/utils/version_comparator.py +10 -13
  220. astrbot/core/zip_updator.py +43 -40
  221. astrbot/dashboard/routes/__init__.py +18 -18
  222. astrbot/dashboard/routes/auth.py +10 -8
  223. astrbot/dashboard/routes/chat.py +30 -21
  224. astrbot/dashboard/routes/config.py +92 -75
  225. astrbot/dashboard/routes/conversation.py +46 -39
  226. astrbot/dashboard/routes/file.py +4 -2
  227. astrbot/dashboard/routes/knowledge_base.py +47 -40
  228. astrbot/dashboard/routes/log.py +9 -4
  229. astrbot/dashboard/routes/persona.py +19 -16
  230. astrbot/dashboard/routes/plugin.py +69 -55
  231. astrbot/dashboard/routes/route.py +3 -1
  232. astrbot/dashboard/routes/session_management.py +130 -116
  233. astrbot/dashboard/routes/stat.py +34 -34
  234. astrbot/dashboard/routes/t2i.py +15 -12
  235. astrbot/dashboard/routes/tools.py +56 -53
  236. astrbot/dashboard/routes/update.py +32 -28
  237. astrbot/dashboard/server.py +30 -26
  238. astrbot/dashboard/utils.py +8 -4
  239. {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/METADATA +2 -1
  240. astrbot-4.5.3.dist-info/RECORD +261 -0
  241. astrbot-4.5.1.dist-info/RECORD +0 -260
  242. {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/WHEEL +0 -0
  243. {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/entry_points.txt +0 -0
  244. {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, user_id, open_kfid, head_content, menu_list, tail_content, msgid=""
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, user_id, open_kfid, name, address, latitude, longitude, msgid=""
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, user_id, open_kfid, appid, title, thumb_media_id, pagepath, msgid=""
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 time
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
- """my define raise exception function"""
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(object):
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(random.randint(1000000000000000, 9999999999999999)).encode()
216
+ return str(
217
+ secrets.randbelow(self.RANDOM_RANGE) + self.MIN_RANDOM_VALUE
218
+ ).encode()
211
219
 
212
220
 
213
- class WXBizJsonMsgCrypt(object):
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,5 +1,4 @@
1
1
  #!/usr/bin/env python
2
- # -*- coding: utf-8 -*-
3
2
  #########################################################################
4
3
  # Author: jonyqin
5
4
  # Created Time: Thu 11 Sep 2014 01:53:58 PM CST
@@ -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
- from typing import Awaitable, Any, Dict, Optional, Callable
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, queue_mgr: WecomAIQueueMgr, callback: Callable[[dict], Awaitable[None]]
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", "企业微信智能机器人适配器,支持 HTTP 回调接收消息"
94
+ "wecom_ai_bot",
95
+ "企业微信智能机器人适配器,支持 HTTP 回调接收消息",
94
96
  )
95
97
  class WecomAIBotAdapter(Platform):
96
98
  """企业微信智能机器人适配器"""
97
99
 
98
100
  def __init__(
99
- self, platform_config: dict, platform_settings: dict, event_queue: asyncio.Queue
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, self._handle_queued_message
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, message_data: Dict[str, Any], callback_params: Dict[str, str]
155
- ) -> Optional[str]:
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, callback_params, stream_id, session_id
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, self.initial_respond_text, False
195
+ stream_id,
196
+ self.initial_respond_text,
197
+ False,
182
198
  )
183
199
  return await self.api_client.encrypt_message(
184
- resp, callback_params["nonce"], callback_params["timestamp"]
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, "", True
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, latest_plain_content, msg_items, finish
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: Dict[str, Any]) -> str:
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: Dict[str, Any],
289
- callback_params: Dict[str, str],
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, session: MessageSesion, message_chain: MessageChain
415
+ self,
416
+ session: MessageSesion,
417
+ message_chain: MessageChain,
394
418
  ):
395
419
  """通过会话发送消息"""
396
420
  # 企业微信智能机器人主要通过回调响应,这里记录日志