除了基于 WebRTC 的实时通信方案外,扣子编程智能语音还推出了 WebSocket OpenAPI 方案,用于实现用户与智能体之间的实时语音通话。该方案通过 WebSocket 协议提供高效、灵活的语音交互能力,适用于多种应用场景。
WebSocket OpenAPI 支持的音频编码格式如下:
在开始集成 WebSocket OpenAPI 之前,你需要先完成以下准备工作。
|
操作 |
说明 |
|---|---|
|
发布智能体 |
已成功搭建并发布智能体为 API 服务。搭建步骤可参考搭建低延时语音助手,发布步骤请参见发布为 API 服务。 |
|
获取访问密钥 |
获取访问密钥,用于身份认证与鉴权。
说明 扣子编程 SDK 封装了多种鉴权方式,能够有效简化鉴权流程,你可以参考鉴权示例代码实现不同方式的 OAuth 认证,以获取和管理访问扣子编程 API 所需的令牌。 |
你可以通过扣子编程 Python SDK 示例代码快速了解调用智能语音 WebSocket OpenAPI 实现语音通话的整体流程,包括语音输入、语音输出以及聊天对话等。
此外,参考 websockets_chat_realtime_gui.py 文件,你可以快速实现包含图形化界面的智能语音应用。通过 WebSocket 与扣子编程 API 通信,快速体验智能语音的 Demo 效果。
发起 HTTP 请求时,在请求头(Header)中添加Authorization信息。Authorization的取值固定为Bearer $Access_Token,用于扣子编程 OpenAPI 鉴权的访问密钥。将您在准备工作中获取的访问密钥替换掉 $Access_Token 后再发起请求。
说明
浏览器不支持在 WebSocket 连接中设置 Header。如果需要通过浏览器发起 WebSocket 建连请求,可以将Authorization 参数放到 URL 的查询参数中。例如,与语音识别 API 建立连接的 URL 格式如下:
wss://ws.coze.cn/v1/audio/transcriptions?authorization=Bearer xxx
以下是建立 WebSocket 连接的示例代码:
本文以双向流式语音对话为例,语音识别和语音合成的 WebSocket 连接建立方式相同,只需要将示例代码中的 url 路径替换为对应的 API 路径即可,语音识别和语音合成的示例代码请参见双向流式语音识别和双向流式语音合成。
import WebSocket from 'ws';
# 双向流式语音对话
const url = `wss://ws.coze.cn/v1/chat?bot_id=73791654286875***&authorization=Bearer pat_OYDacMzM3WyOWV3Dtj2bHRMymzxP****`;
# 如果是语音识别,需要将 url替换为如下地址
# url = `wss://ws.coze.cn/v1/audio/transcriptions?authorization=Bearer pat_OYDacMzM3WyOWV3Dtj2bHRMymzxP****`
const ws = new WebSocket(url);
ws.on('open', function open() {
console.log('Connected to server.');
});
ws.on('message', function incoming(message) {
console.log(JSON.parse(message.toString()));
});
# example requires websocket-client library:
# pip install websocket-client
import os
import json
import websocket
ACCESS_TOKEN = os.environ.get("ACCESS_TOKEN")
# 流式语音对话
url = "wss://ws.coze.cn/v1/chat?bot_id=73791654286875***"
# 如果是语音识别,需要将 url替换为如下地址
# url = "wss://ws.coze.cn/v1/audio/transcriptions"
headers = [
"Authorization: Bearer " + ACCESS_TOKEN
]
def on_open(ws):
print("Connected to server.")
def on_message(ws, message):
data = json.loads(message)
print("Received event:", json.dumps(data, indent=2))
ws = websocket.WebSocketApp(
url,
header=headers,
on_open=on_open,
on_message=on_message,
)
ws.run_forever()
# 双向流式语音对话
const url = `wss://ws.coze.cn/v1/chat?bot_id=73791654286875***&authorization=Bearer pat_OYDacMzM3WyOWV3Dtj2bHRMymzxP****`;
# 如果是语音识别,需要将 url 替换为如下地址
# url = `wss://ws.coze.cn/v1/audio/transcriptions?authorization=Bearer pat_OYDacMzM3WyOWV3Dtj2bHRMymzxP****`;
const ws = new WebSocket(url);
ws.addEventListener('open', function () {
console.log('Connected to server.');
});
ws.addEventListener('message', function (message) {
console.log(JSON.parse(message.data.toString()));
});
通过 WebSocket 与扣子编程智能体进行实时语音交互时,需要通过 WebSocket 接口发送和接收消息。成功连接后,客户端可以发送和接收代表文本、音频、配置更新等的事件。客户端可以发送的事件消息以及从服务器接收的事件消息列表请参见双向流式语音识别事件、双向流式语音合成事件和双向流式对话上行事件。
发送和接收事件的示例代码如下:
# To send a client event, serialize a dictionary to JSON
# of the proper event type
def on_open(ws):
print("Connected to server.")
data = {
"role": "user",
"content_type": "text",
"content": "你好呀"
}
event = {
"event_type": "conversation.message.create",
"data": data
}
ws.send(json.dumps(event))
# Receiving messages will require parsing message payloads
# from JSON
def on_message(ws, message):
data = json.loads(message)
print("Received event:", json.dumps(data, indent=2))
扣子编程提供流式语音识别 WebSocket OpenAPI,可以将指定的音频判断转为文字,支持识别中英文双语种。详细的接口信息请参见双向流式语音识别,相关的事件详细信息请参见双向流式语音识别事件。
扣子编程提供流式语音合成 WebSocket OpenAPI,可以将文字信息转为指定音色的语音片段。详细的接口信息请参见双向流式语音合成,相关事件详细信息请参见双向流式语音合成事件。
扣子编程提供流式语音对话 WebSocket OpenAPI,向指定的智能体发起语音对话。详细的接口信息请参见双向流式语音对话,相关事件详细信息请参见双向流式对话上行事件。
使用扣子编程提供的 WebSocket OpenAPI,你可以实现双向流式语音识别、双向流式语音合成和双向流式语音对话。每个场景中的配置均通过上行事件完成,配置成功后服务端会返回下行事件通知配置结果。通过 WebSocket 事件,你可以使用 WebSocket 协议实现智能语音对话的各种典型场景。
智能语音 WebSocket 事件包括上行事件和下行事件。每个事件有 ID 和 EventType,通过 EventType 可以区分具体的事件类型,每个事件类型对应的 Payload 在 Data 中,开发者可以按需去提取需要的内容。
智能语音 WebSocket 事件的公共参数如下:
|
参数名称 |
类型 |
描述 |
|---|---|---|
|
id |
String |
事件 ID,也就是事件的唯一标识。由客户端或服务端生成,在故障排查场景下用于定位具体的事件,便于排查问题。 |
|
event_type |
String |
事件的类型。 |
|
data |
JSON |
事件的详细信息,其中包含具体事件的业务字段。 |
问题排查
借助抓包工具来分析通信过程中的数据包。以下是详细的排查步骤:
如果未收到 Server Hello 包,从以下几个方面检查 Client Hello 包是否有问题:
|
排查项 |
说明 |
|---|---|
|
检查 Cipher Suites |
检查 Client Hello 包中的 Cipher Suites 是否全部为扣子编程不支持的加密套件。扣子编程支持 TLS1.2 和 TLS1.3 版本,但出于安全考虑,加密套件不支持以下几种:
|
|
检查 Random 中的时间戳 |
时间戳相差过大可能会影响握手过程。客户端需确保其系统时间准确,与服务器时间偏差在合理范围内。若客户端系统时间设置错误,如相差数小时甚至更久,可能导致服务器认为客户端发送的 Client Hello 包无效,从而不返回 Server Hello 包。建议客户端定期同步系统时间,可使用网络时间协议(NTP)等工具来校准时间。 |
|
检查 Extension 中的 server_name(SNI) |
Client Hello 包的 Extension 中必须带有 server_name(SNI)。若缺失 SNI 扩展,服务器可能无法正确识别客户端请求的目标虚拟主机,进而拒绝握手。客户端需检查其 SSL/TLS 配置,确保在发起握手时正确设置了 SNI 扩展,明确指定目标服务器的域名。 |
|
检查 Extension 中的 signature_algorithms |
signature_algorithms 扩展是 SSL/TLS 握手过程中用于协商签名算法的关键部分。若该扩展缺失或不正确,可能导致服务器无法与客户端协商出合适的签名算法,从而使握手失败。客户端需确保其支持的签名算法与扣子编程要求一致,并正确在 Client Hello 包中携带 signature_algorithms 扩展。 |
|
检查 TLS1.3 相关扩展 |
若使用的是 TLS1.3,Client Hello 包的 Extension 中还需带有 supported_groups 和 key_share 扩展。supported_groups 扩展用于协商支持的椭圆曲线群组,key_share 扩展则用于携带客户端的密钥共享信息。若缺少这些扩展,TLS1.3 握手将无法正常进行。 |
如果已收到 Server Hello 包,说明 SSL/TLS 握手已初步成功。请执行下一步检查 HTTP 包。
Authorization: {Access_Token} 字段。若缺失该字段或字段值错误,服务器可能因无法验证客户端身份而拒绝处理请求。正确示例:authorization=Bearer pat_OYDacMzM3WyOWV3Dtj2bHRMymzxP****。可能原因
在 WebSocket 通信过程中,若出现连接关闭的情况,可能是由以下原因导致的:
ping 帧给客户端,若客户端连续四次未响应该 ping 帧,即未返回 pong 帧,扣子编程会认为客户端已下线,从而关闭 WebSocket 连接。error 事件。WebSocket: close 100x(err msg)等错误情况。这些情况可能表明客户端在数据接收过程中存在解析错误或网络传输问题。客户端需仔细检查 WebSocket 数据接收逻辑,确保正确处理各种帧类型(如文本帧、二进制帧等),同时合理设置数据读取超时时间,避免因超时导致连接异常关闭。问题排查
ping 帧。确保客户端能够及时接收并返回 pong 帧,以维持连接的活跃状态。error 事件的处理逻辑。error 事件后不能立即关闭连接。当收到 error 事件时,客户端需要查看 error 事件中具体的错误描述,例如:若建立连接时 AccessToken 无效,扣子编程会返回authentication is invalid错误。根据错误描述,客户端应采取相应的措施,如提示用户、记录日志或重新尝试连接等。