Python 标准库调用 Audio Transcriptions API 的超时与异常处理

把会议录音交给语音识别模型,最容易忽略的不是"识别准不准",而是输入与故障:文件可能为空、格式不支持、网络长时间无响应,或录音本身含个人信息。一个入门但可复用的转写入口应该先拒绝明显错误,再给网络请求时间上限,并把失败变成可处理的状态。本文用 Python 标准库演示 multipart 上传;你可以把它接到上传页面、定时任务或客服质检流程。

语音识别(Automatic Speech Recognition,ASR)会把音频波形转换为文本。模型负责听写,应用仍须负责文件白名单、上传授权、重试策略和文本后处理。官方 Speech-to-Text 文档列出音频转写能力与接口;请在部署时以账号控制台和最新文档确认模型 ID、大小限制、价格及数据政策。

flowchart LR F[用户授权的音频文件] --> S{大小/扩展名检查} S -->|不通过| E[提示重新上传] S -->|通过| M[multipart 请求] M --> A[转写 API] A --> T{超时或错误?} T -->|否| X[保存文本与最少审计信息] T -->|是| R[可追踪失败/人工处理]

环境与运行

Python 3.10+ 无第三方依赖。只在有录音所有者授权的前提下使用;示例不上传任何本地文件。

bash 复制代码
export OPENAI_API_KEY='你的密钥'
python3 transcribe.py meeting.mp3

完整代码

本例构造 multipart 请求并将总请求限制为 45 秒。为让代码聚焦流程,使用当前官方转写文档中的 gpt-4o-transcribe 作为示例模型;接口或权限变化时应以官方文档为准。

python 复制代码
import json, mimetypes, os, pathlib, sys, uuid
import urllib.error, urllib.request

MAX_BYTES = 20 * 1024 * 1024
def part(boundary, name, value, filename=None, content_type=None):
    head = f"--{boundary}\\r\\nContent-Disposition: form-data; name=\\\"{name}\\\""
    if filename: head += f"; filename=\\\"{filename}\\\"\\r\\nContent-Type: {content_type}"
    return head.encode() + b"\\r\\n\\r\\n" + (value if isinstance(value, bytes) else value.encode()) + b"\\r\\n"

def transcribe(path: pathlib.Path):
    key = os.getenv("OPENAI_API_KEY")
    if not key: raise RuntimeError("缺少 OPENAI_API_KEY")
    if not path.is_file() or path.stat().st_size == 0 or path.stat().st_size > MAX_BYTES:
        raise ValueError("文件不存在、为空或超过教学上限 20MB")
    mime = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
    if mime not in {"audio/mpeg", "audio/wav", "audio/mp4", "audio/x-m4a"}:
        raise ValueError("请使用 mp3、wav、m4a 或 mp4 音频")
    boundary = "----snail" + uuid.uuid4().hex
    data = part(boundary, "model", "gpt-4o-transcribe")
    data += part(boundary, "file", path.read_bytes(), path.name, mime)
    data += f"--{boundary}--\\r\\n".encode()
    req = urllib.request.Request("https://api.openai.com/v1/audio/transcriptions", data=data,
        headers={"Authorization": "Bearer " + key, "Content-Type": "multipart/form-data; boundary=" + boundary})
    with urllib.request.urlopen(req, timeout=45) as resp:
        if resp.status != 200: raise RuntimeError(f"HTTP {resp.status}")
        return json.load(resp)["text"]

if __name__ == "__main__":
    try: print(transcribe(pathlib.Path(sys.argv[1])))
    except (IndexError, ValueError, RuntimeError, urllib.error.URLError, TimeoutError) as e:
        print(f"TRANSCRIBE_FAILED: {e}", file=sys.stderr); raise SystemExit(2)

如何理解输出与失败

成功时标准输出是一段文本;失败时进程返回码为 2,并以 TRANSCRIBE_FAILED 开头,便于任务队列识别。mimetypes 只是初筛,恶意上传仍可能伪装扩展名,生产环境还应检测文件头、扫描恶意文件。45 秒并不是最佳值:短音频可更短,长音频应采用拆分、异步任务与可取消状态,而不是无止境等待。

本次用 python3 -m py_compile transcribe.py 完成语法检查,未设置真实密钥、未上传或调用线上 API。常见失败包括:一,密钥权限或余额不足;二,音频编码与扩展名不符;三,网络代理导致超时。分别处理为:不记录密钥、用音频工具规范化编码、将超时任务标为可重试并设置最大次数。

何时采用与如何工程化

适合会议纪要初稿、客服质检、用户明确授权的访谈检索;不适合把未审阅文本当法律、医疗或人事结论。下一步可增加说话人分离、术语表、敏感信息打码、对象存储临时链接和删除策略。五分钟实践:给代码加一个 --dry-run 参数,只打印文件大小与 MIME 类型,确保 CI 不会意外把测试音频传上云。

语音转写失败时,你会优先重试、拆分音频还是转人工?

关注「蜗牛聊AI」,一起看懂技术变化背后的真正机会。


本文首发于 java4u.cn,转载请注明出处。

相关推荐
康小汪13 小时前
AI 写 Vue 总写成同一个味道:给它装 Skills,装的不是知识是边界
前端·vue.js·人工智能·ai编程·最佳实践
收放扳机13 小时前
多机连线(In-Line)场景下,收放板机“缓存工位”的容量与架构选型参考
人工智能·科技·自动化·制造·pcb工艺
武天旭13 小时前
AI安全--AI大模型的后门攻击检测与防御
人工智能·深度学习·安全·机器学习
智能运维指南14 小时前
研制过程“两张皮“怎么破:研制一体化支撑平台的定位、能力边界与落地前提
java·前端·人工智能·嘉为蓝鲸
人工智能AI技术14 小时前
DeepInfer开源炸场!别再妄想个人电脑跑满血DeepSeek
人工智能
深蓝电商API14 小时前
用AI生成拟人行为:让鼠标轨迹更“有人味”
人工智能·爬虫
znnnk14 小时前
数据库被AI“重写”:2026,从CPU中心走向GPU中心
数据库·人工智能·oracle
深蓝AI14 小时前
网站正在对 AI Agent 集体关门:亚马逊封锁 Muse、银行拒绝登录,开发者怎么活下去
人工智能
jason_renyu14 小时前
Vue 4 × AI:流式对话、Agent 状态与高性能渲染的下一代组合
人工智能·vue4·vue4和ai·vue4xai
镭封15 小时前
从视频文案提取到 AI 配音,短视频制作需要哪些工具?
人工智能·智能手机·音视频·语音识别·媒体