如何搭建一个AI实时对话功能,可以模拟大模型对话结合TTS和ASR,集成腾讯ASR和TTS实现语音对话交互功能方案
创建 ScriptProcessorNode :用于处理音频数据,参数分别表示缓冲区大小、输入声道数、输出声道数。- 调用 float32ArrayToBase64Wav 将音频数据转换为Base64编码的WAV格式。- 创建 AudioContext 对象:这是Web Audio API的核心,用于处理音频操作。- 将转换后的音频数据通过 WebSocket通信 发送到服务器。- 设置采样率为1
如何搭建一个AI实时对话功能,可以模拟大模型对话结合TTS和ASR,集成腾讯ASR和TTS实现语音对话交互功能方案

一、当前实现分析
通过查看代码,我发现当前系统已经实现了以下功能:
- 使用WebRTC的getUserMedia获取音频流
- 通过AudioContext和脚本节点处理音频数据
- 使用WebSocket与后端进行实时通信
- 实现了音频录制、发送和播放功能
- 具备消息列表展示对话内容的UI
二、集成腾讯ASR和TTS的方案
1. 系统架构调整
需要在现有架构基础上增加与腾讯云服务的交互层:

2. 消息处理流程修改
修改后端消息处理逻辑:
- 接收前端发送的音频数据
- 调用腾讯云ASR服务进行语音识别
- 将识别结果发送给大模型(如有)
- 接收大模型返回的文本响应
- 调用腾讯云TTS服务将文本转换为音频
- 将音频数据发送回前端播放
3. 错误处理和优化
- 添加网络异常处理
- 实现音频数据缓存和重传机制
- 优化WebSocket连接稳定性
- 增加日志记录以便调试
三、实现方案
1、语音录制与发送逻辑
1. 初始化音频环境
this.play = true
this.audioCtx = new (window.AudioContext || window.webkitAudioContext)({ sampleRate: 16000 })
this.scriptNode = this.audioCtx.createScriptProcessor(4096, 1, 1)
- 创建 AudioContext 对象:这是Web Audio API的核心,用于处理音频操作
- 设置采样率为16000Hz:这是语音识别常用的采样率
- 创建 ScriptProcessorNode :用于处理音频数据,参数分别表示缓冲区大小、输入声道数、输出声道数
2. 获取用户媒体设备
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices
.getUserMedia({ audio: true, video: false })
.then((stream) => {
this.mediaStack = stream
this.source = this.audioCtx.createMediaStreamSource(stream)
this.source.connect(this.scriptNode)
this.scriptNode.connect(this.audioCtx.destination)
})
.catch(function (err) {
console.log('err', err)
})
} else if (navigator.webkitGetUserMedia) {
// 兼容旧版Chrome浏览器的代码
// ...
} else {
console.error("浏览器不支持 getUserMedia");
}
- 使用 getUserMedia API 请求访问用户麦克风
- 获取成功后,创建 MediaStreamSource 节点
- 连接音频源到脚本处理器,再连接到音频目的地(扬声器)
3. 音频数据处理逻辑
this.scriptNode.onaudioprocess = (audioProcessingEvent) => {
const inputBuffer = audioProcessingEvent.inputBuffer
const inputData = inputBuffer.getChannelData(0)
const volume = inputData.reduce((sum, sample) => sum + Math.abs(sample), 0) / inputData.length
const silenceThreshold = 0.018
// 静音检测逻辑 ----检查音量的阈值
// 进行一段话的收音结束操作
if (volume < silenceThreshold) {
} else {
this.float32ArrayToBase64Wav(inputBuffer).then((base64Data) => {
this.audioChunks.push(inputData)
this.sendAudioBufferAppend(base64Data)
})
}
}
3.1 音量检测
-silenceThreshold :静音阈值,低于此值被认为是静音
3.2 声音处理
- 格式为wav格式转化成base64发给后端进行转译
async float32ArrayToBase64Wav(inputBuffer) {
// const interleaved = new Float32Array(inputData);
const channelData = [];
for (let i = 0; i < inputBuffer.numberOfChannels; i++) {
channelData.push(inputBuffer.getChannelData(i));
}
const interleaved = interleave(channelData);
const pcmData = floatTo16BitPCM(interleaved);
const wavBuffer = encodeWAV(pcmData, inputBuffer.sampleRate, inputBuffer.numberOfChannels);
const wavBlob = new Blob([wavBuffer], { type: 'audio/wav' });
// 处理生成的 WAV Blob,例如下载
// const url = URL.createObjectURL(wavBlob);
// const a = document.createElement('a');
// a.href = url;
// a.download = 'output.wav';
// a.click();
// URL.revokeObjectURL(url);
const reader = new FileReader();
reader.readAsDataURL(wavBlob);
return new Promise((resolve) => {
reader.onloadend = () => {
resolve(reader.result.split(',')[1]);
};
});
},
- 当检测到声音时,取消静音定时器
- 如果当前处于语音段结束状态,则重置缓冲区并返回
- 调用 float32ArrayToBase64Wav 将音频数据转换为Base64编码的WAV格式
- 将转换后的音频数据通过 WebSocket通信 发送到服务器
2、语音获取与播放逻辑
1.通过WebSocket通信 获取服务器传递的数据
this.webSocketService = new WebSocketService(webSocketApiUrl);
// 初始化WebSocket连接
// 进行获取后端发送过来的base64音频数据,其中有文字和音频
this.webSocketService.onmessage((data) => {
})
2. 音频数据解码
// 将Base64编码的音频数据转换为ArrayBuffer
const arrayBuffer = this.base64ToArrayBuffer(base64Data);
// 解码ArrayBuffer为AudioBuffer
const audioBuffer = await this.audioCtx.
decodeAudioData(arrayBuffer);
base64ToArrayBuffer(base64) {
const binaryString = atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
for (let i = 0; i < len; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return bytes.buffer;
},
3. 音频源创建与播放
// 创建音频缓冲区源节点
const source = this.audioCtx.createBufferSource();
// 将音频源和缓冲区添加到播放队列
this.audioBufferList.push({ source, audioBuffer });
this.playNextAudio()
createBufferSource() 创建一个用于播放音频缓冲区的节点
将创建的音频源和缓冲区对象存储在 audioBufferList 数组中,调用 playNextAudio 方法开始播放
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)