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
@@ -38,15 +38,15 @@ class VersionComparator:
38
38
  for i in range(length):
39
39
  if v1_parts[i] > v2_parts[i]:
40
40
  return 1
41
- elif v1_parts[i] < v2_parts[i]:
41
+ if v1_parts[i] < v2_parts[i]:
42
42
  return -1
43
43
 
44
44
  # 比较预发布标签
45
45
  if v1_prerelease is None and v2_prerelease is not None:
46
46
  return 1 # 没有预发布标签的版本高于有预发布标签的版本
47
- elif v1_prerelease is not None and v2_prerelease is None:
47
+ if v1_prerelease is not None and v2_prerelease is None:
48
48
  return -1 # 有预发布标签的版本低于没有预发布标签的版本
49
- elif v1_prerelease is not None and v2_prerelease is not None:
49
+ if v1_prerelease is not None and v2_prerelease is not None:
50
50
  len_pre = max(len(v1_prerelease), len(v2_prerelease))
51
51
  for i in range(len_pre):
52
52
  p1 = v1_prerelease[i] if i < len(v1_prerelease) else None
@@ -54,21 +54,18 @@ class VersionComparator:
54
54
 
55
55
  if p1 is None and p2 is not None:
56
56
  return -1
57
- elif p1 is not None and p2 is None:
57
+ if p1 is not None and p2 is None:
58
58
  return 1
59
- elif isinstance(p1, int) and isinstance(p2, str):
59
+ if isinstance(p1, int) and isinstance(p2, str):
60
60
  return -1
61
- elif isinstance(p1, str) and isinstance(p2, int):
61
+ if isinstance(p1, str) and isinstance(p2, int):
62
62
  return 1
63
- elif isinstance(p1, int) and isinstance(p2, int):
63
+ if (isinstance(p1, int) and isinstance(p2, int)) or (
64
+ isinstance(p1, str) and isinstance(p2, str)
65
+ ):
64
66
  if p1 > p2:
65
67
  return 1
66
- elif p1 < p2:
67
- return -1
68
- elif isinstance(p1, str) and isinstance(p2, str):
69
- if p1 > p2:
70
- return 1
71
- elif p1 < p2:
68
+ if p1 < p2:
72
69
  return -1
73
70
  return 0 # 预发布标签完全相同
74
71
 
@@ -1,13 +1,14 @@
1
- import aiohttp
2
1
  import os
3
- import zipfile
2
+ import re
4
3
  import shutil
5
-
6
4
  import ssl
5
+ import zipfile
6
+
7
+ import aiohttp
7
8
  import certifi
8
9
 
9
- from astrbot.core.utils.io import on_error, download_file
10
10
  from astrbot.core import logger
11
+ from astrbot.core.utils.io import download_file, on_error
11
12
  from astrbot.core.utils.version_comparator import VersionComparator
12
13
 
13
14
 
@@ -17,7 +18,10 @@ class ReleaseInfo:
17
18
  body: str
18
19
 
19
20
  def __init__(
20
- self, version: str = "", published_at: str = "", body: str = ""
21
+ self,
22
+ version: str = "",
23
+ published_at: str = "",
24
+ body: str = "",
21
25
  ) -> None:
22
26
  self.version = version
23
27
  self.published_at = published_at
@@ -33,29 +37,31 @@ class RepoZipUpdator:
33
37
  self.rm_on_error = on_error
34
38
 
35
39
  async def fetch_release_info(self, url: str, latest: bool = True) -> list:
36
- """
37
- 请求版本信息。
40
+ """请求版本信息。
38
41
  返回一个列表,每个元素是一个字典,包含版本号、发布时间、更新内容、commit hash等信息。
