feat(i18n): localize panel shell

This commit is contained in:
youzini
2026-06-05 10:45:19 +00:00
parent 49860983a2
commit e06a3ca250
6 changed files with 485 additions and 153 deletions

View File

@@ -1,4 +1,5 @@
import { debugLog } from "../runtime/debug-logging.js";
import { setLocale, t } from "../i18n/index.js";
const MENU_ENTRY_RETRY_MS = 400;
const MENU_ENTRY_MAX_ATTEMPTS = 30;
@@ -9,10 +10,15 @@ function resolvePanelTheme(settings) {
return settings?.panelTheme || "crimson";
}
function syncBridgeLocale(runtime) {
setLocale(runtime.getSettings?.()?.uiLocale || "auto");
}
export function createNoticePanelActionController(runtime) {
syncBridgeLocale(runtime);
if (!runtime.getPanelModule()?.openPanel) return undefined;
return {
label: "打开面板",
label: t("panel.entry.openPanelAction"),
kind: "neutral",
onClick: () => {
runtime.getPanelModule()?.openPanel?.();
@@ -37,20 +43,39 @@ function bindOpenPanelClick(runtime, element) {
runtime.$?.("#extensionsMenu")?.hide?.();
} catch (error) {
runtime.console.error("[ST-BME] 点击菜单打开面板失败:", error);
globalThis.toastr?.error?.("记忆图谱面板加载失败,请查看控制台报错", "ST-BME");
globalThis.toastr?.error?.(t("panel.entry.openFailed"), "ST-BME");
}
});
}
function renderOptionsMenuEntry(menuItem) {
menuItem.innerHTML =
`<i class="fa-lg fa-solid fa-brain"></i><span>${t("panel.entry.menuLabel")}</span>`;
}
function renderExtensionsMenuEntry(menuItem) {
menuItem.innerHTML =
`<div class="fa-solid fa-brain extensionsMenuExtensionButton"></div><span>${t("panel.entry.menuLabel")}</span>`;
}
function renderFloatingBootstrap(fab) {
fab.innerHTML = `
<i class="fa-solid fa-brain bme-fab-icon"></i>
<span class="bme-fab-tooltip">${t("panel.entry.floatingTooltip")}</span>
`;
}
function injectOptionsMenuEntry(runtime) {
syncBridgeLocale(runtime);
const doc = runtime.document;
if (!doc || doc.getElementById(OPTIONS_MENU_ENTRY_ID)) {
const existing = doc?.getElementById(OPTIONS_MENU_ENTRY_ID);
if (existing) renderOptionsMenuEntry(existing);
return true;
}
const menuItem = doc.createElement("a");
menuItem.id = OPTIONS_MENU_ENTRY_ID;
menuItem.innerHTML =
'<i class="fa-lg fa-solid fa-brain"></i><span>记忆图谱</span>';
renderOptionsMenuEntry(menuItem);
bindOpenPanelClick(runtime, menuItem);
const anchor = doc.getElementById("option_toggle_logprobs");
@@ -68,6 +93,7 @@ function injectOptionsMenuEntry(runtime) {
}
function injectExtensionsMenuEntry(runtime) {
syncBridgeLocale(runtime);
const doc = runtime.document;
if (!doc) return false;
@@ -75,6 +101,7 @@ function injectExtensionsMenuEntry(runtime) {
const menu = doc.getElementById("extensionsMenu");
const button = doc.getElementById("extensionsMenuButton");
if (existing) {
renderExtensionsMenuEntry(existing);
if (button?.style) button.style.display = "flex";
runtime.$?.("#extensionsMenuButton")?.css?.("display", "flex");
return true;
@@ -84,8 +111,7 @@ function injectExtensionsMenuEntry(runtime) {
const menuItem = doc.createElement("div");
menuItem.id = EXTENSIONS_MENU_ENTRY_ID;
menuItem.className = "list-group-item flex-container flexGap5";
menuItem.innerHTML =
'<div class="fa-solid fa-brain extensionsMenuExtensionButton"></div><span>记忆图谱</span>';
renderExtensionsMenuEntry(menuItem);
bindOpenPanelClick(runtime, menuItem);
menu.appendChild(menuItem);
@@ -98,6 +124,7 @@ function injectExtensionsMenuEntry(runtime) {
}
function injectFloatingBootstrap(runtime) {
syncBridgeLocale(runtime);
const doc = runtime.document;
if (!doc) return false;
let fab = doc.getElementById("bme-floating-ball");
@@ -106,13 +133,15 @@ function injectFloatingBootstrap(runtime) {
fab.id = "bme-floating-ball";
fab.setAttribute("data-status", "idle");
fab.setAttribute("data-bme-bootstrap", "true");
fab.innerHTML = `
<i class="fa-solid fa-brain bme-fab-icon"></i>
<span class="bme-fab-tooltip">BME 记忆图谱</span>
`;
renderFloatingBootstrap(fab);
const mountTarget = doc.body || doc.documentElement;
if (!mountTarget) return false;
mountTarget.appendChild(fab);
} else if (!fab.querySelector?.(".bme-fab-icon")) {
renderFloatingBootstrap(fab);
} else {
const tip = fab.querySelector?.(".bme-fab-tooltip");
if (tip) tip.textContent = t("panel.entry.floatingTooltip");
}
if (fab.dataset.bmeBridgeBound === "true") {
return true;
@@ -124,7 +153,7 @@ function injectFloatingBootstrap(runtime) {
openPanelController(runtime);
} catch (error) {
runtime.console.error("[ST-BME] 点击悬浮球打开面板失败:", error);
globalThis.toastr?.error?.("记忆图谱面板加载失败,请查看控制台报错", "ST-BME");
globalThis.toastr?.error?.(t("panel.entry.openFailed"), "ST-BME");
}
});
return true;
@@ -198,6 +227,13 @@ async function ensurePanelBridgeReady(runtime) {
runtime.getThemesModule()?.applyTheme?.(nextTheme);
runtime.getPanelModule()?.updatePanelTheme?.(nextTheme);
}
if (Object.prototype.hasOwnProperty.call(patch || {}, "uiLocale")) {
syncBridgeLocale(runtime);
injectOptionsMenuEntry(runtime);
injectExtensionsMenuEntry(runtime);
injectFloatingBootstrap(runtime);
runtime.getPanelModule()?.updatePanelLocale?.(nextSettings.uiLocale || "auto");
}
return nextSettings;
},
actions: runtime.actions,

View File

@@ -3,7 +3,7 @@
<div class="bme-panel-header">
<div class="bme-panel-title">
<i class="fa-solid fa-brain"></i>
<span>ST-BME 记忆图谱</span>
<span data-i18n="panel.title">ST-BME 记忆图谱</span>
<span class="bme-panel-subtitle" id="bme-panel-status"
>SYSTEM_ACTIVE</span
>
@@ -12,6 +12,7 @@
class="bme-fab-toggle-btn"
id="bme-fab-toggle-btn"
title="显示/隐藏悬浮球"
data-i18n-title="panel.header.fabToggleTitle"
type="button"
>
<i class="fa-solid fa-circle-dot"></i>
@@ -21,6 +22,7 @@
class="bme-theme-picker-btn"
id="bme-theme-picker-btn"
title="切换主题"
data-i18n-title="panel.header.themePickerTitle"
type="button"
>
<i class="fa-solid fa-palette"></i>
@@ -28,27 +30,27 @@
<div class="bme-theme-dropdown" id="bme-theme-dropdown">
<button class="bme-theme-option" data-theme="crimson" type="button">
<span class="bme-theme-swatch" style="background: #e94560"></span
>赤红合成
><span data-i18n="theme.crimson">赤红合成</span>
</button>
<button class="bme-theme-option" data-theme="cyan" type="button">
<span class="bme-theme-swatch" style="background: #00e5ff"></span
>霓虹青蓝
><span data-i18n="theme.cyan">霓虹青蓝</span>
</button>
<button class="bme-theme-option" data-theme="amber" type="button">
<span class="bme-theme-swatch" style="background: #ffb300"></span
>琥珀终端
><span data-i18n="theme.amber">琥珀终端</span>
</button>
<button class="bme-theme-option" data-theme="violet" type="button">
<span class="bme-theme-swatch" style="background: #b388ff"></span
>紫雾迷离
><span data-i18n="theme.violet">紫雾迷离</span>
</button>
<button class="bme-theme-option" data-theme="paperDawn" type="button">
<span class="bme-theme-swatch" style="background: #0d9488"></span
>晨光纸感
><span data-i18n="theme.paperDawn">晨光纸感</span>
</button>
<button class="bme-theme-option" data-theme="glacierSky" type="button">
<span class="bme-theme-swatch" style="background: #2563eb"></span
>冰川晴空
><span data-i18n="theme.glacierSky">冰川晴空</span>
</button>
</div>
</div>
@@ -56,6 +58,7 @@
class="bme-panel-close"
id="bme-panel-close"
title="关闭"
data-i18n-title="common.close"
type="button"
>
<i class="fa-solid fa-xmark"></i>
@@ -67,27 +70,27 @@
<div class="bme-tab-list">
<button class="bme-tab-btn active" data-tab="dashboard" type="button">
<i class="fa-solid fa-chart-simple"></i>
<span>总览</span>
<span data-i18n="panel.tab.dashboard">总览</span>
</button>
<button class="bme-tab-btn" data-tab="task" type="button">
<i class="fa-solid fa-list-check"></i>
<span>任务</span>
<span data-i18n="panel.tab.tasks">任务</span>
</button>
<button class="bme-tab-btn" data-tab="actions" type="button">
<i class="fa-solid fa-gear"></i>
<span>操作</span>
<span data-i18n="panel.tab.actions">操作</span>
</button>
<button class="bme-tab-btn" data-tab="config" type="button">
<i class="fa-solid fa-sliders"></i>
<span>配置</span>
<span data-i18n="panel.tab.settings">配置</span>
</button>
</div>
<div class="bme-config-sidebar" id="bme-config-sidebar">
<div class="bme-config-sidebar-header">
<div class="bme-config-sidebar-kicker">配置工作区</div>
<div class="bme-config-sidebar-title">ST-BME 设置</div>
<div class="bme-config-sidebar-help">
<div class="bme-config-sidebar-kicker" data-i18n="panel.sidebar.configKicker">配置工作区</div>
<div class="bme-config-sidebar-title" data-i18n="panel.sidebar.configTitle">ST-BME 设置</div>
<div class="bme-config-sidebar-help" data-i18n="panel.sidebar.configHelp">
左侧切换配置页,右侧查看对应的完整设置表单。
</div>
</div>
@@ -98,7 +101,7 @@
type="button"
>
<i class="fa-solid fa-plug"></i>
<span>API 配置</span>
<span data-i18n="panel.configNav.api">API 配置</span>
</button>
<button
class="bme-config-nav-btn active"
@@ -106,7 +109,7 @@
type="button"
>
<i class="fa-solid fa-toggle-on"></i>
<span>功能开关</span>
<span data-i18n="panel.configNav.toggles">功能开关</span>
</button>
<button
class="bme-config-nav-btn"
@@ -114,7 +117,7 @@
type="button"
>
<i class="fa-solid fa-sliders"></i>
<span>详细参数</span>
<span data-i18n="panel.configNav.advanced">详细参数</span>
</button>
<button
class="bme-config-nav-btn"
@@ -122,7 +125,7 @@
type="button"
>
<i class="fa-solid fa-scroll"></i>
<span>任务预设</span>
<span data-i18n="panel.configNav.prompts">任务预设</span>
</button>
<button
class="bme-config-nav-btn"
@@ -130,7 +133,7 @@
type="button"
>
<i class="fa-solid fa-wand-magic-sparkles"></i>
<span>ENA 规划器</span>
<span data-i18n="panel.configNav.planner">ENA 规划器</span>
</button>
<button
class="bme-config-nav-btn"
@@ -138,7 +141,7 @@
type="button"
>
<i class="fa-solid fa-palette"></i>
<span>面板外观</span>
<span data-i18n="panel.configNav.appearance">面板外观</span>
</button>
<button
class="bme-config-nav-btn"
@@ -146,16 +149,16 @@
type="button"
>
<i class="fa-solid fa-broom"></i>
<span>数据清理</span>
<span data-i18n="panel.configNav.cleanup">数据清理</span>
</button>
</div>
</div>
<div class="bme-task-sidebar" id="bme-task-sidebar">
<div class="bme-task-sidebar-header">
<div class="bme-task-sidebar-kicker">任务监控</div>
<div class="bme-task-sidebar-title">ST-BME 任务流</div>
<div class="bme-task-sidebar-help">
<div class="bme-task-sidebar-kicker" data-i18n="panel.sidebar.taskKicker">任务监控</div>
<div class="bme-task-sidebar-title" data-i18n="panel.sidebar.taskTitle">ST-BME 任务流</div>
<div class="bme-task-sidebar-help" data-i18n="panel.sidebar.taskHelp">
左侧切换监控视图,右侧查看实时任务状态。
</div>
</div>
@@ -166,7 +169,7 @@
type="button"
>
<i class="fa-solid fa-gauge-high"></i>
<span>管线总览</span>
<span data-i18n="panel.taskNav.pipeline">管线总览</span>
</button>
<button
class="bme-task-nav-btn"
@@ -174,7 +177,7 @@
type="button"
>
<i class="fa-solid fa-timeline"></i>
<span>任务流水</span>
<span data-i18n="panel.taskNav.timeline">任务流水</span>
</button>
<button
class="bme-task-nav-btn"
@@ -182,7 +185,7 @@
type="button"
>
<i class="fa-solid fa-brain"></i>
<span>记忆浏览</span>
<span data-i18n="panel.taskNav.memory">记忆浏览</span>
</button>
<button
class="bme-task-nav-btn"
@@ -190,7 +193,7 @@
type="button"
>
<i class="fa-solid fa-syringe"></i>
<span>注入预览</span>
<span data-i18n="panel.taskNav.injection">注入预览</span>
</button>
<button
class="bme-task-nav-btn"
@@ -198,7 +201,7 @@
type="button"
>
<i class="fa-solid fa-route"></i>
<span>消息追踪</span>
<span data-i18n="panel.taskNav.trace">消息追踪</span>
</button>
<button
class="bme-task-nav-btn"
@@ -206,7 +209,7 @@
type="button"
>
<i class="fa-solid fa-database"></i>
<span>持久化</span>
<span data-i18n="panel.taskNav.persistence">持久化</span>
</button>
</div>
</div>
@@ -215,25 +218,25 @@
<div class="bme-tab-pane active" id="bme-pane-dashboard">
<div class="bme-stats-grid">
<div class="bme-stat-card">
<div class="bme-stat-label">活跃节点</div>
<div class="bme-stat-label" data-i18n="panel.dashboard.activeNodes">活跃节点</div>
<div class="bme-stat-value" id="bme-stat-nodes">0</div>
</div>
<div class="bme-stat-card">
<div class="bme-stat-label">边连接</div>
<div class="bme-stat-label" data-i18n="panel.dashboard.edgeCount">边连接</div>
<div class="bme-stat-value" id="bme-stat-edges">0</div>
</div>
<div class="bme-stat-card">
<div class="bme-stat-label">已归档</div>
<div class="bme-stat-label" data-i18n="panel.dashboard.archived">已归档</div>
<div class="bme-stat-value" id="bme-stat-archived">0</div>
</div>
<div class="bme-stat-card">
<div class="bme-stat-label">碎片率</div>
<div class="bme-stat-label" data-i18n="panel.dashboard.fragRate">碎片率</div>
<div class="bme-stat-value warning" id="bme-stat-frag">0%</div>
</div>
</div>
<div class="bme-config-card">
<div class="bme-section-header">运行状态</div>
<div class="bme-section-header" data-i18n="panel.dashboard.runStatus">运行状态</div>
<div class="bme-config-row">
<label>当前聊天</label>
<div class="bme-recent-meta" id="bme-status-chat-id"></div>
@@ -280,7 +283,7 @@
</div>
<div class="bme-config-card">
<div class="bme-section-header">认知 / 空间</div>
<div class="bme-section-header" data-i18n="panel.dashboard.cognitionSpace">认知 / 空间</div>
<div class="bme-config-row">
<label><i class="fa-solid fa-user" style="margin-right:4px;opacity:0.5"></i>当前场景锚点</label>
<div class="bme-recent-meta" id="bme-cognition-active-owner"></div>
@@ -303,14 +306,14 @@
type="button"
>
<i class="fa-solid fa-brain"></i>
<span>在认知视图中查看完整认知 →</span>
<span data-i18n="panel.dashboard.viewFullCognition">在认知视图中查看完整认知 →</span>
</button>
</div>
<div class="bme-section-header">最近提取</div>
<div class="bme-section-header" data-i18n="panel.dashboard.recentExtract">最近提取</div>
<ul class="bme-recent-list" id="bme-recent-extract"></ul>
<div class="bme-section-header">最近召回</div>
<div class="bme-section-header" data-i18n="panel.dashboard.recentRecall">最近召回</div>
<ul class="bme-recent-list" id="bme-recent-recall"></ul>
</div>
@@ -320,8 +323,8 @@
<!-- 记忆操作 -->
<div class="bme-action-group">
<div class="bme-action-group-header">
<span class="bme-action-group-title">记忆操作</span>
<span class="bme-action-group-sub">调用 LLM 处理记忆节点</span>
<span class="bme-action-group-title" data-i18n="panel.actions.memoryGroup">记忆操作</span>
<span class="bme-action-group-sub" data-i18n="panel.actions.memoryGroupSub">调用 LLM 处理记忆节点</span>
</div>
<div class="bme-action-grid">
<button class="bme-action-btn" id="bme-act-extract" type="button">
@@ -404,8 +407,8 @@
<!-- 向量操作 -->
<div class="bme-action-group">
<div class="bme-action-group-header">
<span class="bme-action-group-title">向量操作</span>
<span class="bme-action-group-sub">调用 Embedding API 计算节点向量</span>
<span class="bme-action-group-title" data-i18n="panel.actions.vectorGroup">向量操作</span>
<span class="bme-action-group-sub" data-i18n="panel.actions.vectorGroupSub">调用 Embedding API 计算节点向量</span>
</div>
<div class="bme-action-grid">
<button class="bme-action-btn" id="bme-act-vector-rebuild" type="button">
@@ -453,8 +456,8 @@
<!-- 图谱管理 -->
<div class="bme-action-group">
<div class="bme-action-group-header">
<span class="bme-action-group-title">图谱管理</span>
<span class="bme-action-group-sub">导入导出与危险操作</span>
<span class="bme-action-group-title" data-i18n="panel.actions.graphGroup">图谱管理</span>
<span class="bme-action-group-sub" data-i18n="panel.actions.graphGroupSub">导入导出与危险操作</span>
</div>
<div class="bme-action-grid">
<button class="bme-action-btn" id="bme-act-export" type="button">
@@ -474,8 +477,8 @@
<div class="bme-action-group" id="bme-luker-sidecar-group">
<div class="bme-action-group-header">
<span class="bme-action-group-title">持久化修复</span>
<span class="bme-action-group-sub">本地持久化与 Luker 主 sidecar 的统一修复区域</span>
<span class="bme-action-group-title" data-i18n="panel.actions.persistGroup">持久化修复</span>
<span class="bme-action-group-sub" data-i18n="panel.actions.persistGroupSub">本地持久化与 Luker 主 sidecar 的统一修复区域</span>
</div>
<div class="bme-action-grid">
<button class="bme-action-btn" id="bme-act-retry-persist" type="button">
@@ -512,10 +515,10 @@
<div class="bme-tab-pane" id="bme-pane-config">
<div class="bme-config-placeholder">
<div class="bme-config-placeholder-title">
<div class="bme-config-placeholder-title" data-i18n="panel.configPlaceholder.title">
配置已切换到右侧工作区
</div>
<div class="bme-config-placeholder-help">
<div class="bme-config-placeholder-help" data-i18n="panel.configPlaceholder.help">
左侧子导航负责切页,右侧显示完整的配置表单。
</div>
</div>
@@ -525,15 +528,15 @@
<div class="bme-graph-subtabs">
<button class="bme-graph-subtab active" data-mobile-graph-view="graph" type="button">
<i class="fa-solid fa-diagram-project"></i>
<span>实时图谱</span>
<span data-i18n="panel.graphView.realtime">实时图谱</span>
</button>
<button class="bme-graph-subtab" data-mobile-graph-view="cognition" type="button">
<i class="fa-solid fa-brain"></i>
<span>认知视图</span>
<span data-i18n="panel.graphView.cognition">认知视图</span>
</button>
<button class="bme-graph-subtab" data-mobile-graph-view="summary" type="button">
<i class="fa-solid fa-layer-group"></i>
<span>总结视图</span>
<span data-i18n="panel.graphView.summary">总结视图</span>
</button>
</div>
@@ -542,21 +545,21 @@
<div class="bme-mobile-canvas-wrap">
<canvas id="bme-mobile-graph-canvas"></canvas>
<div class="bme-graph-overlay" id="bme-mobile-graph-overlay" hidden>
<div class="bme-graph-overlay__text" id="bme-mobile-graph-overlay-text">
<div class="bme-graph-overlay__text" id="bme-mobile-graph-overlay-text" data-i18n="panel.graphOverlay.loading">
正在加载当前聊天图谱
</div>
</div>
<div class="bme-mobile-graph-float-controls">
<button id="bme-mobile-render-toggle" title="暂停图谱渲染" type="button">
<button id="bme-mobile-render-toggle" title="暂停图谱渲染" data-i18n-title="panel.graphToolbar.pauseTitle" type="button">
<i class="fa-solid fa-pause"></i>
</button>
<button id="bme-mobile-zoom-in" title="放大" type="button">
<button id="bme-mobile-zoom-in" title="放大" data-i18n-title="panel.graphToolbar.zoomInTitle" type="button">
<i class="fa-solid fa-plus"></i>
</button>
<button id="bme-mobile-zoom-out" title="缩小" type="button">
<button id="bme-mobile-zoom-out" title="缩小" data-i18n-title="panel.graphToolbar.zoomOutTitle" type="button">
<i class="fa-solid fa-minus"></i>
</button>
<button id="bme-mobile-zoom-reset" title="重置" type="button">
<button id="bme-mobile-zoom-reset" title="重置" data-i18n-title="panel.graphToolbar.resetTitle" type="button">
<i class="fa-solid fa-arrows-rotate"></i>
</button>
</div>
@@ -574,14 +577,14 @@
<div class="bme-cog-status-strip" id="bme-mobile-cog-status-strip"></div>
<div class="bme-cog-body">
<div class="bme-cog-column bme-cog-column--owners">
<div class="bme-cog-section-title">
<div class="bme-cog-section-title" data-i18n="panel.cognition.ownerList">
<i class="fa-solid fa-users"></i> 角色认知清单
</div>
<div class="bme-cog-owner-scroll" id="bme-mobile-cog-owner-list"></div>
<div class="bme-cog-owner-detail" id="bme-mobile-cog-owner-detail"></div>
</div>
<div class="bme-cog-column bme-cog-column--space">
<div class="bme-cog-section-title">
<div class="bme-cog-section-title" data-i18n="panel.cognition.spaceConsole">
<i class="fa-solid fa-map-location-dot"></i> 空间控制台
</div>
<div class="bme-cog-space-tools" id="bme-mobile-cog-space-tools"></div>
@@ -602,15 +605,15 @@
></div>
<div class="bme-node-detail" id="bme-mobile-node-detail">
<div class="bme-node-detail-header">
<h3 id="bme-mobile-detail-title">节点详情</h3>
<h3 id="bme-mobile-detail-title" data-i18n="panel.nodeDetail.title">节点详情</h3>
<div class="bme-node-detail-actions">
<button class="bme-detail-action-btn bme-detail-action-danger" id="bme-mobile-detail-delete" type="button" title="删除节点">
<button class="bme-detail-action-btn bme-detail-action-danger" id="bme-mobile-detail-delete" type="button" title="删除节点" data-i18n-title="panel.nodeDetail.delete">
<i class="fa-solid fa-trash"></i>
</button>
<button class="bme-detail-action-btn" id="bme-mobile-detail-save" type="button" title="保存修改">
<button class="bme-detail-action-btn" id="bme-mobile-detail-save" type="button" title="保存修改" data-i18n-title="panel.nodeDetail.save">
<i class="fa-solid fa-floppy-disk"></i>
</button>
<button class="bme-panel-close" id="bme-mobile-detail-close" type="button" title="关闭">
<button class="bme-panel-close" id="bme-mobile-detail-close" type="button" title="关闭" data-i18n-title="common.close">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
@@ -629,28 +632,28 @@
<div class="bme-graph-view-tabs">
<button class="bme-graph-view-tab active" data-graph-view="graph" type="button">
<i class="fa-solid fa-diagram-project"></i>
<span>实时图谱</span>
<span data-i18n="panel.graphView.realtime">实时图谱</span>
</button>
<button class="bme-graph-view-tab" data-graph-view="cognition" type="button">
<i class="fa-solid fa-brain"></i>
<span>认知视图</span>
<span data-i18n="panel.graphView.cognition">认知视图</span>
</button>
<button class="bme-graph-view-tab" data-graph-view="summary" type="button">
<i class="fa-solid fa-layer-group"></i>
<span>总结视图</span>
<span data-i18n="panel.graphView.summary">总结视图</span>
</button>
</div>
<div class="bme-graph-controls">
<button id="bme-graph-render-toggle" title="暂停图谱渲染" type="button">
<button id="bme-graph-render-toggle" title="暂停图谱渲染" data-i18n-title="panel.graphToolbar.pauseTitle" type="button">
<i class="fa-solid fa-pause"></i>
</button>
<button id="bme-graph-zoom-in" title="放大" type="button">
<button id="bme-graph-zoom-in" title="放大" data-i18n-title="panel.graphToolbar.zoomInTitle" type="button">
<i class="fa-solid fa-plus"></i>
</button>
<button id="bme-graph-zoom-out" title="缩小" type="button">
<button id="bme-graph-zoom-out" title="缩小" data-i18n-title="panel.graphToolbar.zoomOutTitle" type="button">
<i class="fa-solid fa-minus"></i>
</button>
<button id="bme-graph-reset" title="重置" type="button">
<button id="bme-graph-reset" title="重置" data-i18n-title="panel.graphToolbar.resetTitle" type="button">
<i class="fa-solid fa-arrows-rotate"></i>
</button>
</div>
@@ -658,7 +661,7 @@
<canvas id="bme-graph-canvas"></canvas>
<div class="bme-graph-overlay" id="bme-graph-overlay" hidden>
<div class="bme-graph-overlay__text" id="bme-graph-overlay-text">
<div class="bme-graph-overlay__text" id="bme-graph-overlay-text" data-i18n="panel.graphOverlay.loading">
正在加载当前聊天图谱
</div>
</div>
@@ -679,14 +682,14 @@
<div class="bme-cog-status-strip" id="bme-cog-status-strip"></div>
<div class="bme-cog-body">
<div class="bme-cog-column bme-cog-column--owners">
<div class="bme-cog-section-title">
<div class="bme-cog-section-title" data-i18n="panel.cognition.ownerList">
<i class="fa-solid fa-users"></i> 角色认知清单
</div>
<div class="bme-cog-owner-scroll" id="bme-cog-owner-list"></div>
<div class="bme-cog-owner-detail" id="bme-cog-owner-detail"></div>
</div>
<div class="bme-cog-column bme-cog-column--space">
<div class="bme-cog-section-title">
<div class="bme-cog-section-title" data-i18n="panel.cognition.spaceConsole">
<i class="fa-solid fa-map-location-dot"></i> 空间控制台
</div>
<div class="bme-cog-space-tools" id="bme-cog-space-tools"></div>
@@ -698,13 +701,14 @@
<div class="bme-node-detail" id="bme-node-detail">
<div class="bme-node-detail-header">
<h3 id="bme-detail-title">节点详情</h3>
<h3 id="bme-detail-title" data-i18n="panel.nodeDetail.title">节点详情</h3>
<div class="bme-node-detail-actions">
<button
class="bme-detail-action-btn bme-detail-action-danger"
id="bme-detail-delete"
type="button"
title="删除节点"
data-i18n-title="panel.nodeDetail.delete"
>
<i class="fa-solid fa-trash"></i>
</button>
@@ -713,6 +717,7 @@
id="bme-detail-save"
type="button"
title="保存修改"
data-i18n-title="panel.nodeDetail.save"
>
<i class="fa-solid fa-floppy-disk"></i>
</button>
@@ -721,6 +726,7 @@
id="bme-detail-close"
type="button"
title="关闭"
data-i18n-title="common.close"
>
<i class="fa-solid fa-xmark"></i>
</button>
@@ -733,9 +739,9 @@
<div class="bme-config-workspace" id="bme-config-workspace">
<div class="bme-config-workspace-header">
<div>
<div class="bme-config-workspace-kicker">配置</div>
<h2 class="bme-config-workspace-title">ST-BME 配置工作区</h2>
<p class="bme-config-workspace-desc">
<div class="bme-config-workspace-kicker" data-i18n="panel.configWorkspace.kicker">配置</div>
<h2 class="bme-config-workspace-title" data-i18n="panel.configWorkspace.title">ST-BME 配置工作区</h2>
<p class="bme-config-workspace-desc" data-i18n="panel.configWorkspace.desc">
在这里集中配置第二记忆模型、功能开关、细粒度参数、任务预设和面板主题。
</p>
</div>
@@ -749,7 +755,7 @@
type="button"
>
<i class="fa-solid fa-plug"></i>
<span>API 配置</span>
<span data-i18n="panel.configNav.api">API 配置</span>
</button>
<button
class="bme-config-nav-btn active"
@@ -757,7 +763,7 @@
type="button"
>
<i class="fa-solid fa-toggle-on"></i>
<span>功能开关</span>
<span data-i18n="panel.configNav.toggles">功能开关</span>
</button>
<button
class="bme-config-nav-btn"
@@ -765,7 +771,7 @@
type="button"
>
<i class="fa-solid fa-sliders"></i>
<span>详细参数</span>
<span data-i18n="panel.configNav.advanced">详细参数</span>
</button>
<button
class="bme-config-nav-btn"
@@ -773,7 +779,7 @@
type="button"
>
<i class="fa-solid fa-scroll"></i>
<span>任务预设</span>
<span data-i18n="panel.configNav.prompts">任务预设</span>
</button>
<button
class="bme-config-nav-btn"
@@ -781,7 +787,7 @@
type="button"
>
<i class="fa-solid fa-wand-magic-sparkles"></i>
<span>ENA 规划器</span>
<span data-i18n="panel.configNav.planner">ENA 规划器</span>
</button>
<button
class="bme-config-nav-btn"
@@ -789,7 +795,7 @@
type="button"
>
<i class="fa-solid fa-palette"></i>
<span>面板外观</span>
<span data-i18n="panel.configNav.appearance">面板外观</span>
</button>
<button
class="bme-config-nav-btn"
@@ -797,7 +803,7 @@
type="button"
>
<i class="fa-solid fa-broom"></i>
<span>数据清理</span>
<span data-i18n="panel.configNav.cleanup">数据清理</span>
</button>
</div>
@@ -807,9 +813,9 @@
data-config-section="api"
>
<div class="bme-config-section-head">
<div class="bme-config-section-kicker">API 配置</div>
<h3 class="bme-config-section-title">模型连接与向量接入</h3>
<p class="bme-config-section-desc">
<div class="bme-config-section-kicker" data-i18n="panel.configSection.apiKicker">API 配置</div>
<h3 class="bme-config-section-title" data-i18n="panel.configSection.apiTitle">模型连接与向量接入</h3>
<p class="bme-config-section-desc" data-i18n="panel.configSection.apiDesc">
统一管理独立记忆 LLM 和 Embedding
的连接方式,保留现有后端代理与直连兜底逻辑。
</p>
@@ -1129,9 +1135,9 @@
<section class="bme-config-section active" data-config-section="toggles">
<div class="bme-config-section-head">
<div class="bme-config-section-kicker">功能开关</div>
<h3 class="bme-config-section-title">主链路与增强能力</h3>
<p class="bme-config-section-desc">
<div class="bme-config-section-kicker" data-i18n="panel.configSection.togglesKicker">功能开关</div>
<h3 class="bme-config-section-title" data-i18n="panel.configSection.togglesTitle">主链路与增强能力</h3>
<p class="bme-config-section-desc" data-i18n="panel.configSection.togglesDesc">
先决定哪些能力参与记忆链路,再到详细参数里微调各模块行为。
</p>
</div>
@@ -1735,9 +1741,9 @@
<section class="bme-config-section" data-config-section="advanced">
<div class="bme-config-section-head">
<div class="bme-config-section-kicker">详细参数</div>
<h3 class="bme-config-section-title">细粒度行为与评分策略</h3>
<p class="bme-config-section-desc">
<div class="bme-config-section-kicker" data-i18n="panel.configSection.advancedKicker">详细参数</div>
<h3 class="bme-config-section-title" data-i18n="panel.configSection.advancedTitle">细粒度行为与评分策略</h3>
<p class="bme-config-section-desc" data-i18n="panel.configSection.advancedDesc">
这里承接旧设置页里的高级项。若对应功能关闭,参数会置灰并提示先到“功能开关”启用。
</p>
</div>
@@ -2893,9 +2899,9 @@
<section class="bme-config-section" data-config-section="prompts">
<div class="bme-config-section-head">
<div class="bme-config-section-kicker">任务预设</div>
<h3 class="bme-config-section-title">任务预设工作区</h3>
<p class="bme-config-section-desc">
<div class="bme-config-section-kicker" data-i18n="panel.configSection.promptsKicker">任务预设</div>
<h3 class="bme-config-section-title" data-i18n="panel.configSection.promptsTitle">任务预设工作区</h3>
<p class="bme-config-section-desc" data-i18n="panel.configSection.promptsDesc">
在这里为每个任务维护独立预设,统一配置 prompt 编排、生成参数和正则规则。
</p>
</div>
@@ -2916,9 +2922,9 @@
<section class="bme-config-section" data-config-section="planner">
<div class="bme-config-section-head">
<div class="bme-config-section-kicker">ENA 规划器</div>
<h3 class="bme-config-section-title">剧情规划 · LLM 接入</h3>
<p class="bme-config-section-desc">
<div class="bme-config-section-kicker" data-i18n="panel.configSection.plannerKicker">ENA 规划器</div>
<h3 class="bme-config-section-title" data-i18n="panel.configSection.plannerTitle">剧情规划 · LLM 接入</h3>
<p class="bme-config-section-desc" data-i18n="panel.configSection.plannerDesc">
发送前自动拦截并调用规划 LLM从角色卡、世界书、BME 记忆、历史 plot 中收集上下文,生成
<code>&lt;plot&gt;</code><code>&lt;note&gt;</code> 追加到你的输入。
</p>
@@ -3219,9 +3225,9 @@
data-config-section="appearance"
>
<div class="bme-config-section-head">
<div class="bme-config-section-kicker">面板外观</div>
<h3 class="bme-config-section-title">主题与视觉同步</h3>
<p class="bme-config-section-desc">
<div class="bme-config-section-kicker" data-i18n="panel.configSection.appearanceKicker">面板外观</div>
<h3 class="bme-config-section-title" data-i18n="panel.configSection.appearanceTitle">主题与视觉同步</h3>
<p class="bme-config-section-desc" data-i18n="panel.configSection.appearanceDesc">
这里的主题选择会和顶部调色盘快捷入口保持同步,并立即刷新图谱配色。
</p>
</div>
@@ -3246,8 +3252,8 @@
style="background: #e94560"
></span>
<span class="bme-theme-card-copy">
<span class="bme-theme-card-title">赤红合成</span>
<span class="bme-theme-card-desc"
<span class="bme-theme-card-title" data-i18n="theme.crimson">赤红合成</span>
<span class="bme-theme-card-desc" data-i18n="theme.crimson.desc"
>高对比、强调变化和警示感。</span
>
</span>
@@ -3265,8 +3271,8 @@
style="background: #00e5ff"
></span>
<span class="bme-theme-card-copy">
<span class="bme-theme-card-title">霓虹青蓝</span>
<span class="bme-theme-card-desc"
<span class="bme-theme-card-title" data-i18n="theme.cyan">霓虹青蓝</span>
<span class="bme-theme-card-desc" data-i18n="theme.cyan.desc"
>更冷静的检视感,适合长时间排查。</span
>
</span>
@@ -3284,8 +3290,8 @@
style="background: #ffb300"
></span>
<span class="bme-theme-card-copy">
<span class="bme-theme-card-title">琥珀终端</span>
<span class="bme-theme-card-desc"
<span class="bme-theme-card-title" data-i18n="theme.amber">琥珀终端</span>
<span class="bme-theme-card-desc" data-i18n="theme.amber.desc"
>更像复古终端,阅读层次稳定。</span
>
</span>
@@ -3303,8 +3309,8 @@
style="background: #b388ff"
></span>
<span class="bme-theme-card-copy">
<span class="bme-theme-card-title">紫雾迷离</span>
<span class="bme-theme-card-desc"
<span class="bme-theme-card-title" data-i18n="theme.violet">紫雾迷离</span>
<span class="bme-theme-card-desc" data-i18n="theme.violet.desc"
>更柔和的夜间质感,适合沉浸式浏览。</span
>
</span>
@@ -3322,8 +3328,8 @@
style="background: #0d9488"
></span>
<span class="bme-theme-card-copy">
<span class="bme-theme-card-title">晨光纸感</span>
<span class="bme-theme-card-desc"
<span class="bme-theme-card-title" data-i18n="theme.paperDawn">晨光纸感</span>
<span class="bme-theme-card-desc" data-i18n="theme.paperDawn.desc"
>亮色暖纸面,青绿主色与琥珀强调,白天阅读友好。</span
>
</span>
@@ -3341,8 +3347,8 @@
style="background: #2563eb"
></span>
<span class="bme-theme-card-copy">
<span class="bme-theme-card-title">冰川晴空</span>
<span class="bme-theme-card-desc"
<span class="bme-theme-card-title" data-i18n="theme.glacierSky">冰川晴空</span>
<span class="bme-theme-card-desc" data-i18n="theme.glacierSky.desc"
>亮色冷灰底与饱和蓝,适合与系统浅色界面同屏。</span
>
</span>
@@ -3359,9 +3365,9 @@
data-config-section="cleanup"
>
<div class="bme-config-section-head">
<div class="bme-config-section-kicker">数据清理</div>
<h3 class="bme-config-section-title">图谱、缓存与存储清理</h3>
<p class="bme-config-section-desc">
<div class="bme-config-section-kicker" data-i18n="panel.configSection.cleanupKicker">数据清理</div>
<h3 class="bme-config-section-title" data-i18n="panel.configSection.cleanupTitle">图谱、缓存与存储清理</h3>
<p class="bme-config-section-desc" data-i18n="panel.configSection.cleanupDesc">
在这里执行高危清理操作。所有操作均需二次确认,部分操作不可撤销。
</p>
</div>
@@ -3522,21 +3528,21 @@
<div class="bme-task-workspace" id="bme-task-workspace">
<div class="bme-task-workspace-header">
<div>
<div class="bme-task-workspace-kicker" id="bme-task-ws-kicker">任务监控</div>
<h2 class="bme-task-workspace-title" id="bme-task-ws-title">ST-BME 任务流工作区</h2>
<p class="bme-task-workspace-desc" id="bme-task-ws-desc">
<div class="bme-task-workspace-kicker" id="bme-task-ws-kicker" data-i18n="panel.taskWorkspace.kicker">任务监控</div>
<h2 class="bme-task-workspace-title" id="bme-task-ws-title" data-i18n="panel.taskWorkspace.title">ST-BME 任务流工作区</h2>
<p class="bme-task-workspace-desc" id="bme-task-ws-desc" data-i18n="panel.taskWorkspace.desc">
实时查看所有任务管线的运行状态与当前批次进度。
</p>
</div>
</div>
<div class="bme-task-nav-mobile" id="bme-task-nav-mobile">
<button class="bme-task-nav-pill active" data-task-section="pipeline" type="button">管线</button>
<button class="bme-task-nav-pill" data-task-section="timeline" type="button">流水</button>
<button class="bme-task-nav-pill" data-task-section="memory" type="button">记忆</button>
<button class="bme-task-nav-pill" data-task-section="injection" type="button">注入</button>
<button class="bme-task-nav-pill" data-task-section="trace" type="button">追踪</button>
<button class="bme-task-nav-pill" data-task-section="persistence" type="button">持久化</button>
<button class="bme-task-nav-pill active" data-task-section="pipeline" type="button" data-i18n="panel.mobileNav.pipeline">管线</button>
<button class="bme-task-nav-pill" data-task-section="timeline" type="button" data-i18n="panel.mobileNav.timeline">流水</button>
<button class="bme-task-nav-pill" data-task-section="memory" type="button" data-i18n="panel.mobileNav.memory">记忆</button>
<button class="bme-task-nav-pill" data-task-section="injection" type="button" data-i18n="panel.mobileNav.injection">注入</button>
<button class="bme-task-nav-pill" data-task-section="trace" type="button" data-i18n="panel.mobileNav.trace">追踪</button>
<button class="bme-task-nav-pill" data-task-section="persistence" type="button" data-i18n="panel.mobileNav.persistence">持久化</button>
</div>
<div class="bme-task-workspace-body">
@@ -3551,15 +3557,15 @@
<div class="bme-memory-popup-scrim" id="bme-memory-popup-scrim" hidden></div>
<div class="bme-memory-popup" id="bme-memory-popup">
<div class="bme-memory-popup__header">
<h3 class="bme-memory-popup__title" id="bme-memory-popup-title">节点详情</h3>
<h3 class="bme-memory-popup__title" id="bme-memory-popup-title" data-i18n="panel.memoryPopup.title">节点详情</h3>
<div class="bme-memory-popup__actions">
<button class="bme-detail-action-btn" id="bme-memory-popup-save" type="button" title="保存修改">
<button class="bme-detail-action-btn" id="bme-memory-popup-save" type="button" title="保存修改" data-i18n-title="panel.nodeDetail.save">
<i class="fa-solid fa-floppy-disk"></i>
</button>
<button class="bme-detail-action-btn bme-detail-action-danger" id="bme-memory-popup-delete" type="button" title="删除节点">
<button class="bme-detail-action-btn bme-detail-action-danger" id="bme-memory-popup-delete" type="button" title="删除节点" data-i18n-title="panel.nodeDetail.delete">
<i class="fa-solid fa-trash"></i>
</button>
<button class="bme-panel-close" id="bme-memory-popup-close" type="button" title="关闭">
<button class="bme-panel-close" id="bme-memory-popup-close" type="button" title="关闭" data-i18n-title="common.close">
<i class="fa-solid fa-xmark"></i>
</button>
</div>
@@ -3580,23 +3586,23 @@
<div class="bme-panel-tabbar">
<button class="bme-tab-btn" data-tab="graph" type="button">
<i class="fa-solid fa-diagram-project"></i>
<span>图谱</span>
<span data-i18n="panel.tab.graph">图谱</span>
</button>
<button class="bme-tab-btn active" data-tab="dashboard" type="button">
<i class="fa-solid fa-chart-simple"></i>
<span>总览</span>
<span data-i18n="panel.tab.dashboard">总览</span>
</button>
<button class="bme-tab-btn" data-tab="task" type="button">
<i class="fa-solid fa-list-check"></i>
<span>任务</span>
<span data-i18n="panel.tab.tasks">任务</span>
</button>
<button class="bme-tab-btn" data-tab="actions" type="button">
<i class="fa-solid fa-gear"></i>
<span>操作</span>
<span data-i18n="panel.tab.actions">操作</span>
</button>
<button class="bme-tab-btn" data-tab="config" type="button">
<i class="fa-solid fa-sliders"></i>
<span>配置</span>
<span data-i18n="panel.tab.settings">配置</span>
</button>
</div>
</div>
@@ -3605,16 +3611,16 @@
<div class="bme-fullscreen-graph-toolbar">
<div class="bme-graph-toolbar-title">
<i class="fa-solid fa-diagram-project"></i>
<span>实时图谱(全屏)</span>
<span data-i18n="panel.fullscreenGraph.title">实时图谱(全屏)</span>
</div>
<div class="bme-fullscreen-graph-controls">
<button id="bme-fs-zoom-in" title="放大" type="button">
<button id="bme-fs-zoom-in" title="放大" data-i18n-title="panel.fsToolbar.zoomInTitle" type="button">
<i class="fa-solid fa-plus"></i>
</button>
<button id="bme-fs-zoom-out" title="缩小" type="button">
<button id="bme-fs-zoom-out" title="缩小" data-i18n-title="panel.fsToolbar.zoomOutTitle" type="button">
<i class="fa-solid fa-minus"></i>
</button>
<button id="bme-fs-close" title="关闭" type="button">
<button id="bme-fs-close" title="关闭" data-i18n-title="panel.fsToolbar.closeTitle" type="button">
<i class="fa-solid fa-xmark"></i>
</button>
</div>

View File

@@ -65,9 +65,21 @@ import {
getMaintenanceExecutionModeLevel,
normalizeMaintenanceExecutionMode,
} from "../runtime/concurrency.js";
import {
hydrateI18n,
setLocale,
t,
} from "../i18n/index.js";
let defaultPromptCache = null;
function _applyPanelLocale(settings = _getSettings?.() || {}) {
setLocale(settings?.uiLocale || "auto");
if (overlayEl) hydrateI18n(overlayEl);
else hydrateI18n(document);
_refreshFloatingBallTooltip();
}
function _refreshMemoryLlmProviderHelp(urlValue = null) {
const helpEl = document.getElementById("bme-memory-llm-provider-help");
if (!helpEl) return;
@@ -1210,6 +1222,8 @@ export async function initPanel({
}
}
_applyPanelLocale(_getSettings?.() || {});
ensureOverlayMountedAtRoot();
bindViewportSync();
syncViewportCssVars();
@@ -1236,12 +1250,23 @@ export async function initPanel({
_bindFabToggle();
}
export function updatePanelLocale(localeMode = "auto") {
_applyPanelLocale({ ...(_getSettings?.() || {}), uiLocale: localeMode });
_refreshRuntimeStatus();
_syncFloatingBallWithRuntimeStatus();
}
// ==================== 悬浮球 ====================
const FAB_STORAGE_KEY = "bme-fab-position";
const FAB_VISIBLE_KEY = "bme-fab-visible";
let _fabEl = null;
function _refreshFloatingBallTooltip() {
const tip = _fabEl?.querySelector?.(".bme-fab-tooltip");
if (tip) tip.textContent = t("panel.entry.floatingTooltip");
}
function _getFabVisible() {
try {
const val = localStorage.getItem(FAB_VISIBLE_KEY);
@@ -1280,15 +1305,16 @@ function _initFloatingBall() {
fab.setAttribute("data-status", "idle");
fab.innerHTML = `
<i class="fa-solid fa-brain bme-fab-icon"></i>
<span class="bme-fab-tooltip">BME 记忆图谱</span>
<span class="bme-fab-tooltip">${t("panel.entry.floatingTooltip")}</span>
`;
} else if (!fab.querySelector(".bme-fab-icon")) {
fab.innerHTML = `
<i class="fa-solid fa-brain bme-fab-icon"></i>
<span class="bme-fab-tooltip">BME 记忆图谱</span>
<span class="bme-fab-tooltip">${t("panel.entry.floatingTooltip")}</span>
`;
}
_fabEl = fab;
_refreshFloatingBallTooltip();
ensureFabMountedAtRoot();
// 应用可见性
@@ -14293,7 +14319,7 @@ function _syncFloatingBallWithRuntimeStatus() {
const status = _getRuntimeStatus?.() || {};
const level = String(status.level || "idle");
const fabStatus = level === "info" ? "idle" : level;
updateFloatingBallStatus(fabStatus, status.text || "BME 记忆图谱");
updateFloatingBallStatus(fabStatus, status.text || t("panel.entry.floatingTooltip"));
}
function _patchSettings(patch = {}, options = {}) {
@@ -14303,6 +14329,10 @@ function _patchSettings(patch = {}, options = {}) {
if (options.refreshTaskWorkspace) _refreshTaskProfileWorkspace(settings);
if (options.refreshTheme)
_highlightThemeChoice(settings.panelTheme || "crimson");
if (Object.prototype.hasOwnProperty.call(patch || {}, "uiLocale")) {
_applyPanelLocale(settings);
_refreshRuntimeStatus();
}
_refreshCloudStorageModeUi(settings);
_refreshNativeRolloutStatusUi(settings);
return settings;