docs: 康记 v1.0 功能设计 spec + CLAUDE.md 工程前提
把原始功能清单收敛为方案 B(核心 5 模块 + Live Activity)。 关键决策:MLX Swift 运行时、结构化 RAG 不做 embedding、 系统级 file protection 不造 AES 轮子、统一拍照合并快拍与归档、 补回 C1/C2 档案库视图、加回报告对比(16.1)。 CLAUDE.md 锁定工程红线供后续 IDE 会话对齐。 Spec 含 6 周时间表、风险预案、与原始清单完整映射。 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
296
CLAUDE.md
Normal file
296
CLAUDE.md
Normal file
@@ -0,0 +1,296 @@
|
||||
# 康记 / 体己 —— 工程前提
|
||||
|
||||
> 这是一个 6 周决赛 demo 项目。今天是 2026-05-25,处于 W1末/W2初。
|
||||
> 任何 IDE/Claude 会话开始干活前,先读这份文件。
|
||||
|
||||
---
|
||||
|
||||
## 1. 产品定位
|
||||
|
||||
- **名字**:康记(对内代号 体己 / Tiji)
|
||||
- **形态**:iOS 原生 App,SwiftUI + SwiftData
|
||||
- **核心卖点**:**100% 本地推理**的个人健康影像档案 + 大白话解读 + 本地 RAG 问答
|
||||
- **目标用户**:不愿把体检/化验报告交给云端的普通人
|
||||
- **明确不做**:医疗诊断、剂量推荐、急诊判断、医生预约、社交、广告、内购、数据上云、账号系统
|
||||
|
||||
---
|
||||
|
||||
## 2. 技术栈 / 选型(已锁定,不要再讨论)
|
||||
|
||||
| 项 | 选型 | 备注 |
|
||||
|---|---|---|
|
||||
| UI | SwiftUI | iOS 17+,用 `@Observable` / `@Model` |
|
||||
| 持久化 | SwiftData | 见 §5 数据模型 |
|
||||
| 图表 | Swift Charts | iOS 16+ 原生 |
|
||||
| **AI 运行时** | **MLX Swift (Apple 官方)** | 不要建议 Core ML / llama.cpp / Ollama |
|
||||
| LLM | Qwen3-1.7B (MLX 4bit 量化) | ~1.0GB,负责文本生成、关键词抽取、趋势解读 |
|
||||
| VL | Qwen2.5-VL-3B (MLX 4bit 量化) | ~2.0GB,负责拍照→结构化指标 |
|
||||
| 文档扫描 | VisionKit `VNDocumentCameraView` | 不要自己写透视校正 |
|
||||
| Face ID | LocalAuthentication | |
|
||||
| Live Activity | ActivityKit + WidgetExtension | demo 杀手锏,真机才能测 |
|
||||
|
||||
**不引入**:任何云服务 SDK、任何 embedding 模型(RAG 用结构化检索,不用语义)、任何账号系统、任何分析 SDK。
|
||||
|
||||
---
|
||||
|
||||
## 3. AI 链路核心规则
|
||||
|
||||
### 3.1 模块边界(强制)
|
||||
|
||||
```
|
||||
UI → CaptureService / AskService / TrendService → AIRuntime → MLX
|
||||
↓
|
||||
Persistence
|
||||
```
|
||||
|
||||
- **UI 永远不直接调 `AIRuntime`**。所有 AI 调用必须经过 `*Service` 层,这样 UI 可以注入 mock、可以预览。
|
||||
- **`AIRuntime` 是 `actor` 单例,串行化**。同一时刻只允许一个推理任务,MLX 共享显存,并发会 OOM。CaptureService 拍照时如果 AskService 正在流式生成,要在队列里排队。
|
||||
- **`*Service` 不直接读写 SwiftData 主上下文**。要么传入 `ModelContext`,要么走 ServiceLocator,方便测试。
|
||||
|
||||
### 3.2 VL pipeline(拍一张 = 一条流程)
|
||||
|
||||
**重要**:快拍(1.x) 和 报告归档(2.x) 已经合并成统一 `CaptureService`,UI 不再有 A1-A3 和 B1-B4 两条独立路径。流程:
|
||||
|
||||
```
|
||||
拍照 → 写 Vault(加密目录) → VL 推理(要求输出 JSON,含 kind=single|report)
|
||||
→ 解析容错(失败回退到手动录入,不卡死)
|
||||
→ 单项走 A2ConfirmView,整份走 B3MetaView
|
||||
→ 保存到 Indicator/Report + 关联 Asset
|
||||
```
|
||||
|
||||
VL prompt 必须:
|
||||
- 明确要求"只输出 JSON,不要解释"
|
||||
- 带 2 个 few-shot 示例(单项 + 多项)
|
||||
- 异常状态由 VL 模型基于参考范围直接判断,不要再二次调用 LLM
|
||||
|
||||
### 3.3 RAG(结构化检索,不做 embedding)
|
||||
|
||||
**两段式调用**:
|
||||
1. 用 Qwen3-1.7B 抽取意图 + 关键词,输出 JSON `{indicators, time_range, intent}`,~50 token,<1s
|
||||
2. SwiftData 按关键词检索 ≤ 10 条记录,拼 `ChatRAG` prompt,流式生成回答
|
||||
|
||||
**第 1 步失败时**回退到"近 30 天全表扫描",不卡死。
|
||||
**引用回链**:回答中 `[1][2]` 后处理为可点击 Pill,点击跳源记录详情。
|
||||
|
||||
### 3.4 Live Activity
|
||||
|
||||
- VL 推理 / RAG 生成开始时启动 Activity
|
||||
- 每 0.5s 通过 `AIRuntime.lastDecodeRate` 推送 tok/s
|
||||
- 推理完成保留 2s 显示"已完成 · 0.8s"再 dismiss
|
||||
- **只能真机测**,模拟器不显示。W5 末预留时间。
|
||||
|
||||
---
|
||||
|
||||
## 4. 模型分发
|
||||
|
||||
- 模型放 `Application Support/Models/`,首启动用 `URLSession.downloadTask` 拉,带断点续传 + 进度条
|
||||
- 总体积 ~3GB,WiFi 提示必须有
|
||||
- App 在模型未就绪时**仍可启动**,但所有 AI 入口显示"模型未就绪,前往下载"
|
||||
- `ModelStore` 必须提供**旁路接口**:允许把模型预拷进沙盒(demo 现场重装时用)
|
||||
|
||||
---
|
||||
|
||||
## 5. 数据模型(SwiftData)
|
||||
|
||||
现有 3 个 `@Model`,要新增 2 个:
|
||||
|
||||
```swift
|
||||
// 已有(在 Models/Models.swift)
|
||||
@Model class Indicator { name, value, unit, range, statusRaw, note, capturedAt }
|
||||
@Model class Report { title, typeRaw, reportDate, institution, note, summary, pageCount, createdAt }
|
||||
@Model class DiaryEntry { content, createdAt }
|
||||
|
||||
// 待加字段
|
||||
// Indicator + report: Report? 反向关系
|
||||
// Indicator + asset: Asset? 关联原图
|
||||
// Indicator + pinned: Bool C2 "关联到趋势" 后置 true,Trends 默认展示 pinned 指标
|
||||
// Report + indicators: [Indicator] @Relationship cascade
|
||||
// Report + assets: [Asset] @Relationship cascade
|
||||
// DiaryEntry + tags: [String] VL/LLM 抽取的标签
|
||||
|
||||
// 待加 @Model
|
||||
@Model class Asset {
|
||||
var relativePath: String // 相对 Vault/ 的路径
|
||||
var mimeType: String
|
||||
var bytes: Int
|
||||
var createdAt: Date
|
||||
}
|
||||
|
||||
@Model class ChatTurn {
|
||||
var question: String
|
||||
var answer: String
|
||||
var referencedIndicatorIDs: [String]
|
||||
var referencedReportIDs: [String]
|
||||
var createdAt: Date
|
||||
var decodeRate: Double // 该轮问答推理速度,Me 页性能展示
|
||||
}
|
||||
```
|
||||
|
||||
**原图存储**: `Asset` 只存元数据 + 相对路径,真实 JPEG 落在 `Application Support/Vault/`,目录用 `.completeFileProtection`(iOS 硬件级加密,不要自己造 AES 轮子)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 安全 / 隐私(已收敛 — 不要扩展)
|
||||
|
||||
| 做 | 不做 |
|
||||
|---|---|
|
||||
| `Application Support/Vault/` 全目录 `.completeFileProtection` | 自实现 AES 加密 |
|
||||
| SwiftData store 文件 `.completeFileProtection` | |
|
||||
| Face ID 启动锁(可选开关,默认关) | |
|
||||
| 永久删除(SwiftData 硬删 + Asset 文件 unlink) | |
|
||||
| 离线运行(自然结果,不用单独做) | |
|
||||
| | 截屏黑屏防护(iOS 没有官方 API,不做) |
|
||||
| | 加密 ZIP 导出 |
|
||||
|
||||
唯一的"导出"是 **9.4 分享文字摘要**(只分享解读文本,不带原图)。
|
||||
|
||||
---
|
||||
|
||||
## 7. 信息架构
|
||||
|
||||
```
|
||||
TabBar: [首页] [+ 记录] [趋势] [我的]
|
||||
│ │ │ │
|
||||
│ │ │ └─ 模型管理 / Face ID / 关于
|
||||
│ │ └─ 折线图 + AI 一句话解读
|
||||
│ └─ Modal: 选择 拍一张 / 写日记 / 问问看
|
||||
└─ 问候 + 今日摘要 + 时间线 + 影像档案入口
|
||||
```
|
||||
|
||||
- **3 Tab 不变**,中间 + 号是 Sheet
|
||||
- AI 问答以 Modal Sheet 形式出现,**不占 Tab**
|
||||
- "问问看"入口除了在 RecordSheet 里,首页摘要卡片下方也有一个常驻入口
|
||||
- 历史时间线在首页下半部分,不单独开 Tab
|
||||
|
||||
### 7.1 档案库 C1 / C2 导航(看的一半)
|
||||
|
||||
录入流程(拍照→VL→编辑→存)只是"录的一半"。**"看的一半"由 C1 列表 + C2 详情承担**——这是 demo 的核心看点之一,不能砍。
|
||||
|
||||
```
|
||||
首页 "我的报告档案" 卡 ──push──► C1 ArchiveListView
|
||||
│
|
||||
│ 分类 chip:全部/体检/化验/影像/处方
|
||||
│ 按 reportDate 年份分组,卡片显示异常 chip
|
||||
│
|
||||
└──push──► C2 ReportDetailView
|
||||
│
|
||||
├─ Tab "原图":TabView(.page) 翻页 + 长按保存
|
||||
├─ Tab "解读":数字摘要(总/高/低/正常)
|
||||
│ + AI 整体摘要
|
||||
│ + 对比上次(同类型上一份 Report diff)
|
||||
└─ Tab "指标":Indicator 列表,异常优先
|
||||
|
||||
C2 底部两个动作:
|
||||
├─ "关联到趋势" ──► 把本报告内未 pinned 的 Indicator 批量 pinned = true,Trends 默认展示
|
||||
└─ "重新解读" ──► CaptureService.reanalyze(report:),重跑 VL 覆盖 summary/indicators
|
||||
|
||||
其他进入 C2 的入口:
|
||||
• ChatTurn 引用 Pill 点击(referencedReportIDs)
|
||||
• 趋势页数据点 tap → 跳到该点来源 Report 的 C2
|
||||
• HomeView 时间线点报告类条目
|
||||
```
|
||||
|
||||
### 7.2 对比上次("对比上次"=报告对比,已加回)
|
||||
|
||||
C2 解读 Tab 底部显示一段 diff 文本,**由 `ReportCompareService` 计算,不再调 LLM**:
|
||||
|
||||
- 找出"同 `typeRaw` 的上一份 Report"(`reportDate < current AND ORDER BY DESC LIMIT 1`)
|
||||
- 同名 `Indicator` 配对,数值 diff:`Δ` 绝对值 + 百分比 + 升/降箭头
|
||||
- 标红:跨越参考范围边界(原本正常→偏高,或反过来)
|
||||
- 文案模板拼装,不走 LLM,响应即时
|
||||
- 若无上一份,该区块隐藏
|
||||
|
||||
---
|
||||
|
||||
## 8. 现有代码状态(2026-05-25)
|
||||
|
||||
```
|
||||
体己/
|
||||
├── App/TijiApp.swift ✅ SwiftData container 已建
|
||||
├── RootView.swift ✅ 3 Tab + RecordSheet 已建
|
||||
├── Models/Models.swift ✅ Indicator / Report / DiaryEntry,缺 Asset / ChatTurn
|
||||
├── DesignSystem/ ✅ Tokens + Components,沿用
|
||||
└── Features/
|
||||
├── Home/ ✅ HomeView 静态 UI,数据未接
|
||||
├── Quick/A1-A3 🔧 待合并进 UnifiedCaptureFlow
|
||||
├── Archive/B1-B4 🔧 B1 砍,B2 改用 VisionKit DocumentCamera
|
||||
├── Record/RecordSheet ✅ 入口选择 UI
|
||||
├── Trends/ ❌ 只有 placeholder
|
||||
└── Me/ ❌ 只有 placeholder
|
||||
|
||||
待建:
|
||||
├── AI/ ❌ AIRuntime, LLMSession, VLSession, Prompts/
|
||||
├── Services/ ❌ CaptureService, AskService, TrendService, ReportCompareService
|
||||
├── Persistence/FileVault.swift ❌ 原图加密目录管理
|
||||
├── Security/AppLock.swift ❌ Face ID 启动锁
|
||||
├── Features/Ask/ ❌ AskSheet (RAG 问答 UI)
|
||||
├── Features/Archive/
|
||||
│ ├── ArchiveListView ❌ C1 档案列表(分类 chip + 年份分组)
|
||||
│ └── ReportDetailView ❌ C2 报告详情(三 Tab:原图/解读/指标 + 对比上次)
|
||||
├── Features/Capture/
|
||||
│ └── UnifiedCaptureFlow ❌ 替代 QuickCaptureFlow,状态机驱动 A1→VL→A2/B3
|
||||
├── Features/Onboarding/ ❌ 首启动隐私承诺 + 模型下载
|
||||
└── LiveActivity/ ❌ WidgetExtension target
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 设计系统约束
|
||||
|
||||
- **不要新增颜色 token**。所有颜色走 `Tj.Palette.*` (sand / paper / ink / brick / leaf / line / text / text3)
|
||||
- **不要新增字体大小**。走 `Font.tjTitle()` / `tjH2()` / `tjSerifBody()` / 系统 size
|
||||
- **圆角走 `Tj.Radius.*`**,卡片走 `.tjCard()` modifier
|
||||
- 按钮走 `TjPrimaryButton` / `TjGhostButton`
|
||||
|
||||
新加 View 时先看 `DesignSystem/Components.swift`,有现成的不要复刻。
|
||||
|
||||
---
|
||||
|
||||
## 10. 不能跨越的红线
|
||||
|
||||
写代码前必读:
|
||||
|
||||
1. **不引入云服务**——任何 SDK 都不行,包括崩溃上报、分析、灰度
|
||||
2. **不自己实现密码学**——`.completeFileProtection` 已经够
|
||||
3. **UI 不直接调 AIRuntime**——必须经过 Service
|
||||
4. **AIRuntime 必须 actor 化**——禁止 class + lock
|
||||
5. **VL/LLM prompt 必须有 few-shot + 失败回退**——不能让用户卡在 AI 错误屏
|
||||
6. **新功能必须问"清单里有吗"**——清单外的功能(用药提醒、多 profile、暗黑模式、iCloud 同步……)默认不做,要做必须先讨论。**例外**:报告对比(16.1)已加回,见 §7.2
|
||||
7. **不要在 6 周里重构现有 Tab/RecordSheet 骨架**——增量加东西,不要推倒重来
|
||||
8. **报告详情(C2)与归档元信息编辑(B3)是两个 View**——B3 是 draft 编辑(写),C2 是 detail 浏览(读),不要合并复用主框架
|
||||
|
||||
---
|
||||
|
||||
## 11. 6 周时间表
|
||||
|
||||
| 周次 | 必交付 |
|
||||
|---|---|
|
||||
| W1 末 / **W2 当前** | 项目结构、MLX 跑通 Qwen3-1.7B、首个 token 在设备吐出 |
|
||||
| W2-W3 | AIRuntime + LLMSession,文字日记 + 基础 RAG 问答(打字机效果) |
|
||||
| W3-W4 | VLSession + 统一拍照流程(单项 + 整份)、Asset / FileVault |
|
||||
| W4 末 | **C1 ArchiveListView**(分类 chip + 年份分组,接 @Query) |
|
||||
| W4-W5 | 趋势(Swift Charts + AI 解读)、**C2 ReportDetailView**(三 Tab + 重新解读) |
|
||||
| W5 中 | **ReportCompareService** + C2 解读 Tab "对比上次" 区块 |
|
||||
| W5 末 | Face ID、永久删除、首页时间线接入真数据、Live Activity(真机) |
|
||||
| W6 | 模型管理页、首启动下载流程、UI polish、demo 视频、PPT |
|
||||
|
||||
**P0 新增项**(从 C 区视觉稿补回):C1 档案列表、C2 报告详情三 Tab、对比上次、关联到趋势、重新解读
|
||||
|
||||
**P1**(必须做完):Live Activity、分享文字摘要(9.4)、首启动隐私承诺页
|
||||
|
||||
**P2**(余力做):—— 任何 P2/P3 都暂时不做,清单里 11/12/13/14/15/17/18/19 全部 deferred(注意:16.1 报告对比已升 P0)
|
||||
|
||||
**砍 P1 决策顺序**(任何一周延期触发):Live Activity → Onboarding 简化 → 分享摘要 → 模型管理页 polish。**绝不动 C1/C2/对比上次**——视觉稿都做了,demo PPT 也要展示,这是核心卖点之一。
|
||||
|
||||
---
|
||||
|
||||
## 12. 评委 PPT 卖点排序(写代码时记住为什么这么做)
|
||||
|
||||
1. 影像档案系统(统一 VL 拍照 + 归档) — 核心创意
|
||||
2. 100% 本地 + SME2 加速 — 技术亮点
|
||||
3. 本地 RAG 长期记忆 — 端侧不可替代性
|
||||
4. 隐私三件套(系统级加密 + Face ID + 永久删除) — 信任建立
|
||||
5. AI 趋势解读 — 长期价值
|
||||
6. Live Activity 实时 tok/s — 现场记忆点
|
||||
|
||||
每写一个功能,问自己:这条提升了上面哪一项?如果都没有,就别做。
|
||||
641
docs/superpowers/specs/2026-05-25-kangji-features-design.md
Normal file
641
docs/superpowers/specs/2026-05-25-kangji-features-design.md
Normal file
@@ -0,0 +1,641 @@
|
||||
# 康记 / 体己 —— 功能设计 Spec(v1.0)
|
||||
|
||||
**日期**:2026-05-25
|
||||
**状态**:Draft, 已与产品方对齐 §1-§6
|
||||
**关联**:[CLAUDE.md](../../../CLAUDE.md) 工程前提
|
||||
|
||||
---
|
||||
|
||||
## 0. 概要
|
||||
|
||||
康记是一个 iOS 原生健康影像档案 App,**100% 端侧 AI 推理**,基于 SwiftUI + SwiftData + MLX Swift,目标 6 周交付决赛 demo。本 spec 把原始功能清单收敛为 **方案 B**:核心 5 模块 + Live Activity + 分享摘要,其余 P2/P3 全部 deferred。
|
||||
|
||||
**5 大核心模块**
|
||||
|
||||
1. 统一拍照(合并原 1.x 异常项快拍 + 2.x 关键报告归档)
|
||||
2. 文字日记
|
||||
3. 本地 RAG 问答(结构化检索)
|
||||
4. 趋势分析(Swift Charts + AI 一句话解读)
|
||||
5. 影像档案库 C1 列表 + C2 详情(看的一半)
|
||||
|
||||
**附加 P1**:Live Activity(demo 杀手锏)、分享文字摘要、首启动 Onboarding、Face ID + 永久删除
|
||||
|
||||
---
|
||||
|
||||
## 1. 整体架构
|
||||
|
||||
### 1.1 模块分层
|
||||
|
||||
```
|
||||
UI 层 (SwiftUI)
|
||||
│
|
||||
├─ Tab: Home / Trend / Me
|
||||
├─ Modal Sheet: RecordSheet → UnifiedCaptureFlow / DiaryComposer / AskSheet
|
||||
└─ Navigation: ArchiveListView → ReportDetailView
|
||||
│
|
||||
▼
|
||||
*Service 层
|
||||
├─ CaptureService // 拍照 → VL → draft → commit
|
||||
├─ AskService // 两段式 RAG
|
||||
├─ TrendService // 聚合 + AI 解读
|
||||
└─ ReportCompareService // 同类型上一份报告 diff(纯模板,不调 LLM)
|
||||
│
|
||||
▼
|
||||
AIRuntime (actor 单例)
|
||||
├─ LLMSession (Qwen3-1.7B, 流式)
|
||||
└─ VLSession (Qwen2.5-VL-3B, 单次)
|
||||
│
|
||||
▼
|
||||
Persistence
|
||||
├─ SwiftData (Indicator / Report / DiaryEntry / Asset / ChatTurn)
|
||||
└─ FileVault (Application Support/Vault/, .completeFileProtection)
|
||||
```
|
||||
|
||||
### 1.2 模块职责与边界
|
||||
|
||||
| 模块 | 干什么 | 不干什么 |
|
||||
|---|---|---|
|
||||
| **UI** | View + ViewModel,组织展示 | 不直接调 MLX,不读写文件 |
|
||||
| **CaptureService** | 拍一张全流程:`UIImage → VL prompt → 结构化 JSON → 存盘 + Indicator/Report` | 不管 UI 状态机 |
|
||||
| **AskService** | RAG:`query → SwiftData 关键词检索 → 拼 prompt → 流式输出 → 引用回链` | 不管对话历史展示样式 |
|
||||
| **TrendService** | 按指标名/时间范围聚合数据,生成 Chart 数据点 + LLM 一句话解读 | 不画图表 |
|
||||
| **ReportCompareService** | 找上一份同类型 Report,逐指标 diff,模板拼装 | 不调 LLM |
|
||||
| **AIRuntime** | MLX 模型加载/卸载/推理,actor 单例,串行化推理 | 不懂业务 |
|
||||
| **Persistence** | SwiftData 持久化 + FileVault 原图加密目录 + 永久删除 | 不懂 AI |
|
||||
|
||||
### 1.3 强制规则(违反即反 spec)
|
||||
|
||||
- **UI 永远不直接调 `AIRuntime`**——必须经过 Service 中转,这样 UI 可注入 mock、可预览
|
||||
- **`AIRuntime` 必须 actor**——同一时刻只允许一个推理任务,MLX 共享显存,并发会 OOM
|
||||
- **`*Service` 不直接读写 SwiftData 主上下文**——传入 `ModelContext` 或走 ServiceLocator
|
||||
- **B3 写,C2 读,不要合并主框架**——B3 是 draft 编辑(写入路径),C2 是 detail 浏览(读取路径)
|
||||
|
||||
---
|
||||
|
||||
## 2. AI 链路
|
||||
|
||||
### 2.1 `AIRuntime` 接口
|
||||
|
||||
```
|
||||
体己/AI/
|
||||
├── AIRuntime.swift // actor 单例,推理串行化
|
||||
├── ModelStore.swift // 模型路径管理 + 下载 + bundle 旁路
|
||||
├── LLMSession.swift // Qwen3-1.7B 文本生成,流式
|
||||
├── VLSession.swift // Qwen2.5-VL-3B 图像理解,单次
|
||||
└── Prompts/
|
||||
├── VLExtraction.swift // 拍照解析(含 few-shot)
|
||||
├── KeywordExtraction.swift // RAG 第一步
|
||||
├── ChatRAG.swift // RAG 第二步
|
||||
└── TrendNarrative.swift // 趋势一句话解读
|
||||
```
|
||||
|
||||
```swift
|
||||
actor AIRuntime {
|
||||
static let shared = AIRuntime()
|
||||
|
||||
enum Status { case notReady, downloading(Double), loading, ready, error(String) }
|
||||
private(set) var status: Status = .notReady
|
||||
|
||||
func prepare() async throws
|
||||
func generate(prompt: String, maxTokens: Int) -> AsyncThrowingStream<TokenChunk, Error>
|
||||
func analyze(image: UIImage, instruction: String) async throws -> String
|
||||
var lastDecodeRate: Double { get }
|
||||
}
|
||||
|
||||
struct TokenChunk {
|
||||
let text: String
|
||||
let decodeRate: Double
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 模型分发
|
||||
|
||||
| 项 | 决策 |
|
||||
|---|---|
|
||||
| 模型来源 | HuggingFace MLX 社区版 Qwen3-1.7B-MLX-4bit + Qwen2.5-VL-3B-MLX-4bit |
|
||||
| 体积 | LLM ~1.0GB + VL ~2.0GB ≈ 3GB |
|
||||
| 存储 | `Application Support/Models/`,`URLSession.downloadTask` + 断点续传 |
|
||||
| 首启动 | 启动屏 → 隐私承诺 → "下载模型"页(进度 + WiFi 提示) → 主界面 |
|
||||
| 旁路 | `ModelStore.seedModelsFromBundle()`,demo 现场预装机用 |
|
||||
| 模型缺失 | App 可启动,AI 入口显示"模型未就绪,前往下载" |
|
||||
|
||||
### 2.3 VL Pipeline:拍一张统一流程
|
||||
|
||||
```
|
||||
拍照 (UIImage)
|
||||
│
|
||||
▼ Step 1 预处理 (CaptureService)
|
||||
- 缩放到 ≤ 1024 长边
|
||||
- 写 Vault 作为 Asset(加密)
|
||||
│
|
||||
▼ Step 2 VL 解析 (AIRuntime.analyze)
|
||||
- VLExtraction prompt 要求输出 JSON
|
||||
- 期望 { kind: "single"|"report", items: [...], summary: "..." }
|
||||
│
|
||||
▼ Step 3 解析容错
|
||||
- JSONDecoder + 宽松正则兜底
|
||||
- 失败 → A2/B3 字段为空,提示"识别不完整,请手动补充"
|
||||
│
|
||||
▼ Step 4 确认页
|
||||
- kind=single → A2ConfirmView(单项 + 一句话)
|
||||
- kind=report → B3MetaView(指标列表 + 整体摘要,异常优先)
|
||||
- 所有字段可编辑
|
||||
│
|
||||
▼ Step 5 保存
|
||||
- draft → commit,事务写入 Indicator + Report + Asset
|
||||
```
|
||||
|
||||
**VL prompt 要点**
|
||||
- 明确"只输出 JSON,不要解释"
|
||||
- 带 2 个 few-shot 示例(单项 + 多项)
|
||||
- 异常状态由 VL 基于参考范围直接判断
|
||||
- **不能让用户卡在错误屏**——失败回退到手动录入
|
||||
|
||||
### 2.4 RAG:结构化检索 + LLM 生成(不做 embedding)
|
||||
|
||||
```
|
||||
用户问句
|
||||
│
|
||||
▼ Step 1 关键词抽取 (Qwen3-1.7B, ~50 token, <1s)
|
||||
{ indicators: [...], time_range: {days: 90}, intent: "trend"|"value"|"diary" }
|
||||
│
|
||||
▼ Step 2 SwiftData 检索 (AskService)
|
||||
- 按 indicators 模糊匹配 Indicator.name
|
||||
- 按 time_range 过滤 capturedAt
|
||||
- intent=diary 时检索 DiaryEntry.content
|
||||
- 返回 ≤ 10 条 + 引用 ID
|
||||
│
|
||||
▼ Step 3 拼 ChatRAG prompt
|
||||
- System: 不诊断、不建议就医、只描述数据
|
||||
- Context: 检索结果, 每条编号 [1]-[n]
|
||||
- User: 原始问句
|
||||
│
|
||||
▼ Step 4 流式生成 (LLMSession.generate)
|
||||
- UI 打字机效果
|
||||
- 顶部小字: "本机推理中 · 24.3 tok/s"
|
||||
│
|
||||
▼ Step 5 引用回链
|
||||
- [1][2] 后处理为可点击 Pill
|
||||
- 点击 → 跳 Indicator/Report C2 详情
|
||||
- 整轮存 ChatTurn(referencedIDs + decodeRate)
|
||||
```
|
||||
|
||||
**Step 1 失败回退**:近 30 天全表扫描,不卡死。
|
||||
**Step 5 跨页跳转**:Report 引用走 ReportDetailView,Indicator 引用走 Trends 高亮该点。
|
||||
|
||||
### 2.5 Live Activity
|
||||
|
||||
| 项 | 决策 |
|
||||
|---|---|
|
||||
| 触发 | VL 推理 / RAG 生成开始 |
|
||||
| 显示 | "Qwen2.5-VL · 24.3 tok/s" / "本机问答中 · 22.1 tok/s" |
|
||||
| 实现 | ActivityKit + WidgetExtension target,`AIRuntime.lastDecodeRate` 每 0.5s `Activity.update` |
|
||||
| 结束 | 完成后保留 2s "已完成 · 0.8s" 再 dismiss |
|
||||
| 真机限定 | 模拟器不支持,W5 末预留 1d 真机调试 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 数据流与数据模型
|
||||
|
||||
### 3.1 SwiftData @Model 全集
|
||||
|
||||
```swift
|
||||
@Model final class Indicator {
|
||||
var name: String
|
||||
var value: String // 字符串,允许 ">10" "阴性" 等非数值
|
||||
var unit: String
|
||||
var range: String
|
||||
var statusRaw: String // "high" | "low" | "normal"
|
||||
var note: String?
|
||||
var capturedAt: Date
|
||||
|
||||
var report: Report? // 反向关系,nil 表示单项快拍
|
||||
var asset: Asset?
|
||||
var pinned: Bool = false // C2 "关联到趋势" 置 true
|
||||
}
|
||||
|
||||
@Model final class Report {
|
||||
var title: String
|
||||
var typeRaw: String
|
||||
var reportDate: Date
|
||||
var institution: String?
|
||||
var note: String?
|
||||
var summary: String? // VL 100 字摘要
|
||||
var pageCount: Int
|
||||
var createdAt: Date
|
||||
|
||||
@Relationship(deleteRule: .cascade, inverse: \Indicator.report)
|
||||
var indicators: [Indicator] = []
|
||||
@Relationship(deleteRule: .cascade)
|
||||
var assets: [Asset] = []
|
||||
}
|
||||
|
||||
@Model final class DiaryEntry {
|
||||
var content: String
|
||||
var createdAt: Date
|
||||
var tags: [String] = [] // VL/LLM 抽取
|
||||
}
|
||||
|
||||
@Model final class Asset {
|
||||
var relativePath: String
|
||||
var mimeType: String
|
||||
var bytes: Int
|
||||
var createdAt: Date
|
||||
}
|
||||
|
||||
@Model final class ChatTurn {
|
||||
var question: String
|
||||
var answer: String
|
||||
var referencedIndicatorIDs: [String]
|
||||
var referencedReportIDs: [String]
|
||||
var createdAt: Date
|
||||
var decodeRate: Double
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 SwiftData migration
|
||||
|
||||
- **W2-W4**:破坏性迁移,改 schema 就删模拟器沙盒。不要写 `VersionedSchema`
|
||||
- **W5 起**:冻结 schema。需要改 → 写 `SchemaMigrationPlan`,只允许加字段
|
||||
- **demo 翻车**:启动检测不兼容 → 弹"数据格式更新,需重建" → 删库重启。**绝不静默丢数据**
|
||||
|
||||
### 3.3 FileVault
|
||||
|
||||
```swift
|
||||
final class FileVault {
|
||||
static let shared = FileVault()
|
||||
private let vaultURL: URL // Application Support/Vault/
|
||||
|
||||
func writeJPEG(_ image: UIImage, quality: CGFloat = 0.85) throws -> (relativePath: String, bytes: Int)
|
||||
func loadImage(relativePath: String) throws -> UIImage
|
||||
func remove(relativePath: String) throws
|
||||
func wipe() throws
|
||||
}
|
||||
```
|
||||
|
||||
- 目录 `.completeFileProtection`,iOS 硬件级加密
|
||||
- 不做版本管理、不做去重、不做缩略图缓存(YAGNI)
|
||||
- 屏幕锁定时文件不可读 → AI 入口本来就由 Face ID 拦,业务上不冲突
|
||||
|
||||
### 3.4 拍照→保存时序
|
||||
|
||||
```
|
||||
User → UI(B2Scan) → CaptureService → AIRuntime → Persistence
|
||||
│ openCamera
|
||||
│ ◄── images[]
|
||||
│ analyze(images)
|
||||
│ writeJPEG × N
|
||||
│ ─────────────────────────► Assets stored
|
||||
│ analyze(image1) ──► MLX VL
|
||||
│ ◄── JSON
|
||||
│ (repeat for img2…)
|
||||
│ ◄── draft (Report + Indicators in-memory)
|
||||
│ edit + save
|
||||
│ commit ──────────────────► Report + Indicators
|
||||
│ ◄── reportID
|
||||
```
|
||||
|
||||
- N 页 VL 推理**串行**(AIRuntime 串行化),UI 显示 "第 k/N 页解析中" + 取消按钮
|
||||
- draft 阶段 SwiftData 未提交,用户取消则 Asset 一并回滚
|
||||
|
||||
---
|
||||
|
||||
## 4. UI 改造与新建清单
|
||||
|
||||
### 4.1 现有视图改造
|
||||
|
||||
| 文件 | 改造 | 工作量 |
|
||||
|---|---|---|
|
||||
| `RootView` | RecordSheet 加"问问看";首页常驻"问问看"入口 | 0.5d |
|
||||
| `HomeView` | `@Query` 接真数据,时间线 5 条,"今日摘要"接 `TrendService.dailyDigest()`,影像档案入口数量 | 1.5d |
|
||||
| `Quick/A1Viewfinder` | 改用 `VNDocumentCameraView` 单张模式 | 0.5d |
|
||||
| `Quick/A2Confirm` | 接 Indicator draft,字段可编辑,显示一句话解读 | 1d |
|
||||
| `Quick/A3Batch` | **复用为整份报告指标列表**,异常优先 | 1d |
|
||||
| `Quick/QuickCaptureFlow` | 改为 `UnifiedCaptureFlow`,kind 分叉 | 1d |
|
||||
| `Archive/B1Guide` | **砍** | -0.5d |
|
||||
| `Archive/B2Scan` | 改用 VNDocumentCameraView 多页 | 0.5d |
|
||||
| `Archive/B3Meta` | 接 Report draft + AI 摘要 + 共用 A3 指标列表 | 1d |
|
||||
| `Archive/B4Progress` | "第 k/N 页"+ 取消,绑 AIRuntime 队列 | 1d |
|
||||
| `Trends/TrendsView` | 全新(见 4.2) | 3d |
|
||||
| `Me/MeView` | 模型管理 + Face ID + 永久删除 + 关于 | 2d |
|
||||
| `Record/RecordSheet` | 四入口 | 0.5d |
|
||||
| `Models/Models.swift` | 加 Asset / ChatTurn + 字段 | 0.5d |
|
||||
|
||||
### 4.2 新建视图
|
||||
|
||||
#### `Features/Capture/UnifiedCaptureFlow.swift`(P0,1d)
|
||||
状态机 View,根据 `CaptureService` 状态切换 Camera → Progress → A2 / B3。
|
||||
|
||||
#### `Features/Ask/AskSheet.swift`(P0,2d)
|
||||
- Modal sheet, fraction(0.9)
|
||||
- 顶部:3 个动态推荐问题 chip
|
||||
- 中部:对话流(`ChatTurn` 气泡)
|
||||
- AI 流式打字机 + 顶部小字 tok/s
|
||||
- 引用 `[1][2]` → Pill → 跳源
|
||||
- 底部输入框 + 发送
|
||||
- **不做**:多轮上下文连续追问(每问独立 RAG)
|
||||
|
||||
#### `Features/Trends/TrendsView.swift`(P0,3d)
|
||||
- 顶部横向 chip:指标(从 pinned + 高频 Indicator.name 去重)
|
||||
- 时间范围 segmented:3M / 6M / 1Y / 全部
|
||||
- Swift `Chart`:折线 + 参考范围 `RuleMark` 条带 + 异常点高亮
|
||||
- 点 tap → C2 详情
|
||||
- 下方 AI 解读卡片(`TrendNarrative`)
|
||||
|
||||
#### `Features/Archive/ArchiveListView.swift`(P0,2d)—— C1
|
||||
- `@Query` 全部 Report,按 `reportDate` 年份分组
|
||||
- 顶部分类 chip:全部 / 体检报告 / 化验单 / 影像报告 / 处方
|
||||
- 卡片:左缩略图 + 右(标题 + 异常 chip + 日期 + 机构)
|
||||
- 入口:HomeView "我的报告档案" 卡 → push
|
||||
|
||||
#### `Features/Archive/ReportDetailView.swift`(P0,2d)—— C2
|
||||
- 三 Tab Picker:原图 / 解读 / 指标
|
||||
- **原图 Tab**:`TabView(.page)` 翻页,点击放大,长按保存到相册(需相册权限)
|
||||
- **解读 Tab**:数字摘要(`indicators.count` / 偏高 / 偏低 / 正常)+ `Report.summary` + **对比上次区块**
|
||||
- **指标 Tab**:`Report.indicators`,异常优先
|
||||
- 底部两按钮:
|
||||
- **关联到趋势** → 本报告 `Indicator.pinned = true` 批量更新
|
||||
- **重新解读** → `CaptureService.reanalyze(report:)` 重跑 VL
|
||||
- 其他入口:ChatTurn 引用 / Trends 数据点 / Home 时间线
|
||||
|
||||
#### `Features/Me/MeView.swift`(P1,2d)
|
||||
1. 模型状态:Qwen3-1.7B / Qwen2.5-VL-3B 状态、占用空间、上次速度
|
||||
2. 隐私:Face ID Toggle(`@AppStorage`)、永久删除(二次确认)
|
||||
3. 数据:导出文字摘要(`UIActivityViewController`)
|
||||
4. 关于:版本 + 模型许可证
|
||||
|
||||
#### `Features/Onboarding/OnboardingFlow.swift`(P1,2d)
|
||||
3 页:隐私承诺 → 模型下载(进度 + WiFi 提示) → 完成。`@AppStorage("onboarded")` 记录。
|
||||
|
||||
#### `LiveActivity/CaptureActivity.swift` + WidgetExtension target(P1,2d)
|
||||
- `CaptureActivityAttributes`: modelName / status / decodeRate / elapsedMs
|
||||
- 锁屏 + 灵动岛 compact/expanded
|
||||
- AIRuntime 推理时 start/update/end
|
||||
- 真机限定
|
||||
|
||||
### 4.3 服务层文件
|
||||
|
||||
```
|
||||
体己/AI/ [7.5d]
|
||||
├── AIRuntime.swift 2d
|
||||
├── ModelStore.swift 1d
|
||||
├── LLMSession.swift 1d
|
||||
├── VLSession.swift 1d
|
||||
└── Prompts/ 2.5d
|
||||
├── VLExtraction.swift
|
||||
├── ChatRAG.swift
|
||||
├── KeywordExtraction.swift
|
||||
└── TrendNarrative.swift
|
||||
|
||||
体己/Services/ [4.5d]
|
||||
├── CaptureService.swift 1.5d
|
||||
├── AskService.swift 1.5d
|
||||
├── TrendService.swift 1d
|
||||
└── ReportCompareService.swift 0.5d
|
||||
|
||||
体己/Persistence/ [1d]
|
||||
├── FileVault.swift 0.5d
|
||||
└── PermanentDelete.swift 0.5d
|
||||
|
||||
体己/Security/ [0.5d]
|
||||
└── AppLock.swift 0.5d
|
||||
```
|
||||
|
||||
### 4.4 工作量
|
||||
|
||||
| 类别 | 估算 |
|
||||
|---|---|
|
||||
| 现有改造 | ~13d |
|
||||
| 新建视图(含 C1/C2 +4d) | ~16d |
|
||||
| AI 层 | ~7.5d |
|
||||
| Services 层(含 ReportCompare +0.5d) | ~4.5d |
|
||||
| Persistence / Security | ~1.5d |
|
||||
| **纯开发** | **~42.5d** |
|
||||
| 联调 / Bug / polish | ~7.5d 缓冲 |
|
||||
| **总计** | **~50d ≈ 6 周** |
|
||||
|
||||
任何一项延期 > 1d,按 §6.R7 砍 P1 不动 P0。
|
||||
|
||||
---
|
||||
|
||||
## 5. 6 周时间表
|
||||
|
||||
### W2(本周,5/25-5/31)—— AI 跑通 + Schema 重建
|
||||
- MLX SPM 引入 + Xcode target
|
||||
- `AIRuntime` actor + `prepare()` + `generate()`
|
||||
- `LLMSession` 跑通 Qwen3-1.7B 加载 + 文本生成
|
||||
- `ModelStore` 路径管理 + bundle 旁路(下载延后到 W6)
|
||||
- `Models/Models.swift` 新增字段 + Asset / ChatTurn
|
||||
- 删模拟器沙盒确认 Schema 重建
|
||||
- `FileVault` 写/读/删测试图
|
||||
|
||||
**里程碑**:debug 按钮点击控制台打印 LLM 流式输出 + 速度
|
||||
**验收**:decode ≥ 15 tok/s,无 OOM
|
||||
**红线**:跑不通周五前换 llama.cpp
|
||||
|
||||
### W3(6/1-6/7)—— 日记 + 基础 RAG
|
||||
- `DiaryComposer` 接 RecordSheet
|
||||
- `AskSheet` 打字机 UI + 流式
|
||||
- `AskService` 两段式 RAG:`KeywordExtraction` → SwiftData → `ChatRAG`
|
||||
- 引用 `[1][2]` → Pill(目标视图可 stub)
|
||||
- `ChatTurn` 持久化
|
||||
|
||||
**里程碑**:写 3 条日记 → 问"我最近写了什么" → 带引用回答
|
||||
**验收**:首 token < 2s,引用 ID 匹配
|
||||
**红线**:JSON 抽取失败率 > 30% → 加 few-shot 或换 prompt
|
||||
|
||||
### W4(6/8-6/14)—— VL + 统一拍照 + C1
|
||||
- `VLSession` 跑通 Qwen2.5-VL 加载 + 单图推理
|
||||
- `VLExtraction` prompt(few-shot + JSON)
|
||||
- `CaptureService.analyze` → draft → commit
|
||||
- `UnifiedCaptureFlow` 状态机
|
||||
- A1/B2 改 `VNDocumentCameraView`
|
||||
- A2/A3/B3/B4 接真数据
|
||||
- **W4 末:`ArchiveListView` C1**(分类 + 年份分组)
|
||||
|
||||
**里程碑**:三张真化验单 → 70% 字段自动填好;档案列表可见所有报告
|
||||
**验收**:VL 单页 < 8s,JSON 失败有可见兜底
|
||||
**红线**:VL > 15s 或失败率 > 40% → 降级 Vision OCR + Qwen3 文本后处理
|
||||
|
||||
### W5(6/15-6/21)—— C2 + Trends + 隐私 + Live Activity
|
||||
- **`ReportDetailView` C2** 三 Tab + 关联到趋势 + 重新解读
|
||||
- **`ReportCompareService`** + C2 解读 Tab "对比上次"
|
||||
- `TrendService` + `TrendsView`(Swift Charts + AI 解读)
|
||||
- `HomeView` 接 `@Query` 真数据 + 时间线 5 条
|
||||
- `TrendService.dailyDigest()` 接首页摘要卡
|
||||
- `AppLock` Face ID 启动锁
|
||||
- `PermanentDelete` 接 Me 页
|
||||
- WidgetExtension target + `CaptureActivity`
|
||||
- **真机调试 Live Activity**
|
||||
|
||||
**里程碑**:C1 → C2 三 Tab → 对比上次 → 关联到趋势 → Trends 上看到新指标;拍照灵动岛滚 tok/s
|
||||
**验收**:Charts ≥ 3 个指标各 ≥ 6 点;Live Activity 锁屏可见
|
||||
**红线**:Live Activity 周三前调不通 → 降级 App 内顶部条
|
||||
|
||||
### W6(6/22-6/28)—— 首启动 + Me + Polish + Demo
|
||||
- `OnboardingFlow`(隐私承诺 + 模型下载 + 完成)
|
||||
- `ModelStore` 真实 URLSession 下载 + 续传 + 进度
|
||||
- `MeView`(模型状态 + 隐私 + 关于)
|
||||
- 9.4 分享文字摘要
|
||||
- 所有空状态插画 / 文案
|
||||
- `#if DEBUG` 种子数据(12 份报告)
|
||||
- 真机录 3 分钟 demo 视频(含 Live Activity)
|
||||
- PPT 5 页核心(按卖点排序)
|
||||
|
||||
**里程碑**:零安装到首问答 < 5 分钟;demo 视频成片
|
||||
**验收**:评委 iPhone 跑得动(提前预拷模型)
|
||||
**红线**:W6 不再加新功能
|
||||
|
||||
### 每周日 retro 决策树
|
||||
|
||||
```
|
||||
本周 P0 全完成?
|
||||
├─ 是 → 进下周
|
||||
└─ 否,延期 > 2d
|
||||
→ 砍下周 1 项 P1
|
||||
砍顺序:Live Activity → Onboarding 简化 → 分享摘要 → Me polish
|
||||
绝不动:C1 / C2 / 对比上次 / 统一拍照 / AskSheet / Trends / Face ID
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 风险与回退预案
|
||||
|
||||
### R1 · MLX 跑不通 / 速度太慢 🔴 致命
|
||||
**信号**:W2 周五,decode < 10 tok/s 或首 token > 5s,OOM
|
||||
**回退**:① 更小量化 → ② llama.cpp + GGUF(失 SME2 卖点)→ ③ Qwen2.5-0.5B
|
||||
**预防**:W2 第一天就跑通;iPhone 15 Pro+ 基线
|
||||
|
||||
### R2 · VL 准确率不够 🔴 致命
|
||||
**信号**:W4 中,5 张真化验单 < 60% 字段正确;频繁残缺 JSON
|
||||
**回退**:① 加强 few-shot 到 4-5 个 → ② 降级 Vision OCR + Qwen3 文本后处理(失"VL"故事但保识别)→ ③ Demo 只用已知能解析的图
|
||||
**预防**:W3 末准备 5-10 张真单做回归集;A2/B3 必备兜底文案
|
||||
|
||||
### R3 · Live Activity 真机调不通 🟠 高
|
||||
**信号**:W5 末,Capability/证书问题,模拟器没法测
|
||||
**回退**:① 只保锁屏不要 App 内顶部条 → ② 整个砍,改 App 内顶部 `safeAreaInset` 粘性条 → ③ Demo 视频后期加字幕
|
||||
**预防**:W5 周一建好 target
|
||||
|
||||
### R4 · SwiftData migration 翻车 🟠 高
|
||||
**信号**:Schema 编过但启动崩 / cascade 误删
|
||||
**回退**:W5 前删沙盒;W5 后 `VersionedSchema` 只加字段;demo 翻车显式弹窗"重建",绝不静默丢数据
|
||||
**预防**:每次改 @Model 重启验证;Schema 改动 W2-W4 集中,W5 冻结
|
||||
|
||||
### R5 · 3GB 下载体验灾难 🟠 高
|
||||
**信号**:demo 现场装包后下载 30 分钟还没好,中断不能续
|
||||
**回退**:① demo 用预拷模型设备 + `seedModelsFromBundle()` → ② 分两步下(先 LLM 后 VL)→ ③ 视频备份
|
||||
**预防**:W6 在 2 台 demo 机断网测试
|
||||
|
||||
### R6 · 健康话术翻车 🟡 中
|
||||
**信号**:LLM 输出"你应该……""建议就医"
|
||||
**回退**:System prompt 末尾追加禁令;AskService 后处理过滤诊断关键词;启动屏永久免责小字
|
||||
**预防**:W3 RAG 跑通后立刻做 20 条危险问题安全测试,写进单元测试
|
||||
|
||||
### R7 · 时间不够 🟡 中
|
||||
**信号**:某周日 P0 还有 > 1d 没完成
|
||||
**回退顺序**:Live Activity → Onboarding 简化 → 分享摘要 → Me polish
|
||||
**绝不砍**:C1/C2、对比上次、统一拍照、AskSheet、Trends、Face ID
|
||||
**预防**:每周日 retro
|
||||
|
||||
### R8 · 评委 iPhone 不支持 SME2 🟡 中
|
||||
**信号**:iPhone 14 非 Pro 装包,速度比预期慢
|
||||
**回退**:不依赖评委设备,自带 iPhone 15 Pro / 16 Pro 演示
|
||||
**预防**:W6 准备 2 台 A17/A18 demo 机
|
||||
|
||||
### 风险红绿灯仪表盘
|
||||
|
||||
| 风险 | W2 | W3 | W4 | W5 | W6 |
|
||||
|---|---|---|---|---|---|
|
||||
| R1 MLX | 🔴 | 🟡 | 🟢 | 🟢 | 🟢 |
|
||||
| R2 VL | — | — | 🔴 | 🟡 | 🟢 |
|
||||
| R3 Live Activity | — | — | — | 🔴 | 🟡 |
|
||||
| R4 Migration | 🟡 | 🟡 | 🟡 | 🟠 冻结 | 🟢 |
|
||||
| R5 模型下载 | — | — | — | 🟡 | 🔴 |
|
||||
| R6 医疗话术 | — | 🟡 | 🟡 | 🟡 | 🟢 |
|
||||
| R7 P0 进度 | 🟡 | 🟡 | 🟠 | 🔴 | 🟡 |
|
||||
| R8 demo 设备 | — | — | — | — | 🔴 |
|
||||
|
||||
每周日 retro 显式确认当周"关键"项:**通过 / 需补救 / 触发回退**。
|
||||
|
||||
---
|
||||
|
||||
## 7. 非目标(明确不做)
|
||||
|
||||
写代码时如果想加,先回这里看一眼:
|
||||
|
||||
- ❌ 医疗诊断、剂量推荐、急诊判断、医生预约
|
||||
- ❌ 连拍模式(1.6)
|
||||
- ❌ AES 自实现 / 截屏黑屏防护(走 iOS 系统级)
|
||||
- ❌ 加密 ZIP 导出(9.1-9.3)——只留 9.4 文字摘要
|
||||
- ❌ 多页 PDF 自写透视校正(VisionKit 白送)
|
||||
- ❌ 用药提醒、复检提醒、体检周年提醒(11.x)
|
||||
- ❌ 语音输入(12.x)
|
||||
- ❌ 多指标相关性、聚类(13.x)
|
||||
- ❌ 暗黑模式、主题色切换(14.x)
|
||||
- ❌ 多 profile / 家庭成员(15.x)
|
||||
- ❌ AI 模型升级 in-app(17.x)
|
||||
- ❌ iCloud 同步(18.x,与"100% 本地"冲突)
|
||||
- ❌ Widget / Home Screen 小组件(19.x;Live Activity 不算)
|
||||
- ❌ 社交、广告、内购、账号系统
|
||||
|
||||
**例外加回**:报告对比 16.1(P0,已加回,见 §4.2 C2 + §5 W5)
|
||||
|
||||
---
|
||||
|
||||
## 8. 评委 PPT 卖点排序
|
||||
|
||||
写每个功能时记住为什么这么做:
|
||||
|
||||
1. **影像档案系统**(统一 VL 拍照 + C1/C2 归档库)— 核心创意
|
||||
2. **100% 本地 + SME2 加速** — 技术亮点
|
||||
3. **本地 RAG 长期记忆** — 端侧不可替代性
|
||||
4. **隐私三件套**(系统级 file protection + Face ID + 永久删除)— 信任建立
|
||||
5. **AI 趋势解读 + 对比上次** — 长期价值
|
||||
6. **Live Activity 实时 tok/s** — 现场记忆点
|
||||
|
||||
每写一个功能,问自己:这条提升了上面哪一项?都没有就别做。
|
||||
|
||||
---
|
||||
|
||||
## 附录 · 与原始功能清单的映射
|
||||
|
||||
| 原编号 | 状态 | 落地位置 |
|
||||
|---|---|---|
|
||||
| 1.x 异常项快拍 | **合并** | UnifiedCaptureFlow(kind=single) |
|
||||
| 1.2 智能取景框 | **砍** | VNDocumentCameraView 取代 |
|
||||
| 1.6 连拍模式 | **砍** | YAGNI |
|
||||
| 2.x 关键报告归档 | **合并** | UnifiedCaptureFlow(kind=report) |
|
||||
| 2.1 多页扫描 | 改造 | VNDocumentCameraView 多页 |
|
||||
| 2.6 原图加密 | 改造 | FileVault `.completeFileProtection` |
|
||||
| 3.x 自然语言日记 | P0 | DiaryComposer + DiaryEntry |
|
||||
| 4.x AI 问答 | P0 | AskSheet + AskService(结构化 RAG) |
|
||||
| 4.4 流式输出 | P0 | LLMSession + AskSheet 打字机 |
|
||||
| 5.x 趋势分析 | P0 | TrendsView + TrendService + Swift Charts |
|
||||
| 6.1-6.2 本地 + 离线 | 自然结果 | MLX + 无网络依赖 |
|
||||
| 6.3 数据加密 | 改造 | `.completeFileProtection`(系统级) |
|
||||
| 6.4 Face ID | P0 | AppLock |
|
||||
| 6.5 截屏防护 | **砍** | iOS 无官方 API |
|
||||
| 6.6 永久删除 | P0 | PermanentDelete |
|
||||
| 7.x 首页 | P0(已有骨架) | HomeView 接真数据 |
|
||||
| 8.x 模型管理 | P1 | MeView |
|
||||
| 9.4 分享文字摘要 | P1 | MeView "导出" |
|
||||
| 9.1-9.3 加密 ZIP 导出 | **砍** | |
|
||||
| 10.x 引导 | P1(简化) | OnboardingFlow 3 页 |
|
||||
| 11.x 提醒 | **砍** | |
|
||||
| 12.x 语音 | **砍** | |
|
||||
| 13.x 进阶趋势 | **砍** | |
|
||||
| 14.x 暗黑/主题 | **砍** | |
|
||||
| 15.x 多 profile | **砍** | 数据模型成本太大 |
|
||||
| **16.1 报告对比** | **加回 P0** | C2 解读 Tab + ReportCompareService |
|
||||
| 17.x 模型升级 | **砍** | |
|
||||
| 18.x iCloud 同步 | **砍** | 与本地卖点冲突 |
|
||||
| 19.2 灵动岛 | P1 加分 | CaptureActivity LiveActivity |
|
||||
| 19.1 Widget | **砍** | |
|
||||
| **C1 档案列表** | **新增 P0** | ArchiveListView |
|
||||
| **C2 报告详情三 Tab** | **新增 P0** | ReportDetailView |
|
||||
| **C2 关联到趋势** | **新增 P0** | Indicator.pinned 批量更新 |
|
||||
| **C2 重新解读** | **新增 P0** | CaptureService.reanalyze |
|
||||
|
||||
---
|
||||
|
||||
**END OF SPEC v1.0**
|
||||
Reference in New Issue
Block a user