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
@@ -1,161 +1,364 @@
1
1
  import abc
2
+ import datetime
3
+ import typing as T
4
+ from contextlib import asynccontextmanager
2
5
  from dataclasses import dataclass
3
- from typing import List, Dict, Any, Tuple
4
- from astrbot.core.db.po import Stats, LLMHistory, ATRIVision, Conversation
6
+
7
+ from deprecated import deprecated
8
+ from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
9
+ from sqlalchemy.orm import sessionmaker
10
+
11
+ from astrbot.core.db.po import (
12
+ Attachment,
13
+ ConversationV2,
14
+ Persona,
15
+ PlatformMessageHistory,
16
+ PlatformSession,
17
+ PlatformStat,
18
+ Preference,
19
+ Stats,
20
+ )
5
21
 
6
22
 
7
23
  @dataclass
8
24
  class BaseDatabase(abc.ABC):
9
- """
10
- 数据库基类
11
- """
25
+ """数据库基类"""
26
+
27
+ DATABASE_URL = ""
12
28
 
13
29
  def __init__(self) -> None:
14
- pass
30
+ self.engine = create_async_engine(
31
+ self.DATABASE_URL,
32
+ echo=False,
33
+ future=True,
34
+ )
35
+ self.AsyncSessionLocal = sessionmaker(
36
+ self.engine,
37
+ class_=AsyncSession,
38
+ expire_on_commit=False,
39
+ )
15
40
 
16
- def insert_base_metrics(self, metrics: dict):
17
- """插入基础指标数据"""
18
- self.insert_platform_metrics(metrics["platform_stats"])
19
- self.insert_plugin_metrics(metrics["plugin_stats"])
20
- self.insert_command_metrics(metrics["command_stats"])
21
- self.insert_llm_metrics(metrics["llm_stats"])
41
+ async def initialize(self):
42
+ """初始化数据库连接"""
22
43
 
44
+ @asynccontextmanager
45
+ async def get_db(self) -> T.AsyncGenerator[AsyncSession, None]:
46
+ """Get a database session."""
47
+ if not self.inited:
48
+ await self.initialize()
49
+ self.inited = True
50
+ async with self.AsyncSessionLocal() as session:
51
+ yield session
52
+
53
+ @deprecated(version="4.0.0", reason="Use get_platform_stats instead")
23
54
  @abc.abstractmethod
24
- def insert_platform_metrics(self, metrics: dict):
25
- """插入平台指标数据"""
55
+ def get_base_stats(self, offset_sec: int = 86400) -> Stats:
56
+ """获取基础统计数据"""
26
57
  raise NotImplementedError
27
58
 
59
+ @deprecated(version="4.0.0", reason="Use get_platform_stats instead")
28
60
  @abc.abstractmethod
29
- def insert_plugin_metrics(self, metrics: dict):
30
- """插入插件指标数据"""
61
+ def get_total_message_count(self) -> int:
62
+ """获取总消息数"""
31
63
  raise NotImplementedError
32
64
 
65
+ @deprecated(version="4.0.0", reason="Use get_platform_stats instead")
33
66
  @abc.abstractmethod
34
- def insert_command_metrics(self, metrics: dict):
35
- """插入指令指标数据"""
67
+ def get_grouped_base_stats(self, offset_sec: int = 86400) -> Stats:
68
+ """获取基础统计数据(合并)"""
36
69
  raise NotImplementedError
37
70
 
71
+ # New methods in v4.0.0
72
+
38
73
  @abc.abstractmethod
39
- def insert_llm_metrics(self, metrics: dict):
40
- """插入 LLM 指标数据"""
41
- raise NotImplementedError
74
+ async def insert_platform_stats(
75
+ self,
76
+ platform_id: str,
77
+ platform_type: str,
78
+ count: int = 1,
79
+ timestamp: datetime.datetime | None = None,
80
+ ) -> None:
81
+ """Insert a new platform statistic record."""
82
+ ...
42
83
 
43
84
  @abc.abstractmethod
