转写接口
通过 WebSocket 长连接进行语音转写:边推音频边返回中间结果,停止时返回最终文本。
与「语音识别接口」的区别:本接口面向一次连续录音的流式转写,采用
start / stop / cancel控制协议,并支持热词与计费幂等键recording_id。
一、接口信息
- 路径:
/v1/asr/stream - 方式:
GET(WebSocket 升级) - 认证: 非浏览器客户端用 Header
X-API-Key;浏览器客户端用 Query 参数api_key
| 场景 | 方式 | 示例 |
|---|---|---|
| 非浏览器 | Header X-API-Key | X-API-Key: your-secret-key-here |
| 浏览器 | Query api_key | wss://api.vuilabs.cn/v1/asr/stream?api_key=your-secret-key-here |
浏览器 WebSocket 无法自定义请求头,故浏览器场景用
api_key查询参数。 API Key 在 控制台 → 项目空间 选择项目后,于「API Key 管理」创建/查看。
二、交互流程
一条 WebSocket 连接对应一次录音,顺序固定:
- 发送
start控制帧(文本帧,JSON); - 收到
recording_started后,即可开始发送音频; - 持续发送二进制音频块,其间可能多次收到
asr_partial; - 发送
stop后,接收最终结果asr_final; - 如需中途放弃,发送
cancel。
client ──(text) start──────────────▶
◀──────recording_started────── 转写 API
client ──(binary) audio chunk──────▶
◀──────asr_partial──────────── 转写 API
client ──(text) stop───────────────▶
◀──────asr_final────────────── 转写 API
三、客户端发送消息
控制消息为文本帧(JSON);音频为二进制帧。
1. start:开始录音
{
"type": "start",
"audio_format": "opus",
"recording_id": "rec-20260622-0001",
"hotwords": ["Hi SaySo", "氨基酸"]
}
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| type | string | 是 | 固定为 start |
| audio_format | string | 否 | 音频格式:opus / pcm,默认 opus |
| recording_id | string | 否 | 本次录音 ID,计费幂等键,建议客户端生成且全局唯一 |
| hotwords | string[] | 否 | 热词列表,提升专有名词、品牌名等的识别准确率 |
| selected_text | string | 否 | 选中文本。传入则进入 AI 助手模式(见下方说明),不传为普通转写 |
AI 助手模式(划词)
start 帧带上 selected_text 时,本次录音不再只是转写,而是把这次语音转写出的内容当作"指令",对 selected_text 执行你想做的操作(翻译、润色、总结、改写、答疑等):
{
"type": "start",
"audio_format": "opus",
"selected_text": "The weather is nice today."
}
例如选中 The weather is nice today. 后说"翻译成中文",asr_final 会在 assistant_text 里返回处理结果(见四、响应事件)。
说明:
- 单次交互——一条连接一次"选中→说指令→出结果",结束即关连接(与普通转写一致)。
- 助手处理为尽力而为:失败或无结果时
assistant_text为空,此时可回退为仅展示指令转写。
2. 发送音频块
直接发送 binary 音频块,无需 Base64:
audio_format = pcm:raw PCM(16-bit 有符号小端、16000 Hz、单声道);audio_format = opus:Opus 编码后的音频块。
3. stop / cancel
{ "type": "stop" }
结束录音,并接收最终转写结果 asr_final。
{ "type": "cancel" }
中途放弃转写,连接随后关闭。
四、响应事件
响应为 JSON 文本消息,通过 type 区分事件类型。
| type | 说明 |
|---|---|
| recording_started | 转写已就绪,可开始发送音频 |
| asr_partial | 中间结果,过程中可能多次返回 |
| asr_final | 最终结果,stop 后返回一次 |
| error | 识别失败 |
事件字段
| 字段 | 类型 | 说明 |
|---|---|---|
| type | string | 事件类型 |
| text | string | 识别文本(asr_partial / asr_final)。AI 助手模式下为指令转写(听到的内容) |
| source_text | string | 文本优化生效时,asr_final 返回优化前的原始转写;否则为空 |
| assistant_text | string | AI 助手模式(start 带 selected_text)下,asr_final 返回对选中文本执行指令后的处理结果;普通转写为空 |
| audio_duration_ms | number | 音频时长(毫秒,asr_final,计费向下取整到秒) |
| word_count | number | 转写字数(asr_final) |
| model | string | 实际使用的识别模型(asr_final) |
| code | string | 错误码(仅 error) |
| message | string | 错误信息(仅 error) |
事件示例
{ "type": "asr_partial", "text": "今天天气" }
{
"type": "asr_final",
"text": "今天天气不错。",
"audio_duration_ms": 2480,
"word_count": 7,
"model": "qwen3-asr-flash-realtime"
}
AI 助手模式(start 带 selected_text,例如选中英文后说"翻译成中文"):
{
"type": "asr_final",
"text": "翻译成中文",
"assistant_text": "今天天气不错。",
"audio_duration_ms": 1860,
"word_count": 5,
"model": "qwen3-asr-flash-realtime"
}
{ "type": "error", "code": "ASR_COMMIT_FAILED", "message": "upstream commit failed" }
五、请求示例
Python
import asyncio, json, websockets
async def main():
uri = "wss://api.vuilabs.cn/v1/asr/stream"
headers = {"X-API-Key": "your-secret-key-here"}
async with websockets.connect(uri, additional_headers=headers) as ws:
await ws.send(json.dumps({
"type": "start",
"audio_format": "pcm",
"recording_id": "rec-20260622-0001",
"hotwords": ["Hi SaySo", "氨基酸"],
}))
with open("sample.pcm", "rb") as f:
while chunk := f.read(4096):
await ws.send(chunk)
await ws.send(json.dumps({"type": "stop"}))
async for message in ws:
event = json.loads(message)
print(event)
if event.get("type") in ("asr_final", "error"):
break
asyncio.run(main())
Browser JavaScript
const ws = new WebSocket("wss://api.vuilabs.cn/v1/asr/stream?api_key=your-secret-key-here");
ws.binaryType = "arraybuffer";
ws.addEventListener("open", () => {
ws.send(JSON.stringify({ type: "start", audio_format: "opus", hotwords: ["Hi SaySo"] }));
ws.send(audioArrayBuffer); // 录音编码后的二进制块
ws.send(JSON.stringify({ type: "stop" }));
});
ws.addEventListener("message", (event) => console.log(JSON.parse(event.data)));
六、错误码
识别失败时通过 error 事件返回 code 与 message。
| 错误码 / 状态 | 说明 |
|---|---|
| 401 | API Key 无效或未授权(握手阶段返回 HTTP 401) |
| 429 | 请求频率超限 |
| 402 | 余额不足 |
| INVALID_META | start 消息缺失或格式错误 |
| ASR_INIT_FAILED | 初始化语音识别失败 |
| ASR_CONNECT_FAILED | 连接语音识别服务失败 |
| ASR_COMMIT_FAILED | 提交音频并获取最终识别结果失败 |
| QUOTA_EXCEEDED | 单次录音音频超出大小上限 |
七、计费说明
具体计费规则、价格和免费额度请参见 产品计费。