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
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import uuid
|
|
3
|
+
|
|
4
|
+
import aiohttp
|
|
5
|
+
from xinference_client.client.restful.async_restful_client import (
|
|
6
|
+
AsyncClient as Client,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from astrbot.core import logger
|
|
10
|
+
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
|
|
11
|
+
from astrbot.core.utils.tencent_record_helper import tencent_silk_to_wav
|
|
12
|
+
|
|
13
|
+
from ..entities import ProviderType
|
|
14
|
+
from ..provider import STTProvider
|
|
15
|
+
from ..register import register_provider_adapter
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@register_provider_adapter(
|
|
19
|
+
"xinference_stt",
|
|
20
|
+
"Xinference STT",
|
|
21
|
+
provider_type=ProviderType.SPEECH_TO_TEXT,
|
|
22
|
+
)
|
|
23
|
+
class ProviderXinferenceSTT(STTProvider):
|
|
24
|
+
def __init__(self, provider_config: dict, provider_settings: dict) -> None:
|
|
25
|
+
super().__init__(provider_config, provider_settings)
|
|
26
|
+
self.provider_config = provider_config
|
|
27
|
+
self.provider_settings = provider_settings
|
|
28
|
+
self.base_url = provider_config.get("api_base", "http://127.0.0.1:9997")
|
|
29
|
+
self.base_url = self.base_url.rstrip("/")
|
|
30
|
+
self.timeout = provider_config.get("timeout", 180)
|
|
31
|
+
self.model_name = provider_config.get("model", "whisper-large-v3")
|
|
32
|
+
self.api_key = provider_config.get("api_key")
|
|
33
|
+
self.launch_model_if_not_running = provider_config.get(
|
|
34
|
+
"launch_model_if_not_running",
|
|
35
|
+
False,
|
|
36
|
+
)
|
|
37
|
+
self.client = None
|
|
38
|
+
self.model_uid = None
|
|
39
|
+
|
|
40
|
+
async def initialize(self):
|
|
41
|
+
if self.api_key:
|
|
42
|
+
logger.info("Xinference STT: Using API key for authentication.")
|
|
43
|
+
self.client = Client(self.base_url, api_key=self.api_key)
|
|
44
|
+
else:
|
|
45
|
+
logger.info("Xinference STT: No API key provided.")
|
|
46
|
+
self.client = Client(self.base_url)
|
|
47
|
+
|
|
48
|
+
try:
|
|
49
|
+
running_models = await self.client.list_models()
|
|
50
|
+
for uid, model_spec in running_models.items():
|
|
51
|
+
if model_spec.get("model_name") == self.model_name:
|
|
52
|
+
logger.info(
|
|
53
|
+
f"Model '{self.model_name}' is already running with UID: {uid}",
|
|
54
|
+
)
|
|
55
|
+
self.model_uid = uid
|
|
56
|
+
break
|
|
57
|
+
|
|
58
|
+
if self.model_uid is None:
|
|
59
|
+
if self.launch_model_if_not_running:
|
|
60
|
+
logger.info(f"Launching {self.model_name} model...")
|
|
61
|
+
self.model_uid = await self.client.launch_model(
|
|
62
|
+
model_name=self.model_name,
|
|
63
|
+
model_type="audio",
|
|
64
|
+
)
|
|
65
|
+
logger.info("Model launched.")
|
|
66
|
+
else:
|
|
67
|
+
logger.warning(
|
|
68
|
+
f"Model '{self.model_name}' is not running and auto-launch is disabled. Provider will not be available.",
|
|
69
|
+
)
|
|
70
|
+
return
|
|
71
|
+
|
|
72
|
+
except Exception as e:
|
|
73
|
+
logger.error(f"Failed to initialize Xinference model: {e}")
|
|
74
|
+
logger.debug(
|
|
75
|
+
f"Xinference initialization failed with exception: {e}",
|
|
76
|
+
exc_info=True,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
async def get_text(self, audio_url: str) -> str:
|
|
80
|
+
if not self.model_uid or self.client is None or self.client.session is None:
|
|
81
|
+
logger.error("Xinference STT model is not initialized.")
|
|
82
|
+
return ""
|
|
83
|
+
|
|
84
|
+
audio_bytes = None
|
|
85
|
+
temp_files = []
|
|
86
|
+
is_tencent = False
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
# 1. Get audio bytes
|
|
90
|
+
if audio_url.startswith("http"):
|
|
91
|
+
if "multimedia.nt.qq.com.cn" in audio_url:
|
|
92
|
+
is_tencent = True
|
|
93
|
+
async with aiohttp.ClientSession() as session:
|
|
94
|
+
async with session.get(audio_url, timeout=self.timeout) as resp:
|
|
95
|
+
if resp.status == 200:
|
|
96
|
+
audio_bytes = await resp.read()
|
|
97
|
+
else:
|
|
98
|
+
logger.error(
|
|
99
|
+
f"Failed to download audio from {audio_url}, status: {resp.status}",
|
|
100
|
+
)
|
|
101
|
+
return ""
|
|
102
|
+
elif os.path.exists(audio_url):
|
|
103
|
+
with open(audio_url, "rb") as f:
|
|
104
|
+
audio_bytes = f.read()
|
|
105
|
+
else:
|
|
106
|
+
logger.error(f"File not found: {audio_url}")
|
|
107
|
+
return ""
|
|
108
|
+
|
|
109
|
+
if not audio_bytes:
|
|
110
|
+
logger.error("Audio bytes are empty.")
|
|
111
|
+
return ""
|
|
112
|
+
|
|
113
|
+
# 2. Check for conversion
|
|
114
|
+
needs_conversion = False
|
|
115
|
+
if (
|
|
116
|
+
audio_url.endswith((".amr", ".silk"))
|
|
117
|
+
or is_tencent
|
|
118
|
+
or b"SILK" in audio_bytes[:8]
|
|
119
|
+
):
|
|
120
|
+
needs_conversion = True
|
|
121
|
+
|
|
122
|
+
# 3. Perform conversion if needed
|
|
123
|
+
if needs_conversion:
|
|
124
|
+
logger.info("Audio requires conversion, using temporary files...")
|
|
125
|
+
temp_dir = os.path.join(get_astrbot_data_path(), "temp")
|
|
126
|
+
os.makedirs(temp_dir, exist_ok=True)
|
|
127
|
+
|
|
128
|
+
input_path = os.path.join(temp_dir, str(uuid.uuid4()))
|
|
129
|
+
output_path = os.path.join(temp_dir, str(uuid.uuid4()) + ".wav")
|
|
130
|
+
temp_files.extend([input_path, output_path])
|
|
131
|
+
|
|
132
|
+
with open(input_path, "wb") as f:
|
|
133
|
+
f.write(audio_bytes)
|
|
134
|
+
|
|
135
|
+
logger.info("Converting silk/amr file to wav ...")
|
|
136
|
+
await tencent_silk_to_wav(input_path, output_path)
|
|
137
|
+
|
|
138
|
+
with open(output_path, "rb") as f:
|
|
139
|
+
audio_bytes = f.read()
|
|
140
|
+
|
|
141
|
+
# 4. Transcribe
|
|
142
|
+
# 官方asyncCLient的客户端似乎实现有点问题,这里直接用aiohttp实现openai标准兼容请求,提交issue等待官方修复后再改回来
|
|
143
|
+
url = f"{self.base_url}/v1/audio/transcriptions"
|
|
144
|
+
headers = {
|
|
145
|
+
"accept": "application/json",
|
|
146
|
+
}
|
|
147
|
+
if self.client and self.client._headers:
|
|
148
|
+
headers.update(self.client._headers)
|
|
149
|
+
|
|
150
|
+
data = aiohttp.FormData()
|
|
151
|
+
data.add_field("model", self.model_uid)
|
|
152
|
+
data.add_field(
|
|
153
|
+
"file",
|
|
154
|
+
audio_bytes,
|
|
155
|
+
filename="audio.wav",
|
|
156
|
+
content_type="audio/wav",
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
async with self.client.session.post(
|
|
160
|
+
url,
|
|
161
|
+
data=data,
|
|
162
|
+
headers=headers,
|
|
163
|
+
timeout=self.timeout,
|
|
164
|
+
) as resp:
|
|
165
|
+
if resp.status == 200:
|
|
166
|
+
result = await resp.json()
|
|
167
|
+
text = result.get("text", "")
|
|
168
|
+
logger.debug(f"Xinference STT result: {text}")
|
|
169
|
+
return text
|
|
170
|
+
error_text = await resp.text()
|
|
171
|
+
logger.error(
|
|
172
|
+
f"Xinference STT transcription failed with status {resp.status}: {error_text}",
|
|
173
|
+
)
|
|
174
|
+
return ""
|
|
175
|
+
|
|
176
|
+
except Exception as e:
|
|
177
|
+
logger.error(f"Xinference STT failed: {e}")
|
|
178
|
+
logger.debug(f"Xinference STT failed with exception: {e}", exc_info=True)
|
|
179
|
+
return ""
|
|
180
|
+
finally:
|
|
181
|
+
# 5. Cleanup
|
|
182
|
+
for temp_file in temp_files:
|
|
183
|
+
try:
|
|
184
|
+
if os.path.exists(temp_file):
|
|
185
|
+
os.remove(temp_file)
|
|
186
|
+
logger.debug(f"Removed temporary file: {temp_file}")
|
|
187
|
+
except Exception as e:
|
|
188
|
+
logger.error(f"Failed to remove temporary file {temp_file}: {e}")
|
|
189
|
+
|
|
190
|
+
async def terminate(self) -> None:
|
|
191
|
+
"""关闭客户端会话"""
|
|
192
|
+
if self.client:
|
|
193
|
+
logger.info("Closing Xinference STT client...")
|
|
194
|
+
try:
|
|
195
|
+
await self.client.close()
|
|
196
|
+
except Exception as e:
|
|
197
|
+
logger.error(f"Failed to close Xinference client: {e}", exc_info=True)
|
|
@@ -1,83 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
# This file was originally created to adapt to glm-4v-flash, which only supports one image in the context.
|
|
2
|
+
# It is no longer specifically adapted to Zhipu's models. To ensure compatibility, this
|
|
3
|
+
|
|
4
|
+
|
|
5
5
|
from ..register import register_provider_adapter
|
|
6
|
-
from astrbot.core.provider.entities import LLMResponse
|
|
7
6
|
from .openai_source import ProviderOpenAIOfficial
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
@register_provider_adapter("zhipu_chat_completion", "
|
|
9
|
+
@register_provider_adapter("zhipu_chat_completion", "智谱 Chat Completion 提供商适配器")
|
|
11
10
|
class ProviderZhipu(ProviderOpenAIOfficial):
|
|
12
11
|
def __init__(
|
|
13
12
|
self,
|
|
14
13
|
provider_config: dict,
|
|
15
14
|
provider_settings: dict,
|
|
16
|
-
db_helper: BaseDatabase,
|
|
17
|
-
persistant_history=True,
|
|
18
|
-
default_persona=None,
|
|
19
15
|
) -> None:
|
|
20
|
-
super().__init__(
|
|
21
|
-
provider_config,
|
|
22
|
-
provider_settings,
|
|
23
|
-
db_helper,
|
|
24
|
-
persistant_history,
|
|
25
|
-
default_persona,
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
async def text_chat(
|
|
29
|
-
self,
|
|
30
|
-
prompt: str,
|
|
31
|
-
session_id: str = None,
|
|
32
|
-
image_urls: List[str] = None,
|
|
33
|
-
func_tool: FuncCall = None,
|
|
34
|
-
contexts=[],
|
|
35
|
-
system_prompt=None,
|
|
36
|
-
**kwargs,
|
|
37
|
-
) -> LLMResponse:
|
|
38
|
-
new_record = await self.assemble_context(prompt, image_urls)
|
|
39
|
-
context_query = []
|
|
40
|
-
|
|
41
|
-
context_query = [*contexts, new_record]
|
|
42
|
-
|
|
43
|
-
model_cfgs: dict = self.provider_config.get("model_config", {})
|
|
44
|
-
model = self.get_model()
|
|
45
|
-
# glm-4v-flash 只支持一张图片
|
|
46
|
-
if model.lower() == "glm-4v-flash" and image_urls and len(context_query) > 1:
|
|
47
|
-
logger.debug("glm-4v-flash 只支持一张图片,将只保留最后一张图片")
|
|
48
|
-
logger.debug(context_query)
|
|
49
|
-
new_context_query_ = []
|
|
50
|
-
for i in range(0, len(context_query) - 1, 2):
|
|
51
|
-
if isinstance(context_query[i].get("content", ""), list):
|
|
52
|
-
continue
|
|
53
|
-
new_context_query_.append(context_query[i])
|
|
54
|
-
new_context_query_.append(context_query[i + 1])
|
|
55
|
-
new_context_query_.append(context_query[-1]) # 保留最后一条记录
|
|
56
|
-
context_query = new_context_query_
|
|
57
|
-
logger.debug(context_query)
|
|
58
|
-
|
|
59
|
-
if system_prompt:
|
|
60
|
-
context_query.insert(0, {"role": "system", "content": system_prompt})
|
|
61
|
-
|
|
62
|
-
payloads = {"messages": context_query, **model_cfgs}
|
|
63
|
-
try:
|
|
64
|
-
llm_response = await self._query(payloads, func_tool)
|
|
65
|
-
return llm_response
|
|
66
|
-
except Exception as e:
|
|
67
|
-
if "maximum context length" in str(e):
|
|
68
|
-
retry_cnt = 10
|
|
69
|
-
while retry_cnt > 0:
|
|
70
|
-
logger.warning(
|
|
71
|
-
f"请求失败:{e}。上下文长度超过限制。尝试弹出最早的记录然后重试。"
|
|
72
|
-
)
|
|
73
|
-
try:
|
|
74
|
-
self.pop_record(session_id)
|
|
75
|
-
llm_response = await self._query(payloads, func_tool)
|
|
76
|
-
break
|
|
77
|
-
except Exception as e:
|
|
78
|
-
if "maximum context length" in str(e):
|
|
79
|
-
retry_cnt -= 1
|
|
80
|
-
else:
|
|
81
|
-
raise e
|
|
82
|
-
else:
|
|
83
|
-
raise e
|
|
16
|
+
super().__init__(provider_config, provider_settings)
|
astrbot/core/star/__init__.py
CHANGED
|
@@ -1,32 +1,64 @@
|
|
|
1
|
-
from .star import StarMetadata
|
|
2
|
-
from .star_manager import PluginManager
|
|
3
|
-
from .context import Context
|
|
4
|
-
from astrbot.core.provider import Provider
|
|
5
|
-
from astrbot.core.utils.command_parser import CommandParserMixin
|
|
6
1
|
from astrbot.core import html_renderer
|
|
2
|
+
from astrbot.core.provider import Provider
|
|
7
3
|
from astrbot.core.star.star_tools import StarTools
|
|
4
|
+
from astrbot.core.utils.command_parser import CommandParserMixin
|
|
5
|
+
|
|
6
|
+
from .context import Context
|
|
7
|
+
from .star import StarMetadata, star_map, star_registry
|
|
8
|
+
from .star_manager import PluginManager
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class Star(CommandParserMixin):
|
|
11
12
|
"""所有插件(Star)的父类,所有插件都应该继承于这个类"""
|
|
12
13
|
|
|
13
|
-
def __init__(self, context: Context):
|
|
14
|
+
def __init__(self, context: Context, config: dict | None = None):
|
|
14
15
|
StarTools.initialize(context)
|
|
15
16
|
self.context = context
|
|
16
17
|
|
|
18
|
+
def __init_subclass__(cls, **kwargs):
|
|
19
|
+
super().__init_subclass__(**kwargs)
|
|
20
|
+
if not star_map.get(cls.__module__):
|
|
21
|
+
metadata = StarMetadata(
|
|
22
|
+
star_cls_type=cls,
|
|
23
|
+
module_path=cls.__module__,
|
|
24
|
+
)
|
|
25
|
+
star_map[cls.__module__] = metadata
|
|
26
|
+
star_registry.append(metadata)
|
|
27
|
+
else:
|
|
28
|
+
star_map[cls.__module__].star_cls_type = cls
|
|
29
|
+
star_map[cls.__module__].module_path = cls.__module__
|
|
30
|
+
|
|
17
31
|
async def text_to_image(self, text: str, return_url=True) -> str:
|
|
18
32
|
"""将文本转换为图片"""
|
|
19
|
-
return await html_renderer.render_t2i(
|
|
33
|
+
return await html_renderer.render_t2i(
|
|
34
|
+
text,
|
|
35
|
+
return_url=return_url,
|
|
36
|
+
template_name=self.context._config.get("t2i_active_template"),
|
|
37
|
+
)
|
|
20
38
|
|
|
21
|
-
async def html_render(
|
|
39
|
+
async def html_render(
|
|
40
|
+
self,
|
|
41
|
+
tmpl: str,
|
|
42
|
+
data: dict,
|
|
43
|
+
return_url=True,
|
|
44
|
+
options: dict | None = None,
|
|
45
|
+
) -> str:
|
|
22
46
|
"""渲染 HTML"""
|
|
23
47
|
return await html_renderer.render_custom_template(
|
|
24
|
-
tmpl,
|
|
48
|
+
tmpl,
|
|
49
|
+
data,
|
|
50
|
+
return_url=return_url,
|
|
51
|
+
options=options,
|
|
25
52
|
)
|
|
26
53
|
|
|
54
|
+
async def initialize(self):
|
|
55
|
+
"""当插件被激活时会调用这个方法"""
|
|
56
|
+
|
|
27
57
|
async def terminate(self):
|
|
28
58
|
"""当插件被禁用、重载插件时会调用这个方法"""
|
|
29
|
-
|
|
59
|
+
|
|
60
|
+
def __del__(self):
|
|
61
|
+
"""[Deprecated] 当插件被禁用、重载插件时会调用这个方法"""
|
|
30
62
|
|
|
31
63
|
|
|
32
|
-
__all__ = ["
|
|
64
|
+
__all__ = ["Context", "PluginManager", "Provider", "Star", "StarMetadata", "StarTools"]
|
astrbot/core/star/config.py
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
"""
|
|
2
|
-
此功能已过时,参考 https://astrbot.app/dev/plugin.html#%E6%B3%A8%E5%86%8C%E6%8F%92%E4%BB%B6%E9%85%8D%E7%BD%AE-beta
|
|
3
|
-
"""
|
|
1
|
+
"""此功能已过时,参考 https://astrbot.app/dev/plugin.html#%E6%B3%A8%E5%86%8C%E6%8F%92%E4%BB%B6%E9%85%8D%E7%BD%AE-beta"""
|
|
4
2
|
|
|
5
|
-
from typing import Union
|
|
6
|
-
import os
|
|
7
3
|
import json
|
|
4
|
+
import os
|
|
8
5
|
|
|
6
|
+
from astrbot.core.utils.astrbot_path import get_astrbot_data_path
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
从配置文件中加载配置。
|
|
8
|
+
|
|
9
|
+
def load_config(namespace: str) -> dict | bool:
|
|
10
|
+
"""从配置文件中加载配置。
|
|
13
11
|
namespace: str, 配置的唯一识别符,也就是配置文件的名字。
|
|
14
12
|
返回值: 当配置文件存在时,返回 namespace 对应配置文件的内容dict,否则返回 False。
|
|
15
13
|
"""
|
|
16
|
-
path = f"
|
|
14
|
+
path = os.path.join(get_astrbot_data_path(), "config", f"{namespace}.json")
|
|
17
15
|
if not os.path.exists(path):
|
|
18
16
|
return False
|
|
19
|
-
with open(path,
|
|
17
|
+
with open(path, encoding="utf-8-sig") as f:
|
|
20
18
|
ret = {}
|
|
21
19
|
data = json.load(f)
|
|
22
20
|
for k in data:
|
|
@@ -25,8 +23,7 @@ def load_config(namespace: str) -> Union[dict, bool]:
|
|
|
25
23
|
|
|
26
24
|
|
|
27
25
|
def put_config(namespace: str, name: str, key: str, value, description: str):
|
|
28
|
-
"""
|
|
29
|
-
将配置项写入以namespace为名字的配置文件,如果key不存在于目标配置文件中。当前 value 仅支持 str, int, float, bool, list 类型(暂不支持 dict)。
|
|
26
|
+
"""将配置项写入以namespace为名字的配置文件,如果key不存在于目标配置文件中。当前 value 仅支持 str, int, float, bool, list 类型(暂不支持 dict)。
|
|
30
27
|
namespace: str, 配置的唯一识别符,也就是配置文件的名字。
|
|
31
28
|
name: str, 配置项的显示名字。
|
|
32
29
|
key: str, 配置项的键。
|
|
@@ -43,11 +40,14 @@ def put_config(namespace: str, name: str, key: str, value, description: str):
|
|
|
43
40
|
raise ValueError("key 只支持 str 类型。")
|
|
44
41
|
if not isinstance(value, (str, int, float, bool, list)):
|
|
45
42
|
raise ValueError("value 只支持 str, int, float, bool, list 类型。")
|
|
46
|
-
|
|
43
|
+
|
|
44
|
+
config_dir = os.path.join(get_astrbot_data_path(), "config")
|
|
45
|
+
path = os.path.join(config_dir, f"{namespace}.json")
|
|
46
|
+
|
|
47
47
|
if not os.path.exists(path):
|
|
48
48
|
with open(path, "w", encoding="utf-8-sig") as f:
|
|
49
49
|
f.write("{}")
|
|
50
|
-
with open(path,
|
|
50
|
+
with open(path, encoding="utf-8-sig") as f:
|
|
51
51
|
d = json.load(f)
|
|
52
52
|
assert isinstance(d, dict)
|
|
53
53
|
if key not in d:
|
|
@@ -65,16 +65,15 @@ def put_config(namespace: str, name: str, key: str, value, description: str):
|
|
|
65
65
|
|
|
66
66
|
|
|
67
67
|
def update_config(namespace: str, key: str, value):
|
|
68
|
-
"""
|
|
69
|
-
更新配置文件中的配置项。
|
|
68
|
+
"""更新配置文件中的配置项。
|
|
70
69
|
namespace: str, 配置的唯一识别符,也就是配置文件的名字。
|
|
71
70
|
key: str, 配置项的键。
|
|
72
71
|
value: str, int, float, bool, list, 配置项的值。
|
|
73
72
|
"""
|
|
74
|
-
path = f"
|
|
73
|
+
path = os.path.join(get_astrbot_data_path(), "config", f"{namespace}.json")
|
|
75
74
|
if not os.path.exists(path):
|
|
76
75
|
raise FileNotFoundError(f"配置文件 {namespace}.json 不存在。")
|
|
77
|
-
with open(path,
|
|
76
|
+
with open(path, encoding="utf-8-sig") as f:
|
|
78
77
|
d = json.load(f)
|
|
79
78
|
assert isinstance(d, dict)
|
|
80
79
|
if key not in d:
|