Rename @testable imports across all test/UI test files after the Tiji→Kangkang
project rename in 44ed01a. Add shared scheme. Sync CLAUDE.md / W2 plan / spec
v1.0 to current scope (Symptom feature noted, C1/C2 flow lockdown).
24 KiB
康康 —— 功能设计 Spec(v1.0)
日期:2026-05-25 状态:Draft, 已与产品方对齐 §1-§6 关联:CLAUDE.md 工程前提
0. 概要
康康是一个 iOS 原生健康影像档案 App,100% 端侧 AI 推理,基于 SwiftUI + SwiftData + MLX Swift,目标 6 周交付决赛 demo。本 spec 把原始功能清单收敛为 方案 B:核心 5 模块 + Live Activity + 分享摘要,其余 P2/P3 全部 deferred。
5 大核心模块
- 统一拍照(合并原 1.x 异常项快拍 + 2.x 关键报告归档)
- 文字日记
- 本地 RAG 问答(结构化检索)
- 趋势分析(Swift Charts + AI 一句话解读)
- 影像档案库 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 // 趋势一句话解读
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-community/Qwen3-1.7B-4bit + mlx-community/Qwen2.5-VL-3B-Instruct-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 全集
@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
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)
- 模型状态:Qwen3-1.7B / Qwen2.5-VL-3B 状态、占用空间、上次速度
- 隐私:Face ID Toggle(
@AppStorage)、永久删除(二次确认) - 数据:导出文字摘要(
UIActivityViewController) - 关于:版本 + 模型许可证
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
AIRuntimeactor +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接 RecordSheetAskSheet打字机 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 加载 + 单图推理VLExtractionprompt(few-shot + JSON)CaptureService.analyze→ draft → commitUnifiedCaptureFlow状态机- A1/B2 改
VNDocumentCameraView - A2/A3/B3/B4 接真数据
- W4 末:
ArchiveListViewC1(分类 + 年份分组)
里程碑:三张真化验单 → 70% 字段自动填好;档案列表可见所有报告 验收:VL 单页 < 8s,JSON 失败有可见兜底 红线:VL > 15s 或失败率 > 40% → 降级 Vision OCR + Qwen3 文本后处理
W5(6/15-6/21)—— C2 + Trends + 隐私 + Live Activity
ReportDetailViewC2 三 Tab + 关联到趋势 + 重新解读ReportCompareService+ C2 解读 Tab "对比上次"TrendService+TrendsView(Swift Charts + AI 解读)HomeView接@Query真数据 + 时间线 5 条TrendService.dailyDigest()接首页摘要卡AppLockFace 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 卖点排序
写每个功能时记住为什么这么做:
- 影像档案系统(统一 VL 拍照 + C1/C2 归档库)— 核心创意
- 100% 本地 + SME2 加速 — 技术亮点
- 本地 RAG 长期记忆 — 端侧不可替代性
- 隐私三件套(系统级 file protection + Face ID + 永久删除)— 信任建立
- AI 趋势解读 + 对比上次 — 长期价值
- 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