实时 ASR(WebSocket)
实时 ASR 通过 WebSocket 流式传输音频,并在您说话时返回转录结果——在音频仍在传输时返回临时的**部分(partial)结果,然后按话语返回权威的最终(final)**结果。可用于实时字幕、会议转录和语音界面。
如需一次性转录完整的音频文件,请改用批量 ASR 端点。
端点
wss://api.shisa.ai/ws/asr/realtime
在 WebSocket 握手期间,使用您的 ASR bearer 令牌进行认证:
Authorization: Bearer YOUR_API_KEY
您的 API 密钥需要对 shisa/asr-realtime 服务具有明确的访问权限。对批量 ASR、聊天、翻译或 TTS 的访问权限不会授予实时 ASR 的访问权限。如果您的密钥使用服务允许列表,请将 shisa/asr-realtime 添加到其中——否则握手将被拒绝。
实时 ASR 专为后端使用而设计。请将 API 密钥保存在服务器端:将音频从浏览器中继到您自己的服务器,再从那里连接到 Shisa。
工作原理
- 使用
Authorization标头打开到端点的 WebSocket。 - 发送一条
session.update消息以设置音频格式和语言。 - 等待
session.created。 - 将原始音频作为 base64 的
input_audio.append消息进行流式传输(每个块 50–250 ms 是不错的起点)。 - 将
asr.partial_result显示为实时临时文本;当asr.final_result到达时将其替换。 - 完成后发送
session.close。
音频要求
发送原始 PCM——不使用容器、不压缩:
| 属性 | 值 |
|---|---|
| 编码 | pcm_s16le(有符号 16 位小端) |
| 采样率 | 16000 Hz |
| 声道 | 1(单声道) |
| 块间隔 | 建议 50–250 ms(示例使用 100 ms) |
发送前请在客户端进行重采样和降混。请勿发送 WAV 头、Ogg、MP3、data URL、浮点 PCM 或立体声音频。
客户端消息
session.update
在发送任何音频之前,务必发送一条 session.update。固定语言的会话是最简单的选项:
{
"type": "session.update",
"session": {
"input_audio_format": "pcm_s16le",
"sample_rate": 16000,
"channels": 1,
"language": "ja"
}
}
| 字段 | 是否必需 | 值 | 备注 |
|---|---|---|---|
input_audio_format | 是 | pcm_s16le | 原始有符号 16 位小端 PCM。 |
sample_rate | 是 | 16000 | 发送前重采样到 16 kHz。 |
channels | 是 | 1 | 仅限单声道。请先降混立体声。 |
language | 是 | ja、en、zh、auto | 已知语言时使用固定值。自动语言识别使用 auto(见下文)。 |
default_language | 仅 auto 时 | ja、en、zh | 检测不确定时的回退值。 |
language_detection_mode | 仅 auto 时 | session、utterance | session 只检测一次;utterance 按段检测(进阶——见下文)。 |
input_audio.append
将音频块作为 base64 编码的 PCM 进行流式传输:
{
"type": "input_audio.append",
"audio": "<base64 pcm_s16le bytes>"
}
session.close
完成后正常关闭会话:
{ "type": "session.close" }
语言识别(可选)
如果您事先不知道说话的语言,请设置 language: "auto"。有两种模式。
会话检测在开始附近识别一次语言,并在整个会话中使用该语言:
{
"type": "session.update",
"session": {
"input_audio_format": "pcm_s16le",
"sample_rate": 16000,
"channels": 1,
"language": "auto",
"default_language": "en",
"language_detection_mode": "session"
}
}
会话会发出 session.language_detecting,然后发出一条包含所选 language 的 session.language_detected。
逐话语检测(language_detection_mode: "utterance")分别检测每个话语的语言,这对于多语言混合的音频很有用。它会为每个话语发出 utterance.language_detected。此模式必须在后端启用;如果未启用,会话将返回带有 code: "invalid_config" 的 error——此时请回退到固定语言或会话检测。
当检测无法确信地选择时,它会回退到 default_language,并且事件会带有 source: "default" 和 reason(例如 no_speech、short_utterance、inconclusive 或 timeout)。请始终将 asr.final_result.text 视为权威结果——不要仅凭语言事件就改写转录文本。
路由器管理的翻译(可选)
路由器可以异步翻译每个非空的asr.final_result。您的密钥必须同时拥有shisa/asr-realtime和shisa/translate访问权限;翻译默认关闭,必须为当前WebSocket会话显式启用。
在session.update之后发送:
{
"type": "router.translation.update",
"id": "translate-en",
"enabled": true,
"target_langs": ["en"]
}
| 字段 | 是否必需 | 说明 |
|---|---|---|
enabled | 必需 | boolean。设为false可禁用翻译,此时省略目标语言。 |
target_langs | 启用时 | 1至3个唯一且有效的语言代码。 |
id | 可选 | 客户端关联ID,会在控制响应中回显;最多36个字符。 |
context | 可选 | 提供给每次翻译的上下文;最多2,000个Unicode码点。 |
keywords | 可选 | 术语表数组;最多20项,每项最多100字节。 |
接受更新后返回:
{
"type": "router.translation.updated",
"id": "translate-en",
"enabled": true,
"target_langs": ["en"]
}
无效配置会返回router.translation.error,例如:
{
"type": "router.translation.error",
"id": "translate-en",
"code": "too_many_target_langs",
"message": "At most 3 target languages are allowed"
}
配置错误代码包括invalid_json、invalid_message_type、invalid_id、id_too_long、invalid_enabled、missing_target_langs、too_many_target_langs、duplicate_target_lang、invalid_target_lang、context_too_long、too_many_keywords、keyword_too_long、translation_access_denied和translation_service_unavailable。其他保留的router.*消息会返回router.error,代码为unknown_router_message或router_message_too_large。
对于每个最终结果,路由器按以下优先级采用第一个有效的源语言:(1) asr.final_result.language,(2) 最新的session.language_detected,(3) session.update.session.language中的固定语言。它不会直接使用独立的utterance.language_detected事件进行翻译。如果最终结果到达时没有已知的有效语言,该目标会收到code: "source_language_unknown"的translation.error。
服务事件
所有事件都是 JSON 文本消息。会话创建后,ASR 后端事件带有session_id和单调递增的seq。路由器生成的router.*和translation.*事件不带这些字段;请通过source_result_id将翻译结果和错误关联到 ASR 最终结果。
session.created
会话已被接受;您可以开始发送音频:
{
"type": "session.created",
"session_id": "asr_sess_...",
"seq": 1,
"format": { "encoding": "pcm_s16le", "sample_rate": 16000, "channels": 1 }
}
语音边界
speech_started 和 speech_stopped 标记每个话语的语音活动检测(VAD)端点:
{
"type": "speech_started",
"session_id": "asr_sess_...",
"seq": 4,
"utterance_id": "utt_0001",
"audio_start_ms": 420
}
{
"type": "speech_stopped",
"session_id": "asr_sess_...",
"seq": 9,
"utterance_id": "utt_0001",
"audio_start_ms": 420,
"audio_end_ms": 2860,
"reason": "vad_endpoint"
}
常见的停止原因有 vad_endpoint、max_buffer 和 session_close。
asr.partial_result
进行中话语的临时文本。请按 utterance_id 显示最新的部分结果,替换前一个——不要将每个部分结果都追加到历史记录中:
{
"type": "asr.partial_result",
"session_id": "asr_sess_...",
"seq": 7,
"utterance_id": "utt_0001",
"result_id": "utt_0001:p3",
"text": "今日の会議は3時から",
"is_final": false,
"audio_start_ms": 420,
"audio_end_ms": 2260
}
asr.final_result
话语的权威文本。使用 replaces 丢弃您正在显示的临时部分结果:
{
"type": "asr.final_result",
"session_id": "asr_sess_...",
"seq": 12,
"utterance_id": "utt_0001",
"result_id": "utt_0001:final",
"replaces": ["utt_0001:p1", "utt_0001:p2", "utt_0001:p3"],
"replaces_audio_range_ms": [420, 2860],
"text": "今日の会議は3時からです。",
"language": "ja",
"is_final": true,
"audio_start_ms": 420,
"audio_end_ms": 2860
}
最终结果是异步的,可能在后续语音事件之后到达。非常长的话语可能会被拆分为带有额外 continuation_of 和 overlap_mode 元数据的续接最终结果;显示时只显示逻辑上的 audio_start_ms–audio_end_ms 范围。
translation.final_result
启用翻译后,路由器会为每个可翻译的ASR最终结果按目标语言各发出一条结果:
{
"type": "translation.final_result",
"utterance_id": "utt_0001",
"source_result_id": "utt_0001:final",
"source_text": "今日の会議は3時からです。",
"text": "Today's meeting starts at 3 o'clock.",
"source_lang": "ja",
"target_lang": "en",
"model": "shisa-v2.1-unphi4-14b"
}
请通过source_result_id将结果附加到产生它的准确ASR最终结果。翻译是异步的,多个目标语言的结果可能以任意顺序到达。model是后端响应报告的模型 ID,可能与翻译请求使用的默认别名shisa-ai/chotto不同。
translation.error
某个目标翻译失败时会发出目标专用错误,而不会关闭ASR会话:
{
"type": "translation.error",
"code": "source_language_unknown",
"message": "Cannot translate ASR final result before source language is known",
"utterance_id": "utt_0001",
"source_result_id": "utt_0001:final",
"target_lang": "en"
}
其他常见代码包括same_source_target_lang、translation_access_denied、translation_service_unavailable、translation_rate_limited、translation_rate_limiter_unavailable、translation_failed和source_text_too_long。空的最终文本不会被翻译,也不会发出翻译结果或翻译错误。
session.usage
用量是累积的。计费使用最新的事件。billable_duration 以整秒为单位:
{
"type": "session.usage",
"session_id": "asr_sess_...",
"seq": 20,
"final": true,
"usage": {
"input_duration": 18.3036875,
"billable_duration": 19,
"utterance_count": 3,
"final_result_count": 3,
"status": "completed",
"final": true
}
}
error
{
"type": "error",
"code": "finalization_failed",
"message": "Finalization failed",
"fatal": false,
"session_id": "asr_sess_...",
"seq": 18,
"utterance_id": "utt_0002"
}
致命(fatal)错误之后会关闭连接。非致命的话语错误则允许会话继续。
处理转录结果
- 以
utterance_id为键保存临时文本。 - 当更新的
asr.partial_result到达时,替换当前的部分结果。 - 收到
asr.final_result时,移除replaces中的 ID 并提交最终文本。 - 通过
source_result_id关联译文,不要假设目标语言结果的到达顺序。 - 显示时忽略空的最终文本(但保留用于诊断)。
- 切勿将
session.usage渲染为转录文本。
后续步骤
- 使用批量 ASR 端点转录完整文件。
- 在音频与语言中查阅支持的格式和语言。
- 在定价中了解用量如何计费。