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,12 +1,16 @@
1
- import uuid
1
+ import asyncio
2
2
  import os
3
- import edge_tts
4
3
  import subprocess
5
- import asyncio
6
- from ..provider import TTSProvider
4
+ import uuid
5
+
6
+ import edge_tts
7
+
8
+ from astrbot.core import logger
9
+ from astrbot.core.utils.astrbot_path import get_astrbot_data_path
10
+
7
11
  from ..entities import ProviderType
12
+ from ..provider import TTSProvider
8
13
  from ..register import register_provider_adapter
9
- from astrbot.core import logger
10
14
 
11
15
  """
12
16
  edge_tts 方式,能够免费、快速生成语音,使用需要先安装edge-tts库
@@ -18,7 +22,9 @@ Windows 如果提示找不到指定文件,以管理员身份运行命令行窗
18
22
 
19
23
 
20
24
  @register_provider_adapter(
21
- "edge_tts", "Microsoft Edge TTS", provider_type=ProviderType.TEXT_TO_SPEECH
25
+ "edge_tts",
26
+ "Microsoft Edge TTS",
27
+ provider_type=ProviderType.TEXT_TO_SPEECH,
22
28
  )
23
29
  class ProviderEdgeTTS(TTSProvider):
24
30
  def __init__(
@@ -30,9 +36,9 @@ class ProviderEdgeTTS(TTSProvider):
30
36
 
31
37
  # 设置默认语音,如果没有指定则使用中文小萱
32
38
  self.voice = provider_config.get("edge-tts-voice", "zh-CN-XiaoxiaoNeural")
33
- self.rate = provider_config.get("rate", None)
34
- self.volume = provider_config.get("volume", None)
35
- self.pitch = provider_config.get("pitch", None)
39
+ self.rate = provider_config.get("rate")
40
+ self.volume = provider_config.get("volume")
41
+ self.pitch = provider_config.get("pitch")
36
42
  self.timeout = provider_config.get("timeout", 30)
37
43
 
38
44
  self.proxy = os.getenv("https_proxy", None)
@@ -40,9 +46,9 @@ class ProviderEdgeTTS(TTSProvider):
40
46
  self.set_model("edge_tts")
41
47
 
42
48
  async def get_audio(self, text: str) -> str:
43
- os.makedirs("data/temp", exist_ok=True)
44
- mp3_path = f"data/temp/edge_tts_temp_{uuid.uuid4()}.mp3"
45
- wav_path = f"data/temp/edge_tts_{uuid.uuid4()}.wav"
49
+ temp_dir = os.path.join(get_astrbot_data_path(), "temp")
50
+ mp3_path = os.path.join(temp_dir, f"edge_tts_temp_{uuid.uuid4()}.mp3")
51
+ wav_path = os.path.join(temp_dir, f"edge_tts_{uuid.uuid4()}.wav")
46
52
 
47
53
  # 构建 Edge TTS 参数
48
54
  kwargs = {"text": text, "voice": self.voice}
@@ -96,26 +102,25 @@ class ProviderEdgeTTS(TTSProvider):
96
102
  os.remove(mp3_path)
97
103
  if os.path.exists(wav_path) and os.path.getsize(wav_path) > 0:
98
104
  return wav_path
99
- else:
100
- logger.error("生成的WAV文件不存在或为空")
101
- raise RuntimeError("生成的WAV文件不存在或为空")
105
+ logger.error("生成的WAV文件不存在或为空")
106
+ raise RuntimeError("生成的WAV文件不存在或为空")
102
107
 
103
108
  except subprocess.CalledProcessError as e:
104
109
  logger.error(
105
- f"FFmpeg 转换失败: {e.stderr.decode() if e.stderr else str(e)}"
110
+ f"FFmpeg 转换失败: {e.stderr.decode() if e.stderr else str(e)}",
106
111
  )
107
112
  try:
108
113
  if os.path.exists(mp3_path):
109
114
  os.remove(mp3_path)
110
115
  except Exception:
111
116
  pass
112
- raise RuntimeError(f"FFmpeg 转换失败: {str(e)}")
117
+ raise RuntimeError(f"FFmpeg 转换失败: {e!s}")
113
118
 
114
119
  except Exception as e:
115
- logger.error(f"音频生成失败: {str(e)}")
120
+ logger.error(f"音频生成失败: {e!s}")
116
121
  try:
117
122
  if os.path.exists(mp3_path):
118
123
  os.remove(mp3_path)
119
124
  except Exception:
120
125
  pass
121
- raise RuntimeError(f"音频生成失败: {str(e)}")
126
+ raise RuntimeError(f"音频生成失败: {e!s}")
@@ -1,10 +1,16 @@
1
+ import os
2
+ import re
1
3
  import uuid
4
+ from typing import Annotated, Literal
5
+
2
6
  import ormsgpack
3
- from pydantic import BaseModel, conint
4
7
  from httpx import AsyncClient
5
- from typing import Annotated, Literal
6
- from ..provider import TTSProvider
8
+ from pydantic import BaseModel, conint
9
+
10
+ from astrbot.core.utils.astrbot_path import get_astrbot_data_path
11
+
7
12
  from ..entities import ProviderType
13
+ from ..provider import TTSProvider
8
14
  from ..register import register_provider_adapter
9
15
 
10
16
 
@@ -22,8 +28,8 @@ class ServeTTSRequest(BaseModel):
22
28
  # 参考音频
23
29
  references: list[ServeReferenceAudio] = []
24
30
  # 参考模型 ID
25
- # 例如 https://fish.audio/m/7f92f8afb8ec43bf81429cc1c9199cb1/
26
- # 其中reference_id为 7f92f8afb8ec43bf81429cc1c9199cb1
31
+ # 例如 https://fish.audio/m/626bb6d3f3364c9cbc3aa6a67300a664/
32
+ # 其中reference_id为 626bb6d3f3364c9cbc3aa6a67300a664
27
33
  reference_id: str | None = None
28
34
  # 对中英文文本进行标准化,这可以提高数字的稳定性
29
35
  normalize: bool = True
@@ -32,7 +38,9 @@ class ServeTTSRequest(BaseModel):
32
38
 
33
39
 
34
40
  @register_provider_adapter(
35
- "fishaudio_tts_api", "FishAudio TTS API", provider_type=ProviderType.TEXT_TO_SPEECH
41
+ "fishaudio_tts_api",
42
+ "FishAudio TTS API",
43
+ provider_type=ProviderType.TEXT_TO_SPEECH,
36
44
  )
37
45
  class ProviderFishAudioTTSAPI(TTSProvider):
38
46
  def __init__(
@@ -42,18 +50,19 @@ class ProviderFishAudioTTSAPI(TTSProvider):
42
50
  ) -> None:
43
51
  super().__init__(provider_config, provider_settings)
44
52
  self.chosen_api_key: str = provider_config.get("api_key", "")
53
+ self.reference_id: str = provider_config.get("fishaudio-tts-reference-id", "")
45
54
  self.character: str = provider_config.get("fishaudio-tts-character", "可莉")
46
55
  self.api_base: str = provider_config.get(
47
- "api_base", "https://api.fish-audio.cn/v1"
56
+ "api_base",
57
+ "https://api.fish-audio.cn/v1",
48
58
  )
49
59
  self.headers = {
50
60
  "Authorization": f"Bearer {self.chosen_api_key}",
51
61
  }
52
- self.set_model(provider_config.get("model", None))
62
+ self.set_model(provider_config.get("model"))
53
63
 
54
64
  async def _get_reference_id_by_character(self, character: str) -> str:
55
- """
56
- 获取角色的reference_id
65
+ """获取角色的reference_id
57
66
 
58
67
  Args:
59
68
  character: 角色名称
@@ -63,13 +72,16 @@ class ProviderFishAudioTTSAPI(TTSProvider):
63
72
 
64
73
  exception:
65
74
  APIException: 获取语音角色列表为空
75
+
66
76
  """
