浏览器JS/WebAssembly语音识别PocketSphinx火了

前有科技后进阶 2024-05-05 04:56:07

大家好,很高兴又见面了,我是"高级前端‬进阶‬",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!

什么是 PocketSphinx.js

PocketSphinx.js 是一个完全在 Web 浏览器中运行语音识别器,建立在以下核心能力之上:

用 C (PocketSphinx) 编写的语音识别器使用 Emscripten 转换为 JavaScript 或 WebAssembly使用 web audio API 的 audio recorder, 录音机可以独立使用来构建其他类型的与音频相关的 Web 应用程序

PocketSphinx.js 项目包括几个可以独立使用的组件:

pocketsphinx.js:一个由 emscripten 生成的 JavaScript 库,基本上是 PocketSphinx 包装以提供更简单的 API,并编译成 JavaScript 或 WebAssembly。pocketsphinx.wasm:编译后的 WebAssembly 文件(如果编译成 WebAssembly)。recognizer.js:Web Worker 内 pocketsphinx.js 的包装器,用于卸载 UI 线程,免于下载和运行大型 JavaScript 文件以及运行成本高昂的语音识别过程。audioRecorder.js:一个基于 Recorderjs 的录音库,将 recorder 的样本转换为适当的采样率并将其传递给识别器。callbackManager.js:一个小实用程序,用于通过调用和回调而不是消息传递与 Web Workers 进行交互。

目前 PocketSphinx.js 已经在 Github 通过 MIT 协议开源,有超过 1.5k 的 star,是一个值得关注的前端优质开源项目。

如何使用 PocketSphinx.jspocketsphinx.js 使用规范

pocketsphinx.js 文件可以直接包含到 HTML 文件中,但由于其相当大(几 MB,取决于编译和打包文件时使用的优化级别),下载和加载它需要时间并影响 UI 线程。 因此,大多数情况应该在 Web Worker 中使用,例如使用 recognizer.js。

该 API 基于 embind,可能应该查看 emscripten 文档中的该部分,以了解如何与 emscripten 生成的 JavaScript 进行交互。 Pocketsphinx.js 的早期版本使用 C 风格的 API,现已弃用,但仍然可以在 OBSOLETE_API 分支中使用。

请注意,如果使用 WebAssembly 版本,则需要 pocketsphinx.js 和 pocketsphinx.wasm。 一旦 pocketsphinx.js 加载到页面中,它将通过查看根文件夹中的文件开始加载和编译 pocketsphinx.wasm。 可以在加载 pocketsphinx.js 之前设置备用 URL:

var Module = { locateFile: function() {return "/path/to/pocketsphinx.wasm";} }

另外,由于 pocketsphinx.wasm 是异步加载,因此需要等到其加载并编译后才能执行任何操作。一种方法是为 onRuntimeInitialized 添加回调:

