面向家庭的本地化健康数据管理平台。把散落的 PDF、影像、化验单组织成可索引、可检索、可提醒的个人档案——全部在你自己的机器上,不上传任何原始数据。
不是电子病历、诊断工具或云服务;是把家庭健康文件目录变成可查询数据库的一组工具链,首页直观展示「未来 6 个月要做什么复查」。
PDF / 图片 / Markdown
│ (soma ingest) OCR 派发
▼
all-in-one.data.json 目录级 OCR 汇总
│ (soma llm-extract) LLM 结构化
▼
summary.data.json labs / medications / findings / events / guidance
│ (soma reindex) 索引入 SQLite
▼
SQLite ──► FastAPI ──► Next.js UI / iCal 导出 / CLI 查询
两条硬约束贯穿始终:
- 源文件只读:annotate / ingest / llm-extract 永远只新增
.meta.yaml/.data.json/_ai/summary.md,绝不修改或删除原文件。 - 索引库是派生数据:schema 要变就
soma reindex --wipe重建,不写迁移。
组件:
| 组件 | 技术 | 默认端口 |
|---|---|---|
| 后端 API | Python + FastAPI + uvicorn | 8001 |
| 前端 UI | Next.js (React) | 3000 |
| CLI | Python(cli/soma) |
— |
仓库结构:
Soma/
├── backend/ FastAPI + indexer + LLM extractor + pipeline
├── frontend/ Next.js App Router UI
├── cli/soma 统一 CLI 入口
├── scripts/ soma 子命令的实现
├── docs/ 扩展文档(见下方链接)
└── .health/prompts/ AI 摘要 prompt 模板
数据目录(完全独立于代码仓):
$HEALTH_DATA_ROOT/
├── _alice/
│ └── 甲状腺/_alice_2026_04/
│ ├── report.pdf ← 源文件(只读)
│ ├── .meta.yaml ← soma annotate 新增
│ ├── all-in-one.data.json ← soma ingest 新增
│ ├── summary.data.json ← soma llm-extract 新增
│ └── _ai/summary.md ← 可选:soma summarize 新增
└── 2024体检/
└── ...
上述是 inline 布局(默认)。也支持 external 布局把所有 sidecar 挪到 data_root/_soma/ 镜像树,让源目录保持干净——挂到云端时更友好,详见 docs/STORAGE_LAYOUTS.md。
目录命名规范详见 docs/DIRECTORY_CONVENTION.md。
前置:python3 >= 3.11、npm;claude / gemini / codex CLI 任一可选(见 docs/LLM_BACKENDS.md)。
git clone https://github.com/OpenKikCoc/Soma ~/code/Soma
cd ~/code/Soma
./cli/soma init --data-root "/path/to/your/HealthData"soma init 幂等,失败重跑即可。它会:建 .venv/ 并 pip install -e backend/ → npm install 前端依赖 → 写 ~/.config/soma/config.yaml(存 data_root / db_path / code_root)→ 给未标注目录 soma annotate --apply 新增 .meta.yaml → soma reindex 建 SQLite。
把 soma 加到 PATH(后续示例都假设你做了这步):
ln -s ~/code/Soma/cli/soma ~/.local/bin/soma # 确保 PATH 有 ~/.local/bin
# 或
export PATH="$HOME/code/Soma/cli:$PATH" # 写到 ~/.zshrc首次 soma init 之后只有 .meta.yaml——ingest / LLM 尚未触发。第一次 soma run 打开 http://localhost:3000 大概率是人员名字有了、化验/用药/发现全空,首页明显提示:
⚠️ OCR 有缺口 ⚠️ LLM 结构化待更新(0/36)
missing=36 failed=0 fresh=0 · stale=0 · missing=36
跑完整流水线:
soma llm-extract --estimate # 先看看 LLM 会烧多少钱
soma reindex --wipe --force-llm --concurrency 3 --cost-limit 2.0第一条输出形如:
=== 成本预估(model=claude-haiku-4-5)===
扫描目录: 70 需调 LLM: 36 跳过(hash hit): 0
待处理文本量: 801,091 chars
估算 input ~490,545 tokens, output ~122,636 tokens
估算成本: $1.104 (当前 --cost-limit $5.00)
第二条实际执行 ingest → llm-extract → reindex。跑完刷新首页,两张覆盖率卡片应变绿。
加了新文件:丢到数据目录任一位置,soma reindex 增量处理,或 soma watch 前台跑(1.5s 防抖后自动 ingest + reindex)。reindex 会按需跑 ingest(新文件)→ llm-extract(source_hash 变)→ SQLite 重建。
手工校对 OCR 原文:通过 /browse 页的 OcrActions 改完,点 RebuildButton(调 /api/ingest/fast-reindex),或命令行 soma reindex——会检测到 source_hash 变化并重跑 LLM。
重命名/移动目录:所有派生文件都不可重命名,但可以随便加新子目录。确需重组旧目录请先备份再手动处理,Soma 只保证 additive。
全量重建:
soma reindex --wipe --force-llm --concurrency 3 --cost-limit 2.0| flag | 作用 |
|---|---|
--wipe |
清空 SQLite 从零重建(不删数据目录任何文件) |
--force-llm |
无视 source_hash 缓存,重跑所有 LLM,重写 summary.data.json |
--skip-llm |
跳过 LLM 阶段,只重建 SQLite |
--concurrency N |
-j N 同义,N 个 LLM 子进程并发 |
--cost-limit N |
累计 >N USD 就中止派发(默认 5.0) |
换台机器 / 迁移 data_root:config.yaml、index.db、代码仓都是派生物,可丢。把数据目录带走 → 新机器 git clone + soma init --data-root <新路径> → soma reindex --force-llm 重建。把 data_root 搬到 Google Drive 的分步流程见 docs/STORAGE_LAYOUTS.md。
暂时不想跑 LLM:soma reindex --skip-llm——只用目录结构 + .meta.yaml 建 SQLite,前端能看文件树和提醒,但 labs/findings/medications 全空。
启动:soma run(后端 :8001 + 前端 :3000 同时前台运行,Ctrl-C 双杀)。
| 路由 | 用途 |
|---|---|
/ |
家庭总览:OCR / LLM 覆盖率卡 · 临近 5 条提醒 · 成员卡片 |
/people/[slug] |
成员详情:病情档案、生活指导、化验趋势、近期资料 |
/conditions/[id] |
病情详情:提醒时间线、临床发现、用药记录、指导、关联资料 |
/reminders |
所有复查/预约/手术时间轴(按人/窗口过滤;另有 /api/reminders.ics) |
/browse |
文件树 + OcrActions 原地改 OCR + RebuildButton 触发增量重建 |
/summaries |
所有目录的 summary.data.json 列表 |
/coverage |
OCR 覆盖率详情:missing / unknown-kind / failed 文件清单 |
/file?path=... |
单个源文件查看(PDF 嵌入 / 图片 / markdown 渲染) |
右上角 RebuildButton 任意页触发 POST /api/ingest/fast-reindex。
- CLI 参考 — 所有
soma子命令的完整 flag 列表 - 配置 —
config.yaml、本地 overlay、环境变量 - 目录布局与云端备份 —
inlinevsexternal、挂到 Google Drive/iCloud/Dropbox、从本地迁到 Drive 的分步流程 - LLM backend — claude / gemini / codex / api 四种 backend 选择
- 目录规范 — 数据目录命名与结构规范
| 现象 | 处理 |
|---|---|
HEALTH_DATA_ROOT 未配置 |
没跑 soma init 或 ~/.config/soma/config.yaml 不存在。重跑 init,或 export HEALTH_DATA_ROOT=... |
soma: command not found |
没加到 PATH。用 ./cli/soma ...,或见 安装 |
首页 ⚠️ LLM 结构化待更新(0/N) |
正常——提醒跑 LLM。先 soma llm-extract --estimate 看成本,再 soma reindex --force-llm |
首页 ⚠️ OCR 有缺口 |
有文件未被 OCR。点卡片进 /coverage 看 missing/failed 清单 |
claude CLI 不可用 |
没装或不在 PATH。装 Claude Code,或 HEALTH_LLM_BACKEND=gemini_cli/codex_cli,或设 ANTHROPIC_API_KEY 走 SDK |
gemini / codex CLI 不可用 |
对应命令没装或不在 PATH。装完后 gemini --version / codex --version 验证 |
gemini / codex 输出非 JSON |
模型没听 prompt。重跑,或切回 HEALTH_LLM_BACKEND=cli |
累计成本 >$X,停止派发 |
命中 --cost-limit。提高上限或调低 --concurrency |
| 前端 404 / 空 | 后端没起来。curl http://localhost:8001/api/people 确认 |
| DB 里东西不全 | soma llm-extract 让 summary.data.json 齐全,再 soma reindex --wipe |
soma watch 不跑 LLM |
预期行为——避免偶发 save 烧钱。LLM 刷新手动 soma reindex |