web网页录音(recorder.js)并上传后端语音转文字(Vosk)

北海怪兽Monster 2024-08-02 10:33:01 阅读 82

我是一个后端开发人员,现在都快进化成全栈了。操了,是谁有好的项目让我跳跳槽,转转行吧

写在前面,很重要

在这里插入图片描述

这是官方文档的说明

翻译如下:

我们有两种型号-大型号和小型号,小型号非常适合在移动应用程序上执行一些有限的任务。它们可以在智能手机、树莓派上运行。它们也被推荐用于桌面应用程序。小型模型的大小通常在50Mb左右,运行时需要大约300Mb的内存。大模型用于服务器上的高精度转录。大型机型需要高达16Gb的内存,因为它们采用了先进的人工智能算法。理想情况下,您可以在一些高端服务器上运行它们,如i7或最新的AMD Ryzen。在AWS上,您可以查看c5a机器和其他云中的类似机器。

大多数小型模型允许动态词汇表重新配置。大模型是静态的——词汇表在运行时无法修改。

大模型对于硬件是有要求的。我下面的demo是基于小模型来的。

VOSK网址:

https://alphacephei.com/vosk/models

前端使用H5进行录音

一开始我使用的是H5的录音功能。网上一搜一大堆,下面的可以录音,将录音放入audio中。

录音之后将文件上传后端。

<code><body>

<button id="startRecord" onclick="startAudio()">开始录音</button>code>

<button id="stopRecord" disabled onclick="stopAudio()">停止录音并保存</button>code>

<audio controls id="player"></audio>code>

<form style="display: none" enctype="multipart/form-data" method="post" id="fileinfo_high">code>

</form>

<div>

<button id="upload" onclick="updateFile()">上传文件</button>code>

</div>

async function startAudio(){

await navigator.mediaDevices.getUserMedia({ audio: true })

.then(stream => {

mediaStream = stream;

startButton.disabled = false;

console.log('成功获取音频输入源')

})

.catch(err => {

console.log('无法获取音频输入源', err);

});

// 获取音频流

recorder = new MediaRecorder(mediaStream);

//recorder.sampleBits=16; // 采样位数,支持 8 或 16,默认是16

//recorder.sampleRate=48000; // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000

// 处理音频数据

recorder.ondataavailable = (event) => {

if (event.data.size > 0) {

chunks.push(event.data);

}

};

// 完成录音

recorder.start();

// 停止录音

stopButton.disabled = false;

startButton.disabled = true;

console.log('开始录音...');

}

// 停止录音并生成文件

stopButton.addEventListener('click', () => {

// 停止录音

recorder.stop();

startButton.disabled = false;

stopButton.disabled = true;

recorder.onstop = () => {

console.log('录音已停止');

// 音频类型 ogg webm mp3

const blob = new Blob(chunks, { type: 'audio/mp3; codecs=opus' });

// 将录音设置为可播放

const url = window.URL.createObjectURL(blob);

player.src = url;

console.log('尝试播放录音');

};

if (mediaStream) {

var tracks = mediaStream.getTracks();

for (let i = 0; i < tracks.length; i++) {

var track = tracks[i];

track.stop();

}

}

});

function updateFile(){

var f = new FormData(document.getElementById("fileinfo_high"));

var file = new File(chunks,'audio.mp3',{ type: 'audio/mp3; codecs=opus' });

f.append("file", file);

$.ajax({

url: "/RecordTools/uploadAudio",

type: 'POST',

data: f,

traditional: true,

dataType: 'JSON',

cache: false,

processData: false,

contentType: false,

success: function (data) {

console.log(data)

},

error: function () {

AtsBase.atsAlert("Error!");

}

});

}

从网页录音到上传到后端存放都是顺利的。

不知道你们使用的什么框架识别语音。我使用的VOSK,因为它可以离线,免费。

那么问题就来了,VOSK,只支持WAV格式的语音文件。

一开始我将这段代码更改为 WAV格式

var file = new File(chunks,'audio.mp3',{ type: 'audio/mp3; codecs=opus' });

当然没这么轻易了

还是识别失败,报错截图就不展示了,就是将不支持这个格式。

@PostMapping("uploadAudio")

public Map<String,Object> uploadAudio(MultipartFile file){

HashMap<String, Object> result = new HashMap<>();

System.out.println(file);

System.out.println(file.getOriginalFilename());

System.out.println(file.getName());

InputStream inputStream = file.getInputStream();

FileOutputStream out001 = new FileOutputStream("D:\\Others\\Logs\\test.wav");

FileCopyUtils.copy(inputStream, out001);

}

文件存放下来打开也是正常的。

