Files
life-echo/docs/plans/2026-03-26-tts-interrupt-read-aloud-design.md
2026-03-26 14:32:30 +08:00

79 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TTS 打断、朗读态与重复朗读 — 设计定稿
**日期:** 2026-03-26
**范围:** Expo 对话页;后端已具备 TTS 上传与 URL 落库,本设计侧重客户端与可选协议增强。
---
## 1. 目标
- **打断B** 开始录音时立即停止 TTS 并清空待播队列。
- **打断C** 在「自动 TTS 正在播放」时,点击助手文本气泡区域停止朗读。
- **区分纯文本:** 正在朗读时,助手气泡有明确视觉态(描边/底 + 行内「朗读中」或扬声器动效)。
- **重复朗读:** 对已落库且带有 COS URL 列表的助手消息,可再次按序播放,**不重新合成**(见第 4 节)。
**手势分工:** 气泡空白区域在播放中 = 停止;**独立「朗读 / 再读」控件** = 开始或重播,避免与「点一下停」冲突。
---
## 2. 后端现状(方案 C 已具备)
- `Segment` / `ConversationMessage` 均有 `tts_audio_urls`JSON 数组)。
- `pipeline._send_tts_audio` 上传 COS 后返回 URL回合结束 `attach_ai_tts_audio_urls` 写库。
- 历史/API 已透出 `ttsAudioUrls`camelCase
**重复朗读策略:** 客户端从消息读取 `ttsAudioUrls`,按顺序 `enqueue`;无需新增「按文本重合成」接口作为默认路径。
---
## 3. 客户端缺口与数据模型
### 3.1 `MessageItem`
- 增加可选字段:`ttsAudioUrls?: string[]`(与后端一致)。
- 从 REST / React Query 缓存映射时填入;无数组或为空则隐藏「朗读」或置灰。
### 3.2 `PlaybackItem``use-player` / `features/voice/types`
- 扩展:`kind: 'tts_auto' | 'tts_repeat' | 'voice'`(或保留 `label` 并规范化)。
- `messageRef?: { listKey: string }`(或 `messageId`),用于高亮对应气泡。
- 入队时:自动 TTS 片段写入 `kind: 'tts_auto'` + 当前助手消息引用(若能从会话层解析);手动「再读」写入 `kind: 'tts_repeat'` + 该条 `listKey`
### 3.3 `RealtimeSession` / WS
- `TtsSegmentPayload` 携带 `index` / `total`(类型已存在,需从 `client` 映射到回调)。
- 理想情况:后端在 `tts_audio` 中增加 `assistant_message_id`(或与 segment 对齐的 id便于客户端稳定绑定「哪一条在播」。**未上字段前:** 流式阶段可仅用「当前 streaming 轮次」+ 全局条提示;落库后以 `messageId` + `ttsAudioUrls` 为准。
---
## 4. 打断与串播
- **`stop()`** 已在 `usePlayer`;在开始录音成功后调用 `stop()`,保证队列清空(除 `audioFocus` 外,逻辑上立即静音)。
- **服务端后续片段:** 若用户已 `stop()` 仍收到 `tts_audio`,可能再次入队。推荐客户端维护 **`ttsPlaybackGeneration`**(打断时自增),仅处理与当前 generation 匹配的片段;或后续增加 `tts_cancel` WS 与 pipeline 短路(可选)。
---
## 5. UI 要点
- 助手文本气泡:内联「朗读」按钮(图标 + a11y 文案);播放中可显示为停止或与气泡点击一致。
- 播放中:气泡弱高亮 + 「朗读中…」;流式未结束时可对 streaming 区使用同一套样式。
- 与用户语音条:沿用 `Play`/`Pause` 或扬声器语义,降低认知成本。
---
## 6. 错误与测试
- **无 `ttsAudioUrls`** 提示「暂无法朗读」或隐藏按钮。
- **单测:** `stop()` 后队列为空generation 丢弃旧片段(若实现)。
- **手测:** 录音打断、点气泡停止、自动播完后高亮消失、用历史 URL 重播同一条。
---
## 7. 实施顺序建议
1. 类型与 API 映射:`ttsAudioUrls``MessageItem`
2. `PlaybackItem` + `usePlayer` 入队参数TTS 回调写入 `messageRef`(力所能及)。
3. 录音与气泡 `Pressable` 调用 `stop()` / generation。
4. 助手气泡 UI朗读按钮 + 朗读中高亮。
5. 可选WS `tts_cancel``assistant_message_id`