@theseus-whale/dsh-continuity 0.0.0-stage → 4.12.2
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/INSTALL.md +25 -0
- package/PANEL.md +92 -0
- package/README.md +286 -2
- package/RELEASE-NOTES.md +732 -0
- package/bin/bc-acceptance-full.mjs +91 -0
- package/bin/bc-acceptance-tight.mjs +66 -0
- package/bin/bc-acceptance.mjs +22 -0
- package/bin/bc-add-keywords.mjs +21 -0
- package/bin/bc-demo.mjs +47 -0
- package/bin/bc-expand-hint.mjs +179 -0
- package/bin/bc-ingest-index.mjs +35 -0
- package/bin/bc-ingest.mjs +31 -0
- package/bin/bc-label-demo.mjs +18 -0
- package/bin/bc-relabel.mjs +150 -0
- package/bin/bc-sessionize.mjs +59 -0
- package/bin/coref_pipeline.py +47 -0
- package/bin/coref_service.py +57 -0
- package/bin/debug_ckip.py +16 -0
- package/bin/debug_ner_zh.py +18 -0
- package/bin/doctor.mjs +275 -0
- package/bin/en_ner_error_audit.py +33 -0
- package/bin/eval-label-rules.mjs +342 -0
- package/bin/export-turns.py +68 -0
- package/bin/extract-user-paragraph.mjs +14 -0
- package/bin/extraction-composite-smoke.mjs +28 -0
- package/bin/extraction-latency.mjs +58 -0
- package/bin/extraction-user-smoke.mjs +28 -0
- package/bin/extraction_service.py +164 -0
- package/bin/facet-active-experiment.mjs +110 -0
- package/bin/facet-covid.mjs +8 -0
- package/bin/facet-curve.mjs +27 -0
- package/bin/facet-embedding-train.mjs +20 -0
- package/bin/facet-embedding-validate.mjs +83 -0
- package/bin/facet-eval-roleplay.mjs +42 -0
- package/bin/facet-eval.mjs +38 -0
- package/bin/facet-fold.mjs +31 -0
- package/bin/facet-load.mjs +16 -0
- package/bin/facet-mlp-scan.mjs +45 -0
- package/bin/facet-mvp.mjs +34 -0
- package/bin/facet-online-experiments.mjs +78 -0
- package/bin/facet-online-race.mjs +99 -0
- package/bin/facet-online-validate.mjs +51 -0
- package/bin/facet-panel.mjs +22 -0
- package/bin/facet-passage.mjs +41 -0
- package/bin/facet-random-validate.mjs +48 -0
- package/bin/facet-roleplay.mjs +33 -0
- package/bin/facet-scan.mjs +56 -0
- package/bin/facet-segment.mjs +34 -0
- package/bin/facet-train.mjs +19 -0
- package/bin/facet-validate.mjs +103 -0
- package/bin/facet-zeroshot.mjs +14 -0
- package/bin/install-templates.mjs +72 -0
- package/bin/memory-bench.mjs +53 -0
- package/bin/memory-build-summary.mjs +43 -0
- package/bin/memory-build-vector.mjs +31 -0
- package/bin/memory-build.mjs +41 -0
- package/bin/memory-calibration.mjs +70 -0
- package/bin/memory-closed-loop.mjs +119 -0
- package/bin/memory-dry-run.mjs +70 -0
- package/bin/memory-eval.mjs +104 -0
- package/bin/memory-event-alias-test.mjs +89 -0
- package/bin/memory-extraction-bench.mjs +58 -0
- package/bin/memory-load-gate-replay.mjs +137 -0
- package/bin/memory-loop-test.mjs +90 -0
- package/bin/memory-pre-turn-harness.mjs +63 -0
- package/bin/memory-query.mjs +39 -0
- package/bin/memory-replay-hints.mjs +84 -0
- package/bin/memory-scale.mjs +58 -0
- package/bin/memory-scenario-test.mjs +146 -0
- package/bin/memory-user-loop.mjs +95 -0
- package/bin/ner_bench_tiny_zh.py +59 -0
- package/bin/ner_bench_zh.py +60 -0
- package/bin/ner_conll_en.py +139 -0
- package/bin/ner_direct_en.py +123 -0
- package/bin/ner_direct_zh.py +100 -0
- package/bin/ner_pipeline.py +208 -0
- package/bin/noise-selfcheck.mjs +50 -0
- package/bin/pack-integrity.mjs +47 -0
- package/bin/panel-check.mjs +57 -0
- package/bin/plugin-integrity.mjs +74 -0
- package/bin/preview-live.mjs +13 -0
- package/bin/public-install-check.mjs +222 -0
- package/bin/relabel-apply.mjs +272 -0
- package/bin/relabel-dry-run.mjs +381 -0
- package/bin/relik_pipeline.py +39 -0
- package/bin/relik_service.py +52 -0
- package/bin/srl_pipeline.py +55 -0
- package/bin/srl_service.py +68 -0
- package/bin/summary-index.mjs +151 -0
- package/bin/summary-query.mjs +79 -0
- package/bin/vec-check.mjs +27 -0
- package/bin/zh_ner_error_audit.py +36 -0
- package/bin/zh_ner_slot_eval.py +38 -0
- package/client.js +760 -0
- package/cordis.patch.yml +378 -0
- package/docs/API-NOTES.md +1743 -0
- package/docs/ARCHITECTURE.md +355 -0
- package/docs/CACHE.md +253 -0
- package/docs/CONDUCT.md +30 -0
- package/docs/CREATOR-HANDOFF.md +102 -0
- package/docs/EXPERIMENT.md +136 -0
- package/docs/FACET-MVP-REPORT.md +473 -0
- package/docs/GUIDE-0.4.66.md +195 -0
- package/docs/GUIDE.md +127 -0
- package/docs/MECHANISM.md +243 -0
- package/docs/NEW-INSTANCE-HANDOFF.md +219 -0
- package/docs/README.md +37 -0
- package/docs/SESSION-LAYOUT.md +151 -0
- package/docs/history-map.md +249 -0
- package/docs/relabel-migration-wiring.md +366 -0
- package/guides/00-READ-FIRST.md +206 -0
- package/guides/01-INSTALL.md +207 -0
- package/guides/02-TABLES.md +225 -0
- package/guides/03-AUDIT.md +201 -0
- package/guides/04-REBUILD.md +306 -0
- package/guides/05-FIRST-RUN.md +191 -0
- package/guides/06-EMBEDDING.md +146 -0
- package/guides/07-PTC-AND-ASSETS.md +221 -0
- package/icon.svg +7 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/models/README.md +13 -0
- package/models/Xenova/bge-small-zh-v1.5/config.json +31 -0
- package/models/Xenova/bge-small-zh-v1.5/onnx/model_quantized.onnx +0 -0
- package/models/Xenova/bge-small-zh-v1.5/tokenizer.json +21278 -0
- package/models/Xenova/bge-small-zh-v1.5/tokenizer_config.json +15 -0
- package/package.json +139 -4
- package/src/asset-tool.mjs +237 -0
- package/src/assets.mjs +244 -0
- package/src/backfill.mjs +74 -0
- package/src/backup.mjs +80 -0
- package/src/deadend.mjs +95 -0
- package/src/deleted-store.mjs +35 -0
- package/src/engine.mjs +3831 -0
- package/src/facets/classifier.mjs +146 -0
- package/src/facets/embedding-service.mjs +53 -0
- package/src/facets/embedding-worker.mjs +27 -0
- package/src/facets/embedding.mjs +163 -0
- package/src/facets/extract.mjs +80 -0
- package/src/facets/fold-plan.mjs +84 -0
- package/src/facets/hybrid.mjs +29 -0
- package/src/facets/index.mjs +113 -0
- package/src/facets/linear-probe.mjs +43 -0
- package/src/facets/load.mjs +37 -0
- package/src/facets/mlp-probe.mjs +54 -0
- package/src/facets/mlp-service.mjs +53 -0
- package/src/facets/mlp-worker.mjs +26 -0
- package/src/facets/online-knn.mjs +58 -0
- package/src/facets/online-models.mjs +227 -0
- package/src/facets/panel-state.mjs +23 -0
- package/src/facets/panel.mjs +73 -0
- package/src/facets/random.mjs +26 -0
- package/src/facets/scanner.mjs +35 -0
- package/src/facets/schema.mjs +75 -0
- package/src/facets/seed-examples.mjs +58 -0
- package/src/facets/sensitivity.mjs +98 -0
- package/src/facets/service.mjs +53 -0
- package/src/facets/store.mjs +39 -0
- package/src/facets/worker.mjs +23 -0
- package/src/folds-store.mjs +109 -0
- package/src/groups.mjs +167 -0
- package/src/handoff-tool.mjs +51 -0
- package/src/handoff.mjs +127 -0
- package/src/index.mjs +649 -0
- package/src/inject-policy.mjs +17 -0
- package/src/learning.mjs +88 -0
- package/src/memory/alias-proposal.mjs +40 -0
- package/src/memory/bc-audit.mjs +245 -0
- package/src/memory/bc-index-updater.mjs +404 -0
- package/src/memory/bc-index.mjs +48 -0
- package/src/memory/bc-label.mjs +220 -0
- package/src/memory/bc-panel-state.mjs +107 -0
- package/src/memory/bc-pre-step.mjs +463 -0
- package/src/memory/bc-recall.mjs +470 -0
- package/src/memory/bc-shift.mjs +123 -0
- package/src/memory/bc-store.mjs +41 -0
- package/src/memory/bm25.mjs +112 -0
- package/src/memory/calibration.mjs +54 -0
- package/src/memory/chatter.mjs +29 -0
- package/src/memory/cmap-file.mjs +107 -0
- package/src/memory/concepts-file.mjs +41 -0
- package/src/memory/coref-slots.mjs +40 -0
- package/src/memory/event-alias-ledger.mjs +87 -0
- package/src/memory/event-log.mjs +95 -0
- package/src/memory/event-model.mjs +132 -0
- package/src/memory/event-segmenter.mjs +36 -0
- package/src/memory/event-summary-tree.mjs +122 -0
- package/src/memory/extraction-adapter.mjs +76 -0
- package/src/memory/extraction-composite.mjs +75 -0
- package/src/memory/extraction-core.mjs +76 -0
- package/src/memory/extraction-pre-step.mjs +161 -0
- package/src/memory/extraction-provider.mjs +300 -0
- package/src/memory/extraction-score.mjs +36 -0
- package/src/memory/facet-stabilizer.mjs +59 -0
- package/src/memory/history-map.mjs +139 -0
- package/src/memory/language-router.mjs +30 -0
- package/src/memory/load-gate.mjs +161 -0
- package/src/memory/mechanical-note.mjs +104 -0
- package/src/memory/onboarding.mjs +163 -0
- package/src/memory/persona.mjs +78 -0
- package/src/memory/planner.mjs +249 -0
- package/src/memory/pre-turn.mjs +80 -0
- package/src/memory/query-aliases.mjs +39 -0
- package/src/memory/recall-cue.mjs +43 -0
- package/src/memory/recall.mjs +65 -0
- package/src/memory/referent-candidates.mjs +55 -0
- package/src/memory/referent-ledger.mjs +86 -0
- package/src/memory/relabel-migrate.mjs +376 -0
- package/src/memory/relik-adapter.mjs +25 -0
- package/src/memory/special-keywords.mjs +60 -0
- package/src/memory/structured-adapters.mjs +75 -0
- package/src/memory/summary-index.mjs +335 -0
- package/src/memory/summary-tree.mjs +110 -0
- package/src/memory/term-extractor.mjs +44 -0
- package/src/memory/tokenize.mjs +9 -0
- package/src/memory/vector-index.mjs +54 -0
- package/src/memory/window-summary.mjs +133 -0
- package/src/mood.mjs +133 -0
- package/src/peer-tool.mjs +63 -0
- package/src/peer.mjs +144 -0
- package/src/policy.mjs +170 -0
- package/src/preflight.mjs +113 -0
- package/src/provenance.mjs +94 -0
- package/src/range.mjs +75 -0
- package/src/recall-exact-tool.mjs +267 -0
- package/src/recall-tool.mjs +521 -0
- package/src/recheck.mjs +99 -0
- package/src/save-start.mjs +29 -0
- package/src/session-guard.mjs +140 -0
- package/src/session-log-tool.mjs +322 -0
- package/src/session-log.mjs +606 -0
- package/src/skills.mjs +111 -0
- package/src/split-range.mjs +115 -0
- package/src/state.mjs +198 -0
- package/src/t0.mjs +149 -0
- package/src/tag-confirm.mjs +78 -0
- package/src/tag-detect.mjs +42 -0
- package/src/tag-maintenance.mjs +285 -0
- package/src/tag-reject.mjs +73 -0
- package/src/tags-store.mjs +94 -0
- package/src/tags.mjs +692 -0
- package/src/threads-backend.mjs +26 -0
- package/src/threads-core.mjs +1887 -0
- package/src/threads-store.mjs +207 -0
- package/src/threads-tool.mjs +522 -0
- package/src/threads.mjs +929 -0
- package/src/tool-preview.mjs +427 -0
- package/src/topic.mjs +63 -0
- package/src/training.mjs +75 -0
- package/src/turn-tag.mjs +62 -0
- package/src/user-turn.mjs +39 -0
- package/templates/cmap.md +11 -0
- package/templates/concepts.md +12 -0
- package/templates/habits.md +40 -0
- package/templates/keywords.md +6 -0
- package/templates/rebuild.md +134 -0
- package/templates/rules-safe.md +184 -0
- package/templates/rules.md +177 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Build the middle-layer summary index from one raw session.
|
|
4
|
+
*
|
|
5
|
+
* Phase 0/1:
|
|
6
|
+
* - imports existing compaction/summary records (native checkpoint + gist)
|
|
7
|
+
* - plans missing windows by seq/token gaps
|
|
8
|
+
* - dry-run by default; --apply writes summaries/index.json
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* node bin/summary-index.mjs --raw <session.v4.jsonl.zstd> [--out <index.json>] [--json]
|
|
12
|
+
* node bin/summary-index.mjs --raw ... --apply [--session-dir <dir>]
|
|
13
|
+
*/
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
import zlib from 'node:zlib';
|
|
17
|
+
import { buildSummaryIndex, summaryIndexPath } from '../src/memory/summary-index.mjs';
|
|
18
|
+
import { buildWindowSummary } from '../src/memory/window-summary.mjs';
|
|
19
|
+
|
|
20
|
+
function arg(name, fallback = null) {
|
|
21
|
+
const i = process.argv.indexOf(`--${name}`);
|
|
22
|
+
return i >= 0 ? process.argv[i + 1] ?? fallback : fallback;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function readRawLines(file) {
|
|
26
|
+
if (!/\.zstd$/i.test(file)) {
|
|
27
|
+
return fs.readFileSync(file, 'utf8').replace(/^\uFEFF/, '').split(/\r?\n/).filter(Boolean);
|
|
28
|
+
}
|
|
29
|
+
const buf = fs.readFileSync(file);
|
|
30
|
+
const magic = Buffer.from([0x28, 0xb5, 0x2f, 0xfd]);
|
|
31
|
+
const starts = [];
|
|
32
|
+
for (let at = 0; ;) {
|
|
33
|
+
const found = buf.indexOf(magic, at);
|
|
34
|
+
if (found < 0) break;
|
|
35
|
+
starts.push(found);
|
|
36
|
+
at = found + magic.length;
|
|
37
|
+
}
|
|
38
|
+
const lines = [];
|
|
39
|
+
for (const start of starts) {
|
|
40
|
+
let out;
|
|
41
|
+
try { out = zlib.zstdDecompressSync(buf.subarray(start)); } catch { continue; }
|
|
42
|
+
lines.push(...out.toString('utf8').split(/\r?\n/).filter(Boolean));
|
|
43
|
+
}
|
|
44
|
+
return lines;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const raw = arg('raw');
|
|
48
|
+
if (!raw) {
|
|
49
|
+
console.error('用法: node bin/summary-index.mjs --raw <session.v4.jsonl[.zstd]> [--out <index.json>] [--apply] [--json]');
|
|
50
|
+
process.exit(2);
|
|
51
|
+
}
|
|
52
|
+
if (!fs.existsSync(raw)) {
|
|
53
|
+
console.error(`raw not found: ${raw}`);
|
|
54
|
+
process.exit(2);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const sessionDirArg = arg('session-dir');
|
|
58
|
+
const sessionDir = sessionDirArg ?? path.dirname(raw);
|
|
59
|
+
const sessionId = arg('session-id', path.basename(sessionDir));
|
|
60
|
+
const windowTokens = Math.max(1000, Number(arg('window-tokens', 40000)) || 40000);
|
|
61
|
+
const outArg = arg('out');
|
|
62
|
+
const out = outArg ?? (sessionDirArg ? summaryIndexPath(sessionDirArg) : null);
|
|
63
|
+
const apply = process.argv.includes('--apply');
|
|
64
|
+
const extractPending = process.argv.includes('--extract-pending');
|
|
65
|
+
const printJson = process.argv.includes('--json');
|
|
66
|
+
if (apply && !out) {
|
|
67
|
+
console.error('--apply requires explicit --session-dir (Continuity session dir) or --out');
|
|
68
|
+
process.exit(2);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const events = [];
|
|
72
|
+
const seen = new Set();
|
|
73
|
+
for (const line of readRawLines(raw)) {
|
|
74
|
+
let event;
|
|
75
|
+
try { event = JSON.parse(line.replace(/^\uFEFF/, '')); } catch { continue; }
|
|
76
|
+
const seq = Number(event?.seq);
|
|
77
|
+
if (Number.isInteger(seq)) {
|
|
78
|
+
if (seen.has(seq)) continue;
|
|
79
|
+
seen.add(seq);
|
|
80
|
+
}
|
|
81
|
+
events.push(event);
|
|
82
|
+
}
|
|
83
|
+
events.sort((a, b) => Number(a.seq) - Number(b.seq));
|
|
84
|
+
|
|
85
|
+
const bootstrapFile = path.join(sessionDir, 'summaries', 'bootstrap-ranges.json');
|
|
86
|
+
let bootstrapRanges = [];
|
|
87
|
+
try {
|
|
88
|
+
if (fs.existsSync(bootstrapFile)) {
|
|
89
|
+
const parsed = JSON.parse(fs.readFileSync(bootstrapFile, 'utf8'));
|
|
90
|
+
if (Array.isArray(parsed?.ranges)) bootstrapRanges = parsed.ranges;
|
|
91
|
+
}
|
|
92
|
+
} catch { /* malformed sidecar is ignored; index still builds */ }
|
|
93
|
+
|
|
94
|
+
const baseIndex = buildSummaryIndex({ sessionId, events, windowTokens, bootstrapRanges });
|
|
95
|
+
const windowSummaries = extractPending
|
|
96
|
+
? baseIndex.pendingWindows.map((pending) => buildWindowSummary({
|
|
97
|
+
events,
|
|
98
|
+
fromSeq: pending.fromSeq,
|
|
99
|
+
toSeq: pending.toSeq,
|
|
100
|
+
maxTokens: 800,
|
|
101
|
+
}))
|
|
102
|
+
: [];
|
|
103
|
+
const windowRanges = windowSummaries.map((summary) => ({
|
|
104
|
+
fromSeq: summary.fromSeq,
|
|
105
|
+
toSeq: summary.toSeq,
|
|
106
|
+
tokens: summary.approxTokens,
|
|
107
|
+
hash: summary.hash,
|
|
108
|
+
at: new Date().toISOString(),
|
|
109
|
+
}));
|
|
110
|
+
const index = windowSummaries.length > 0
|
|
111
|
+
? buildSummaryIndex({ sessionId, events, windowTokens, bootstrapRanges, windowRanges, windowRecords: windowSummaries })
|
|
112
|
+
: baseIndex;
|
|
113
|
+
if (apply && extractPending) {
|
|
114
|
+
const windowDir = path.join(path.dirname(out), 'windows');
|
|
115
|
+
fs.mkdirSync(windowDir, { recursive: true });
|
|
116
|
+
for (const summary of windowSummaries) {
|
|
117
|
+
fs.writeFileSync(
|
|
118
|
+
path.join(windowDir, `${summary.fromSeq}-${summary.toSeq}.json`),
|
|
119
|
+
JSON.stringify(summary, null, 2),
|
|
120
|
+
'utf8',
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (apply) {
|
|
125
|
+
fs.mkdirSync(path.dirname(out), { recursive: true });
|
|
126
|
+
const tmp = `${out}.tmp-${process.pid}`;
|
|
127
|
+
fs.writeFileSync(tmp, JSON.stringify(index, null, 2), 'utf8');
|
|
128
|
+
fs.renameSync(tmp, out);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (printJson) {
|
|
132
|
+
console.log(JSON.stringify(index, null, 2));
|
|
133
|
+
} else {
|
|
134
|
+
console.log(JSON.stringify({
|
|
135
|
+
sessionId: index.sessionId,
|
|
136
|
+
raw: path.resolve(raw),
|
|
137
|
+
out: apply ? path.resolve(out) : null,
|
|
138
|
+
apply,
|
|
139
|
+
windowTokens: index.windowTokens,
|
|
140
|
+
maxSummarySeq: index.maxSummarySeq,
|
|
141
|
+
coveredThroughSeq: index.coveredThroughSeq,
|
|
142
|
+
latestSummaryAt: index.latestSummaryAt,
|
|
143
|
+
records: index.records.length,
|
|
144
|
+
checkpoints: index.records.filter((record) => record.kind === 'checkpoint').length,
|
|
145
|
+
gists: index.records.filter((record) => record.kind === 'gist').length,
|
|
146
|
+
pendingWindows: index.pendingWindows.length,
|
|
147
|
+
pending: index.pendingWindows.slice(0, 8),
|
|
148
|
+
extractedWindows: windowSummaries.length,
|
|
149
|
+
coverage: index.coverage,
|
|
150
|
+
}, null, 2));
|
|
151
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Read-only query over the Continuity summary index.
|
|
4
|
+
* This is a first step for recall's summaryHits; no model, no writes.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* node bin/summary-query.mjs --index <index.json> --query "..." [--limit 5] [--json]
|
|
8
|
+
* node bin/summary-query.mjs --session-dir <dir> --query "..."
|
|
9
|
+
*/
|
|
10
|
+
import fs from 'node:fs';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { summaryIndexPath } from '../src/memory/summary-index.mjs';
|
|
13
|
+
|
|
14
|
+
function arg(name, fallback = null) {
|
|
15
|
+
const i = process.argv.indexOf(`--${name}`);
|
|
16
|
+
return i >= 0 ? process.argv[i + 1] ?? fallback : fallback;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const sessionDir = arg('session-dir');
|
|
20
|
+
const indexFile = arg('index', sessionDir ? summaryIndexPath(sessionDir) : null);
|
|
21
|
+
const query = String(arg('query', '')).trim();
|
|
22
|
+
const limit = Math.min(Math.max(Number(arg('limit', 5)) || 5, 1), 50);
|
|
23
|
+
const json = process.argv.includes('--json');
|
|
24
|
+
if (!indexFile || !fs.existsSync(indexFile)) {
|
|
25
|
+
console.error('summary index not found; pass --index or --session-dir');
|
|
26
|
+
process.exit(2);
|
|
27
|
+
}
|
|
28
|
+
if (!query) {
|
|
29
|
+
console.error('query required');
|
|
30
|
+
process.exit(2);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const index = JSON.parse(fs.readFileSync(indexFile, 'utf8').replace(/^\uFEFF/, ''));
|
|
34
|
+
const q = query.normalize('NFKC').toLowerCase();
|
|
35
|
+
const qChars = [...q];
|
|
36
|
+
const cjkQuery = /[\u3400-\u9fff]/.test(q);
|
|
37
|
+
const records = Array.isArray(index.records) ? index.records : [];
|
|
38
|
+
const scored = [];
|
|
39
|
+
for (const record of records) {
|
|
40
|
+
const text = String(record.text ?? '').normalize('NFKC').toLowerCase();
|
|
41
|
+
if (!text) continue;
|
|
42
|
+
let score = 0;
|
|
43
|
+
const exact = text.includes(q);
|
|
44
|
+
if (exact) score += 100;
|
|
45
|
+
if (cjkQuery && qChars.length >= 2) {
|
|
46
|
+
const covered = qChars.filter((ch) => text.includes(ch)).length;
|
|
47
|
+
if (covered === qChars.length) score += 5;
|
|
48
|
+
}
|
|
49
|
+
if (score > 0) scored.push({ record, score, exact });
|
|
50
|
+
}
|
|
51
|
+
scored.sort((a, b) => b.score - a.score || b.record.toSeq - a.record.toSeq);
|
|
52
|
+
const hits = scored.slice(0, limit).map(({ record, score, exact }) => ({
|
|
53
|
+
id: record.id,
|
|
54
|
+
kind: record.kind,
|
|
55
|
+
fromSeq: record.fromSeq,
|
|
56
|
+
toSeq: record.toSeq,
|
|
57
|
+
fromTurn: record.fromTurn,
|
|
58
|
+
toTurn: record.toTurn,
|
|
59
|
+
threads: record.threads,
|
|
60
|
+
approxTokens: record.approxTokens,
|
|
61
|
+
score: Number(score.toFixed(2)),
|
|
62
|
+
exact,
|
|
63
|
+
excerpt: String(record.text ?? '').slice(0, 500),
|
|
64
|
+
}));
|
|
65
|
+
const result = {
|
|
66
|
+
index: path.resolve(indexFile),
|
|
67
|
+
query,
|
|
68
|
+
total: scored.length,
|
|
69
|
+
shown: hits.length,
|
|
70
|
+
hits,
|
|
71
|
+
};
|
|
72
|
+
if (json) console.log(JSON.stringify(result, null, 2));
|
|
73
|
+
else {
|
|
74
|
+
console.log(`query=${query} total=${result.total} shown=${result.shown}`);
|
|
75
|
+
for (const hit of hits) {
|
|
76
|
+
console.log(`\n[${hit.kind}] ${hit.id} · turn ${hit.fromTurn ?? '?'}-${hit.toTurn ?? '?'} · seq ${hit.fromSeq}-${hit.toSeq} · score ${hit.score}`);
|
|
77
|
+
console.log(hit.excerpt.replace(/\s+/g, ' ').slice(0, 300));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Check whether the local embedding runtime produces a usable vector.
|
|
4
|
+
*
|
|
5
|
+
* Run from the installed package:
|
|
6
|
+
* node bin/vec-check.mjs
|
|
7
|
+
*/
|
|
8
|
+
import { embedTexts } from '../src/facets/embedding.mjs';
|
|
9
|
+
|
|
10
|
+
try {
|
|
11
|
+
const [vector] = await embedTexts(['连续性记忆审计自检']);
|
|
12
|
+
const dim = Array.isArray(vector) ? vector.length : 0;
|
|
13
|
+
const finite = Array.isArray(vector) && vector.every((value) => Number.isFinite(value));
|
|
14
|
+
console.log(JSON.stringify({
|
|
15
|
+
ok: dim > 0 && finite,
|
|
16
|
+
dimensions: dim,
|
|
17
|
+
first3: Array.isArray(vector) ? vector.slice(0, 3) : [],
|
|
18
|
+
}, null, 2));
|
|
19
|
+
if (dim === 0 || !finite) process.exit(1);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
console.error(JSON.stringify({
|
|
22
|
+
ok: false,
|
|
23
|
+
error: String(error?.message ?? error),
|
|
24
|
+
hint: 'run pnpm approve-builds, then pnpm rebuild onnxruntime-node sharp in the DSH profile',
|
|
25
|
+
}, null, 2));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
import sys
|
|
4
|
+
from collections import Counter
|
|
5
|
+
|
|
6
|
+
src, out = sys.argv[1], sys.argv[2]
|
|
7
|
+
data = json.load(open(src, encoding="utf-8"))
|
|
8
|
+
rows = data["rows"]
|
|
9
|
+
gold_count = Counter()
|
|
10
|
+
pred_count = Counter()
|
|
11
|
+
fp = []
|
|
12
|
+
fn = []
|
|
13
|
+
for row in rows:
|
|
14
|
+
gold = {(g["entity"], g["label"]) for g in row["gold"]}
|
|
15
|
+
pred = {(p["text"].replace(" ", ""), p["label"]) for p in row["pred"]}
|
|
16
|
+
for item in gold:
|
|
17
|
+
gold_count[item[1]] += 1
|
|
18
|
+
for item in pred:
|
|
19
|
+
pred_count[item[1]] += 1
|
|
20
|
+
for item in pred - gold:
|
|
21
|
+
fp.append({"text": item[0], "label": item[1], "sentence": row["text"]})
|
|
22
|
+
for item in gold - pred:
|
|
23
|
+
fn.append({"text": item[0], "label": item[1], "sentence": row["text"]})
|
|
24
|
+
|
|
25
|
+
summary = {
|
|
26
|
+
"n": data["n"],
|
|
27
|
+
"score": data["score"],
|
|
28
|
+
"gold_by_label": dict(gold_count),
|
|
29
|
+
"pred_by_label": dict(pred_count),
|
|
30
|
+
"fp_by_label": dict(Counter(x["label"] for x in fp)),
|
|
31
|
+
"fn_by_label": dict(Counter(x["label"] for x in fn)),
|
|
32
|
+
"fp_samples": fp[:20],
|
|
33
|
+
"fn_samples": fn[:20],
|
|
34
|
+
}
|
|
35
|
+
json.dump(summary, open(out, "w", encoding="utf-8"), ensure_ascii=False, indent=2)
|
|
36
|
+
print(json.dumps({k: v for k, v in summary.items() if not k.endswith("samples")}, ensure_ascii=False, indent=2))
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
import sys
|
|
4
|
+
|
|
5
|
+
MAP = {
|
|
6
|
+
"name": "PERSON",
|
|
7
|
+
"address": "PLACE",
|
|
8
|
+
"scene": "PLACE",
|
|
9
|
+
"company": "ORG",
|
|
10
|
+
"organization": "ORG",
|
|
11
|
+
"government": "ORG",
|
|
12
|
+
"book": "WORK",
|
|
13
|
+
"movie": "WORK",
|
|
14
|
+
"game": "WORK",
|
|
15
|
+
"position": "ROLE",
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def coarse(label):
|
|
20
|
+
return MAP.get(label, label)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
data = json.load(open(sys.argv[1], encoding="utf-8"))
|
|
24
|
+
tp = fp = fn = 0
|
|
25
|
+
for row in data["rows"]:
|
|
26
|
+
gold = {(g["entity"], coarse(g["label"])) for g in row["gold"]}
|
|
27
|
+
pred = {(p["text"].replace(" ", ""), coarse(p["label"])) for p in row["pred"]}
|
|
28
|
+
tp += len(gold & pred)
|
|
29
|
+
fp += len(pred - gold)
|
|
30
|
+
fn += len(gold - pred)
|
|
31
|
+
precision = 0 if tp + fp == 0 else tp / (tp + fp)
|
|
32
|
+
recall = 0 if tp + fn == 0 else tp / (tp + fn)
|
|
33
|
+
f1 = 0 if precision + recall == 0 else 2 * precision * recall / (precision + recall)
|
|
34
|
+
print(json.dumps({
|
|
35
|
+
"n": data["n"],
|
|
36
|
+
"exact_label_f1": data["score"]["f1"],
|
|
37
|
+
"coarse_slot": {"tp": tp, "fp": fp, "fn": fn, "precision": round(precision, 4), "recall": round(recall, 4), "f1": round(f1, 4)},
|
|
38
|
+
}, ensure_ascii=False, indent=2))
|