> ## Documentation Index
> Fetch the complete documentation index at: https://docs.senseaudio.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 同声传译 WebSocket

> 基于 WebSocket 的实时同声传译协议参考

## 说明

基于 WebSocket 的同声传译接口，支持实时语音识别、翻译与译文播报。通信包含 JSON 控制消息与二进制音频消息两类。

* **接入地址**：`wss://api.senseaudio.cn/ws/v1/audio/simulat-interpreting`
* **鉴权方式**：Bearer Token，格式 `Authorization: Bearer SENSEAUDIO_API_KEY`
* **音频格式**：PCM signed 16-bit little-endian，采样率 16000Hz，单声道
* **模型参数**：`sensenova-livetranslate-1.0`
* **计费单位**：按输入音频时长计费，详见 [计费说明](/guides/account/billing)
* **使用场景**：跨语言会议、实时交流、直播与国际活动

<Warning>
  - 音频必须为 **PCM 16-bit little-endian / 16kHz / 单声道**。
  - 控制消息必须以 **JSON 文本帧** 发送，音频数据必须以 **二进制帧** 发送。
  - 客户端需等待 `connected_success` 后再发送 `task_start`，等待 `task_started` 后再开始推送音频。
  - 当前 API 不支持断线恢复，连接断开后需要重新建立连接并创建新任务。
</Warning>

## 请求头 (Request Headers)

| 参数名 | 必填 | 说明 | 示例 |
| :- | :- | :- | :- |
| **Authorization** | 是 | 鉴权 Token。格式：Bearer SENSEAUDIO\_API\_KEY | Bearer sk-123456... |

## 通信流程

```
1. 客户端建立 WebSocket 连接
   ↓
2. 服务端返回 connected_success 事件
   ↓
3. 客户端发送 task_start 事件
   ↓
4. 服务端返回 task_started 事件
   ↓
5. 客户端持续发送二进制 PCM 音频帧
   ↓
6. 服务端返回原文、译文、译文 TTS 事件
   ↓
7. 客户端发送 task_finish 事件
   ↓
8. 服务端返回 task_finished 事件并关闭连接
```

```mermaid theme={null}
sequenceDiagram
    participant Client as 客户端
    participant Server as 服务端

    Client->>Server: WebSocket Connect + Authorization
    Server-->>Client: connected_success
    Client->>Server: task_start (JSON)
    Server-->>Client: task_started

    loop 实时推流
        Client->>Server: PCM Audio (binary)
        Server-->>Client: si_segment_start
        opt 启用 multi-stage 实时预览
            Server-->>Client: si_incremental_update（可重复）
            Server-->>Client: si_incremental_end
        end
        Server-->>Client: si_token（可重复）
        Server-->>Client: si_text_done
        opt 启用译文 TTS
            Server-->>Client: si_tts_start
            Server-->>Client: si_tts_file
            Server-->>Client: si_tts_end
        end
        Server-->>Client: si_segment_done
    end

    Client->>Server: task_finish (JSON)
    Server-->>Client: task_finished
    Server-->>Client: Close Connection
```

***

## 客户端事件

### 1. task\_start - 开始任务

客户端收到 `connected_success` 后发送 `task_start` 事件配置参数。服务端返回 `task_started` 后方可开始推送二进制音频帧。

**请求参数**

| 参数名 | 类型 | 必填 | 说明 |
| :- | :- | :- | :- |
| **event** | string | 是 | 固定值：`task_start` |
| **model** | string | 是 | 模型名称，目前使用 `sensenova-livetranslate-1.0` |
| **audio\_setting** | object | 是 | 音频参数设置 |
| **vad\_setting** | object | 否 | VAD（语音活动检测）设置 |
| **voice\_input\_setting** | object | 否 | 源语言与目标语言设置 |
| **tts\_setting** | object | 否 | 译文 TTS 输出设置 |

#### audio\_setting

| 参数名 | 类型 | 必填 | 说明 |
| :- | :- | :- | :- |
| **sample\_rate** | int | 是 | 采样率，目前仅支持 `16000` |
| **channel** | int | 是 | 声道数，目前仅支持 `1`（单声道） |
| **format** | string | 是 | 音频格式，目前仅支持 `pcm` |

#### vad\_setting（可选）