<script type="text/javascript"> var Module = { locateFile: function() {return "/path/to/pocketsphinx.wasm";}, onRuntimeInitialized: function() { // 开始使用具体方法 } }; </script> <script src="path/to/pocketsphinx.js"></script>

作为第一个示例,以下代码创建一个新的识别器:

var recognizer = new Module.Recognizer();/* ..创建一个识别器... */recognizer.delete();

对 pocketsphinx.js 函数的调用是同步的,这也是可能需要将其加载到 Web Worker 中的原因。

大多数调用返回 ResultType 对象,该对象可以是以下之一:

SUCCESS,如果操作执行成功。BAD_STATE,如果当前状态不允许该操作。BAD_ARGUMENT,如果提供的参数无效。RUNTIME_ERROR,如果识别器中存在运行时错误。

在 JavaScript 中,这些值可以称为 Module.ReturnType.SUCCESS、Module.ReturnType.BAD_STATE 等。例如:

var recognizer = new Module.Recognizer();/* ..创建一个识别器.. */if (recognizer.reInit(config) != Module.ReturnType.SUCCESS) alert("Error while recognizer is re-initialized");Recognizer 对象

pocketsphinx.js 的入口是 Recognizer 对象。 开发者可以根据需要创建任意数量的实例,但很多情况下可能不需要并且希望节省内存。 创建新实例时,可以给出一个可选的 Config 对象,该对象将用于设置用于初始化 Pocketsphinx 的参数。

var config = new Module.Config();config.push_back(["-fwdflat", "no"]);var recognizer = new Module.recognizer(config);config.delete();/* ..删除一个识别器. */recognizer.delete();

此时将初始化一个 recognizer,并将 “-fwdflat” 设置为 “no”。

如果在编译 pocketsphinx.js 时包含了多个声学模型,则可以通过设置 “-hmm” 参数来选择应使用哪一个。 假设有两个模型,一种用于英语,一种用于法语,并且已使用 -DHMM_FOLDERS="english;french" 编译了库,则可以通过在 Config 对象中设置正确的值来使用法语模型初始化识别器:

var config = new Module.Config();config.push_back(["-hmm", "french"]);var recognizer = new Module.recognizer(config);

如果没有给出 “-hmm” 参数,或者给它一个无效值,则将使用列表中的第一个模型(此处为英语)。

同样,应该使用 recognizer 配置参数来加载之前打包在 pocketshinx.js 中的统计语言模型(“-lm”)或字典(“-dict”)。 请注意,如果要使用 SLM,则还必须有一个包含 SLM 中使用的单词的词典文件。

此外,在创建实例后,可以通过调用 reInit 来使用新参数重新初始化识别器对象,例如:

var config_english = new Module.Config();config_english.push_back(["-hmm", "english"]);var config_french = new Module.Config();config_french.push_back(["-hmm", "french"]);var recognizer = new Module.recognizer(config_english);/* ..个性化识别参数. */if (recognizer.reInit(config_french) != Module.ReturnType.SUCCESS) alert("Error while recognizer is re-initialized");识别音频 Recognizing audio

要识别音频,必须首先调用 start 来初始化识别,然后通过调用来向识别器提供音频数据以进行处理,最后在完成后调用 stop。 在识别期间和识别之后,可以通过调用 getHyp 来检索已识别的字符串。

在调用 start 之前,必须确保当前的语言模型是正确的,主要是最后发生的情况:

如果刚刚向识别器提供语法或关键字搜索,它将自动用作当前语言模型。如果对 switchSearch 的调用成功,则将在下一次调用中使用指定的搜索来启动。如果 SLM 打包在 pocketsphinx.js 中,并通过将参数添加到实例化(或重新初始化)识别器时使用的 Config 对象来加载,则该模型就是当前的语言模型。

对 process 的调用必须包含 AudioBuffer 对象形式的音频缓冲区。 AudioBuffer 对象可以重复使用,但必须包含以 16kHz 录制的 2 字节整数形式的音频样本(除非声学模型使用不同的特性)。

var array = ... // array that contains an audio buffervar buffer = new Module.AudioBuffer();for (var i = 0 ; i < array.length ; i++) buffer.push_back(array[i]); // Feed the array with audio datavar output = recognizer.start(); // Starts recognition on current language modeloutput = recognizer.process(buffer); // Processes the buffervar hyp = recognizer.getHyp(); // Gets the current recognized string (hypothesis)/* ... */for (var i = 0 ; i < array.length ; i++) buffer.set(i, array[i]); // Feed buffer with new dataoutput = recognizer.process(buffer);hyp = recognizer.getHyp();/* ... */output = recognizer.stop();// Gets the final recognized string:var final_hyp = recognizer.getHyp();buffer.delete();将 recognizer.js 连接到录音机

PocketSphinx.js 包含一个基于 Web Audio API 的音频录制库,该库访问麦克风、获取音频样本、将其转换为适当的采样率(默认声学模型为 16kHz),并将其发送到识别器, 该库源自 Recorderjs。

在 HTML 文件中包含 audioRecorder.js,并确保 audioRecorderWorker.js 位于同一文件夹中。 要使用它,请创建一个 AudioRecorder 的新实例,并将 MediaStreamSource 作为参数。 截至今天,Google Chrome 和 Firefox (25+) 都实现了,还需要将识别器属性设置为识别器工作线程,如上所述。

// Deal with prefixed APIswindow.AudioContext = window.AudioContext || window.webkitAudioContext;// Instantiating AudioContexttry { var audioContext = new AudioContext();} catch (e) { console.log("Error initializing Web Audio");}var recorder;// Callback once the user authorizes access to the microphone:function startUserMedia(stream) { var input = audioContext.createMediaStreamSource(stream); recorder = new AudioRecorder(input); // We can, for instance, add a recognizer as consumer if (recognizer) recorder.consumers.push(recognizer); };// Call getUserMediaif (navigator.mediaDevices.getUserMedia) navigator.mediaDevices.getUserMedia({audio: true}) .then(startUserMedia) .catch(function(e) { console.log("No live audio input in this browser"); });else console.log("No web audio support in this browser");

recorder 启动并运行后,可以通过以下方式开始和停止录音和识别:

// To start recording:recorder.start();// The hypothesis is periodically sent by the recognizer, as described previously// To stop recording:recorder.stop(); // The final hypothesis is sent

AudioRecorder 的构造函数可以采用可选的配置对象。 此配置可以包含一个回调函数,该函数在录制过程中出现错误时执行。 截至目前,唯一可能的错误是输入样本静音时,还可以包括输出采样率,如果使用 8kHz 音频的声学模型可能需要设置该输出采样率。

var audioRecorderConfig = { errorCallback: function(x) {alert("Error from recorder: " + x);}, outputSampleRate: 8000 };recorder = new AudioRecorder(input, audioRecorderConfig);本文总结

本文主要和大家介绍 PocketSphinx.js,其是一个完全在 Web 浏览器中运行语音识别器,建立在 PocketSphinx,使用 web audio API 的 audio recorder 之上。 因为篇幅问题,关于 PocketSphinx.js 只是做了一个简短的介绍,但是文末的参考资料以及个人主页提供了大量优秀文档以供学习,如果有兴趣可以自行阅读。如果大家有什么疑问欢迎在评论区留言。

参考资料

https://github.com/syl22-00/pocketsphinx.js

https://www.instructables.com/Introduction-to-Pocketsphinx-for-Voice-Controled-A/

https://www.youtube.com/watch?v=J-bQQiCMV5k

https://levelup.gitconnected.com/how-to-use-web-workers-api-b1ef96c46fc0

0 阅读:0

前有科技后进阶

简介:感谢大家的关注