本文档介绍如何通过 AI 加速网关,使用有状态、基于事件的 Realtime API 来调用您自部署的语音识别(ASR)模型。
Realtime API 通过 WebSocket 协议进行通信,适用于需要低延迟、实时流式传输的场景。它允许客户端与服务端建立持久连接,并在此连接上进行双向的事件驱动通信,从而实现语音识别。
与 Realtime API 建立 WebSocket 连接时,需要指定以下参数:
wss://$BASE_URL/realtime?intent=transcription&model=$MODEL_NAMEAuthorization: Bearer $AI_GATEWAY_API_KEY本节将引导您完成一次完整的 API 调用,从建立连接到接收合成的音频。
为网关实例绑定您的自部署 语音识别 模型。具体操作,请参见通过 AI 加速网关接入和调用自部署模型。
注意
自部署模型仅支持通过 OpenAI 兼容协议 方式调用。配置自部署模型时,必须提供 API Key。
在实例管理页面,单击实例名称进入实例详情,从实例详情中获取以下信息:
$BASE_URL)$AI_GATEWAY_API_KEY)$MODEL_NAME)创建一个名为 requirements.txt 的文件,并填入以下依赖:
numpy soundfile scipy websockets==12.0 openai
创建一个名为 ASR_client.py 的文件,并将以下示例代码粘贴进去。
说明
注意将代码中的 $BASE_URL、$MODEL_NAME 和 $AI_GATEWAY_API_KEY 替换为实际值;将 <your_audio_file> 替换成输入音频文件的路径。可以使用以下音频文件进行测试:hello.wav
注意
以下示例代码仅用于测试,请勿用于生产环境。
# prerequisites # pip install websockets==12.0 numpy soundfile scipy import asyncio import base64 import json import numpy as np import soundfile as sf from scipy.signal import resample import websockets SAMPLE_RATE = 16000 # your_sample_rate def resample_audio(audio_data, original_sample_rate, target_sample_rate): number_of_samples = round(len(audio_data) * float(target_sample_rate) / original_sample_rate) resampled_audio = resample(audio_data, number_of_samples) return resampled_audio.astype(np.int16) async def send_audio(client, audio_file_path: str): duration_ms = 100 samples_per_chunk = SAMPLE_RATE * (duration_ms / 1000) bytes_per_sample = 2 bytes_per_chunk = int(samples_per_chunk * bytes_per_sample) extra_params = {} if audio_file_path.endswith(".raw"): extra_params = { "samplerate": SAMPLE_RATE, "channels": 1, "subtype": "PCM_16", } audio_data, original_sample_rate = sf.read(audio_file_path, dtype="int16", **extra_params) if original_sample_rate != SAMPLE_RATE: audio_data = resample_audio(audio_data, original_sample_rate, SAMPLE_RATE) audio_bytes = audio_data.tobytes() for i in range(0, len(audio_bytes), bytes_per_chunk): await asyncio.sleep((duration_ms - 20) / 1000) chunk = audio_bytes[i: i + bytes_per_chunk] base64_audio = base64.b64encode(chunk).decode("utf-8") append_event = { "type": "input_audio_buffer.append", "audio": base64_audio } await client.send(json.dumps(append_event)) print("send complete") commit_event = { "type": "input_audio_buffer.commit" } await client.send(json.dumps(commit_event)) async def receive_messages(client): while not client.closed: message = await client.recv() print(message) event = json.loads(message) if event.get("type") == "conversation.item.input_audio_transcription.completed": return def get_session_update_msg(): config = { "input_audio_format": "pcm", "input_audio_sample_rate": SAMPLE_RATE, "input_audio_bits": 16, "input_audio_channel": 1, "result_type": 0, "turn_detection": { "type": "server_vad", "threshold": 0.5, "prefix_padding_ms": 300, "silence_duration_ms": 300, } } event = { "type": "transcription_session.update", "session": config } return json.dumps(event) async def with_openai(audio_file_path: str): key = "$AI_GATEWAY_API_KEY" ws_url = "wss://$BASE_URL/realtime?intent=transcription&model=$MODEL_NAME" headers = { "Authorization": f"Bearer {key}", } async with websockets.connect(ws_url, ping_interval=None, extra_headers=headers) as client: session_msg = get_session_update_msg() await client.send(session_msg) await asyncio.gather(send_audio(client, audio_file_path), receive_messages(client)) if __name__ == "__main__": file_path = "<your_audio_file>" asyncio.run(with_openai(file_path))
打开终端,运行以下命令安装所需的 Python 库:
pip install -r requirements.txt
执行脚本:
python3 ASR_client.py
运行成功后,您将在终端看到详细的日志输出,包括连接状态、发送的事件以及从服务端接收到的识别结果。
Realtime API 的交互是基于事件的。客户端和服务端通过交换一系列 JSON 格式的事件来完成一次完整的语音识别任务。
事件类型 | 事件名 | 说明 |
|---|---|---|
客户端 | 会话初始化 - | 在连接建立后发送,用于配置 ASR 会话参数。 |
语音上报 - | 将 Base64 编码的音频数据块发送到服务端。 | |
上报完成 - | 通知服务端,客户端已完成当前轮次的音频数据发送。 | |
服务端 | 配置确认 - | 确认服务端的会话配置已更新。 |
增量结果输出 - | 实时返回识别过程中的增量结果。 | |
全量结果输出 - | 实时返回识别过程中的全量结果。 | |
完整结果输出 - | 返回当前轮次音频的最终、完整识别结果。 |
transcription_session.update客户端在建立连接后,必须首先发送此事件来配置 ASR 会话。它定义了音频输入的格式、期望的返回结果类型以及语音活动检测(VAD)等行为。
参数:
session (object)
input_audio_format (string)
音频格式。例如: pcm。
input_audio_codec (string)
音频编码。例如: raw。
input_audio_sample_rate (integer)
音频采样率(Hz)。例如: 16000。
input_audio_bits (integer)
采样位深。例如: 16。
input_audio_channel (integer)
音频通道数。例如: 1。
result_type (integer)
ASR 结果的输出模式。0 表示全量输出(.result 事件),1 表示增量输出(.delta 事件)。默认值为 0。
说明
result_type 设置为 0,网关将透传模型识别结果。result_type 设置为 0 时,网关会将增量结果聚合成全量返回。result_type 设置为 1 时,网关将透传模型识别结果。turn_detection (object)
语音活动检测(VAD)配置,用于判断一句话的结束。
type (string)server_vad_text_mode:由网关根据 ASR 模型返回结果的间隔来判断语音结束。
"turn_detection": { "type": "server_vad_text_mode", "text_interval": 300 //判断识别结束的时间间隔(单位ms) }
server_vad:由 ASR 模型自身进行 VAD 处理。如果不传递 ASR 相关参数或者参数值为 null,那么网关会传递默认值。默认值示例如下。
注意
如果 ASR 模型不支持 VAD。请勿选择该方式,否则会返回错误。
"turn_detection": { "type": "server_vad", "threshold": 0.5, "prefix_padding_ms": 300, "silence_duration_ms": 500 }
priority_order_mode:客户端上报多种 VAD 模式,由网关决定采取哪种模式(使用的模式通过 transcription_session.updated 事件返回)。
"turn_detection": { "type": "priority_order_mode", "modes": [ { "type": "server_vad", "threshold": 0.5, "prefix_padding_ms": 300, "silence_duration_ms": 500 }, { "type": "server_vad_text_mode", "text_interval": 300 } ] }
如果此字段为 null,则表示由客户端控制语音结束(通过发送 input_audio_buffer.commit 事件)。
示例:
{ "type": "transcription_session.update", "session": { "input_audio_format": "pcm", "input_audio_codec": "raw", "input_audio_sample_rate": 16000, "input_audio_bits": 16, "input_audio_channel": 1, "result_type": 0, "extra_data": {}, "turn_detection": { "type": "server_vad_text_mode", "text_interval": 300 } } }
input_audio_buffer.append用于将音频数据块流式传输到服务端。音频数据需要经过 Base64 编码。
参数:
audio (string)示例:
{ "event_id": "event_wQp5vyn4VloVTOcrQS6bo", "type": "input_audio_buffer.append", "item_id": "item_ezC2f0aiYLtsTILllMIXe", "audio": "xxxxxx" }
input_audio_buffer.commit当客户端 VAD 判断一句话结束后,发送此事件通知服务端当前轮次的音频已全部发送完毕。服务端在收到此事件后,会开始处理并返回最终识别结果。如果 VAD 由服务端处理,则客户端无需发送此事件。
参数:无
示例:
{ "event_id": "event_wQp5vyn4VloVTOcrQS6bo", "type": "input_audio_buffer.commit", "item_id": "item_ezC2f0aiYLtsTILllMIXe" }
transcription_session.updated服务端在收到客户端的 transcription_session.update 请求后,会返回此事件,以确认会话配置已成功应用。事件内容将包含当前生效的完整会话配置。
参数:
session (object)session 对象类似。示例:
{ "event_id": "event_5678", "type": "transcription_session.updated", "session": { "id": "sess_001", "object": "realtime.transcription_session", "input_audio_format": "pcm", "input_audio_codec": "raw", "input_audio_sample_rate": 16000, "input_audio_bits": 16, "input_audio_channel": 1, "result_type": 0, "turn_detection": { "type": "server_vad_text_mode", "text_interval": 300 } } }
conversation.item.input_audio_transcription.delta如果 result_type 配置为 1(增量输出),服务端会通过此事件实时返回识别过程中的增量文本结果。
说明
适用于采用增量输出模式的模型。
参数:
delta (string)start (float)end (float)示例:
{ "type": "conversation.item.input_audio_transcription.delta", "event_id": "event_001", "item_id": "item_001", "content_index": 0, "delta": "Hello", "start": 0.0, "end": 3.319999933242798 }
conversation.item.input_audio_transcription.result如果 result_type 配置为 0(全量输出),服务端会通过此事件实时返回当前已识别到的完整语句。每次返回的都是当前句子的全量内容。
说明
适用于采用实时输出全量结果的模型,如方舟大模型语音识别。
参数:
transcript (string)words (array)示例:
{ "type": "conversation.item.input_audio_transcription.result", "event_id": "event_001", "item_id": "item_001", "transcript": "Hello, how?", "words": [ { "start": 0.0, "end": 1.319999933242798, "word": "Hello" }, ... ] }
{ "type": "conversation.item.input_audio_transcription.result", "event_id": "event_002", "item_id": "item_001", "transcript": "Hello, how are you?", "words": [ { "start": 0.0, "end": 1.319999933242798, "word": "Hello" }, ... ] }
conversation.item.input_audio_transcription.completed在服务端判断一句话识别结束后(通过 VAD 或收到 commit 事件),会发送此事件,标志着一轮识别任务的完成。该事件包含最终的、最准确的识别结果。
参数:
transcript (string)words (array)示例:
{ "event_id": "event_2122", "type": "conversation.item.input_audio_transcription.completed", "item_id": "msg_003", "transcript": "Hello, how are you?", "words": [ { "start": 0.0, "end": 1.319999933242798, "word": "Hello" }, ... ] }