EVA Gateway WebSocket 接入文档

EVA Gateway WebSocket API

EVA Gateway 提供基于 WebSocket 的 ASR 双向流式接口,可在持续发送音频的同时接收实时识别结果。该接口兼容 OpenAI Realtime API 的转录事件子集;模型、音频格式、采样率等参数与 HTTP ASR 接口保持一致,具体参数取值和模型限制请参阅 ASR 参数说明

当前仅支持 ASR,暂不支持 TTS。 仅部分 ASR 模型支持 WebSocket 实时识别,请在模型广场中查看模型信息、接口能力和音频参数。

连接与鉴权

连接地址:

wss://eva-gateway.autoarkai.com/v1/realtime

建立 WebSocket 连接时,须在握手请求头中携带 API Key:

Authorization: Bearer <你的 API_KEY>

会话流程

  1. 建立 WebSocket 连接,等待服务端返回 session.created
  2. 发送 session.update,配置模型、音频格式和服务端 VAD。
  3. 收到 session.updated 后,通过 input_audio_buffer.append 持续发送 Base64 编码的音频块。
  4. 服务端返回实时识别结果,并通过 server_vad 自动完成分句。
  5. 音频发送完毕并收到最终结果后,由客户端关闭连接;若长时间没有语音输入,服务端会在静音超时后主动断开。

当前仅支持 turn_detection: {"type": "server_vad"} 自动分句,不支持客户端通过 input_audio_buffer.commitinput_audio_buffer.clear 手动控制分句。

静音超时

若 60 秒内没有识别出任何文本,服务端会发送 errorcode: "51005")并主动断开连接。

注意:部分上游服务商在一定时间内未收到音频帧时会主动断开连接,请客户端自行处理此类问题,例如发送静音音频帧、监听连接关闭事件并按需重连等。

时序

sequenceDiagram
    participant C as 客户端
    participant G as EVA Gateway

    C->>G: WebSocket Upgrade + Authorization
    G-->>C: session.created
    C->>G: session.update
    G-->>C: session.updated
    loop 持续发送音频
        C->>G: input_audio_buffer.append(audio: Base64)
        G-->>C: conversation.item.input_audio_transcription.delta
    end
    G-->>C: input_audio_buffer.committed
    G-->>C: conversation.item.input_audio_transcription.completed
    C->>G: 关闭连接

每条消息均为 JSON 文本帧。event_id 由 Gateway 生成,用于定位事件;客户端不应依赖其具体格式。

客户端事件

session.update

收到 session.created 后,客户端应发送此事件以初始化转录会话。模型通过 session.audio.input.transcription.model 指定。

{  "type": "session.update",  "session": {    "type": "transcription",    "audio": {      "input": {        "format": {          "audio_format": "pcm",          "sample_rate": 16000,          "channels": 1        },        "transcription": {          "model": "<支持实时 ASR 的模型 ID>",          "keywords": "奇多多,无界方舟"        },        "turn_detection": {          "type": "server_vad"        }      }    },    "provider_params": "{\"key\": \"value\"}"  }}
参数类型说明
session.typestring固定为 transcription。当前不支持完整的 realtime 会话。
session.audio.input.transcription.modelstring模型广场中标记为支持实时 WebSocket 的 ASR 模型 ID。不同模型的音频格式和采样率要求可能不同。
session.audio.input.transcription.keywordsstring,可选热词提示,逗号分隔字符串(与 HTTP 转录接口的 hotwords 参数一致),按模型能力生效。
session.audio.input.format.audio_formatstring音频编码类型。仅支持可按字节精确计时的 PCM 格式(pcm* 及其容器 wav);opus/flac/aac 等压缩格式因无法按转发字节计费而会被拒绝。经 provider_params 重写的格式同样受限。
session.audio.input.format.sample_rateinteger必填。音频采样率,单位 Hz,必须为正整数并符合所选模型要求。
session.audio.input.format.channelsinteger声道数。示例使用单声道 1
session.audio.input.turn_detection.typestring当前固定为 server_vad,由模型服务自动判断分句结束。
session.provider_paramsstring,可选原生参数透传通道,用于传入上表未覆盖的模型专属参数(与 HTTP 转录接口的 provider_params 参数一致),其值为一个 JSON 字符串。当某项参数同时通过上表字段设置时,以 provider_params 中的值为准(model 除外)。

input_audio_buffer.append

发送一段音频。audio 必须是原始音频字节经 Base64 编码后得到的字符串。