| 参数名 | 类型 | 说明 | 默认值 |
| :- | :- | :- | :- |
| **threshold** | number | VAD 阈值，有效范围 `(0, 1]` | 0.45 |
| **silence\_duration** | int | 静音断句时长，单位 ms | 500 |
| **min\_speech\_duration** | int | 最短语音时长，单位 ms | 500 |
| **soft\_max\_duration** | int | 分句软上限，单位 ms | 10000 |
| **hard\_max\_duration** | int | 分句硬上限，单位 ms | 20000 |
| **soft\_silence\_duration** | int | 达到软上限后的静音断句时长，单位 ms | 250 |

#### voice\_input\_setting

| 参数名 | 类型 | 必填 | 说明 |
| :- | :- | :- | :- |
| **language** | string | 否 | 输入语言，例如 `Chinese`、`English` |
| **target\_language** | string | 否 | 目标语言，例如 `English`、`Chinese`；为空时不生成译文 |
| **hot\_words** | string\[] | 否 | 热词列表 |
| **abbreviations** | object | 否 | 缩写或专有词映射，键为原词，值为期望内容 |
| **pipeline\_mode** | string | 否 | pipeline 模式，可选 `single_stage` 或 `multi_stage`，默认 `single_stage` |
| **incremental\_enabled** | boolean | 否 | 是否启用 VAD 定段前的实时预览，默认 `false`；仅当 `pipeline_mode` 为 `multi_stage` 时可设为 `true` |

当前可用的输入语言与目标语言包括：

* `Chinese`
* `English`
* `Japanese`
* `Korean`
* `Cantonese`
* `German`
* `French`
* `Spanish`
* `Portuguese`
* `Italian`
* `Russian`

#### tts\_setting

| 字段 | 类型 | 默认值 | 说明 |
| - | - | - | - |
| **enable** | boolean | false | 是否生成译文 TTS 音频 |
| **mode** | string | 空 | TTS 模式；可选 `clone` 或 `preset` |
| **voice\_id** | string | 空 | TTS 音色 ID；启用 TTS 时应传入可用音色 |

#### 支持的音色

`tts_setting.mode` 为 `preset` 时，`voice_id` 支持以下预设音色：

| 语种 | 女声 (f) | 男声 (m) |
| - | - | - |
| 中文 | `basic_chinese_f` | `basic_chinese_m` |
| 粤语 | `basic_cantonese_f` | `basic_cantonese_m` |
| 英语（英音） | `f_m_0006_en-GB` | `m_y_0034_c_en-GB` |
| 英语（美音） | `f_m_0006_en-US` | `m_y_0034_c_en-US` |
| 日语 | `f_m_0006_ja-JP` | `m_y_0034_c_ja-JP` |
| 韩语 | `f_m_0006_ko-KR` | `m_y_0034_c_ko-KR` |
| 法语 | `f_m_0006_fr-FR` | `m_y_0034_c_fr-FR` |
| 德语 | `f_m_0006_de-DE` | `m_y_0034_c_de-DE` |
| 俄语 | `f_m_0006_ru-RU` | `m_y_0034_c_ru-RU` |
| 意大利语 | `f_m_0006_it-IT` | `m_y_0034_c_it-IT` |
| 西班牙语 | `f_m_0006_es-ES` | `m_y_0034_c_es-ES` |
| 葡萄牙语 | `f_m_0006_pt-BR` | `m_y_0034_c_pt-BR` |

**请求示例**

```json theme={null}
{
  "event": "task_start",
  "model": "sensenova-livetranslate-1.0",
  "audio_setting": {
    "sample_rate": 16000,
    "format": "pcm",
    "channel": 1
  },
  "voice_input_setting": {
    "language": "Chinese",
    "target_language": "English"
  },
  "tts_setting": {
    "enable": false
  }
}
```

任务启动成功后，服务端返回 `task_started`。

### 2. 发送音频

音频通过 WebSocket 二进制消息发送，不要放入 JSON，也不要进行 Base64 编码。

音频必须符合以下要求：

* PCM signed 16-bit
* 小端序（little-endian）
* 采样率 16000Hz
* 单声道

建议每次发送约 100ms 音频，即 3200 字节。

### 3. task\_finish

音频发送完成后，客户端发送：

