Skip to content

按住说话:再次按下会丢失/错乱上一轮的回复、语音状态和追问 #400

Description

@LUPENGHAN

背景

按住说话(PTT)模式下,上一轮还没结束(回复还在流式、语音还在播、或在等追问)时用户又按住说话开始下一轮,会出现三类问题:回复气泡消失后不再出现、音频状态被错误打断、追问把新一轮的状态强行改写。

已确认问题

  1. _startTurn() 开头无条件清空 replyText,同时 fix(assistant): 按住说话点掉回复后,上一轮回复会重现并挡住语音条 #364 加的 request_id 轮次门控没有相应处理:新一轮换了 request_id 后,上一轮剩余的流式增量全部被当成"别人的"丢掉,replyText 永远停在被清空的那一刻——现象是"长回复气泡完全不出现",而语音不受影响照常播,回复越长越容易踩到。
  2. 同一类问题也出现在 voice.dialogue.question:没有任何轮次门控,上一轮被打断后晚到的追问会把已经推进到新一轮的 phase 强行掰回 asking。
  3. voice.tts.start/voice.tts.end 同样没有门控(协议本身也不带 request_id,没法照搬同样的判断):上一轮的语音还在播时开始新一轮,两轮音频会同时播放;上一轮迟到的 tts.end 会把已经推进到新一轮的 phase 强行掰回 idle。

目标

再次按住说话应该等同于用户主动点掉气泡(dismissReply):文字立即清空、语音立即停播,然后干净地开始听新一段,不改变现有语音状态机和消息协议。

修复范围

  • _startTurn() 开始新一轮时清空 replyText 并停播上一轮语音,行为跟点掉气泡一致;voice.dialogue.reply 门控保持"只认当前轮",上一轮迟到的增量正常丢弃,不会把已经清空的气泡重新填回去。
  • voice.dialogue.question 补上跟回复一样的轮次门控。
  • 新一轮开始(或点掉气泡)时,如果上一轮语音还没播完,主动停止播放并把这条音频的 id 记进一个集合;它迟到的 tts.end 到达时只从集合里摘除、不再碰 phase——用集合是因为连续按多次时,只记一个 id 会被后一次覆盖掉,导致更早放弃的那条迟到收尾消息漏判。

非目标

  • 不改变语音传输协议、request_id 语义,不给 voice.tts.start/voice.tts.end 加 request_id 字段(那需要改后端协议,这次范围只在前端)。
  • 不改动连续通话模式(本身不受影响,它的门控设计不一样)。

已知局限(不在这次修复范围内)

voice.tts.start/voice.tts.end 协议本身不带任何轮次标识,如果新一轮开始的时机恰好卡在服务端"上一轮 tts.start 刚发出、取消还没生效"这个协程调度间隙内(毫秒级窗口,人手操作基本碰不到,网络抖动/服务端负载异常时概率会升高),这条迟到的 tts.start 依然会被当成合法消息接受,可能让 phase 卡在 speaking 直到新一轮自己的消息把它带走。要彻底堵上需要后端配合,本次不在范围。

验收标准

  • 语音播放中再按住说话:气泡立即清空、语音立即停播。
  • 上一轮迟到的流式增量到达:不会把已经清空的气泡重新填回去。
  • 气泡被点掉后,晚到的旧回复不会把它重新弹回来(fix(assistant): 按住说话点掉回复后,上一轮回复会重现并挡住语音条 #364 场景不回归)。
  • 上一轮迟到的追问不会把已经推进到新一轮的状态改写。
  • 连续按住说话多次:更早放弃的那条音频迟到的收尾消息不会把最新一轮的状态掰回 idle。
  • 相关单元测试通过。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions