本文介绍通过WebSocket进行会议纪要实时转写的方法。
前提条件
已开通服务并获取与配置 API Key,请配置API Key到环境变量,而非硬编码在代码中,防范因代码泄露导致的安全风险。
整体调用流程
请参考实时会议。
调用时序图

WebSocket建联
对应时序图中过程1。
对于常用编程语言,有许多现成的WebSocket库和示例可供参考,例如:
- Go:
gorilla/websocket - PHP:
Ratchet - Node.js:
ws
建联请求头
WebSocket接入地址
向服务端发送指令
您可以向服务端发送指令,控制转写的开始和停止。
指令分为两种,run-task和finish-task,都需要以Text Frame方式发送的JSON格式的数据,具体协议如下:
run-task指令
对应时序图中过程2,通知服务端开始一个转写任务。
协议字段如下:
字段 | 类型 | 说明 |
|---|---|---|
header | Object | |
header.action | String | 固定填写run-task。 |
header.task_id | String | 自定义16位随机字符串,排查问题使用,后续finish-task也应该使用这个task_id。 |
header.streaming | String | 固定填写duplex。 |
payload | Object | |
payload.model | String | 固定填写tingwu-meeting-realtime。 |
payload.task_group | String | 固定填写aigc。 |
payload.task | String | 固定填写multimodal-generation。 |
payload.function | String | 固定填写generation。 |
payload.input | Object | |
payload.input.appId | String | 填写会议纪要控制台中发布的应用id,可从控制台获取。 |
payload.input.directive | String | 固定传start。 |
payload.input.dataId | String | 请填写CreateTask中获取的dataId |
finish-task
对应时序图中过程6,通知服务端音频已全部发送完成。
协议字段如下:
字段 | 类型 | 说明 |
|---|---|---|
header | Object | |
header.action | String | 固定填写finish-task。 |
header.task_id | String | 请填写run-task指令中填写的task_id。 |
header.streaming | String | 固定填写duplex。 |
payload | Object | |
payload.model | String | 固定填写tingwu-meeting-realtime。 |
payload.task_group | String | 固定填写aigc。 |
payload.task | String | 固定填写multimodal-generation。 |
payload.function | String | 固定填写generation。 |
payload.input | Object | |
payload.input.directive | String | 固定传stop。 |
向服务端发送音频
将原始音频直接转为二进制流即可,无需额外处理。但需要注意:
- 上传的语音识别音频采样率必须是8000Hz或16000Hz,且与调用CreateTask时传入参数一致。
- 音频编码格式需要与调用CreateTask时传入参数一致。
- 支持的音频格式:pcm、opus、aac、speex、mp3。
接收服务端返回的事件
在指令或音频发送后,服务端会向您发送不同种类的事件,每个事件代表不同的处理阶段,请严格遵循时序图对不同事件做相应处理。
事件总共分为五种,分别是speech-listen事件、recognize-result事件、心跳事件、speech-end事件及task-failed事件。
speech-listen事件
对应时序图中的过程3,speech-listen事件会在run-task指令后返回,代表服务端收到了您的转写指令,并完成相关初始化工作,您可以开始发送音频了。
协议字段如下:
字段 | 类型 | 说明 |
|---|---|---|
header | Object | |
header.event | String | 固定为result-generated。 |
header.task_id | String | 您在run-task指令中填写的task_id。 |
payload | Object | |
payload.output | Object | |
payload.output.action | String | 固定为speech-listen。 |
payload.output.dataId | String | 您传入的dataId |
recognize-result事件
对应时序图中的过程4,recognize-result事件会在您发送一段时间的音频后返回,也可能会在您发送finish-task指令后返回,代表当前服务端识别到的原文和译文结果。
协议字段如下:
字段 | 类型 | 说明 |
|---|---|---|
header | Object | |
header.event | String | 固定为result-generated。 |
header.task_id | String | 您在run-task指令中填写的task_id。 |
payload | Object | |
payload.output | Object | |
payload.output.action | String | 固定为recognize-result。 |
payload.output.transcription | Object | 转写的原始结果。 |
payload.output.transcription.sentenceId | Integer | 句子序号。 |
payload.output.transcription.time | Integer | 当前已处理的音频时长。 |
payload.output.transcription.text | String | 识别文本。 |
payload.output.transcription.words | Array[Word] | 字时间戳信息。 |
payload.output.transcription.sentenceEnd | Boolean | true:当前文本已构成一句完整句子。 false:当前文本未构成完整句子,识别结果可能会更新。 |
payload.output.transcription.stashResult | Object | 语音识别的暂存结果,是暂未完成断句的下一句话信息。您可以将stashResult结果和上面的text结果拼接以便后续处理 |
payload.output.transcription.stashResult.sentenceId | Integer | 下一句话的句子ID |
payload.output.transcription.stashResult.text | String | stash结果的ASR文本 |
payload.output.transcription.stashResult.words | Array[Word] | stash结果的词信息 |
payload.output.translations | Object | 翻译结果 |
payload.output.translations[targetLang].sourceLang | String | 原始语种 |
payload.output.translations[targetLang].targetLang | String | 目标语种 |
payload.output.translations[targetLang].translateResult | Array[Object] | 翻译句子结果 |
payload.output.translations[targetLang].translateResult[i].sentenceId | Integer | 翻译句子编号,从0开始递增。 |
payload.output.translations[targetLang].translateResult[i].text | String | 句子翻译结果 |
payload.output.translations[targetLang].translateResult[i].beginTime | Integer | 翻译句子的开始时间,单位为毫秒,在翻译SentenceEnd识别结果时会返回。 |
payload.output.translations[targetLang].translateResult[i].endTime | Integer | 翻译句子的结束时间,单位为毫秒,在翻译SentenceEnd识别结果时会返回。 |
payload.output.translations[targetLang].translateResult[i].partial | Boolean | 为true时对应stash部分识别内容的翻译结果。 |
字段 | 类型 | 说明 |
|---|---|---|
beginTime | Integer | 当前词在音频中的开始时间。 |
endTime | Integer | 当前词在音频中的结束时间。 |
text | String | 当前词的内容。 |
识别到句子开始
识别到句子中
识别到句子结束
翻译结果
心跳事件
对应时序图中的过程5。在长时间发送静音音频时,为保证下行链路不中断,服务端会发送心跳保活事件,心跳保活事件会在最后一次下发事件后30s后发送,服务端无需对心跳事件进行回复。
协议字段如下:
字段 | 类型 | 说明 |
|---|---|---|
header | Object | |
header.event | String | 固定为result-generated。 |
header.task_id | String | 您在run-task指令中填写的task_id。 |
payload | Object | |
payload.output | Object | |
payload.output.action | String | 固定为ping。 |
speech-end事件
对应时序图中的过程7。speech-end事件代表本次实时转写的结果已全部发送完毕,之后您可以关闭WebSocket连接。
协议字段如下:
字段 | 类型 | 说明 |
|---|---|---|
header | Object | |
header.event | String | 固定为result-generated。 |
header.task_id | String | 您在run-task指令中填写的task_id。 |
payload | Object | |
payload.output | Object | |
payload.output.action | String | 固定为speech-end。 |
task-failed事件
若在任务过程中,由于客户端传参错误或服务端内部错误导致任务失败,服务端会返回给您task-failed事件,随即会中断WebSocket连接。
协议字段如下:
字段 | 类型 | 说明 |
|---|---|---|
header | Object | |
header.event | String | 固定为result-generated。 |
header.task_id | String | 您在run-task指令中填写的task_id。 |
payload | Object | |
payload.output | Object | |
payload.output.action | String | 固定为task-failed。 |
payload.output.errorCode | String | 错误码 |
payload.output.errorMessage | String | 错误信息 |
会议暂停及恢复
WebSocket生命周期内,您可以随时通过发送finish-task指令暂停会议。
若客户端10s内无文本指令或二进制语音流发送,连接将自动断开。
单个会议dataId的有效期是24h,在此期间,您可以随时重新通过建立WebSocket并传入会议dataId恢复指定的会议。
代码示例
错误码
错误码 | 错误信息 | 说明 |
|---|---|---|
InvalidParameter | Invalid parameter. Please refer to the official documents. | 参数错误,请检查您传入的参数。 |
Agent.FrameSequenceIllegal | Agent Websocket Frame Sequence Illegal. | 调用指令时序不合法。 |
Agent.InputActionIllegal | Agent Input Action Illegal. | 传入的指令action字段不合法。 |
Agent.InputAppIdIllegal | Agent Input appId illegal. | 传入的应用Id字段不合法。 |
Agent.AppNotPublished | Agent App not published. | 传入的应用Id尚未发布。 |
Agent.InputInvalidDataId | Agent Input invalid dataId. | 传入的dataId不合法。 |
Agent.CustomTaskIdInvalid | The length of custom task id must be 16. | 传入的taskId字段长度不合法,必须是16位字符串。 |
BIL.ServiceNotActivate | User hasn't activate service. | 您尚未开通通义听悟Agent服务。 |
BIL.UserArrears | User is in arrears. | 您目前处在欠费状态。 |
Agent.AppInfoNotExist | Agent App Info not exist. | 传入的应用Id信息不存在,请先在控制台保存并发布应用配置信息。 |
ServerError | Server error. | 服务端内部错误。 |