```json theme={null}
{
  "event": "task_finish"
}
```

发送 `task_finish` 后，不要继续发送音频或其他业务事件。服务端会继续处理已经接收的剩余音频，随后返回 `task_finished`。

***

## 服务端事件

| 事件 | 说明 |
| - | - |
| `connected_success` | WebSocket 连接建立成功 |
| `task_started` | 任务已启动，可以发送音频 |
| `si_segment_start` | 一个语音段开始处理 |
| `si_incremental_update` | 实时预览快照，可多次修订 |
| `si_incremental_end` | 当前预览停止更新，等待权威结果 |
| `si_segment_discarded` | 预览被判定为噪声，应删除该预览 |
| `si_token` | 译文流式 token |
| `si_text_done` | 文本流水线完成，不等待 TTS |
| `si_tts_start` | 译文 TTS 开始 |
| `si_tts_file` | TTS 音频结果 |
| `si_tts_end` | TTS 处理结束 |
| `si_segment_done` | 分句最终完成，包含完整 timing |
| `si_segment_error` | 单个分句处理失败，会话可以继续 |
| `heartbeat` | WebSocket 保活 |
| `task_finished` | 任务完成，随后连接关闭 |
| `task_failed` | 任务级错误，查看 `base_resp` |

### 通用消息格式

除 WebSocket Ping 控制帧外，服务端业务事件均为 JSON 文本消息：

```json theme={null}
{
  "event": "connected_success",
  "session_id": "session-id-xxx",
  "base_resp": {
    "status_code": 0,
    "status_msg": "success"
  }
}
```

| 字段 | 类型 | 说明 |
| - | - | - |
| `event` | string | 事件类型 |
| `session_id` | string | 当前 WebSocket 任务的会话 ID |
| `data` | object | 事件数据。没有数据时不返回该字段 |
| `base_resp.status_code` | int | 状态码，`0` 表示成功 |
| `base_resp.status_msg` | string | 状态详情 |

***

## 错误处理

连接建立后的错误通过 `task_failed.base_resp` 返回。客户端应同时记录 `status_code`、`status_msg` 和 `session_id`。

常见错误包括：

* 首条消息不是 `task_start`
* 建立连接后长时间未发送 `task_start`
* 重复发送 `task_start`
* 在 `task_started` 前发送音频
* 在 `task_finish` 后继续发送音频
* 使用文本帧发送音频
* 使用二进制帧发送 JSON
* 输入音频不是 16000Hz、16-bit、单声道 PCM
* 模型不存在或不支持同声传译
* 余额不足或并发受限

### 1. 握手阶段 HTTP 错误

路由为 `GET /ws/v1/audio/simulat-interpreting`。ApiToken、ApiKey、User 中间件返回 OpenAI 风格错误 JSON（顶层 `code`、`message`），状态与消息如下：

| HTTP 状态 | `code` | `message` | 触发条件 |
| - | - | - | - |
| 401 | `authentication_error` | `invalid authorization` | 未提供 token |
| 401 | `authentication_error` | `incorrect API key provided` | token/API key 无效、已禁用或找不到 |
| 403 | `permission_error` | `access token does not have permission for this endpoint` | access token ACL 不允许访问该路径 |
| 403 | `permission_error` | `incorrect API key provided` | 间接 API key 直接访问 |
| 403 | `permission_error` | `this api key is not allowed to access the requested model type` | 该API key禁用了STT模型类型 |
| 403 | `permission_error` | `your account is disabled` | 用户被禁用或账号状态不可用 |
| 402 | `quota_exceeded_error` | `you exceeded your current quota` | 剩余额度不足 |
| 500 | `internal_error` | `internal error, please try later again` | 内部错误 |

WebSocket 升级请求缺少协议必需头时，gorilla/websocket 直接返回 HTTP 错误：通常为 400（缺少 `Connection: Upgrade`、`Upgrade: websocket`、`Sec-WebSocket-Version: 13` 或无效 `Sec-WebSocket-Key`）、403（Origin 不允许）、405（方法不是 GET）或 500（服务端无法 hijack）；响应为普通 HTTP 错误文本，不带 `base_resp`。

### 2. 连接建立后的 `task_failed` 事件错误信息