39
42
  """
40
43
  try:
41
44
  ssl_context = ssl.create_default_context(
42
- cafile=certifi.where()
45
+ cafile=certifi.where(),
43
46
  ) # 新增:创建基于 certifi 的 SSL 上下文
44
47
  connector = aiohttp.TCPConnector(
45
- ssl=ssl_context
48
+ ssl=ssl_context,
46
49
  ) # 新增:使用 TCPConnector 指定 SSL 上下文
47
- async with aiohttp.ClientSession(
48
- trust_env=True, connector=connector
49
- ) as session:
50
- async with session.get(url) as response:
51
- # 检查 HTTP 状态码
52
- if response.status != 200:
53
- text = await response.text()
54
- logger.error(
55
- f"请求 {url} 失败,状态码: {response.status}, 内容: {text}"
56
- )
57
- raise Exception(f"请求失败,状态码: {response.status}")
58
- result = await response.json()
50
+ async with (
51
+ aiohttp.ClientSession(
52
+ trust_env=True,
53
+ connector=connector,
54
+ ) as session,
55
+ session.get(url) as response,
56
+ ):
57
+ # 检查 HTTP 状态码
58
+ if response.status != 200:
59
+ text = await response.text()
60
+ logger.error(
61
+ f"请求 {url} 失败,状态码: {response.status}, 内容: {text}",
62
+ )
63
+ raise Exception(f"请求失败,状态码: {response.status}")
64
+ result = await response.json()
59
65
  if not result:
60
66
  return []
61
67
  # if latest:
@@ -71,7 +77,7 @@ class RepoZipUpdator:
71
77
  "body": release["body"],
72
78
  "tag_name": release["tag_name"],
73
79
  "zipball_url": release["zipball_url"],
74
- }
80
+ },
75
81
  )
76
82
  except Exception as e:
77
83
  logger.error(f"解析版本信息时发生异常: {e}")
@@ -79,8 +85,7 @@ class RepoZipUpdator:
79
85
  return ret
80
86
 
81
87
  def github_api_release_parser(self, releases: list) -> list:
82
- """
83
- 解析 GitHub API 返回的 releases 信息。
88
+ """解析 GitHub API 返回的 releases 信息。
84
89
  返回一个列表,每个元素是一个字典,包含版本号、发布时间、更新内容、commit hash等信息。
85
90
  """
86
91
  ret = []
@@ -92,98 +97,140 @@ class RepoZipUpdator:
92
97
  "body": release["body"],
93
98
  "tag_name": release["tag_name"],
94
99
  "zipball_url": release["zipball_url"],
95
- }
100
+ },
96
101
  )
97
102
  return ret
98
103
 
99
104
  def unzip(self):
100
- raise NotImplementedError()
105
+ raise NotImplementedError
101
106
 
102
107
  async def update(self):
103
- raise NotImplementedError()
108
+ raise NotImplementedError
104
109
 
105
110
  def compare_version(self, v1: str, v2: str) -> int:
106
111
  """Semver 版本比较"""
107
112
  return VersionComparator.compare_version(v1, v2)
108
113
 
109
- async def check_update(self, url: str, current_version: str) -> ReleaseInfo | None:
114
+ async def check_update(
115
+ self,
116
+ url: str,
117
+ current_version: str,
118
+ consider_prerelease: bool = True,
119
+ ) -> ReleaseInfo | None:
110
120
  update_data = await self.fetch_release_info(url)
111
- tag_name = update_data[0]["tag_name"]
121
+
122
+ sel_release_data = None
123
+ if consider_prerelease:
124
+ tag_name = update_data[0]["tag_name"]
125
+ sel_release_data = update_data[0]
126
+ else:
127
+ for data in update_data:
128
+ # 跳过带有 alpha、beta 等预发布标签的版本
129
+ if re.search(
130
+ r"[\-_.]?(alpha|beta|rc|dev)[\-_.]?\d*$",
131
+ data["tag_name"],
132
+ re.IGNORECASE,
133
+ ):
134
+ continue
135
+ tag_name = data["tag_name"]
136
+ sel_release_data = data
137
+ break
138
+
139
+ if not sel_release_data or not tag_name:
140
+ logger.error("未找到合适的发布版本")
141
+ return None
112
142
 
113
143
  if self.compare_version(current_version, tag_name) >= 0:
114
144
  return None
115
145
  return ReleaseInfo(
116
146
  version=tag_name,
117
- published_at=update_data[0]["published_at"],
118
- body=update_data[0]["body"],
147
+ published_at=sel_release_data["published_at"],
148
+ body=f"{tag_name}\n\n{sel_release_data['body']}",
119
149
  )
120
150
 
121
151
  async def download_from_repo_url(self, target_path: str, repo_url: str, proxy=""):
122
- repo_namespace = repo_url.split("/")[-2:]
123
- author = repo_namespace[0]
124
- repo = repo_namespace[1]
152
+ author, repo, branch = self.parse_github_url(repo_url)
125
153
 
126
154
  logger.info(f"正在下载更新 {repo} ...")
127
- release_url = f"https://api.github.com/repos/{author}/{repo}/releases"
128
- releases = await self.fetch_release_info(url=release_url)
129
- if not releases:
130
- # download from the default branch directly.
131
- logger.info(f"正在从默认分支下载 {author}/{repo} ")
155
+
156
+ if branch:
157
+ logger.info(f"正在从指定分支 {branch} 下载 {author}/{repo}")
132
158
  release_url = (
133
- f"https://github.com/{author}/{repo}/archive/refs/heads/master.zip"
159
+ f"https://github.com/{author}/{repo}/archive/refs/heads/{branch}.zip"
134
160
  )