{  "type": "input_audio_buffer.append",  "audio": "<Base64 编码的音频字节>"}

建议客户端按照音频实际速率发送时长约为 100-200 ms 的音频块。当前不支持 input_audio_buffer.commitinput_audio_buffer.clear,发送后会收到 error 事件。

服务端事件

session.created

连接建立后,Gateway 发送以下事件:

{  "event_id": "evt_abc12345_1",  "type": "session.created",  "session": {    "id": "abc12345-...",    "object": "realtime.session"  }}

session.updated

配置成功后,Gateway 返回规范化后的会话配置:

{  "event_id": "evt_abc12345_2",  "type": "session.updated",  "session": {    "id": "abc12345-...",    "object": "realtime.session",    "audio": {      "input": {        "format": {          "audio_format": "pcm",          "sample_rate": 16000,          "channels": 1        },        "transcription": {          "model": "<请求的模型 ID>",          "keywords": "奇多多,无界方舟"        },        "turn_detection": {          "type": "server_vad"        }      }    }  }}

conversation.item.input_audio_transcription.delta

返回实时识别候选文本:

{  "event_id": "evt_abc12345_8",  "type": "conversation.item.input_audio_transcription.delta",  "item_id": "item_turn_001",  "content_index": 0,  "delta": "你好,欢迎使用"}

delta 的内容取决于具体模型,可能是当前分句的增量片段,也可能是当前分句的完整候选文本,客户端不要无条件拼接所有 delta

服务端 VAD 确定分句后,事件顺序为 committedcompleted

input_audio_buffer.committed

{  "event_id": "evt_abc12345_9",  "type": "input_audio_buffer.committed",  "item_id": "item_turn_001",  "previous_item_id": null}

conversation.item.input_audio_transcription.completed

{  "event_id": "evt_abc12345_10",  "type": "conversation.item.input_audio_transcription.completed",  "item_id": "item_turn_001",  "content_index": 0,  "transcript": "你好,欢迎使用 EVA Gateway。",  "usage": {    "duration_ms": 1840  },  "credit": 123}

error

{  "event_id": "evt_abc12345_11",  "type": "error",  "error": {    "code": "40003",    "type": "client",    "message": "input_audio_buffer.commit is not supported; turns are detected automatically (server_vad)",    "param": null  }}

Python 示例

import asyncioimport base64import json import websockets async def main():    async with websockets.connect(        "wss://eva-gateway.autoarkai.com/v1/realtime",        additional_headers={"Authorization": "Bearer <你的 API_KEY>"},    ) as ws:        await ws.recv()  # session.created         # 配置会话        await ws.send(json.dumps({            "type": "session.update",            "session": {                "type": "transcription",                "audio": {                    "input": {                        "format": {"audio_format": "pcm", "sample_rate": 16000, "channels": 1},                        "transcription": {"model": "<支持实时 ASR 的模型 ID>"},                        "turn_detection": {"type": "server_vad"},                    }                }            }        }))        await ws.recv()  # session.updated         # 发送音频(16kHz 单声道 PCM,按实际速率每 200ms 发送 200ms 音频)        CHUNK_BYTES = 6400  # 200ms @ 16kHz/16bit/mono        with open("audio.pcm", "rb") as f:            while data := f.read(CHUNK_BYTES):                await ws.send(json.dumps({                    "type": "input_audio_buffer.append",                    "audio": base64.b64encode(data).decode(),                }))                await asyncio.sleep(0.2)         # 音频发完后追加 2s 静音,让 server_vad 判定句子结束、下发 completed        SILENCE = b"\x00" * (16000 * 4)  # 2s 静音(16kHz/16bit/单声道)        for i in range(0, len(SILENCE), CHUNK_BYTES):            await ws.send(json.dumps({                "type": "input_audio_buffer.append",                "audio": base64.b64encode(SILENCE[i:i + CHUNK_BYTES]).decode(),            }))            await asyncio.sleep(0.2)         # 接收识别结果        async for raw in ws:            event = json.loads(raw)            if event["type"] == "conversation.item.input_audio_transcription.delta":                print("实时:", event["delta"])            elif event["type"] == "conversation.item.input_audio_transcription.completed":                print("最终:", event["transcript"])                break asyncio.run(main())

运行前请将 API_KEY 替换为你的密钥,并按所选模型的要求准备音频文件(上述示例对应 16kHz / 单声道 PCM)。