以下是 apisvc 当前分支会主动生成的完整固定消息。除特别标注外，状态码为 `400000`（请求/状态错误）或 `500000`（内部/上游错误）。带 `%q`、`%s` 的消息会插入实际字段值。

| 状态码 | `status_msg` | 触发条件 |
| - | - | - |
| 401004 | `unauthorized` | 会话认证过期或API key未解析到用户 |
| 400000 | `task_start timeout` | 连接成功后15秒内未收到 `task_start` |
| 500000 | `failed to read task_start` | 读取首帧失败 |
| 400000 | `first WebSocket message must be task_start` | 首帧不是文本 `task_start`，或事件名不正确 |
| 400000 | `invalid JSON format` | 控制帧不是合法JSON |
| 400000 | `task_start is only allowed once` | 任务运行中重复发送`task_start` |
| 400000 | `task_finish requires a running task` | 非运行态发送`task_finish` |
| 400000 | `audio is only accepted after task_started and before task_finish` | 音频发送时机不正确 |
| 400000 | `unsupported WebSocket message type` | 发送了文本/二进制之外的帧类型 |
| 400000 | `unknown event %q` | 任务运行中发送了未知控制事件 |
| 400000 | `model not set` | 未提供模型 |
| 400000 | `model %q not found` | 模型不存在 |
| 400000 | `unsupported model %q` | 模型不在同传支持列表 |
| 400000 | `<field> must not be null` | task\_start任一已识别字段显式为 JSON `null` |
| 400000 | `audio_setting.format must be 'pcm', got %q` | 音频格式不是 `pcm` |
| 400000 | `audio_setting.sample_rate must be 16000` | 采样率不是 16000 |
| 400000 | `audio_setting.channel must be 1` | 不是单声道 |
| 400000 | `vad_setting.threshold must be between 0 and 1` | VAD阈值越界 |
| 400000 | `<field> must be 0 or between 1 and 2147483647` | VAD时长字段为负数或超过 int32 |
| 400000 | `vad_setting.soft_max_duration must not exceed hard_max_duration` | 软上限大于硬上限 |
| 400000 | `vad_setting.min_speech_duration must not exceed hard_max_duration` | 最短语音时长大于硬上限 |
| 400000 | `unsupported voice_input_setting.language %q` | 输入语言不支持 |
| 400000 | `unsupported voice_input_setting.target_language %q` | 目标语言不支持 |
| 400000 | `voice_input_setting intervals must be between 0 and 2147483647` | 摘要/整理间隔越界 |
| 400000 | `voice_input_setting.pipeline_mode must be 'single_stage' or 'multi_stage'` | pipeline 模式非法 |
| 400000 | `voice_input_setting.incremental_enabled requires pipeline_mode 'multi_stage'` | 增量开启但未使用multi-stage |
| 400000 | `tts_setting.mode must be 'clone' or 'preset'` | TTS模式非法 |
| 500000 | `failed to initialize WebSocket heartbeat` | 初始化心跳失败 |
| 500000 | `WebSocket heartbeat timeout` | 客户端未及时响应心跳 |
| 500000 | `failed to validate model` | 模型校验内部失败 |
| 500000 | `failed to initialize billing` | 初始化计费失败 |
| 400001 | `insufficient funds` | 余额/计费账户不可用（`RCInsufficientFunds`） |
| 429002 | `rate limit exceeded` | 计费限流 |
| 500000 | `failed to check balance` | 余额检查内部失败 |
| 500000 | `billing failed` | 计费过程失败 |
| 500000 | `failed to connect upstream` | 连接模型上游失败 |
| 500000 | `failed to send task_started` | 向客户端发送成功事件失败 |
| 500000 | `failed to send audio upstream` | 向模型上游发送音频失败 |
| 500000 | `failed to finish upstream task` | 向模型上游发送结束命令失败 |
| 500000 | `upstream finish timeout` | 上游未在结束超时内返回终态 |
| 500000 | `upstream audio write timeout` | 上游音频写入超时 |
| 500000 | `upstream connection interrupted` | 上游连接中断或监听 panic |
| 500000 | `upstream ended without terminal event` | 上游结束但未返回 `task_finished`/`task_failed` |
| 500000 | `failed to forward upstream event` | 向客户端转发上游事件失败 |

***

## 调用示例

### Python

依赖：

