第30章 Voicebox 语音转写(Transcription)架构与实现
开发者 - 语音转写(Transcription)
Voicebox 中基于 Whisper 的音频转写是如何实现的
概述
Voicebox 使用 OpenAI 的 Whisper 做自动语音识别(ASR)。转写功能支撑两个流程:
- 参考文本自动填充——用户录制或上传语音样本时,后端自动转写并填充 reference_text 字段,供声音克隆使用。
- 按需转写——面向用户的 /transcribe 接口,可转写任意音频。
在 Apple Silicon 上,转写走 MLX-Whisper(来自 mlx-audio),推理速度比 PyTorch 快约 8 倍;其他平台则使用 PyTorch 的 transformers 版 Whisper。
架构
转写与 TTS 共用同一套后端抽象。STTBackend 协议定义在 backend/backends/__init__.py:
@runtime_checkable
class STTBackend(Protocol):
async def load_model(self, model_size: str) -> None: ...
async def transcribe(
self,
audio_path: str,
language: Optional[str] = None,
model_size: Optional[str] = None,
) -> str: ...
def unload_model(self) -> None: ...
def is_loaded(self) -> bool: ...
目前提供两个实现:
- MLXSTTBackend(backends/mlx_backend.py)——调用 mlx_audio.stt.load(),Apple Silicon 上的默认选项。
- PyTorchSTTBackend(backends/pytorch_backend.py)——调用 transformers.WhisperForConditionalGeneration,其他平台的默认选项。
get_stt_backend() 会根据 get_backend_type() 自动选择合适的后端。backend/services/transcribe.py 是一个轻量封装,负责委托给后端执行。
模型规格
ModelConfig 中注册了五个 Whisper 变体:
| 模型 | HuggingFace 仓库 | 大小 | 说明 |
|---|---|---|---|
| Base | openai/whisper-base | 约 300 MB | 默认选项,速度快、质量尚可 |
| Small | openai/whisper-small | 约 500 MB | 质量更好,速度依然很快 |
| Medium | openai/whisper-medium | 约 1.5 GB | 高质量 |
| Large | openai/whisper-large-v3 | 约 3 GB | 质量最佳,CPU 上较慢 |
| Turbo | openai/whisper-large-v3-turbo | 约 1.5 GB | Large 级质量,速度约快 5 倍 |
tiny 模型未开放——相比 base 质量差距太大,不值得下载。
v0.1.10 中,Apple Silicon 上结合 Turbo 与 MLX-Whisper 后,用户端转写延迟从约 20 秒降至 2-3 秒。
语言提示
Whisper 能自动检测语言,但对短音频而言,提供语言提示可提升准确率:
text = await backend.transcribe(audio_path, language="en")
支持标准的 Whisper 语言集合(99 种以上)。前端通常会传入 profile 中配置的语言,否则交给 Whisper 自动检测。
模型加载
两个后端都是懒加载:首次使用时才加载模型并缓存到内存中。切换模型规格时会卸载上一个模型。
MLX 通过 mlx_audio.stt.load(hf_repo) 加载;PyTorch 则通过:
WhisperProcessor.from_pretrained(hf_repo)
WhisperForConditionalGeneration.from_pretrained(hf_repo).to(device)
两条加载路径都使用 backends/base.py 中的 model_load_progress(),因此首次使用时前端可以实时看到下载进度。
音频预处理
Whisper 要求单声道 16 kHz 音频。backend/utils/audio.py 中的音频工具会透明地完成重采样和格式转换:
- 支持格式:WAV、MP3、FLAC、OGG、M4A(通过 soundfile / librosa)
- 目标格式:单声道、16 kHz、float32
超过 Whisper 30 秒窗口的长音频由底层库的分块逻辑处理——Voicebox 代码中无需显式切分。
API 接口
| 方法 | 路径 | 说明 |
|---|---|---|
| POST | /transcribe | 转写上传的音频文件 |
请求
Multipart 表单数据:
POST /transcribe
Content-Type: multipart/form-data
file: <audio_file>
language: en # 可选
model_size: base # 可选(默认 "base")
响应
{
"text": "Hello, this is a test transcription.",
"duration": 3.5
}
使用场景
声音克隆的参考文本
添加语音样本时会自动触发转写:
- 用户上传或录制音频。
- 后端保存音频文件并在内部调用 /transcribe(或由前端单独调用)。
- 返回的文本写入新 profile_samples 记录的 reference_text 字段。
- 需要参考文本的克隆引擎(Chatterbox、TADA 等)从这里读取。
质量建议
- 短音频(5 秒以内)建议提供语言提示——音频太少时自动检测不可靠。
- 嘈杂音频建议用 Turbo 或 Large——Base 在困难输入上可能产生幻觉。
- 尽量使用干净的音频;转写错误会变成参考文本错误,进而导致克隆错误。
内存管理
unload_model() 会释放模型引用,并在适用时清空 CUDA 缓存。/models/unload 接口提供了手动控制的入口。
get_stt_backend() 为每个后端返回单例——多个调用方共享同一个 Whisper 实例。
错误处理
| 错误 | 原因 | 解决方案 |
|---|---|---|
| 模型未找到 | 首次运行时网络故障 | 重试;检查网络连接 |
| 加载时内存溢出 | 低显存 GPU 加载大模型 | 切换到 Small 或 Turbo |
| 结果为空 | 音频中没有语音 | 确认输入包含人声;检查裁剪设置 |
| 语言识别错误 | 自动检测失效 | 传入语言提示 |
下一步
- 模型管理——模型的下载、加载与卸载
- 语音档案——参考文本如何与语音样本一同存储
- GPU 加速——各平台的加速方案,包括 MLX-Whisper
在 GitHub 上编辑本页
- 故事与时间线——Voicebox 中多语音时间线编辑器的实现
- 音频通道——音频输出路由的工作原理