语音识别探索
起因: 在Chat GPT发布一个月后, 基于AI实现的各种小工具层出不穷, 感觉真像是忽如一夜春风来, 千树万树梨花开. 而我, 在两天前的一个晚上也刷到一个up主使用chat ai实现了一个自制语音小助手的视频, 看完后感觉, 嗯有意思. 然后我便开始了一系列捣鼓. 原视频在这里
1. 兜兜转转浪费时间篇
顾名思义, 在这三天时间内, 我许多时间都用来这看看那看看, 浪费了许多精力, 但也有了一些大概的实现方向, 因此也在这里浅浅记录下.
1.1 基于原视频的Porcupine
在视频中博主使用了Porcupine 做为热词识别的引擎, 通过该工具进行热词检测, 如siri 这种唤醒词.
该方案的特点就是支持的平台多, 语言多, 以及准确率高(来自官网).
在找到该工具官网后, 发现其支持的平台和语言也确实很多, 前端的node, web, vue, react这些都有相应的包, 但是问题就是还需要自己去解析语音数据. 该工具需要是模拟声音信号, 16Bit 512长度, 这是个麻烦的事情, 所以这里需要一些时间去看相关资料, 自己对声音进行处理. (具体的代码例子可以参考官网)
这里我做了一些尝试, 但是感觉如果沿着这条路走下去可能需要耗费不少精力先去看一些专业的语音相关知识, 所以打算后面换向, 自己尝试体验下暂时没必要耗费太多时间.
1.2 基于Web Speech
该方案是我在网上搜索的时候看到的, 该api是一个实验中的特性, 目前在只有部分浏览器是可以正常运行的. 下面是MDN上的介绍, 更多可以看这里
Web Speech API 使您能够将语音数据合并到 Web 应用程序中。Web Speech API 有两个部分:SpeechSynthesis 语音合成(文本到语音 TTS)和 SpeechRecognition 语音识别(异步语音识别)。
该方案的特点是简单, 功能集成在一起, 缺点就是依赖浏览器支持以及科学上网
Demo代码如下
// 该段代码来自https://www.infoq.cn/article/ofypxojpzb3eiw6ap0c3
const startBtn = document.createElement("button");
startBtn.innerHTML = "Start listening";
const result = document.createElement("div");
const processing = document.createElement("p");
document.write("<body><h1>My Siri</h1><p>Give it a try with 'hello', 'how are you', 'what's your name', 'what time is it', 'stop', ... </p></body>");
document.body.append(startBtn);
document.body.append(result);
document.body.append(processing);
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
if (typeof SpeechRecognition === "undefined") {
startBtn.remove();
result.innerHTML = "<b>Browser does not support Speech API. Please download latest chrome.<b>";
}
const recognition = new SpeechRecognition();
recognition.continuous = true;
recognition.interimResults = true;
function process(speech_text) {
return "....";
}
recognition.onresult = event => {
const last = event.results.length - 1;
const res = event.results[last];
const text = res[0].transcript;
console.log(text)
if (res.isFinal) {
processing.innerHTML = "processing ....";
const response = process(text);
const p = document.createElement("p");
p.innerHTML = `You said: ${text} </br>Siri said: ${response}`;
processing.innerHTML = "";
result.appendChild(p);
// add text to speech later
} else {
processing.innerHTML = `listening: ${text}`;
}
}
let listening = false;
toggleBtn = () => {
if (listening) {
recognition.stop();
startBtn.textContent = "Start listening";
} else {
recognition.start();
startBtn.textContent = "Stop listening";
}
listening = !listening;
};
startBtn.addEventListener("click", toggleBtn);1.3 基于Navigator.mediaDevices和Web Audio API
更多mediaDevices资料参考: https://juejin.cn/post/6924563220657586184
MDN上的介绍为:
Navigator接口表示用户代理的状态和标识。它允许脚本查询它和注册自己进行一些活动。mediaDevices 是 Navigator 只读属性,返回一个
MediaDevices对象,该对象可提供对相机和麦克风等媒体输入设备的连接访问,也包括屏幕共享。
总之可以用这个接口获取客户端的媒体控制, 猜测牛客网的屏幕共享也可能采用了此方案.
在获取到音频数据后, 再使用Web Audio API 对音频进行处理, 如平移变换, 改变输入等. 具体api的介绍为:
Web Audio API 提供了在 Web 上控制音频的一个非常有效通用的系统,允许开发者来自选音频源,对音频添加特效,使音频可视化,添加空间效果(如平移),等等。
在这个方案里面, 可以将采样到的语音进行一个编码, 然后传递给服务端, 服务端进行一些处理, 或者页面处理后进行一个可视化, 或者传递给AudioDestinationNode` (音频输出目的地)进行播放等操作.
在这里就可以搭配Porcupine 进行使用, 即将音频进行采样, 然后处理成Porcupine 需要的数据格式, 交给Porcupine 进行判断是否触发唤醒词.
在上面就遇到了PCM音频编码转换, 根据网上搜索的资料, 首先需要指定采集音频的采样率, 然后进行音频流采集, 此时是连续数据, 即模拟信号; 然后对该信号进行采样过滤, 生成离散数据, 即数字信号. 从模拟信号转换到数字信号便可得到PCM数据.
这篇文章里面有对该转换的一些讲解, https://bbs.huaweicloud.com/blogs/128210.
