最近需要在nodejs中接入vosk语音识别,下面让我们来试下示例
实现思路
- 在nodejs中实现vosk其实还是挺简单的,只要在nodejs中引入需要的依赖和模型,调用vosk的API即可
- 因为vosk底层使用python编写,还需要用到C++编译器。所以会有一些需要注意的地方详见下面注意事项
注意事项
- 下载c++编译
- 下载python3.8
- 卸载npm全局包windows-build-tools
- 本地添加node-gyp包/可用全局node-gyp包编译一次再npm(todo)
- node版本升级到18,不能低于14.21.3
1. 安装Visual Studio Community 2022
可以在微软商店下载,在软件中安装模块:使用C++的桌面开发
2.下载python3.8
这个也可以在微软商店下载,不可以下载python2.x
3. 初始化node项目,使用package.json
初始化的过程就不赘述了,需要安装的依赖有
{
"name": "vosk-demo",
"version": "1.0.0",
"description": "",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"busboy": "^1.6.0",
"koa": "^2.14.2",
"koa-bodyparser": "^4.4.0",
"koa-router": "^12.0.0",
"vosk": "^0.3.39"
}
}
在这个例子里面入口文件为根路径的index.js
代码编写
index.js
import Koa from 'koa';
import Router from 'koa-router';
import bodyParser from 'koa-bodyparser';
import busboy from 'busboy';
import speechRecognition from './vosk.js';
const app = new Koa();
const router = new Router();
app.use(bodyParser());
router.post('/transcribe', async (ctx) => {
/**
* 将上传的音频流转换为文本
* @returns {Promise<{code: number, text: string, msg: string}>}
*/
const audioStreamToText = () => {
const bb = busboy({ headers: ctx.req.headers });
return new Promise((resolve, reject) => {
bb.on('file', async (fieldname, stream, fileInfo) => {
const { mimeType } = fileInfo;
if (mimeType !== 'audio/wave') {
reject({ code: 400, text: '', msg: '只支持wav格式的音频文件' });
return;
}
const result = await speechRecognition(stream).catch((err) => {
reject({ code: 500, text: '', msg: err });
});
resolve({ code: 200, text: result, msg: 'success' });
});
ctx.req.pipe(bb);
});
};
const result = await audioStreamToText().catch((err) => {
return err;
});
ctx.body = result;
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000);
里面引入了vosk.js文件 通过传入的wav文件流进行解析,返回解析的文本
mport { existsSync } from 'node:fs';
import vosk from 'vosk';
import { Readable } from 'node:stream';
import wav from 'wav';
const MODEL_PATH = './model/vosk-model-small-cn';
if (!existsSync(MODEL_PATH)) {
console.log('模型不存在,请确认路径是否正确');
process.exit();
}
/**
* 语音识别
* @param {stream} audioStream
*/
const speechRecognition = async (audioStream) => {
return new Promise((resolve, reject) => {
const wfReader = new wav.Reader();
const wfReadable = new Readable().wrap(wfReader);
wfReader.on('format', async ({ audioFormat, sampleRate, channels }) => {
if (audioFormat !== 1 || channels !== 1) {
reject('只支持单声道wav格式的音频文件');
return;
}
try {
const model = new vosk.Model(MODEL_PATH);
const rec = new vosk.Recognizer({
model: model,
sampleRate: sampleRate
});
for await (const data of wfReadable) {
rec.acceptWaveform(data);
}
const result = rec.result();
rec.free();
resolve(result.text);
} catch (ex) {
reject('语音识别失败');
}
});
wfReadable.on('error', (err) => {
reject('文件读取失败');
});
audioStream.pipe(wfReader);
});
};
export default speechRecognition;
需要注意的是,进行解析的文件需要为wav文件,并且为单通道的。如果没有对应文件的话,可以参考我的另一篇文章,将mp3转为wav文件。
(nodejs-转换视频格式):[juejin.cn/post/722505…]
在这个例子中需要下载模型文件,模型文件可在下方地址中进行下载,然后在上方的MODEL_PATH中引入
注意事项:
- 如果遇到node-gyp的问题,可以在本地npm i node-gyp进行编译。也可以全局安装node-gyp依赖包,再通过node-typ命令进行解决
使用
postman中访问http://localhost:3000/transcribe POST请求,传入单声道的wav文件进行测试
参考资料
(vosk官网):[alphacephei.com/vosk/] (vosk github地址):[github.com/alphacep/vo…] (vosk 模型下载地址):[alphacephei.com/vosk/models]