因为正常打开,所以一开始我就很纳闷,是这个格式,为什么说不支持这个格式文件呢。

我最初想的是,难道是后端文件存放问题?我将文件变成字节数组,前后端乱七糟八整了很久。

最后我发现,根本原因是编码格式的问题。

使用H5进行录音,谷歌默认是mp3的格式,所以我在前端使用了recorder.js

这个js内部也是使用的H5的流媒体,但是它里面还封装了一个编码器。

Recorder.js

const startButton = document.getElementById('startRecord');// 开始录音

const stopButton = document.getElementById('stopRecord');// 停止录音

const player = document.getElementById('player');// 播放

function startAudio(){

recorder = new Recorder({

sampleBits: 16, // 采样位数,支持 8 或 16,默认是16

sampleRate: 16000, // 采样率,支持 11025、16000、22050、24000、44100、48000,根据浏览器默认值,我的chrome是48000

numChannels: 1

})

this.recorder.start().then(

() => {

// 开始录音

console.log('开始录音了=========')

},

(error) => {

// 出错了

console.log(error)

}

)

startButton.disabled = true;

stopButton.disabled = false;

}

function stopAudio(){

this.recorder.stop();

startButton.disabled = false;

stopButton.disabled = true;

}

function updateFile() {

let wavBlob = this.recorder.getWAVBlob()

let renameFile =new File([wavBlob], '文件名.wav', { type: 'audio/wav' });

var f = new FormData(document.getElementById("fileinfo_high"));

f.append("file", renameFile);

$.ajax({

url: "/RecordTools/uploadAudio",

type: 'POST',

data: f,

traditional: true,

dataType: 'JSON',

cache: false,

processData: false,

contentType: false,

success: function (data) {

console.log(data)

if(data.flag){

AtsBase.atsMsg("S", "图片上传成功!");

}else{

AtsBase.atsMsg("W", "图片上传失败!");

}

},

error: function () {

AtsBase.atsAlert("Error!");

}

});

}

后端代码 VOSK

maven

<!-- 获取音频信息 -->

<dependency>

<groupId>org</groupId>

<artifactId>jaudiotagger</artifactId>

<version>2.0.3</version>

</dependency>

<!-- vosk 语音识别 -->

<dependency>

<groupId>net.java.dev.jna</groupId>

<artifactId>jna</artifactId>

<version>5.7.0</version>

</dependency>

<dependency>

<groupId>com.alphacephei</groupId>

<artifactId>vosk</artifactId>

<version>0.3.32</version>

</dependency>

@PostMapping("uploadAudio")

public Map<String,Object> uploadAudio(MultipartFile file) throws IOException {

HashMap<String, Object> result = new HashMap<>();

System.out.println(file);

System.out.println(file.getOriginalFilename());

System.out.println(file.getName());

// InputStream inputStream = file.getInputStream();

/*FileOutputStream out001 = new FileOutputStream("D:\\Others\\Logs\\test.wav");

FileCopyUtils.copy(inputStream, out001);*/

/// LibVosk.setLogLevel(LogLevel.DEBUG);

/*try (

Model model = new Model("D:\\Others\\vosk\\vosk-model-small-cn-0.22");

InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(inputStream));

Recognizer recognizer = new Recognizer(model, 16000)

) {

int bytes;

byte[] b = new byte[4096];

while ((bytes = ais.read(b)) >= 0) {

recognizer.acceptWaveForm(b, bytes);

}

System.out.println(recognizer.getFinalResult() + System.lineSeparator());

}catch (Exception e){

e.printStackTrace();

}*/

try {

LibVosk.setLogLevel(LogLevel.DEBUG);

Model model = new Model("D:\\Others\\vosk\\vosk-model-small-cn-0.22");//该段是模型地址

// File audioFile = new File("D:\\Others\\Logs\\d357c391-d387-4359-b57e-c0bf8c6853da.wav");

InputStream ais = AudioSystem.getAudioInputStream(new BufferedInputStream(file.getInputStream()));

//该段是要转的语言文件,仅支持wav

Recognizer recognizer = new Recognizer(model, 16000);

//该段中12000是语言频率,需要大于8000,可以自行调整

int nbytes;

byte[] b = new byte[4096];

while ((nbytes = ais.read(b)) >= 0) {

if (recognizer.acceptWaveForm(b, nbytes)) {

System.out.println(recognizer.getResult());

} else {

System.out.println(recognizer.getPartialResult());

}

}

System.out.println("--------------------");

System.out.println(recognizer.getFinalResult());

}catch (Exception e){

e.printStackTrace();

}

result.put("flag",true);

return result;

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。