第一个请求示例:与实时数字人对话
📖第一个请求示例:与实时数字人对话
NavTalk 提供基于 WebSocket + WebRTC 的实时数字人能力,支持语音识别Function Calling 和视频口型同步。下面是完整的接入流程与关键代码说明。
整体流程
建立 WebSocket 连接(带 license + characterName)
配置会话参数(voice、音频格式、上下文等)
获取浏览器麦克风音频并转为 PCM,发送音频流到服务端
接收服务端响应(文本、音频、Function Call)
通过 WebRTC 获取实时视频展示数字人形象
🔹 Step 1:建立 WebSocket 实时语音连接
你需要通过我们颁发的 license 创建 WebSocket 连接,并传入 characterName
以选择数字人形象。
const license = "YOUR_LICENSE_KEY";
const characterName = "girl2";
const socket = new WebSocket(`wss://api.navtalk.ai/api/realtime-api?license=${encodeURIComponent(license)}&characterName=${characterName}`);
socket.binaryType = 'arraybuffer';
socket.onopen = () => {
console.log("WebSocket 连接成功");
};
socket.onmessage = (event) => {
if (typeof event.data === 'string') {
const data = JSON.parse(event.data);
handleReceivedMessage(data); // 处理 JSON 消息
} else if (event.data instanceof ArrayBuffer) {
handleReceivedBinaryMessage(event.data); // 处理音频流
}
};
🔹 Step 2:配置会话参数(初始化)
在 session.created
返回后,发送 session.update
配置 AI 的行为风格、语言模型、音频参数、转录方式等。
const sessionConfig = {
type: "session.update",
session: {
instructions: "chat",
voice: "alloy",
temperature: 1,
max_response_output_tokens: 4096,
modalities: ["text", "audio"],
input_audio_format: "pcm16",
output_audio_format: "pcm16",
input_audio_transcription: {
model: "whisper-1"
}
}
};
socket.send(JSON.stringify(sessionConfig));
可扩展:tools 字段支持 Function Calling 自定义函数能力。
🔹 Step 3:获取用户语音并推送
通过浏览器访问麦克风,实时录制语音、转换为 PCM16 格式,并 base64 编码后发送至服务器。
navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
const audioContext = new AudioContext({ sampleRate: 24000 });
const source = audioContext.createMediaStreamSource(stream);
const processor = audioContext.createScriptProcessor(8192, 1, 1);
processor.onaudioprocess = (event) => {
const input = event.inputBuffer.getChannelData(0);
const buffer = floatTo16BitPCM(input);
const base64Audio = base64EncodeAudio(new Uint8Array(buffer));
// 分片发送音频块
const chunkSize = 4096;
for (let i = 0; i < base64Audio.length; i += chunkSize) {
const chunk = base64Audio.slice(i, i + chunkSize);
socket.send(JSON.stringify({ type: "input_audio_buffer.append", audio: chunk }));
}
};
source.connect(processor);
processor.connect(audioContext.destination);
});
🔹 Step 4:处理 AI 返回事件
平台会返回多个事件,主要包括:
session.created
会话创建成功,需立即发送配置
session.updated
可开始发送音频
response.audio_transcript.delta
实时返回语音识别文本
response.audio.delta
返回 AI 音频数据(播放)
response.function_call_arguments.done
触发函数调用
response.audio.done
一轮响应结束
示例:
function handleReceivedMessage(data) {
switch (data.type) {
case "session.created":
sendSessionUpdate();
break;
case "session.updated":
startRecording();
break;
case "response.audio_transcript.delta":
console.log("AI 说:", data.delta.text);
break;
case "response.audio.delta":
// 播放 data.delta 音频内容
break;
case "response.function_call_arguments.done":
handleFunctionCall(data);
break;
}
}
🔹 Step 5:建立 WebRTC 视频流连接(展示数字人)
WebRTC 是数字人实时表现力(唇形、表情、视线等)的载体,务必确保在建立 WebSocket 实时语音连接的同时,创建 WebRTC 视频通道。
你将需要:
一个绑定了视频的 HTML
<video>
标签一个专属的
license
(即 userId)一个目标
sessionId
(需由实时 WebSocket 会话关联)
1️⃣ 绑定视频元素
在你的 HTML 中预留一个用于显示数字人形象的 <video>
标签:
<video id="character-avatar-video" autoplay muted playsinline style="width: 320px; height: 400px;"></video>
autoplay
和playsinline
是移动端浏览器展示视频的关键属性
然后在 JavaScript 中绑定该元素:
const remoteVideo = document.getElementById('character-avatar-video');
2️⃣ 建立 WebRTC 信令连接
使用你的 license
创建 WebSocket 信令通道:
const remoteVideo = document.getElementById('character-avatar-video');
const resultSocket = new WebSocket(`wss://api.navtalk.ai/iwebrtc?userId=${license}`);
resultSocket.onopen = () => {
resultSocket.send(JSON.stringify({ type: 'create', targetSessionId: "123" }));
};
3️⃣ 接收 offer / answer / ICE 候选
服务端会依次返回:
offer(SDP 请求)
answer(SDP 应答)
iceCandidate(网络打洞地址)
处理这些消息如下:
resultSocket.onmessage = (event) => {
const message = JSON.parse(event.data);
switch (message.type) {
case "offer": handleOffer(message); break;
case "answer": handleAnswer(message); break;
case "iceCandidate": handleIceCandidate(message); break;
}
};
4️⃣ 创建 RTCPeerConnection 并播放视频
const configuration = { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] };
let peerConnectionA = null;
function handleOffer(message) {
const offer = new RTCSessionDescription(message.sdp);
peerConnectionA = new RTCPeerConnection(configuration);
// 设置远端 SDP
peerConnectionA.setRemoteDescription(offer)
.then(() => peerConnectionA.createAnswer())
.then(answer => peerConnectionA.setLocalDescription(answer))
.then(() => {
resultSocket.send(JSON.stringify({
type: 'answer',
targetSessionId: message.targetSessionId,
sdp: peerConnectionA.localDescription
}));
});
// 监听远端流
peerConnectionA.ontrack = (event) => {
console.log("接收到视频流");
remoteVideo.srcObject = event.streams[0];
remoteVideo.play();
};
// 收集 ICE 候选
peerConnectionA.onicecandidate = (event) => {
if (event.candidate) {
resultSocket.send(JSON.stringify({
type: 'iceCandidate',
targetSessionId: message.targetSessionId,
candidate: event.candidate
}));
}
};
}
5️⃣ 接收 ICE 反向通道
function handleIceCandidate(message) {
const candidate = new RTCIceCandidate(message.candidate);
if (peerConnectionA) {
peerConnectionA.addIceCandidate(candidate).catch(console.error);
}
}
🛠 常见问题与调试建议
没有返回语音
检查是否发送了 session.update
,音频格式是否正确
视频不显示
检查 WebRTC 连接是否成功,是否已绑定 video DOM
AI 不回应
是否配置了语音转文本模型、是否成功发送音频流
ICE failed
检查网络环境,尝试更换 STUN 服务器
📦 完整示例项目
我们建议使用官方 DEMO 项目快速验证连接是否成功:这是一个待补充的链接。示例支持录音、角色选择、视频渲染、Function Call 等全流程。
Last updated