本节摘要:语音入口的第一段是把声音变文字。Whisper(OpenAI 开源的语音转写模型)按大小分档:tiny/base/small/medium/large——参数量从 39M 到 1550M,越大越准也越慢,档位的本质是"用准确率换实时性"。本节先给档位表(数字以 openai/whisper 官方 README 为准),按"有没有 GPU、延迟要求几秒"教选档;然后是录音三纪律(16kHz、单声道、控时长)与中文转写代码示意;最后治中文转写三病:简繁混杂(社区常见现象与缓解写法)、静音幻觉(对静音段编话)、太慢(降档)。转写出来的字符串直接按第 2 章契约装进 messages——从这一刻起,语音问题退化成文字问题。
阅读完本节,你应当能够:
nanochat 发布帖的四阶段口径:推理界面 = llama.cpp 部署 + Whisper 语音输入。分工清晰:
你说的话 ──► Whisper ──► 文字 ──► messages(第 2 章契约)──► llama-server(6.2)──► 回答 (本节) │ └── 从这里开始,与打字输入完全同路
这个设计的教学价值在于解耦:语音不碰模型、不碰模板——它只是文本入口的另一个壳。所以本章不引入任何新的模型知识,只解决"转得准、转得快"两件事。
参数量与显存为 openai/whisper 官方 README 口径;"相对速度"是官方 README 给的量级示意(以 large 为 1× 基准,随硬件浮动);中文表现为本书经验概括,示意口径。
| 档位 | 参数量 | 显存 | 相对速度 | 中文表现(示意) |
|---|---|---|---|---|
| tiny | 39M | ~1GB | ~32× | 错误较多,简单短句勉强可用 |
| base | 74M | ~1GB | ~10× | 日常短句可用 |
| small | 244M | ~2GB | ~4× | 日常中文可用,性价比点 |
| medium | 769M | ~5GB | ~2× | 更稳,专有名词更好 |
| large(-v3 等版本) | 1550M | ~10GB | 1× | 最强,也最慢最贵 |
选档三问:机器有没有 GPU(无 GPU 优先 tiny/base,或转 whisper.cpp 路线);延迟要求多少(交互式闭环建议转写环节不超过 2 秒,见 7.2 预算表);口音与专有名词重不重(重则升档)。另有 English-only 的 .en 变体(如 tiny.en/base.en),中文场景不用。
档位与学生模型(124M)的对照值得玩味:Whisper small 244M 参数比你的对话模型还大——转写是"听清"的任务,容错低;对话是"说对"的任务,可窄可宽。两个模型的选型逻辑(准确率换实时性)完全同构。
录音三纪律:16kHz 采样率(Whisper 的输入口径)、单声道、控制单条时长(几秒的提问比长段独白体验好,也让低档位模型够用)。
# record_and_transcribe.py —— 录音并转写(写法示意,以 openai/whisper README 为准) # 依赖:pip install openai-whisper sounddevice import wave import sounddevice as sd import whisper SR, SECS = 16000, 6 # 16kHz、单声道、固定 6 秒 print("请说话…") audio = sd.rec(int(SECS * SR), samplerate=SR, channels=1, dtype="int16") sd.wait() with wave.open("data_voice/question.wav", "w") as w: w.setnchannels(1) w.setsampwidth(2) w.setframerate(SR) w.writeframes(audio.tobytes()) model = whisper.load_model("small") # 档位表选出的性价比点 result = model.transcribe("data_voice/question.wav", language="zh", fp16=False) print("转写:", result["text"])
两个参数说明:language="zh" 显式指定语言,省去语言检测的开销与误判;fp16=False 兼容纯 CPU 运行。长音频的切窗由库内处理(30 秒窗口口径),教学场景的几秒提问碰不到这个边界。
💡 档位不是一次性的决定:7.2 的实时性预算表会逼你回头改选——先记下本机各档的大致耗时(附录 C 第 7 题正是这个练习),预算表才有数字可填。
| 病 | 症状 | 处置 |
|---|---|---|
| 简繁混杂 | 简体语音转出繁体字(Whisper 的常见现象,社区广泛报告) | 转写参数加 initial_prompt 引导简体(写法示意:transcribe(..., initial_prompt="以下是简体中文的普通话。"),以官方文档为准);或转写后过一遍简繁转换 |
| 静音幻觉 | 没说话的段落被"编"出一句旁白(Whisper 对静音/噪声的已知弱点) | 录音掐头去尾裁静音;转写为空或过短时直接忽略本轮 |
| 太慢 | 转写耗时超过对话预算(7.2 表) | 降档(small→base→tiny);CPU 场景考虑 whisper.cpp 路线(以官方仓库 README 为准) |
| 专有名词错 | 人名/术语被转成同音字 | 升档(small 以上);initial_prompt 里给一两个正确写法做示例(写法示意,同简繁引导) |
⚠️ 转写字符串进 messages 前做一次轻清洗:去首尾空白、去偶发的时段标记(如 [00:00])——但不要过度纠错,改错字是下一个模型的事,入口保持透明,出问题才好定位。
文字这一端稳了——7.2 节把录音、转写、6.2 的对话服务串成一条会听会说的完整回路。