# 边录边转写（实时 ASR）接入指南

更新日期：2026-10-26。API 根地址：`https://work.zingyang.com/api`。

本指南依据当前平台签发服务与 iOS 实际调用方整理。实时音频由客户端通过 WebSocket 发往腾讯云；平台负责校验用户、租户、套餐并签发短时连接地址。它不同于[上传文件后识别的短语音 ASR](/asr/)，也不是 SSE 对话接口。

## 1. 接入前提

- 已登录，具有有效的 `X-Access-Token`。
- 每次签发带 `X-Tenant-Id`：租户存在、启用且在有效期内，当前用户为有效成员。
- 租户拥有有效的 `TALK_AI_PROCESS_MINUTES` 权益，且通过至少 1 个计量单位的余量检查；无限额权益按平台规则处理。管理员身份也不绕过此检查。
- 服务端已开启实时转写，腾讯 ASR 凭据、对应产品及供应商额度可用；若配置了账号允许名单，还须命中名单。
- 客户端取得麦克风权限，并明确告知音频将发送到腾讯云、取得用户同意；尊重仅 Wi-Fi 上传设置。

**计量边界：当前签发入口仅检查套餐准入，没有在此预扣额度，也没有按这条 WebSocket 实际时长结算或在余量耗尽时主动断开。** 签发成功不等于完整实时用量闭环；不能将 60 秒凭证有效期理解为仅能识别 60 秒或已购买 60 秒额度。

## 2. 获取短时连接地址

`POST /talk/v1/realtime-speech/session`

无请求体，无查询参数。不接受客户端传入用户 ID、模型、腾讯密钥或签名参数。

```bash
curl --request POST \
  'https://work.zingyang.com/api/talk/v1/realtime-speech/session' \
  --header 'X-Access-Token: <平台登录token>' \
  --header 'X-Tenant-Id: <当前租户ID>' \
  --header 'Accept: application/json'
```

正常 App 请求使用上述平台请求头。AI 工具代用户操作时须先获得授权，并额外携带 `X-Zing-Ai-Context: 1`、`X-Open-Confirm: confirmed`。

成功响应为平台标准结构，数据从 **`result`** 读取；不要使用旧文档中的 `data`：

```json
{
  "success": true,
  "code": 200,
  "message": "",
  "result": {
    "url": "wss://asr.cloud.tencent.com/asr/v2/APP_ID?SIGNED_QUERY",
    "voice_id": "00000000-0000-4000-8000-000000000001",
    "expires_at": 1792972860
  },
  "timestamp": 1792972800000
}
```

以上地址与时间仅为结构示例，不可直接使用。

| 字段 | 类型 | 说明 |
|---|---|---|
| url | string | 服务端生成的完整 WebSocket 签名地址；直接使用，不修改参数、不重复编码 |
| voice_id | string | 本次会话 UUID；每次签发均为新会话 |
| expires_at | integer | Unix 秒，服务端签发时刻加 60 秒；在过期前建立连接 |

响应带 `Cache-Control: no-store`。完整 URL 是敏感短时凭证，不写日志、分析平台、剪贴板或持久缓存，不转发给其他用户。客户端不接触 SecretKey，也不自行实现签名。同租户同用户签发间隔至少 1 秒；没有客户端幂等键。

## 3. 建立连接与发送音频

1. 检查签发请求 HTTP 状态、`success`、`code`，确认 `result.url` 为 `wss`、主机为 `asr.cloud.tencent.com`、路径以 `/asr/v2/` 开头且凭证未过期。
2. 用完整 URL 建立 WebSocket。平台 token 和租户头只发给平台接口，**不要转发到腾讯云**。
3. 等待腾讯首个响应，确认 `code == 0` 后才开始发送音频；现有 iOS 调用方设置 10 秒握手截止时间。
4. 按录音节奏发送二进制 PCM 帧，并持续接收识别结果。
5. 结束时先发送剩余音频，再发送文本帧 `{"type":"end"}`；等到 `final == 1` 后关闭。现有 iOS 最多等待 8 秒，超时也释放连接。

当前签发参数固定为 `engine_model_type=16k_zh_en_speaker`、`voice_format=1`、`result_mod=1`、`speaker_diarization=1`、`enable_speaker_context=0`。客户端不能更改已签名参数。

| 音频项 | 当前客户端发送格式 |
|---|---|
| 采样率 | 16000 Hz |
| 位深与声道 | 16 位有符号整数，小端，单声道 |
| 容器 | 原始 PCM，无 WAV 文件头 |
| 帧类型 | WebSocket 二进制帧，不是 Base64 或 JSON |
| 分包节奏 | 每 40 ms 发送约 40 ms 音频，即 1280 字节；末包可不足 1280 字节 |

不要直接发送麦克风产生的 44.1/48 kHz Float32 数据，也不要直接发送 m4a/mp3 压缩文件。先重采样并转换格式。当前 iOS 待发送队列最多约 5 秒；慢网应停止云连接并明确提示，不能无限缓存或高速补发整段历史音频。

## 4. 解析实时文本和说话人

