From c3f8ec400cede3465cd45acd9444324194318f54 Mon Sep 17 00:00:00 2001 From: link2026 Date: Wed, 10 Jun 2026 08:23:36 +0800 Subject: [PATCH] =?UTF-8?q?docs(spec):=20=E8=BA=AB=E4=BD=93=E6=A1=A3?= =?UTF-8?q?=E6=A1=88=E8=BE=93=E5=85=A5=E6=A1=86=E8=AF=AD=E9=9F=B3=E5=90=AC?= =?UTF-8?q?=E5=86=99=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- ...2026-06-10-voice-export-composer-design.md | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-10-voice-export-composer-design.md diff --git a/docs/superpowers/specs/2026-06-10-voice-export-composer-design.md b/docs/superpowers/specs/2026-06-10-voice-export-composer-design.md new file mode 100644 index 0000000..80e4ec7 --- /dev/null +++ b/docs/superpowers/specs/2026-06-10-voice-export-composer-design.md @@ -0,0 +1,47 @@ +# 「身体档案」输入框语音输入 设计 + +> 2026-06-10 · 在「身体档案」(`HealthExportSheet`)底部聊天输入框加端侧语音听写,复用 `SpeechDictationService`,识别文字实时流进输入框。 + +## 背景 + +「身体档案」composer 是聊天式输入(提问/诉求 → 发送 → LLM 对话/生成报告)。与日记不同,这里输入的内容马上交给 LLM,**不需要"整理"加工**;口述原话直接进输入框即正确行为(类似系统键盘听写)。 + +## 决策(已与用户确认) + +| 维度 | 决定 | +|---|---| +| 交互 | 听写直接流进输入框:点 mic 开始,实时上屏;再点停止;用户自查后手动发送 | +| LLM | 不调用(无整理步骤、不自动发送) | +| 复用 | `SpeechDictationService`(**@State 持有**,防视图重建丢实例)、权限 alert 文案、3 分钟看门狗、onDisappear abort | +| UI | mic 按钮放 TextField 与发送键之间;`isAvailable == false` 隐藏;录音中变红色停止态(脉冲动画) | + +## 组件 + +### 1. `SpeechDictationService.merge(prefix:partial:)`(新,static 纯函数) + +听写文本拼接规则,唯一可单测的逻辑: +- `prefix` 为空 → 返回 `partial` +- `prefix` 以空白/换行结尾 → `prefix + partial` +- 其余 → `prefix + " " + partial` + +### 2. `HealthExportSheet` 改动 + +- `@State dictation` + `isDictating` + `dictationPrefix` + 看门狗 Task +- 点 mic:申请权限(拒绝 → alert 跳设置,与日记同文案)→ 记录 `dictationPrefix = draftQuestion` → start,每个 partial:`draftQuestion = merge(prefix:partial:)` +- 再点:`stop()`,最终稿同 merge 落定;**stop 返回空时保留输入框现状**(partial 已实时在框里,天然兜底,不提示「没听清」) +- 3 分钟看门狗自动停(防麦克风悬挂) + +## 冲突防护 + +- 录音中:TextField 与发送按钮、「生成整理报告」按钮禁用(防手输与 partial 互相覆盖、防录音中发送) +- `isAnswering / isGeneratingReport` 时 mic 禁用 +- `onDisappear` abort + +## 测试 + +- `merge(prefix:partial:)` 3 个单测(空前缀 / 空白结尾前缀 / 普通前缀) +- 真机手测:听写上屏、停止落定、已有文字保留、权限拒绝、3 分钟自动停 + +## 不做(YAGNI) + +快捷问答弹窗 / 个人资料 Form 等其他输入处的语音;自动发送;录音面板;LLM 整理。