AstrBot 4.5.1__py3-none-any.whl → 4.5.2__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 +47 -52
  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.2.dist-info}/METADATA +2 -1
  240. astrbot-4.5.2.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.2.dist-info}/WHEEL +0 -0
  243. {astrbot-4.5.1.dist-info → astrbot-4.5.2.dist-info}/entry_points.txt +0 -0
  244. {astrbot-4.5.1.dist-info → astrbot-4.5.2.dist-info}/licenses/LICENSE +0 -0
@@ -2,24 +2,24 @@ import asyncio
2
2
  import base64
3
3
  import json
4
4
  import os
5
- import traceback
6
5
  import time
7
- from typing import Optional
6
+ import traceback
8
7
 
9
8
  import aiohttp
10
9
  import anyio
11
10
  import websockets
11
+
12
12
  from astrbot import logger
13
- from astrbot.api.message_components import Plain, Image, At, Record
13
+ from astrbot.api.message_components import At, Image, Plain, Record
14
14
  from astrbot.api.platform import Platform, PlatformMetadata
15
15
  from astrbot.core.message.message_event_result import MessageChain
16
+ from astrbot.core.platform.astr_message_event import MessageSesion
16
17
  from astrbot.core.platform.astrbot_message import (
17
18
  AstrBotMessage,
18
19
  MessageMember,
19
20
  MessageType,
20
21
  )
21
22
  from astrbot.core.utils.astrbot_path import get_astrbot_data_path
22
- from astrbot.core.platform.astr_message_event import MessageSesion
23
23
 
24
24
  from ...register import register_platform_adapter
25
25
  from .wechatpadpro_message_event import WeChatPadProMessageEvent
@@ -28,14 +28,17 @@ try:
28
28
  from .xml_data_parser import GeweDataParser
29
29
  except ImportError as e:
30
30
  logger.warning(
31
- f"警告: 可能未安装 defusedxml 依赖库,将导致无法解析微信的 表情包、引用 类型的消息: {str(e)}"
31
+ f"警告: 可能未安装 defusedxml 依赖库,将导致无法解析微信的 表情包、引用 类型的消息: {e!s}",
32
32
  )
33
33
 
34
34
 
35
35
  @register_platform_adapter("wechatpadpro", "WeChatPadPro 消息平台适配器")
36
36
  class WeChatPadProAdapter(Platform):
37
37
  def __init__(
38
- self, platform_config: dict, platform_settings: dict, event_queue: asyncio.Queue
38
+ self,
39
+ platform_config: dict,
40
+ platform_settings: dict,
41
+ event_queue: asyncio.Queue,
39
42
  ) -> None:
40
43
  super().__init__(event_queue)
41
44
  self._shutdown_event = None
@@ -55,16 +58,19 @@ class WeChatPadProAdapter(Platform):
55
58
  self.host = self.config.get("host")
56
59
  self.port = self.config.get("port")
57
60
  self.active_mesasge_poll: bool = self.config.get(
58
- "wpp_active_message_poll", False
61
+ "wpp_active_message_poll",
62
+ False,
59
63
  )
60
64
  self.active_message_poll_interval: int = self.config.get(
61
- "wpp_active_message_poll_interval", 5
65
+ "wpp_active_message_poll_interval",
66
+ 5,
62
67
  )
63
68
  self.base_url = f"http://{self.host}:{self.port}"
64
69
  self.auth_key = None # 用于保存生成的授权码
65
70
  self.wxid = None # 用于保存登录成功后的 wxid
66
71
  self.credentials_file = os.path.join(
67
- get_astrbot_data_path(), "wechatpadpro_credentials.json"
72
+ get_astrbot_data_path(),
73
+ "wechatpadpro_credentials.json",
68
74
  ) # 持久化文件路径
69
75
  self.ws_handle_task = None
70
76
 
@@ -81,9 +87,7 @@ class WeChatPadProAdapter(Platform):
81
87
  self.max_text_cache = 100
82
88
 
83
89
  async def run(self) -> None:
84
- """
85
- 启动平台适配器的运行实例。
86
- """
90
+ """启动平台适配器的运行实例。"""
87
91
  logger.info("WeChatPadPro 适配器正在启动...")
88
92
 
89
93
  if loaded_credentials := self.load_credentials():
