首页 → 博客 → Python 语音转文字:从一个文件到可用脚本
Python 语音转文字:从一个文件到可用脚本
用 Python 做语音转文字只需要四行代码。这篇教程讲的是四行之外不那么显然的部分:该请求哪种响应格式、文件太大怎么办,以及为什么你的第一版脚本会比它应有的速度慢得多。
安装与第一个请求
只有一个依赖——官方 OpenAI SDK。API 在协议层兼容,不需要任何专用客户端:
pip install openai
from openai import OpenAI
client = OpenAI(base_url="https://voicesscribe.com/v1", api_key="your key")
with open("audio.mp3", "rb") as f:
result = client.audio.transcriptions.create(model="whisper-1", file=f)
print(result.text)
这就是全部。密钥请放进环境变量,不要写进源代码:
import os
client = OpenAI(base_url="https://voicesscribe.com/v1", api_key=os.environ["VS_KEY"])选择响应格式
默认返回一个带 text 字段的对象。另外三种格式各有用途:
| 格式 | 返回内容 | 适用场景 |
|---|---|---|
json | 带 .text 的对象 | 默认;只需要文字本身 |
verbose_json | 分段、时间轴、检测出的语种 | 时间戳、章节、质量检查 |
srt / vtt | 现成的字幕文件字符串 | 给视频配字幕 |
text | 不带外壳的纯字符串 | 直接管道给下一个工具 |
用 verbose_json 时,响应还带有检测出的语种及其置信度——这是你能拿到的最便宜的质量信号:
r = client.audio.transcriptions.create(
model="whisper-1", file=f, response_format="verbose_json",
)
for s in r.segments:
print(f"[{s.start:6.1f}] {s.text.strip()}")
if r.language_probability < 0.6:
print("可疑的录音——值得人工检查一下")正确地处理错误
SDK 抛出带类型的异常,处理起来很直接。关键的区分:有些错误值得重试,有些永远会以同样方式失败。
from openai import APIStatusError, APIConnectionError
try:
r = client.audio.transcriptions.create(model="whisper-1", file=f)
except APIConnectionError:
... # 网络问题——重试有意义
except APIStatusError as e:
if e.status_code == 401:
raise RuntimeError("密钥无效")
if e.status_code == 413:
raise RuntimeError("文件超过 25 MB——压缩或切分")
if e.status_code == 429:
... # 限流或额度用尽——等待后再试
raise
400 通常意味着文件为空或已损坏。先确认它能被播放器打开,再怀疑 API。
超过 25 MB 的文件
单次请求限制 25 MB。两条出路,按优先级排列。
先重新编码。超限的文件多数是 wav 或高码率立体声。16 kHz 单声道正是模型内部使用的规格:
ffmpeg -i input.wav -ac 1 -ar 16000 -b:a 48k output.mp3
转换之后一小时音频约 25 MB——大部分文件根本不再需要切分。
仍然太大再切分。按停顿切而不是按固定分钟切,句子才能保持完整:
ffmpeg -i long.mp3 -f segment -segment_time 1800 -c copy part%03d.mp3让脚本跑得更快
每个人写的第一版脚本都是逐个文件处理,几乎全部时间耗在等网络上。转录是 IO 密集型任务,线程正好解决:
from concurrent.futures import ThreadPoolExecutor
def transcribe(path):
with open(path, "rb") as f:
return client.audio.transcriptions.create(model="whisper-1", file=f).text
with ThreadPoolExecutor(max_workers=4) as pool:
texts = list(pool.map(transcribe, paths))
max_workers 按套餐的每秒请求数限制来定,不是按 CPU 核数。开得比限制更宽,只会把成功的请求变成 429。
用自有词表提高准确率
最被低估的参数是 prompt。它不会出现在输出里——只是把识别向你列出的词偏移:
r = client.audio.transcriptions.create(
model="whisper-1", file=f,
prompt="产品:红隼、鹰巢。发言人:杜阿尔特、张伟。",
language="zh",
)
音频里真实出现的二十到四十个术语有效;一整段泛泛的描述没有作用。音频是单一语种时加上 language,能消除短片段上的语种误判。
最浪费时间的几个错误
- 把整个文件读进内存再当字节传。直接传文件对象——SDK 会流式上传。
- 对空结果重试。空字符串意味着没有语音,不是出了故障。重试只会消耗分钟数。
- 长文件用默认超时。客户端默认值适合短片段;一小时的录音要调大。
- 把 8 kHz 电话音频上采样到 44 kHz指望更准。只会增加字节,不会增加信息。
用你自己的录音试一试。 注册只需一分钟,免费额度足够判断识别质量。
免费获取 API 密钥常见问题
需要专门的 Python 库吗?
不需要,官方 openai 包直接可用——API 在协议层兼容。与 OpenAI 默认配置的区别只有 base_url 和密钥。
需要用 Python 预处理音频格式吗?
基本不用:ogg、opus、mp3、wav、m4a、webm 都按原样接收。转成 16 kHz 单声道 mp3 只是为了不超过 25 MB 的请求限制。
Python 里怎么拿到时间戳?
请求 response_format=verbose_json——响应包含带起止时间的分段,以及检测出的语种和置信度。
可以并行转录多个文件吗?
可以,用 ThreadPoolExecutor。转录是在等网络,线程是对的工具;线程池设得略低于套餐的每秒请求数限制。
超过 25 MB 的文件怎么办?
先重新编码成 16 kHz 单声道——大部分情况这一步就够了。仍然太大就按停顿切分,再把结果合并。
相关阅读
- 如何为音频存档搭建批量转录流水线 — 转录上万条录音而不丢失任何一条:任务队列、并发控制、重试策略、崩溃后续跑,以及如何把账单控制在预期之内。
- 如何提高语音识别准确率:八个实用方法 — 真正能改善转录质量的八件事:音频预处理、指定语种、prompt 词表、切分策略、响应格式,以及如何测量字错率。
- 语音消息转文字:Telegram、WhatsApp 及其他即时通讯工具 — 如何自动把语音消息转成文字:处理 ogg/opus 格式、提升短录音准确率、应对静音,以及可直接使用的聊天机器人代码。