3.8 KiB
3.8 KiB
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_cancelWS 与 pipeline 短路(可选)。
5. UI 要点
- 助手文本气泡:内联「朗读」按钮(图标 + a11y 文案);播放中可显示为停止或与气泡点击一致。
- 播放中:气泡弱高亮 + 「朗读中…」;流式未结束时可对 streaming 区使用同一套样式。
- 与用户语音条:沿用
Play/Pause或扬声器语义,降低认知成本。
6. 错误与测试
- 无
ttsAudioUrls: 提示「暂无法朗读」或隐藏按钮。 - 单测:
stop()后队列为空;generation 丢弃旧片段(若实现)。 - 手测: 录音打断、点气泡停止、自动播完后高亮消失、用历史 URL 重播同一条。
7. 实施顺序建议
- 类型与 API 映射:
ttsAudioUrls→MessageItem。 PlaybackItem+usePlayer入队参数;TTS 回调写入messageRef(力所能及)。- 录音与气泡
Pressable调用stop()/ generation。 - 助手气泡 UI:朗读按钮 + 朗读中高亮。
- (可选)WS
tts_cancel与assistant_message_id。