# 5.8 实时识别：边说边出字，名单放在哪一步

这份代码回答两个问题。第一，实时语音识别的延迟花在哪：开口后多久出第一个字，说完后多久拿到最终文字。第二，人名这类上下文，放进识别模型（识别时给 `terms`），还是放进后面的纠错模型（识别完再交给一个大模型改），哪种做法写对的人名多、代价是多等多久。

有两个脚本：

- `run.py`：拿模块 2 的示例录音（每条都有脚本原文作标准答案）做对比实验。每条录音按真实语速推给 AI Builder Space 的实时接口，比较五种做法：识别时不给名单；识别时给 `terms`；识别后交给纠错模型；识别时给 `terms` 再交给纠错模型；以及作为参考的“说完后整段上传识别”。每种做法数人名写对了几处，再记两个延迟。
- `live.py`：给你自己用的小工具。对着麦克风说话，文字边说边打印出来；说完按回车，拿到最终文字。也可以用 `--file` 推一段录音。

## 需要什么设备

只用 API，任何电脑都行。`live.py` 用麦克风时需要一个能录音的输入设备。

## 安装与运行

```bash
cd 5_8_realtime
uv venv && source .venv/bin/activate      # 没有 uv 就用 python3 -m venv .venv
uv pip install -r requirements.txt
export AI_BUILDER_TOKEN=sk_你的key

python run.py --lang zh       # 中文示例录音，约 6 分钟，花费约 0.2 美元
python run.py --lang en       # 英文示例录音
python live.py                # 对着麦克风说话，说完按回车
python live.py --terms names.txt          # 识别时带名单，每行一个词
```

第一次运行 `run.py` 会自动下载模块 2 的 38 条示例录音（约 13 MB），只用其中提到人名的 23 条。录音是按真实语速推的，模拟一个人正在说话，所以跑得和录音一样长。

实时接口有两个模型：默认的 `gpt-live-transcribe`，和 `--model gpt-realtime`。

## 该看到什么

我们的样例输出在 `sample_output/`（2026-10-23，Mac Studio 上调用 AI Builder Space，中英文各跑两遍）。23 条录音里一共有 31 处人名、20 处术语：

| 做法 | 人名写对（中文，两遍） | 人名写对（英文，两遍） | 说完后多久拿到最终文字 |
|---|---|---|---|
| 识别时不给名单 | 3/31、3/31 | 3/31、3/31 | 约 0.9–1.0 秒 |
| 识别时给 terms | 22/31、24/31 | 26/31、27/31 | 约 0.8–1.0 秒 |
| 识别后交给纠错模型（deepseek） | 22/31、23/31 | 20/31、21/31 | 约 2.5–2.8 秒 |
| 识别时给 terms，再交给纠错模型 | 30/31、29/31 | 27/31、28/31 | 约 2.2–2.5 秒 |
| （参考）说完后整段上传识别，不给名单 | 4/31、4/31 | 3/31、3/31 | 约 1.4–3.1 秒 |

实时识别开口后约 1.1–1.2 秒出第一段字，之后边说边出。说完到拿到最终文字不到 1 秒，比说完再整段上传快。

几个值得注意的地方：

- **名单放进识别这一步，几乎不增加延迟。** 人名从 3 处升到 22–27 处，说完后拿到最终文字的时间没有变化。
- **放进纠错这一步，要多等一次大模型调用**，中位数 1.5–1.8 秒。英文里它不如识别时给 terms（20–21 vs 26–27），中文里两者差不多。
- **两种错误不一样，所以两步都做最好。** 识别时没有名单，“祁骁”被听成“取消”“其消息”，这些是通顺的真词，纠错模型看不出它们是人名，就留着没改；识别时给了 terms，声音还在，就能写对。反过来，“蔺思远”有几次在识别时给了 terms 还是写错，纠错模型照名单改了回来。两步都做，中文到 29–30 处，英文到 27–28 处。
- **另一个模型的取舍。** 用 `--model gpt-realtime` 跑中文一遍：识别时给 terms 写对 28/31，比默认模型多；但它在说话过程中不出字，第一段文字要等说完、提交以后才来（中位数 12.2 秒，基本就是录音时长）。边说边出字和最终准确率，要按你的场景取舍。

## 换成你自己的数据

`run.py` 需要两样东西：一个录音目录（每条一个 `<id>.wav`），和一个标准答案文件，格式照 `memos_zh.json`：

```json
{"people": {"人名": "角色说明"}, "terms": ["术语1", "术语2"],
 "memos": [{"id": "001", "text": "这条录音实际说了什么（逐字）"}]}
```

然后 `python run.py --audio 我的录音目录 --memos 我的答案.json`。名单（识别时的 terms 和纠错时的名单）用的就是 `people` 和 `terms` 两栏。只有提到 `people` 里人名的录音会参与比较。

录音要是 24 kHz、单声道、16 位的 WAV。手机录的 m4a 之类先转一下：

```bash
ffmpeg -i 录音.m4a -ar 24000 -ac 1 -sample_fmt s16 录音.wav
```

计分规则：某个词在标准答案里出现 n 次，转写里出现 k 次，就算写对 min(n, k) 处。中文忽略大小写和空格按字面匹配，英文按整词匹配，和模块 2 的计分一致。

`live.py` 的麦克风路径我们在 Mac 上通过一个虚拟音频设备验证过（把录音放进虚拟设备，再从它录进来），没有用真人现场说话测过。
