phoenixyun64 downloadsObsidian 内完全本地运行的数据自动补全引擎:直接解析 vault 内 Excel/CSV,按报告上下文从真实数据检索候选数值并强制溯源;无外部服务、无 LLM。支持占位符补全、指标缺值波浪线 + 下拉/Tab 补全、语义兜底、手动搜索、备份恢复。
A fully local data autocomplete engine for Obsidian: it parses Excel/CSV files inside your vault and retrieves real values by report context, with forced source tracing. No external services, no LLM, no Python backend — your data never leaves the vault.
isDesktopOnly: true)<vault>/.obsidian/plugins/data-autocomplete/, then enable it in Settings → Community plugins (turn off restricted mode).When writing reports or documents, you often need to fill "metric name + value" into the text. This plugin automates that:
data-autocomplete-data/);本月试驾量为【待补充】), or just write the metric name without a value;NO_RESULT — it never fabricates values.It depends on no external service. Data stays inside the vault and works fully offline.
When you type a placeholder (【待补充】) or a metric name without a value, the plugin runs a 5-stage retrieval state machine — it never invents numbers:

Retrieval priority: EXACT → ALIAS → PARTIAL → SEMANTIC_CANDIDATE → NO_RESULT. Structured hits always win over semantic (AD-21); the semantic fallback is a fully local hash-vector + cosine similarity (256-dim, no model, no network), accepting only strong approximations ≥ 0.5 to prevent weak substring overlaps from creating misleading candidates. All candidate facts come from the real record index, each with file / sheet / row source trace.
Watch a short demo of the plugin in action (placeholder completion, wavy-underline + dropdown, source tracing):
Or download it directly: demo.mp4
data-autocomplete-data/ folder in your vault root and put Excel/CSV files inside (supported layouts:dimension1/dimension2/month/metric/value/metric description…/specific metric/metric description/entity), row 2 date columns (累计值/2026-07月数据/ranking columns), data starts from row 3)<vault>/.obsidian/plugins/data-autocomplete/, then enable it in Settings → Community plugins (turn off restricted mode).Mark missing data with placeholders while writing, for example:
华东区 2026年7月经营数据
本月试驾量为【待补充】,成交量为【待补充】,客流量是【待补充】。
客单价【待补充】,单车毛利为【待补充】,成交率【待补充】。
Run 「分析当前笔记(数据自动补全候选)」 (Ctrl/Cmd+P), and a popup lists every data request:
placeholder / metric_no_value), confidence, metric word, original sentenceEXACT / ALIAS / PARTIAL / NO_RESULT) with explanationNO_RESULT is a normal path: it means there is no matching record in the real data. This plugin never invents numbers.
重建数据索引(解析 vault 内 Excel/CSV) — rebuild the data index分析当前笔记(数据自动补全候选) — analyze the current note for autocomplete candidates数据索引概览 — data index overview手动搜索数据(查询理解 + 排序) — manual search with natural-language query understanding and ranking数据预览:单主体单指标全部历史 — preview all history for one entity + one metric浏览数据:全量明细分页 — browse all records with pagination多表管理:切换活跃数据表 — switch the active data table (each subfolder = one named table)创建数据备份(打包数据目录) — back up the data directory as a zip恢复最新备份 — restore from the latest backup确保数据目录存在(幂等) — ensure the data directory exists (idempotent)一键补全全部占位符(auto/manual/nodata) — fill all placeholders in one pass (auto / manual / nodata)展开省略号为【待补充】占位符 — expand ellipses (。。。/.../……) into placeholdersdata-autocomplete-data (relative to vault root)【 shows a real-data candidate dropdown in place (↑↓ to select, Enter/click to insert and auto-close 】); typing a metric-name prefix (e.g. 成交/本月成交) pops up a metric-name dropdown, Enter completes the name (default on)数据目录/history.jsonl# Engine regression tests against real data (no Obsidian needed, plain node)
node test/engine.test.mjs
Current engine 25 assertions, wavy-mark 9 assertions, dropdown 29 assertions all pass: narrow table 1008 records, hierarchical wide table 498 records, single-entity wide table 10 entities × 20160 records, 21666 real records total / 13 entities / 263 metrics; all 7 placeholders in the sample note hit EXACT real values (试驾量 235.3, 成交量 35.2, 客流量 1086.5, 客单价 301569.4, 单车毛利 42552.6, 成交率 11.2, 总利润 8127), each with file/sheet/row source trace.
npm install # esbuild + xlsx
npm run build # src/main.js → single-file main.js (2.1MB, includes xlsx)
npm run test:engine # engine regression
node test/marks.test.mjs # wavy-mark + Tab chain
node test/dropdown.test.mjs # dropdown decision
Module layout (mirrors the Python pipeline):
parser.js (narrow/hierarchical wide tables) → index.js (in-memory index) → context.js (context/entity/date/metric extraction) → detector.js (placeholder/metric-missing detection) → retrieval.js (EXACT→ALIAS→PARTIAL→NO_RESULT) → engine.js (orchestration, output shaped like the Python /analyze-report).
When structured retrieval (exact/alias/partial) all miss, semantic fallback kicks in:
semantic.js): embed metric "surface names" (canonical name + alias keys) as 256-dim unit vectors via character/bigram hashing; embed the query the same way, compute cosine, take top-3.人数/数量) from creating misleading approximations (外星人数量 always stays NO_RESULT).SEMANTIC_CANDIDATE fallback after EXACT → ALIAS → PARTIAL all fail; candidate facts still come from the real record index (lookupMetric) — never generates values.New status SEMANTIC_CANDIDATE (shown in orange in the popup), retrieval order: EXACT → ALIAS → PARTIAL → SEMANTIC_CANDIDATE → NO_RESULT.
Example: note writes 本月到店人数为【待补充】 → semantic layer hits 进店人数 (0.71) → normalized to 客流量 → returns real value 1086.5 (2026-07, 经营数据-示例.xlsx row 76).
When you type the placeholder 【, a candidate card pops up in place (src/editor/inlineSuggest.js, CodeMirror 6):
Engine.suggest(cursor-prefix) reuses the full pipeline — it automatically combines the note's first line (entity/date title) + the paragraph before the cursor into a query segment, then runs request detection → structured → semantic fallback;↓/↑ to switch candidates, Enter or click inserts the real value and auto-closes 】, Esc closes;value metric@date entity (file:row); status/explanation in the title line (EXACT/ALIAS/PARTIAL/SEMANTIC_CANDIDATE/NO_RESULT).NO_RESULT instead of forcing a number.Toggle in settings (default on). CodeMirror packages are injected by the Obsidian runtime (build.mjs marks them external, not bundled).
MIT License — see LICENSE.