说明
基于 WebSocket 的流式语音转文字接口,协议风格对齐 OpenAI Realtime。全部消息均为 JSON 文本帧,PCM 音频以 Base64 放入 JSON 字段传输,适用于实时字幕、边录边转、直播转写等场景。- 接入地址:
wss://api.senseaudio.cn/ws/v1/realtime/transcriptions - 鉴权方式:Bearer Token,格式
Authorization: Bearer SENSEAUDIO_API_KEY - 消息载体:全部为文本 JSON 帧(音频也以 Base64 放在 JSON 中,非二进制帧)
- 音频格式:PCM signed 16-bit little-endian,单声道;采样率支持 16000 / 24000
- 模型参数:默认
senseaudio-asr-stream-1.5-260910 - 计费单位:按音频时长计费,3.6 元 / 小时,详见 计费说明
- 离线转写:文件批量转写请使用 语音识别转写
- 本接口与
/ws/v1/audio/transcriptions(语音识别 WebSocket)协议不兼容:本接口全部使用 JSON 文本帧,音频必须 Base64 编码。 - 声道数不可通过接口配置,服务端固定为单声道
channel=1。 - 客户端需先发送
session.update,收到session.updated后再开始推送音频。
请求头 (Request Headers)
| 参数名 | 必填 | 说明 | 示例 |
|---|---|---|---|
| Authorization | 是 | 鉴权 Token。格式:Bearer SENSEAUDIO_API_KEY | Bearer sk-123456… |
通信流程
1. 客户端建立 WebSocket 连接
↓
2. 服务端返回 session.created(可选)
↓
3. 客户端发送 session.update(配置识别参数)
↓
4. 服务端返回 session.updated
↓
5. 客户端循环发送 input_audio_buffer.append(Base64 PCM)
↓
6. 服务端返回中间识别 / VAD / 转写事件(可多次)
↓
7. 客户端发送 sense_asr.session.finish
↓
8. 服务端返回最终识别事件 → sense_asr.session.finished
客户端事件
1. session.update - 初始化会话
必须作为首个业务消息发送,用于配置音频格式、识别模型、VAD 与扩展能力。 请求参数| 参数路径 | 类型 | 必填 | 说明 |
|---|---|---|---|
| type | string | 是 | 固定值:session.update |
| session.type | string | 否 | 只能为空或 transcription |
| session.audio.input.format.type | string | 否 | 默认 audio/pcm;仅支持 audio/pcm、pcm |
| session.audio.input.format.rate | int | 否 | 默认 16000;仅支持 16000 或 24000 |
| session.audio.input.transcription.model | string | 否 | 默认 senseaudio-asr-stream-1.5-260910 |
| session.audio.input.transcription.prompt | string | 否 | 识别提示词 |
| session.audio.input.transcription.keywords | string[] | 否 | 热词数组 |
| session.audio.input.transcription.languages | string[] | 否 | 语言代码数组,如 ["zh", "en"] |
| session.audio.input.turn_detection.type | string | 否 | 仅支持 server_vad;不传则不配置 VAD |
| session.audio.input.turn_detection.threshold | number | 否 | VAD 阈值 |
| session.audio.input.turn_detection.prefix_padding_ms | int | 否 | 语音开始前保留时长(毫秒) |
| session.audio.input.turn_detection.silence_duration_ms | int | 否 | 判定语音结束的静音时长(毫秒) |
| session.x_sense_asr.sentence_timestamps.enabled | boolean | 否 | 句子级时间戳,默认 false |
| session.x_sense_asr.word_timestamps.enabled | boolean | 否 | 字级时间戳,默认 false |
| session.x_sense_asr.speaker_diarization.enabled | boolean | 否 | 说话人区分 |
| session.x_sense_asr.speaker_diarization.preserve_overlap | boolean | 否 | 是否保留重叠语音 |
| session.x_sense_asr.translation.enabled | boolean | 否 | 是否启用翻译 |
| session.x_sense_asr.translation.target_language | string | 否 | 翻译目标语言 |
| session.x_sense_asr.smart_edit.enabled | boolean | 否 | 是否启用智能编辑 |
{
"type": "session.update",
"session": {
"type": "transcription",
"audio": {
"input": {
"format": { "type": "audio/pcm", "rate": 16000 },
"transcription": {
"model": "senseaudio-asr-stream-1.5-260910",
"prompt": "",
"keywords": ["SenseAudio", "实时转写"],
"languages": ["zh", "en"]
},
"turn_detection": {
"type": "server_vad",
"threshold": 0.5,
"prefix_padding_ms": 300,
"silence_duration_ms": 500
}
}
},
"x_sense_asr": {
"sentence_timestamps": { "enabled": true },
"word_timestamps": { "enabled": false },
"speaker_diarization": { "enabled": false, "preserve_overlap": false },
"translation": { "enabled": false, "target_language": "en" },
"smart_edit": { "enabled": false }
}
}
}
2. input_audio_buffer.append - 追加音频
每段音频一个 JSON 帧,audio 为 Base64 编码的 PCM 字节。建议每片约 100ms(16kHz 时约 3200 字节,24kHz 时约 4800 字节)。
{
"type": "input_audio_buffer.append",
"audio": "<Base64 编码的 PCM 字节>"
}
3. sense_asr.session.finish - 结束识别
音频全部发送完成后发送:{ "type": "sense_asr.session.finish" }
服务端事件
| 事件 type | 说明 |
|---|---|
| session.created | 连接建立后服务端先下发初始 session(在 session.updated 之前) |
| session.updated | 初始化成功,session.type 回显 transcription |
| sense_asr.client_ack | 对客户端事件的 ACK,含处理序号 |
| input_audio_buffer.speech_started | VAD 检测到语音开始 |
| input_audio_buffer.speech_stopped | VAD 检测到语音结束 |
| input_audio_buffer.committed | 音频缓冲提交为一条 item |
| conversation.item.created | 对话项创建 |
| conversation.item.input_audio_transcription.delta | 转写增量 |
| conversation.item.input_audio_transcription.completed | 转写最终稿,含 transcript、usage 等 |
| sense_asr.session.finished | 本次会话结束标志 |
{
"type": "session.updated",
"session": { "type": "transcription" }
}
{ "type": "sense_asr.session.finished" }
与语音识别 WebSocket 的区别
| 维度 | 语音识别 WebSocket /ws/v1/audio/transcriptions | 本接口 /ws/v1/realtime/transcriptions |
|---|---|---|
| 音频上传 | 二进制帧直接发 PCM | 文本 JSON 帧,PCM 做 Base64 放 audio 字段 |
| 控制事件 | task_start / task_finish / result_final | session.update / input_audio_buffer.append / sense_asr.session.finish |
| 模型 | senseaudio-asr-deepthink-1.5-260319 | senseaudio-asr-stream-1.5-260910 |
| 采样率 | 仅 16000 | 16000 / 24000 |
| 扩展能力 | vad_setting / transcription_setting | x_sense_asr(时间戳、说话人区分、翻译、智能编辑) |
| 计费 | 3.6 元 / 小时 | 3.6 元 / 小时 |
代码示例
- Python
- JavaScript
import asyncio
import base64
import json
import os
import websockets
WS_URL = "wss://api.senseaudio.cn/ws/v1/realtime/transcriptions"
API_KEY = os.environ["SENSEAUDIO_API_KEY"]
AUDIO_FILE = "audio_16k.pcm"
RATE = 16000
async def main():
headers = {"Authorization": f"Bearer {API_KEY}"}
async with websockets.connect(WS_URL, additional_headers=headers) as ws:
await ws.send(json.dumps({
"type": "session.update",
"session": {
"type": "transcription",
"audio": {
"input": {
"format": {"type": "audio/pcm", "rate": RATE},
"transcription": {
"model": "senseaudio-asr-stream-1.5-260910",
"languages": ["zh", "en"]
},
"turn_detection": {
"type": "server_vad",
"threshold": 0.5,
"prefix_padding_ms": 300,
"silence_duration_ms": 500
}
}
},
"x_sense_asr": {
"sentence_timestamps": {"enabled": True}
}
}
}))
# 等待 session.updated
while True:
msg = json.loads(await ws.recv())
if msg.get("type") == "session.updated":
break
chunk = RATE * 2 // 10 # 约 100ms
with open(AUDIO_FILE, "rb") as f:
while True:
data = f.read(chunk)
if not data:
break
await ws.send(json.dumps({
"type": "input_audio_buffer.append",
"audio": base64.b64encode(data).decode()
}))
await ws.send(json.dumps({"type": "sense_asr.session.finish"}))
while True:
msg = json.loads(await ws.recv())
print(msg.get("type"), msg.get("transcript") or msg.get("delta") or "")
if msg.get("type") == "sense_asr.session.finished":
break
asyncio.run(main())
const WebSocket = require('ws');
const fs = require('fs');
const WS_URL = 'wss://api.senseaudio.cn/ws/v1/realtime/transcriptions';
const API_KEY = process.env.SENSEAUDIO_API_KEY;
const AUDIO_FILE = 'audio_16k.pcm';
const RATE = 16000;
const ws = new WebSocket(WS_URL, {
headers: { Authorization: `Bearer ${API_KEY}` }
});
ws.on('open', () => {
ws.send(JSON.stringify({
type: 'session.update',
session: {
type: 'transcription',
audio: {
input: {
format: { type: 'audio/pcm', rate: RATE },
transcription: {
model: 'senseaudio-asr-stream-1.5-260910',
languages: ['zh', 'en']
},
turn_detection: {
type: 'server_vad',
threshold: 0.5,
prefix_padding_ms: 300,
silence_duration_ms: 500
}
}
},
x_sense_asr: {
sentence_timestamps: { enabled: true }
}
}
}));
});
let started = false;
ws.on('message', (data) => {
const msg = JSON.parse(data.toString());
console.log('<', msg.type);
if (msg.type === 'session.updated' && !started) {
started = true;
const chunkSize = Math.floor(RATE * 2 * 0.1);
const buf = fs.readFileSync(AUDIO_FILE);
for (let i = 0; i < buf.length; i += chunkSize) {
const chunk = buf.subarray(i, i + chunkSize);
ws.send(JSON.stringify({
type: 'input_audio_buffer.append',
audio: chunk.toString('base64')
}));
}
ws.send(JSON.stringify({ type: 'sense_asr.session.finish' }));
}
if (msg.type === 'sense_asr.session.finished') {
ws.close();
}
});
注意事项
- 全部 JSON 文本帧:控制消息与音频消息均使用文本帧;音频必须 Base64 编码,不要发送二进制帧。
- 事件顺序:
连接 → session.update → session.updated → append 音频 → finish → finished。 - 音频参数:PCM s16le / 单声道;采样率须与
format.rate一致(16000 或 24000)。 - 实时节奏:建议按约 100ms 一片发送,避免过快占满缓冲或过慢导致 VAD 误触发。
- 计费:按识别音频时长计费,不足 1 秒按 1 秒计时,单价 3.6 元 / 小时。
相关资源
语音识别介绍
模型对比、接口选型与接入步骤。
语音识别 WebSocket
二进制帧协议的实时识别接口。
离线转写 API
基于 HTTP 的文件识别接口。
产品定价
语音识别计费规则。