44
- def update_llm_history(self, session_id: str, content: str, provider_type: str):
45
- """更新 LLM 历史记录。当不存在 session_id 时插入"""
46
- raise NotImplementedError
85
+ async def count_platform_stats(self) -> int:
86
+ """Count the number of platform statistics records."""
87
+ ...
47
88
 
48
89
  @abc.abstractmethod
49
- def get_llm_history(
50
- self, session_id: str = None, provider_type: str = None
51
- ) -> List[LLMHistory]:
52
- """获取 LLM 历史记录, 如果 session_id 为 None, 返回所有"""
53
- raise NotImplementedError
90
+ async def get_platform_stats(self, offset_sec: int = 86400) -> list[PlatformStat]:
91
+ """Get platform statistics within the specified offset in seconds and group by platform_id."""
92
+ ...
54
93
 
55
94
  @abc.abstractmethod
56
- def get_base_stats(self, offset_sec: int = 86400) -> Stats:
57
- """获取基础统计数据"""
58
- raise NotImplementedError
95
+ async def get_conversations(
96
+ self,
97
+ user_id: str | None = None,
98
+ platform_id: str | None = None,
99
+ ) -> list[ConversationV2]:
100
+ """Get all conversations for a specific user and platform_id(optional).
101
+
102
+ content is not included in the result.
103
+ """
104
+ ...
59
105
 
60
106
  @abc.abstractmethod
61
- def get_total_message_count(self) -> int:
62
- """获取总消息数"""
63
- raise NotImplementedError
107
+ async def get_conversation_by_id(self, cid: str) -> ConversationV2:
108
+ """Get a specific conversation by its ID."""
109
+ ...
64
110
 
65
111
  @abc.abstractmethod
66
- def get_grouped_base_stats(self, offset_sec: int = 86400) -> Stats:
67
- """获取基础统计数据(合并)"""
68
- raise NotImplementedError
112
+ async def get_all_conversations(
113
+ self,
114
+ page: int = 1,
115
+ page_size: int = 20,
116
+ ) -> list[ConversationV2]:
117
+ """Get all conversations with pagination."""
118
+ ...
69
119
 
70
120
  @abc.abstractmethod
71
- def insert_atri_vision_data(self, vision_data: ATRIVision):
72
- """插入 ATRI 视觉数据"""
73
- raise NotImplementedError
121
+ async def get_filtered_conversations(
122
+ self,
123
+ page: int = 1,
124
+ page_size: int = 20,
125
+ platform_ids: list[str] | None = None,
126
+ search_query: str = "",
127
+ **kwargs,
128
+ ) -> tuple[list[ConversationV2], int]:
129
+ """Get conversations filtered by platform IDs and search query."""
130
+ ...
74
131
 
75
132
  @abc.abstractmethod
76
- def get_atri_vision_data(self) -> List[ATRIVision]:
77
- """获取 ATRI 视觉数据"""
78
- raise NotImplementedError
133
+ async def create_conversation(
134
+ self,
135
+ user_id: str,
136
+ platform_id: str,
137
+ content: list[dict] | None = None,
138
+ title: str | None = None,
139
+ persona_id: str | None = None,
140
+ cid: str | None = None,
141
+ created_at: datetime.datetime | None = None,
142
+ updated_at: datetime.datetime | None = None,
143
+ ) -> ConversationV2:
144
+ """Create a new conversation."""
145
+ ...
79
146
 
80
147
  @abc.abstractmethod
81
- def get_atri_vision_data_by_path_or_id(
82
- self, url_or_path: str, id: str
83
- ) -> ATRIVision:
84
- """通过 url path 获取 ATRI 视觉数据"""
85
- raise NotImplementedError
148
+ async def update_conversation(
149
+ self,
150
+ cid: str,
151
+ title: str | None = None,
152
+ persona_id: str | None = None,
153
+ content: list[dict] | None = None,
154
+ ) -> None:
155
+ """Update a conversation's history."""
156
+ ...
86
157
 
87
158
  @abc.abstractmethod
