2.2 KiB
2.2 KiB
「身体档案」输入框语音输入 设计
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为空 → 返回partialprefix以空白/换行结尾 →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 禁用onDisappearabort
测试
merge(prefix:partial:)3 个单测(空前缀 / 空白结尾前缀 / 普通前缀)- 真机手测:听写上屏、停止落定、已有文字保留、权限拒绝、3 分钟自动停
不做(YAGNI)
快捷问答弹窗 / 个人资料 Form 等其他输入处的语音;自动发送;录音面板;LLM 整理。