AstrBot 4.5.1__py3-none-any.whl → 4.5.3__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 +10 -11
- astrbot/api/event/__init__.py +5 -6
- astrbot/api/event/filter/__init__.py +37 -36
- astrbot/api/platform/__init__.py +7 -8
- astrbot/api/provider/__init__.py +7 -7
- astrbot/api/star/__init__.py +3 -4
- astrbot/api/util/__init__.py +2 -2
- astrbot/cli/__main__.py +5 -5
- astrbot/cli/commands/__init__.py +3 -3
- astrbot/cli/commands/cmd_conf.py +19 -16
- astrbot/cli/commands/cmd_init.py +3 -2
- astrbot/cli/commands/cmd_plug.py +8 -10
- astrbot/cli/commands/cmd_run.py +5 -6
- astrbot/cli/utils/__init__.py +6 -6
- astrbot/cli/utils/basic.py +14 -14
- astrbot/cli/utils/plugin.py +24 -15
- astrbot/cli/utils/version_comparator.py +10 -12
- astrbot/core/__init__.py +8 -6
- astrbot/core/agent/agent.py +3 -2
- astrbot/core/agent/handoff.py +6 -2
- astrbot/core/agent/hooks.py +9 -6
- astrbot/core/agent/mcp_client.py +50 -15
- astrbot/core/agent/message.py +168 -0
- astrbot/core/agent/response.py +2 -1
- astrbot/core/agent/run_context.py +2 -3
- astrbot/core/agent/runners/base.py +10 -13
- astrbot/core/agent/runners/tool_loop_agent_runner.py +52 -51
- astrbot/core/agent/tool.py +60 -41
- astrbot/core/agent/tool_executor.py +9 -3
- astrbot/core/astr_agent_context.py +3 -1
- astrbot/core/astrbot_config_mgr.py +29 -9
- astrbot/core/config/__init__.py +2 -2
- astrbot/core/config/astrbot_config.py +28 -26
- astrbot/core/config/default.py +4 -6
- astrbot/core/conversation_mgr.py +105 -36
- astrbot/core/core_lifecycle.py +68 -54
- astrbot/core/db/__init__.py +33 -18
- astrbot/core/db/migration/helper.py +12 -10
- astrbot/core/db/migration/migra_3_to_4.py +53 -34
- astrbot/core/db/migration/migra_45_to_46.py +1 -1
- astrbot/core/db/migration/shared_preferences_v3.py +2 -1
- astrbot/core/db/migration/sqlite_v3.py +26 -23
- astrbot/core/db/po.py +27 -18
- astrbot/core/db/sqlite.py +74 -45
- astrbot/core/db/vec_db/base.py +10 -14
- astrbot/core/db/vec_db/faiss_impl/document_storage.py +90 -77
- astrbot/core/db/vec_db/faiss_impl/embedding_storage.py +9 -3
- astrbot/core/db/vec_db/faiss_impl/vec_db.py +36 -31
- astrbot/core/event_bus.py +8 -6
- astrbot/core/file_token_service.py +6 -5
- astrbot/core/initial_loader.py +7 -5
- astrbot/core/knowledge_base/chunking/__init__.py +1 -3
- astrbot/core/knowledge_base/chunking/base.py +1 -0
- astrbot/core/knowledge_base/chunking/fixed_size.py +2 -0
- astrbot/core/knowledge_base/chunking/recursive.py +16 -10
- astrbot/core/knowledge_base/kb_db_sqlite.py +50 -48
- astrbot/core/knowledge_base/kb_helper.py +30 -17
- astrbot/core/knowledge_base/kb_mgr.py +6 -7
- astrbot/core/knowledge_base/models.py +10 -4
- astrbot/core/knowledge_base/parsers/__init__.py +3 -5
- astrbot/core/knowledge_base/parsers/base.py +1 -0
- astrbot/core/knowledge_base/parsers/markitdown_parser.py +2 -1
- astrbot/core/knowledge_base/parsers/pdf_parser.py +2 -1
- astrbot/core/knowledge_base/parsers/text_parser.py +1 -0
- astrbot/core/knowledge_base/parsers/util.py +1 -1
- astrbot/core/knowledge_base/retrieval/__init__.py +6 -8
- astrbot/core/knowledge_base/retrieval/manager.py +17 -14
- astrbot/core/knowledge_base/retrieval/rank_fusion.py +7 -3
- astrbot/core/knowledge_base/retrieval/sparse_retriever.py +11 -5
- astrbot/core/log.py +21 -13
- astrbot/core/message/components.py +123 -217
- astrbot/core/message/message_event_result.py +24 -24
- astrbot/core/persona_mgr.py +20 -11
- astrbot/core/pipeline/__init__.py +7 -7
- 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 +12 -13
- astrbot/core/pipeline/content_safety_check/strategies/keywords.py +1 -0
- astrbot/core/pipeline/content_safety_check/strategies/strategy.py +6 -6
- astrbot/core/pipeline/context.py +4 -1
- astrbot/core/pipeline/context_utils.py +77 -7
- astrbot/core/pipeline/preprocess_stage/stage.py +12 -9
- astrbot/core/pipeline/process_stage/method/llm_request.py +125 -72
- astrbot/core/pipeline/process_stage/method/star_request.py +19 -17
- astrbot/core/pipeline/process_stage/stage.py +13 -10
- astrbot/core/pipeline/process_stage/utils.py +6 -5
- astrbot/core/pipeline/rate_limit_check/stage.py +37 -36
- astrbot/core/pipeline/respond/stage.py +23 -20
- astrbot/core/pipeline/result_decorate/stage.py +31 -23
- astrbot/core/pipeline/scheduler.py +12 -8
- astrbot/core/pipeline/session_status_check/stage.py +12 -8
- astrbot/core/pipeline/stage.py +10 -4
- astrbot/core/pipeline/waking_check/stage.py +24 -18
- astrbot/core/pipeline/whitelist_check/stage.py +10 -7
- astrbot/core/platform/__init__.py +6 -6
- astrbot/core/platform/astr_message_event.py +76 -110
- astrbot/core/platform/astrbot_message.py +11 -13
- astrbot/core/platform/manager.py +16 -15
- astrbot/core/platform/message_session.py +5 -3
- astrbot/core/platform/platform.py +16 -24
- astrbot/core/platform/platform_metadata.py +4 -4
- astrbot/core/platform/register.py +8 -8
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_message_event.py +23 -15
- astrbot/core/platform/sources/aiocqhttp/aiocqhttp_platform_adapter.py +51 -33
- astrbot/core/platform/sources/dingtalk/dingtalk_adapter.py +42 -27
- astrbot/core/platform/sources/dingtalk/dingtalk_event.py +7 -3
- astrbot/core/platform/sources/discord/client.py +9 -6
- astrbot/core/platform/sources/discord/components.py +18 -14
- astrbot/core/platform/sources/discord/discord_platform_adapter.py +45 -30
- astrbot/core/platform/sources/discord/discord_platform_event.py +38 -30
- astrbot/core/platform/sources/lark/lark_adapter.py +23 -17
- astrbot/core/platform/sources/lark/lark_event.py +21 -14
- astrbot/core/platform/sources/misskey/misskey_adapter.py +107 -67
- astrbot/core/platform/sources/misskey/misskey_api.py +153 -129
- astrbot/core/platform/sources/misskey/misskey_event.py +20 -15
- astrbot/core/platform/sources/misskey/misskey_utils.py +74 -62
- astrbot/core/platform/sources/qqofficial/qqofficial_message_event.py +63 -44
- 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 +12 -7
- astrbot/core/platform/sources/satori/satori_adapter.py +56 -38
- astrbot/core/platform/sources/satori/satori_event.py +34 -25
- astrbot/core/platform/sources/slack/client.py +11 -9
- astrbot/core/platform/sources/slack/slack_adapter.py +52 -36
- astrbot/core/platform/sources/slack/slack_event.py +34 -24
- astrbot/core/platform/sources/telegram/tg_adapter.py +38 -18
- astrbot/core/platform/sources/telegram/tg_event.py +32 -18
- astrbot/core/platform/sources/webchat/webchat_adapter.py +27 -17
- astrbot/core/platform/sources/webchat/webchat_event.py +14 -10
- astrbot/core/platform/sources/wechatpadpro/wechatpadpro_adapter.py +115 -120
- astrbot/core/platform/sources/wechatpadpro/wechatpadpro_message_event.py +9 -8
- astrbot/core/platform/sources/wechatpadpro/xml_data_parser.py +15 -16
- astrbot/core/platform/sources/wecom/wecom_adapter.py +35 -18
- astrbot/core/platform/sources/wecom/wecom_event.py +55 -48
- astrbot/core/platform/sources/wecom/wecom_kf.py +34 -44
- astrbot/core/platform/sources/wecom/wecom_kf_message.py +26 -10
- astrbot/core/platform/sources/wecom_ai_bot/WXBizJsonMsgCrypt.py +18 -10
- astrbot/core/platform/sources/wecom_ai_bot/__init__.py +3 -5
- astrbot/core/platform/sources/wecom_ai_bot/ierror.py +0 -1
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_adapter.py +61 -37
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_api.py +67 -28
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_event.py +8 -9
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_queue_mgr.py +18 -9
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_server.py +14 -12
- astrbot/core/platform/sources/wecom_ai_bot/wecomai_utils.py +22 -12
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py +40 -26
- astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py +47 -45
- astrbot/core/platform_message_history_mgr.py +5 -3
- astrbot/core/provider/__init__.py +2 -3
- astrbot/core/provider/entites.py +8 -8
- astrbot/core/provider/entities.py +61 -75
- astrbot/core/provider/func_tool_manager.py +59 -55
- astrbot/core/provider/manager.py +32 -22
- astrbot/core/provider/provider.py +72 -46
- astrbot/core/provider/register.py +7 -7
- astrbot/core/provider/sources/anthropic_source.py +48 -30
- astrbot/core/provider/sources/azure_tts_source.py +17 -13
- astrbot/core/provider/sources/coze_api_client.py +27 -17
- astrbot/core/provider/sources/coze_source.py +104 -87
- astrbot/core/provider/sources/dashscope_source.py +18 -11
- astrbot/core/provider/sources/dashscope_tts.py +36 -23
- astrbot/core/provider/sources/dify_source.py +25 -20
- astrbot/core/provider/sources/edge_tts_source.py +21 -17
- astrbot/core/provider/sources/fishaudio_tts_api_source.py +22 -14
- astrbot/core/provider/sources/gemini_embedding_source.py +12 -13
- astrbot/core/provider/sources/gemini_source.py +72 -58
- astrbot/core/provider/sources/gemini_tts_source.py +8 -6
- astrbot/core/provider/sources/gsv_selfhosted_source.py +17 -14
- astrbot/core/provider/sources/gsvi_tts_source.py +11 -7
- astrbot/core/provider/sources/minimax_tts_api_source.py +50 -40
- astrbot/core/provider/sources/openai_embedding_source.py +6 -8
- astrbot/core/provider/sources/openai_source.py +77 -69
- astrbot/core/provider/sources/openai_tts_api_source.py +14 -6
- astrbot/core/provider/sources/sensevoice_selfhosted_source.py +13 -11
- astrbot/core/provider/sources/vllm_rerank_source.py +10 -4
- astrbot/core/provider/sources/volcengine_tts.py +38 -31
- astrbot/core/provider/sources/whisper_api_source.py +14 -12
- astrbot/core/provider/sources/whisper_selfhosted_source.py +15 -11
- astrbot/core/provider/sources/xinference_rerank_source.py +16 -8
- astrbot/core/provider/sources/xinference_stt_provider.py +35 -25
- astrbot/core/star/__init__.py +16 -11
- astrbot/core/star/config.py +10 -15
- astrbot/core/star/context.py +97 -75
- astrbot/core/star/filter/__init__.py +4 -3
- astrbot/core/star/filter/command.py +30 -28
- astrbot/core/star/filter/command_group.py +27 -24
- 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 +4 -2
- astrbot/core/star/filter/regex.py +4 -2
- astrbot/core/star/register/__init__.py +19 -19
- astrbot/core/star/register/star.py +6 -2
- astrbot/core/star/register/star_handler.py +96 -73
- astrbot/core/star/session_llm_manager.py +48 -14
- astrbot/core/star/session_plugin_manager.py +29 -15
- astrbot/core/star/star.py +1 -2
- astrbot/core/star/star_handler.py +13 -8
- astrbot/core/star/star_manager.py +151 -59
- astrbot/core/star/star_tools.py +44 -37
- astrbot/core/star/updator.py +10 -10
- astrbot/core/umop_config_router.py +10 -4
- astrbot/core/updator.py +13 -5
- astrbot/core/utils/astrbot_path.py +3 -5
- astrbot/core/utils/dify_api_client.py +33 -15
- astrbot/core/utils/io.py +66 -42
- astrbot/core/utils/log_pipe.py +1 -1
- astrbot/core/utils/metrics.py +7 -7
- astrbot/core/utils/path_util.py +15 -16
- astrbot/core/utils/pip_installer.py +5 -5
- astrbot/core/utils/session_waiter.py +19 -20
- astrbot/core/utils/shared_preferences.py +45 -20
- astrbot/core/utils/t2i/__init__.py +4 -1
- astrbot/core/utils/t2i/network_strategy.py +35 -26
- astrbot/core/utils/t2i/renderer.py +11 -5
- astrbot/core/utils/t2i/template_manager.py +14 -15
- astrbot/core/utils/tencent_record_helper.py +19 -13
- astrbot/core/utils/version_comparator.py +10 -13
- astrbot/core/zip_updator.py +43 -40
- astrbot/dashboard/routes/__init__.py +18 -18
- astrbot/dashboard/routes/auth.py +10 -8
- astrbot/dashboard/routes/chat.py +30 -21
- astrbot/dashboard/routes/config.py +92 -75
- astrbot/dashboard/routes/conversation.py +46 -39
- astrbot/dashboard/routes/file.py +4 -2
- astrbot/dashboard/routes/knowledge_base.py +47 -40
- astrbot/dashboard/routes/log.py +9 -4
- astrbot/dashboard/routes/persona.py +19 -16
- astrbot/dashboard/routes/plugin.py +69 -55
- astrbot/dashboard/routes/route.py +3 -1
- astrbot/dashboard/routes/session_management.py +130 -116
- astrbot/dashboard/routes/stat.py +34 -34
- astrbot/dashboard/routes/t2i.py +15 -12
- astrbot/dashboard/routes/tools.py +56 -53
- astrbot/dashboard/routes/update.py +32 -28
- astrbot/dashboard/server.py +30 -26
- astrbot/dashboard/utils.py +8 -4
- {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/METADATA +2 -1
- astrbot-4.5.3.dist-info/RECORD +261 -0
- astrbot-4.5.1.dist-info/RECORD +0 -260
- {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/WHEEL +0 -0
- {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/entry_points.txt +0 -0
- {astrbot-4.5.1.dist-info → astrbot-4.5.3.dist-info}/licenses/LICENSE +0 -0
astrbot/dashboard/routes/t2i.py
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# astrbot/dashboard/routes/t2i.py
|
|
2
2
|
|
|
3
3
|
from dataclasses import asdict
|
|
4
|
+
|
|
4
5
|
from quart import jsonify, request
|
|
5
6
|
|
|
6
7
|
from astrbot.core import logger
|
|
7
8
|
from astrbot.core.core_lifecycle import AstrBotCoreLifecycle
|
|
8
9
|
from astrbot.core.utils.t2i.template_manager import TemplateManager
|
|
10
|
+
|
|
9
11
|
from .route import Response, Route, RouteContext
|
|
10
12
|
|
|
11
13
|
|
|
@@ -49,7 +51,7 @@ class T2iRoute(Route):
|
|
|
49
51
|
try:
|
|
50
52
|
active_template = self.config.get("t2i_active_template", "base")
|
|
51
53
|
return jsonify(
|
|
52
|
-
asdict(Response().ok(data={"active_template": active_template}))
|
|
54
|
+
asdict(Response().ok(data={"active_template": active_template})),
|
|
53
55
|
)
|
|
54
56
|
except Exception as e:
|
|
55
57
|
logger.error("Error in get_active_template", exc_info=True)
|
|
@@ -62,7 +64,7 @@ class T2iRoute(Route):
|
|
|
62
64
|
try:
|
|
63
65
|
content = self.manager.get_template(name)
|
|
64
66
|
return jsonify(
|
|
65
|
-
asdict(Response().ok(data={"name": name, "content": content}))
|
|
67
|
+
asdict(Response().ok(data={"name": name, "content": content})),
|
|
66
68
|
)
|
|
67
69
|
except FileNotFoundError:
|
|
68
70
|
response = jsonify(asdict(Response().error("Template not found")))
|
|
@@ -81,7 +83,7 @@ class T2iRoute(Route):
|
|
|
81
83
|
content = data.get("content")
|
|
82
84
|
if not name or not content:
|
|
83
85
|
response = jsonify(
|
|
84
|
-
asdict(Response().error("Name and content are required."))
|
|
86
|
+
asdict(Response().error("Name and content are required.")),
|
|
85
87
|
)
|
|
86
88
|
response.status_code = 400
|
|
87
89
|
return response
|
|
@@ -91,15 +93,16 @@ class T2iRoute(Route):
|
|
|
91
93
|
response = jsonify(
|
|
92
94
|
asdict(
|
|
93
95
|
Response().ok(
|
|
94
|
-
data={"name": name},
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
data={"name": name},
|
|
97
|
+
message="Template created successfully.",
|
|
98
|
+
),
|
|
99
|
+
),
|
|
97
100
|
)
|
|
98
101
|
response.status_code = 201
|
|
99
102
|
return response
|
|
100
103
|
except FileExistsError:
|
|
101
104
|
response = jsonify(
|
|
102
|
-
asdict(Response().error("Template with this name already exists."))
|
|
105
|
+
asdict(Response().error("Template with this name already exists.")),
|
|
103
106
|
)
|
|
104
107
|
response.status_code = 409
|
|
105
108
|
return response
|
|
@@ -149,7 +152,7 @@ class T2iRoute(Route):
|
|
|
149
152
|
name = name.strip()
|
|
150
153
|
self.manager.delete_template(name)
|
|
151
154
|
return jsonify(
|
|
152
|
-
asdict(Response().ok(message="Template deleted successfully."))
|
|
155
|
+
asdict(Response().ok(message="Template deleted successfully.")),
|
|
153
156
|
)
|
|
154
157
|
except FileNotFoundError:
|
|
155
158
|
response = jsonify(asdict(Response().error("Template not found.")))
|
|
@@ -189,7 +192,7 @@ class T2iRoute(Route):
|
|
|
189
192
|
|
|
190
193
|
except FileNotFoundError:
|
|
191
194
|
response = jsonify(
|
|
192
|
-
asdict(Response().error(f"模板 '{name}' 不存在,无法应用。"))
|
|
195
|
+
asdict(Response().error(f"模板 '{name}' 不存在,无法应用。")),
|
|
193
196
|
)
|
|
194
197
|
response.status_code = 404
|
|
195
198
|
return response
|
|
@@ -215,9 +218,9 @@ class T2iRoute(Route):
|
|
|
215
218
|
return jsonify(
|
|
216
219
|
asdict(
|
|
217
220
|
Response().ok(
|
|
218
|
-
message="Default template has been reset and activated."
|
|
219
|
-
)
|
|
220
|
-
)
|
|
221
|
+
message="Default template has been reset and activated.",
|
|
222
|
+
),
|
|
223
|
+
),
|
|
221
224
|
)
|
|
222
225
|
except FileNotFoundError as e:
|
|
223
226
|
response = jsonify(asdict(Response().error(str(e))))
|
|
@@ -13,7 +13,9 @@ DEFAULT_MCP_CONFIG = {"mcpServers": {}}
|
|
|
13
13
|
|
|
14
14
|
class ToolsRoute(Route):
|
|
15
15
|
def __init__(
|
|
16
|
-
self,
|
|
16
|
+
self,
|
|
17
|
+
context: RouteContext,
|
|
18
|
+
core_lifecycle: AstrBotCoreLifecycle,
|
|
17
19
|
) -> None:
|
|
18
20
|
super().__init__(context)
|
|
19
21
|
self.core_lifecycle = core_lifecycle
|
|
@@ -64,7 +66,7 @@ class ToolsRoute(Route):
|
|
|
64
66
|
return Response().ok(servers).__dict__
|
|
65
67
|
except Exception as e:
|
|
66
68
|
logger.error(traceback.format_exc())
|
|
67
|
-
return Response().error(f"获取 MCP 服务器列表失败: {
|
|
69
|
+
return Response().error(f"获取 MCP 服务器列表失败: {e!s}").__dict__
|
|
68
70
|
|
|
69
71
|
async def add_mcp_server(self):
|
|
70
72
|
try:
|
|
@@ -105,23 +107,22 @@ class ToolsRoute(Route):
|
|
|
105
107
|
if self.tool_mgr.save_mcp_config(config):
|
|
106
108
|
try:
|
|
107
109
|
await self.tool_mgr.enable_mcp_server(
|
|
108
|
-
name,
|
|
110
|
+
name,
|
|
111
|
+
server_config,
|
|
112
|
+
timeout=30,
|
|
109
113
|
)
|
|
110
114
|
except TimeoutError:
|
|
111
115
|
return Response().error(f"启用 MCP 服务器 {name} 超时。").__dict__
|
|
112
116
|
except Exception as e:
|
|
113
117
|
logger.error(traceback.format_exc())
|
|
114
118
|
return (
|
|
115
|
-
Response()
|
|
116
|
-
.error(f"启用 MCP 服务器 {name} 失败: {str(e)}")
|
|
117
|
-
.__dict__
|
|
119
|
+
Response().error(f"启用 MCP 服务器 {name} 失败: {e!s}").__dict__
|
|
118
120
|
)
|
|
119
121
|
return Response().ok(None, f"成功添加 MCP 服务器 {name}").__dict__
|
|
120
|
-
|
|
121
|
-
return Response().error("保存配置失败").__dict__
|
|
122
|
+
return Response().error("保存配置失败").__dict__
|
|
122
123
|
except Exception as e:
|
|
123
124
|
logger.error(traceback.format_exc())
|
|
124
|
-
return Response().error(f"添加 MCP 服务器失败: {
|
|
125
|
+
return Response().error(f"添加 MCP 服务器失败: {e!s}").__dict__
|
|
125
126
|
|
|
126
127
|
async def update_mcp_server(self):
|
|
127
128
|
try:
|
|
@@ -139,7 +140,8 @@ class ToolsRoute(Route):
|
|
|
139
140
|
|
|
140
141
|
# 获取活动状态
|
|
141
142
|
active = server_data.get(
|
|
142
|
-
"active",
|
|
143
|
+
"active",
|
|
144
|
+
config["mcpServers"][name].get("active", True),
|
|
143
145
|
)
|
|
144
146
|
|
|
145
147
|
# 创建新的配置对象
|
|
@@ -177,19 +179,21 @@ class ToolsRoute(Route):
|
|
|
177
179
|
except TimeoutError as e:
|
|
178
180
|
return (
|
|
179
181
|
Response()
|
|
180
|
-
.error(f"启用前停用 MCP 服务器时 {name} 超时: {
|
|
182
|
+
.error(f"启用前停用 MCP 服务器时 {name} 超时: {e!s}")
|
|
181
183
|
.__dict__
|
|
182
184
|
)
|
|
183
185
|
except Exception as e:
|
|
184
186
|
logger.error(traceback.format_exc())
|
|
185
187
|
return (
|
|
186
188
|
Response()
|
|
187
|
-
.error(f"启用前停用 MCP 服务器时 {name} 失败: {
|
|
189
|
+
.error(f"启用前停用 MCP 服务器时 {name} 失败: {e!s}")
|
|
188
190
|
.__dict__
|
|
189
191
|
)
|
|
190
192
|
try:
|
|
191
193
|
await self.tool_mgr.enable_mcp_server(
|
|
192
|
-
name,
|
|
194
|
+
name,
|
|
195
|
+
config["mcpServers"][name],
|
|
196
|
+
timeout=30,
|
|
193
197
|
)
|
|
194
198
|
except TimeoutError:
|
|
195
199
|
return (
|
|
@@ -199,34 +203,30 @@ class ToolsRoute(Route):
|
|
|
199
203
|
logger.error(traceback.format_exc())
|
|
200
204
|
return (
|
|
201
205
|
Response()
|
|
202
|
-
.error(f"启用 MCP 服务器 {name} 失败: {
|
|
206
|
+
.error(f"启用 MCP 服务器 {name} 失败: {e!s}")
|
|
207
|
+
.__dict__
|
|
208
|
+
)
|
|
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}")
|
|
203
222
|
.__dict__
|
|
204
223
|
)
|
|
205
|
-
else:
|
|
206
|
-
# 如果要停用服务器
|
|
207
|
-
if name in self.tool_mgr.mcp_client_dict:
|
|
208
|
-
try:
|
|
209
|
-
await self.tool_mgr.disable_mcp_server(name, timeout=10)
|
|
210
|
-
except TimeoutError:
|
|
211
|
-
return (
|
|
212
|
-
Response()
|
|
213
|
-
.error(f"停用 MCP 服务器 {name} 超时。")
|
|
214
|
-
.__dict__
|
|
215
|
-
)
|
|
216
|
-
except Exception as e:
|
|
217
|
-
logger.error(traceback.format_exc())
|
|
218
|
-
return (
|
|
219
|
-
Response()
|
|
220
|
-
.error(f"停用 MCP 服务器 {name} 失败: {str(e)}")
|
|
221
|
-
.__dict__
|
|
222
|
-
)
|
|
223
224
|
|
|
224
225
|
return Response().ok(None, f"成功更新 MCP 服务器 {name}").__dict__
|
|
225
|
-
|
|
226
|
-
return Response().error("保存配置失败").__dict__
|
|
226
|
+
return Response().error("保存配置失败").__dict__
|
|
227
227
|
except Exception as e:
|
|
228
228
|
logger.error(traceback.format_exc())
|
|
229
|
-
return Response().error(f"更新 MCP 服务器失败: {
|
|
229
|
+
return Response().error(f"更新 MCP 服务器失败: {e!s}").__dict__
|
|
230
230
|
|
|
231
231
|
async def delete_mcp_server(self):
|
|
232
232
|
try:
|
|
@@ -255,20 +255,17 @@ class ToolsRoute(Route):
|
|
|
255
255
|
logger.error(traceback.format_exc())
|
|
256
256
|
return (
|
|
257
257
|
Response()
|
|
258
|
-
.error(f"停用 MCP 服务器 {name} 失败: {
|
|
258
|
+
.error(f"停用 MCP 服务器 {name} 失败: {e!s}")
|
|
259
259
|
.__dict__
|
|
260
260
|
)
|
|
261
261
|
return Response().ok(None, f"成功删除 MCP 服务器 {name}").__dict__
|
|
262
|
-
|
|
263
|
-
return Response().error("保存配置失败").__dict__
|
|
262
|
+
return Response().error("保存配置失败").__dict__
|
|
264
263
|
except Exception as e:
|
|
265
264
|
logger.error(traceback.format_exc())
|
|
266
|
-
return Response().error(f"删除 MCP 服务器失败: {
|
|
265
|
+
return Response().error(f"删除 MCP 服务器失败: {e!s}").__dict__
|
|
267
266
|
|
|
268
267
|
async def test_mcp_connection(self):
|
|
269
|
-
"""
|
|
270
|
-
测试 MCP 服务器连接
|
|
271
|
-
"""
|
|
268
|
+
"""测试 MCP 服务器连接"""
|
|
272
269
|
try:
|
|
273
270
|
server_data = await request.json
|
|
274
271
|
config = server_data.get("mcp_server_config", None)
|
|
@@ -283,9 +280,8 @@ class ToolsRoute(Route):
|
|
|
283
280
|
if len(keys) > 1:
|
|
284
281
|
return Response().error("一次只能配置一个 MCP 服务器配置").__dict__
|
|
285
282
|
config = config["mcpServers"][keys[0]]
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
return Response().error("MCP 服务器配置不能为空").__dict__
|
|
283
|
+
elif not config:
|
|
284
|
+
return Response().error("MCP 服务器配置不能为空").__dict__
|
|
289
285
|
|
|
290
286
|
tools_name = await self.tool_mgr.test_mcp_server_connection(config)
|
|
291
287
|
return (
|
|
@@ -294,17 +290,25 @@ class ToolsRoute(Route):
|
|
|
294
290
|
|
|
295
291
|
except Exception as e:
|
|
296
292
|
logger.error(traceback.format_exc())
|
|
297
|
-
return Response().error(f"测试 MCP 连接失败: {
|
|
293
|
+
return Response().error(f"测试 MCP 连接失败: {e!s}").__dict__
|
|
298
294
|
|
|
299
295
|
async def get_tool_list(self):
|
|
300
296
|
"""获取所有注册的工具列表"""
|
|
301
297
|
try:
|
|
302
298
|
tools = self.tool_mgr.func_list
|
|
303
|
-
tools_dict = [
|
|
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
|
+
]
|
|
304
308
|
return Response().ok(data=tools_dict).__dict__
|
|
305
309
|
except Exception as e:
|
|
306
310
|
logger.error(traceback.format_exc())
|
|
307
|
-
return Response().error(f"获取工具列表失败: {
|
|
311
|
+
return Response().error(f"获取工具列表失败: {e!s}").__dict__
|
|
308
312
|
|
|
309
313
|
async def toggle_tool(self):
|
|
310
314
|
"""启用或停用指定的工具"""
|
|
@@ -320,18 +324,17 @@ class ToolsRoute(Route):
|
|
|
320
324
|
try:
|
|
321
325
|
ok = self.tool_mgr.activate_llm_tool(tool_name, star_map=star_map)
|
|
322
326
|
except ValueError as e:
|
|
323
|
-
return Response().error(f"启用工具失败: {
|
|
327
|
+
return Response().error(f"启用工具失败: {e!s}").__dict__
|
|
324
328
|
else:
|
|
325
329
|
ok = self.tool_mgr.deactivate_llm_tool(tool_name)
|
|
326
330
|
|
|
327
331
|
if ok:
|
|
328
332
|
return Response().ok(None, "操作成功。").__dict__
|
|
329
|
-
|
|
330
|
-
return Response().error(f"工具 {tool_name} 不存在或操作失败。").__dict__
|
|
333
|
+
return Response().error(f"工具 {tool_name} 不存在或操作失败。").__dict__
|
|
331
334
|
|
|
332
335
|
except Exception as e:
|
|
333
336
|
logger.error(traceback.format_exc())
|
|
334
|
-
return Response().error(f"操作工具失败: {
|
|
337
|
+
return Response().error(f"操作工具失败: {e!s}").__dict__
|
|
335
338
|
|
|
336
339
|
async def sync_provider(self):
|
|
337
340
|
"""同步 MCP 提供者配置"""
|
|
@@ -348,4 +351,4 @@ class ToolsRoute(Route):
|
|
|
348
351
|
return Response().ok(message="同步成功").__dict__
|
|
349
352
|
except Exception as e:
|
|
350
353
|
logger.error(traceback.format_exc())
|
|
351
|
-
return Response().error(f"同步失败: {
|
|
354
|
+
return Response().error(f"同步失败: {e!s}").__dict__
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import traceback
|
|
2
|
-
|
|
2
|
+
|
|
3
3
|
from quart import request
|
|
4
|
+
|
|
5
|
+
from astrbot.core import DEMO_MODE, logger, pip_installer
|
|
6
|
+
from astrbot.core.config.default import VERSION
|
|
4
7
|
from astrbot.core.core_lifecycle import AstrBotCoreLifecycle
|
|
8
|
+
from astrbot.core.db.migration.helper import check_migration_needed_v4, do_migration_v4
|
|
5
9
|
from astrbot.core.updator import AstrBotUpdator
|
|
6
|
-
from astrbot.core import logger, pip_installer
|
|
7
10
|
from astrbot.core.utils.io import download_dashboard, get_dashboard_version
|
|
8
|
-
|
|
9
|
-
from
|
|
10
|
-
from astrbot.core.db.migration.helper import do_migration_v4, check_migration_needed_v4
|
|
11
|
+
|
|
12
|
+
from .route import Response, Route, RouteContext
|
|
11
13
|
|
|
12
14
|
CLEAR_SITE_DATA_HEADERS = {"Clear-Site-Data": '"cache"'}
|
|
13
15
|
|
|
@@ -40,12 +42,14 @@ class UpdateRoute(Route):
|
|
|
40
42
|
data = await request.json
|
|
41
43
|
pim = data.get("platform_id_map", {})
|
|
42
44
|
await do_migration_v4(
|
|
43
|
-
self.core_lifecycle.db,
|
|
45
|
+
self.core_lifecycle.db,
|
|
46
|
+
pim,
|
|
47
|
+
self.core_lifecycle.astrbot_config,
|
|
44
48
|
)
|
|
45
49
|
return Response().ok(None, "迁移成功。").__dict__
|
|
46
50
|
except Exception as e:
|
|
47
51
|
logger.error(f"迁移失败: {traceback.format_exc()}")
|
|
48
|
-
return Response().error(f"迁移失败: {
|
|
52
|
+
return Response().error(f"迁移失败: {e!s}").__dict__
|
|
49
53
|
|
|
50
54
|
async def check_update(self):
|
|
51
55
|
type_ = request.args.get("type", None)
|
|
@@ -58,20 +62,19 @@ class UpdateRoute(Route):
|
|
|
58
62
|
.ok({"has_new_version": dv != f"v{VERSION}", "current_version": dv})
|
|
59
63
|
.__dict__
|
|
60
64
|
)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
).__dict__
|
|
65
|
+
ret = await self.astrbot_updator.check_update(None, None, False)
|
|
66
|
+
return Response(
|
|
67
|
+
status="success",
|
|
68
|
+
message=str(ret) if ret is not None else "已经是最新版本了。",
|
|
69
|
+
data={
|
|
70
|
+
"version": f"v{VERSION}",
|
|
71
|
+
"has_new_version": ret is not None,
|
|
72
|
+
"dashboard_version": dv,
|
|
73
|
+
"dashboard_has_new_version": bool(dv and dv != f"v{VERSION}"),
|
|
74
|
+
},
|
|
75
|
+
).__dict__
|
|
73
76
|
except Exception as e:
|
|
74
|
-
logger.warning(f"检查更新失败: {
|
|
77
|
+
logger.warning(f"检查更新失败: {e!s} (不影响除项目更新外的正常使用)")
|
|
75
78
|
return Response().error(e.__str__()).__dict__
|
|
76
79
|
|
|
77
80
|
async def get_releases(self):
|
|
@@ -98,7 +101,9 @@ class UpdateRoute(Route):
|
|
|
98
101
|
|
|
99
102
|
try:
|
|
100
103
|
await self.astrbot_updator.update(
|
|
101
|
-
latest=latest,
|
|
104
|
+
latest=latest,
|
|
105
|
+
version=version,
|
|
106
|
+
proxy=proxy,
|
|
102
107
|
)
|
|
103
108
|
|
|
104
109
|
try:
|
|
@@ -121,13 +126,12 @@ class UpdateRoute(Route):
|
|
|
121
126
|
.__dict__
|
|
122
127
|
)
|
|
123
128
|
return ret, 200, CLEAR_SITE_DATA_HEADERS
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
return ret, 200, CLEAR_SITE_DATA_HEADERS
|
|
129
|
+
ret = (
|
|
130
|
+
Response()
|
|
131
|
+
.ok(None, "更新成功,AstrBot 将在下次启动时应用新的代码。")
|
|
132
|
+
.__dict__
|
|
133
|
+
)
|
|
134
|
+
return ret, 200, CLEAR_SITE_DATA_HEADERS
|
|
131
135
|
except Exception as e:
|
|
132
136
|
logger.error(f"/api/update_project: {traceback.format_exc()}")
|
|
133
137
|
return Response().error(e.__str__()).__dict__
|
astrbot/dashboard/server.py
CHANGED
|
@@ -39,7 +39,7 @@ class AstrBotDashboard:
|
|
|
39
39
|
self.data_path = os.path.abspath(webui_dir)
|
|
40
40
|
else:
|
|
41
41
|
self.data_path = os.path.abspath(
|
|
42
|
-
os.path.join(get_astrbot_data_path(), "dist")
|
|
42
|
+
os.path.join(get_astrbot_data_path(), "dist"),
|
|
43
43
|
)
|
|
44
44
|
|
|
45
45
|
self.app = Quart("dashboard", static_folder=self.data_path, static_url_path="/")
|
|
@@ -53,11 +53,15 @@ class AstrBotDashboard:
|
|
|
53
53
|
logging.getLogger(self.app.name).removeHandler(default_handler)
|
|
54
54
|
self.context = RouteContext(self.config, self.app)
|
|
55
55
|
self.ur = UpdateRoute(
|
|
56
|
-
self.context,
|
|
56
|
+
self.context,
|
|
57
|
+
core_lifecycle.astrbot_updator,
|
|
58
|
+
core_lifecycle,
|
|
57
59
|
)
|
|
58
60
|
self.sr = StatRoute(self.context, db, core_lifecycle)
|
|
59
61
|
self.pr = PluginRoute(
|
|
60
|
-
self.context,
|
|
62
|
+
self.context,
|
|
63
|
+
core_lifecycle,
|
|
64
|
+
core_lifecycle.plugin_manager,
|
|
61
65
|
)
|
|
62
66
|
self.cr = ConfigRoute(self.context, core_lifecycle)
|
|
63
67
|
self.lr = LogRoute(self.context, core_lifecycle.log_broker)
|
|
@@ -68,7 +72,9 @@ class AstrBotDashboard:
|
|
|
68
72
|
self.conversation_route = ConversationRoute(self.context, db, core_lifecycle)
|
|
69
73
|
self.file_route = FileRoute(self.context)
|
|
70
74
|
self.session_management_route = SessionManagementRoute(
|
|
71
|
-
self.context,
|
|
75
|
+
self.context,
|
|
76
|
+
db,
|
|
77
|
+
core_lifecycle,
|
|
72
78
|
)
|
|
73
79
|
self.persona_route = PersonaRoute(self.context, db, core_lifecycle)
|
|
74
80
|
self.t2i_route = T2iRoute(self.context, core_lifecycle)
|
|
@@ -85,9 +91,7 @@ class AstrBotDashboard:
|
|
|
85
91
|
self._init_jwt_secret()
|
|
86
92
|
|
|
87
93
|
async def srv_plug_route(self, subpath, *args, **kwargs):
|
|
88
|
-
"""
|
|
89
|
-
插件路由
|
|
90
|
-
"""
|
|
94
|
+
"""插件路由"""
|
|
91
95
|
registered_web_apis = self.core_lifecycle.star_context.registered_web_apis
|
|
92
96
|
for api in registered_web_apis:
|
|
93
97
|
route, view_handler, methods, _ = api
|
|
@@ -97,18 +101,17 @@ class AstrBotDashboard:
|
|
|
97
101
|
|
|
98
102
|
async def auth_middleware(self):
|
|
99
103
|
if not request.path.startswith("/api"):
|
|
100
|
-
return
|
|
104
|
+
return None
|
|
101
105
|
allowed_endpoints = ["/api/auth/login", "/api/file"]
|
|
102
106
|
if any(request.path.startswith(prefix) for prefix in allowed_endpoints):
|
|
103
|
-
return
|
|
104
|
-
#
|
|
107
|
+
return None
|
|
108
|
+
# 声明 JWT
|
|
105
109
|
token = request.headers.get("Authorization")
|
|
106
110
|
if not token:
|
|
107
111
|
r = jsonify(Response().error("未授权").__dict__)
|
|
108
112
|
r.status_code = 401
|
|
109
113
|
return r
|
|
110
|
-
|
|
111
|
-
token = token[7:]
|
|
114
|
+
token = token.removeprefix("Bearer ")
|
|
112
115
|
try:
|
|
113
116
|
payload = jwt.decode(token, self._jwt_secret, algorithms=["HS256"])
|
|
114
117
|
g.username = payload["username"]
|
|
@@ -122,9 +125,7 @@ class AstrBotDashboard:
|
|
|
122
125
|
return r
|
|
123
126
|
|
|
124
127
|
def check_port_in_use(self, port: int) -> bool:
|
|
125
|
-
"""
|
|
126
|
-
跨平台检测端口是否被占用
|
|
127
|
-
"""
|
|
128
|
+
"""跨平台检测端口是否被占用"""
|
|
128
129
|
try:
|
|
129
130
|
# 创建 IPv4 TCP Socket
|
|
130
131
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
@@ -136,7 +137,7 @@ class AstrBotDashboard:
|
|
|
136
137
|
# result 为 0 表示端口被占用
|
|
137
138
|
return result == 0
|
|
138
139
|
except Exception as e:
|
|
139
|
-
logger.warning(f"检查端口 {port} 时发生错误: {
|
|
140
|
+
logger.warning(f"检查端口 {port} 时发生错误: {e!s}")
|
|
140
141
|
# 如果出现异常,保守起见认为端口可能被占用
|
|
141
142
|
return True
|
|
142
143
|
|
|
@@ -157,10 +158,10 @@ class AstrBotDashboard:
|
|
|
157
158
|
]
|
|
158
159
|
return "\n ".join(proc_info)
|
|
159
160
|
except (psutil.NoSuchProcess, psutil.AccessDenied) as e:
|
|
160
|
-
return f"无法获取进程详细信息(可能需要管理员权限): {
|
|
161
|
+
return f"无法获取进程详细信息(可能需要管理员权限): {e!s}"
|
|
161
162
|
return "未找到占用进程"
|
|
162
163
|
except Exception as e:
|
|
163
|
-
return f"获取进程信息失败: {
|
|
164
|
+
return f"获取进程信息失败: {e!s}"
|
|
164
165
|
|
|
165
166
|
def _init_jwt_secret(self):
|
|
166
167
|
if not self.config.get("dashboard", {}).get("jwt_secret", None):
|
|
@@ -182,13 +183,13 @@ class AstrBotDashboard:
|
|
|
182
183
|
|
|
183
184
|
if not enable:
|
|
184
185
|
logger.info("WebUI 已被禁用")
|
|
185
|
-
return
|
|
186
|
+
return None
|
|
186
187
|
|
|
187
188
|
logger.info(f"正在启动 WebUI, 监听地址: http://{host}:{port}")
|
|
188
189
|
|
|
189
190
|
if host == "0.0.0.0":
|
|
190
191
|
logger.info(
|
|
191
|
-
"提示: WebUI 将监听所有网络接口,请注意安全。(可在 data/cmd_config.json 中配置 dashboard.host 以修改 host)"
|
|
192
|
+
"提示: WebUI 将监听所有网络接口,请注意安全。(可在 data/cmd_config.json 中配置 dashboard.host 以修改 host)",
|
|
192
193
|
)
|
|
193
194
|
|
|
194
195
|
if host not in ["localhost", "127.0.0.1"]:
|
|
@@ -207,16 +208,17 @@ class AstrBotDashboard:
|
|
|
207
208
|
f"请确保:\n"
|
|
208
209
|
f"1. 没有其他 AstrBot 实例正在运行\n"
|
|
209
210
|
f"2. 端口 {port} 没有被其他程序占用\n"
|
|
210
|
-
f"3. 如需使用其他端口,请修改配置文件"
|
|
211
|
+
f"3. 如需使用其他端口,请修改配置文件",
|
|
211
212
|
)
|
|
212
213
|
|
|
213
214
|
raise Exception(f"端口 {port} 已被占用")
|
|
214
215
|
|
|
215
|
-
|
|
216
|
-
|
|
216
|
+
parts = [f"\n ✨✨✨\n AstrBot v{VERSION} WebUI 已启动,可访问\n\n"]
|
|
217
|
+
parts.append(f" ➜ 本地: http://localhost:{port}\n")
|
|
217
218
|
for ip in ip_addr:
|
|
218
|
-
|
|
219
|
-
|
|
219
|
+
parts.append(f" ➜ 网络: http://{ip}:{port}\n")
|
|
220
|
+
parts.append(" ➜ 默认用户名和密码: astrbot\n ✨✨✨\n")
|
|
221
|
+
display = "".join(parts)
|
|
220
222
|
|
|
221
223
|
if not ip_addr:
|
|
222
224
|
display += (
|
|
@@ -226,7 +228,9 @@ class AstrBotDashboard:
|
|
|
226
228
|
logger.info(display)
|
|
227
229
|
|
|
228
230
|
return self.app.run_task(
|
|
229
|
-
host=host,
|
|
231
|
+
host=host,
|
|
232
|
+
port=port,
|
|
233
|
+
shutdown_trigger=self.shutdown_trigger,
|
|
230
234
|
)
|
|
231
235
|
|
|
232
236
|
async def shutdown_trigger(self):
|
astrbot/dashboard/utils.py
CHANGED
|
@@ -2,14 +2,17 @@ import base64
|
|
|
2
2
|
import os
|
|
3
3
|
import traceback
|
|
4
4
|
from io import BytesIO
|
|
5
|
+
|
|
5
6
|
from astrbot.api import logger
|
|
7
|
+
from astrbot.core.db.vec_db.faiss_impl import FaissVecDB
|
|
6
8
|
from astrbot.core.knowledge_base.kb_helper import KBHelper
|
|
7
9
|
from astrbot.core.knowledge_base.kb_mgr import KnowledgeBaseManager
|
|
8
|
-
from astrbot.core.db.vec_db.faiss_impl import FaissVecDB
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
async def generate_tsne_visualization(
|
|
12
|
-
query: str,
|
|
13
|
+
query: str,
|
|
14
|
+
kb_names: list[str],
|
|
15
|
+
kb_manager: KnowledgeBaseManager,
|
|
13
16
|
) -> str | None:
|
|
14
17
|
"""生成 t-SNE 可视化图片
|
|
15
18
|
|
|
@@ -20,18 +23,19 @@ async def generate_tsne_visualization(
|
|
|
20
23
|
|
|
21
24
|
Returns:
|
|
22
25
|
图片路径或 None
|
|
26
|
+
|
|
23
27
|
"""
|
|
24
28
|
try:
|
|
25
29
|
import faiss
|
|
26
|
-
import numpy as np
|
|
27
30
|
import matplotlib
|
|
31
|
+
import numpy as np
|
|
28
32
|
|
|
29
33
|
matplotlib.use("Agg") # 使用非交互式后端
|
|
30
34
|
import matplotlib.pyplot as plt
|
|
31
35
|
from sklearn.manifold import TSNE
|
|
32
36
|
except ImportError as e:
|
|
33
37
|
raise Exception(
|
|
34
|
-
"缺少必要的库以生成 t-SNE 可视化。请安装 matplotlib 和 scikit-learn: {e}"
|
|
38
|
+
"缺少必要的库以生成 t-SNE 可视化。请安装 matplotlib 和 scikit-learn: {e}",
|
|
35
39
|
) from e
|
|
36
40
|
|
|
37
41
|
try:
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: AstrBot
|
|
3
|
-
Version: 4.5.
|
|
3
|
+
Version: 4.5.3
|
|
4
4
|
Summary: 易上手的多平台 LLM 聊天机器人及开发框架
|
|
5
5
|
License-File: LICENSE
|
|
6
|
+
Keywords: Astrbot,Astrbot Module,Astrbot Plugin
|
|
6
7
|
Requires-Python: >=3.10
|
|
7
8
|
Requires-Dist: aiocqhttp>=1.4.4
|
|
8
9
|
Requires-Dist: aiodocker>=0.24.0
|