88
- def get_conversation_by_user_id(self, user_id: str, cid: str) -> Conversation:
89
- """通过 user_id cid 获取 Conversation"""
90
- raise NotImplementedError
159
+ async def delete_conversation(self, cid: str) -> None:
160
+ """Delete a conversation by its ID."""
161
+ ...
91
162
 
92
163
  @abc.abstractmethod
93
- def new_conversation(self, user_id: str, cid: str):
94
- """新建 Conversation"""
95
- raise NotImplementedError
164
+ async def delete_conversations_by_user_id(self, user_id: str) -> None:
165
+ """Delete all conversations for a specific user."""
166
+ ...
96
167
 
97
168
  @abc.abstractmethod
98
- def get_conversations(self, user_id: str) -> List[Conversation]:
99
- raise NotImplementedError
169
+ async def insert_platform_message_history(
170
+ self,
171
+ platform_id: str,
172
+ user_id: str,
173
+ content: dict,
174
+ sender_id: str | None = None,
175
+ sender_name: str | None = None,
176
+ ) -> None:
177
+ """Insert a new platform message history record."""
178
+ ...
100
179
 
101
180
  @abc.abstractmethod
102
- def update_conversation(self, user_id: str, cid: str, history: str):
103
- """更新 Conversation"""
104
- raise NotImplementedError
181
+ async def delete_platform_message_offset(
182
+ self,
183
+ platform_id: str,
184
+ user_id: str,
185
+ offset_sec: int = 86400,
186
+ ) -> None:
187
+ """Delete platform message history records newer than the specified offset."""
188
+ ...
105
189
 
106
190
  @abc.abstractmethod
107
- def delete_conversation(self, user_id: str, cid: str):
108
- """删除 Conversation"""
109
- raise NotImplementedError
191
+ async def get_platform_message_history(
192
+ self,
193
+ platform_id: str,
194
+ user_id: str,
195
+ page: int = 1,
196
+ page_size: int = 20,
197
+ ) -> list[PlatformMessageHistory]:
198
+ """Get platform message history for a specific user."""
199
+ ...
110
200
 
111
201
  @abc.abstractmethod
112
- def update_conversation_title(self, user_id: str, cid: str, title: str):
113
- """更新 Conversation 标题"""
114
- raise NotImplementedError
202
+ async def insert_attachment(
203
+ self,
204
+ path: str,
205
+ type: str,
206
+ mime_type: str,
207
+ ):
208
+ """Insert a new attachment record."""
209
+ ...
115
210
 
116
211
  @abc.abstractmethod
117
- def update_conversation_persona_id(self, user_id: str, cid: str, persona_id: str):
118
- """更新 Conversation Persona ID"""
119
- raise NotImplementedError
212
+ async def get_attachment_by_id(self, attachment_id: str) -> Attachment:
213
+ """Get an attachment by its ID."""
214
+ ...
215
+
216
+ @abc.abstractmethod
217
+ async def insert_persona(
218
+ self,
219
+ persona_id: str,
220
+ system_prompt: str,
221
+ begin_dialogs: list[str] | None = None,
222
+ tools: list[str] | None = None,
223
+ ) -> Persona:
224
+ """Insert a new persona record."""
225
+ ...
120
226
 
121
227
  @abc.abstractmethod
