👣2023年了,还有人不会语音转文字吧(js) |
您所在的位置:网站首页 › 声音转文字的 › 👣2023年了,还有人不会语音转文字吧(js) |
一、Web语音API - SpeechRecognition
这 SpeechRecognition 的接口 Web 语音 API 是识别服务的控制器接口;它还处理 SpeechRecognitionEvent 从识别服务发送。 注意: 在某些浏览器(如 Chrome)上,在网页上使用语音识别会涉及基于服务器的识别引擎。音频将发送到 Web 服务进行识别处理,因此它无法脱机工作。 更多详情可以查看MDN : developer.mozilla.org/en-US/docs/… 这种方式的话需要考虑这种方式的兼容性问题,有些浏览器可以不太兼容。 这里列出他的一些常用的属性事件和方法: 属性: 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 百度的语音识别(收费) |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |