## ADDED Requirements ### Requirement: Message status lifecycle 每条对话消息 SHALL 拥有独立的状态字段,使用 3 个状态: - `loading`: 处理中(发送/转录/流式输出) - `done`: 完成 - `error`: 失败 #### Scenario: Student message sent successfully - **WHEN** 学生完成录音并发送消息 - **THEN** 消息状态从 `loading` 变为 `done`,消息内容来自 ASR 转写结果 #### Scenario: AI reply streams in - **WHEN** 学生消息发送成功后触发 AI 回复 - **THEN** AI 消息进入 `loading` 状态(显示 typing 动画),收到 token 后逐字渲染,流结束后变为 `done` #### Scenario: Request fails at any stage - **WHEN** 网络异常或后端错误导致请求失败(不区分 ASR/LLM 阶段) - **THEN** 出错的消息状态变为 `error`,显示「重试」按钮 ### Requirement: Message retry 系统 SHALL 支持对 `error` 状态的消息进行重试操作。重试按钮 SHALL 显示在出错消息的下方。 #### Scenario: Retry a failed student message - **WHEN** 用户点击学生消息下方的「重试」按钮 - **THEN** 系统用缓存的 audioBlob 重新调用 `/speak`,整个流程重走 #### Scenario: Retry a failed AI message (stream interrupted) - **WHEN** AI 消息流式中断,用户点击 AI 消息下方的「重新生成」按钮 - **THEN** 系统清空 AI 消息内容,重新调用 `/speak`(后端幂等,不重复存学生消息),重新流式填充 #### Scenario: User chooses to re-record instead of retry - **WHEN** 学生消息发送失败后,用户直接点击录音按钮录新音频 - **THEN** 系统丢弃失败消息,用新录音发起新的 `/speak` 请求 ### Requirement: AudioBlob lifecycle 录音 Blob SHALL 在该轮对话成功完成前保持缓存,以支持重试。 #### Scenario: Retain blob until round completes - **WHEN** 学生完成录音 - **THEN** audioBlob 保持在内存中,直到该轮 AI 回复 `done` 后才可释放 ### Requirement: Round progression 对话引擎 SHALL 按轮次推进对话。每轮结束由后端 SSE `done` 事件触发。 #### Scenario: Normal round progression - **WHEN** 收到 SSE `done` 事件且 `isComplete` 为 false - **THEN** 录音按钮恢复可用,等待学生下一轮录音;下一轮的 AI 消息由后端在 `done` 事件中返回 #### Scenario: Dialogue complete - **WHEN** 收到 SSE `done` 事件且 `isComplete` 为 true - **THEN** 触发 `complete` 事件,前端转到报告页 #### Scenario: First round initialization - **WHEN** 调用 `POST /session` 创建对话 - **THEN** 后端返回 AI 开场白,前端显示第一条 AI 消息,学生进入可录音状态 ### Requirement: Input locking 系统 SHALL 在消息处理过程中禁用录音按钮,保证一次只能有一条处理中的消息。 #### Scenario: Lock during processing - **WHEN** 有任何消息处于 `loading` 状态 - **THEN** 录音按钮处于禁用状态 #### Scenario: Unlock after completion or error - **WHEN** 当前轮所有消息都是 `done` 或 `error` 状态 - **THEN** 录音按钮恢复可用 ### Requirement: Auto scroll 消息列表 SHALL 在新内容到达时自动滚动到底部。 #### Scenario: Auto scroll on new content - **WHEN** 新消息添加或流式输出产生新内容 - **THEN** 自动滚动到底部