10 KiB
10 KiB
实时会议 WebSocket 调用说明
本文档说明当前项目实时会议识别接口的调用方式、入参与返回格式。
1. 接口地址
- 推荐地址:
/ws/v1/asr - 显式地址:
/ws/v1/asr/qwen
说明:
/ws/v1/asr/funasr已废弃,不再使用。- 当前返回结构按腾讯实时识别风格组织,核心消息类型为:
voice_id、start、sentences、end、error。
2. 交互流程
客户端调用顺序:
- 建立 WebSocket 连接
- 发送
start消息 - 持续发送音频二进制数据
- 接收服务端返回的
voice_id、start、sentences - 发送
stop - 接收最终
end
3. start 消息
客户端先发送文本消息:
{
"type": "start",
"payload": {
"format": "pcm",
"sample_rate": 16000,
"session_id": "meeting-abc-123",
"language": null,
"context": "",
"enable_inverse_text_normalization": true,
"silence_duration_ms": 800,
"min_partial_sec": 0.3,
"pre_roll_ms": 240,
"max_sentence_count": 8,
"partial_holdback_chars": 2,
"unfixed_token_num": 3,
"enable_native_partial_stream": true,
"enable_speaker": true,
"match_speaker_registry": true,
"speaker_threshold": 0.6,
"enable_realtime_vad_split": true,
"enable_realtime_longform": false,
"force_stable_segment_sec": 6,
"force_stable_min_chars": 24,
"max_segment_sec": 12
}
}
4. start 参数说明
必填/常用参数
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
format |
string | pcm |
当前建议传 pcm |
sample_rate |
number | 16000 |
采样率 |
session_id |
string | 自动生成/可不传 | 会话标识;断线重连时传同一个值可在保活期内恢复同一会议会话 |
language |
string/null | null |
识别语言,留空表示自动判断 |
context |
string | "" |
上下文提示,如会议主题、术语 |
enable_inverse_text_normalization |
boolean | true |
是否启用数字归一化 |
partial / 切段相关
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
silence_duration_ms |
number | 800 |
静音多久触发收段 |
min_partial_sec |
number | 0.9(后端默认) |
最短 partial 窗口 |
pre_roll_ms |
number | 240 |
句首预读毫秒数 |
max_sentence_count |
number | 8 |
一段内最多允许的句子数 |
partial_holdback_chars |
number | 后端默认 | partial 尾部保留字数,减少尾字抖动 |
unfixed_token_num |
number | 5(后端默认) |
native partial 模式下回滚 token 数 |
enable_native_partial_stream |
boolean | false |
是否启用底层原生流式 partial |
enable_realtime_vad_split |
boolean | false |
是否启用实时 VAD 拆段 |
enable_realtime_longform |
boolean | false |
是否启用长段重转写 |
force_stable_segment_sec |
number | 后端默认 | 超时后软提交的时间阈值 |
force_stable_min_chars |
number | 后端默认 | 软提交最少字数 |
max_segment_sec |
number | 后端默认 | 单段最长秒数 |
speaker 相关
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
enable_speaker |
boolean | true |
是否开启说话人分离 |
match_speaker_registry |
boolean | false |
是否匹配已注册声纹库 |
speaker_threshold |
number/null | null |
本次声纹匹配阈值 |
说明:
enable_speaker=true时,服务端会先返回文本,再异步补充 speaker 归属。match_speaker_registry=true时,若匹配到声纹库,会返回实名 speaker 信息。
5. 音频数据发送
start 成功后,客户端持续发送音频二进制帧。
当前推荐:
- 单声道 PCM
- 16k 采样率
- 小块持续发送
示例:
ws.send(pcmChunkArrayBuffer);
6. stop 消息
识别结束后发送:
{
"type": "stop"
}
7. 服务端返回消息
7.1 voice_id
连接启动后首先返回:
{
"type": "voice_id",
"voice_id": "41ff1926",
"session_id": "meeting-abc-123"
}
7.2 start
服务端确认开始识别:
{
"type": "start",
"session_id": "meeting-abc-123"
}
说明:
- 若客户端在
start.payload.session_id中传入固定值,服务端会优先复用该值。 - 若客户端未传
session_id,服务端仍按当前连接生成voice_id,并同步作为session_id返回。 - 在
REALTIME_SESSION_RESUME_TTL_SEC保活时间内,客户端断线后使用相同session_id再次发送start,服务端会恢复原会话上下文。
7.3 sentences
识别过程中会持续返回 sentences。
重要说明:
sentence_type=0/slice_type=1表示实时 partial,仅用于实时展示。sentence_type=1/slice_type=2表示该段最终定稿,建议作为最终业务入库依据。- 若开启
enable_native_partial_stream=true,partial 刷新会更快,但中间文本可能更活。 - 若希望少存数据,建议不要存 partial,只对
sentence_type=1做落库或 upsert。
partial 返回
{
"type": "sentences",
"code": 0,
"voice_id": "41ff1926",
"final": 0,
"result": {
"slice_type": 1,
"index": 3,
"voice_text_str": "今天这个会议主要讨论预算。"
},
"sentences": [
{
"sentence_id": 3,
"sentence_type": 0,
"speaker_id": -1,
"start_time": 12000,
"end_time": 15600,
"sentence": "今天这个会议主要讨论预算。"
}
]
}
字段说明:
| 字段 | 说明 |
|---|---|
slice_type=1 |
partial |
sentence_type=0 |
partial 句子 |
speaker_id=-1 |
当前还未确认 speaker |
定稿返回
{
"type": "sentences",
"code": 0,
"voice_id": "41ff1926",
"final": 0,
"result": {
"slice_type": 2,
"index": 3,
"voice_text_str": "今天这个会议主要讨论预算。"
},
"sentences": [
{
"sentence_id": 3,
"sentence_type": 1,
"speaker_id": -1,
"start_time": 12000,
"end_time": 15880,
"sentence": "今天这个会议主要讨论预算。",
"speaker_name": "",
"user_id": null
}
]
}
字段说明:
| 字段 | 说明 |
|---|---|
slice_type=2 |
该段文本已定稿 |
sentence_type=1 |
final 句子 |
speaker_name |
项目扩展字段 |
user_id |
项目扩展字段 |
speaker 回写返回
如果 speaker 后续识别完成,服务端会再次返回相同 sentence_id 的 sentences 消息,只更新 speaker 归属:
{
"type": "sentences",
"code": 0,
"voice_id": "41ff1926",
"final": 0,
"result": {
"slice_type": 2,
"index": 3,
"voice_text_str": "今天这个会议主要讨论预算。"
},
"sentences": [
{
"sentence_id": 3,
"sentence_type": 1,
"speaker_id": 19,
"start_time": 12000,
"end_time": 15880,
"sentence": "今天这个会议主要讨论预算。",
"speaker_name": "Alan Paine",
"user_id": "3"
}
]
}
说明:
- speaker 是异步补归属,不保证和文本首个 final 同时返回。
- 前端应使用
sentence_id做幂等更新,而不是简单追加。
7.3.1 partial 与 final 的使用建议
推荐使用方式:
- 前端实时显示:使用
sentence_type=0 - 最终文本入库:使用
sentence_type=1 - 说话人归属更新:继续按相同
sentence_id更新已有 final 记录
推荐入库字段:
sentence_idstart_timeend_timesentencespeaker_idspeaker_nameuser_id
推荐入库策略:
- 收到
sentences后,仅处理sentence_type=1 - 使用
sentence_id作为同一连接内的幂等更新键 - 若后续相同
sentence_id再次返回,通常表示 speaker 归属补写,直接更新原记录 - 收到
end后,可将本次会话的 final 结果视为最终完成结果
7.4 end
客户端发送 stop 后,服务端返回最终结束消息:
{
"type": "end",
"code": 0,
"message": "",
"voice_id": "41ff1926",
"final": 1,
"result": {
"slice_type": 2,
"index": 3,
"voice_text_str": "完整识别文本"
},
"sentences": [
{
"sentence_id": 0,
"sentence_type": 1,
"speaker_id": 19,
"start_time": 0,
"end_time": 3200,
"sentence": "第一句",
"speaker_name": "Alan Paine",
"user_id": "3"
}
]
}
7.5 error
异常时返回:
{
"type": "error",
"code": -1,
"message": "错误信息",
"voice_id": "41ff1926"
}
8. 腾讯风格字段兼容说明
当前实时会议返回格式按腾讯实时 speaker demo 风格组织,核心字段保持一致:
typecodevoice_idfinalresult.slice_typeresult.indexresult.voice_text_strsentences[].sentence_idsentences[].sentence_typesentences[].speaker_idsentences[].start_timesentences[].end_timesentences[].sentence
在此基础上,项目额外补充:
sentences[].speaker_namesentences[].user_id
9. JavaScript 调用示例
const ws = new WebSocket("ws://127.0.0.1:8000/ws/v1/asr");
ws.onopen = () => {
ws.send(JSON.stringify({
type: "start",
payload: {
format: "pcm",
sample_rate: 16000,
language: null,
context: "预算评审会",
enable_inverse_text_normalization: true,
silence_duration_ms: 800,
min_partial_sec: 0.3,
pre_roll_ms: 240,
max_sentence_count: 8,
partial_holdback_chars: 2,
unfixed_token_num: 3,
enable_native_partial_stream: true,
enable_speaker: true,
match_speaker_registry: true,
speaker_threshold: 0.6,
enable_realtime_vad_split: true,
enable_realtime_longform: false,
force_stable_segment_sec: 6,
force_stable_min_chars: 24,
max_segment_sec: 12
}
}));
};
ws.onmessage = (event) => {
const payload = JSON.parse(event.data);
console.log("ws message:", payload);
};
function sendPcmChunk(arrayBuffer) {
ws.send(arrayBuffer);
}
function stopRecognition() {
ws.send(JSON.stringify({ type: "stop" }));
}
10. 对接注意事项
- 前端要按
sentence_id更新句子,不要把 speaker 回写当成新句子追加。 speaker_id=-1代表 speaker 暂未确认,不代表识别失败。- 默认启用
enable_native_partial_stream;partial 刷新更快,但中间文本可能会修订。 - 最终展示建议以
sentence_type=1的句子为准。 - 若需要排查前端是否真的传了某个参数,建议把
start payload直接打印到页面日志。