Whisper-1 语音转文字 API 调用指南

Whisper-1 语音转文字 API 调用指南

很多人第一次调用 Whisper 会卡住,主要原因是:这个接口不是普通 JSON 请求,而是 multipart/form-data 文件上传请求。你需要把音频文件作为 file 字段上传,再告诉接口使用 whisper-1 模型。

本文用 OpenAI 兼容接口举例,官方 OpenAI 和很多中转 API 都是同样的调用方式。

1. 接口地址

官方 OpenAI:

https://api.331704.shop/v1/audio/transcriptions

中转 API:

https://你的中转域名/v1/audio/transcriptions

如果你的中转后台只给了 base URL,比如:

https://example.com

那么完整转录接口通常是:

https://example.com/v1/audio/transcriptions

2. 请求方式

请求方法:

POST

请求类型:

multipart/form-data

不要用普通 JSON body。下面这种是错的:

{
  "model": "whisper-1",
  "file": "audio.mp3"
}

file 必须是真实的文件二进制上传。

3. 最小 curl 示例

curl https://api.331704.shop/v1/audio/transcriptions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -F "model=whisper-1" \
  -F "file=@audio.mp3"

如果你使用中转 API,把 URL 换成中转地址:

curl https://example.com/v1/audio/transcriptions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -F "model=whisper-1" \
  -F "file=@audio.mp3"

4. 推荐请求参数

更适合做视频拆解、字幕切分、时间轴分析的写法:

curl https://example.com/v1/audio/transcriptions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -F "model=whisper-1" \
  -F "response_format=verbose_json" \
  -F "temperature=0" \
  -F "file=@audio.mp3"

参数说明:

参数 作用
model 固定填 whisper-1
file 要转录的音频文件
response_format 推荐 verbose_json,会返回分段和时间戳
temperature 推荐 0,输出更稳定

5. 为什么推荐 verbose_json

默认返回可能只有一整段文字。做视频分析时,我们更需要知道“第几秒说了什么”,所以推荐:

response_format=verbose_json

返回结果里会有类似:

{
  "text": "有兄弟说想看我穿黑线,安排。",
  "segments": [
    {
      "start": 0.0,
      "end": 2.0,
      "text": "有兄弟说想看我穿黑线"
    },
    {
      "start": 2.0,
      "end": 4.0,
      "text": "安排"
    }
  ]
}

这样就可以做成:

[00:00] 有兄弟说想看我穿黑线
[00:02] 安排

6. 从视频里提取音频

Whisper 接收音频文件,不需要上传整个视频。推荐先用 ffmpeg 从视频里提取一个较小的 MP3:

ffmpeg \
  -i input.mp4 \
  -vn \
  -acodec libmp3lame \
  -ar 16000 \
  -ac 1 \
  -b:a 64k \
  audio.mp3

含义:

参数 作用
-vn 不要视频,只保留音频
-ar 16000 采样率转为 16kHz
-ac 1 单声道
-b:a 64k 音频码率 64kbps,文件更小

这种格式足够语音识别使用,上传也更快。

7. Python 标准库示例

下面是不依赖 OpenAI SDK 的写法,适合想看清楚请求体结构的人:

from pathlib import Path
from urllib.request import Request, urlopen
import uuid
import json

api_key = "sk-你的key"
endpoint = "https://example.com/v1/audio/transcriptions"
audio_path = Path("audio.mp3")

boundary = f"----Boundary{uuid.uuid4().hex}"
body = bytearray()

def add_field(name, value):
    body.extend(f"--{boundary}\r\n".encode())
    body.extend(f'Content-Disposition: form-data; name="{name}"\r\n\r\n'.encode())
    body.extend(str(value).encode())
    body.extend(b"\r\n")

add_field("model", "whisper-1")
add_field("response_format", "verbose_json")
add_field("temperature", "0")

body.extend(f"--{boundary}\r\n".encode())
body.extend(
    f'Content-Disposition: form-data; name="file"; filename="{audio_path.name}"\r\n'.encode()
)
body.extend(b"Content-Type: audio/mpeg\r\n\r\n")
body.extend(audio_path.read_bytes())
body.extend(b"\r\n")
body.extend(f"--{boundary}--\r\n".encode())

headers = {
    "Authorization": f"Bearer {api_key}",
    "Content-Type": f"multipart/form-data; boundary={boundary}",
}

req = Request(endpoint, data=bytes(body), headers=headers, method="POST")

with urlopen(req, timeout=300) as res:
    data = json.loads(res.read().decode("utf-8"))

print(data["text"])
for segment in data.get("segments", []):
    print(segment["start"], segment["end"], segment["text"])

8. Node.js 示例

Node 18+ 可以用内置 fetchFormDataBlob

import { readFile } from "node:fs/promises";

const apiKey = process.env.OPENAI_API_KEY;
const endpoint = "https://example.com/v1/audio/transcriptions";

const audioBuffer = await readFile("audio.mp3");

const form = new FormData();
form.append("model", "whisper-1");
form.append("response_format", "verbose_json");
form.append("temperature", "0");
form.append("file", new Blob([audioBuffer], { type: "audio/mpeg" }), "audio.mp3");

const res = await fetch(endpoint, {
  method: "POST",
  headers: {
    Authorization: `Bearer ${apiKey}`,
  },
  body: form,
});

if (!res.ok) {
  throw new Error(`${res.status} ${await res.text()}`);
}

const data = await res.json();
console.log(data.text);
console.log(data.segments);

注意:使用 FormData 时,不要自己手动设置 Content-Type。让 fetch 自动生成 boundary。

9. 常见错误

1. 用 JSON 上传文件

错误原因:file 不是字符串路径,必须是 multipart 文件。

正确做法:

-F "file=@audio.mp3"

2. 中转地址少了 /v1/audio/transcriptions

如果中转只给你:

https://example.com

不要直接 POST 到根路径。通常要补成:

https://example.com/v1/audio/transcriptions

3. 中转不支持 whisper-1

报错可能类似:

model_not_found
whisper-1 无可用渠道

这不是你的请求体写错,而是中转平台当前没有给 whisper-1 分配可用渠道。可以稍后重试,或换一个支持音频转录的中转。

4. 文件太大

Whisper 上传有大小限制。建议先用 ffmpeg 压成 16kHz、单声道、64kbps MP3。如果还是太大,就按时长切片上传,再把时间戳拼回去。

5. 没有时间戳

如果你只拿到纯文本,检查是否设置了:

response_format=verbose_json

10. 完整工作流

一个实用的视频转录流程是:

# 1. 从视频提取小体积音频
ffmpeg -i input.mp4 -vn -acodec libmp3lame -ar 16000 -ac 1 -b:a 64k audio.mp3

# 2. 调用 whisper-1 转录
curl https://example.com/v1/audio/transcriptions \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -F "model=whisper-1" \
  -F "response_format=verbose_json" \
  -F "temperature=0" \
  -F "file=@audio.mp3"

核心记住一句话:

Whisper-1 = POST multipart/form-data,把音频文件作为 file 上传。

Subscribe to GAGUA AI

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe