ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

TEN Framework Soniox 实时语音识别 WebSocket API 深度指南:soniox_asr_python 扩展的协议解析与源码实现

TEN Framework Soniox 实时语音识别 WebSocket API 深度指南:soniox_asr_python 扩展的协议解析与源码实现 TEN Framework Soniox 实时语音识别 WebSocket API 深度指南soniox_asr_python 扩展的协议解析与源码实现【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址: https://gitcode.com/TEN-framework/ten-frameworkSoniox 实时语音识别ASR服务通过 WebSocket 提供流式转写能力而 TEN Framework 的soniox_asr_python扩展则将该协议封装为标准 ASR 接口可直接接入对话式语音 Agent 的图Graph编排。本文以 API_REFERENCE.md 为骨架完整讲解 Soniox WebSocket API 的认证配置、音频流式传输、finalize、KeepAlive 与各类响应格式并结合扩展源码extension.py、websocket.py、config.py揭示每个协议字段在框架内的默认值、解析逻辑与容错机制。读完本文你将能够独立编写兼容 Soniox WebSocket API 的客户端或深入定制 TEN Framework 中的 ASR 扩展行为。一、会话建立认证与配置消息在发送任何音频数据之前客户端必须先向服务器发送一条 JSON 配置消息完成身份认证与会话参数设定。API 参考文档给出的完整示例为{ api_key: SONIOX_API_KEY|SONIOX_TEMPORARY_API_KEY, model: stt-rt-preview, audio_format: auto, num_channels: 1, sample_rate: 16000, language_hints: [zh, en], context: , enable_speaker_diarization: false, enable_language_identification: false, enable_non_final_tokens: true, max_non_final_tokens_duration_ms: 360, enable_endpoint_detection: false, holding_mode: false, client_reference_id: }其中api_key、model、audio_format为必填项其余均为可选。api_key既可以是常规的 Soniox API Key也可以是临时 API KeySONIOX_TEMPORARY_API_KEYaudio_format取值auto表示由服务端自动探测编码TEN 扩展层则显式指定为pcm_s16le见下文源码分析。各字段含义如下表字段必填说明api_key是Soniox API Key 或临时 API Key用于身份认证model是ASR 模型标识如stt-rt-preview、stt-rt-v4audio_format是音频编码格式auto表示自动探测num_channels否声道数示例为 1单声道sample_rate否采样率Hz示例为 16000language_hints否语言提示列表如[zh, en]用于提示识别语言context否上下文提示文本可为空字符串enable_speaker_diarization否是否启用说话人分离enable_language_identification否是否启用语言识别enable_non_final_tokens否是否返回非最终partialtokenmax_non_final_tokens_duration_ms否非最终 token 的最大累积时长毫秒示例为 360enable_endpoint_detection否是否启用端点检测endpointingholding_mode否缓冲/持有模式取值见下文client_reference_id否客户端自定义的会话引用 ID可用于追踪holding_mode取值较为特殊文档明确说明其可选值为false、finalize、endpointing_only其中false表示不做持有、实时输出finalize表示持有至会话 finalize 后统一刷新endpointing_only表示按端点endpoint切分分段使用该模式时必须同时开启enable_endpoint_detection: true否则分段边界无法按端点对齐。在 TEN Framework 的soniox_asr_python扩展中holding_mode还额外支持sentence_terminator模式详见本文第七节这是扩展层对原生协议的增强。二、音频流式传输配置消息发送成功后即可开始流式传输音频。Soniox WebSocket API 支持两种音频发送方式二进制 WebSocket 帧推荐直接发送原始音频字节传输效率最高是首选方式Base64 编码文本消息在不支持二进制帧的客户端环境中将音频数据 Base64 编码后以文本消息发送。每个流的最大持续时长为 65 分钟超出后服务端会断开连接因此长会话需要自行规划分段或重连策略。从 websocket.py 的源码可以看到扩展通过SonioxWebsocketClient.send_audio()将AudioFrame的原始字节放入异步发送队列并记录发送字节数以维护音频时间线async def send_audio(self, audio: bytes): if self.enable_keepalive: self._last_audio_time time.time() await self._send_queue.put(audio)对应扩展层 extension.py 中send_audio()的实现会先按sample_rate计算该帧音频时长并累加到audio_timeline随后才转发给 WebSocket 客户端self.audio_timeline.add_user_audio( int(len(buf) / (self.config.sample_rate / 1000 * 2)) ) await self.websocket.send_audio(bytes(buf))扩展默认按 16 kHz、单声道、16-bit2 字节采样宽度的 PCM 数据输入见input_audio_sample_rate()返回 16000、input_audio_channels()返回 1、input_audio_sample_width()返回 2这与配置消息中的sample_rate: 16000、num_channels: 1严格对应。三、结束会话流要优雅地结束一次转写会话只需发送一个空的 WebSocket 消息空的二进制帧或文本帧均可。服务端收到后会返回剩余的全部最终结果随后发送一条完成消息finished响应见第五节最后关闭连接。在扩展源码中SonioxWebsocketClient.stop()正是通过向发送队列放入空字符串来触发这一流程并等待_stop_event最多 5 秒超时确认服务端完成关闭async def stop(self, wait: bool True): self.state self.State.STOPPING if self.enable_keepalive: self._stop_keepalive_task() await self._send_queue.put() if wait: try: await asyncio.wait_for(self._stop_event.wait(), timeout5.0) ...四、手动 finalize立即固化已收到的音频在某些场景下例如用户说完一句话、需要立即拿到确定结果时不必关闭整个会话而是发送一条特殊消息触发手动最终化manual finalize{type: finalize}Soniox 会将该时刻之前收到的所有音频一次性最终化与之关联的所有 token 都会以is_final: true返回。最终化完成后模型会返回一个特殊 token 作为操作结束标记{ text: fin, is_final: true }fintoken 的出现即表示本次 finalize 操作完成。扩展层的SonioxWebsocketClient.finalize()在原生协议之上还支持附加trailing_silence_ms参数尾随静音时长用于降低最终化延迟async def finalize(self, trailing_silence_ms: int | None None, ...): q: dict[str, Any] {type: finalize} if trailing_silence_ms is not None: q[trailing_silence_ms] trailing_silence_ms message json.dumps(q) ...这个trailing_silence_ms来自上游传入asr_finalizeData 消息中的silence_duration_ms属性extension.py 的on_data()方法。此外扩展的_real_finalize()还支持在 finalize 前主动发送一段静音包default_finalize_send_silence/default_finalize_silence_duration_ms默认 800 ms并在开启音频转储轮转dump_rotate_on_finalize时于发送 finalize 消息前执行转储文件轮转回调。五、KeepAlive保持连接存活当长时间没有音频数据时为避免连接被服务端回收需要发送心跳消息{type: keepalive}API 参考文档要求当没有音频数据时该消息应每 20 秒发送一次可以更频繁。发送任何音频本身也相当于活跃信号因此只有在静默期才需要心跳。扩展的 websocket.py 将这一机制实现为后台任务_keepalive_loop它每秒检查一次距上次音频发送的间隔超过keepalive_interval扩展默认15 秒比协议建议的 20 秒更保守即自动向队列投递一条{type: keepalive}消息并重置计时if time_since_last_audio self.keepalive_interval: keepalive_message json.dumps({type: keepalive}) await self._send_queue.put(keepalive_message) self._last_audio_time current_time该行为由配置项enable_keepalive默认true控制扩展在创建 WebSocket 客户端时传入见 extension.py 的_start_websocket()。因此接入 TEN Framework 时无需自行维护心跳。六、响应格式token 结构与时间统计Soniox 会以 JSON 形式持续返回转写结果。一次成功的转写响应遵循如下结构{ tokens: [ { text: Hello, start_ms: 600, end_ms: 760, confidence: 0.97, is_final: true, speaker: 1, language: en } ], final_audio_proc_ms: 760, total_audio_proc_ms: 880 }响应字段说明字段说明tokens[].text识别出的文本片段tokens[].start_ms该 token 在音频流中的起始时间毫秒tokens[].end_ms该 token 的结束时间毫秒tokens[].confidence置信度0~1如 0.97tokens[].is_final是否为最终结果false表示尚未确定的中间结果tokens[].speaker说话人标识启用说话人分离时返回tokens[].languagetoken 所属语言final_audio_proc_ms已最终化音频的处理时长毫秒total_audio_proc_ms全部音频的处理时长毫秒在扩展中服务端返回的每条响应由_handle_recv()按模式匹配分发websocket.py含error_code/error_message的消息 → 触发ERROR事件含finished: true的消息 → 触发FINISHED事件并置位停止事件含tokens字段的消息 → 触发TRANSCRIPT事件并将原始 token 解析为强类型对象。_parse_token()会将原始 token 按内容分类为四种类型普通转写 tokenSonioxTranscriptToken、翻译 tokenSonioxTranslationToken含translation_status、source_language等字段、fin标记SonioxFinToken与end标记SonioxEndToken。随后 extension.py 的_handle_transcript()会按最终 token 在前、非最终 token 在后、翻译 token 跟随对应转写 token的规律分组将转写结果映射为标准asr_result数据结构见 README.md并通过Data消息asr_results发布到图Graph下游实现与 TEN Framework 标准 ASR 接口的兼容。七、会话完成finished 响应在流结束客户端发送空消息时Soniox 会发送一条表示会话完成的最终消息{ tokens: [], final_audio_proc_ms: 1560, total_audio_proc_ms: 1680, finished: true }此时tokens为空数组finished字段为true随后服务端会关闭 WebSocket 连接。扩展在收到该消息后触发FINISHED事件_handle_finished()记录final_audio_proc_ms与total_audio_proc_ms并置位_stop_event使stop()正常返回。八、错误响应HTTP 错误码与连接关闭如果发生错误服务端会发送如下错误响应并立即关闭连接{ tokens: [], error_code: 503, error_message: Service is currently overloaded. Please retry your request... }其中error_code是标准 HTTP 状态码。扩展对该错误做了细致的分级容错extension.py 中的SonioxASRErrorFilterNON_FATAL_400_PHRASES (No audio received, Audio is too long) classmethod def get_module_error_code(cls, error_code: int, error_message: str) - int: if error_code 400 and any( phrase in error_message for phrase in cls.NON_FATAL_400_PHRASES ): return ModuleErrorCode.NON_FATAL_ERROR.value if error_code in (400, 401, 402): return ModuleErrorCode.FATAL_ERROR.value return ModuleErrorCode.NON_FATAL_ERROR.value即400 错误中未收到音频、音频过长两类视为非致命错误可继续/重试400、401、402 其余情况视为致命错误其余错误码如 503 过载一律归为非致命错误交由上层决定是否重试。错误会通过send_asr_error()以标准ModuleError形式上报同时携带供应商信息vendor、code、message。连接意外关闭时扩展通过 reconnect_manager.py 的ReconnectManager执行指数退避重连基础延迟 0.5 秒、最大延迟 4.0 秒每次失败后延迟翻倍min(base_delay * 2^(attempts-1), max_delay)连接成功后重置尝试计数。九、协议在扩展层的关键映射与配置默认值将原生 Soniox WebSocket API 接入 TEN Framework 时config.py 中的SonioxASRConfig定义了扩展级配置其中协议相关参数在update()中设置了默认值参数默认值说明urlwss://stt-rt.soniox.com/transcribe-websocketSoniox WebSocket 端点modelstt-rt-previewASR 模型audio_formatpcm_s16lePCM 有符号 16 位小端num_channels1单声道sample_rate1600016 kHzenable_language_identificationtrue默认开启语言识别max_non_final_tokens_duration_ms360非最终 token 最大时长enable_keepalivetrue自动心跳15 秒间隔holding_modefalse默认不持有结果实时输出一个典型的测试配置tests/configs/property_en.json如下api_key支持${env:SONIOX_ASR_API_KEY}环境变量注入{ params: { api_key: ${env:SONIOX_ASR_API_KEY}, url: wss://stt-rt.soniox.com/transcribe-websocket, model: stt-rt-v4, language_hints: [en], sample_rate: 16000 } }holding_mode 的扩展增强除协议原生三种取值外扩展还支持sentence_terminator模式README.md它持有供应商返回的is_final分段直到通过pySBD英文句号与缩写叠加本地强终止符簇。……、!!!、...等检测到完整句边界后才输出逗号不作为句末。该逻辑实现在 text_utils.py 的SentenceBoundaryDetector中仅对中英文生效且会优先合并尾部纯标点 token 再判断边界。会话结束时收到fin前若仍有未达句边界的延迟 token扩展会在_finalize_end()中强制以is_final: true刷新输出避免结果丢失。需要特别注意的是enable_endpoint_detection未包含在 TEN Framework 标准 ASR 接口中见 README 说明因此在图编排中无法通过标准接口直接下发该参数若要在扩展层使用endpointing_only模式需在属性配置中显式提供enable_endpoint_detection: true否则_effective_holding_mode()会自动回退为false。finalize 触发方式扩展在收到名为asr_finalize的Data消息时触发最终化见 extension.py 的on_data()其行为由finalize_mode控制共四种取值default发送 finalize 消息可选附尾随静音、mute_pkg发送静音包代替 finalize 消息、close关闭连接触发最终化之后按finalize_reconnect_mode决定立即重连或等到有音频再重连、ignore忽略 finalize 请求依赖端点检测自动切分。对应的端到端流程可参考测试用例 tests/test_finalize.py它模拟了先发送 5 帧音频、再发送asr_finalizeData 消息的完整交互可用于验证最终化路径的正确性。语言代码映射协议中language_hints与返回 token 的language字段使用 ISO 语言代码而 Soniox 内部使用zh-CN、en-US这类区域化代码。const.py 中的LANGUAGE_CODE_MAPPING维护了 60 余种语言的映射如zh → zh-CN、en → en-US、ja → ja-JPmap_language_code()负责双向对齐未支持的代码则原样透传。十、小结Soniox WebSocket API 的整体交互流程可归纳为发送配置消息建立会话 → 流式发送音频二进制优先→ 可选发送 finalize/keepalive 控制消息 → 空消息结束会话 → 处理 finished 完成响应。TEN Framework 的soniox_asr_python扩展版本 0.6.0见 manifest.json依赖ten_runtime_python0.11 与ten_ai_base0.7已将这套协议完整封装自动心跳、指数退避重连、错误分级、语言映射、holding/finalize 策略以及标准asr_result/asr_translation_result输出使得在语音 Agent 图中接入 Soniox 实时转写时开发者只需关注property.json中的参数配置即可。对于需要深度定制的场景可直接阅读 extension.py 与 websocket.py 理解协议解析与状态机细节再配合 tests 目录下的测试用例进行验证。【免费下载链接】ten-frameworkOpen-source framework for conversational voice AI agents项目地址: https://gitcode.com/TEN-framework/ten-framework创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表