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.
- astrbot/api/__init__.py +16 -4
- astrbot/api/all.py +2 -1
- astrbot/api/event/__init__.py +5 -6
- astrbot/api/event/filter/__init__.py +37 -34
- astrbot/api/platform/__init__.py +7 -8
- astrbot/api/provider/__init__.py +8 -7
- astrbot/api/star/__init__.py +3 -4
- astrbot/api/util/__init__.py +2 -2
- astrbot/cli/__init__.py +1 -0
- astrbot/cli/__main__.py +18 -197
- astrbot/cli/commands/__init__.py +6 -0
- astrbot/cli/commands/cmd_conf.py +209 -0
- astrbot/cli/commands/cmd_init.py +56 -0
- astrbot/cli/commands/cmd_plug.py +245 -0
- astrbot/cli/commands/cmd_run.py +62 -0
- astrbot/cli/utils/__init__.py +18 -0
- astrbot/cli/utils/basic.py +76 -0
- astrbot/cli/utils/plugin.py +246 -0
- astrbot/cli/utils/version_comparator.py +90 -0
- astrbot/core/__init__.py +17 -19
- astrbot/core/agent/agent.py +14 -0
- astrbot/core/agent/handoff.py +38 -0
- astrbot/core/agent/hooks.py +30 -0
- astrbot/core/agent/mcp_client.py +385 -0
- astrbot/core/agent/message.py +175 -0
- astrbot/core/agent/response.py +14 -0
- astrbot/core/agent/run_context.py +22 -0
- astrbot/core/agent/runners/__init__.py +3 -0
- astrbot/core/agent/runners/base.py +65 -0
- astrbot/core/agent/runners/coze/coze_agent_runner.py +367 -0
- astrbot/core/agent/runners/coze/coze_api_client.py +324 -0
- astrbot/core/agent/runners/dashscope/dashscope_agent_runner.py +403 -0
- astrbot/core/agent/runners/dify/dify_agent_runner.py +336 -0
- astrbot/core/agent/runners/dify/dify_api_client.py +195 -0
- astrbot/core/agent/runners/tool_loop_agent_runner.py +400 -0
- astrbot/core/agent/tool.py +285 -0
- astrbot/core/agent/tool_executor.py +17 -0
- astrbot/core/astr_agent_context.py +19 -0
- astrbot/core/astr_agent_hooks.py +36 -0
- astrbot/core/astr_agent_run_util.py +80 -0
- astrbot/core/astr_agent_tool_exec.py +246 -0
- astrbot/core/astrbot_config_mgr.py +275 -0
- astrbot/core/config/__init__.py +2 -2
- astrbot/core/config/astrbot_config.py +60 -20
- astrbot/core/config/default.py +1972 -453
- astrbot/core/config/i18n_utils.py +110 -0
- astrbot/core/conversation_mgr.py +285 -75
- astrbot/core/core_lifecycle.py +167 -62
- astrbot/core/db/__init__.py +305 -102
- astrbot/core/db/migration/helper.py +69 -0
- astrbot/core/db/migration/migra_3_to_4.py +357 -0
- astrbot/core/db/migration/migra_45_to_46.py +44 -0
- astrbot/core/db/migration/migra_webchat_session.py +131 -0
- astrbot/core/db/migration/shared_preferences_v3.py +48 -0
- astrbot/core/db/migration/sqlite_v3.py +497 -0
- astrbot/core/db/po.py +259 -55
- astrbot/core/db/sqlite.py +773 -528
- astrbot/core/db/vec_db/base.py +73 -0
- astrbot/core/db/vec_db/faiss_impl/__init__.py +3 -0
- astrbot/core/db/vec_db/faiss_impl/document_storage.py +392 -0
- astrbot/core/db/vec_db/faiss_impl/embedding_storage.py +93 -0
- astrbot/core/db/vec_db/faiss_impl/sqlite_init.sql +17 -0
- astrbot/core/db/vec_db/faiss_impl/vec_db.py +204 -0
- astrbot/core/event_bus.py +26 -22
- astrbot/core/exceptions.py +9 -0
- astrbot/core/file_token_service.py +98 -0
- astrbot/core/initial_loader.py +19 -10
- astrbot/core/knowledge_base/chunking/__init__.py +9 -0
- astrbot/core/knowledge_base/chunking/base.py +25 -0
- astrbot/core/knowledge_base/chunking/fixed_size.py +59 -0
- astrbot/core/knowledge_base/chunking/recursive.py +161 -0
- astrbot/core/knowledge_base/kb_db_sqlite.py +301 -0
- astrbot/core/knowledge_base/kb_helper.py +642 -0
- astrbot/core/knowledge_base/kb_mgr.py +330 -0
- astrbot/core/knowledge_base/models.py +120 -0
- astrbot/core/knowledge_base/parsers/__init__.py +13 -0
- astrbot/core/knowledge_base/parsers/base.py +51 -0
- astrbot/core/knowledge_base/parsers/markitdown_parser.py +26 -0
- astrbot/core/knowledge_base/parsers/pdf_parser.py +101 -0
- astrbot/core/knowledge_base/parsers/text_parser.py +42 -0
- astrbot/core/knowledge_base/parsers/url_parser.py +103 -0
- astrbot/core/knowledge_base/parsers/util.py +13 -0
- astrbot/core/knowledge_base/prompts.py +65 -0
- astrbot/core/knowledge_base/retrieval/__init__.py +14 -0
- astrbot/core/knowledge_base/retrieval/hit_stopwords.txt +767 -0
- astrbot/core/knowledge_base/retrieval/manager.py +276 -0
- astrbot/core/knowledge_base/retrieval/rank_fusion.py +142 -0
- astrbot/core/knowledge_base/retrieval/sparse_retriever.py +136 -0
- astrbot/core/log.py +21 -15
- astrbot/core/message/components.py +413 -287
- astrbot/core/message/message_event_result.py +35 -24
- astrbot/core/persona_mgr.py +192 -0
- astrbot/core/pipeline/__init__.py +14 -14
- astrbot/core/pipeline/content_safety_check/stage.py +13 -9
- astrbot/core/pipeline/content_safety_check/strategies/__init__.py +1 -2
- astrbot/core/pipeline/content_safety_check/strategies/baidu_aip.py +13 -14
- astrbot/core/pipeline/content_safety_check/strategies/keywords.py +2 -1
- astrbot/core/pipeline/content_safety_check/strategies/strategy.py +6 -6
- astrbot/core/pipeline/context.py +7 -1
- astrbot/core/pipeline/context_utils.py +107 -0
- astrbot/core/pipeline/preprocess_stage/stage.py +63 -36
- astrbot/core/pipeline/process_stage/method/agent_request.py +48 -0
- astrbot/core/pipeline/process_stage/method/agent_sub_stages/internal.py +464 -0
- astrbot/core/pipeline/process_stage/method/agent_sub_stages/third_party.py +202 -0
- astrbot/core/pipeline/process_stage/method/star_request.py +26 -32
- astrbot/core/pipeline/process_stage/stage.py +21 -15
- astrbot/core/pipeline/process_stage/utils.py +125 -0
- astrbot/core/pipeline/rate_limit_check/stage.py +34 -36
- astrbot/core/pipeline/respond/stage.py +142 -101
- astrbot/core/pipeline/result_decorate/stage.py +124 -57
- astrbot/core/pipeline/scheduler.py +21 -16
- astrbot/core/pipeline/session_status_check/stage.py +37 -0
- astrbot/core/pipeline/stage.py +11 -76
- astrbot/core/pipeline/waking_check/stage.py +69 -33
- astrbot/core/pipeline/whitelist_check/stage.py +10 -7
- astrbot/core/platform/__init__.py +6 -6
- astrbot/core/platform/astr_message_event.py +107 -129
- astrbot/core/platform/astrbot_message.py +32 -12
- astrbot/core/platform/manager.py +62 -18
- astrbot/core/platform/message_session.py +30 -0
- astrbot/core/platform/platform.py +16 -24
- astrbot/core/platform/platform_metadata.py +9 -4
- astrbot/core/platform/register.py +12 -7
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +136 -60
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +126 -46
- astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +63 -31
- astrbot/core/platform/sources/dingtalk/dingtalk_event.py +30 -26
- astrbot/core/platform/sources/discord/client.py +129 -0
- astrbot/core/platform/sources/discord/components.py +139 -0
- astrbot/core/platform/sources/discord/discord_platform_adapter.py +473 -0
- astrbot/core/platform/sources/discord/discord_platform_event.py +313 -0
- astrbot/core/platform/sources/lark/lark_adapter.py +27 -18
- astrbot/core/platform/sources/lark/lark_event.py +39 -13
- astrbot/core/platform/sources/misskey/misskey_adapter.py +770 -0
- astrbot/core/platform/sources/misskey/misskey_api.py +964 -0
- astrbot/core/platform/sources/misskey/misskey_event.py +163 -0
- astrbot/core/platform/sources/misskey/misskey_utils.py +550 -0
- astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +149 -33
- astrbot/core/platform/sources/qqofficial/qqofficial_platform_adapter.py +41 -26
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_adapter.py +36 -17
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_event.py +3 -1
- astrbot/core/platform/sources/qqofficial_webhook/qo_webhook_server.py +14 -8
- astrbot/core/platform/sources/satori/satori_adapter.py +792 -0
- astrbot/core/platform/sources/satori/satori_event.py +432 -0
- astrbot/core/platform/sources/slack/client.py +164 -0
- astrbot/core/platform/sources/slack/slack_adapter.py +416 -0
- astrbot/core/platform/sources/slack/slack_event.py +253 -0
- astrbot/core/platform/sources/telegram/tg_adapter.py +100 -43
- astrbot/core/platform/sources/telegram/tg_event.py +136 -36
- astrbot/core/platform/sources/webchat/webchat_adapter.py +72 -22
- astrbot/core/platform/sources/webchat/webchat_event.py +46 -22
- astrbot/core/platform/sources/webchat/webchat_queue_mgr.py +35 -0
- astrbot/core/platform/sources/wechatpadpro/wechatpadpro_adapter.py +926 -0
- astrbot/core/platform/sources/wechatpadpro/wechatpadpro_message_event.py +178 -0
- astrbot/core/platform/sources/wechatpadpro/xml_data_parser.py +159 -0
- astrbot/core/platform/sources/wecom/wecom_adapter.py +169 -27
- astrbot/core/platform/sources/wecom/wecom_event.py +162 -77
- astrbot/core/platform/sources/wecom/wecom_kf.py +279 -0
- astrbot/core/platform/sources/wecom/wecom_kf_message.py +196 -0
- astrbot/core/platform/sources/wecom_ai_bot/WXBizJsonMsgCrypt.py +297 -0
- astrbot/core/platform/sources/wecom_ai_bot/__init__.py +15 -0
- astrbot/core/platform/sources/wecom_ai_bot/ierror.py +19 -0
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_adapter.py +472 -0
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_api.py +417 -0
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_event.py +152 -0
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_queue_mgr.py +153 -0
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_server.py +168 -0
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_utils.py +209 -0
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +306 -0
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py +186 -0
- astrbot/core/platform_message_history_mgr.py +49 -0
- astrbot/core/provider/__init__.py +2 -3
- astrbot/core/provider/entites.py +8 -8
- astrbot/core/provider/entities.py +154 -98
- astrbot/core/provider/func_tool_manager.py +446 -458
- astrbot/core/provider/manager.py +345 -207
- astrbot/core/provider/provider.py +188 -73
- astrbot/core/provider/register.py +9 -7
- astrbot/core/provider/sources/anthropic_source.py +295 -115
- astrbot/core/provider/sources/azure_tts_source.py +224 -0
- astrbot/core/provider/sources/bailian_rerank_source.py +236 -0
- astrbot/core/provider/sources/dashscope_tts.py +138 -14
- astrbot/core/provider/sources/edge_tts_source.py +24 -19
- astrbot/core/provider/sources/fishaudio_tts_api_source.py +58 -13
- astrbot/core/provider/sources/gemini_embedding_source.py +61 -0
- astrbot/core/provider/sources/gemini_source.py +310 -132
- astrbot/core/provider/sources/gemini_tts_source.py +81 -0
- astrbot/core/provider/sources/groq_source.py +15 -0
- astrbot/core/provider/sources/gsv_selfhosted_source.py +151 -0
- astrbot/core/provider/sources/gsvi_tts_source.py +14 -7
- astrbot/core/provider/sources/minimax_tts_api_source.py +159 -0
- astrbot/core/provider/sources/openai_embedding_source.py +40 -0
- astrbot/core/provider/sources/openai_source.py +241 -145
- astrbot/core/provider/sources/openai_tts_api_source.py +18 -7
- astrbot/core/provider/sources/sensevoice_selfhosted_source.py +13 -11
- astrbot/core/provider/sources/vllm_rerank_source.py +71 -0
- astrbot/core/provider/sources/volcengine_tts.py +115 -0
- astrbot/core/provider/sources/whisper_api_source.py +18 -13
- astrbot/core/provider/sources/whisper_selfhosted_source.py +19 -12
- astrbot/core/provider/sources/xinference_rerank_source.py +116 -0
- astrbot/core/provider/sources/xinference_stt_provider.py +197 -0
- astrbot/core/provider/sources/zhipu_source.py +6 -73
- astrbot/core/star/__init__.py +43 -11
- astrbot/core/star/config.py +17 -18
- astrbot/core/star/context.py +362 -138
- astrbot/core/star/filter/__init__.py +4 -3
- astrbot/core/star/filter/command.py +111 -35
- astrbot/core/star/filter/command_group.py +46 -34
- astrbot/core/star/filter/custom_filter.py +6 -5
- astrbot/core/star/filter/event_message_type.py +4 -2
- astrbot/core/star/filter/permission.py +4 -2
- astrbot/core/star/filter/platform_adapter_type.py +45 -12
- astrbot/core/star/filter/regex.py +4 -2
- astrbot/core/star/register/__init__.py +19 -15
- astrbot/core/star/register/star.py +41 -13
- astrbot/core/star/register/star_handler.py +236 -86
- astrbot/core/star/session_llm_manager.py +280 -0
- astrbot/core/star/session_plugin_manager.py +170 -0
- astrbot/core/star/star.py +36 -43
- astrbot/core/star/star_handler.py +47 -85
- astrbot/core/star/star_manager.py +442 -260
- astrbot/core/star/star_tools.py +167 -45
- astrbot/core/star/updator.py +17 -20
- astrbot/core/umop_config_router.py +106 -0
- astrbot/core/updator.py +38 -13
- astrbot/core/utils/astrbot_path.py +39 -0
- astrbot/core/utils/command_parser.py +1 -1
- astrbot/core/utils/io.py +119 -60
- astrbot/core/utils/log_pipe.py +1 -1
- astrbot/core/utils/metrics.py +11 -10
- astrbot/core/utils/migra_helper.py +73 -0
- astrbot/core/utils/path_util.py +63 -62
- astrbot/core/utils/pip_installer.py +37 -15
- astrbot/core/utils/session_lock.py +29 -0
- astrbot/core/utils/session_waiter.py +19 -20
- astrbot/core/utils/shared_preferences.py +174 -34
- astrbot/core/utils/t2i/__init__.py +4 -1
- astrbot/core/utils/t2i/local_strategy.py +386 -238
- astrbot/core/utils/t2i/network_strategy.py +109 -49
- astrbot/core/utils/t2i/renderer.py +29 -14
- astrbot/core/utils/t2i/template/astrbot_powershell.html +184 -0
- astrbot/core/utils/t2i/template_manager.py +111 -0
- astrbot/core/utils/tencent_record_helper.py +115 -1
- astrbot/core/utils/version_comparator.py +10 -13
- astrbot/core/zip_updator.py +112 -65
- astrbot/dashboard/routes/__init__.py +20 -13
- astrbot/dashboard/routes/auth.py +20 -9
- astrbot/dashboard/routes/chat.py +297 -141
- astrbot/dashboard/routes/config.py +652 -55
- astrbot/dashboard/routes/conversation.py +107 -37
- astrbot/dashboard/routes/file.py +26 -0
- astrbot/dashboard/routes/knowledge_base.py +1244 -0
- astrbot/dashboard/routes/log.py +27 -2
- astrbot/dashboard/routes/persona.py +202 -0
- astrbot/dashboard/routes/plugin.py +197 -139
- astrbot/dashboard/routes/route.py +27 -7
- astrbot/dashboard/routes/session_management.py +354 -0
- astrbot/dashboard/routes/stat.py +85 -18
- astrbot/dashboard/routes/static_file.py +5 -2
- astrbot/dashboard/routes/t2i.py +233 -0
- astrbot/dashboard/routes/tools.py +184 -120
- astrbot/dashboard/routes/update.py +59 -36
- astrbot/dashboard/server.py +96 -36
- astrbot/dashboard/utils.py +165 -0
- astrbot-4.7.0.dist-info/METADATA +294 -0
- astrbot-4.7.0.dist-info/RECORD +274 -0
- {astrbot-3.5.6.dist-info → astrbot-4.7.0.dist-info}/WHEEL +1 -1
- astrbot/core/db/plugin/sqlite_impl.py +0 -112
- astrbot/core/db/sqlite_init.sql +0 -50
- astrbot/core/pipeline/platform_compatibility/stage.py +0 -56
- astrbot/core/pipeline/process_stage/method/llm_request.py +0 -606
- astrbot/core/platform/sources/gewechat/client.py +0 -806
- astrbot/core/platform/sources/gewechat/downloader.py +0 -55
- astrbot/core/platform/sources/gewechat/gewechat_event.py +0 -255
- astrbot/core/platform/sources/gewechat/gewechat_platform_adapter.py +0 -103
- astrbot/core/platform/sources/gewechat/xml_data_parser.py +0 -110
- astrbot/core/provider/sources/dashscope_source.py +0 -203
- astrbot/core/provider/sources/dify_source.py +0 -281
- astrbot/core/provider/sources/llmtuner_source.py +0 -132
- astrbot/core/rag/embedding/openai_source.py +0 -20
- astrbot/core/rag/knowledge_db_mgr.py +0 -94
- astrbot/core/rag/store/__init__.py +0 -9
- astrbot/core/rag/store/chroma_db.py +0 -42
- astrbot/core/utils/dify_api_client.py +0 -152
- astrbot-3.5.6.dist-info/METADATA +0 -249
- astrbot-3.5.6.dist-info/RECORD +0 -158
- {astrbot-3.5.6.dist-info → astrbot-4.7.0.dist-info}/entry_points.txt +0 -0
- {astrbot-3.5.6.dist-info → astrbot-4.7.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,12 +1,16 @@
|
|
|
1
|
-
import
|
|
1
|
+
import asyncio
|
|
2
2
|
import os
|
|
3
|
-
import edge_tts
|
|
4
3
|
import subprocess
|
|
5
|
-
import
|
|
6
|
-
|
|
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",
|
|
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"
|
|
34
|
-
self.volume = provider_config.get("volume"
|
|
35
|
-
self.pitch = provider_config.get("pitch"
|
|
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.
|
|
44
|
-
mp3_path = f"
|
|
45
|
-
wav_path = f"
|
|
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
|
-
|
|
100
|
-
|
|
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 转换失败: {
|
|
117
|
+
raise RuntimeError(f"FFmpeg 转换失败: {e!s}")
|
|
113
118
|
|
|
114
119
|
except Exception as e:
|
|
115
|
-
logger.error(f"音频生成失败: {
|
|
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"音频生成失败: {
|
|
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
|
|
6
|
-
|
|
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/
|
|
26
|
-
# 其中reference_id为
|
|
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",
|
|
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",
|
|
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"
|
|
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",
|
|
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=
|
|
130
|
+
reference_id=reference_id,
|
|
87
131
|
)
|
|
88
132
|
|
|
89
133
|
async def get_audio(self, text: str) -> str:
|
|
90
|
-
|
|
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)
|