WebSocket 消息使用腾讯 ASR V2 协议，**不是平台的 Result 包装**；这里的 `code=0` 才表示供应商成功。当前客户端读取 `sentences.sentence_list`：

```json
{
  "code": 0,
  "final": 0,
  "sentences": {
    "sentence_list": [
      {
        "sentence_id": 0,
        "sentence": "我们开始今天的会议。",
        "sentence_type": 1,
        "speaker_id": 0,
        "start_time": 0,
        "end_time": 1800
      }
    ]
  }
}
```

| 字段 | 客户端处理 |
|---|---|
| code | 非 0 表示供应商错误；停止发送并释放连接 |
| final | 1 表示整条会话结束，不等同某一句定稿；字段可能不出现 |
| sentences | 握手或结束消息可能没有句子；不能因此解析失败 |
| sentence_id | 在当前会话内作为句子更新键，不是全局 ID |
| sentence | 当前句子的完整文本快照，按键更新，不能逐包直接追加 |
| sentence_type | 0 为暂定，1 为确定；迟到的暂定结果不应覆盖已确定结果 |
| speaker_id | 当前会话内的说话人标签；负数显示待确认，不代表用户或人物 ID |
| start_time / end_time | 毫秒，相对于当前语音会话；续录时叠加本地录音偏移 |

已有 iOS 以当前录音轮次隔离回调，按 `sentence_id` 更新并排序。不同会话的同一个 `speaker_id` 不保证同一人；不要据此自动绑定联系人、人物或声纹身份。可选的 `/realtime-speech/candidates` 是另一项暂定人物候选能力，不是获取文本的必需步骤，本指南不把它当作正式身份识别。

供应商字段语义可对照[腾讯云实时语音识别 V2 官方协议](https://cloud.tencent.com/document/product/1093/131127)；平台签发参数和当前客户端解析以上述实际实现为准。

## 5. 暂停、续录、取消与保存

- 暂停时结束当前流；续录重新申请凭证、建立新会话。保留前文，使用新的轮次标识，忽略旧连接迟到的回调。
- 用户退出、取消、切换账号或租户时，关闭旧连接并停止发送；不能复用旧租户的 URL。
- 断线重连需要新凭证；当前没有断点续传或自动补转保证。失败期间可能存在文本空档，应如实提示。
- 具备本机识别能力的客户端可以按已获授权切回本机转写，并显示实际来源；不可通过其他云接口绕过平台的套餐拒绝。
- 此接口不会创建会议记录、登记 COS 文件或保存最终转写正文。完整录音的保存、上传和会后处理仍走原有业务链路；需要持久化文件时参考[统一 COS 上传](/ios-cos-upload/)，不要把实时签发接口当作文件上传接口。

## 6. 错误处理

签发阶段同时检查 HTTP 状态、平台数值 `code`、`success` 和 `message`。Talk 业务错误可能在 `result.code` 附带字符串错误码；共享鉴权或套餐异常不保证有这个扩展字段。

| 场景 | 常见状态 / 错误 | 处理 |
|---|---|---|
| 未登录、用户失效 | 401 | 恢复登录，重新核对租户 |
| 租户无效、非有效成员 | 403 | 选择合法租户，不擅自切换他人租户 |
| 套餐未开通、失效或余量不足 | 402 | 引导套餐购买、续费或升级；不循环重试 |
| 未命中允许名单 | 403 / REALTIME_NOT_ENABLED | 联系管理员确认开通范围 |
| 签发过于频繁 | 429 / REALTIME_RATE_LIMIT | 等待至少 1 秒，避免重复点击并限制重试次数 |
| 实时服务未开启或凭据缺失 | 503 / SERVICE_NOT_CONFIGURED | 联系管理员检查配置与供应商服务 |
| Redis 或其他内部故障 | 500 等实际响应 | 有限退避，不把无凭证当作可直连 |
| 腾讯 WebSocket 返回非 0 code | 供应商错误码 | 与平台 HTTP/业务码分开处理；保留脱敏 code，不记录签名 URL |

现有客户端对腾讯 `4004` 提示供应商额度不可用，对 `6001` 提示跨境能力未开通；这两者不等于平台套餐 402。平台签发成功也不保证供应商握手、余额或识别成功。网络超时可能发生在签发完成之后，每次重试均可能得到新会话，避免无限自动重试。

## 7. 验证范围

已核对 `TalkRealtimeSpeechController#session` → `TalkRealtimeSpeechService#issue/sign` → `AiInvocationAccess#check`、`TalkResponseAdvice`，以及实际调用方 `TencentSpeechSession.prepare/finish`、`TencentSpeechMessage`、`LiveTranscript.applyTencent`。

本次仅发布接入文档与静态站资源，未签发生产语音凭证、发送生产音频或进行付费识别。公开文档可访问不代表所有租户均已开通，也不代表当前实时计量已具备完整结算闭环。

- [上传文件后进行短语音 ASR](/asr/)
- [本人租户列表与切换](/user-tenants/)
- [文件上传与 COS](/ios-cos-upload/)
