local-knowledge-graph 1.5.0 → 1.6.1
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.
- package/HELP.md +7 -0
- package/package.json +1 -1
- package/public/app.js +47 -2
- package/public/style.css +117 -5
package/HELP.md
CHANGED
|
@@ -72,6 +72,7 @@ kg
|
|
|
72
72
|
- **语义检索**:配置硅基流动 API Key 后支持语义+关键词混合检索(未配置时自动退化为关键词模式)
|
|
73
73
|
- **最短路径 / 中心子图 / 推理**:挖掘实体间关联链路、层级范围与隐性关系
|
|
74
74
|
- **撤销**:Ctrl+Z 或按钮,可连续撤销
|
|
75
|
+
- **浅色主题**:视图设置 → 界面主题 → 浅色,整站配色与 3D 画布同步切换,选择本地记忆
|
|
75
76
|
- **保存点与回溯**:版本页签打保存点,随时回滚;每次保存点自动滚动备份到 `data/backups/`
|
|
76
77
|
- **图片绑定**:实体信息卡上传本地图片
|
|
77
78
|
- **导出**:RDF(Turtle)、整库 .db、单文件只读网页版
|
|
@@ -96,11 +97,17 @@ kg
|
|
|
96
97
|
**Q:数据会上传到云端吗?**
|
|
97
98
|
图谱数据只存在本机。仅当你在"检索"页签配置了语义检索 API Key 时,检索向量化的文本片段才会发往你配置的模型服务;OpenCode 补全公开知识时按其自身机制联网。其余全部本地完成。
|
|
98
99
|
|
|
100
|
+
**Q:GitHub 仓库和 npm 包版本如何保持一致?**
|
|
101
|
+
仓库内置 GitHub Actions(`.github/workflows/publish.yml`):只要推送 `v*` 格式的标签,流水线会自动校验"标签版本 = package.json 版本"→ 跑全部测试 → 发布 npm → 创建 GitHub Release。即:改 package.json 版本 → 提交 → 打同名 tag → push,两端自动同步,人工只需打一次标签。
|
|
102
|
+
|
|
99
103
|
**Q:如何回滚某次误操作?**
|
|
100
104
|
优先用「撤销」(可连续);需要回到更早状态时在"版本"页签回溯到对应保存点。
|
|
101
105
|
|
|
102
106
|
## 版本历史摘要
|
|
103
107
|
|
|
108
|
+
- **v1.6.1**:修复浅色主题切换导致画布空白的问题;标题栏按钮防挤压(窄屏可横滑);修复3D样式主题刷新后不恢复的问题;新增脚本异常提示
|
|
109
|
+
- **v1.6.0**:界面主题新增浅色配色(视图设置一键切换,本地记忆);GitHub 仓库与 npm 包通过 Actions 自动同步(打 tag 即测试+发布+Release)
|
|
110
|
+
|
|
104
111
|
- **v1.5.0**:npm 包化(`npm i -g local-knowledge-graph` + `kg` 一键安装启动);数据目录迁至用户目录(升级无损);应用内更新支持 npm 与 git 双模式
|
|
105
112
|
|
|
106
113
|
- **v1.4.0**:设置与帮助面板内置版本号、检查更新、一键更新;项目目录新增本帮助文档
|
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -111,6 +111,35 @@ function makeRingSprite(cssColor, isCenter) {
|
|
|
111
111
|
return sprite;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
+
/* ================= 界面主题(深色/浅色,独立于3D样式主题) ================= */
|
|
115
|
+
const UI_THEME_KEY = 'kg_ui_theme_v1';
|
|
116
|
+
const UI_THEMES = {
|
|
117
|
+
dark: { grid1: 0x1c2a47, grid2: 0x141e35 },
|
|
118
|
+
light: { grid1: 0xb7c6dd, grid2: 0xcdd9ea },
|
|
119
|
+
};
|
|
120
|
+
let UI_THEME = 'dark';
|
|
121
|
+
try { if (localStorage.getItem(UI_THEME_KEY) === 'light') UI_THEME = 'light'; } catch (_) {}
|
|
122
|
+
document.documentElement.dataset.theme = UI_THEME;
|
|
123
|
+
|
|
124
|
+
function applyUiTheme(mode) {
|
|
125
|
+
UI_THEME = UI_THEMES[mode] ? mode : 'dark';
|
|
126
|
+
document.documentElement.dataset.theme = UI_THEME;
|
|
127
|
+
try { localStorage.setItem(UI_THEME_KEY, UI_THEME); } catch (_) {}
|
|
128
|
+
if (typeof scene !== 'undefined' && typeof grid !== 'undefined' && grid) {
|
|
129
|
+
const t = UI_THEMES[UI_THEME];
|
|
130
|
+
scene.remove(grid);
|
|
131
|
+
if (typeof grid.dispose === 'function') grid.dispose(); // three r128 GridHelper 无 dispose
|
|
132
|
+
grid = new THREE.GridHelper(480, 48, t.grid1, t.grid2);
|
|
133
|
+
grid.position.y = -60;
|
|
134
|
+
scene.add(grid);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/* 启动期兜底:任何未捕获异常立刻弹出提示,避免画布空白却无感知 */
|
|
139
|
+
window.addEventListener('error', (e) => {
|
|
140
|
+
try { toast('脚本异常: ' + (e.message || '未知错误'), 6000); } catch (_) {}
|
|
141
|
+
});
|
|
142
|
+
|
|
114
143
|
/* ================= Three.js 场景 ================= */
|
|
115
144
|
const wrap = $('canvas-wrap');
|
|
116
145
|
const scene = new THREE.Scene();
|
|
@@ -129,9 +158,13 @@ scene.add(new THREE.AmbientLight(0xffffff, 0.55));
|
|
|
129
158
|
const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
|
|
130
159
|
dirLight.position.set(120, 200, 100);
|
|
131
160
|
scene.add(dirLight);
|
|
132
|
-
|
|
161
|
+
let grid = new THREE.GridHelper(480, 48, 0x1c2a47, 0x141e35);
|
|
133
162
|
grid.position.y = -60;
|
|
134
163
|
scene.add(grid);
|
|
164
|
+
applyUiTheme(UI_THEME); // 按存储的主题重建网格(CSS背景经 data-theme 生效)
|
|
165
|
+
|
|
166
|
+
const savedTheme = loadTheme();
|
|
167
|
+
if (savedTheme && applyTheme(savedTheme)) { /* 启动时恢复用户保存的3D样式主题 */ }
|
|
135
168
|
|
|
136
169
|
let nodeGroup = new THREE.Group();
|
|
137
170
|
let linkGroup = new THREE.Group();
|
|
@@ -1292,6 +1325,13 @@ function renderStylePanel() {
|
|
|
1292
1325
|
</div>`).join('');
|
|
1293
1326
|
p.innerHTML = `
|
|
1294
1327
|
<h4>视图设置<span id="style-close" title="关闭">x</span></h4>
|
|
1328
|
+
<div class="style-sec">界面主题</div>
|
|
1329
|
+
<div class="style-row"><span class="sname">配色</span>
|
|
1330
|
+
<select id="ui-theme-select" style="flex:1">
|
|
1331
|
+
<option value="dark">深色(默认)</option>
|
|
1332
|
+
<option value="light">浅色</option>
|
|
1333
|
+
</select>
|
|
1334
|
+
</div>
|
|
1295
1335
|
<div class="style-sec">实体 · 颜色 / 大小倍率</div>${entRows}
|
|
1296
1336
|
<div class="style-sec">关系 · 颜色 / 虚线 / 段长 / 间隔 / 不透明度</div>${relRows}
|
|
1297
1337
|
<div class="row">
|
|
@@ -1300,8 +1340,13 @@ function renderStylePanel() {
|
|
|
1300
1340
|
</div>
|
|
1301
1341
|
<div class="hint-text">修改即时生效并应用于3D画布与图例;「保存主题」写入浏览器本地存储。受WebGL限制线宽恒为1px,虚线可通过段长/间隔调节密度。</div>`;
|
|
1302
1342
|
$('style-close').addEventListener('click', () => $('style-panel').classList.remove('show'));
|
|
1343
|
+
const themeSel = $('ui-theme-select');
|
|
1344
|
+
themeSel.value = UI_THEME;
|
|
1345
|
+
themeSel.addEventListener('change', () => { applyUiTheme(themeSel.value); toast(themeSel.value === 'light' ? '已切换浅色主题' : '已切换深色主题'); });
|
|
1303
1346
|
$('style-save').addEventListener('click', () => {
|
|
1304
|
-
|
|
1347
|
+
const t = currentThemeJson();
|
|
1348
|
+
localStorage.setItem(THEME_KEY, JSON.stringify(t));
|
|
1349
|
+
applyTheme(t);
|
|
1305
1350
|
toast('主题已保存到本地');
|
|
1306
1351
|
});
|
|
1307
1352
|
$('style-reset').addEventListener('click', () => {
|
package/public/style.css
CHANGED
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
height: 50px; display: flex; align-items: center; gap: 10px; padding: 0 14px;
|
|
13
13
|
background: #101728; border-bottom: 1px solid #1e2a44; flex-shrink: 0;
|
|
14
14
|
}
|
|
15
|
-
header h1 { font-size: 15px; font-weight: 600; color: #7fd1ff; letter-spacing: 1px; }
|
|
15
|
+
header h1 { font-size: 15px; font-weight: 600; color: #7fd1ff; letter-spacing: 1px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
16
16
|
header .spacer { flex: 1; }
|
|
17
17
|
header .badge { font-size: 11px; color: #8fa3c0; border: 1px solid #2a3a5c; border-radius: 10px; padding: 2px 9px; }
|
|
18
|
+
header button, header .badge { flex-shrink: 0; }
|
|
18
19
|
header .badge.ok { color: #7ee787; border-color: #2ea04366; }
|
|
19
20
|
header .badge.off { color: #f0883e; border-color: #f0883e66; }
|
|
20
21
|
|
|
@@ -277,13 +278,15 @@
|
|
|
277
278
|
/* 主题设置移动端可达:按钮保留,面板收窄为屏幕内浮层 */
|
|
278
279
|
#style-panel { max-width: calc(100vw - 16px); width: 288px; top: 8px; right: 8px; }
|
|
279
280
|
|
|
280
|
-
/*
|
|
281
|
+
/* 隐藏大标题,所有功能按钮单行排布,最大化画布显示范围;
|
|
282
|
+
按钮过多时允许横向滑动兜底(360px以下窄屏),滚动条隐藏 */
|
|
281
283
|
header {
|
|
282
|
-
flex-wrap: nowrap; height: 44px; padding: 0 6px; gap:
|
|
283
|
-
overflow: hidden;
|
|
284
|
+
flex-wrap: nowrap; height: 44px; padding: 0 6px; gap: 3px;
|
|
285
|
+
overflow-x: auto; overflow-y: hidden; scrollbar-width: none;
|
|
284
286
|
}
|
|
287
|
+
header::-webkit-scrollbar { display: none; }
|
|
285
288
|
header h1 { display: none; }
|
|
286
|
-
header button { padding: 5px
|
|
289
|
+
header button { padding: 5px 6px; font-size: 11px; flex-shrink: 0; min-width: 0; }
|
|
287
290
|
#btn-export { display: none; } /* 导出RDF移入文件菜单 */
|
|
288
291
|
#stat-badge, #agent-badge { display: none; }
|
|
289
292
|
|
|
@@ -372,3 +375,112 @@
|
|
|
372
375
|
@media (max-width: 768px) {
|
|
373
376
|
#help-panel { width: calc(100vw - 24px); right: 12px; }
|
|
374
377
|
}
|
|
378
|
+
|
|
379
|
+
/* ================= 浅色主题(html[data-theme="light"]) ================= */
|
|
380
|
+
html[data-theme="light"] body { background: #f2f6fc; color: #22304c; }
|
|
381
|
+
html[data-theme="light"] header { background: #ffffff; border-bottom-color: #dfe7f2; }
|
|
382
|
+
html[data-theme="light"] header h1 { color: #0b66c3; }
|
|
383
|
+
html[data-theme="light"] header .badge { color: #5a6c8c; border-color: #c9d6ea; }
|
|
384
|
+
html[data-theme="light"] header .badge.ok { color: #1a7f42; border-color: #8fd4a866; }
|
|
385
|
+
html[data-theme="light"] header .badge.off { color: #b25f0a; border-color: #e8b47866; }
|
|
386
|
+
html[data-theme="light"] button { background: #eaf1fb; color: #1f3f6e; border-color: #b9cfe9; }
|
|
387
|
+
html[data-theme="light"] button:hover { background: #d9e8fa; }
|
|
388
|
+
html[data-theme="light"] button.primary { background: #1f6feb; border-color: #388bfd; color: #ffffff; }
|
|
389
|
+
html[data-theme="light"] button.primary:hover { background: #2b7bff; }
|
|
390
|
+
html[data-theme="light"] button.danger { background: #fdeef2; border-color: #f0c2cd; color: #b3405a; }
|
|
391
|
+
html[data-theme="light"] button.danger:hover { background: #fadde5; }
|
|
392
|
+
html[data-theme="light"] #backdrop { background: rgba(30, 45, 70, 0.35); }
|
|
393
|
+
html[data-theme="light"] .panel { background: #ffffff; border-right-color: #dfe7f2; }
|
|
394
|
+
html[data-theme="light"] .panel.right { border-left-color: #dfe7f2; }
|
|
395
|
+
html[data-theme="light"] .tabs { border-bottom-color: #dfe7f2; }
|
|
396
|
+
html[data-theme="light"] .tabs div { color: #5a6c8c; }
|
|
397
|
+
html[data-theme="light"] .tabs div.active { color: #0b66c3; border-bottom-color: #1f6feb; background: #eaf3ff; }
|
|
398
|
+
html[data-theme="light"] #btn-inference.active { background: #f1eafa; border-color: #7c4dbc; color: #7c4dbc; }
|
|
399
|
+
html[data-theme="light"] .tabbody::-webkit-scrollbar-thumb, html[data-theme="light"] .messages::-webkit-scrollbar-thumb { background: #c4d3e8; }
|
|
400
|
+
html[data-theme="light"] .card { background: #f7fafd; border-color: #e2eaf5; }
|
|
401
|
+
html[data-theme="light"] .card h3 { color: #48608a; }
|
|
402
|
+
html[data-theme="light"] label { color: #5a6c8c; }
|
|
403
|
+
html[data-theme="light"] input, html[data-theme="light"] select, html[data-theme="light"] textarea {
|
|
404
|
+
background: #ffffff; border-color: #c9d6ea; color: #22304c;
|
|
405
|
+
}
|
|
406
|
+
html[data-theme="light"] .list-item { background: #ffffff; border-color: #e2eaf5; }
|
|
407
|
+
html[data-theme="light"] .list-item .name { color: #22304c; }
|
|
408
|
+
html[data-theme="light"] .list-item .sub { color: #7286a8; }
|
|
409
|
+
html[data-theme="light"] #canvas-wrap { background: radial-gradient(ellipse at center, #f2f6fc 0%, #dde8f5 100%); }
|
|
410
|
+
html[data-theme="light"] .legend { background: rgba(255, 255, 255, 0.88); border-color: #d5e1f0; color: #4a5f85; }
|
|
411
|
+
html[data-theme="light"] .legend b { color: #22304c; }
|
|
412
|
+
html[data-theme="light"] #info-card { background: rgba(255, 255, 255, 0.95); border-color: #c9d6ea; }
|
|
413
|
+
html[data-theme="light"] #info-card h4 { color: #0b66c3; }
|
|
414
|
+
html[data-theme="light"] #info-card .kv { color: #4a5f85; }
|
|
415
|
+
html[data-theme="light"] #info-card .kv b { color: #22304c; }
|
|
416
|
+
html[data-theme="light"] #empty-hint { color: #8aa0c4; }
|
|
417
|
+
html[data-theme="light"] #ego-bar { background: rgba(255, 255, 255, 0.95); border-color: #c9d6ea; }
|
|
418
|
+
html[data-theme="light"] #ego-bar .ego-name { color: #a06b00; }
|
|
419
|
+
html[data-theme="light"] #ego-bar label { color: #5a6c8c; }
|
|
420
|
+
html[data-theme="light"] #ego-bar .ego-hint { color: #8598b8; }
|
|
421
|
+
html[data-theme="light"] #img-grid img { border-color: #c9d6ea; background: #ffffff; }
|
|
422
|
+
html[data-theme="light"] #lightbox { background: rgba(240, 245, 252, 0.94); }
|
|
423
|
+
html[data-theme="light"] #lightbox img { background: #ffffff; }
|
|
424
|
+
html[data-theme="light"] #lightbox figcaption { color: #22304c; }
|
|
425
|
+
html[data-theme="light"] #lightbox .lb-close { background: rgba(255, 255, 255, 0.92); }
|
|
426
|
+
html[data-theme="light"] .msg .who { color: #7286a8; }
|
|
427
|
+
html[data-theme="light"] .msg .bubble { background: #f7fafd; border-color: #e2eaf5; }
|
|
428
|
+
html[data-theme="light"] .msg.user .bubble { background: #eaf3ff; border-color: #bcd7f7; }
|
|
429
|
+
html[data-theme="light"] .chip { background: #e6f7ec; color: #1a7f42; border-color: #8fd4a855; }
|
|
430
|
+
html[data-theme="light"] .chip.warn { background: #fdf1e3; color: #a3620a; border-color: #e8b47855; }
|
|
431
|
+
html[data-theme="light"] .chat-input { border-top-color: #dfe7f2; }
|
|
432
|
+
html[data-theme="light"] .hint-text { color: #8598b8; }
|
|
433
|
+
html[data-theme="light"] #file-chip { background: #eaf3ff; border-color: #9fc1ea; }
|
|
434
|
+
html[data-theme="light"] #file-chip-name { color: #0b66c3; }
|
|
435
|
+
html[data-theme="light"] .report { color: #4a5f85; background: #f2f7fd; border-color: #e2eaf5; }
|
|
436
|
+
html[data-theme="light"] .report b { color: #1a7f42; }
|
|
437
|
+
html[data-theme="light"] .report .rerr { color: #a3620a; }
|
|
438
|
+
html[data-theme="light"] #toast { background: #ffffff; border-color: #9fc1ea; color: #22304c; box-shadow: 0 4px 16px rgba(30, 50, 80, 0.18); }
|
|
439
|
+
html[data-theme="light"] #toast.err { border-color: #f0c2cd; color: #b3405a; background: #fdf1f4; }
|
|
440
|
+
html[data-theme="light"] .log-item { border-bottom-color: #e7eef8; }
|
|
441
|
+
html[data-theme="light"] .log-item .l1 { color: #48608a; }
|
|
442
|
+
html[data-theme="light"] .log-item .l2 { color: #7286a8; }
|
|
443
|
+
html[data-theme="light"] .ver-item { background: #ffffff; border-color: #e2eaf5; }
|
|
444
|
+
html[data-theme="light"] .ver-item code { color: #0b66c3; }
|
|
445
|
+
html[data-theme="light"] .ver-item .v2 { color: #33456b; }
|
|
446
|
+
html[data-theme="light"] .ver-item .v3 { color: #7286a8; }
|
|
447
|
+
html[data-theme="light"] #style-panel, html[data-theme="light"] #help-panel,
|
|
448
|
+
html[data-theme="light"] #path-panel, html[data-theme="light"] #tooltip3d {
|
|
449
|
+
background: rgba(255, 255, 255, 0.97); border-color: #c9d6ea;
|
|
450
|
+
box-shadow: 0 4px 16px rgba(30, 50, 80, 0.16);
|
|
451
|
+
}
|
|
452
|
+
html[data-theme="light"] .style-row .sname { color: #22304c; }
|
|
453
|
+
html[data-theme="light"] .style-sec { color: #48608a; }
|
|
454
|
+
html[data-theme="light"] .hp-head span:last-child:hover { color: #22304c; }
|
|
455
|
+
html[data-theme="light"] .hp-body h3 { color: #0b66c3; border-bottom-color: #e2eaf5; }
|
|
456
|
+
html[data-theme="light"] .hp-p, html[data-theme="light"] .hp-list { color: #33456b; }
|
|
457
|
+
html[data-theme="light"] .hp-list b { color: #22304c; }
|
|
458
|
+
html[data-theme="light"] .hp-line { color: #5a6c8c; }
|
|
459
|
+
html[data-theme="light"] .upd-box { border-color: #e2eaf5; background: #f2f7fd; }
|
|
460
|
+
html[data-theme="light"] .upd-ver { color: #22304c; }
|
|
461
|
+
html[data-theme="light"] .upd-ver b { color: #0b66c3; }
|
|
462
|
+
html[data-theme="light"] .upd-status { color: #5a6c8c; }
|
|
463
|
+
html[data-theme="light"] .ask-chip { border-color: #c9d6ea; color: #4a5f85; background: #eef3fa; }
|
|
464
|
+
html[data-theme="light"] .ask-chip.ok { border-color: #8fd4a8; color: #1a7f42; background: #e6f7ec; }
|
|
465
|
+
html[data-theme="light"] .ask-chip.timeout { border-color: #e8b478; color: #a3620a; background: #fdf1e3; }
|
|
466
|
+
html[data-theme="light"] .ask-chip.err, html[data-theme="light"] .ask-chip.degraded { border-color: #f0c2cd; color: #b3405a; background: #fdeef2; }
|
|
467
|
+
html[data-theme="light"] .ask-sec { color: #5a6c8c; border-bottom-color: #e2eaf5; }
|
|
468
|
+
html[data-theme="light"] .ask-synth { color: #33456b; background: #f2f7fd; border-color: #dfe7f2; }
|
|
469
|
+
html[data-theme="light"] .syn-ref { color: #0b66c3; border-bottom-color: #0b66c388; }
|
|
470
|
+
html[data-theme="light"] .tooltip3d, html[data-theme="light"] #tooltip3d { color: #22304c; }
|
|
471
|
+
html[data-theme="light"] #tooltip3d b { color: #0b66c3; }
|
|
472
|
+
html[data-theme="light"] #tooltip3d .tt-cat { color: #5a6c8c; }
|
|
473
|
+
html[data-theme="light"] #tooltip3d .tt-attr { color: #48608a; }
|
|
474
|
+
html[data-theme="light"] #path-panel .p-head { color: #0b66c3; }
|
|
475
|
+
html[data-theme="light"] #path-panel .p-head #path-close { color: #5a6c8c; }
|
|
476
|
+
html[data-theme="light"] #path-panel .p-ent { background: #eaf3ff; border-color: #c9d6ea; color: #22304c; }
|
|
477
|
+
html[data-theme="light"] #path-panel .p-ent:hover { border-color: #0b66c3; }
|
|
478
|
+
html[data-theme="light"] #path-panel .p-rel { color: #5a729c; }
|
|
479
|
+
html[data-theme="light"] .log-filter select, html[data-theme="light"] .log-filter input {
|
|
480
|
+
background: #ffffff; border-color: #c9d6ea; color: #22304c;
|
|
481
|
+
}
|
|
482
|
+
html[data-theme="light"] #file-menu { background: #ffffff; border-color: #c9d6ea; box-shadow: 0 8px 24px rgba(30, 50, 80, 0.18); }
|
|
483
|
+
html[data-theme="light"] #file-menu button { color: #22304c; border-bottom-color: #edf2f9; }
|
|
484
|
+
html[data-theme="light"] #file-menu button:active { background: #eaf3ff; }
|
|
485
|
+
html[data-theme="light"] .m-btn { background: #eaf3ff; }
|
|
486
|
+
html[data-theme="light"] #m-legend { background: rgba(255, 255, 255, 0.92); }
|