67
77
  sort_options = ["score", "task_count", "created_at"]
68
78
  async with AsyncClient(base_url=self.api_base.replace("/v1", "")) as client:
69
79
  for sort_by in sort_options:
70
80
  params = {"title": character, "sort_by": sort_by}
71
81
  response = await client.get(
72
- "/model", params=params, headers=self.headers
82
+ "/model",
83
+ params=params,
84
+ headers=self.headers,
73
85
  )
74
86
  resp_data = response.json()
75
87
  if resp_data["total"] == 0:
@@ -79,15 +91,48 @@ class ProviderFishAudioTTSAPI(TTSProvider):
79
91
  return item["_id"]
80
92
  return None
81
93
 
94
+ def _validate_reference_id(self, reference_id: str) -> bool:
95
+ """验证reference_id格式是否有效
96
+
97
+ Args:
98
+ reference_id: 参考模型ID
99
+
100
+ Returns:
101
+ bool: ID是否有效
102
+
103
+ """
104
+ if not reference_id or not reference_id.strip():
105
+ return False
106
+
107
+ # FishAudio的reference_id通常是32位十六进制字符串
108
+ # 例如: 626bb6d3f3364c9cbc3aa6a67300a664
109
+ pattern = r"^[a-fA-F0-9]{32}$"
110
+ return bool(re.match(pattern, reference_id.strip()))
111
+
82
112
  async def _generate_request(self, text: str) -> dict:
113
+ # 向前兼容逻辑:优先使用reference_id,如果没有则使用角色名称查询
114
+ if self.reference_id and self.reference_id.strip():
115
+ # 验证reference_id格式
116
+ if not self._validate_reference_id(self.reference_id):
117
+ raise ValueError(
118
+ f"无效的FishAudio参考模型ID: '{self.reference_id}'. "
119
+ f"请确保ID是32位十六进制字符串(例如: 626bb6d3f3364c9cbc3aa6a67300a664)。"
120
+ f"您可以从 https://fish.audio/zh-CN/discovery 获取有效的模型ID。",
121
+ )
122
+ reference_id = self.reference_id.strip()
123
+ else:
124
+ # 回退到原来的角色名称查询逻辑
125
+ reference_id = await self._get_reference_id_by_character(self.character)
126
+
83
127
  return ServeTTSRequest(
84
128
  text=text,
85
129
  format="wav",
86
- reference_id=await self._get_reference_id_by_character(self.character),
130
+ reference_id=reference_id,
87
131
  )
88
132
 
89
133
  async def get_audio(self, text: str) -> str:
90
- path = f"data/temp/fishaudio_tts_api_{uuid.uuid4()}.wav"
134
+ temp_dir = os.path.join(get_astrbot_data_path(), "temp")
135
+ path = os.path.join(temp_dir, f"fishaudio_tts_api_{uuid.uuid4()}.wav")
91
136
  self.headers["content-type"] = "application/msgpack"
92
137
  request = await self._generate_request(text)
93
138
  async with AsyncClient(base_url=self.api_base).stream(
@@ -0,0 +1,61 @@
1
+ from google import genai
2
+ from google.genai import types
3
+ from google.genai.errors import APIError
4
+
5
+ from ..entities import ProviderType
6
+ from ..provider import EmbeddingProvider
7
+ from ..register import register_provider_adapter
8
+
9
+
10
+ @register_provider_adapter(
11
+ "gemini_embedding",
12
+ "Google Gemini Embedding 提供商适配器",
13
+ provider_type=ProviderType.EMBEDDING,
14
+ )
15
+ class GeminiEmbeddingProvider(EmbeddingProvider):
16
+ def __init__(self, provider_config: dict, provider_settings: dict) -> None:
17
+ super().__init__(provider_config, provider_settings)
18
+ self.provider_config = provider_config
19
+ self.provider_settings = provider_settings
20
+
21
+ api_key: str = provider_config.get("embedding_api_key")
22
+ api_base: str = provider_config.get("embedding_api_base")
23
+ timeout: int = int(provider_config.get("timeout", 20))
24
+
25
+ http_options = types.HttpOptions(timeout=timeout * 1000)
26
+ if api_base:
27
+ api_base = api_base.removesuffix("/")
28
+ http_options.base_url = api_base
29
+
30
+ self.client = genai.Client(api_key=api_key, http_options=http_options).aio
31
+
32
+ self.model = provider_config.get(
33
+ "embedding_model",
34
+ "gemini-embedding-exp-03-07",
35
+ )
36
+
37
+ async def get_embedding(self, text: str) -> list[float]:
38
+ """获取文本的嵌入"""
39
+ try:
40
+ result = await self.client.models.embed_content(
41
+ model=self.model,
42
+ contents=text,
43
+ )
44
+ return result.embeddings[0].values
45
+ except APIError as e:
46
+ raise Exception(f"Gemini Embedding API请求失败: {e.message}")
47
+
48
+ async def get_embeddings(self, texts: list[str]) -> list[list[float]]:
49
+ """批量获取文本的嵌入"""
50
+ try:
51
+ result = await self.client.models.embed_content(
52
+ model=self.model,
53
+ contents=texts,
54
+ )
55
+ return [embedding.values for embedding in result.embeddings]
56
+ except APIError as e:
57
+ raise Exception(f"Gemini Embedding API批量请求失败: {e.message}")
58
+
59
+ def get_dim(self) -> int:
60
+ """获取向量的维度"""
61
+ return self.provider_config.get("embedding_dimensions", 768)