👣2023年了,还有人不会语音转文字吧(js)

您所在的位置:网站首页 声音转文字的 👣2023年了,还有人不会语音转文字吧(js)

👣2023年了,还有人不会语音转文字吧(js)

2024-07-14 10:37| 来源: 网络整理| 查看: 265

一、Web语音API - SpeechRecognition

这 SpeechRecognition 的接口 Web 语音 API 是识别服务的控制器接口;它还处理 SpeechRecognitionEvent 从识别服务发送。

注意: 在某些浏览器(如 Chrome)上,在网页上使用语音识别会涉及基于服务器的识别引擎。音频将发送到 Web 服务进行识别处理,因此它无法脱机工作。

更多详情可以查看MDN : developer.mozilla.org/en-US/docs/…

这种方式的话需要考虑这种方式的兼容性问题,有些浏览器可以不太兼容。

图片.png

这里列出他的一些常用的属性事件和方法: 属性:

SpeechRecognition.grammars:返回并设置 SpeechGrammar 表示当前将理解的语法的对象 SpeechRecognition。

SpeechRecognition.lang:返回并设置当前语言 SpeechRecognition.如果未指定,则默认为 HTML [lang] 属性值或用户代理的语言设置(如果也未设置)。

SpeechRecognition.continuous:控制是为每个识别返回连续结果,还是只返回单个结果。默认为单个 ( false.)。

事件:

[end] 在语音识别服务断开连接时触发。 也可通过 onend 财产。

[error]发生语音识别错误时触发。 也可通过 onerror 财产。

[result] 当语音识别服务返回结果时触发 - 单词或短语已被积极识别,并且已将其传达回应用。 也可通过 onresult 财产。

[soundstart] 当检测到任何声音(无论是否可识别的语音)时触发。 也可通过 onsoundstart 财产。

[soundend]当任何声音(无论是否可识别的语音)停止被检测到时触发。 也可通过 onsoundend 财产。

[start] 当语音识别服务开始侦听传入音频以识别与当前关联的语法时触发 SpeechRecognition. 也可通过 onstart 财产。

方法:

SpeechRecognition.start() : 启动侦听传入音频的语音识别服务,以识别与当前 SpeechRecognition。

SpeechRecognition.stop(): 停止语音识别服务侦听传入的音频,并尝试返回 [SpeechRecognitionResult]使用到目前为止捕获的音频。

import { ref } from 'vue' let interimText = ref() const recognition: any = new webkitSpeechRecognition() || new SpeechRecognition() recognition.continuous = true recognition.interimResults = true recognition.lang = 'en-US' //(可以改成其他的语言) recognition.onstart = () => {   console.log('Speech recognition started') } recognition.onsoundstart = function (e) {   console.log('开始收听了')   console.log(e) } recognition.onspeechstart = (e) => {   console.log('开始讲话了')   console.log(e) } recognition.onspeechend = (e) => {   console.log('讲话完毕')   console.log(e) } //语音转化成字符串 recognition.onresult = (event) => {   console.log('文本结果')   interimText.value = event.results[0][0].transcript   console.log('interimText', interimText) } //监听报错 recognition.onerror = (event) => {   console.log(`Error occurred in recognition: ${event.error}`) } //开始 const startListening = () => {   recognition.start()   console.log('开始录音');   //监听开始 } //停止 const stopListening = () => {   recognition.stop()   recognition.continuous = false;   console.log('结束录音'); }       Audio Recognition Test     输入语音     结束录音   二、百度语音识别

废话不多说,先上代码。

/components/robot/recoder.js

