前一段时间利用开源软件,整合Live2D数字人、Dify和Ollama部署了一个本地的2D数字人,具体参考:
北方的郎:2G显卡就能跑的数字人系统:Win10上Dify智能体+live2d数字人
添加图片注释,不超过 140 字(可选)
玩了一阵子,感觉还是有些遗憾就是不能自动语音唤醒,每次交互都要点击按钮才行。
于是就自己试了一下,一开始只用音量,但是对噪音太敏感。后来加入频域,过零点检测等,有提升不过还是不够好,后来找到VAD技术,发现效果不错,具体参考:
北方的郎:应用前端语音唤醒机制简单研究、测试:音量、VAD等
1 VAD前端控件简介
找了一个基于JavaScript的VAD开源项目:
https://github.com/ricky0123/vad
添加图片注释,不超过 140 字(可选)
项目说明如下:此软件包旨在提供一个准确、用户友好的声音活动检测器(VAD),可在浏览器中运行。通过使用此软件包,您可以提示用户授予麦克风权限,开始录制音频,将包含语音的音频片段发送到您的服务器进行处理,或者在用户说话时显示特定的动画或指示器。
调用说明:
Voice Activity Detection for Javascript
Voice Activity Detection for Javascript
运行它提供的Demo,发现效果不错,能很准确的区分噪音和语音。而且录制的语音很完整。运行Demo的步骤如下:
npm i@ricky0123/vad-react
git clone https://github.com/ricky0123/vad
cd ./vad/examples/react-bundler
npm run build && npm run start
添加图片注释,不超过 140 字(可选)
2 整合Live2D数字人前端及VAD控件
本人前端开发经验很少,所以一些方法可能不够优雅,请见谅。
VAD控件的调用,参考的是它自己提供的react例子:
vad/examples/react-bundler at master · ricky0123/vad
修改的代码是开源的Live2d数字人:
GitHub - wan-h/awesome-digital-human-live2d: Awesome Digital Human
步骤如下
1,修改web\package.json
加入
"@ricky0123/vad-react": "^0.0.25",
添加图片注释,不超过 140 字(可选)
2,修改\web\app\lib\comm.ts
加入asrFromBase64的定义
public async asrFromBase64(
base64str: string,
settings: { [key: string]: string } = {},
engine: string = "default",
format: string = "wav",
sampleRate: Number = 16000,
sampleWidth: Number = 2
): Promise {
if (!base64str) {
return "";
}
try {
const response = await API.asr_infer_api(
base64str,
engine,
format,
sampleRate,
sampleWidth,
settings
);
return response.data;
} catch (error) {
console.error(error);
return "";
}
}
3,修改\web\app\ui\home\chatbot.tsx
加入引用及函数定义
import { useMicVAD, utils } from "@ricky0123/vad-react"; // 引入VAD控件
let micRecorder: Recorder | null = null;
let isRecording: boolean = false;
function UserSpeaking() {
return user is speaking
}
function UserNotSpeaking() {
return user is not speaking
}
function arrayBufferToWavBlob(arrayBuffer) {
// 将 ArrayBuffer 转换为 Blob,设置 MIME 类型为 audio/wav
return new Blob([arrayBuffer], { type: 'audio/wav' });
}
修改function Chatbot,加入
// VAD相关状态
const [audioList, setAudioList] = useState([])
const vad = useMicVAD({
startOnLoad: true,
onSpeechEnd: (audio) => {
if (isProcessing) return;
console.log("VAD SpeechEnd", "");
const wavBuffer = utils.encodeWAV(audio, 1, 16000, 1, 16);
const base64 = utils.arrayBufferToBase64(wavBuffer);
const url = `data:audio/wav;base64,${base64}`
setAudioList((old) => [url, ...old])
setIsProcessing(true);
Comm.getInstance().asrFromBase64(base64, settings).then(
(res) => {
console.log("asr: ", res);
if (res) {
chatWithAI(res);
} else {
setIsProcessing(false);
}
}
).catch(
(error) => {
setIsProcessing(false);
}
)
},
})
如果为了方便调试,显示VAD获取的音频,可以在Return后的({micRecordAlert ?
{vad.listening && VAD is running}
{!vad.listening && VAD is NOT running}
{vad.userSpeaking && }
{!vad.userSpeaking && }
{audioList.map((audioURL) => {
return (
-
)
})}
4,其他
然后就可以执行npm run build进行编译了。
把编译后的VAD项目(
https://github.com/ricky0123/vad)的例子react-bundler下的dist目录:vad\examples\react-bundler\dist下的这几个文件
添加图片注释,不超过 140 字(可选)
拷贝到编译后的数字人的这两个目录下
web\.next\static\chunks\
web\.next\static\chunks\app\
这么做主要是我在把这几个文件的拷贝命令加入到next.config.mjs的时候,一直报错,所以干脆直接拷贝了。
然后执行npm run start就可以看到效果了
添加图片注释,不超过 140 字(可选)
还有就是调试的时候可以执行 npm run dev进行调试。