AstrBot 3.5.6__py3-none-any.whl → 4.7.0__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 (288) hide show
  1. astrbot/api/__init__.py +16 -4
  2. astrbot/api/all.py +2 -1
  3. astrbot/api/event/__init__.py +5 -6
  4. astrbot/api/event/filter/__init__.py +37 -34
  5. astrbot/api/platform/__init__.py +7 -8
  6. astrbot/api/provider/__init__.py +8 -7
  7. astrbot/api/star/__init__.py +3 -4
  8. astrbot/api/util/__init__.py +2 -2
  9. astrbot/cli/__init__.py +1 -0
  10. astrbot/cli/__main__.py +18 -197
  11. astrbot/cli/commands/__init__.py +6 -0
  12. astrbot/cli/commands/cmd_conf.py +209 -0
  13. astrbot/cli/commands/cmd_init.py +56 -0
  14. astrbot/cli/commands/cmd_plug.py +245 -0
  15. astrbot/cli/commands/cmd_run.py +62 -0
  16. astrbot/cli/utils/__init__.py +18 -0
  17. astrbot/cli/utils/basic.py +76 -0
  18. astrbot/cli/utils/plugin.py +246 -0
  19. astrbot/cli/utils/version_comparator.py +90 -0
  20. astrbot/core/__init__.py +17 -19
  21. astrbot/core/agent/agent.py +14 -0
  22. astrbot/core/agent/handoff.py +38 -0
  23. astrbot/core/agent/hooks.py +30 -0
  24. astrbot/core/agent/mcp_client.py +385 -0
  25. astrbot/core/agent/message.py +175 -0
  26. astrbot/core/agent/response.py +14 -0
  27. astrbot/core/agent/run_context.py +22 -0
  28. astrbot/core/agent/runners/__init__.py +3 -0
  29. astrbot/core/agent/runners/base.py +65 -0
  30. astrbot/core/agent/runners/coze/coze_agent_runner.py +367 -0
  31. astrbot/core/agent/runners/coze/coze_api_client.py +324 -0
  32. astrbot/core/agent/runners/dashscope/dashscope_agent_runner.py +403 -0
  33. astrbot/core/agent/runners/dify/dify_agent_runner.py +336 -0
  34. astrbot/core/agent/runners/dify/dify_api_client.py +195 -0
  35. astrbot/core/agent/runners/tool_loop_agent_runner.py +400 -0
  36. astrbot/core/agent/tool.py +285 -0
  37. astrbot/core/agent/tool_executor.py +17 -0
  38. astrbot/core/astr_agent_context.py +19 -0
  39. astrbot/core/astr_agent_hooks.py +36 -0
  40. astrbot/core/astr_agent_run_util.py +80 -0
  41. astrbot/core/astr_agent_tool_exec.py +246 -0
  42. astrbot/core/astrbot_config_mgr.py +275 -0
  43. astrbot/core/config/__init__.py +2 -2
  44. astrbot/core/config/astrbot_config.py +60 -20
  45. astrbot/core/config/default.py +1972 -453
  46. astrbot/core/config/i18n_utils.py +110 -0
  47. astrbot/core/conversation_mgr.py +285 -75
  48. astrbot/core/core_lifecycle.py +167 -62
  49. astrbot/core/db/__init__.py +305 -102
  50. astrbot/core/db/migration/helper.py +69 -0
  51. astrbot/core/db/migration/migra_3_to_4.py +357 -0
  52. astrbot/core/db/migration/migra_45_to_46.py +44 -0
  53. astrbot/core/db/migration/migra_webchat_session.py +131 -0
  54. astrbot/core/db/migration/shared_preferences_v3.py +48 -0
  55. astrbot/core/db/migration/sqlite_v3.py +497 -0
  56. astrbot/core/db/po.py +259 -55
  57. astrbot/core/db/sqlite.py +773 -528
  58. astrbot/core/db/vec_db/base.py +73 -0
  59. astrbot/core/db/vec_db/faiss_impl/__init__.py +3 -0
  60. astrbot/core/db/vec_db/faiss_impl/document_storage.py +392 -0
  61. astrbot/core/db/vec_db/faiss_impl/embedding_storage.py +93 -0
  62. astrbot/core/db/vec_db/faiss_impl/sqlite_init.sql +17 -0
  63. astrbot/core/db/vec_db/faiss_impl/vec_db.py +204 -0
  64. astrbot/core/event_bus.py +26 -22
  65. astrbot/core/exceptions.py +9 -0
  66. astrbot/core/file_token_service.py +98 -0
  67. astrbot/core/initial_loader.py +19 -10
  68. astrbot/core/knowledge_base/chunking/__init__.py +9 -0
  69. astrbot/core/knowledge_base/chunking/base.py +25 -0
  70. astrbot/core/knowledge_base/chunking/fixed_size.py +59 -0
  71. astrbot/core/knowledge_base/chunking/recursive.py +161 -0
  72. astrbot/core/knowledge_base/kb_db_sqlite.py +301 -0
  73. astrbot/core/knowledge_base/kb_helper.py +642 -0
  74. astrbot/core/knowledge_base/kb_mgr.py +330 -0
  75. astrbot/core/knowledge_base/models.py +120 -0
  76. astrbot/core/knowledge_base/parsers/__init__.py +13 -0
  77. astrbot/core/knowledge_base/parsers/base.py +51 -0
  78. astrbot/core/knowledge_base/parsers/markitdown_parser.py +26 -0
  79. astrbot/core/knowledge_base/parsers/pdf_parser.py +101 -0
  80. astrbot/core/knowledge_base/parsers/text_parser.py +42 -0
  81. astrbot/core/knowledge_base/parsers/url_parser.py +103 -0
  82. astrbot/core/knowledge_base/parsers/util.py +13 -0
  83. astrbot/core/knowledge_base/prompts.py +65 -0
  84. astrbot/core/knowledge_base/retrieval/__init__.py +14 -0
  85. astrbot/core/knowledge_base/retrieval/hit_stopwords.txt +767 -0
  86. astrbot/core/knowledge_base/retrieval/manager.py +276 -0
  87. astrbot/core/knowledge_base/retrieval/rank_fusion.py +142 -0
  88. astrbot/core/knowledge_base/retrieval/sparse_retriever.py +136 -0
  89. astrbot/core/log.py +21 -15
  90. astrbot/core/message/components.py +413 -287
  91. astrbot/core/message/message_event_result.py +35 -24
  92. astrbot/core/persona_mgr.py +192 -0
  93. astrbot/core/pipeline/__init__.py +14 -14
  94. astrbot/core/pipeline/content_safety_check/stage.py +13 -9
  95. astrbot/core/pipeline/content_safety_check/strategies/__init__.py +1 -2
  96. astrbot/core/pipeline/content_safety_check/strategies/baidu_aip.py +13 -14
  97. astrbot/core/pipeline/content_safety_check/strategies/keywords.py +2 -1
  98. astrbot/core/pipeline/content_safety_check/strategies/strategy.py +6 -6
  99. astrbot/core/pipeline/context.py +7 -1
  100. astrbot/core/pipeline/context_utils.py +107 -0
  101. astrbot/core/pipeline/preprocess_stage/stage.py +63 -36
  102. astrbot/core/pipeline/process_stage/method/agent_request.py +48 -0
  103. astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py +464 -0
  104. astrbot/core/pipeline/process_stage/method/agent_sub_stages/third_party.py +202 -0
  105. astrbot/core/pipeline/process_stage/method/star_request.py +26 -32
  106. astrbot/core/pipeline/process_stage/stage.py +21 -15
  107. astrbot/core/pipeline/process_stage/utils.py +125 -0
  108. astrbot/core/pipeline/rate_limit_check/stage.py +34 -36
  109. astrbot/core/pipeline/respond/stage.py +142 -101
  110. astrbot/core/pipeline/result_decorate/stage.py +124 -57
  111. astrbot/core/pipeline/scheduler.py +21 -16
  112. astrbot/core/pipeline/session_status_check/stage.py +37 -0
  113. astrbot/core/pipeline/stage.py +11 -76
  114. astrbot/core/pipeline/waking_check/stage.py +69 -33
  115. astrbot/core/pipeline/whitelist_check/stage.py +10 -7
  116. astrbot/core/platform/__init__.py +6 -6
  117. astrbot/core/platform/astr_message_event.py +107 -129
  118. astrbot/core/platform/astrbot_message.py +32 -12
  119. astrbot/core/platform/manager.py +62 -18
  120. astrbot/core/platform/message_session.py +30 -0
  121. astrbot/core/platform/platform.py +16 -24
  122. astrbot/core/platform/platform_metadata.py +9 -4
  123. astrbot/core/platform/register.py +12 -7
  124. astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +136 -60
  125. astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +126 -46
  126. astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +63 -31
  127. astrbot/core/platform/sources/dingtalk/dingtalk_event.py +30 -26
  128. astrbot/core/platform/sources/discord/client.py +129 -0
  129. astrbot/core/platform/sources/discord/components.py +139 -0
  130. astrbot/core/platform/sources/discord/discord_platform_adapter.py +473 -0
  131. astrbot/core/platform/sources/discord/discord_platform_event.py +313 -0
  132. astrbot/core/platform/sources/lark/lark_adapter.py +27 -18
  133. astrbot/core/platform/sources/lark/lark_event.py +39 -13
  134. astrbot/core/platform/sources/misskey/misskey_adapter.py +770 -0
  135. astrbot/core/platform/sources/misskey/misskey_api.py +964 -0
  136. astrbot/core/platform/sources/misskey/misskey_event.py +163 -0
  137. astrbot/core/platform/sources/misskey/misskey_utils.py +550 -0
  138. astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +149 -33
  139. astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +41 -26
  140. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +36 -17
  141. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_event.py +3 -1
  142. astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_server.py +14 -8
  143. astrbot/core/platform/sources/satori/satori_adapter.py +792 -0
  144. astrbot/core/platform/sources/satori/satori_event.py +432 -0
  145. astrbot/core/platform/sources/slack/client.py +164 -0
  146. astrbot/core/platform/sources/slack/slack_adapter.py +416 -0
  147. astrbot/core/platform/sources/slack/slack_event.py +253 -0
  148. astrbot/core/platform/sources/telegram/tg_adapter.py +100 -43
  149. astrbot/core/platform/sources/telegram/tg_event.py +136 -36
  150. astrbot/core/platform/sources/webchat/webchat_adapter.py +72 -22
  151. astrbot/core/platform/sources/webchat/webchat_event.py +46 -22
  152. astrbot/core/platform/sources/webchat/webchat_queue_mgr.py +35 -0
  153. astrbot/core/platform/sources/wechatpadpro/wechatpadpro_adapter.py +926 -0
  154. astrbot/core/platform/sources/wechatpadpro/wechatpadpro_message_event.py +178 -0
  155. astrbot/core/platform/sources/wechatpadpro/xml_data_parser.py +159 -0
  156. astrbot/core/platform/sources/wecom/wecom_adapter.py +169 -27
  157. astrbot/core/platform/sources/wecom/wecom_event.py +162 -77
  158. astrbot/core/platform/sources/wecom/wecom_kf.py +279 -0
  159. astrbot/core/platform/sources/wecom/wecom_kf_message.py +196 -0
  160. astrbot/core/platform/sources/wecom_ai_bot/WXBizJsonMsgCrypt.py +297 -0
  161. astrbot/core/platform/sources/wecom_ai_bot/__init__.py +15 -0
  162. astrbot/core/platform/sources/wecom_ai_bot/ierror.py +19 -0
  163. astrbot/core/platform/sources/wecom_ai_bot/wecomai_adapter.py +472 -0
  164. astrbot/core/platform/sources/wecom_ai_bot/wecomai_api.py +417 -0
  165. astrbot/core/platform/sources/wecom_ai_bot/wecomai_event.py +152 -0
  166. astrbot/core/platform/sources/wecom_ai_bot/wecomai_queue_mgr.py +153 -0
  167. astrbot/core/platform/sources/wecom_ai_bot/wecomai_server.py +168 -0
  168. astrbot/core/platform/sources/wecom_ai_bot/wecomai_utils.py +209 -0
  169. astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +306 -0
  170. astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py +186 -0
  171. astrbot/core/platform_message_history_mgr.py +49 -0
  172. astrbot/core/provider/__init__.py +2 -3
  173. astrbot/core/provider/entites.py +8 -8
  174. astrbot/core/provider/entities.py +154 -98
  175. astrbot/core/provider/func_tool_manager.py +446 -458
  176. astrbot/core/provider/manager.py +345 -207
  177. astrbot/core/provider/provider.py +188 -73
  178. astrbot/core/provider/register.py +9 -7
  179. astrbot/core/provider/sources/anthropic_source.py +295 -115
  180. astrbot/core/provider/sources/azure_tts_source.py +224 -0
  181. astrbot/core/provider/sources/bailian_rerank_source.py +236 -0
  182. astrbot/core/provider/sources/dashscope_tts.py +138 -14
  183. astrbot/core/provider/sources/edge_tts_source.py +24 -19
  184. astrbot/core/provider/sources/fishaudio_tts_api_source.py +58 -13
  185. astrbot/core/provider/sources/gemini_embedding_source.py +61 -0
  186. astrbot/core/provider/sources/gemini_source.py +310 -132
  187. astrbot/core/provider/sources/gemini_tts_source.py +81 -0
  188. astrbot/core/provider/sources/groq_source.py +15 -0
  189. astrbot/core/provider/sources/gsv_selfhosted_source.py +151 -0
  190. astrbot/core/provider/sources/gsvi_tts_source.py +14 -7
  191. astrbot/core/provider/sources/minimax_tts_api_source.py +159 -0
  192. astrbot/core/provider/sources/openai_embedding_source.py +40 -0
  193. astrbot/core/provider/sources/openai_source.py +241 -145
  194. astrbot/core/provider/sources/openai_tts_api_source.py +18 -7
  195. astrbot/core/provider/sources/sensevoice_selfhosted_source.py +13 -11
  196. astrbot/core/provider/sources/vllm_rerank_source.py +71 -0
  197. astrbot/core/provider/sources/volcengine_tts.py +115 -0
  198. astrbot/core/provider/sources/whisper_api_source.py +18 -13
  199. astrbot/core/provider/sources/whisper_selfhosted_source.py +19 -12
  200. astrbot/core/provider/sources/xinference_rerank_source.py +116 -0
  201. astrbot/core/provider/sources/xinference_stt_provider.py +197 -0
  202. astrbot/core/provider/sources/zhipu_source.py +6 -73
  203. astrbot/core/star/__init__.py +43 -11
  204. astrbot/core/star/config.py +17 -18
  205. astrbot/core/star/context.py +362 -138
  206. astrbot/core/star/filter/__init__.py +4 -3
  207. astrbot/core/star/filter/command.py +111 -35
  208. astrbot/core/star/filter/command_group.py +46 -34
  209. astrbot/core/star/filter/custom_filter.py +6 -5
  210. astrbot/core/star/filter/event_message_type.py +4 -2
  211. astrbot/core/star/filter/permission.py +4 -2
  212. astrbot/core/star/filter/platform_adapter_type.py +45 -12
  213. astrbot/core/star/filter/regex.py +4 -2
  214. astrbot/core/star/register/__init__.py +19 -15
  215. astrbot/core/star/register/star.py +41 -13
  216. astrbot/core/star/register/star_handler.py +236 -86
  217. astrbot/core/star/session_llm_manager.py +280 -0
  218. astrbot/core/star/session_plugin_manager.py +170 -0
  219. astrbot/core/star/star.py +36 -43
  220. astrbot/core/star/star_handler.py +47 -85
  221. astrbot/core/star/star_manager.py +442 -260
  222. astrbot/core/star/star_tools.py +167 -45
  223. astrbot/core/star/updator.py +17 -20
  224. astrbot/core/umop_config_router.py +106 -0
  225. astrbot/core/updator.py +38 -13
  226. astrbot/core/utils/astrbot_path.py +39 -0
  227. astrbot/core/utils/command_parser.py +1 -1
  228. astrbot/core/utils/io.py +119 -60
  229. astrbot/core/utils/log_pipe.py +1 -1
  230. astrbot/core/utils/metrics.py +11 -10
  231. astrbot/core/utils/migra_helper.py +73 -0
  232. astrbot/core/utils/path_util.py +63 -62
  233. astrbot/core/utils/pip_installer.py +37 -15
  234. astrbot/core/utils/session_lock.py +29 -0
  235. astrbot/core/utils/session_waiter.py +19 -20
  236. astrbot/core/utils/shared_preferences.py +174 -34
  237. astrbot/core/utils/t2i/__init__.py +4 -1
  238. astrbot/core/utils/t2i/local_strategy.py +386 -238
  239. astrbot/core/utils/t2i/network_strategy.py +109 -49
  240. astrbot/core/utils/t2i/renderer.py +29 -14
  241. astrbot/core/utils/t2i/template/astrbot_powershell.html +184 -0
  242. astrbot/core/utils/t2i/template_manager.py +111 -0
  243. astrbot/core/utils/tencent_record_helper.py +115 -1
  244. astrbot/core/utils/version_comparator.py +10 -13
  245. astrbot/core/zip_updator.py +112 -65
  246. astrbot/dashboard/routes/__init__.py +20 -13
  247. astrbot/dashboard/routes/auth.py +20 -9
  248. astrbot/dashboard/routes/chat.py +297 -141
  249. astrbot/dashboard/routes/config.py +652 -55
  250. astrbot/dashboard/routes/conversation.py +107 -37
  251. astrbot/dashboard/routes/file.py +26 -0
  252. astrbot/dashboard/routes/knowledge_base.py +1244 -0
  253. astrbot/dashboard/routes/log.py +27 -2
  254. astrbot/dashboard/routes/persona.py +202 -0
  255. astrbot/dashboard/routes/plugin.py +197 -139
  256. astrbot/dashboard/routes/route.py +27 -7
  257. astrbot/dashboard/routes/session_management.py +354 -0
  258. astrbot/dashboard/routes/stat.py +85 -18
  259. astrbot/dashboard/routes/static_file.py +5 -2
  260. astrbot/dashboard/routes/t2i.py +233 -0
  261. astrbot/dashboard/routes/tools.py +184 -120
  262. astrbot/dashboard/routes/update.py +59 -36
  263. astrbot/dashboard/server.py +96 -36
  264. astrbot/dashboard/utils.py +165 -0
  265. astrbot-4.7.0.dist-info/METADATA +294 -0
  266. astrbot-4.7.0.dist-info/RECORD +274 -0
  267. {astrbot-3.5.6.dist-info → astrbot-4.7.0.dist-info}/WHEEL +1 -1
  268. astrbot/core/db/plugin/sqlite_impl.py +0 -112
  269. astrbot/core/db/sqlite_init.sql +0 -50
  270. astrbot/core/pipeline/platform_compatibility/stage.py +0 -56
  271. astrbot/core/pipeline/process_stage/method/llm_request.py +0 -606
  272. astrbot/core/platform/sources/gewechat/client.py +0 -806
  273. astrbot/core/platform/sources/gewechat/downloader.py +0 -55
  274. astrbot/core/platform/sources/gewechat/gewechat_event.py +0 -255
  275. astrbot/core/platform/sources/gewechat/gewechat_platform_adapter.py +0 -103
  276. astrbot/core/platform/sources/gewechat/xml_data_parser.py +0 -110
  277. astrbot/core/provider/sources/dashscope_source.py +0 -203
  278. astrbot/core/provider/sources/dify_source.py +0 -281
  279. astrbot/core/provider/sources/llmtuner_source.py +0 -132
  280. astrbot/core/rag/embedding/openai_source.py +0 -20
  281. astrbot/core/rag/knowledge_db_mgr.py +0 -94
  282. astrbot/core/rag/store/__init__.py +0 -9
  283. astrbot/core/rag/store/chroma_db.py +0 -42
  284. astrbot/core/utils/dify_api_client.py +0 -152
  285. astrbot-3.5.6.dist-info/METADATA +0 -249
  286. astrbot-3.5.6.dist-info/RECORD +0 -158
  287. {astrbot-3.5.6.dist-info → astrbot-4.7.0.dist-info}/entry_points.txt +0 -0
  288. {astrbot-3.5.6.dist-info → astrbot-4.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,196 @@
1
+ """The MIT License (MIT)
2
+
3
+ Copyright (c) 2014-2020 messense
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ """
23
+
24
+ from optionaldict import optionaldict
25
+ from wechatpy.client.api.base import BaseWeChatAPI
26
+
27
+
28
+ class WeChatKFMessage(BaseWeChatAPI):
29
+ """发送微信客服消息
30
+
31
+ https://work.weixin.qq.com/api/doc/90000/90135/94677
32
+
33
+ 支持:
34
+ * 文本消息
35
+ * 图片消息
36
+ * 语音消息
37
+ * 视频消息
38
+ * 文件消息
39
+ * 图文链接
40
+ * 小程序
41
+ * 菜单消息
42
+ * 地理位置
43
+ """
44
+
45
+ def send(self, user_id, open_kfid, msgid="", msg=None):
46
+ """当微信客户处于“新接入待处理”或“由智能助手接待”状态下,可调用该接口给用户发送消息。
47
+ 注意仅当微信客户在主动发送消息给客服后的48小时内,企业可发送消息给客户,最多可发送5条消息;若用户继续发送消息,企业可再次下发消息。
48
+ 支持发送消息类型:文本、图片、语音、视频、文件、图文、小程序、菜单消息、地理位置。
49
+
50
+ :param user_id: 指定接收消息的客户UserID
51
+ :param open_kfid: 指定发送消息的客服帐号ID
52
+ :param msgid: 指定消息ID
53
+ :param tag_ids: 标签ID列表。
54
+ :param msg: 发送消息的 dict 对象
55
+ :type msg: dict | None
56
+ :return: 接口调用结果
57
+ """
58
+ msg = msg or {}
59
+ data = {
60
+ "touser": user_id,
61
+ "open_kfid": open_kfid,
62
+ }
63
+ if msgid:
64
+ data["msgid"] = msgid
65
+ data.update(msg)
66
+ return self._post("kf/send_msg", data=data)
67
+
68
+ def send_text(self, user_id, open_kfid, content, msgid=""):
69
+ return self.send(
70
+ user_id,
71
+ open_kfid,
72
+ msgid,
73
+ msg={"msgtype": "text", "text": {"content": content}},
74
+ )
75
+
76
+ def send_image(self, user_id, open_kfid, media_id, msgid=""):
77
+ return self.send(
78
+ user_id,
79
+ open_kfid,
80
+ msgid,
81
+ msg={"msgtype": "image", "image": {"media_id": media_id}},
82
+ )
83
+
84
+ def send_voice(self, user_id, open_kfid, media_id, msgid=""):
85
+ return self.send(
86
+ user_id,
87
+ open_kfid,
88
+ msgid,
89
+ msg={"msgtype": "voice", "voice": {"media_id": media_id}},
90
+ )
91
+
92
+ def send_video(self, user_id, open_kfid, media_id, msgid=""):
93
+ video_data = optionaldict()
94
+ video_data["media_id"] = media_id
95
+
96
+ return self.send(
97
+ user_id,
98
+ open_kfid,
99
+ msgid,
100
+ msg={"msgtype": "video", "video": dict(video_data)},
101
+ )
102
+
103
+ def send_file(self, user_id, open_kfid, media_id, msgid=""):
104
+ return self.send(
105
+ user_id,
106
+ open_kfid,
107
+ msgid,
108
+ msg={"msgtype": "file", "file": {"media_id": media_id}},
109
+ )
110
+
111
+ def send_articles_link(self, user_id, open_kfid, article, msgid=""):
112
+ articles_data = {
113
+ "title": article["title"],
114
+ "desc": article["desc"],
115
+ "url": article["url"],
116
+ "thumb_media_id": article["thumb_media_id"],
117
+ }
118
+ return self.send(
119
+ user_id,
120
+ open_kfid,
121
+ msgid,
122
+ msg={"msgtype": "news", "link": {"link": articles_data}},
123
+ )
124
+
125
+ def send_msgmenu(
126
+ self,
127
+ user_id,
128
+ open_kfid,
129
+ head_content,
130
+ menu_list,
131
+ tail_content,
132
+ msgid="",
133
+ ):
134
+ return self.send(
135
+ user_id,
136
+ open_kfid,
137
+ msgid,
138
+ msg={
139
+ "msgtype": "msgmenu",
140
+ "msgmenu": {
141
+ "head_content": head_content,
142
+ "list": menu_list,
143
+ "tail_content": tail_content,
144
+ },
145
+ },
146
+ )
147
+
148
+ def send_location(
149
+ self,
150
+ user_id,
151
+ open_kfid,
152
+ name,
153
+ address,
154
+ latitude,
155
+ longitude,
156
+ msgid="",
157
+ ):
158
+ return self.send(
159
+ user_id,
160
+ open_kfid,
161
+ msgid,
162
+ msg={
163
+ "msgtype": "location",
164
+ "msgmenu": {
165
+ "name": name,
166
+ "address": address,
167
+ "latitude": latitude,
168
+ "longitude": longitude,
169
+ },
170
+ },
171
+ )
172
+
173
+ def send_miniprogram(
174
+ self,
175
+ user_id,
176
+ open_kfid,
177
+ appid,
178
+ title,
179
+ thumb_media_id,
180
+ pagepath,
181
+ msgid="",
182
+ ):
183
+ return self.send(
184
+ user_id,
185
+ open_kfid,
186
+ msgid,
187
+ msg={
188
+ "msgtype": "miniprogram",
189
+ "msgmenu": {
190
+ "appid": appid,
191
+ "title": title,
192
+ "thumb_media_id": thumb_media_id,
193
+ "pagepath": pagepath,
194
+ },
195
+ },
196
+ )
@@ -0,0 +1,297 @@
1
+ #!/usr/bin/env python
2
+
3
+ """对企业微信发送给企业后台的消息加解密示例代码.
4
+ @copyright: Copyright (c) 1998-2020 Tencent Inc.
5
+
6
+ """
7
+ # ------------------------------------------------------------------------
8
+
9
+ import base64
10
+ import hashlib
11
+ import json
12
+ import logging
13
+ import secrets
14
+ import socket
15
+ import struct
16
+ import time
17
+
18
+ from Crypto.Cipher import AES
19
+
20
+ from . import ierror
21
+
22
+ """
23
+ 关于Crypto.Cipher模块,ImportError: No module named 'Crypto'解决方案
24
+ 请到官方网站 https://www.dlitz.net/software/pycrypto/ 下载pycrypto。
25
+ 下载后,按照README中的“Installation”小节的提示进行pycrypto安装。
26
+ """
27
+
28
+
29
+ class FormatException(Exception):
30
+ pass
31
+
32
+
33
+ def throw_exception(message, exception_class=FormatException):
34
+ """My define raise exception function"""
35
+ raise exception_class(message)
36
+
37
+
38
+ class SHA1:
39
+ """计算企业微信的消息签名接口"""
40
+
41
+ def getSHA1(self, token, timestamp, nonce, encrypt):
42
+ """用SHA1算法生成安全签名
43
+ @param token: 票据
44
+ @param timestamp: 时间戳
45
+ @param encrypt: 密文
46
+ @param nonce: 随机字符串
47
+ @return: 安全签名
48
+ """
49
+ try:
50
+ # 确保所有输入都是字符串类型
51
+ if isinstance(encrypt, bytes):
52
+ encrypt = encrypt.decode("utf-8")
53
+
54
+ sortlist = [str(token), str(timestamp), str(nonce), str(encrypt)]
55
+ sortlist.sort()
56
+ sha = hashlib.sha1()
57
+ sha.update("".join(sortlist).encode("utf-8"))
58
+ return ierror.WXBizMsgCrypt_OK, sha.hexdigest()
59
+
60
+ except Exception as e:
61
+ print(e)
62
+ return ierror.WXBizMsgCrypt_ComputeSignature_Error, None
63
+
64
+
65
+ class JsonParse:
66
+ """提供提取消息格式中的密文及生成回复消息格式的接口"""
67
+
68
+ # json消息模板
69
+ AES_TEXT_RESPONSE_TEMPLATE = """{
70
+ "encrypt": "%(msg_encrypt)s",
71
+ "msgsignature": "%(msg_signaturet)s",
72
+ "timestamp": "%(timestamp)s",
73
+ "nonce": "%(nonce)s"
74
+ }"""
75
+
76
+ def extract(self, jsontext):
77
+ """提取出json数据包中的加密消息
78
+ @param jsontext: 待提取的json字符串
79
+ @return: 提取出的加密消息字符串
80
+ """
81
+ try:
82
+ json_dict = json.loads(jsontext)
83
+ return ierror.WXBizMsgCrypt_OK, json_dict["encrypt"]
84
+ except Exception as e:
85
+ print(e)
86
+ return ierror.WXBizMsgCrypt_ParseJson_Error, None
87
+
88
+ def generate(self, encrypt, signature, timestamp, nonce):
89
+ """生成json消息
90
+ @param encrypt: 加密后的消息密文
91
+ @param signature: 安全签名
92
+ @param timestamp: 时间戳
93
+ @param nonce: 随机字符串
94
+ @return: 生成的json字符串
95
+ """
96
+ resp_dict = {
97
+ "msg_encrypt": encrypt,
98
+ "msg_signaturet": signature,
99
+ "timestamp": timestamp,
100
+ "nonce": nonce,
101
+ }
102
+ resp_json = self.AES_TEXT_RESPONSE_TEMPLATE % resp_dict
103
+ return resp_json
104
+
105
+
106
+ class PKCS7Encoder:
107
+ """提供基于PKCS7算法的加解密接口"""
108
+
109
+ block_size = 32
110
+
111
+ def encode(self, text):
112
+ """对需要加密的明文进行填充补位
113
+ @param text: 需要进行填充补位操作的明文(bytes类型)
114
+ @return: 补齐明文字符串(bytes类型)
115
+ """
116
+ text_length = len(text)
117
+ # 计算需要填充的位数
118
+ amount_to_pad = self.block_size - (text_length % self.block_size)
119
+ if amount_to_pad == 0:
120
+ amount_to_pad = self.block_size
121
+ # 获得补位所用的字符
122
+ pad = bytes([amount_to_pad])
123
+ # 确保text是bytes类型
124
+ if isinstance(text, str):
125
+ text = text.encode("utf-8")
126
+ return text + pad * amount_to_pad
127
+
128
+ def decode(self, decrypted):
129
+ """删除解密后明文的补位字符
130
+ @param decrypted: 解密后的明文
131
+ @return: 删除补位字符后的明文
132
+ """
133
+ pad = ord(decrypted[-1])
134
+ if pad < 1 or pad > 32:
135
+ pad = 0
136
+ return decrypted[:-pad]
137
+
138
+
139
+ class Prpcrypt:
140
+ """提供接收和推送给企业微信消息的加解密接口"""
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
+
148
+ def __init__(self, key):
149
+ # self.key = base64.b64decode(key+"=")
150
+ self.key = key
151
+ # 设置加解密模式为AES的CBC模式
152
+ self.mode = AES.MODE_CBC
153
+
154
+ def encrypt(self, text, receiveid):
155
+ """对明文进行加密
156
+ @param text: 需要加密的明文
157
+ @return: 加密得到的字符串
158
+ """
159
+ # 16位随机字符串添加到明文开头
160
+ text = text.encode()
161
+ text = (
162
+ self.get_random_str()
163
+ + struct.pack("I", socket.htonl(len(text)))
164
+ + text
165
+ + receiveid.encode()
166
+ )
167
+
168
+ # 使用自定义的填充方式对明文进行补位填充
169
+ pkcs7 = PKCS7Encoder()
170
+ text = pkcs7.encode(text)
171
+ # 加密
172
+ cryptor = AES.new(self.key, self.mode, self.key[:16]) # type: ignore
173
+ try:
174
+ ciphertext = cryptor.encrypt(text)
175
+ # 使用BASE64对加密后的字符串进行编码
176
+ return ierror.WXBizMsgCrypt_OK, base64.b64encode(ciphertext)
177
+ except Exception as e:
178
+ logger = logging.getLogger("astrbot")
179
+ logger.error(e)
180
+ return ierror.WXBizMsgCrypt_EncryptAES_Error, None
181
+
182
+ def decrypt(self, text, receiveid):
183
+ """对解密后的明文进行补位删除
184
+ @param text: 密文
185
+ @return: 删除填充补位后的明文
186
+ """
187
+ try:
188
+ cryptor = AES.new(self.key, self.mode, self.key[:16]) # type: ignore
189
+ # 使用BASE64对密文进行解码,然后AES-CBC解密
190
+ plain_text = cryptor.decrypt(base64.b64decode(text))
191
+ except Exception as e:
192
+ print(e)
193
+ return ierror.WXBizMsgCrypt_DecryptAES_Error, None
194
+ try:
195
+ pad = plain_text[-1]
196
+ # 去掉补位字符串
197
+ # pkcs7 = PKCS7Encoder()
198
+ # plain_text = pkcs7.encode(plain_text)
199
+ # 去除16位随机字符串
200
+ content = plain_text[16:-pad]
201
+ json_len = socket.ntohl(struct.unpack("I", content[:4])[0])
202
+ json_content = content[4 : json_len + 4].decode("utf-8")
203
+ from_receiveid = content[json_len + 4 :].decode("utf-8")
204
+ except Exception as e:
205
+ print(e)
206
+ return ierror.WXBizMsgCrypt_IllegalBuffer, None
207
+ if from_receiveid != receiveid:
208
+ print("receiveid not match", receiveid, from_receiveid)
209
+ return ierror.WXBizMsgCrypt_ValidateCorpid_Error, None
210
+ return 0, json_content
211
+
212
+ def get_random_str(self):
213
+ """随机生成16位字符串
214
+ @return: 16位字符串
215
+ """
216
+ return str(
217
+ secrets.randbelow(self.RANDOM_RANGE) + self.MIN_RANDOM_VALUE
218
+ ).encode()
219
+
220
+
221
+ class WXBizJsonMsgCrypt:
222
+ # 构造函数
223
+ def __init__(self, sToken, sEncodingAESKey, sReceiveId):
224
+ try:
225
+ self.key = base64.b64decode(sEncodingAESKey + "=")
226
+ assert len(self.key) == 32
227
+ except Exception as e:
228
+ throw_exception(f"[error]: EncodingAESKey invalid: {e}", FormatException)
229
+ # return ierror.WXBizMsgCrypt_IllegalAesKey,None
230
+ self.m_sToken = sToken
231
+ self.m_sReceiveId = sReceiveId
232
+
233
+ # 验证URL
234
+ # @param sMsgSignature: 签名串,对应URL参数的msg_signature
235
+ # @param sTimeStamp: 时间戳,对应URL参数的timestamp
236
+ # @param sNonce: 随机串,对应URL参数的nonce
237
+ # @param sEchoStr: 随机串,对应URL参数的echostr
238
+ # @param sReplyEchoStr: 解密之后的echostr,当return返回0时有效
239
+ # @return:成功0,失败返回对应的错误码
240
+
241
+ def VerifyURL(self, sMsgSignature, sTimeStamp, sNonce, sEchoStr):
242
+ sha1 = SHA1()
243
+ ret, signature = sha1.getSHA1(self.m_sToken, sTimeStamp, sNonce, sEchoStr)
244
+ if ret != 0:
245
+ return ret, None
246
+ if not signature == sMsgSignature:
247
+ return ierror.WXBizMsgCrypt_ValidateSignature_Error, None
248
+ pc = Prpcrypt(self.key)
249
+ ret, sReplyEchoStr = pc.decrypt(sEchoStr, self.m_sReceiveId)
250
+ return ret, sReplyEchoStr
251
+
252
+ def EncryptMsg(self, sReplyMsg, sNonce, timestamp=None):
253
+ # 将企业回复用户的消息加密打包
254
+ # @param sReplyMsg: 企业号待回复用户的消息,json格式的字符串
255
+ # @param sTimeStamp: 时间戳,可以自己生成,也可以用URL参数的timestamp,如为None则自动用当前时间
256
+ # @param sNonce: 随机串,可以自己生成,也可以用URL参数的nonce
257
+ # sEncryptMsg: 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的json格式的字符串,
258
+ # return:成功0,sEncryptMsg,失败返回对应的错误码None
259
+ pc = Prpcrypt(self.key)
260
+ ret, encrypt = pc.encrypt(sReplyMsg, self.m_sReceiveId)
261
+ encrypt = encrypt.decode("utf-8") # type: ignore
262
+ if ret != 0:
263
+ return ret, None
264
+ if timestamp is None:
265
+ timestamp = str(int(time.time()))
266
+ # 生成安全签名
267
+ sha1 = SHA1()
268
+ ret, signature = sha1.getSHA1(self.m_sToken, timestamp, sNonce, encrypt)
269
+ if ret != 0:
270
+ return ret, None
271
+ jsonParse = JsonParse()
272
+ return ret, jsonParse.generate(encrypt, signature, timestamp, sNonce)
273
+
274
+ def DecryptMsg(self, sPostData, sMsgSignature, sTimeStamp, sNonce):
275
+ # 检验消息的真实性,并且获取解密后的明文
276
+ # @param sMsgSignature: 签名串,对应URL参数的msg_signature
277
+ # @param sTimeStamp: 时间戳,对应URL参数的timestamp
278
+ # @param sNonce: 随机串,对应URL参数的nonce
279
+ # @param sPostData: 密文,对应POST请求的数据
280
+ # json_content: 解密后的原文,当return返回0时有效
281
+ # @return: 成功0,失败返回对应的错误码
282
+ # 验证安全签名
283
+ jsonParse = JsonParse()
284
+ ret, encrypt = jsonParse.extract(sPostData)
285
+ if ret != 0:
286
+ return ret, None
287
+ sha1 = SHA1()
288
+ ret, signature = sha1.getSHA1(self.m_sToken, sTimeStamp, sNonce, encrypt)
289
+ if ret != 0:
290
+ return ret, None
291
+ if not signature == sMsgSignature:
292
+ print("signature not match")
293
+ print(signature)
294
+ return ierror.WXBizMsgCrypt_ValidateSignature_Error, None
295
+ pc = Prpcrypt(self.key)
296
+ ret, json_content = pc.decrypt(encrypt, self.m_sReceiveId)
297
+ return ret, json_content
@@ -0,0 +1,15 @@
1
+ """企业微信智能机器人平台适配器包"""
2
+
3
+ from .wecomai_adapter import WecomAIBotAdapter
4
+ from .wecomai_api import WecomAIBotAPIClient
5
+ from .wecomai_event import WecomAIBotMessageEvent
6
+ from .wecomai_server import WecomAIBotServer
7
+ from .wecomai_utils import WecomAIBotConstants
8
+
9
+ __all__ = [
10
+ "WecomAIBotAPIClient",
11
+ "WecomAIBotAdapter",
12
+ "WecomAIBotConstants",
13
+ "WecomAIBotMessageEvent",
14
+ "WecomAIBotServer",
15
+ ]
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env python
2
+ #########################################################################
3
+ # Author: jonyqin
4
+ # Created Time: Thu 11 Sep 2014 01:53:58 PM CST
5
+ # File Name: ierror.py
6
+ # Description:定义错误码含义
7
+ #########################################################################
8
+ WXBizMsgCrypt_OK = 0
9
+ WXBizMsgCrypt_ValidateSignature_Error = -40001
10
+ WXBizMsgCrypt_ParseJson_Error = -40002
11
+ WXBizMsgCrypt_ComputeSignature_Error = -40003
12
+ WXBizMsgCrypt_IllegalAesKey = -40004
13
+ WXBizMsgCrypt_ValidateCorpid_Error = -40005
14
+ WXBizMsgCrypt_EncryptAES_Error = -40006
15
+ WXBizMsgCrypt_DecryptAES_Error = -40007
16
+ WXBizMsgCrypt_IllegalBuffer = -40008
17
+ WXBizMsgCrypt_EncodeBase64_Error = -40009
18
+ WXBizMsgCrypt_DecodeBase64_Error = -40010
19
+ WXBizMsgCrypt_GenReturnJson_Error = -40011