135
161
  else:
136
- release_url = releases[0]["zipball_url"]
162
+ try:
163
+ release_url = f"https://api.github.com/repos/{author}/{repo}/releases"
164
+ releases = await self.fetch_release_info(url=release_url)
165
+ except Exception as e:
166
+ logger.warning(
167
+ f"获取 {author}/{repo} 的 GitHub Releases 失败: {e},将尝试下载默认分支",
168
+ )
169
+ releases = []
170
+ if not releases:
171
+ # 如果没有最新版本,下载默认分支
172
+ logger.info(f"正在从默认分支下载 {author}/{repo}")
173
+ release_url = (
174
+ f"https://github.com/{author}/{repo}/archive/refs/heads/master.zip"
175
+ )
176
+ else:
177
+ release_url = releases[0]["zipball_url"]
137
178
 
138
179
  if proxy:
180
+ proxy = proxy.rstrip("/")
139
181
  release_url = f"{proxy}/{release_url}"
140
- logger.info(f"使用代理下载: {release_url}")
182
+ logger.info(
183
+ f"检查到设置了镜像站,将使用镜像站下载 {author}/{repo} 仓库源码: {release_url}",
184
+ )
141
185
 
142
186
  await download_file(release_url, target_path + ".zip")
143
187
 
144
- def unzip_file(self, zip_path: str, target_dir: str):
145
- """
146
- 解压缩文件, 并将压缩包内**第一个**文件夹内的文件移动到 target_dir
188
+ def parse_github_url(self, url: str):
189
+ """使用正则表达式解析 GitHub 仓库 URL,支持 `.git` 后缀和 `tree/branch` 结构
190
+ Returns:
191
+ tuple[str, str, str]: 返回作者名、仓库名和分支名
192
+ Raises:
193
+ ValueError: 如果 URL 格式不正确
147
194
  """
195
+ cleaned_url = url.rstrip("/")
196
+ pattern = r"^https://github\.com/([a-zA-Z0-9_-]+)/([a-zA-Z0-9_-]+)(\.git)?(?:/tree/([a-zA-Z0-9_-]+))?$"
197
+ match = re.match(pattern, cleaned_url)
198
+
199
+ if match:
200
+ author = match.group(1)
201
+ repo = match.group(2)
202
+ branch = match.group(4)
203
+ return author, repo, branch
204
+ raise ValueError("无效的 GitHub URL")
205
+
206
+ def unzip_file(self, zip_path: str, target_dir: str):
207
+ """解压缩文件, 并将压缩包内**第一个**文件夹内的文件移动到 target_dir"""
148
208
  os.makedirs(target_dir, exist_ok=True)
149
209
  update_dir = ""
150
- logger.info(f"解压文件: {zip_path}")
151
210
  with zipfile.ZipFile(zip_path, "r") as z:
152
211
  update_dir = z.namelist()[0]
153
212
  z.extractall(target_dir)
213
+ logger.debug(f"解压文件完成: {zip_path}")
154
214
 
155
215
  files = os.listdir(os.path.join(target_dir, update_dir))
156
216
  for f in files:
157
- logger.info(f"移动更新文件/目录: {f}")
158
217
  if os.path.isdir(os.path.join(target_dir, update_dir, f)):
159
218
  if os.path.exists(os.path.join(target_dir, f)):
160
219
  shutil.rmtree(os.path.join(target_dir, f), onerror=on_error)
161
- else:
162
- if os.path.exists(os.path.join(target_dir, f)):
163
- os.remove(os.path.join(target_dir, f))
220
+ elif os.path.exists(os.path.join(target_dir, f)):
221
+ os.remove(os.path.join(target_dir, f))
164
222
  shutil.move(os.path.join(target_dir, update_dir, f), target_dir)
165
223
 
166
224
  try:
167
- logger.info(
168
- f"删除临时更新文件: {zip_path} 和 {os.path.join(target_dir, update_dir)}"
225
+ logger.debug(
226
+ f"删除临时更新文件: {zip_path} 和 {os.path.join(target_dir, update_dir)}",
169
227
  )
170
228
  shutil.rmtree(os.path.join(target_dir, update_dir), onerror=on_error)
171
229
  os.remove(zip_path)
172
230
  except BaseException:
173
- logger.warn(
174
- f"删除更新文件失败,可以手动删除 {zip_path} 和 {os.path.join(target_dir, update_dir)}"
231
+ logger.warning(
232
+ f"删除更新文件失败,可以手动删除 {zip_path} 和 {os.path.join(target_dir, update_dir)}",
175
233
  )
176
234
 
177
- def format_repo_name(self, repo_url: str) -> str:
178
- if repo_url.endswith("/"):
179
- repo_url = repo_url[:-1]
180
-
181
- repo_namespace = repo_url.split("/")[-2:]
182
- repo = repo_namespace[1]
183
-
184
- repo = self.format_name(repo)
185
-
186
- return repo
187
-
188
235
  def format_name(self, name: str) -> str:
189
236
  return name.replace("-", "_").lower()
@@ -1,24 +1,31 @@
1
1
  from .auth import AuthRoute
2
- from .plugin import PluginRoute
2
+ from .chat import ChatRoute
3
3
  from .config import ConfigRoute
4
- from .update import UpdateRoute
5
- from .stat import StatRoute
4
+ from .conversation import ConversationRoute
5
+ from .file import FileRoute
6
+ from .knowledge_base import KnowledgeBaseRoute
6
7
  from .log import LogRoute
8
+ from .persona import PersonaRoute
9
+ from .plugin import PluginRoute
10
+ from .session_management import SessionManagementRoute
11
+ from .stat import StatRoute
7
12
  from .static_file import StaticFileRoute
8
- from .chat import ChatRoute
9
- from .tools import ToolsRoute # 导入新的ToolsRoute
10
- from .conversation import ConversationRoute
11
-
13
+ from .tools import ToolsRoute
14
+ from .update import UpdateRoute
12
15
 
13
16
  __all__ = [
14
17
  "AuthRoute",
15
- "PluginRoute",
18
+ "ChatRoute",
16
19
  "ConfigRoute",
17
- "UpdateRoute",
18
- "StatRoute",
20
+ "ConversationRoute",
21
+ "FileRoute",
22
+ "KnowledgeBaseRoute",
19
23
  "LogRoute",
24
+ "PersonaRoute",
25
+ "PluginRoute",
26
+ "SessionManagementRoute",
27
+ "StatRoute",
20
28
  "StaticFileRoute",
21
- "ChatRoute",
22
- "ToolsRoute", # 添加新的ToolsRoute
23
- "ConversationRoute",
29
+ "ToolsRoute",
30
+ "UpdateRoute",
24
31
  ]
@@ -1,9 +1,13 @@
1
- import jwt
1
+ import asyncio
2
2
  import datetime
3
- from .route import Route, Response, RouteContext
3
+
4
+ import jwt
4
5
  from quart import request
5
- from astrbot.core import WEBUI_SK, DEMO_MODE
6
+
6
7
  from astrbot import logger
8
+ from astrbot.core import DEMO_MODE
9
+
10
+ from .route import Response, Route, RouteContext
7
11
 
8
12
 
9
13
  class AuthRoute(Route):
@@ -21,7 +25,11 @@ class AuthRoute(Route):
21
25
  post_data = await request.json
22
26
  if post_data["username"] == username and post_data["password"] == password:
23
27
  change_pwd_hint = False
24
- if username == "astrbot" and password == "77b90590a8945a7d36c963981a307dc9":
28
+ if (
29
+ username == "astrbot"
30
+ and password == "77b90590a8945a7d36c963981a307dc9"
31
+ and not DEMO_MODE
32
+ ):
25
33
  change_pwd_hint = True
26
34
  logger.warning("为了保证安全,请尽快修改默认密码。")
27
35
 
@@ -32,12 +40,12 @@ class AuthRoute(Route):
32
40
  "token": self.generate_jwt(username),
33
41
  "username": username,
34
42
  "change_pwd_hint": change_pwd_hint,
35
- }
43
+ },
36
44
  )
37
45
  .__dict__
38
46
  )
39
- else:
40
- return Response().error("用户名或密码错误").__dict__
47
+ await asyncio.sleep(3)
48
+ return Response().error("用户名或密码错误").__dict__
41
49
 
42
50
  async def edit_account(self):
43
51
  if DEMO_MODE:
@@ -72,7 +80,10 @@ class AuthRoute(Route):
72
80
  def generate_jwt(self, username):
73
81
  payload = {
74
82
  "username": username,
75
- "exp": datetime.datetime.utcnow() + datetime.timedelta(days=30),
83
+ "exp": datetime.datetime.utcnow() + datetime.timedelta(days=7),
76
84
  }
77
- token = jwt.encode(payload, WEBUI_SK, algorithm="HS256")
85
+ jwt_token = self.config["dashboard"].get("jwt_secret", None)
86
+ if not jwt_token:
87
+ raise ValueError("JWT secret is not set in the cmd_config.")
88
+ token = jwt.encode(payload, jwt_token, algorithm="HS256")
78
89
  return token