122
- def get_all_conversations(
123
- self, page: int = 1, page_size: int = 20
124
- ) -> Tuple[List[Dict[str, Any]], int]:
125
- """获取所有对话,支持分页
228
+ async def get_persona_by_id(self, persona_id: str) -> Persona:
229
+ """Get a persona by its ID."""
230
+ ...
126
231
 
127
- Args:
128
- page: 页码,从1开始
129
- page_size: 每页数量
232
+ @abc.abstractmethod
233
+ async def get_personas(self) -> list[Persona]:
234
+ """Get all personas for a specific bot."""
235
+ ...
130
236
 
131
- Returns:
132
- Tuple[List[Dict[str, Any]], int]: 返回一个元组,包含对话列表和总对话数
133
- """
134
- raise NotImplementedError
237
+ @abc.abstractmethod
238
+ async def update_persona(
239
+ self,
240
+ persona_id: str,
241
+ system_prompt: str | None = None,
242
+ begin_dialogs: list[str] | None = None,
243
+ tools: list[str] | None = None,
244
+ ) -> Persona | None:
245
+ """Update a persona's system prompt or begin dialogs."""
246
+ ...
247
+
248
+ @abc.abstractmethod
249
+ async def delete_persona(self, persona_id: str) -> None:
250
+ """Delete a persona by its ID."""
251
+ ...
252
+
253
+ @abc.abstractmethod
254
+ async def insert_preference_or_update(
255
+ self,
256
+ scope: str,
257
+ scope_id: str,
258
+ key: str,
259
+ value: dict,
260
+ ) -> Preference:
261
+ """Insert a new preference record."""
262
+ ...
263
+
264
+ @abc.abstractmethod
265
+ async def get_preference(self, scope: str, scope_id: str, key: str) -> Preference:
266
+ """Get a preference by scope ID and key."""
267
+ ...
268
+
269
+ @abc.abstractmethod
270
+ async def get_preferences(
271
+ self,
272
+ scope: str,
273
+ scope_id: str | None = None,
274
+ key: str | None = None,
275
+ ) -> list[Preference]:
276
+ """Get all preferences for a specific scope ID or key."""
277
+ ...
278
+
279
+ @abc.abstractmethod
280
+ async def remove_preference(self, scope: str, scope_id: str, key: str) -> None:
281
+ """Remove a preference by scope ID and key."""
282
+ ...
283
+
284
+ @abc.abstractmethod
285
+ async def clear_preferences(self, scope: str, scope_id: str) -> None:
286
+ """Clear all preferences for a specific scope ID."""
287
+ ...
288
+
289
+ # @abc.abstractmethod
290
+ # async def insert_llm_message(
291
+ # self,
292
+ # cid: str,
293
+ # role: str,
294
+ # content: list,
295
+ # tool_calls: list = None,
296
+ # tool_call_id: str = None,
297
+ # parent_id: str = None,
298
+ # ) -> LLMMessage:
299
+ # """Insert a new LLM message into the conversation."""
300
+ # ...
301
+
302
+ # @abc.abstractmethod
303
+ # async def get_llm_messages(self, cid: str) -> list[LLMMessage]:
304
+ # """Get all LLM messages for a specific conversation."""
305
+ # ...
135
306
 
136
307
  @abc.abstractmethod
