WebSocket协议说明

更新时间:
复制 MD 格式

本文介绍实时语音识别的 WebSocket 协议,包括鉴权、请求指令、响应事件和交互流程,适用于不使用 SDK、直接开发客户端的场景。

功能介绍

实时语音识别通过 WebSocket 接收音频流并返回转写结果,支持长语音。指令和事件使用 JSON 格式的文本帧(Text Frame),音频使用二进制帧(Binary Frame)。关于帧类型,请参见 Data Frames。

  • 支持的输入格式:PCM、PCM 编码的 WAV、OGG 封装的 OPUS、OGG 封装的 SPEEX、AMR、MP3、AAC。音频需为单声道,PCM 采样位数为 16 bit。

  • 支持的音频采样率:8000 Hz、16000 Hz。音频、请求参数和项目所选模型的采样率需匹配。

  • 支持返回中间识别结果、添加标点、将中文数字转换为阿拉伯数字,以及返回词信息。

  • 语种和方言模型在项目中配置,不能通过本协议的请求参数切换。模型配置方法请参见管理项目。

鉴权

服务端使用临时 Token 鉴权。建立 WebSocket 连接时,在 URL 的 token 参数中传入有效 Token。

获取方法请参见获取 Token。

将以下 URL 中的 <your_token> 替换为实际 Token。

访问类型

说明

URL

公网访问

通过公网连接服务。

wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1?token=<your_token>

上海 ECS 内网访问

适用于华东 2(上海)地域的 VPC 内 ECS 实例。经典网络不支持此访问方式。通过内网访问不产生 ECS 公网流量费用。

ws://nls-gateway-cn-shanghai-internal.aliyuncs.com:80/ws/v1?token=<your_token>

交互流程

指令和音频流按以下顺序发送:

  1. 携带 Token 建立 WebSocket 连接。

  2. 发送 StartTranscription 指令,等待 TranscriptionStarted 事件。

  3. 以二进制帧分片发送音频,同时处理 SentenceBegin、TranscriptionResultChanged 和 SentenceEnd 事件。中间结果仅在开启相应参数后返回。

  4. 音频发送完毕后,发送 StopTranscription 指令。

  5. 收到 TranscriptionCompleted 后关闭连接。发生错误时,读取 TaskFailed 事件中的状态码和错误信息。

image

指令

指令通过 JSON 文本帧发送,包含 header 和可选的 payload。以下 JSON 为协议结构示例;调用时替换 Appkey,并为任务和消息生成实际 ID。

Header 格式

参数

类型

必选

说明

appkey

String

是

项目的 Appkey。获取方法请参见管理项目。

message_id

String

是

当前消息的唯一 ID,由客户端生成,包含 32 个十六进制字符。每条指令使用新的 ID。

task_id

String

是

当前识别任务的唯一 ID,包含 32 个十六进制字符。同一任务的所有指令保持一致。

namespace

String

是

固定为 SpeechTranscriber。

name

String

是

指令名称:StartTranscription 或 StopTranscription。

StartTranscription 指令

payload 参数如下:

参数

类型

必选

说明

format

String

否

音频格式,默认 pcm。支持 pcm、wav、opus、speex、amr、mp3、aac。

sample_rate

Integer

否

音频采样率,单位为 Hz,默认 16000。根据音频采样率选择 8000 或 16000,并在项目中配置匹配的模型。

enable_intermediate_result

Boolean

否

是否返回中间识别结果,默认 false。

enable_punctuation_prediction

Boolean

否

是否在后处理中添加标点,默认 false。

enable_inverse_text_normalization

Boolean

否

是否启用逆文本规范化(ITN),将中文数字转换为阿拉伯数字,默认 false。

customization_id

String

否

自学习模型 ID。

vocabulary_id

String

否

定制泛热词 ID。

max_sentence_silence

Integer

否

断句静音阈值,单位为毫秒。静音时长超过该阈值时判定断句。取值范围为 200~2000,默认 800。

enable_words

Boolean

否

是否返回词信息,默认 false。

disfluency

Boolean

否

是否过滤转写文本中的语气词,默认 false。

speech_noise_threshold

Float

否

噪音判定阈值,范围为 -1~1。越接近 -1,噪音越可能被判定为语音;越接近 1,语音越可能被判定为噪音。此为高级参数,调整后需测试识别效果。

enable_semantic_sentence_detection

Boolean

否

是否启用语义断句,默认 false。

{
  "header": {
    "message_id": "05450bf69c53413f8d88aed1ee600001",
    "task_id": "640bc797bb684bd69601856513070001",
    "namespace": "SpeechTranscriber",
    "name": "StartTranscription",
    "appkey": "<your_appkey>"
  },
  "payload": {
    "format": "pcm",
    "sample_rate": 16000,
    "enable_intermediate_result": true,
    "enable_punctuation_prediction": true,
    "enable_inverse_text_normalization": true
  }
}

StopTranscription 指令

通知服务端音频发送完毕并停止转写。此指令无需 payload。

{
  "header": {
    "message_id": "05450bf69c53413f8d88aed1ee600002",
    "task_id": "640bc797bb684bd69601856513070001",
    "namespace": "SpeechTranscriber",
    "name": "StopTranscription",
    "appkey": "<your_appkey>"
  }
}

事件

