/** * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights * Reserved. MIT License (https://opensource.org/licenses/MIT) */ /* 2022-2023 by zhaoming,mali aihealthx.com */ // 连接; 定义socket连接类对象与语音对象 var wsconnecter = new WebSocketConnectMethod({ msgHandle: getJsonMessage, stateHandle: getConnState }); var audioBlob; var isfilemode = true; // if it is in file mode // 录音; 定义录音对象,wav格式 var rec = Recorder({ type: "pcm", bitRate: 16, sampleRate: 16000, onProcess: recProcess }); var sampleBuf = new Int16Array(); var rec_text = ""; // for online rec asr result var offline_text = ""; // for offline rec asr result var file_ext = ""; var file_sample_rate = 16000; //for wav file sample rate var file_data_array; // array to save file data var totalsend = 0; addresschange(); function addresschange() { var Uri = 'ws://192.168.0.232:10095'; Uri = Uri.replace(/wss/g, "https"); window.open(Uri, '_blank'); } var readWavInfo = function (bytes) { //读取wav文件头,统一成44字节的头 if (bytes.byteLength < 44) { return null; }; var wavView = bytes; var eq = function (p, s) { for (var i = 0; i < s.length; i++) { if (wavView[p + i] != s.charCodeAt(i)) { return false; }; }; return true; }; if (eq(0, "RIFF") && eq(8, "WAVEfmt ")) { var numCh = wavView[22]; if (wavView[20] == 1 && (numCh == 1 || numCh == 2)) {//raw pcm 单或双声道 var sampleRate = wavView[24] + (wavView[25] << 8) + (wavView[26] << 16) + (wavView[27] << 24); var bitRate = wavView[34] + (wavView[35] << 8); var heads = [wavView.subarray(0, 12)], headSize = 12;//head只保留必要的块 //搜索data块的位置 var dataPos = 0; // 44 或有更多块 for (var i = 12, iL = wavView.length - 8; i < iL;) { if (wavView[i] == 100 && wavView[i + 1] == 97 && wavView[i + 2] == 116 && wavView[i + 3] == 97) {//eq(i,"data") heads.push(wavView.subarray(i, i + 8)); headSize += 8; dataPos = i + 8; break; } var i0 = i; i += 4; i += 4 + wavView[i] + (wavView[i + 1] << 8) + (wavView[i + 2] << 16) + (wavView[i + 3] << 24); if (i0 == 12) {//fmt heads.push(wavView.subarray(i0, i)); headSize += i - i0; } } if (dataPos) { var wavHead = new Uint8Array(headSize); for (var i = 0, n = 0; i < heads.length; i++) { wavHead.set(heads[i], n); n += heads[i].length; } return { sampleRate: sampleRate , bitRate: bitRate , numChannels: numCh , wavHead44: wavHead , dataPos: dataPos }; }; }; }; return null; }; function upfileOnchange(files) { this.files = [files]; var len = this.files.length; for (let i = 0; i < len; i++) { let fileAudio = new FileReader(); fileAudio.readAsArrayBuffer(this.files[i]); file_ext = this.files[i].name.split('.').pop().toLowerCase(); var audioblob; fileAudio.onload = function () { audioblob = fileAudio.result; file_data_array = audioblob; } fileAudio.onerror = function (e) { console.log('error' + e); } } // for wav file, we get the sample rate if (file_ext == "wav") { for (let i = 0; i < len; i++) { let fileAudio = new FileReader(); fileAudio.readAsArrayBuffer(this.files[i]); fileAudio.onload = function () { audioblob = new Uint8Array(fileAudio.result); var info = readWavInfo(audioblob); file_sample_rate = info.sampleRate; } } } } function play_file() { var audioblob = new Blob([new Uint8Array(file_data_array)], { type: "audio/wav" }); var audio_record = document.getElementById('audio_record'); audio_record.src = (window.URL || webkitURL).createObjectURL(audioblob); audio_record.controls = true; } function start_file_send() { sampleBuf = new Uint8Array(file_data_array); var chunk_size = 960; // for asr chunk_size [5, 10, 5] while (sampleBuf.length >= chunk_size) { sendBuf = sampleBuf.slice(0, chunk_size); totalsend = totalsend + sampleBuf.length; sampleBuf = sampleBuf.slice(chunk_size, sampleBuf.length); wsconnecter.wsSend(sendBuf); } stop(); } function stop() { var chunk_size = new Array(5, 10, 5); var request = { "chunk_size": chunk_size, "wav_name": "h5", "is_speaking": false, "chunk_interval": 10, "mode": getAsrMode(), }; if (sampleBuf.length > 0) { wsconnecter.wsSend(sampleBuf); sampleBuf = new Int16Array(); } wsconnecter.wsSend(JSON.stringify(request)); // 控件状态更新 isRec = false; if (isfilemode == false) { //wait 3s for asr result setTimeout(function () { wsconnecter.wsStop(); }, 3000); rec.stop(function (blob, duration) { var audioBlob = Recorder.pcm2wav(data = { sampleRate: 16000, bitRate: 16, blob: blob }, function (theblob, duration) { console.log(theblob); var audio_record = document.getElementById('audio_record'); audio_record.src = (window.URL || webkitURL).createObjectURL(theblob); audio_record.controls = true; }, function (msg) { console.log(msg); } ); }, function (errMsg) { console.log("errMsg: " + errMsg); }); } // 停止连接 } function getAsrMode() { return 'offline'; } function getHotwords() { return null } function handleWithTimestamp(tmptext, tmptime) { if (tmptime == null || tmptime == "undefined" || tmptext.length <= 0) { return tmptext; } tmptext = tmptext.replace(/。|?|,|、|\?|\.|\ /g, ","); // in case there are a lot of "。" var words = tmptext.split(","); // split to chinese sentence or english words var jsontime = JSON.parse(tmptime); //JSON.parse(tmptime.replace(/\]\]\[\[/g, "],[")); // in case there are a lot segments by VAD var char_index = 0; // index for timestamp var text_withtime = ""; for (var i = 0; i < words.length; i++) { if (words[i] == "undefined" || words[i].length <= 0) { continue; } if (/^[a-zA-Z]+$/.test(words[i])) { // if it is english text_withtime = text_withtime + jsontime[char_index][0] / 1000 + ":" + words[i] + "\n"; char_index = char_index + 1; //for english, timestamp unit is about a word } else { text_withtime = text_withtime + jsontime[char_index][0] / 1000 + ":" + words[i] + "\n"; char_index = char_index + words[i].length; //for chinese, timestamp unit is about a char } } return text_withtime; } // 语音识别结果; 对jsonMsg数据解析,将识别结果附加到编辑框中 function getJsonMessage(jsonMsg) { var rectxt = "" + JSON.parse(jsonMsg.data)['text']; var asrmodel = JSON.parse(jsonMsg.data)['mode']; var is_final = JSON.parse(jsonMsg.data)['is_final']; var timestamp = JSON.parse(jsonMsg.data)['timestamp']; if (asrmodel == "2pass-offline" || asrmodel == "offline") { offline_text = offline_text + handleWithTimestamp(rectxt, timestamp); //rectxt; //.replace(/ +/g,""); rec_text = offline_text; } else { rec_text = rec_text + rectxt; } videoText = rec_text; if (is_final == true) { play_file(); wsconnecter.wsStop(); btnConnect.disabled = false; } } // 连接状态响应 function getConnState(connState) { if (connState === 0) start_file_send(); } // 识别启动、停止、清空操作 function start() { var ret = wsconnecter.wsStart();//启动连接 return ret == 1 ? 1 : 0; } function recProcess(buffer, powerLevel, bufferDuration, bufferSampleRate, newBufferIdx, asyncEnd) { if (isRec === true) { var data_48k = buffer[buffer.length - 1]; var array_48k = new Array(data_48k); var data_16k = Recorder.SampleData(array_48k, bufferSampleRate, 16000).data; sampleBuf = Int16Array.from([...sampleBuf, ...data_16k]); var chunk_size = 960; // for asr chunk_size [5, 10, 5] while (sampleBuf.length >= chunk_size) { sendBuf = sampleBuf.slice(0, chunk_size); sampleBuf = sampleBuf.slice(chunk_size, sampleBuf.length); wsconnecter.wsSend(sendBuf); } } } function getUseITN() { return false; }