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