AstrBot 4.6.1__py3-none-any.whl → 4.7.1__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/core/agent/mcp_client.py +3 -3
- astrbot/core/agent/runners/base.py +7 -4
- astrbot/core/agent/runners/coze/coze_agent_runner.py +367 -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/{utils → agent/runners/dify}/dify_api_client.py +51 -13
- astrbot/core/agent/runners/tool_loop_agent_runner.py +0 -6
- astrbot/core/config/default.py +141 -26
- astrbot/core/config/i18n_utils.py +110 -0
- astrbot/core/core_lifecycle.py +11 -13
- astrbot/core/db/po.py +1 -1
- astrbot/core/db/sqlite.py +2 -2
- astrbot/core/pipeline/process_stage/method/agent_request.py +48 -0
- astrbot/core/pipeline/process_stage/method/{llm_request.py → agent_sub_stages/internal.py} +13 -34
- astrbot/core/pipeline/process_stage/method/agent_sub_stages/third_party.py +202 -0
- astrbot/core/pipeline/process_stage/method/star_request.py +1 -1
- astrbot/core/pipeline/process_stage/stage.py +8 -5
- astrbot/core/pipeline/result_decorate/stage.py +15 -5
- astrbot/core/provider/manager.py +43 -41
- astrbot/core/star/session_llm_manager.py +0 -107
- astrbot/core/star/session_plugin_manager.py +0 -81
- astrbot/core/umop_config_router.py +19 -0
- astrbot/core/utils/migra_helper.py +73 -0
- astrbot/core/utils/shared_preferences.py +1 -28
- astrbot/dashboard/routes/chat.py +13 -1
- astrbot/dashboard/routes/config.py +20 -16
- astrbot/dashboard/routes/knowledge_base.py +0 -156
- astrbot/dashboard/routes/session_management.py +311 -606
- {astrbot-4.6.1.dist-info → astrbot-4.7.1.dist-info}/METADATA +1 -1
- {astrbot-4.6.1.dist-info → astrbot-4.7.1.dist-info}/RECORD +34 -30
- {astrbot-4.6.1.dist-info → astrbot-4.7.1.dist-info}/WHEEL +1 -1
- astrbot/core/provider/sources/coze_source.py +0 -650
- astrbot/core/provider/sources/dashscope_source.py +0 -207
- astrbot/core/provider/sources/dify_source.py +0 -285
- /astrbot/core/{provider/sources → agent/runners/coze}/coze_api_client.py +0 -0
- {astrbot-4.6.1.dist-info → astrbot-4.7.1.dist-info}/entry_points.txt +0 -0
- {astrbot-4.6.1.dist-info → astrbot-4.7.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -42,87 +42,6 @@ class SessionPluginManager:
|
|
|
42
42
|
# 如果都没有配置,默认为启用(兼容性考虑)
|
|
43
43
|
return True
|
|
44
44
|
|
|
45
|
-
@staticmethod
|
|
46
|
-
def set_plugin_status_for_session(
|
|
47
|
-
session_id: str,
|
|
48
|
-
plugin_name: str,
|
|
49
|
-
enabled: bool,
|
|
50
|
-
) -> None:
|
|
51
|
-
"""设置插件在指定会话中的启停状态
|
|
52
|
-
|
|
53
|
-
Args:
|
|
54
|
-
session_id: 会话ID (unified_msg_origin)
|
|
55
|
-
plugin_name: 插件名称
|
|
56
|
-
enabled: True表示启用,False表示禁用
|
|
57
|
-
|
|
58
|
-
"""
|
|
59
|
-
# 获取当前配置
|
|
60
|
-
session_plugin_config = sp.get(
|
|
61
|
-
"session_plugin_config",
|
|
62
|
-
{},
|
|
63
|
-
scope="umo",
|
|
64
|
-
scope_id=session_id,
|
|
65
|
-
)
|
|
66
|
-
if session_id not in session_plugin_config:
|
|
67
|
-
session_plugin_config[session_id] = {
|
|
68
|
-
"enabled_plugins": [],
|
|
69
|
-
"disabled_plugins": [],
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
session_config = session_plugin_config[session_id]
|
|
73
|
-
enabled_plugins = session_config.get("enabled_plugins", [])
|
|
74
|
-
disabled_plugins = session_config.get("disabled_plugins", [])
|
|
75
|
-
|
|
76
|
-
if enabled:
|
|
77
|
-
# 启用插件
|
|
78
|
-
if plugin_name in disabled_plugins:
|
|
79
|
-
disabled_plugins.remove(plugin_name)
|
|
80
|
-
if plugin_name not in enabled_plugins:
|
|
81
|
-
enabled_plugins.append(plugin_name)
|
|
82
|
-
else:
|
|
83
|
-
# 禁用插件
|
|
84
|
-
if plugin_name in enabled_plugins:
|
|
85
|
-
enabled_plugins.remove(plugin_name)
|
|
86
|
-
if plugin_name not in disabled_plugins:
|
|
87
|
-
disabled_plugins.append(plugin_name)
|
|
88
|
-
|
|
89
|
-
# 保存配置
|
|
90
|
-
session_config["enabled_plugins"] = enabled_plugins
|
|
91
|
-
session_config["disabled_plugins"] = disabled_plugins
|
|
92
|
-
session_plugin_config[session_id] = session_config
|
|
93
|
-
sp.put(
|
|
94
|
-
"session_plugin_config",
|
|
95
|
-
session_plugin_config,
|
|
96
|
-
scope="umo",
|
|
97
|
-
scope_id=session_id,
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
logger.info(
|
|
101
|
-
f"会话 {session_id} 的插件 {plugin_name} 状态已更新为: {'启用' if enabled else '禁用'}",
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
@staticmethod
|
|
105
|
-
def get_session_plugin_config(session_id: str) -> dict[str, list[str]]:
|
|
106
|
-
"""获取指定会话的插件配置
|
|
107
|
-
|
|
108
|
-
Args:
|
|
109
|
-
session_id: 会话ID (unified_msg_origin)
|
|
110
|
-
|
|
111
|
-
Returns:
|
|
112
|
-
Dict[str, List[str]]: 包含enabled_plugins和disabled_plugins的字典
|
|
113
|
-
|
|
114
|
-
"""
|
|
115
|
-
session_plugin_config = sp.get(
|
|
116
|
-
"session_plugin_config",
|
|
117
|
-
{},
|
|
118
|
-
scope="umo",
|
|
119
|
-
scope_id=session_id,
|
|
120
|
-
)
|
|
121
|
-
return session_plugin_config.get(
|
|
122
|
-
session_id,
|
|
123
|
-
{"enabled_plugins": [], "disabled_plugins": []},
|
|
124
|
-
)
|
|
125
|
-
|
|
126
45
|
@staticmethod
|
|
127
46
|
def filter_handlers_by_session(event: AstrMessageEvent, handlers: list) -> list:
|
|
128
47
|
"""根据会话配置过滤处理器列表
|
|
@@ -85,3 +85,22 @@ class UmopConfigRouter:
|
|
|
85
85
|
|
|
86
86
|
self.umop_to_conf_id[umo] = conf_id
|
|
87
87
|
await self.sp.global_put("umop_config_routing", self.umop_to_conf_id)
|
|
88
|
+
|
|
89
|
+
async def delete_route(self, umo: str):
|
|
90
|
+
"""删除一条路由
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
umo (str): 需要删除的 UMO 字符串
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
ValueError: 当 umo 格式不正确时抛出
|
|
97
|
+
"""
|
|
98
|
+
|
|
99
|
+
if not isinstance(umo, str) or len(umo.split(":")) != 3:
|
|
100
|
+
raise ValueError(
|
|
101
|
+
"umop must be a string in the format [platform_id]:[message_type]:[session_id], with optional wildcards * or empty for all",
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if umo in self.umop_to_conf_id:
|
|
105
|
+
del self.umop_to_conf_id[umo]
|
|
106
|
+
await self.sp.global_put("umop_config_routing", self.umop_to_conf_id)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import traceback
|
|
2
|
+
|
|
3
|
+
from astrbot.core import astrbot_config, logger
|
|
4
|
+
from astrbot.core.astrbot_config_mgr import AstrBotConfig, AstrBotConfigManager
|
|
5
|
+
from astrbot.core.db.migration.migra_45_to_46 import migrate_45_to_46
|
|
6
|
+
from astrbot.core.db.migration.migra_webchat_session import migrate_webchat_session
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _migra_agent_runner_configs(conf: AstrBotConfig, ids_map: dict) -> None:
|
|
10
|
+
"""
|
|
11
|
+
Migra agent runner configs from provider configs.
|
|
12
|
+
"""
|
|
13
|
+
try:
|
|
14
|
+
default_prov_id = conf["provider_settings"]["default_provider_id"]
|
|
15
|
+
if default_prov_id in ids_map:
|
|
16
|
+
conf["provider_settings"]["default_provider_id"] = ""
|
|
17
|
+
p = ids_map[default_prov_id]
|
|
18
|
+
if p["type"] == "dify":
|
|
19
|
+
conf["provider_settings"]["dify_agent_runner_provider_id"] = p["id"]
|
|
20
|
+
conf["provider_settings"]["agent_runner_type"] = "dify"
|
|
21
|
+
elif p["type"] == "coze":
|
|
22
|
+
conf["provider_settings"]["coze_agent_runner_provider_id"] = p["id"]
|
|
23
|
+
conf["provider_settings"]["agent_runner_type"] = "coze"
|
|
24
|
+
elif p["type"] == "dashscope":
|
|
25
|
+
conf["provider_settings"]["dashscope_agent_runner_provider_id"] = p[
|
|
26
|
+
"id"
|
|
27
|
+
]
|
|
28
|
+
conf["provider_settings"]["agent_runner_type"] = "dashscope"
|
|
29
|
+
conf.save_config()
|
|
30
|
+
except Exception as e:
|
|
31
|
+
logger.error(f"Migration for third party agent runner configs failed: {e!s}")
|
|
32
|
+
logger.error(traceback.format_exc())
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
async def migra(
|
|
36
|
+
db, astrbot_config_mgr, umop_config_router, acm: AstrBotConfigManager
|
|
37
|
+
) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Stores the migration logic here.
|
|
40
|
+
btw, i really don't like migration :(
|
|
41
|
+
"""
|
|
42
|
+
# 4.5 to 4.6 migration for umop_config_router
|
|
43
|
+
try:
|
|
44
|
+
await migrate_45_to_46(astrbot_config_mgr, umop_config_router)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
logger.error(f"Migration from version 4.5 to 4.6 failed: {e!s}")
|
|
47
|
+
logger.error(traceback.format_exc())
|
|
48
|
+
|
|
49
|
+
# migration for webchat session
|
|
50
|
+
try:
|
|
51
|
+
await migrate_webchat_session(db)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
logger.error(f"Migration for webchat session failed: {e!s}")
|
|
54
|
+
logger.error(traceback.format_exc())
|
|
55
|
+
|
|
56
|
+
# migra third party agent runner configs
|
|
57
|
+
_c = False
|
|
58
|
+
providers = astrbot_config["provider"]
|
|
59
|
+
ids_map = {}
|
|
60
|
+
for prov in providers:
|
|
61
|
+
type_ = prov.get("type")
|
|
62
|
+
if type_ in ["dify", "coze", "dashscope"]:
|
|
63
|
+
prov["provider_type"] = "agent_runner"
|
|
64
|
+
ids_map[prov["id"]] = {
|
|
65
|
+
"type": type_,
|
|
66
|
+
"id": prov["id"],
|
|
67
|
+
}
|
|
68
|
+
_c = True
|
|
69
|
+
if _c:
|
|
70
|
+
astrbot_config.save_config()
|
|
71
|
+
|
|
72
|
+
for conf in acm.confs.values():
|
|
73
|
+
_migra_agent_runner_configs(conf, ids_map)
|
|
@@ -40,9 +40,6 @@ class SharedPreferences:
|
|
|
40
40
|
else:
|
|
41
41
|
ret = default
|
|
42
42
|
return ret
|
|
43
|
-
raise ValueError(
|
|
44
|
-
"scope_id and key cannot be None when getting a specific preference.",
|
|
45
|
-
)
|
|
46
43
|
|
|
47
44
|
async def range_get_async(
|
|
48
45
|
self,
|
|
@@ -56,30 +53,6 @@ class SharedPreferences:
|
|
|
56
53
|
ret = await self.db_helper.get_preferences(scope, scope_id, key)
|
|
57
54
|
return ret
|
|
58
55
|
|
|
59
|
-
@overload
|
|
60
|
-
async def session_get(
|
|
61
|
-
self,
|
|
62
|
-
umo: None,
|
|
63
|
-
key: str,
|
|
64
|
-
default: Any = None,
|
|
65
|
-
) -> list[Preference]: ...
|
|
66
|
-
|
|
67
|
-
@overload
|
|
68
|
-
async def session_get(
|
|
69
|
-
self,
|
|
70
|
-
umo: str,
|
|
71
|
-
key: None,
|
|
72
|
-
default: Any = None,
|
|
73
|
-
) -> list[Preference]: ...
|
|
74
|
-
|
|
75
|
-
@overload
|
|
76
|
-
async def session_get(
|
|
77
|
-
self,
|
|
78
|
-
umo: None,
|
|
79
|
-
key: None,
|
|
80
|
-
default: Any = None,
|
|
81
|
-
) -> list[Preference]: ...
|
|
82
|
-
|
|
83
56
|
async def session_get(
|
|
84
57
|
self,
|
|
85
58
|
umo: str | None,
|
|
@@ -88,7 +61,7 @@ class SharedPreferences:
|
|
|
88
61
|
) -> _VT | list[Preference]:
|
|
89
62
|
"""获取会话范围的偏好设置
|
|
90
63
|
|
|
91
|
-
Note: 当
|
|
64
|
+
Note: 当 umo 或者 key 为 None,时,返回 Preference 列表,其中的 value 属性是一个 dict,value["val"] 为值。
|
|
92
65
|
"""
|
|
93
66
|
if umo is None or key is None:
|
|
94
67
|
return await self.range_get_async("umo", umo, key)
|
astrbot/dashboard/routes/chat.py
CHANGED
|
@@ -56,6 +56,7 @@ class ChatRoute(Route):
|
|
|
56
56
|
self.conv_mgr = core_lifecycle.conversation_manager
|
|
57
57
|
self.platform_history_mgr = core_lifecycle.platform_message_history_manager
|
|
58
58
|
self.db = db
|
|
59
|
+
self.umop_config_router = core_lifecycle.umop_config_router
|
|
59
60
|
|
|
60
61
|
self.running_convs: dict[str, bool] = {}
|
|
61
62
|
|
|
@@ -266,7 +267,8 @@ class ChatRoute(Route):
|
|
|
266
267
|
return Response().error("Permission denied").__dict__
|
|
267
268
|
|
|
268
269
|
# 删除该会话下的所有对话
|
|
269
|
-
|
|
270
|
+
message_type = "GroupMessage" if session.is_group else "FriendMessage"
|
|
271
|
+
unified_msg_origin = f"{session.platform_id}:{message_type}:{session.platform_id}!{username}!{session_id}"
|
|
270
272
|
await self.conv_mgr.delete_conversations_by_user_id(unified_msg_origin)
|
|
271
273
|
|
|
272
274
|
# 删除消息历史
|
|
@@ -276,6 +278,16 @@ class ChatRoute(Route):
|
|
|
276
278
|
offset_sec=99999999,
|
|
277
279
|
)
|
|
278
280
|
|
|
281
|
+
# 删除与会话关联的配置路由
|
|
282
|
+
try:
|
|
283
|
+
await self.umop_config_router.delete_route(unified_msg_origin)
|
|
284
|
+
except ValueError as exc:
|
|
285
|
+
logger.warning(
|
|
286
|
+
"Failed to delete UMO route %s during session cleanup: %s",
|
|
287
|
+
unified_msg_origin,
|
|
288
|
+
exc,
|
|
289
|
+
)
|
|
290
|
+
|
|
279
291
|
# 清理队列(仅对 webchat)
|
|
280
292
|
if session.platform_id == "webchat":
|
|
281
293
|
webchat_queue_mgr.remove_queues(session_id)
|
|
@@ -14,6 +14,7 @@ from astrbot.core.config.default import (
|
|
|
14
14
|
DEFAULT_CONFIG,
|
|
15
15
|
DEFAULT_VALUE_MAP,
|
|
16
16
|
)
|
|
17
|
+
from astrbot.core.config.i18n_utils import ConfigMetadataI18n
|
|
17
18
|
from astrbot.core.core_lifecycle import AstrBotCoreLifecycle
|
|
18
19
|
from astrbot.core.platform.register import platform_cls_map, platform_registry
|
|
19
20
|
from astrbot.core.provider import Provider
|
|
@@ -133,7 +134,9 @@ def save_config(post_config: dict, config: AstrBotConfig, is_core: bool = False)
|
|
|
133
134
|
is_core,
|
|
134
135
|
)
|
|
135
136
|
else:
|
|
136
|
-
errors, post_config = validate_config(
|
|
137
|
+
errors, post_config = validate_config(
|
|
138
|
+
post_config, getattr(config, "schema", {}), is_core
|
|
139
|
+
)
|
|
137
140
|
except BaseException as e:
|
|
138
141
|
logger.error(traceback.format_exc())
|
|
139
142
|
logger.warning(f"验证配置时出现异常: {e}")
|
|
@@ -247,11 +250,8 @@ class ConfigRoute(Route):
|
|
|
247
250
|
|
|
248
251
|
async def get_default_config(self):
|
|
249
252
|
"""获取默认配置文件"""
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
.ok({"config": DEFAULT_CONFIG, "metadata": CONFIG_METADATA_3})
|
|
253
|
-
.__dict__
|
|
254
|
-
)
|
|
253
|
+
metadata = ConfigMetadataI18n.convert_to_i18n_keys(CONFIG_METADATA_3)
|
|
254
|
+
return Response().ok({"config": DEFAULT_CONFIG, "metadata": metadata}).__dict__
|
|
255
255
|
|
|
256
256
|
async def get_abconf_list(self):
|
|
257
257
|
"""获取所有 AstrBot 配置文件的列表"""
|
|
@@ -282,17 +282,15 @@ class ConfigRoute(Route):
|
|
|
282
282
|
try:
|
|
283
283
|
if system_config:
|
|
284
284
|
abconf = self.acm.confs["default"]
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
.ok({"config": abconf, "metadata": CONFIG_METADATA_3_SYSTEM})
|
|
288
|
-
.__dict__
|
|
285
|
+
metadata = ConfigMetadataI18n.convert_to_i18n_keys(
|
|
286
|
+
CONFIG_METADATA_3_SYSTEM
|
|
289
287
|
)
|
|
288
|
+
return Response().ok({"config": abconf, "metadata": metadata}).__dict__
|
|
289
|
+
if abconf_id is None:
|
|
290
|
+
raise ValueError("abconf_id cannot be None")
|
|
290
291
|
abconf = self.acm.confs[abconf_id]
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
.ok({"config": abconf, "metadata": CONFIG_METADATA_3})
|
|
294
|
-
.__dict__
|
|
295
|
-
)
|
|
292
|
+
metadata = ConfigMetadataI18n.convert_to_i18n_keys(CONFIG_METADATA_3)
|
|
293
|
+
return Response().ok({"config": abconf, "metadata": metadata}).__dict__
|
|
296
294
|
except ValueError as e:
|
|
297
295
|
return Response().error(str(e)).__dict__
|
|
298
296
|
|
|
@@ -598,9 +596,15 @@ class ConfigRoute(Route):
|
|
|
598
596
|
return Response().error("缺少参数 provider_id").__dict__
|
|
599
597
|
|
|
600
598
|
prov_mgr = self.core_lifecycle.provider_manager
|
|
601
|
-
provider
|
|
599
|
+
provider = prov_mgr.inst_map.get(provider_id, None)
|
|
602
600
|
if not provider:
|
|
603
601
|
return Response().error(f"未找到 ID 为 {provider_id} 的提供商").__dict__
|
|
602
|
+
if not isinstance(provider, Provider):
|
|
603
|
+
return (
|
|
604
|
+
Response()
|
|
605
|
+
.error(f"提供商 {provider_id} 类型不支持获取模型列表")
|
|
606
|
+
.__dict__
|
|
607
|
+
)
|
|
604
608
|
|
|
605
609
|
try:
|
|
606
610
|
models = await provider.get_models()
|
|
@@ -60,10 +60,6 @@ class KnowledgeBaseRoute(Route):
|
|
|
60
60
|
# "/kb/media/delete": ("POST", self.delete_media),
|
|
61
61
|
# 检索
|
|
62
62
|
"/kb/retrieve": ("POST", self.retrieve),
|
|
63
|
-
# 会话知识库配置
|
|
64
|
-
"/kb/session/config/get": ("GET", self.get_session_kb_config),
|
|
65
|
-
"/kb/session/config/set": ("POST", self.set_session_kb_config),
|
|
66
|
-
"/kb/session/config/delete": ("POST", self.delete_session_kb_config),
|
|
67
63
|
}
|
|
68
64
|
self.register_routes()
|
|
69
65
|
|
|
@@ -920,158 +916,6 @@ class KnowledgeBaseRoute(Route):
|
|
|
920
916
|
logger.error(traceback.format_exc())
|
|
921
917
|
return Response().error(f"检索失败: {e!s}").__dict__
|
|
922
918
|
|
|
923
|
-
# ===== 会话知识库配置 API =====
|
|
924
|
-
|
|
925
|
-
async def get_session_kb_config(self):
|
|
926
|
-
"""获取会话的知识库配置
|
|
927
|
-
|
|
928
|
-
Query 参数:
|
|
929
|
-
- session_id: 会话 ID (必填)
|
|
930
|
-
|
|
931
|
-
返回:
|
|
932
|
-
- kb_ids: 知识库 ID 列表
|
|
933
|
-
- top_k: 返回结果数量
|
|
934
|
-
- enable_rerank: 是否启用重排序
|
|
935
|
-
"""
|
|
936
|
-
try:
|
|
937
|
-
from astrbot.core import sp
|
|
938
|
-
|
|
939
|
-
session_id = request.args.get("session_id")
|
|
940
|
-
|
|
941
|
-
if not session_id:
|
|
942
|
-
return Response().error("缺少参数 session_id").__dict__
|
|
943
|
-
|
|
944
|
-
# 从 SharedPreferences 获取配置
|
|
945
|
-
config = await sp.session_get(session_id, "kb_config", default={})
|
|
946
|
-
|
|
947
|
-
logger.debug(f"[KB配置] 读取到配置: session_id={session_id}")
|
|
948
|
-
|
|
949
|
-
# 如果没有配置,返回默认值
|
|
950
|
-
if not config:
|
|
951
|
-
config = {"kb_ids": [], "top_k": 5, "enable_rerank": True}
|
|
952
|
-
|
|
953
|
-
return Response().ok(config).__dict__
|
|
954
|
-
|
|
955
|
-
except Exception as e:
|
|
956
|
-
logger.error(f"[KB配置] 获取配置时出错: {e}", exc_info=True)
|
|
957
|
-
return Response().error(f"获取会话知识库配置失败: {e!s}").__dict__
|
|
958
|
-
|
|
959
|
-
async def set_session_kb_config(self):
|
|
960
|
-
"""设置会话的知识库配置
|
|
961
|
-
|
|
962
|
-
Body:
|
|
963
|
-
- scope: 配置范围 (目前只支持 "session")
|
|
964
|
-
- scope_id: 会话 ID (必填)
|
|
965
|
-
- kb_ids: 知识库 ID 列表 (必填)
|
|
966
|
-
- top_k: 返回结果数量 (可选, 默认 5)
|
|
967
|
-
- enable_rerank: 是否启用重排序 (可选, 默认 true)
|
|
968
|
-
"""
|
|
969
|
-
try:
|
|
970
|
-
from astrbot.core import sp
|
|
971
|
-
|
|
972
|
-
data = await request.json
|
|
973
|
-
|
|
974
|
-
scope = data.get("scope")
|
|
975
|
-
scope_id = data.get("scope_id")
|
|
976
|
-
kb_ids = data.get("kb_ids", [])
|
|
977
|
-
top_k = data.get("top_k", 5)
|
|
978
|
-
enable_rerank = data.get("enable_rerank", True)
|
|
979
|
-
|
|
980
|
-
# 验证参数
|
|
981
|
-
if scope != "session":
|
|
982
|
-
return Response().error("目前仅支持 session 范围的配置").__dict__
|
|
983
|
-
|
|
984
|
-
if not scope_id:
|
|
985
|
-
return Response().error("缺少参数 scope_id").__dict__
|
|
986
|
-
|
|
987
|
-
if not isinstance(kb_ids, list):
|
|
988
|
-
return Response().error("kb_ids 必须是列表").__dict__
|
|
989
|
-
|
|
990
|
-
# 验证知识库是否存在
|
|
991
|
-
kb_mgr = self._get_kb_manager()
|
|
992
|
-
invalid_ids = []
|
|
993
|
-
valid_ids = []
|
|
994
|
-
for kb_id in kb_ids:
|
|
995
|
-
kb_helper = await kb_mgr.get_kb(kb_id)
|
|
996
|
-
if kb_helper:
|
|
997
|
-
valid_ids.append(kb_id)
|
|
998
|
-
else:
|
|
999
|
-
invalid_ids.append(kb_id)
|
|
1000
|
-
logger.warning(f"[KB配置] 知识库不存在: {kb_id}")
|
|
1001
|
-
|
|
1002
|
-
if invalid_ids:
|
|
1003
|
-
logger.warning(f"[KB配置] 以下知识库ID无效: {invalid_ids}")
|
|
1004
|
-
|
|
1005
|
-
# 允许保存空列表,表示明确不使用任何知识库
|
|
1006
|
-
if kb_ids and not valid_ids:
|
|
1007
|
-
# 只有当用户提供了 kb_ids 但全部无效时才报错
|
|
1008
|
-
return Response().error(f"所有提供的知识库ID都无效: {kb_ids}").__dict__
|
|
1009
|
-
|
|
1010
|
-
# 如果 kb_ids 为空列表,表示用户想清空配置
|
|
1011
|
-
if not kb_ids:
|
|
1012
|
-
valid_ids = []
|
|
1013
|
-
|
|
1014
|
-
# 构建配置对象(只保存有效的ID)
|
|
1015
|
-
config = {
|
|
1016
|
-
"kb_ids": valid_ids,
|
|
1017
|
-
"top_k": top_k,
|
|
1018
|
-
"enable_rerank": enable_rerank,
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
# 保存到 SharedPreferences
|
|
1022
|
-
await sp.session_put(scope_id, "kb_config", config)
|
|
1023
|
-
|
|
1024
|
-
# 立即验证是否保存成功
|
|
1025
|
-
verify_config = await sp.session_get(scope_id, "kb_config", default={})
|
|
1026
|
-
|
|
1027
|
-
if verify_config == config:
|
|
1028
|
-
return (
|
|
1029
|
-
Response()
|
|
1030
|
-
.ok(
|
|
1031
|
-
{"valid_ids": valid_ids, "invalid_ids": invalid_ids},
|
|
1032
|
-
"保存知识库配置成功",
|
|
1033
|
-
)
|
|
1034
|
-
.__dict__
|
|
1035
|
-
)
|
|
1036
|
-
logger.error("[KB配置] 配置保存失败,验证不匹配")
|
|
1037
|
-
return Response().error("配置保存失败").__dict__
|
|
1038
|
-
|
|
1039
|
-
except Exception as e:
|
|
1040
|
-
logger.error(f"[KB配置] 设置配置时出错: {e}", exc_info=True)
|
|
1041
|
-
return Response().error(f"设置会话知识库配置失败: {e!s}").__dict__
|
|
1042
|
-
|
|
1043
|
-
async def delete_session_kb_config(self):
|
|
1044
|
-
"""删除会话的知识库配置
|
|
1045
|
-
|
|
1046
|
-
Body:
|
|
1047
|
-
- scope: 配置范围 (目前只支持 "session")
|
|
1048
|
-
- scope_id: 会话 ID (必填)
|
|
1049
|
-
"""
|
|
1050
|
-
try:
|
|
1051
|
-
from astrbot.core import sp
|
|
1052
|
-
|
|
1053
|
-
data = await request.json
|
|
1054
|
-
|
|
1055
|
-
scope = data.get("scope")
|
|
1056
|
-
scope_id = data.get("scope_id")
|
|
1057
|
-
|
|
1058
|
-
# 验证参数
|
|
1059
|
-
if scope != "session":
|
|
1060
|
-
return Response().error("目前仅支持 session 范围的配置").__dict__
|
|
1061
|
-
|
|
1062
|
-
if not scope_id:
|
|
1063
|
-
return Response().error("缺少参数 scope_id").__dict__
|
|
1064
|
-
|
|
1065
|
-
# 从 SharedPreferences 删除配置
|
|
1066
|
-
await sp.session_remove(scope_id, "kb_config")
|
|
1067
|
-
|
|
1068
|
-
return Response().ok(message="删除知识库配置成功").__dict__
|
|
1069
|
-
|
|
1070
|
-
except Exception as e:
|
|
1071
|
-
logger.error(f"删除会话知识库配置失败: {e}")
|
|
1072
|
-
logger.error(traceback.format_exc())
|
|
1073
|
-
return Response().error(f"删除会话知识库配置失败: {e!s}").__dict__
|
|
1074
|
-
|
|
1075
919
|
async def upload_document_from_url(self):
|
|
1076
920
|
"""从 URL 上传文档
|
|
1077
921
|
|