137
- def get_filtered_conversations(
308
+ async def get_session_conversations(
138
309
  self,
139
310
  page: int = 1,
140
311
  page_size: int = 20,
141
- platforms: List[str] = None,
142
- message_types: List[str] = None,
143
- search_query: str = None,
144
- exclude_ids: List[str] = None,
145
- exclude_platforms: List[str] = None,
146
- ) -> Tuple[List[Dict[str, Any]], int]:
147
- """获取筛选后的对话列表
148
-
149
- Args:
150
- page: 页码
151
- page_size: 每页数量
152
- platforms: 平台筛选列表
153
- message_types: 消息类型筛选列表
154
- search_query: 搜索关键词
155
- exclude_ids: 排除的用户ID列表
156
- exclude_platforms: 排除的平台列表
157
-
158
- Returns:
159
- Tuple[List[Dict[str, Any]], int]: 返回一个元组,包含对话列表和总对话数
160
- """
161
- raise NotImplementedError
312
+ search_query: str | None = None,
313
+ platform: str | None = None,
314
+ ) -> tuple[list[dict], int]:
315
+ """Get paginated session conversations with joined conversation and persona details, support search and platform filter."""
316
+ ...
317
+
318
+ # ====
319
+ # Platform Session Management
320
+ # ====
321
+
322
+ @abc.abstractmethod
323
+ async def create_platform_session(
324
+ self,
325
+ creator: str,
326
+ platform_id: str = "webchat",
327
+ session_id: str | None = None,
328
+ display_name: str | None = None,
329
+ is_group: int = 0,
330
+ ) -> PlatformSession:
331
+ """Create a new Platform session."""
332
+ ...
333
+
334
+ @abc.abstractmethod
335
+ async def get_platform_session_by_id(
336
+ self, session_id: str
337
+ ) -> PlatformSession | None:
338
+ """Get a Platform session by its ID."""
339
+ ...
340
+
341
+ @abc.abstractmethod
342
+ async def get_platform_sessions_by_creator(
343
+ self,
344
+ creator: str,
345
+ platform_id: str | None = None,
346
+ page: int = 1,
347
+ page_size: int = 20,
348
+ ) -> list[PlatformSession]:
349
+ """Get all Platform sessions for a specific creator (username) and optionally platform."""
350
+ ...
351
+
352
+ @abc.abstractmethod
353
+ async def update_platform_session(
354
+ self,
355
+ session_id: str,
356
+ display_name: str | None = None,
357
+ ) -> None:
358
+ """Update a Platform session's updated_at timestamp and optionally display_name."""
359
+ ...
360
+
361
+ @abc.abstractmethod
362
+ async def delete_platform_session(self, session_id: str) -> None:
363
+ """Delete a Platform session by its ID."""
364
+ ...
@@ -0,0 +1,69 @@
1
+ import os
2
+
3
+ from astrbot.api import logger, sp
4
+ from astrbot.core.config import AstrBotConfig
5
+ from astrbot.core.db import BaseDatabase
6
+ from astrbot.core.utils.astrbot_path import get_astrbot_data_path
7
+
8
+ from .migra_3_to_4 import (
9
+ migration_conversation_table,
10
+ migration_persona_data,
11
+ migration_platform_table,
12
+ migration_preferences,
13
+ migration_webchat_data,
14
+ )
15
+
16
+
17
+ async def check_migration_needed_v4(db_helper: BaseDatabase) -> bool:
18
+ """检查是否需要进行数据库迁移
19
+ 如果存在 data_v3.db 并且 preference 中没有 migration_done_v4,则需要进行迁移。
20
+ """
21
+ # 仅当 data 目录下存在旧版本数据(data_v3.db 文件)时才考虑迁移
22
+ data_dir = get_astrbot_data_path()
23
+ data_v3_db = os.path.join(data_dir, "data_v3.db")
24
+
25
+ if not os.path.exists(data_v3_db):
26
+ return False
27
+ migration_done = await db_helper.get_preference(
28
+ "global",
29
+ "global",
30
+ "migration_done_v4",
31
+ )
32
+ if migration_done:
33
+ return False
34
+ return True
35
+
36
+
37
+ async def do_migration_v4(
38
+ db_helper: BaseDatabase,
39
+ platform_id_map: dict[str, dict[str, str]],
40
+ astrbot_config: AstrBotConfig,
41
+ ) -> None:
42
+ """执行数据库迁移
43
+ 迁移旧的 webchat_conversation 表到新的 conversation 表。
44
+ 迁移旧的 platform 到新的 platform_stats 表。
45
+ """
46
+ if not await check_migration_needed_v4(db_helper):
47
+ return
48
+
49
+ logger.info("开始执行数据库迁移...")
50
+
51
+ # 执行会话表迁移
52
+ await migration_conversation_table(db_helper, platform_id_map)
53
+
54
+ # 执行人格数据迁移
55
+ await migration_persona_data(db_helper, astrbot_config)
56
+
57
+ # 执行 WebChat 数据迁移
58
+ await migration_webchat_data(db_helper, platform_id_map)
59
+
60
+ # 执行偏好设置迁移
61
+ await migration_preferences(db_helper, platform_id_map)
62
+
63
+ # 执行平台统计表迁移
64
+ await migration_platform_table(db_helper, platform_id_map)
65
+
66
+ # 标记迁移完成
67
+ await sp.put_async("global", "global", "migration_done_v4", True)
68
+
69
+ logger.info("数据库迁移完成。")