@@ -132,12 +136,10 @@ class WeChatPadProAdapter(Platform):
132
136
  logger.info("WeChatPadPro 适配器已停止。")
133
137
 
134
138
  def load_credentials(self):
135
- """
136
- 从文件中加载 auth_key 和 wxid。
137
- """
139
+ """从文件中加载 auth_key 和 wxid。"""
138
140
  if os.path.exists(self.credentials_file):
139
141
  try:
140
- with open(self.credentials_file, "r") as f:
142
+ with open(self.credentials_file) as f:
141
143
  credentials = json.load(f)
142
144
  logger.info("成功加载 WeChatPadPro 凭据。")
143
145
  return credentials
@@ -146,9 +148,7 @@ class WeChatPadProAdapter(Platform):
146
148
  return None
147
149
 
148
150
  def save_credentials(self):
149
- """
150
- 将 auth_key 和 wxid 保存到文件。
151
- """
151
+ """将 auth_key 和 wxid 保存到文件。"""
152
152
  credentials = {
153
153
  "auth_key": self.auth_key,
154
154
  "wxid": self.wxid,
@@ -163,9 +163,7 @@ class WeChatPadProAdapter(Platform):
163
163
  logger.error(f"保存 WeChatPadPro 凭据失败: {e}")
164
164
 
165
165
  async def check_online_status(self):
166
- """
167
- 检查 WeChatPadPro 设备是否在线。
168
- """
166
+ """检查 WeChatPadPro 设备是否在线。"""
169
167
  if not self.auth_key:
170
168
  return False
171
169
  url = f"{self.base_url}/login/GetLoginStatus"
@@ -182,25 +180,23 @@ class WeChatPadProAdapter(Platform):
182
180
  logger.info("WeChatPadPro 设备当前在线。")
183
181
  return True
184
182
  # login_state == 3 为离线状态
185
- elif login_state == 3:
183
+ if login_state == 3:
186
184
  logger.info("WeChatPadPro 设备不在线。")
187
185
  return False
188
- else:
189
- logger.error(f"未知的在线状态: {response_data}")
190
- return False
186
+ logger.error(f"未知的在线状态: {response_data}")
187
+ return False
191
188
  # Code == 300 为微信退出状态。
192
- elif response.status == 200 and response_data.get("Code") == 300:
189
+ if response.status == 200 and response_data.get("Code") == 300:
193
190
  logger.info("WeChatPadPro 设备已退出。")
194
191
  return False
195
- elif response.status == 200 and response_data.get("Code") == -2:
192
+ if response.status == 200 and response_data.get("Code") == -2:
196
193
  # 该链接不存在
197
194
  self.auth_key = None
198
195
  return False
199
- else:
200
- logger.error(
201
- f"检查在线状态失败: {response.status}, {response_data}"
202
- )
203
- return False
196
+ logger.error(
197
+ f"检查在线状态失败: {response.status}, {response_data}",
198
+ )
199
+ return False
204
200
 
205
201
  except aiohttp.ClientConnectorError as e:
206
202
  logger.error(f"连接到 WeChatPadPro 服务失败: {e}")
@@ -221,9 +217,7 @@ class WeChatPadProAdapter(Platform):
221
217
  return None
222
218
 
223
219
  async def generate_auth_key(self):
224
- """
225
- 生成授权码。
226
- """
220
+ """生成授权码。"""
227
221
  url = f"{self.base_url}/admin/GenAuthKey1"
228
222
  params = {"key": self.admin_key}
229
223
  payload = {"Count": 1, "Days": 365} # 生成一个有效期365天的授权码
@@ -235,7 +229,7 @@ class WeChatPadProAdapter(Platform):
235
229
  async with session.post(url, params=params, json=payload) as response:
236
230
  if response.status != 200:
237
231
  logger.error(
238
- f"生成授权码失败: {response.status}, {await response.text()}"
232
+ f"生成授权码失败: {response.status}, {await response.text()}",
239
233
  )
240
234
  return
241
235
 
@@ -248,7 +242,7 @@ class WeChatPadProAdapter(Platform):
248
242
  logger.info("成功获取授权码")
249
243
  else:
250
244
  logger.error(
251
- f"生成授权码成功但未找到授权码: {response_data}"
245
+ f"生成授权码成功但未找到授权码: {response_data}",
252
246
  )
253
247
  else:
254
248
  logger.error(f"生成授权码失败: {response_data}")
@@ -258,9 +252,7 @@ class WeChatPadProAdapter(Platform):
258
252
  logger.error(f"生成授权码时发生错误: {e}")
259
253
 
260
254
  async def get_login_qr_code(self):
261
- """
262
- 获取登录二维码地址。
263
- """
255
+ """获取登录二维码地址。"""
264
256
  url = f"{self.base_url}/login/GetLoginQrCodeNew"
265
257
  params = {"key": self.auth_key}
266
258
  payload = {} # 根据文档,这个接口的 body 可以为空
@@ -272,26 +264,24 @@ class WeChatPadProAdapter(Platform):
272
264
  if response.status == 200 and response_data.get("Code") == 200:
273
265
  # 二维码地址在 Data.QrCodeUrl 字段中
274
266
  if response_data.get("Data") and response_data["Data"].get(
275
- "QrCodeUrl"
267
+ "QrCodeUrl",
276
268
  ):
277
269
  return response_data["Data"]["QrCodeUrl"]
278
- else:
279
- logger.error(
280
- f"获取登录二维码成功但未找到二维码地址: {response_data}"
281
- )
282
- return None
283
- elif "该 key 无效" in response_data.get("Text"):
284
270
  logger.error(
285
- "授权码无效,已经清除。请重新启动 AstrBot 或者本消息适配器。原因也可能是 WeChatPadPro 的 MySQL 服务没有启动成功,请检查 WeChatPadPro 服务的日志。"
271
+ f"获取登录二维码成功但未找到二维码地址: {response_data}",
286
272
  )
287
- self.auth_key = None
288
- self.save_credentials()
289
273
  return None
290
- else:
274
+ if "该 key 无效" in response_data.get("Text"):
291
275
  logger.error(
292
- f"获取登录二维码失败: {response.status}, {response_data}"
276
+ "授权码无效,已经清除。请重新启动 AstrBot 或者本消息适配器。原因也可能是 WeChatPadPro 的 MySQL 服务没有启动成功,请检查 WeChatPadPro 服务的日志。",
293
277
  )
278
+ self.auth_key = None
279
+ self.save_credentials()
294
280
  return None
281
+ logger.error(
282
+ f"获取登录二维码失败: {response.status}, {response_data}",
283
+ )
284
+ return None
295
285
  except aiohttp.ClientConnectorError as e:
296
286
  logger.error(f"连接到 WeChatPadPro 服务失败: {e}")
297
287
  return None
@@ -300,8 +290,7 @@ class WeChatPadProAdapter(Platform):
300
290
  return None
301
291
 
302
292
  async def check_login_status(self):
303
- """
304
- 循环检测扫码状态。
293
+ """循环检测扫码状态。
305
294
  尝试 6 次后跳出循环,添加倒计时。
306
295
  返回 True 如果登录成功,否则返回 False。
307
296
  """
@@ -325,31 +314,31 @@ class WeChatPadProAdapter(Platform):
325
314
  ):
326
315
  status = response_data["Data"]["state"]
327
316
  logger.info(
328
- f"第 {attempts + 1} 次尝试,当前登录状态: {status},还剩{countdown - attempts * 5}秒"
317
+ f"第 {attempts + 1} 次尝试,当前登录状态: {status},还剩{countdown - attempts * 5}秒",
329
318
  )
330
319
  if status == 2: # 状态 2 表示登录成功
331
320
  self.wxid = response_data["Data"].get("wxid")
332
321
  self.wxnewpass = response_data["Data"].get(
333
- "wxnewpass"
322
+ "wxnewpass",
334
323
  )
335
324
  logger.info(
336
- f"登录成功,wxid: {self.wxid}, wxnewpass: {self.wxnewpass}"
325
+ f"登录成功,wxid: {self.wxid}, wxnewpass: {self.wxnewpass}",
337
326
  )
338
327
  self.save_credentials() # 登录成功后保存凭据
339
328
  return True
340
- elif status == -2: # 二维码过期
329
+ if status == -2: # 二维码过期
341
330
  logger.error("二维码已过期,请重新获取。")
342
331
  return False
343
332
  else:
344
333
  logger.error(
345
- f"检测登录状态成功但未找到登录状态: {response_data}"
334
+ f"检测登录状态成功但未找到登录状态: {response_data}",
346
335
  )
347
336
  elif response_data.get("Code") == 300:
348
337
  # "不存在状态"
349
338
  pass
350
339
  else:
351
340
  logger.info(
352
- f"检测登录状态失败: {response.status}, {response_data}"
341
+ f"检测登录状态失败: {response.status}, {response_data}",
353
342
  )
354
343
 
355
344
  except aiohttp.ClientConnectorError as e:
@@ -368,13 +357,11 @@ class WeChatPadProAdapter(Platform):
368
357
  return False
369
358
 
370
359
  async def connect_websocket(self):
371
- """
372
- 建立 WebSocket 连接并处理接收到的消息。
373
- """
360
+ """建立 WebSocket 连接并处理接收到的消息。"""
374
361
  os.environ["no_proxy"] = f"localhost,127.0.0.1,{self.host}"
375
362
  ws_url = f"ws://{self.host}:{self.port}/ws/GetSyncMsg?key={self.auth_key}"
376
363
  logger.info(
377
- f"正在连接 WebSocket: ws://{self.host}:{self.port}/ws/GetSyncMsg?key=***"
364
+ f"正在连接 WebSocket: ws://{self.host}:{self.port}/ws/GetSyncMsg?key=***",
378
365
  )
379
366
  while True:
380
367
  try:
@@ -389,7 +376,8 @@ class WeChatPadProAdapter(Platform):
389
376
  while True:
390
377
  try:
391
378
  message = await asyncio.wait_for(
392
- websocket.recv(), timeout=wait_time
379
+ websocket.recv(),
380
+ timeout=wait_time,
393
381
  )
394
382
  # logger.debug(message) # 不显示原始消息内容
395
383
  asyncio.create_task(self.handle_websocket_message(message))
@@ -404,14 +392,12 @@ class WeChatPadProAdapter(Platform):
404
392
  break
405
393
  except Exception as e:
406
394
  logger.error(
407
- f"WebSocket 连接失败: {e}, 请检查WeChatPadPro服务状态,或尝试重启WeChatPadPro适配器。"
395
+ f"WebSocket 连接失败: {e}, 请检查WeChatPadPro服务状态,或尝试重启WeChatPadPro适配器。",
408
396
  )
409
397
  await asyncio.sleep(5)
410
398
 
411
399
  async def handle_websocket_message(self, message: str):
412
- """
413
- 处理从 WebSocket 接收到的消息。
414
- """
400
+ """处理从 WebSocket 接收到的消息。"""
415
401
  logger.debug(f"收到 WebSocket 消息: {message}")
416
402
  try:
417
403
  message_data = json.loads(message)
@@ -441,9 +427,7 @@ class WeChatPadProAdapter(Platform):
441
427
  logger.error(f"处理 WebSocket 消息时发生错误: {e}")
442
428
 
443
429
  async def convert_message(self, raw_message: dict) -> AstrBotMessage | None:
444
- """
445
- 将 WeChatPadPro 原始消息转换为 AstrBotMessage。
446
- """
430
+ """将 WeChatPadPro 原始消息转换为 AstrBotMessage。"""
447
431
  abm = AstrBotMessage()
448
432
  abm.raw_message = raw_message
449
433
  abm.message_id = str(raw_message.get("msg_id"))
@@ -452,7 +436,7 @@ class WeChatPadProAdapter(Platform):
452
436
 
453
437
  if int(time.time()) - abm.timestamp > 180:
454
438
  logger.warning(
455
- f"忽略 3 分钟前的旧消息:消息时间戳 {abm.timestamp} 超过当前时间 {int(time.time())}。"
439
+ f"忽略 3 分钟前的旧消息:消息时间戳 {abm.timestamp} 超过当前时间 {int(time.time())}。",
456
440
  )
457
441
  return None
458
442
 
@@ -476,7 +460,12 @@ class WeChatPadProAdapter(Platform):
476
460
 
477
461
  # 先判断群聊/私聊并设置基本属性
478
462
  if await self._process_chat_type(
479
- abm, raw_message, from_user_name, to_user_name, content, push_content
463
+ abm,
464
+ raw_message,
465
+ from_user_name,
466
+ to_user_name,
467
+ content,
468
+ push_content,
480
469
  ):
481
470
  # 再根据消息类型处理消息内容
482
471
  await self._process_message_content(abm, raw_message, msg_type, content)
@@ -493,9 +482,7 @@ class WeChatPadProAdapter(Platform):
493
482
  content: str,
494
483
  push_content: str,
495
484
  ):
496
- """
497
- 判断消息是群聊还是私聊,并设置 AstrBotMessage 的基本属性。
498
- """
485
+ """判断消息是群聊还是私聊,并设置 AstrBotMessage 的基本属性。"""
499
486
  if from_user_name == "weixin":
500
487
  return False
501
488
  at_me = False
@@ -510,7 +497,8 @@ class WeChatPadProAdapter(Platform):
510
497
  # 获取群聊发送者的nickname
511
498
  if sender_wxid:
512
499
  accurate_nickname = await self._get_group_member_nickname(
513
- abm.group_id, sender_wxid
500
+ abm.group_id,
501
+ sender_wxid,
514
502
  )
515
503
  if accurate_nickname:
516
504
  abm.sender.nickname = accurate_nickname
@@ -539,11 +527,11 @@ class WeChatPadProAdapter(Platform):
539
527
  return True
540
528
 
541
529
  async def _get_group_member_nickname(
542
- self, group_id: str, member_wxid: str
543
- ) -> Optional[str]:
544
- """
545
- 通过接口获取群成员的昵称。
546
- """
530
+ self,
531
+ group_id: str,
532
+ member_wxid: str,
533
+ ) -> str | None:
534
+ """通过接口获取群成员的昵称。"""
547
535
  url = f"{self.base_url}/group/GetChatroomMemberDetail"
548
536
  params = {"key": self.auth_key}
549
537
  payload = {
@@ -565,11 +553,11 @@ class WeChatPadProAdapter(Platform):
565
553
  if member.get("user_name") == member_wxid:
566
554
  return member.get("nick_name")
567
555
  logger.warning(
568
- f"在群 {group_id} 中未找到成员 {member_wxid} 的昵称"
556
+ f"在群 {group_id} 中未找到成员 {member_wxid} 的昵称",
569
557
  )
570
558
  else:
571
559
  logger.error(
572
- f"获取群成员详情失败: {response.status}, {response_data}"
560
+ f"获取群成员详情失败: {response.status}, {response_data}",
573
561
  )
574
562
  return None
575
563
  except aiohttp.ClientConnectorError as e:
@@ -580,7 +568,10 @@ class WeChatPadProAdapter(Platform):
580
568
  return None
581
569
 
582
570
  async def _download_raw_image(
583
- self, from_user_name: str, to_user_name: str, msg_id: int
571
+ self,
572
+ from_user_name: str,
573
+ to_user_name: str,
574
+ msg_id: int,
584
575
  ):
585
576
  """下载原始图片。"""
586
577
  url = f"{self.base_url}/message/GetMsgBigImg"
@@ -598,9 +589,8 @@ class WeChatPadProAdapter(Platform):
598
589
  async with session.post(url, params=params, json=payload) as response:
599
590
  if response.status == 200:
600
591
  return await response.json()
601
- else:
602
- logger.error(f"下载图片失败: {response.status}")
603
- return None
592
+ logger.error(f"下载图片失败: {response.status}")
593
+ return None
604
594
  except aiohttp.ClientConnectorError as e:
605
595
  logger.error(f"连接到 WeChatPadPro 服务失败: {e}")
606
596
  return None
@@ -609,7 +599,11 @@ class WeChatPadProAdapter(Platform):
609
599
  return None
610
600
 
611
601
  async def download_voice(
612
- self, to_user_name: str, new_msg_id: str, bufid: str, length: int
602
+ self,
603
+ to_user_name: str,
604
+ new_msg_id: str,
605
+ bufid: str,
606
+ length: int,
613
607
  ):
614
608
  """下载原始音频。"""
615
609
  url = f"{self.base_url}/message/GetMsgVoice"
@@ -635,11 +629,13 @@ class WeChatPadProAdapter(Platform):
635
629
  return None
636
630
 
637
631
  async def _process_message_content(
638
- self, abm: AstrBotMessage, raw_message: dict, msg_type: int, content: str
632
+ self,
633
+ abm: AstrBotMessage,
634
+ raw_message: dict,
635
+ msg_type: int,
636
+ content: str,
639
637
  ):
640
- """
641
- 根据消息类型处理消息内容,填充 AstrBotMessage 的 message 列表。
642
- """
638
+ """根据消息类型处理消息内容,填充 AstrBotMessage 的 message 列表。"""
643
639
  if msg_type == 1: # 文本消息
644
640
  abm.message_str = content
645
641
  if abm.type == MessageType.GROUP_MESSAGE:
@@ -671,10 +667,12 @@ class WeChatPadProAdapter(Platform):
671
667
  if at_me:
672
668
  # 被@了,在消息开头插入At组件(参考gewechat的做法)
673
669
  bot_nickname = await self._get_group_member_nickname(
674
- abm.group_id, abm.self_id
670
+ abm.group_id,
671
+ abm.self_id,
675
672
  )
676
673
  abm.message.insert(
677
- 0, At(qq=abm.self_id, name=bot_nickname or abm.self_id)
674
+ 0,
675
+ At(qq=abm.self_id, name=bot_nickname or abm.self_id),
678
676
  )
679
677
 
680
678
  # 只有当消息内容不仅仅是@时才添加Plain组件
@@ -727,7 +725,9 @@ class WeChatPadProAdapter(Platform):
727
725
  to_user_name = raw_message.get("to_user_name", {}).get("str", "")
728
726
  msg_id = raw_message.get("msg_id")
729
727
  image_resp = await self._download_raw_image(
730
- from_user_name, to_user_name, msg_id
728
+ from_user_name,
729
+ to_user_name,
730
+ msg_id,
731
731
  )
732
732
  image_bs64_data = (
733
733
  image_resp.get("Data", {}).get("Data", {}).get("Buffer", None)
@@ -789,7 +789,8 @@ class WeChatPadProAdapter(Platform):
789
789
  voice_bs64_data = base64.b64decode(voice_bs64_data)
790
790
  temp_dir = os.path.join(get_astrbot_data_path(), "temp")
791
791
  file_path = os.path.join(
792
- temp_dir, f"wechatpadpro_voice_{abm.message_id}.silk"
792
+ temp_dir,
793
+ f"wechatpadpro_voice_{abm.message_id}.silk",
793
794
  )
794
795
 
795
796
  async with await anyio.open_file(file_path, "wb") as f:
@@ -819,9 +820,7 @@ class WeChatPadProAdapter(Platform):
819
820
  logger.warning(f"收到未处理的消息类型: {msg_type}。")
820
821
 
821
822
  async def terminate(self):
822
- """
823
- 终止一个平台的运行实例。
824
- """
823
+ """终止一个平台的运行实例。"""
825
824
  logger.info("终止 WeChatPadPro 适配器。")
826
825
  try:
827
826
  if self.ws_handle_task:
@@ -831,13 +830,13 @@ class WeChatPadProAdapter(Platform):
831
830
  pass
832
831
 
833
832
  def meta(self) -> PlatformMetadata:
834
- """
835
- 得到一个平台的元数据。
836
- """
833
+ """得到一个平台的元数据。"""
837
834
  return self.metadata
838
835
 
839
836
  async def send_by_session(
840
- self, session: MessageSesion, message_chain: MessageChain
837
+ self,
838
+ session: MessageSesion,
839
+ message_chain: MessageChain,
841
840
  ):
842
841
  dummy_message_obj = AstrBotMessage()
843
842
  dummy_message_obj.session_id = session.session_id
@@ -864,9 +863,7 @@ class WeChatPadProAdapter(Platform):
864
863
  await sending_event.send(message_chain)
865
864
 
866
865
  async def get_contact_list(self):
867
- """
868
- 获取联系人列表。
869
- """
866
+ """获取联系人列表。"""
870
867
  url = f"{self.base_url}/friend/GetContactList"
871
868
  params = {"key": self.auth_key}
872
869
  payload = {"CurrentChatRoomContactSeq": 0, "CurrentWxcontactSeq": 0}
@@ -884,9 +881,8 @@ class WeChatPadProAdapter(Platform):
884
881
  .get("contactUsernameList", [])
885
882
  )
886
883
  return contact_list
887
- else:
888
- logger.error(f"获取联系人列表失败: {result}")
889
- return None
884
+ logger.error(f"获取联系人列表失败: {result}")
885
+ return None
890
886
  except aiohttp.ClientConnectorError as e:
891
887
  logger.error(f"连接到 WeChatPadPro 服务失败: {e}")
892
888
  return None
@@ -895,11 +891,11 @@ class WeChatPadProAdapter(Platform):
895
891
  return None
896
892
 
897
893
  async def get_contact_details_list(
898
- self, room_wx_id_list: list[str] = None, user_names: list[str] = None
899
- ) -> Optional[dict]:
900
- """
901
- 获取联系人详情列表。
902
- """
894
+ self,
895
+ room_wx_id_list: list[str] = None,
896
+ user_names: list[str] = None,
897
+ ) -> dict | None:
898
+ """获取联系人详情列表。"""
903
899
  if room_wx_id_list is None:
904
900
  room_wx_id_list = []
905
901
  if user_names is None:
@@ -917,9 +913,8 @@ class WeChatPadProAdapter(Platform):
917
913
  if result.get("Code") == 200 and result.get("Data"):
918
914
  contact_list = result.get("Data", {}).get("contactList", {})
919
915
  return contact_list
920
- else:
921
- logger.error(f"获取联系人详情列表失败: {result}")
922
- return None
916
+ logger.error(f"获取联系人详情列表失败: {result}")
917
+ return None
923
918
  except aiohttp.ClientConnectorError as e:
924
919
  logger.error(f"连接到 WeChatPadPro 服务失败: {e}")
925
920
  return None
@@ -10,8 +10,8 @@ from astrbot import logger
10
10
  from astrbot.core.message.components import (
11
11
  Image,
12
12
  Plain,
13
- WechatEmoji,
14
13
  Record,
14
+ WechatEmoji,
15
15
  ) # Import Image
16
16
  from astrbot.core.message.message_event_result import MessageChain
17
17
  from astrbot.core.platform.astr_message_event import AstrMessageEvent
@@ -56,8 +56,8 @@ class WeChatPadProMessageEvent(AstrMessageEvent):
56
56
  b64c = self._compress_image(raw)
57
57
  payload = {
58
58
  "MsgItem": [
59
- {"ImageContent": b64c, "MsgType": 3, "ToUserName": self.session_id}
60
- ]
59
+ {"ImageContent": b64c, "MsgType": 3, "ToUserName": self.session_id},
60
+ ],
61
61
  }
62
62
  url = f"{self.adapter.base_url}/message/SendImageNewMessage"
63
63
  await self._post(session, url, payload)
@@ -66,7 +66,8 @@ class WeChatPadProMessageEvent(AstrMessageEvent):
66
66
  if (
67
67
  self.message_obj.type == MessageType.GROUP_MESSAGE # 确保是群聊消息
68
68
  and self.adapter.settings.get(
69
- "reply_with_mention", False
69
+ "reply_with_mention",
70
+ False,
70
71
  ) # 检查适配器设置是否启用 reply_with_mention
71
72
  and self.message_obj.sender # 确保有发送者信息
72
73
  and (
@@ -91,8 +92,8 @@ class WeChatPadProMessageEvent(AstrMessageEvent):
91
92
  "MsgType": 1,
92
93
  "TextContent": message_text,
93
94
  "ToUserName": session_id,
94
- }
95
- ]
95
+ },
96
+ ],
96
97
  }
97
98
  url = f"{self.adapter.base_url}/message/SendTextMessage"
98
99
  await self._post(session, url, payload)
@@ -104,8 +105,8 @@ class WeChatPadProMessageEvent(AstrMessageEvent):
104
105
  "EmojiMd5": comp.md5,
105
106
  "EmojiSize": comp.md5_len,
106
107
  "ToUserName": self.session_id,
107
- }
108
- ]
108
+ },
109
+ ],
109
110
  }
110
111
  url = f"{self.adapter.base_url}/message/SendEmojiMessage"
111
112
  await self._post(session, url, payload)