Files
teaching-feedback-assistant/docs/incidents/2026-07-22-miniprogram-voice-retry.md

128 lines
4.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.

# 小程序语音转录失败后无法重试
## 状态
- 记录日期2026-07-22
- 当前状态:待处理
- 影响范围:小程序反馈生成页的语音转录重试流程
- 相关会话:`7dc4f0dd-bd32-4d4b-b90a-c36ae83c2ca7`
## 用户现象
1. 用户点击“生成反馈”。
2. 小程序提示“部分语音转录失败,请重试后再生成反馈”。
3. 用户尝试点击重试入口,但界面没有可观察到的状态变化。
4. 再次点击“生成反馈”仍收到相同提示。
## 已确认事实
### 请求轨迹
2026-07-22 14:07:04 至 14:09:42Asia/Shanghai期间同一反馈会话共发起 6 次:
```text
POST /api/v1/feedback-sessions/7dc4f0dd-bd32-4d4b-b90a-c36ae83c2ca7/generate
```
6 次请求均返回 HTTP 400。同期 Loki 中没有以下请求:
```text
POST /api/v1/audio-segments/{segment_id}/retry
POST /api/v1/feedback-lessons/{lesson_id}/finish
```
因此,本次“点击重试无反应”发生在重试请求到达 API 之前,不能归因于 API 重试接口或 FunASR 在重试阶段报错。
可用于关联排查的生成请求编号包括:
- `e0516f03-7c38-4cfc-aa6f-78dfa4188fb5`
- `2eacfd84-449d-4135-a74b-0582a1ab1a4f`
- `14359b2d-a97c-4b3e-a3d1-cc37ad33b8ab`
- `49375fae-b00f-471b-a63b-9aa4e1a13dd8`
- `c30130e9-3e10-4050-a807-720fc90bb39a`
- `45f8188e-921b-45a1-bc06-76b1502949be`
### 失败片段
数据库中存在一个阻止反馈生成的失败片段:
- 片段 ID`4dc61129-10b4-4a4c-91ff-b44ac38f5997`
- 时长2800 ms
- 格式MP3
- 转录尝试次数1
- 失败时间2026-07-21 15:18:18Asia/Shanghai
- FunASR 响应HTTP 422`no clear speech was recognized`
同一反馈会话的其余 5 个录音片段均为 `ready`。当前生成接口会在发现任意 `failed` 片段时拒绝整个反馈生成请求。
## 代码层问题
### 主操作没有优先处理失败片段
`pages/feedback/index.ts``syncVoicePresentation` 在存在可生成内容时把主操作设置为“生成反馈”,即使会话同时包含失败片段。`saveFeedback` 也只优先处理 `processing`,没有在调用生成接口前处理 `failedSegmentCount`
结果是用户可以持续点击“生成反馈”,但 API 必然持续返回 HTTP 400。
### 重试入口不够明确
当前重试流程隐藏在语音状态区域和原生弹窗中:
```text
点击语音状态 -> 打开语音记录弹窗 -> 点击“重试失败项”
```
页面没有独立、明确的“重试转录”主操作,也没有显示将要重试的失败片段数量。
### 生成失败后没有刷新会话
`generateFeedback` 捕获 API 错误后只显示短暂 Toast没有重新调用 `loadActiveSession`,也没有把错误信息和 `X-Request-Id` 保存到页面的持久错误区域。
这会导致服务端状态和页面状态不一致时,用户无法通过当前页面恢复到正确的重试入口。
### 缺少重试操作可观测性
API 当前只有通用 HTTP 请求日志。重试请求未到达服务端时,没有前端操作日志;请求到达服务端后,也缺少 `transcription_retry_requested` 等业务事件日志。
## 待实现方案
1.`failedSegmentCount > 0` 时,主操作优先显示“重试转录”,并直接调用失败片段重试流程。
2. 禁止在存在失败片段时调用生成接口。
3. 重试开始后立即显示处理中状态,刷新会话并恢复转录轮询,直到片段进入 `ready` 或再次进入 `failed`
4. 生成接口返回失败片段错误时,重新加载活动会话并展示持久错误信息及请求编号。
5. API 为重试受理、生成拒绝和转录失败增加包含会话 ID、课堂 ID、片段 ID、尝试次数和错误分类的结构化业务日志。
6. 对“未识别到清晰语音”提供更准确的用户提示,说明可能是录音过短、静音或环境噪声,并允许放弃该失败片段或重新录制。
## 验收标准
- 存在失败片段时,主按钮不再显示“生成反馈”。
- 点击“重试转录”后API 日志中能查询到对应 `/retry` 请求和业务事件。
- 页面在重试期间显示明确的处理中状态,且不会重复提交生成请求。
- 重试成功后自动恢复“生成反馈”;再次失败时显示可理解的失败原因。
- 所有 API 错误都能在页面上获得可复制的请求编号。
- 自动化测试覆盖失败片段优先级、重试状态流转和生成失败后的会话刷新。
## 临时排查查询
排除健康检查后查看 API 日志:
```logql
{application="teaching-feedback", service="api"}
| json
| span_path != "/health"
```
查看失败请求:
```logql
{application="teaching-feedback", service="api"}
| json
| status >= 400
```
查看指定反馈会话:
```logql
{application="teaching-feedback", service="api"}
|= "7dc4f0dd-bd32-4d4b-b90a-c36ae83c2ca7"
```