```bash theme={null}
pip install websockets
```

示例代码：

```python theme={null}
import asyncio
import json
import os

import websockets

WS_URL = "wss://api.senseaudio.cn/ws/v1/audio/simulat-interpreting"
API_KEY = os.environ["SENSEAUDIO_API_KEY"]
AUDIO_FILE = "input_16k_s16le_mono.pcm"


async def wait_for_event(ws, expected):
    while True:
        message = json.loads(await ws.recv())
        if message.get("event") == "task_failed":
            raise RuntimeError((message.get("base_resp") or {}).get("status_msg"))
        if message.get("event") == expected:
            return message


async def receive_events(ws):
    async for raw in ws:
        message = json.loads(raw)
        event = message.get("event")
        data = message.get("data") or {}

        if event == "si_segment_done":
            print(f"原文: {data.get('original_text', '')}")
            print(f"译文: {data.get('text', '')}")
        elif event == "task_failed":
            raise RuntimeError((message.get("base_resp") or {}).get("status_msg"))
        elif event == "task_finished":
            return


async def main():
    headers = {"Authorization": f"Bearer {API_KEY}"}

    async with websockets.connect(WS_URL, additional_headers=headers) as ws:
        await wait_for_event(ws, "connected_success")

        await ws.send(json.dumps({
            "event": "task_start",
            "model": "sensenova-livetranslate-1.0",
            "audio_setting": {
                "sample_rate": 16000,
                "format": "pcm",
                "channel": 1,
            },
            "voice_input_setting": {
                "language": "Chinese",
                "target_language": "English",
            },
            "tts_setting": {"enable": False},
        }))
        await wait_for_event(ws, "task_started")

        receive_task = asyncio.create_task(receive_events(ws))

        with open(AUDIO_FILE, "rb") as audio:
            while chunk := audio.read(3200):
                await ws.send(chunk)
                await asyncio.sleep(0.1)

        await ws.send(json.dumps({"event": "task_finish"}))
        await receive_task


asyncio.run(main())
```

### Node.js

依赖：

```bash theme={null}
npm install ws
```

示例代码：

```javascript theme={null}
const fs = require('fs')
const WebSocket = require('ws')

const WS_URL = 'wss://api.senseaudio.cn/ws/v1/audio/simulat-interpreting'
const API_KEY = process.env.SENSEAUDIO_API_KEY
const AUDIO_FILE = 'input_16k_s16le_mono.pcm'

const ws = new WebSocket(WS_URL, {
  headers: {
    Authorization: `Bearer ${API_KEY}`,
  },
})

let audioStream = null

ws.on('message', (raw, isBinary) => {
  if (isBinary) return

  const message = JSON.parse(raw.toString())
  const event = message.event
  const data = message.data || {}

  switch (event) {
    case 'connected_success':
      ws.send(JSON.stringify({
        event: 'task_start',
        model: 'sensenova-livetranslate-1.0',
        audio_setting: {
          sample_rate: 16000,
          format: 'pcm',
          channel: 1,
        },
        voice_input_setting: {
          language: 'Chinese',
          target_language: 'English',
        },
        tts_setting: { enable: false },
      }))
      break

    case 'task_started':
      audioStream = fs.createReadStream(AUDIO_FILE, { highWaterMark: 3200 })
      audioStream.on('data', (chunk) => {
        audioStream.pause()
        ws.send(chunk, { binary: true }, () => {
          setTimeout(() => audioStream.resume(), 100)
        })
      })
      audioStream.on('end', () => {
        ws.send(JSON.stringify({ event: 'task_finish' }))
      })
      break

    case 'si_segment_done':
      console.log('原文:', data.original_text || '')
      console.log('译文:', data.text || '')
      break

    case 'task_failed':
      console.error('任务失败:', message.base_resp?.status_msg)
      break
  }
})
```

***

## 计费说明

请参考 [计费规则](/guides/account/billing)。

***

## 相关资源

<CardGroup cols={2}>
  <Card title="同声传译介绍" icon="book-open" href="/guides/simultaneous-interpretation/overview">
    查看同声传译能力概览、使用场景与参数建议。
  </Card>

  <Card title="模型列表" icon="list" href="/guides/account/model-list">
    查看同声传译模型与其他可调用模型。
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.