let leftDataList = new Array(); let rightDataList = new Array(); //百度api地址 const url = ""; class Recorder {   constructor() {     this.mediaNode = null;     this.jsNode = null;     this.txt = "";     this.wavBuffer=null;   }   // 开始录音   beginRecorder() {     // 重置数据     this._dataInit();     // 采集声音     window.navigator.mediaDevices       .getUserMedia({         audio: {           sampleRate: 44100, // 采样率           channelCount: 2, // 声道           volume: 1.0, // 音量         },       })       .then((mediaStream) => {         this._begin(mediaStream);       })       .catch((err) => {         console.error(err);       });   }   // 结束录音 callback   stopRecorder() {     this.mediaNode.disconnect();     this.jsNode.disconnect();     // 停止录音     let leftData = this._mergeArray(leftDataList),       rightData = this._mergeArray(rightDataList);     let allData = this._interleaveLeftAndRight(leftData, rightData);     this.wavBuffer = this._createWavFile(allData);     // this._audioCheck(wavBuffer, callback);   }   // this._audioCheck(wavBuffer, callback); //  重置数据   _dataInit() {     leftDataList = [];     rightDataList = [];     this.txt = "";   }   _begin(mediaStream) {     // AudioContext接口表示由链接在一起的音频模块构建的音频处理图,每个模块由一个AudioNode表示。音频上下文控制它包含的节点的创建和音频处理或解码的执行。     // 在做任何其他操作之前,你需要创建一个AudioContext对象,因为所有事情都是在上下文中发生的。     // 建议创建一个AudioContext对象并复用它,而不是每次初始化一个新的AudioContext对象,并且可以对多个不同的音频源和管道同时使用一个AudioContext对象。     let audioContext = new (window.AudioContext || window.webkitAudioContext)();     // 创建一个MediaStreamAudioSourceNode接口来关联可能来自本地计算机麦克风或其他来源的音频流MediaStream。     this.mediaNode = audioContext.createMediaStreamSource(mediaStream);     // 创建一个jsNode     this.jsNode = this._createJSNode(audioContext);     // 需要连到扬声器消费掉outputBuffer,process回调才能触发     // 并且由于不给outputBuffer设置内容,所以扬声器不会播放出声音     this.jsNode.connect(audioContext.destination);     this.jsNode.onaudioprocess = this._onAudioProcess;     // 把mediaNode连接到jsNode     this.mediaNode.connect(this.jsNode);   }   _createJSNode(audioContext) {     // 缓冲区大小,以样本帧为单位。具体来讲,缓冲区大小必须是下面这些值当中的某一个:256, 512, 1024, 2048, 4096, 8192, 16384.     // 如果不传,或者参数为 0,则取当前环境最合适的缓冲区大小,取值为 2 的幂次方的一个常数,在该 node 的整个生命周期中都不变。     // 该取值控制着 audioprocess 事件被分派的频率,以及每一次调用多少样本帧被处理。较低 bufferSzie 将导致一定的延迟。     // 较高的 bufferSzie 就要注意避免音频的崩溃和故障。推荐作者不要给定具体的缓冲区大小,让系统自己选一个好的值来平衡延迟和音频质量。     const BUFFER_SIZE = 4096;     // 值为整数,用于指定输入 node 的声道的数量,默认值是 2,最高能取 32.     const INPUT_CHANNEL_COUNT = 2;     // 值为整数,用于指定输出 node 的声道的数量,默认值是 2,最高能取 32.     const OUTPUT_CHANNEL_COUNT = 2;     // createJavaScriptNode已被废弃     let creator =       audioContext.createAudioWorkletNode ||       audioContext.createScriptProcessor ||       audioContext.createJavaScriptNode;     creator = creator.bind(audioContext);     return creator(BUFFER_SIZE, INPUT_CHANNEL_COUNT, OUTPUT_CHANNEL_COUNT);   }   _onAudioProcess(event) {     let audioBuffer = event.inputBuffer;     let leftChannelData = audioBuffer.getChannelData(0),       rightChannelData = audioBuffer.getChannelData(1);     // 需要克隆一下     leftDataList.push(leftChannelData.slice(0));     rightDataList.push(rightChannelData.slice(0));   }   // 合并数组   _mergeArray(list) {     let length = list.length * list[0].length;     let data = new Float32Array(length),       offset = 0;     for (let i = 0; i < list.length; i++) {       data.set(list[i], offset);       offset += list[i].length;     }     return data;   }   // 交叉合并左右声道的数据   _interleaveLeftAndRight(left, right) {     let totalLength = left.length + right.length;     let data = new Float32Array(totalLength);     for (let i = 0; i < left.length; i++) {       let k = i * 2;       data[k] = left[i];       data[k + 1] = right[i];     }     return data;   }   _createWavFile(audioData) {     const WAV_HEAD_SIZE = 44;     let buffer = new ArrayBuffer(audioData.length * 2 + WAV_HEAD_SIZE),       // 需要用一个view来操控buffer       view = new DataView(buffer);     // 写入wav头部信息     // RIFF chunk descriptor/identifier     this._writeUTFBytes(view, 0, "RIFF");     // RIFF chunk length     view.setUint32(4, 44 + audioData.length * 2, true);     // RIFF type     this._writeUTFBytes(view, 8, "WAVE");     // format chunk identifier     // FMT sub-chunk     this._writeUTFBytes(view, 12, "fmt ");     // format chunk length     view.setUint32(16, 16, true);     // sample format (raw)  格式类型     view.setUint16(20, 1, true);     // stereo (2 channels) 声道数     view.setUint16(22, 2, true);     // sample rate 采样率,每秒样本数,表示每个通道的播放速度     view.setUint32(24, 44100, true);     // byte rate (sample rate * block align)波形数据传输率 (每秒平均字节数)     view.setUint32(28, 44100 * 2, true);     // block align (channel count * bytes per sample)     view.setUint16(32, 2 * 2, true);     // bits per sample     view.setUint16(34, 16, true);     // data sub-chunk     // data chunk identifier     this._writeUTFBytes(view, 36, "data");     // data chunk length     view.setUint32(40, audioData.length * 2, true);     // 写入PCM数据     let length = audioData.length;     let index = 44;     let volume = 1;     for (let i = 0; i < length; i++) {       view.setInt16(index, audioData[i] * (0x7fff * volume), true);       index += 2;     }     return buffer;   }   // 创建一个wav文件   _writeUTFBytes(view, offset, string) {     var lng = string.length;     for (var i = 0; i < lng; i++) {       view.setUint8(offset + i, string.charCodeAt(i));     }   }   // 上传录音到百度并检查结果data, 发送   sendAudioCheck(callback) {     let data =this.wavBuffer     let form = new FormData();     let newData = new Blob([new Uint8Array(data)], { type: "audio/wav" });     form.append("arrayBuffer", newData);     let xhr = new XMLHttpRequest();     xhr.open("post", url, true);     xhr.send(form);     xhr.onreadystatechange = () => {       if (xhr.readyState === 4) {         if (xhr.status === 200) {           let res = xhr.responseText;           let index = res.search(/{/);           console.log(res);           res = JSON.parse(res.slice(index)).result[0];           console.log(res);           let ans = { ans: "我不清楚,请再说一遍", index: 0 };           // if (res) ans = dialog.getAnswer(res);           ans = { ans: "暂不回答", index: 666 };           this.txt = ans;           if (callback && typeof callback === "function")             callback(res, this.txt);         }       }     };   } } export { Recorder };

