From 2c5f68e6961e91424ae404b262deb88922aa6e8c Mon Sep 17 00:00:00 2001 From: Soulter <37870767+Soulter@users.noreply.github.com> Date: Mon, 20 Oct 2025 12:01:06 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=9E=84=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E5=B9=B3=E5=8F=B0=E6=97=B6=E7=9A=84=E6=B5=81=E7=A8=8B?= =?UTF-8?q?=E5=8F=8A=E4=B8=80=E4=BA=9B=20UI=20=E4=BC=98=E5=8C=96=20(#3102)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 支持在平台直接选择配置文件 * add webchat * feat: 支持新建平台时现场预览、创建和编辑配置文件 * fix: update configuration file descriptions and visibility based on updating mode * perf: use incremental decoder * perf: update descriptions * fix: UI update issues in config file dialog * fix: update UI elements for better readability and organization * feat: enhance sidebar navigation with group feature and dynamic resizing Co-authored-by: IGCrystal <3811541171@qq.com> * refactor: persona selector * perf: 修改部分默认行为 * fix: adjust ExtensionCard layout and improve responsiveness * refactor: 配置文件绑定消息平台重构为消息平台绑定配文件 * style: add custom styling for v-select selection text * fix: correct subtitle text in provider.json * refactor: update conversation management terminology and improve session ID handling * refactor: add Conversation ID localization and update table header reference * Update astrbot/core/db/migration/migra_45_to_46.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * style: format logger warning for better readability * refactor: comment out WebChat configuration for future reference --------- Co-authored-by: IGCrystal <3811541171@qq.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- astrbot/core/astrbot_config_mgr.py | 74 +- astrbot/core/config/default.py | 31 +- astrbot/core/core_lifecycle.py | 14 +- astrbot/core/db/migration/migra_45_to_46.py | 44 + astrbot/core/umop_config_router.py | 81 ++ astrbot/dashboard/routes/config.py | 83 +- .../config/AstrBotCoreConfigWrapper.vue | 105 ++ .../components/platform/AddNewPlatform.vue | 961 +++++++++++++++--- .../src/components/shared/AstrBotConfig.vue | 28 +- .../src/components/shared/AstrBotConfigV4.vue | 4 +- .../src/components/shared/ExtensionCard.vue | 230 ++--- dashboard/src/components/shared/ItemCard.vue | 1 - .../src/components/shared/PersonaForm.vue | 528 ++++++++++ .../src/components/shared/PersonaSelector.vue | 32 +- .../i18n/locales/en-US/core/navigation.json | 9 +- .../locales/en-US/features/conversation.json | 4 +- .../i18n/locales/zh-CN/core/navigation.json | 13 +- .../locales/zh-CN/features/conversation.json | 10 +- .../i18n/locales/zh-CN/features/platform.json | 12 +- .../i18n/locales/zh-CN/features/provider.json | 28 +- .../zh-CN/features/session-management.json | 2 +- .../layouts/full/vertical-sidebar/NavItem.vue | 54 +- .../full/vertical-sidebar/VerticalSidebar.vue | 102 +- .../full/vertical-sidebar/sidebarItem.ts | 68 +- dashboard/src/router/MainRoutes.ts | 6 +- dashboard/src/views/ConfigPage.vue | 651 +----------- dashboard/src/views/ConversationPage.vue | 6 +- dashboard/src/views/ExtensionPage.vue | 4 +- dashboard/src/views/PersonaPage.vue | 507 +-------- dashboard/src/views/PlatformPage.vue | 246 +---- dashboard/src/views/ProviderPage.vue | 6 +- dashboard/src/views/SessionManagementPage.vue | 4 +- packages/astrbot/commands/provider.py | 2 +- packages/astrbot/commands/sid.py | 21 +- 34 files changed, 2172 insertions(+), 1799 deletions(-) create mode 100644 astrbot/core/db/migration/migra_45_to_46.py create mode 100644 astrbot/core/umop_config_router.py create mode 100644 dashboard/src/components/config/AstrBotCoreConfigWrapper.vue create mode 100644 dashboard/src/components/shared/PersonaForm.vue diff --git a/astrbot/core/astrbot_config_mgr.py b/astrbot/core/astrbot_config_mgr.py index 056135d02..0ee3f4fe6 100644 --- a/astrbot/core/astrbot_config_mgr.py +++ b/astrbot/core/astrbot_config_mgr.py @@ -5,6 +5,7 @@ from astrbot.core.utils.shared_preferences import SharedPreferences from astrbot.core.config.astrbot_config import ASTRBOT_CONFIG_PATH from astrbot.core.config.default import DEFAULT_CONFIG from astrbot.core.platform.message_session import MessageSession +from astrbot.core.umop_config_router import UmopConfigRouter from astrbot.core.utils.astrbot_path import get_astrbot_config_path from typing import TypeVar, TypedDict @@ -15,14 +16,12 @@ class ConfInfo(TypedDict): """Configuration information for a specific session or platform.""" id: str # UUID of the configuration or "default" - umop: list[str] # Unified Message Origin Pattern name: str path: str # File name to the configuration file DEFAULT_CONFIG_CONF_INFO = ConfInfo( id="default", - umop=["::"], name="default", path=ASTRBOT_CONFIG_PATH, ) @@ -31,8 +30,14 @@ DEFAULT_CONFIG_CONF_INFO = ConfInfo( class AstrBotConfigManager: """A class to manage the system configuration of AstrBot, aka ACM""" - def __init__(self, default_config: AstrBotConfig, sp: SharedPreferences): + def __init__( + self, + default_config: AstrBotConfig, + ucr: UmopConfigRouter, + sp: SharedPreferences, + ): self.sp = sp + self.ucr = ucr self.confs: dict[str, AstrBotConfig] = {} """uuid / "default" -> AstrBotConfig""" self.confs["default"] = default_config @@ -63,24 +68,15 @@ class AstrBotConfigManager: ) continue - def _is_umo_match(self, p1: str, p2: str) -> bool: - """判断 p2 umo 是否逻辑包含于 p1 umo""" - p1_ls = p1.split(":") - p2_ls = p2.split(":") - - if len(p1_ls) != 3 or len(p2_ls) != 3: - return False # 非法格式 - - return all(p == "" or p == "*" or p == t for p, t in zip(p1_ls, p2_ls)) - def _load_conf_mapping(self, umo: str | MessageSession) -> ConfInfo: """获取指定 umo 的配置文件 uuid, 如果不存在则返回默认配置(返回 "default") Returns: ConfInfo: 包含配置文件的 uuid, 路径和名称等信息, 是一个 dict 类型 """ - # uuid -> { "umop": list, "path": str, "name": str } + # uuid -> { "path": str, "name": str } abconf_data = self._get_abconf_data() + if isinstance(umo, MessageSession): umo = str(umo) else: @@ -89,10 +85,13 @@ class AstrBotConfigManager: except Exception: return DEFAULT_CONFIG_CONF_INFO - for uuid_, meta in abconf_data.items(): - for pattern in meta["umop"]: - if self._is_umo_match(pattern, umo): - return ConfInfo(**meta, id=uuid_) + conf_id = self.ucr.get_conf_id_for_umop(umo) + if conf_id: + meta = abconf_data.get(conf_id) + if meta and isinstance(meta, dict): + # the bind relation between umo and conf is defined in ucr now, so we remove "umop" here + meta.pop("umop", None) + return ConfInfo(**meta, id=conf_id) return DEFAULT_CONFIG_CONF_INFO @@ -100,23 +99,14 @@ class AstrBotConfigManager: self, abconf_path: str, abconf_id: str, - umo_parts: list[str] | list[MessageSession], abconf_name: str | None = None, ) -> None: """保存配置文件的映射关系""" - for part in umo_parts: - if isinstance(part, MessageSession): - part = str(part) - elif not isinstance(part, str): - raise ValueError( - "umo_parts must be a list of strings or MessageSession instances" - ) abconf_data = self.sp.get( "abconf_mapping", {}, scope="global", scope_id="global" ) random_word = abconf_name or uuid.uuid4().hex[:8] abconf_data[abconf_id] = { - "umop": umo_parts, "path": abconf_path, "name": random_word, } @@ -153,29 +143,26 @@ class AstrBotConfigManager: def get_conf_list(self) -> list[ConfInfo]: """获取所有配置文件的元数据列表""" conf_list = [] - conf_list.append(DEFAULT_CONFIG_CONF_INFO) abconf_mapping = self._get_abconf_data() for uuid_, meta in abconf_mapping.items(): + if not isinstance(meta, dict): + continue + meta.pop("umop", None) conf_list.append(ConfInfo(**meta, id=uuid_)) + conf_list.append(DEFAULT_CONFIG_CONF_INFO) return conf_list def create_conf( self, - umo_parts: list[str] | list[MessageSession], config: dict = DEFAULT_CONFIG, name: str | None = None, ) -> str: - """ - umo 由三个部分组成 [platform_id]:[message_type]:[session_id]。 - - umo_parts 可以是 "::" (代表所有), 可以是 "[platform_id]::" (代表指定平台下的所有类型消息和会话)。 - """ conf_uuid = str(uuid.uuid4()) conf_file_name = f"abconf_{conf_uuid}.json" conf_path = os.path.join(get_astrbot_config_path(), conf_file_name) conf = AstrBotConfig(config_path=conf_path, default_config=config) conf.save_config() - self._save_conf_mapping(conf_file_name, conf_uuid, umo_parts, abconf_name=name) + self._save_conf_mapping(conf_file_name, conf_uuid, abconf_name=name) self.confs[conf_uuid] = conf return conf_uuid @@ -228,15 +215,12 @@ class AstrBotConfigManager: logger.info(f"成功删除配置文件 {conf_id}") return True - def update_conf_info( - self, conf_id: str, name: str | None = None, umo_parts: list[str] | None = None - ) -> bool: + def update_conf_info(self, conf_id: str, name: str | None = None) -> bool: """更新配置文件信息 Args: conf_id: 配置文件的 UUID name: 新的配置文件名称 (可选) - umo_parts: 新的 UMO 部分列表 (可选) Returns: bool: 更新是否成功 @@ -255,18 +239,6 @@ class AstrBotConfigManager: if name is not None: abconf_data[conf_id]["name"] = name - # 更新 UMO 部分 - if umo_parts is not None: - # 验证 UMO 部分格式 - for part in umo_parts: - if isinstance(part, MessageSession): - part = str(part) - elif not isinstance(part, str): - raise ValueError( - "umo_parts must be a list of strings or MessageSession instances" - ) - abconf_data[conf_id]["umop"] = umo_parts - # 保存更新 self.sp.put("abconf_mapping", abconf_data, scope="global", scope_id="global") self.abconf_data = abconf_data diff --git a/astrbot/core/config/default.py b/astrbot/core/config/default.py index a4743ba9e..7977e4392 100644 --- a/astrbot/core/config/default.py +++ b/astrbot/core/config/default.py @@ -166,7 +166,7 @@ CONFIG_METADATA_2 = { "callback_server_host": "0.0.0.0", "port": 6196, }, - "QQ 个人号(aiocqhttp)": { + "QQ 个人号(OneBot v11)": { "id": "default", "type": "aiocqhttp", "enable": False, @@ -174,7 +174,7 @@ CONFIG_METADATA_2 = { "ws_reverse_port": 6199, "ws_reverse_token": "", }, - "微信个人号(WeChatPadPro)": { + "WeChatPadPro": { "id": "wechatpadpro", "type": "wechatpadpro", "enable": False, @@ -301,8 +301,26 @@ CONFIG_METADATA_2 = { "satori_heartbeat_interval": 10, "satori_reconnect_delay": 5, }, + # "WebChat": { + # "id": "webchat", + # "type": "webchat", + # "enable": False, + # "webchat_link_path": "", + # "webchat_present_type": "fullscreen", + # }, }, "items": { + # "webchat_link_path": { + # "description": "链接路径", + # "_special": "webchat_link_path", + # "type": "string", + # }, + # "webchat_present_type": { + # "_special": "webchat_present_type", + # "description": "展现形式", + # "type": "string", + # "options": ["fullscreen", "embedded"], + # }, "satori_api_base_url": { "description": "Satori API 终结点", "type": "string", @@ -491,19 +509,18 @@ CONFIG_METADATA_2 = { "hint": "启用后,机器人可以接收到频道的私聊消息。", }, "ws_reverse_host": { - "description": "反向 Websocket 主机地址(AstrBot 为服务器端)", + "description": "反向 Websocket 主机", "type": "string", - "hint": "aiocqhttp 适配器的反向 Websocket 服务器 IP 地址,不包含端口号。", + "hint": "AstrBot 将作为服务器端。", }, "ws_reverse_port": { "description": "反向 Websocket 端口", "type": "int", - "hint": "aiocqhttp 适配器的反向 Websocket 端口。", }, "ws_reverse_token": { "description": "反向 Websocket Token", "type": "string", - "hint": "aiocqhttp 适配器的反向 Websocket Token。未设置则不启用 Token 验证。", + "hint": "反向 Websocket Token。未设置则不启用 Token 验证。", }, "wecom_ai_bot_name": { "description": "企业微信智能机器人的名字", @@ -2219,7 +2236,7 @@ CONFIG_METADATA_3 = { "provider_settings.wake_prefix": { "description": "LLM 聊天额外唤醒前缀 ", "type": "string", - "hint": "例子: 如果唤醒前缀为 `/`, 额外聊天唤醒前缀为 `chat`,则需要 `/chat` 才会触发 LLM 请求。默认为空。", + "hint": "如果唤醒前缀为 `/`, 额外聊天唤醒前缀为 `chat`,则需要 `/chat` 才会触发 LLM 请求。默认为空。", }, "provider_settings.prompt_prefix": { "description": "用户提示词", diff --git a/astrbot/core/core_lifecycle.py b/astrbot/core/core_lifecycle.py index 972a5f4f1..499637344 100644 --- a/astrbot/core/core_lifecycle.py +++ b/astrbot/core/core_lifecycle.py @@ -26,11 +26,13 @@ from astrbot.core.persona_mgr import PersonaManager from astrbot.core.provider.manager import ProviderManager from astrbot.core import LogBroker from astrbot.core.db import BaseDatabase +from astrbot.core.db.migration.migra_45_to_46 import migrate_45_to_46 from astrbot.core.updator import AstrBotUpdator from astrbot.core import logger, sp from astrbot.core.config.default import VERSION from astrbot.core.conversation_mgr import ConversationManager from astrbot.core.platform_message_history_mgr import PlatformMessageHistoryManager +from astrbot.core.umop_config_router import UmopConfigRouter from astrbot.core.astrbot_config_mgr import AstrBotConfigManager from astrbot.core.star.star_handler import star_handlers_registry, EventType from astrbot.core.star.star_handler import star_map @@ -84,11 +86,21 @@ class AstrBotCoreLifecycle: await html_renderer.initialize() + # 初始化 UMOP 配置路由器 + self.umop_config_router = UmopConfigRouter(sp=sp) + # 初始化 AstrBot 配置管理器 self.astrbot_config_mgr = AstrBotConfigManager( - default_config=self.astrbot_config, sp=sp + default_config=self.astrbot_config, ucr=self.umop_config_router, sp=sp ) + # 4.5 to 4.6 migration for umop_config_router + try: + await migrate_45_to_46(self.astrbot_config_mgr, self.umop_config_router) + except Exception as e: + logger.error(f"Migration from version 4.5 to 4.6 failed: {e!s}") + logger.error(traceback.format_exc()) + # 初始化事件队列 self.event_queue = Queue() diff --git a/astrbot/core/db/migration/migra_45_to_46.py b/astrbot/core/db/migration/migra_45_to_46.py new file mode 100644 index 000000000..8a1dc5de7 --- /dev/null +++ b/astrbot/core/db/migration/migra_45_to_46.py @@ -0,0 +1,44 @@ +from astrbot.api import logger, sp +from astrbot.core.astrbot_config_mgr import AstrBotConfigManager +from astrbot.core.umop_config_router import UmopConfigRouter + + +async def migrate_45_to_46(acm: AstrBotConfigManager, ucr: UmopConfigRouter): + abconf_data = acm.abconf_data + + if not isinstance(abconf_data, dict): + # should be unreachable + logger.warning( + f"migrate_45_to_46: abconf_data is not a dict (type={type(abconf_data)}). Value: {abconf_data!r}" + ) + return + + # 如果任何一项带有 umop,则说明需要迁移 + need_migration = False + for conf_id, conf_info in abconf_data.items(): + if isinstance(conf_info, dict) and "umop" in conf_info: + need_migration = True + break + + if not need_migration: + return + + logger.info("Starting migration from version 4.5 to 4.6") + + # extract umo->conf_id mapping + umo_to_conf_id = {} + for conf_id, conf_info in abconf_data.items(): + if isinstance(conf_info, dict) and "umop" in conf_info: + umop_ls = conf_info.pop("umop") + if not isinstance(umop_ls, list): + continue + for umo in umop_ls: + if isinstance(umo, str) and umo not in umo_to_conf_id: + umo_to_conf_id[umo] = conf_id + + # update the abconf data + await sp.global_put("abconf_mapping", abconf_data) + # update the umop config router + await ucr.update_routing_data(umo_to_conf_id) + + logger.info("Migration from version 45 to 46 completed successfully") diff --git a/astrbot/core/umop_config_router.py b/astrbot/core/umop_config_router.py new file mode 100644 index 000000000..dd2063e56 --- /dev/null +++ b/astrbot/core/umop_config_router.py @@ -0,0 +1,81 @@ +from astrbot.core.utils.shared_preferences import SharedPreferences + + +class UmopConfigRouter: + """UMOP 配置路由器""" + + def __init__(self, sp: SharedPreferences): + self.umop_to_conf_id: dict[str, str] = {} + """UMOP 到配置文件 ID 的映射""" + self.sp = sp + + self._load_routing_table() + + def _load_routing_table(self): + """加载路由表""" + # 从 SharedPreferences 中加载 umop_to_conf_id 映射 + sp_data = self.sp.get( + "umop_config_routing", {}, scope="global", scope_id="global" + ) + self.umop_to_conf_id = sp_data + + def _is_umo_match(self, p1: str, p2: str) -> bool: + """判断 p2 umo 是否逻辑包含于 p1 umo""" + p1_ls = p1.split(":") + p2_ls = p2.split(":") + + if len(p1_ls) != 3 or len(p2_ls) != 3: + return False # 非法格式 + + return all(p == "" or p == "*" or p == t for p, t in zip(p1_ls, p2_ls)) + + def get_conf_id_for_umop(self, umo: str) -> str | None: + """根据 UMO 获取对应的配置文件 ID + + Args: + umo (str): UMO 字符串 + + Returns: + str | None: 配置文件 ID,如果没有找到则返回 None + """ + for pattern, conf_id in self.umop_to_conf_id.items(): + if self._is_umo_match(pattern, umo): + return conf_id + return None + + async def update_routing_data(self, new_routing: dict[str, str]): + """更新路由表 + + Args: + new_routing (dict[str, str]): 新的 UMOP 到配置文件 ID 的映射。umo 由三个部分组成 [platform_id]:[message_type]:[session_id]。 + umop 可以是 "::" (代表所有), 可以是 "[platform_id]::" (代表指定平台下的所有类型消息和会话)。 + + Raises: + ValueError: 如果 new_routing 中的 key 格式不正确 + """ + for part in new_routing.keys(): + if not isinstance(part, str) or len(part.split(":")) != 3: + raise ValueError( + "umop keys must be strings in the format [platform_id]:[message_type]:[session_id], with optional wildcards * or empty for all" + ) + + self.umop_to_conf_id = new_routing + await self.sp.global_put("umop_config_routing", self.umop_to_conf_id) + + async def update_route(self, umo: str, conf_id: str): + """更新一条路由 + + Args: + umo (str): UMO 字符串 + conf_id (str): 配置文件 ID + + Raises: + ValueError: 如果 umo 格式不正确 + """ + if not isinstance(umo, str) or len(umo.split(":")) != 3: + raise ValueError( + "umop must be a string in the format [platform_id]:[message_type]:[session_id], with optional wildcards * or empty for all" + ) + + self.umop_to_conf_id[umo] = conf_id + await self.sp.global_put("umop_config_routing", self.umop_to_conf_id) diff --git a/astrbot/dashboard/routes/config.py b/astrbot/dashboard/routes/config.py index bb0b723bf..01b9b2432 100644 --- a/astrbot/dashboard/routes/config.py +++ b/astrbot/dashboard/routes/config.py @@ -6,6 +6,7 @@ from .route import Route, Response, RouteContext from astrbot.core.provider.entities import ProviderType from quart import request from astrbot.core.config.default import ( + DEFAULT_CONFIG, CONFIG_METADATA_2, DEFAULT_VALUE_MAP, CONFIG_METADATA_3, @@ -152,13 +153,19 @@ class ConfigRoute(Route): self.config: AstrBotConfig = core_lifecycle.astrbot_config self._logo_token_cache = {} # 缓存logo token,避免重复注册 self.acm = core_lifecycle.astrbot_config_mgr + self.ucr = core_lifecycle.umop_config_router self.routes = { "/config/abconf/new": ("POST", self.create_abconf), "/config/abconf": ("GET", self.get_abconf), "/config/abconfs": ("GET", self.get_abconf_list), "/config/abconf/delete": ("POST", self.delete_abconf), "/config/abconf/update": ("POST", self.update_abconf), + "/config/umo_abconf_routes": ("GET", self.get_uc_table), + "/config/umo_abconf_route/update_all": ("POST", self.update_ucr_all), + "/config/umo_abconf_route/update": ("POST", self.update_ucr), + "/config/umo_abconf_route/delete": ("POST", self.delete_ucr), "/config/get": ("GET", self.get_configs), + "/config/default": ("GET", self.get_default_config), "/config/astrbot/update": ("POST", self.post_astrbot_configs), "/config/plugin/update": ("POST", self.post_plugin_configs), "/config/platform/new": ("POST", self.post_new_platform), @@ -174,6 +181,75 @@ class ConfigRoute(Route): } self.register_routes() + async def get_uc_table(self): + """获取 UMOP 配置路由表""" + return Response().ok({"routing": self.ucr.umop_to_conf_id}).__dict__ + + async def update_ucr_all(self): + """更新 UMOP 配置路由表的全部内容""" + post_data = await request.json + if not post_data: + return Response().error("缺少配置数据").__dict__ + + new_routing = post_data.get("routing", None) + + if not new_routing or not isinstance(new_routing, dict): + return Response().error("缺少或错误的路由表数据").__dict__ + + try: + await self.ucr.update_routing_data(new_routing) + return Response().ok(message="更新成功").__dict__ + except Exception as e: + logger.error(traceback.format_exc()) + return Response().error(f"更新路由表失败: {str(e)}").__dict__ + + async def update_ucr(self): + """更新 UMOP 配置路由表""" + post_data = await request.json + if not post_data: + return Response().error("缺少配置数据").__dict__ + + umo = post_data.get("umo", None) + conf_id = post_data.get("conf_id", None) + + if not umo or not conf_id: + return Response().error("缺少 UMO 或配置文件 ID").__dict__ + + try: + await self.ucr.update_route(umo, conf_id) + return Response().ok(message="更新成功").__dict__ + except Exception as e: + logger.error(traceback.format_exc()) + return Response().error(f"更新路由表失败: {str(e)}").__dict__ + + async def delete_ucr(self): + """删除 UMOP 配置路由表中的一项""" + post_data = await request.json + if not post_data: + return Response().error("缺少配置数据").__dict__ + + umo = post_data.get("umo", None) + + if not umo: + return Response().error("缺少 UMO").__dict__ + + try: + if umo in self.ucr.umop_to_conf_id: + del self.ucr.umop_to_conf_id[umo] + await self.ucr.update_routing_data(self.ucr.umop_to_conf_id) + return Response().ok(message="删除成功").__dict__ + except Exception as e: + logger.error(traceback.format_exc()) + return Response().error(f"删除路由表项失败: {str(e)}").__dict__ + + async def get_default_config(self): + """获取默认配置文件""" + return ( + Response() + .ok({"config": DEFAULT_CONFIG, "metadata": CONFIG_METADATA_3}) + .__dict__ + ) + async def get_abconf_list(self): """获取所有 AstrBot 配置文件的列表""" abconf_list = self.acm.get_conf_list() @@ -184,11 +260,11 @@ class ConfigRoute(Route): post_data = await request.json if not post_data: return Response().error("缺少配置数据").__dict__ - umo_parts = post_data["umo_parts"] name = post_data.get("name", None) + config = post_data.get("config", DEFAULT_CONFIG) try: - conf_id = self.acm.create_conf(umo_parts=umo_parts, name=name) + conf_id = self.acm.create_conf(name=name, config=config) return Response().ok(message="创建成功", data={"conf_id": conf_id}).__dict__ except ValueError as e: return Response().error(str(e)).__dict__ @@ -250,10 +326,9 @@ class ConfigRoute(Route): return Response().error("缺少配置文件 ID").__dict__ name = post_data.get("name") - umo_parts = post_data.get("umo_parts") try: - success = self.acm.update_conf_info(conf_id, name=name, umo_parts=umo_parts) + success = self.acm.update_conf_info(conf_id, name=name) if success: return Response().ok(message="更新成功").__dict__ else: diff --git a/dashboard/src/components/config/AstrBotCoreConfigWrapper.vue b/dashboard/src/components/config/AstrBotCoreConfigWrapper.vue new file mode 100644 index 000000000..f3d5abe14 --- /dev/null +++ b/dashboard/src/components/config/AstrBotCoreConfigWrapper.vue @@ -0,0 +1,105 @@ + + + + + \ No newline at end of file diff --git a/dashboard/src/components/platform/AddNewPlatform.vue b/dashboard/src/components/platform/AddNewPlatform.vue index 236a6aab7..b837eef0d 100644 --- a/dashboard/src/components/platform/AddNewPlatform.vue +++ b/dashboard/src/components/platform/AddNewPlatform.vue @@ -1,51 +1,272 @@ + - + \ No newline at end of file diff --git a/dashboard/src/components/shared/AstrBotConfig.vue b/dashboard/src/components/shared/AstrBotConfig.vue index ea8a62b80..e45327eb8 100644 --- a/dashboard/src/components/shared/AstrBotConfig.vue +++ b/dashboard/src/components/shared/AstrBotConfig.vue @@ -135,7 +135,7 @@ function hasVisibleItemsAfter(items, currentIndex) { + + \ No newline at end of file diff --git a/dashboard/src/layouts/full/vertical-sidebar/sidebarItem.ts b/dashboard/src/layouts/full/vertical-sidebar/sidebarItem.ts index 861a51e47..7dfe0d9a8 100644 --- a/dashboard/src/layouts/full/vertical-sidebar/sidebarItem.ts +++ b/dashboard/src/layouts/full/vertical-sidebar/sidebarItem.ts @@ -18,31 +18,26 @@ export interface menu { // 在组件中使用时需要通过t()函数进行翻译 // 所有键名都使用 core.navigation.* 格式 const sidebarItem: menu[] = [ - { - title: 'core.navigation.dashboard', - icon: 'mdi-view-dashboard', - to: '/dashboard/default' - }, { title: 'core.navigation.platforms', - icon: 'mdi-message-processing', - to: '/platforms', + icon: 'mdi-robot', + to: '/', }, { title: 'core.navigation.providers', icon: 'mdi-creation', to: '/providers', }, + { + title: 'core.navigation.config', + icon: 'mdi-cog', + to: '/config', + }, { title: 'core.navigation.toolUse', icon: 'mdi-function-variant', to: '/tool-use' }, - { - title: 'core.navigation.persona', - icon: 'mdi-heart', - to: '/persona' - }, { title: 'core.navigation.extension', icon: 'mdi-puzzle', @@ -53,31 +48,42 @@ const sidebarItem: menu[] = [ icon: 'mdi-text-box-search', to: '/alkaid/knowledge-base', }, - { - title: 'core.navigation.config', - icon: 'mdi-cog', - to: '/config', - }, { title: 'core.navigation.chat', icon: 'mdi-chat', to: '/chat' }, { - title: 'core.navigation.conversation', - icon: 'mdi-database', - to: '/conversation' - }, - { - title: 'core.navigation.sessionManagement', - icon: 'mdi-account-group', - to: '/session-management' - }, - { - title: 'core.navigation.console', - icon: 'mdi-console', - to: '/console' - }, + title: 'core.navigation.groups.more', + icon: 'mdi-dots-horizontal', + children: [ + { + title: 'core.navigation.persona', + icon: 'mdi-heart', + to: '/persona' + }, + { + title: 'core.navigation.conversation', + icon: 'mdi-database', + to: '/conversation' + }, + { + title: 'core.navigation.sessionManagement', + icon: 'mdi-account-group', + to: '/session-management' + }, + { + title: 'core.navigation.dashboard', + icon: 'mdi-view-dashboard', + to: '/dashboard/default' + }, + { + title: 'core.navigation.console', + icon: 'mdi-console', + to: '/console' + }, + ] + } // { // title: 'Project ATRI', // icon: 'mdi-grain', diff --git a/dashboard/src/router/MainRoutes.ts b/dashboard/src/router/MainRoutes.ts index 29b3bf5e7..8fb328a20 100644 --- a/dashboard/src/router/MainRoutes.ts +++ b/dashboard/src/router/MainRoutes.ts @@ -3,13 +3,13 @@ const MainRoutes = { meta: { requiresAuth: true }, - redirect: '/main/dashboard/default', + redirect: '/main/platforms', component: () => import('@/layouts/full/FullLayout.vue'), children: [ { - name: 'Dashboard', + name: 'MainPage', path: '/', - component: () => import('@/views/dashboards/default/DefaultDashboard.vue') + component: () => import('@/views/PlatformPage.vue') }, { name: 'Extensions', diff --git a/dashboard/src/views/ConfigPage.vue b/dashboard/src/views/ConfigPage.vue index ef022d9d7..dbf47f624 100644 --- a/dashboard/src/views/ConfigPage.vue +++ b/dashboard/src/views/ConfigPage.vue @@ -11,12 +11,6 @@ - @@ -37,38 +31,10 @@
-
- - - {{ metadata[key]['name'] }} - - - - - -
- - - -
-
-
- - -
- {{ tm('help.helpPrefix') }} - {{ tm('help.documentation') }} - {{ tm('help.helpMiddle') }} - {{ tm('help.support') }}{{ tm('help.helpSuffix') }} - -
- -
-
+ @@ -118,7 +84,7 @@ - AstrBot 支持针对不同消息平台实例分别设置配置文件。默认会使用 `default` 配置。 + AstrBot 支持针对不同机器人分别设置配置文件。默认会使用 `default` 配置。
新建配置文件 @@ -128,8 +94,6 @@ - 当前应用于: {{ formatUmop(config.umop) }} -