Messages
{
"event": "<string>",
"model": "<string>",
"audio_setting": {
"sample_rate": 123,
"channel": 123,
"format": "<string>"
},
"vad_setting": {
"silence_duration": 123,
"min_speech_duration": 123,
"soft_max_duration": 123,
"hard_max_duration": 123,
"soft_silence_duration": 123,
"threshold": 123
},
"transcription_setting": {
"target_language": "<string>",
"recognize_mode": "<string>"
}
}{}{
"event": "<string>"
}{
"event": "<string>",
"session_id": "<string>",
"trace_id": "<string>",
"base_resp": {
"status_code": 123,
"status_msg": "<string>"
}
}{
"event": "<string>",
"session_id": "<string>",
"trace_id": "<string>",
"base_resp": {
"status_code": 123,
"status_msg": "<string>"
}
}{}{
"event": "<string>",
"session_id": "<string>",
"trace_id": "<string>",
"base_resp": {
"status_code": 123,
"status_msg": "<string>"
}
}{
"event": "<string>",
"session_id": "<string>",
"trace_id": "<string>",
"base_resp": {
"status_code": 123,
"status_msg": "<string>"
}
}语音识别
语音识别 WebSocket (ASR)
基于 WebSocket 的实时 ASR 识别协议参考
WSS
/
audio
/
transcriptions
说明
基于 WebSocket 的流式语音转文字接口,支持边录边转的实时交互,适用于实时字幕、语音助手、跨语言翻译、语音听写等低延迟场景。通信包含 JSON 控制消息与二进制音频消息两类。- 接入地址:
wss://api.senseaudio.cn/ws/v1/audio/transcriptions - 鉴权方式:Bearer Token,格式
Authorization: Bearer SENSEAUDIO_API_KEY - 音频格式:PCM signed 16-bit little-endian,采样率 16000Hz,单声道
- 模型参数:目前仅支持
senseaudio-asr-deepthink-1.5-260319 - 计费单位:按音频时长计费,详见 计费说明
- 离线转写:文件批量转写请使用 语音识别转写
- 音频必须为 PCM 16-bit little-endian / 16kHz / 单声道;其他采样率、格式、声道当前不支持。
- 控制消息必须以 JSON 文本帧 发送,音频数据必须以 二进制帧 发送。
- 客户端需等待
connected_success后再发送task_start,等待task_started后再开始推送音频。
请求头 (Request Headers)
| 参数名 | 必填 | 说明 | 示例 |
|---|---|---|---|
| Authorization | 是 | 鉴权 Token。格式:Bearer SENSEAUDIO_API_KEY | Bearer sk-123456… |
通信流程
1. 客户端建立 WebSocket 连接
↓
2. 服务端返回 connected_success 事件
↓
3. 客户端发送 task_start 事件(包含音频参数、VAD、识别配置)
↓
4. 服务端返回 task_started 事件
↓
5. 客户端持续发送二进制音频帧
↓
6. 服务端在 VAD 断句后返回 result_final 事件(可多次)
↓
7. 客户端发送 task_finish 事件
↓
8. 服务端返回 task_finished 事件并关闭连接
客户端事件
1. task_start - 开始任务
客户端发送task_start 事件配置参数。服务端返回 task_started 后方可开始推送二进制音频帧。
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event | string | 是 | 固定值:task_start |
| model | string | 是 | 模型名称,目前仅支持 senseaudio-asr-deepthink-1.5-260319 |
| audio_setting | object | 是 | 音频参数设置,见下文详情 |
| vad_setting | object | 否 | VAD(语音活动检测)设置,见下文详情 |
| transcription_setting | object | 否 | 识别相关设置,见下文详情 |
audio_setting
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sample_rate | int | 是 | 采样率,目前仅支持 16000 |
| channel | int | 是 | 声道数,目前仅支持 1(单声道) |
| format | string | 是 | 音频格式,目前仅支持 pcm |
vad_setting(可选)
| 参数名 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| silence_duration | int | 静音切分阈值 (ms) | 500 |
| min_speech_duration | int | 最小语音时长 (ms) | 300 |
| soft_max_duration | int | 软超时时长 (ms) | 15000 |
| hard_max_duration | int | 硬超时时长 (ms) | 30000 |
| soft_silence_duration | int | 软超时后的静音阈值 (ms) | 300 |
| threshold | float | VAD 能量阈值 (0.0 - 1.0) | 0.5 |
transcription_setting(可选)
| 参数名 | 类型 | 说明 | 示例 |
|---|---|---|---|
| target_language | string | 目标语言代码(详见下表) | en, zh |
| recognize_mode | string | 识别模式 | auto(默认)、record_only(仅识别不执行指令) |
target_language)
| 代码 | 语言 | 代码 | 语言 | 代码 | 语言 |
|---|---|---|---|---|---|
ar | Arabic | yue | Cantonese | zh | Chinese |
nl | Dutch | en | English | fr | French |
de | German | id | Indonesian | it | Italian |
ja | Japanese | ko | Korean | ms | Malay |
pt | Portuguese | ru | Russian | es | Spanish |
th | Thai | tr | Turkish | ur | Urdu |
vi | Vietnamese |
{
"event": "task_start",
"model": "senseaudio-asr-deepthink-1.5-260319",
"audio_setting": {
"sample_rate": 16000,
"format": "pcm",
"channel": 1
},
"vad_setting": {
"silence_duration": 500,
"min_speech_duration": 300
}
}
| 参数名 | 类型 | 说明 |
|---|---|---|
| event | string | 事件类型 |
| session_id | string | 会话 ID |
| trace_id | string | 链路追踪 ID |
| base_resp | object | 请求状态信息 |
| base_resp.status_code | int | 状态码 |
| base_resp.status_msg | string | 状态详情 |
{
"event": "task_started",
"session_id": "trace-id-xxx",
"trace_id": "trace-id-xxx",
"base_resp": { "status_code": 0, "status_msg": "success" }
}
2. 音频流传输(Binary Message)
客户端持续发送二进制音频数据,无需额外封装。- 格式要求:PCM signed 16-bit little-endian,16kHz,单声道。
- 建议分片:每片约 100ms(3200 字节)发送,便于模拟实时流。
- 断句机制:服务端通过 VAD 自动断句,每识别完一句话会返回一次
result_final。
result_final)
{
"event": "result_final",
"session_id": "trace-id-xxx",
"trace_id": "trace-id-xxx",
"data": {
"text": "你好,今天天气真不错。",
"is_final": true,
"segment_id": 1,
"timestamp_end": 1773027072669
},
"base_resp": { "status_code": 0, "status_msg": "success" }
}
3. task_finish - 结束任务
客户端发送task_finish 事件通知音频发送完毕。服务端处理剩余音频后返回 task_finished 并关闭连接。
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| event | string | 是 | 固定值:task_finish |
{ "event": "task_finish" }
{
"event": "task_finished",
"session_id": "trace-id-xxx",
"trace_id": "trace-id-xxx",
"base_resp": { "status_code": 0, "status_msg": "success" }
}
服务端事件
connected_success - 连接建立成功
初次请求接口时,表示 WebSocket 连接建立成功。{
"event": "connected_success",
"session_id": "trace-id-xxx",
"trace_id": "trace-id-xxx",
"base_resp": { "status_code": 0, "status_msg": "success" }
}
task_started - 任务已开始
标志任务已成功开始,客户端可以开始推送音频帧。{
"event": "task_started",
"session_id": "trace-id-xxx",
"trace_id": "trace-id-xxx",
"base_resp": { "status_code": 0, "status_msg": "success" }
}
result_final - 识别结果
每完成一句断句返回一次,data 中包含识别文本及时间戳等信息。
| 参数名 | 类型 | 说明 |
|---|---|---|
| event | string | 事件类型 |
| session_id | string | 会话 ID |
| trace_id | string | 链路追踪 ID |
| data.text | string | 识别结果文本 |
| data.is_final | boolean | 识别是否结束 |
| data.segment_id | int | 分句序号 |
| data.timestamp_end | int64 | 该句结束时间(毫秒时间戳) |
| base_resp | object | 请求状态信息 |
task_finished - 任务已结束
标志任务已结束,WebSocket 连接即将关闭。{
"event": "task_finished",
"session_id": "trace-id-xxx",
"trace_id": "trace-id-xxx",
"base_resp": { "status_code": 0, "status_msg": "success" }
}
task_failed - 任务失败
标志任务失败,base_resp.status_msg 中包含错误信息,服务端可能随即关闭连接。
{
"event": "task_failed",
"session_id": "trace-id-xxx",
"trace_id": "trace-id-xxx",
"base_resp": { "status_code": 2013, "status_msg": "model is required" }
}
使用示例
请将示例代码中的SENSEAUDIO_API_KEY 和 AUDIO_FILE 替换为实际值。
- Python
- Go
- Node.js
依赖: pip install websockets
import asyncio
import json
import websockets
SENSEAUDIO_API_KEY = "SENSEAUDIO_API_KEY"
WS_URL = "wss://api.senseaudio.cn/ws/v1/audio/transcriptions"
AUDIO_FILE = "test_audio_16k.pcm" # 16kHz, 16bit, PCM 单声道
async def receive_messages(websocket):
async for message in websocket:
msg_json = json.loads(message)
print(f"< Received Event: {msg_json.get('event')}")
if msg_json.get("event") == "result_final":
print(f" 识别结果: {msg_json['data']['text']}")
elif msg_json.get("event") == "task_finished":
print(" 任务完成")
break
async def speech_recognition():
headers = {"Authorization": f"Bearer {SENSEAUDIO_API_KEY}"}
async with websockets.connect(WS_URL, additional_headers=headers) as websocket:
# 1. 接收连接成功消息
resp = await websocket.recv()
print(f"< Received: {resp}")
# 2. 发送 task_start
start_payload = {
"event": "task_start",
"model": "senseaudio-asr-deepthink-1.5-260319",
"audio_setting": {"sample_rate": 16000, "format": "pcm", "channel": 1},
}
await websocket.send(json.dumps(start_payload))
print("> Sent task_start")
# 接收 task_started
resp = await websocket.recv()
print(f"< Received: {resp}")
# 3. 接收结果(并发)+ 发送音频
receive_task = asyncio.create_task(receive_messages(websocket))
with open(AUDIO_FILE, "rb") as f:
while True:
data = f.read(3200) # 每次发送 3200 字节(约 100ms)
if not data:
break
await websocket.send(data)
await asyncio.sleep(0.1) # 模拟实时流
# 4. 发送 task_finish
await websocket.send(json.dumps({"event": "task_finish"}))
print("> Sent task_finish")
await receive_task
if __name__ == "__main__":
asyncio.run(speech_recognition())
依赖: go get github.com/gorilla/websocket
package main
import (
"encoding/json"
"fmt"
"io"
"log"
"net/http"
"os"
"time"
"github.com/gorilla/websocket"
)
const (
SENSEAUDIO_API_KEY = "SENSEAUDIO_API_KEY"
WS_URL = "wss://api.senseaudio.cn/ws/v1/audio/transcriptions"
AUDIO_FILE = "test_audio_16k.pcm"
)
func main() {
header := http.Header{}
header.Add("Authorization", "Bearer "+SENSEAUDIO_API_KEY)
log.Printf("Connecting to %s", WS_URL)
c, _, err := websocket.DefaultDialer.Dial(WS_URL, header)
if err != nil {
log.Fatal("dial error:", err)
}
defer c.Close()
// 1. 读取连接成功 msg
readMessage(c)
// 2. 发送 task_start
startMsg := map[string]interface{}{
"event": "task_start",
"model": "senseaudio-asr-deepthink-1.5-260319",
"audio_setting": map[string]interface{}{
"sample_rate": 16000,
"format": "pcm",
"channel": 1,
},
}
if err := c.WriteJSON(startMsg); err != nil {
log.Fatal("write startMsg error:", err)
}
fmt.Println("> Sent task_start")
// 读取 task_started
readMessage(c)
// 3. 准备并发读取结果
done := make(chan struct{})
go func() {
defer close(done)
for {
_, message, err := c.ReadMessage()
if err != nil {
if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
fmt.Println("< Connection closed normally")
return
}
log.Println("read error:", err)
return
}
fmt.Printf("< Received: %s\n", message)
var msgMap map[string]interface{}
if err := json.Unmarshal(message, &msgMap); err != nil {
log.Println("json unmarshal error:", err)
continue
}
if event, ok := msgMap["event"].(string); ok && event == "task_finished" {
return
}
}
}()
// 4. 发送音频(100ms 分片)
file, err := os.Open(AUDIO_FILE)
if err != nil {
log.Fatal("open audio file error:", err)
}
defer file.Close()
const chunkSize = 3200
buf := make([]byte, chunkSize)
for {
n, err := file.Read(buf)
if err == io.EOF {
break
}
if err != nil {
log.Fatal("read file error:", err)
}
if err := c.WriteMessage(websocket.BinaryMessage, buf[:n]); err != nil {
log.Fatal("write message error:", err)
}
fmt.Printf("> Sent %d bytes audio data\n", n)
// 模拟实时发送:100ms 的音频数据等待 100ms
if n == chunkSize {
time.Sleep(100 * time.Millisecond)
}
}
// 5. 发送 task_finish
if err := c.WriteJSON(map[string]string{"event": "task_finish"}); err != nil {
log.Fatal("write task_finish error:", err)
}
// 6. 等待服务端处理完成并返回 task_finished
<-done
fmt.Println("> Sent task_finish")
fmt.Println("All done!")
}
func readMessage(c *websocket.Conn) {
_, message, err := c.ReadMessage()
if err != nil {
if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
fmt.Println("< Connection closed")
return
}
log.Fatal("read message error:", err)
}
fmt.Printf("< Received: %s\n", message)
}
依赖: npm install ws
const WebSocket = require('ws');
const fs = require('fs');
const SENSEAUDIO_API_KEY = "SENSEAUDIO_API_KEY";
const WS_URL = "wss://api.senseaudio.cn/ws/v1/audio/transcriptions";
const AUDIO_FILE = "test_audio_16k.pcm";
const ws = new WebSocket(WS_URL, {
headers: {
Authorization: `Bearer ${SENSEAUDIO_API_KEY}`,
},
});
ws.on('open', () => console.log('Connected'));
ws.on('message', (data, isBinary) => {
if (isBinary) return;
const msg = JSON.parse(data.toString());
console.log('< Received:', msg.event);
if (msg.event === 'connected_success') {
const startMsg = {
event: 'task_start',
model: 'senseaudio-asr-deepthink-1.5-260319',
audio_setting: { sample_rate: 16000, format: 'pcm', channel: 1 },
};
ws.send(JSON.stringify(startMsg));
console.log('> Sent task_start');
} else if (msg.event === 'task_started') {
streamAudio();
} else if (msg.event === 'result_final') {
console.log(' Result:', msg.data.text);
} else if (msg.event === 'task_finished') {
process.exit(0);
}
});
function streamAudio() {
const stream = fs.createReadStream(AUDIO_FILE, { highWaterMark: 3200 });
let processing = false;
stream.on('data', (chunk) => {
stream.pause();
processing = true;
ws.send(chunk);
setTimeout(() => {
processing = false;
stream.resume();
}, 100);
});
stream.on('end', () => {
const checkAndFinish = () => {
if (!processing) {
ws.send(JSON.stringify({ event: 'task_finish' }));
console.log('> Sent task_finish');
} else {
setTimeout(checkAndFinish, 50);
}
};
checkAndFinish();
});
}
错误码说明
| 状态码 | 说明 | 解决方案 |
|---|---|---|
| 0 | 成功 | - |
| 2013 | 缺少必填参数 | 检查 task_start 是否携带了 model 等必填字段 |
注意事项
- 消息类型区分:控制消息必须用文本帧发送 JSON,音频帧必须用二进制帧发送;混用会导致服务端解析失败。
- 事件发送顺序:必须按
连接 → task_start → 音频帧 → task_finish顺序发送;仅在收到task_started后才可发送音频。 - 音频参数:当前仅支持 16kHz / 16-bit / 单声道 PCM;若录音源采样率不同,需在客户端重采样。
- 实时流节奏:建议每片约 100ms(3200 字节)发送,避免过快占满缓冲或过慢导致 VAD 误触发。
- 连接关闭:收到
task_finished或task_failed后服务端会关闭连接,客户端应及时回收资源。
相关资源
离线转写 API
基于 HTTP 的文件识别接口。
WebSocket 实时识别指南
WebSocket ASR 的应用场景与接入最佳实践。
ASR 总览
语音识别能力与模型对比。
音频质量检测
离线音频噪声/可用性检测。
Messages
{
"event": "<string>",
"model": "<string>",
"audio_setting": {
"sample_rate": 123,
"channel": 123,
"format": "<string>"
},
"vad_setting": {
"silence_duration": 123,
"min_speech_duration": 123,
"soft_max_duration": 123,
"hard_max_duration": 123,
"soft_silence_duration": 123,
"threshold": 123
},
"transcription_setting": {
"target_language": "<string>",
"recognize_mode": "<string>"
}
}{}{
"event": "<string>"
}{
"event": "<string>",
"session_id": "<string>",
"trace_id": "<string>",
"base_resp": {
"status_code": 123,
"status_msg": "<string>"
}
}{
"event": "<string>",
"session_id": "<string>",
"trace_id": "<string>",
"base_resp": {
"status_code": 123,
"status_msg": "<string>"
}
}{}{
"event": "<string>",
"session_id": "<string>",
"trace_id": "<string>",
"base_resp": {
"status_code": 123,
"status_msg": "<string>"
}
}{
"event": "<string>",
"session_id": "<string>",
"trace_id": "<string>",
"base_resp": {
"status_code": 123,
"status_msg": "<string>"
}
}bearerAuth
type:http
Bearer Token 鉴权,格式 Authorization: Bearer <SENSEAUDIO_API_KEY>
task_start
type:object
开始识别任务
音频二进制帧
type:string
PCM 音频二进制帧
task_finish
type:object
结束识别任务
connected_success
type:object
连接建立成功
task_started
type:object
任务已开始
result_final
识别结果
task_finished
type:object
任务已结束
task_failed
type:object
任务失败
⌘I