服务端通过 JSON 文本帧返回事件。header 标识任务、事件名称和状态,payload 包含该事件的数据。成功响应的 header.status 为 20000000,状态说明位于 header.status_text。以下为省略部分字段的结构示例,文本和时间值仅用于说明字段含义。

TranscriptionStarted 事件

表示服务端已准备好接收音频。收到该事件后再发送二进制音频帧;通过 header.task_id 关联任务,不依赖响应中存在 payload.session_id。

{
  "header": {
    "namespace": "SpeechTranscriber",
    "name": "TranscriptionStarted",
    "task_id": "640bc797bb684bd69601856513070001",
    "status": 20000000,
    "status_text": "Gateway:SUCCESS:Success."
  }
}

SentenceBegin 事件

表示服务端检测到一句话的开始。

Payload 参数

类型

说明

index

Integer

句子编号,从 1 开始递增。

time

Integer

相对于整个音频流起点的句子开始时间,单位为毫秒。

{
  "header": {"name": "SentenceBegin", "status": 20000000},
  "payload": {"index": 1, "time": 0}
}

TranscriptionResultChanged 事件

开启 enable_intermediate_result 后,识别结果变化时返回此事件。

Payload 参数

类型

说明

index

Integer

句子编号,从 1 开始递增。

time

Integer

当前已处理的音频时长,单位为毫秒。

result

String

当前的中间识别结果。

words

Array<Word>

词信息数组,开启 enable_words 后返回词信息。

status

Integer

句子级状态码(如返回),与 header.status 分开处理。

Word 结构

参数

类型

说明

text

String

词文本。

startTime

Integer

词开始时间,单位为毫秒。

endTime

Integer

词结束时间,单位为毫秒。

示例

{
  "header": {"name": "TranscriptionResultChanged", "status": 20000000},
  "payload": {
    "index": 1,
    "time": 1000,
    "result": "今天天气",
    "words": [
      {"text": "今天", "startTime": 0, "endTime": 500},
      {"text": "天气", "startTime": 500, "endTime": 1000}
    ]
  }
}

SentenceEnd 事件

表示服务端检测到一句话的结束。

Payload 参数

类型

说明

index

Integer

句子编号,从 1 开始递增。

time

Integer

当前已处理的音频时长,单位为毫秒。

begin_time

Integer

对应 SentenceBegin 事件的时间,单位为毫秒。

result

String

当前句子的最终识别结果。

confidence

Double

结果置信度,范围为 0.0~1.0,值越大表示置信度越高。

words

Array<Word>

词信息数组,开启 enable_words 后返回词信息。

status

Integer

句子级状态码。正常识别结果可返回 0。不要与 header.status 混淆。

stash_result

StashResult

暂存结果。启用语义断句后可包含下一句尚未断句的中间结果;其中的文本也可能为空。

StashResult 结构

参数

类型

说明

sentenceId

Integer

句子编号,从 1 开始递增。

beginTime

Integer

句子开始时间。

text

String

暂存的转写内容。

currentTime

Integer

当前处理时间。

示例

{
  "header": {"name": "SentenceEnd", "status": 20000000},
  "payload": {
    "index": 1,
    "time": 1500,
    "begin_time": 0,
    "result": "今天天气很好。"
  }
}

TranscriptionCompleted 事件

发送 StopTranscription 后,服务端完成转写并返回该事件。

{
  "header": {
    "namespace": "SpeechTranscriber",
    "name": "TranscriptionCompleted",
    "task_id": "640bc797bb684bd69601856513070001",
    "status": 20000000,
    "status_text": "Gateway:SUCCESS:Success."
  }
}

TaskFailed 事件

请求失败时,读取 header.status 和 header.status_text 定位问题。例如,消息 ID 格式无效时返回 40000002。该值是服务端业务错误码,不是 WebSocket Close 帧的状态码。

JavaScript 示例代码

可以参考实时语音识别前端 demo.html了解浏览器录音和音频发送方式。

常见问题

如何发送音频?每次发送多少字节?

音频通过二进制帧发送,不放入指令的 JSON payload。按音频时长分片发送,例如 16000 Hz、16 bit、单声道 PCM 每 100 ms 对应 3200 字节,8000 Hz 时对应 1600 字节。分片大小不限定为这两个值;发送节奏需与音频时长匹配。

为什么返回 Invalid message id?

检查 message_id 是否包含 32 个十六进制字符。仅长度为 32、但包含非十六进制字符的字符串仍会被拒绝。task_id 也需符合格式要求。

发送音频后连接断开,如何排查?

先记录服务端返回的 TaskFailed 事件、task_id、状态码和错误信息,再检查 Token 是否有效、请求字段是否正确、音频格式是否受支持,以及客户端是否持续按协议发送音频。没有收到错误事件时,再检查客户端的错误和连接关闭日志。客户端设置 status 不能改变服务端处理结果。

如何生成 message_id 和 task_id?

由客户端生成 32 个十六进制字符组成的唯一 ID。同一识别任务始终使用同一个 task_id;每次发送指令时生成新的 message_id。

如何持续发送实时音频?

客户端持续采集音频并分片发送,同时接收服务端事件。停止采集并发送完剩余音频后,再发送 StopTranscription。使用本地文件模拟实时音频流的代码,请参见Java SDK。