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,233 @@
|
|
|
1
|
+
# astrbot/dashboard/routes/t2i.py
|
|
2
|
+
|
|
3
|
+
from dataclasses import asdict
|
|
4
|
+
|
|
5
|
+
from quart import jsonify, request
|
|
6
|
+
|
|
7
|
+
from astrbot.core import logger
|
|
8
|
+
from astrbot.core.core_lifecycle import AstrBotCoreLifecycle
|
|
9
|
+
from astrbot.core.utils.t2i.template_manager import TemplateManager
|
|
10
|
+
|
|
11
|
+
from .route import Response, Route, RouteContext
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class T2iRoute(Route):
|
|
15
|
+
def __init__(self, context: RouteContext, core_lifecycle: AstrBotCoreLifecycle):
|
|
16
|
+
super().__init__(context)
|
|
17
|
+
self.core_lifecycle = core_lifecycle
|
|
18
|
+
self.config = core_lifecycle.astrbot_config
|
|
19
|
+
self.manager = TemplateManager()
|
|
20
|
+
# 使用列表保证路由注册顺序,避免 /<name> 路由优先匹配 /reset_default
|
|
21
|
+
self.routes = [
|
|
22
|
+
("/t2i/templates", ("GET", self.list_templates)),
|
|
23
|
+
("/t2i/templates/active", ("GET", self.get_active_template)),
|
|
24
|
+
("/t2i/templates/create", ("POST", self.create_template)),
|
|
25
|
+
("/t2i/templates/reset_default", ("POST", self.reset_default_template)),
|
|
26
|
+
("/t2i/templates/set_active", ("POST", self.set_active_template)),
|
|
27
|
+
# 动态路由应该在静态路由之后注册
|
|
28
|
+
(
|
|
29
|
+
"/t2i/templates/<name>",
|
|
30
|
+
[
|
|
31
|
+
("GET", self.get_template),
|
|
32
|
+
("PUT", self.update_template),
|
|
33
|
+
("DELETE", self.delete_template),
|
|
34
|
+
],
|
|
35
|
+
),
|
|
36
|
+
]
|
|
37
|
+
self.register_routes()
|
|
38
|
+
|
|
39
|
+
async def list_templates(self):
|
|
40
|
+
"""获取所有T2I模板列表"""
|
|
41
|
+
try:
|
|
42
|
+
templates = self.manager.list_templates()
|
|
43
|
+
return jsonify(asdict(Response().ok(data=templates)))
|
|
44
|
+
except Exception as e:
|
|
45
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
46
|
+
response.status_code = 500
|
|
47
|
+
return response
|
|
48
|
+
|
|
49
|
+
async def get_active_template(self):
|
|
50
|
+
"""获取当前激活的T2I模板"""
|
|
51
|
+
try:
|
|
52
|
+
active_template = self.config.get("t2i_active_template", "base")
|
|
53
|
+
return jsonify(
|
|
54
|
+
asdict(Response().ok(data={"active_template": active_template})),
|
|
55
|
+
)
|
|
56
|
+
except Exception as e:
|
|
57
|
+
logger.error("Error in get_active_template", exc_info=True)
|
|
58
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
59
|
+
response.status_code = 500
|
|
60
|
+
return response
|
|
61
|
+
|
|
62
|
+
async def get_template(self, name: str):
|
|
63
|
+
"""获取指定名称的T2I模板内容"""
|
|
64
|
+
try:
|
|
65
|
+
content = self.manager.get_template(name)
|
|
66
|
+
return jsonify(
|
|
67
|
+
asdict(Response().ok(data={"name": name, "content": content})),
|
|
68
|
+
)
|
|
69
|
+
except FileNotFoundError:
|
|
70
|
+
response = jsonify(asdict(Response().error("Template not found")))
|
|
71
|
+
response.status_code = 404
|
|
72
|
+
return response
|
|
73
|
+
except Exception as e:
|
|
74
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
75
|
+
response.status_code = 500
|
|
76
|
+
return response
|
|
77
|
+
|
|
78
|
+
async def create_template(self):
|
|
79
|
+
"""创建一个新的T2I模板"""
|
|
80
|
+
try:
|
|
81
|
+
data = await request.json
|
|
82
|
+
name = data.get("name")
|
|
83
|
+
content = data.get("content")
|
|
84
|
+
if not name or not content:
|
|
85
|
+
response = jsonify(
|
|
86
|
+
asdict(Response().error("Name and content are required.")),
|
|
87
|
+
)
|
|
88
|
+
response.status_code = 400
|
|
89
|
+
return response
|
|
90
|
+
name = name.strip()
|
|
91
|
+
|
|
92
|
+
self.manager.create_template(name, content)
|
|
93
|
+
response = jsonify(
|
|
94
|
+
asdict(
|
|
95
|
+
Response().ok(
|
|
96
|
+
data={"name": name},
|
|
97
|
+
message="Template created successfully.",
|
|
98
|
+
),
|
|
99
|
+
),
|
|
100
|
+
)
|
|
101
|
+
response.status_code = 201
|
|
102
|
+
return response
|
|
103
|
+
except FileExistsError:
|
|
104
|
+
response = jsonify(
|
|
105
|
+
asdict(Response().error("Template with this name already exists.")),
|
|
106
|
+
)
|
|
107
|
+
response.status_code = 409
|
|
108
|
+
return response
|
|
109
|
+
except ValueError as e:
|
|
110
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
111
|
+
response.status_code = 400
|
|
112
|
+
return response
|
|
113
|
+
except Exception as e:
|
|
114
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
115
|
+
response.status_code = 500
|
|
116
|
+
return response
|
|
117
|
+
|
|
118
|
+
async def update_template(self, name: str):
|
|
119
|
+
"""更新一个已存在的T2I模板"""
|
|
120
|
+
try:
|
|
121
|
+
name = name.strip()
|
|
122
|
+
data = await request.json
|
|
123
|
+
content = data.get("content")
|
|
124
|
+
if content is None:
|
|
125
|
+
response = jsonify(asdict(Response().error("Content is required.")))
|
|
126
|
+
response.status_code = 400
|
|
127
|
+
return response
|
|
128
|
+
|
|
129
|
+
self.manager.update_template(name, content)
|
|
130
|
+
|
|
131
|
+
# 检查更新的是否为当前激活的模板,如果是,则热重载
|
|
132
|
+
active_template = self.config.get("t2i_active_template", "base")
|
|
133
|
+
if name == active_template:
|
|
134
|
+
await self.core_lifecycle.reload_pipeline_scheduler("default")
|
|
135
|
+
message = f"模板 '{name}' 已更新并重新加载。"
|
|
136
|
+
else:
|
|
137
|
+
message = f"模板 '{name}' 已更新。"
|
|
138
|
+
|
|
139
|
+
return jsonify(asdict(Response().ok(data={"name": name}, message=message)))
|
|
140
|
+
except ValueError as e:
|
|
141
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
142
|
+
response.status_code = 400
|
|
143
|
+
return response
|
|
144
|
+
except Exception as e:
|
|
145
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
146
|
+
response.status_code = 500
|
|
147
|
+
return response
|
|
148
|
+
|
|
149
|
+
async def delete_template(self, name: str):
|
|
150
|
+
"""删除一个T2I模板"""
|
|
151
|
+
try:
|
|
152
|
+
name = name.strip()
|
|
153
|
+
self.manager.delete_template(name)
|
|
154
|
+
return jsonify(
|
|
155
|
+
asdict(Response().ok(message="Template deleted successfully.")),
|
|
156
|
+
)
|
|
157
|
+
except FileNotFoundError:
|
|
158
|
+
response = jsonify(asdict(Response().error("Template not found.")))
|
|
159
|
+
response.status_code = 404
|
|
160
|
+
return response
|
|
161
|
+
except ValueError as e:
|
|
162
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
163
|
+
response.status_code = 400
|
|
164
|
+
return response
|
|
165
|
+
except Exception as e:
|
|
166
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
167
|
+
response.status_code = 500
|
|
168
|
+
return response
|
|
169
|
+
|
|
170
|
+
async def set_active_template(self):
|
|
171
|
+
"""设置当前活动的T2I模板"""
|
|
172
|
+
try:
|
|
173
|
+
data = await request.json
|
|
174
|
+
name = data.get("name")
|
|
175
|
+
if not name:
|
|
176
|
+
response = jsonify(asdict(Response().error("模板名称(name)不能为空。")))
|
|
177
|
+
response.status_code = 400
|
|
178
|
+
return response
|
|
179
|
+
|
|
180
|
+
# 验证模板文件是否存在
|
|
181
|
+
self.manager.get_template(name)
|
|
182
|
+
|
|
183
|
+
# 更新配置
|
|
184
|
+
config = self.config
|
|
185
|
+
config["t2i_active_template"] = name
|
|
186
|
+
config.save_config(config)
|
|
187
|
+
|
|
188
|
+
# 热重载以应用更改
|
|
189
|
+
await self.core_lifecycle.reload_pipeline_scheduler("default")
|
|
190
|
+
|
|
191
|
+
return jsonify(asdict(Response().ok(message=f"模板 '{name}' 已成功应用。")))
|
|
192
|
+
|
|
193
|
+
except FileNotFoundError:
|
|
194
|
+
response = jsonify(
|
|
195
|
+
asdict(Response().error(f"模板 '{name}' 不存在,无法应用。")),
|
|
196
|
+
)
|
|
197
|
+
response.status_code = 404
|
|
198
|
+
return response
|
|
199
|
+
except Exception as e:
|
|
200
|
+
logger.error("Error in set_active_template", exc_info=True)
|
|
201
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
202
|
+
response.status_code = 500
|
|
203
|
+
return response
|
|
204
|
+
|
|
205
|
+
async def reset_default_template(self):
|
|
206
|
+
"""重置默认的'base'模板"""
|
|
207
|
+
try:
|
|
208
|
+
self.manager.reset_default_template()
|
|
209
|
+
|
|
210
|
+
# 更新配置,将激活模板也重置为'base'
|
|
211
|
+
config = self.config
|
|
212
|
+
config["t2i_active_template"] = "base"
|
|
213
|
+
config.save_config(config)
|
|
214
|
+
|
|
215
|
+
# 热重载以应用更改
|
|
216
|
+
await self.core_lifecycle.reload_pipeline_scheduler("default")
|
|
217
|
+
|
|
218
|
+
return jsonify(
|
|
219
|
+
asdict(
|
|
220
|
+
Response().ok(
|
|
221
|
+
message="Default template has been reset and activated.",
|
|
222
|
+
),
|
|
223
|
+
),
|
|
224
|
+
)
|
|
225
|
+
except FileNotFoundError as e:
|
|
226
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
227
|
+
response.status_code = 404
|
|
228
|
+
return response
|
|
229
|
+
except Exception as e:
|
|
230
|
+
logger.error("Error in reset_default_template", exc_info=True)
|
|
231
|
+
response = jsonify(asdict(Response().error(str(e))))
|
|
232
|
+
response.status_code = 500
|
|
233
|
+
return response
|
|
@@ -1,18 +1,21 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import json
|
|
3
|
-
import aiohttp
|
|
4
1
|
import traceback
|
|
5
|
-
|
|
2
|
+
|
|
6
3
|
from quart import request
|
|
7
|
-
|
|
4
|
+
|
|
8
5
|
from astrbot.core import logger
|
|
6
|
+
from astrbot.core.core_lifecycle import AstrBotCoreLifecycle
|
|
7
|
+
from astrbot.core.star import star_map
|
|
8
|
+
|
|
9
|
+
from .route import Response, Route, RouteContext
|
|
9
10
|
|
|
10
11
|
DEFAULT_MCP_CONFIG = {"mcpServers": {}}
|
|
11
12
|
|
|
12
13
|
|
|
13
14
|
class ToolsRoute(Route):
|
|
14
15
|
def __init__(
|
|
15
|
-
self,
|
|
16
|
+
self,
|
|
17
|
+
context: RouteContext,
|
|
18
|
+
core_lifecycle: AstrBotCoreLifecycle,
|
|
16
19
|
) -> None:
|
|
17
20
|
super().__init__(context)
|
|
18
21
|
self.core_lifecycle = core_lifecycle
|
|
@@ -21,44 +24,17 @@ class ToolsRoute(Route):
|
|
|
21
24
|
"/tools/mcp/add": ("POST", self.add_mcp_server),
|
|
22
25
|
"/tools/mcp/update": ("POST", self.update_mcp_server),
|
|
23
26
|
"/tools/mcp/delete": ("POST", self.delete_mcp_server),
|
|
24
|
-
"/tools/mcp/
|
|
27
|
+
"/tools/mcp/test": ("POST", self.test_mcp_connection),
|
|
28
|
+
"/tools/list": ("GET", self.get_tool_list),
|
|
29
|
+
"/tools/toggle-tool": ("POST", self.toggle_tool),
|
|
30
|
+
"/tools/mcp/sync-provider": ("POST", self.sync_provider),
|
|
25
31
|
}
|
|
26
32
|
self.register_routes()
|
|
27
33
|
self.tool_mgr = self.core_lifecycle.provider_manager.llm_tools
|
|
28
34
|
|
|
29
|
-
@property
|
|
30
|
-
def mcp_config_path(self):
|
|
31
|
-
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
32
|
-
data_dir = os.path.abspath(os.path.join(current_dir, "../../../data"))
|
|
33
|
-
return os.path.join(data_dir, "mcp_server.json")
|
|
34
|
-
|
|
35
|
-
def load_mcp_config(self):
|
|
36
|
-
if not os.path.exists(self.mcp_config_path):
|
|
37
|
-
# 配置文件不存在,创建默认配置
|
|
38
|
-
os.makedirs(os.path.dirname(self.mcp_config_path), exist_ok=True)
|
|
39
|
-
with open(self.mcp_config_path, "w", encoding="utf-8") as f:
|
|
40
|
-
json.dump(DEFAULT_MCP_CONFIG, f, ensure_ascii=False, indent=4)
|
|
41
|
-
return DEFAULT_MCP_CONFIG
|
|
42
|
-
|
|
43
|
-
try:
|
|
44
|
-
with open(self.mcp_config_path, "r", encoding="utf-8") as f:
|
|
45
|
-
return json.load(f)
|
|
46
|
-
except Exception as e:
|
|
47
|
-
logger.error(f"加载 MCP 配置失败: {e}")
|
|
48
|
-
return DEFAULT_MCP_CONFIG
|
|
49
|
-
|
|
50
|
-
def save_mcp_config(self, config):
|
|
51
|
-
try:
|
|
52
|
-
with open(self.mcp_config_path, "w", encoding="utf-8") as f:
|
|
53
|
-
json.dump(config, f, ensure_ascii=False, indent=4)
|
|
54
|
-
return True
|
|
55
|
-
except Exception as e:
|
|
56
|
-
logger.error(f"保存 MCP 配置失败: {e}")
|
|
57
|
-
return False
|
|
58
|
-
|
|
59
35
|
async def get_mcp_servers(self):
|
|
60
36
|
try:
|
|
61
|
-
config = self.load_mcp_config()
|
|
37
|
+
config = self.tool_mgr.load_mcp_config()
|
|
62
38
|
servers = []
|
|
63
39
|
|
|
64
40
|
# 获取所有服务器并添加它们的工具列表
|
|
@@ -90,7 +66,7 @@ class ToolsRoute(Route):
|
|
|
90
66
|
return Response().ok(servers).__dict__
|
|
91
67
|
except Exception as e:
|
|
92
68
|
logger.error(traceback.format_exc())
|
|
93
|
-
return Response().error(f"获取 MCP 服务器列表失败: {
|
|
69
|
+
return Response().error(f"获取 MCP 服务器列表失败: {e!s}").__dict__
|
|
94
70
|
|
|
95
71
|
async def add_mcp_server(self):
|
|
96
72
|
try:
|
|
@@ -121,28 +97,32 @@ class ToolsRoute(Route):
|
|
|
121
97
|
if not has_valid_config:
|
|
122
98
|
return Response().error("必须提供有效的服务器配置").__dict__
|
|
123
99
|
|
|
124
|
-
config = self.load_mcp_config()
|
|
100
|
+
config = self.tool_mgr.load_mcp_config()
|
|
125
101
|
|
|
126
102
|
if name in config["mcpServers"]:
|
|
127
103
|
return Response().error(f"服务器 {name} 已存在").__dict__
|
|
128
104
|
|
|
129
105
|
config["mcpServers"][name] = server_config
|
|
130
106
|
|
|
131
|
-
if self.save_mcp_config(config):
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
107
|
+
if self.tool_mgr.save_mcp_config(config):
|
|
108
|
+
try:
|
|
109
|
+
await self.tool_mgr.enable_mcp_server(
|
|
110
|
+
name,
|
|
111
|
+
server_config,
|
|
112
|
+
timeout=30,
|
|
113
|
+
)
|
|
114
|
+
except TimeoutError:
|
|
115
|
+
return Response().error(f"启用 MCP 服务器 {name} 超时。").__dict__
|
|
116
|
+
except Exception as e:
|
|
117
|
+
logger.error(traceback.format_exc())
|
|
118
|
+
return (
|
|
119
|
+
Response().error(f"启用 MCP 服务器 {name} 失败: {e!s}").__dict__
|
|
120
|
+
)
|
|
140
121
|
return Response().ok(None, f"成功添加 MCP 服务器 {name}").__dict__
|
|
141
|
-
|
|
142
|
-
return Response().error("保存配置失败").__dict__
|
|
122
|
+
return Response().error("保存配置失败").__dict__
|
|
143
123
|
except Exception as e:
|
|
144
124
|
logger.error(traceback.format_exc())
|
|
145
|
-
return Response().error(f"添加 MCP 服务器失败: {
|
|
125
|
+
return Response().error(f"添加 MCP 服务器失败: {e!s}").__dict__
|
|
146
126
|
|
|
147
127
|
async def update_mcp_server(self):
|
|
148
128
|
try:
|
|
@@ -153,14 +133,15 @@ class ToolsRoute(Route):
|
|
|
153
133
|
if not name:
|
|
154
134
|
return Response().error("服务器名称不能为空").__dict__
|
|
155
135
|
|
|
156
|
-
config = self.load_mcp_config()
|
|
136
|
+
config = self.tool_mgr.load_mcp_config()
|
|
157
137
|
|
|
158
138
|
if name not in config["mcpServers"]:
|
|
159
139
|
return Response().error(f"服务器 {name} 不存在").__dict__
|
|
160
140
|
|
|
161
141
|
# 获取活动状态
|
|
162
142
|
active = server_data.get(
|
|
163
|
-
"active",
|
|
143
|
+
"active",
|
|
144
|
+
config["mcpServers"][name].get("active", True),
|
|
164
145
|
)
|
|
165
146
|
|
|
166
147
|
# 创建新的配置对象
|
|
@@ -189,49 +170,63 @@ class ToolsRoute(Route):
|
|
|
189
170
|
|
|
190
171
|
config["mcpServers"][name] = server_config
|
|
191
172
|
|
|
192
|
-
if self.save_mcp_config(config):
|
|
173
|
+
if self.tool_mgr.save_mcp_config(config):
|
|
193
174
|
# 处理MCP客户端状态变化
|
|
194
175
|
if active:
|
|
195
|
-
# 如果要激活服务器或者配置已更改
|
|
196
176
|
if name in self.tool_mgr.mcp_client_dict or not only_update_active:
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
177
|
+
try:
|
|
178
|
+
await self.tool_mgr.disable_mcp_server(name, timeout=10)
|
|
179
|
+
except TimeoutError as e:
|
|
180
|
+
return (
|
|
181
|
+
Response()
|
|
182
|
+
.error(f"启用前停用 MCP 服务器时 {name} 超时: {e!s}")
|
|
183
|
+
.__dict__
|
|
184
|
+
)
|
|
185
|
+
except Exception as e:
|
|
186
|
+
logger.error(traceback.format_exc())
|
|
187
|
+
return (
|
|
188
|
+
Response()
|
|
189
|
+
.error(f"启用前停用 MCP 服务器时 {name} 失败: {e!s}")
|
|
190
|
+
.__dict__
|
|
191
|
+
)
|
|
192
|
+
try:
|
|
193
|
+
await self.tool_mgr.enable_mcp_server(
|
|
194
|
+
name,
|
|
195
|
+
config["mcpServers"][name],
|
|
196
|
+
timeout=30,
|
|
202
197
|
)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
"name": name,
|
|
207
|
-
"cfg": config["mcpServers"][name],
|
|
208
|
-
}
|
|
198
|
+
except TimeoutError:
|
|
199
|
+
return (
|
|
200
|
+
Response().error(f"启用 MCP 服务器 {name} 超时。").__dict__
|
|
209
201
|
)
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
"cfg": config["mcpServers"][name],
|
|
217
|
-
}
|
|
202
|
+
except Exception as e:
|
|
203
|
+
logger.error(traceback.format_exc())
|
|
204
|
+
return (
|
|
205
|
+
Response()
|
|
206
|
+
.error(f"启用 MCP 服务器 {name} 失败: {e!s}")
|
|
207
|
+
.__dict__
|
|
218
208
|
)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
self.tool_mgr.
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
209
|
+
# 如果要停用服务器
|
|
210
|
+
elif name in self.tool_mgr.mcp_client_dict:
|
|
211
|
+
try:
|
|
212
|
+
await self.tool_mgr.disable_mcp_server(name, timeout=10)
|
|
213
|
+
except TimeoutError:
|
|
214
|
+
return (
|
|
215
|
+
Response().error(f"停用 MCP 服务器 {name} 超时。").__dict__
|
|
216
|
+
)
|
|
217
|
+
except Exception as e:
|
|
218
|
+
logger.error(traceback.format_exc())
|
|
219
|
+
return (
|
|
220
|
+
Response()
|
|
221
|
+
.error(f"停用 MCP 服务器 {name} 失败: {e!s}")
|
|
222
|
+
.__dict__
|
|
227
223
|
)
|
|
228
224
|
|
|
229
225
|
return Response().ok(None, f"成功更新 MCP 服务器 {name}").__dict__
|
|
230
|
-
|
|
231
|
-
return Response().error("保存配置失败").__dict__
|
|
226
|
+
return Response().error("保存配置失败").__dict__
|
|
232
227
|
except Exception as e:
|
|
233
228
|
logger.error(traceback.format_exc())
|
|
234
|
-
return Response().error(f"更新 MCP 服务器失败: {
|
|
229
|
+
return Response().error(f"更新 MCP 服务器失败: {e!s}").__dict__
|
|
235
230
|
|
|
236
231
|
async def delete_mcp_server(self):
|
|
237
232
|
try:
|
|
@@ -241,50 +236,119 @@ class ToolsRoute(Route):
|
|
|
241
236
|
if not name:
|
|
242
237
|
return Response().error("服务器名称不能为空").__dict__
|
|
243
238
|
|
|
244
|
-
config = self.load_mcp_config()
|
|
239
|
+
config = self.tool_mgr.load_mcp_config()
|
|
245
240
|
|
|
246
241
|
if name not in config["mcpServers"]:
|
|
247
242
|
return Response().error(f"服务器 {name} 不存在").__dict__
|
|
248
243
|
|
|
249
|
-
# 删除服务器配置
|
|
250
244
|
del config["mcpServers"][name]
|
|
251
245
|
|
|
252
|
-
if self.save_mcp_config(config):
|
|
253
|
-
# 关闭并删除MCP客户端
|
|
246
|
+
if self.tool_mgr.save_mcp_config(config):
|
|
254
247
|
if name in self.tool_mgr.mcp_client_dict:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
248
|
+
try:
|
|
249
|
+
await self.tool_mgr.disable_mcp_server(name, timeout=10)
|
|
250
|
+
except TimeoutError:
|
|
251
|
+
return (
|
|
252
|
+
Response().error(f"停用 MCP 服务器 {name} 超时。").__dict__
|
|
253
|
+
)
|
|
254
|
+
except Exception as e:
|
|
255
|
+
logger.error(traceback.format_exc())
|
|
256
|
+
return (
|
|
257
|
+
Response()
|
|
258
|
+
.error(f"停用 MCP 服务器 {name} 失败: {e!s}")
|
|
259
|
+
.__dict__
|
|
260
|
+
)
|
|
262
261
|
return Response().ok(None, f"成功删除 MCP 服务器 {name}").__dict__
|
|
262
|
+
return Response().error("保存配置失败").__dict__
|
|
263
|
+
except Exception as e:
|
|
264
|
+
logger.error(traceback.format_exc())
|
|
265
|
+
return Response().error(f"删除 MCP 服务器失败: {e!s}").__dict__
|
|
266
|
+
|
|
267
|
+
async def test_mcp_connection(self):
|
|
268
|
+
"""测试 MCP 服务器连接"""
|
|
269
|
+
try:
|
|
270
|
+
server_data = await request.json
|
|
271
|
+
config = server_data.get("mcp_server_config", None)
|
|
272
|
+
|
|
273
|
+
if not isinstance(config, dict) or not config:
|
|
274
|
+
return Response().error("无效的 MCP 服务器配置").__dict__
|
|
275
|
+
|
|
276
|
+
if "mcpServers" in config:
|
|
277
|
+
keys = list(config["mcpServers"].keys())
|
|
278
|
+
if not keys:
|
|
279
|
+
return Response().error("MCP 服务器配置不能为空").__dict__
|
|
280
|
+
if len(keys) > 1:
|
|
281
|
+
return Response().error("一次只能配置一个 MCP 服务器配置").__dict__
|
|
282
|
+
config = config["mcpServers"][keys[0]]
|
|
283
|
+
elif not config:
|
|
284
|
+
return Response().error("MCP 服务器配置不能为空").__dict__
|
|
285
|
+
|
|
286
|
+
tools_name = await self.tool_mgr.test_mcp_server_connection(config)
|
|
287
|
+
return (
|
|
288
|
+
Response().ok(data=tools_name, message="🎉 MCP 服务器可用!").__dict__
|
|
289
|
+
)
|
|
290
|
+
|
|
291
|
+
except Exception as e:
|
|
292
|
+
logger.error(traceback.format_exc())
|
|
293
|
+
return Response().error(f"测试 MCP 连接失败: {e!s}").__dict__
|
|
294
|
+
|
|
295
|
+
async def get_tool_list(self):
|
|
296
|
+
"""获取所有注册的工具列表"""
|
|
297
|
+
try:
|
|
298
|
+
tools = self.tool_mgr.func_list
|
|
299
|
+
tools_dict = [
|
|
300
|
+
{
|
|
301
|
+
"name": tool.name,
|
|
302
|
+
"description": tool.description,
|
|
303
|
+
"parameters": tool.parameters,
|
|
304
|
+
"active": tool.active,
|
|
305
|
+
}
|
|
306
|
+
for tool in tools
|
|
307
|
+
]
|
|
308
|
+
return Response().ok(data=tools_dict).__dict__
|
|
309
|
+
except Exception as e:
|
|
310
|
+
logger.error(traceback.format_exc())
|
|
311
|
+
return Response().error(f"获取工具列表失败: {e!s}").__dict__
|
|
312
|
+
|
|
313
|
+
async def toggle_tool(self):
|
|
314
|
+
"""启用或停用指定的工具"""
|
|
315
|
+
try:
|
|
316
|
+
data = await request.json
|
|
317
|
+
tool_name = data.get("name")
|
|
318
|
+
action = data.get("activate") # True or False
|
|
319
|
+
|
|
320
|
+
if not tool_name or action is None:
|
|
321
|
+
return Response().error("缺少必要参数: name 或 action").__dict__
|
|
322
|
+
|
|
323
|
+
if action:
|
|
324
|
+
try:
|
|
325
|
+
ok = self.tool_mgr.activate_llm_tool(tool_name, star_map=star_map)
|
|
326
|
+
except ValueError as e:
|
|
327
|
+
return Response().error(f"启用工具失败: {e!s}").__dict__
|
|
263
328
|
else:
|
|
264
|
-
|
|
329
|
+
ok = self.tool_mgr.deactivate_llm_tool(tool_name)
|
|
330
|
+
|
|
331
|
+
if ok:
|
|
332
|
+
return Response().ok(None, "操作成功。").__dict__
|
|
333
|
+
return Response().error(f"工具 {tool_name} 不存在或操作失败。").__dict__
|
|
334
|
+
|
|
265
335
|
except Exception as e:
|
|
266
336
|
logger.error(traceback.format_exc())
|
|
267
|
-
return Response().error(f"
|
|
268
|
-
|
|
269
|
-
async def
|
|
270
|
-
|
|
271
|
-
page_size = request.args.get("page_size", 10, type=int)
|
|
272
|
-
BASE_URL = "https://api.soulter.top/astrbot/mcpservers?page={}&page_size={}".format(
|
|
273
|
-
page,
|
|
274
|
-
page_size,
|
|
275
|
-
)
|
|
337
|
+
return Response().error(f"操作工具失败: {e!s}").__dict__
|
|
338
|
+
|
|
339
|
+
async def sync_provider(self):
|
|
340
|
+
"""同步 MCP 提供者配置"""
|
|
276
341
|
try:
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
except Exception as _:
|
|
342
|
+
data = await request.json
|
|
343
|
+
provider_name = data.get("name") # modelscope, or others
|
|
344
|
+
match provider_name:
|
|
345
|
+
case "modelscope":
|
|
346
|
+
access_token = data.get("access_token", "")
|
|
347
|
+
await self.tool_mgr.sync_modelscope_mcp_servers(access_token)
|
|
348
|
+
case _:
|
|
349
|
+
return Response().error(f"未知: {provider_name}").__dict__
|
|
350
|
+
|
|
351
|
+
return Response().ok(message="同步成功").__dict__
|
|
352
|
+
except Exception as e:
|
|
289
353
|
logger.error(traceback.format_exc())
|
|
290
|
-
|
|
354
|
+
return Response().error(f"同步失败: {e!s}").__dict__
|