/components/robot/recorder.d.ts

declare class Recorder {   beginRecorder(): void;   stopRecorder(): void;   sendAudioCheck(callback: Function):void; } export { Recorder };

在vue中的使用: Recorder.vue

import { ref } from 'vue' import { Recorder } from '../robot/recorder' // 录音 let startRecorder = ref(false) // 语音机器人 let recorder = new Recorder() let startTxt = ref("开始录音"); let clickLock = false // 出结果后再允许触发开始录音事件 function startRecorderFn() {   if (clickLock) return   clickLock = true   startTxt.value = '处理中...'   startRecorder.value = true   recorder.beginRecorder() } function stopRecorderFn() {   startRecorder.value = false   recorder.stopRecorder(recorderRes) } // 语音识别结果回调 /**  *  * @param que 根据语音生成的文本内容  * @param res 根据文本内容,找到答案,暂无  */ function recorderRes(que: string, res: any) {   if (!que) que = '...'   setTimeout(() => {     console.log(que);     startTxt.value = '开始录音'     clickLock = false   }, 600) }     {{startTxt}}   停止录音   引用: 前端语音转文字实践总结 前端js实现asr(语音转文字) MDN中的 MediaDevices.getUserMedia() MDN中的SpeechRecognition 百度的语音识别(收费)

56ac935951ab4af78bf31af55b600d95.jpg

如果这篇文章对你有用,多多点赞收藏!!!


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3