| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566 |
- /**
- * 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;
- // 录音; 定义录音对象,wav格式
- var rec = Recorder({
- type:"pcm",
- bitRate:16,
- sampleRate:16000,
- onProcess:recProcess
- });
-
-
-
- var sampleBuf=new Int16Array();
- // 定义按钮响应事件
- var btnStart = document.getElementById('btnStart');
- btnStart.onclick = record;
- var btnStop = document.getElementById('btnStop');
- btnStop.onclick = stop;
- btnStop.disabled = true;
- btnStart.disabled = true;
-
- btnConnect= document.getElementById('btnConnect');
- btnConnect.onclick = start;
- var awsslink= document.getElementById('wsslink');
-
- var rec_text=""; // for online rec asr result
- var offline_text=""; // for offline rec asr result
- var info_div = document.getElementById('info_div');
- var upfile = document.getElementById('upfile');
-
- var isfilemode=false; // if it is in file mode
- 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;
- var now_ipaddress=window.location.href;
- now_ipaddress=now_ipaddress.replace("https://","wss://");
- now_ipaddress=now_ipaddress.replace("static/index.html","");
- var localport=window.location.port;
- now_ipaddress=now_ipaddress.replace(localport,"10095");
- document.getElementById('wssip').value=now_ipaddress;
- addresschange();
- function addresschange()
- {
-
- var Uri = document.getElementById('wssip').value;
- document.getElementById('info_wslink').innerHTML="点此处手工授权(IOS手机)";
- Uri=Uri.replace(/wss/g,"https");
- console.log("addresschange uri=",Uri);
-
- awsslink.onclick=function(){
- window.open(Uri, '_blank');
- }
-
- }
- upfile.onclick=function()
- {
- btnStart.disabled = true;
- btnStop.disabled = true;
- btnConnect.disabled=false;
-
- }
- // from https://github.com/xiangyuecn/Recorder/tree/master
- 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;
- };
- upfile.onchange = function () {
- 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;
-
-
- info_div.innerHTML='请点击连接进行识别';
-
- }
- 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);
-
- // for wav file, we can get the sample rate
- var info=readWavInfo(audioblob);
- console.log(info);
- 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;
- //audio_record.play(); //not auto play
- }
- 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 on_recoder_mode_change()
- {
- var item = null;
- var obj = document.getElementsByName("recoder_mode");
- for (var i = 0; i < obj.length; i++) { //遍历Radio
- if (obj[i].checked) {
- item = obj[i].value;
- break;
- }
-
- }
- if(item=="mic")
- {
- document.getElementById("mic_mode_div").style.display = 'block';
- document.getElementById("rec_mode_div").style.display = 'none';
-
-
- btnStart.disabled = true;
- btnStop.disabled = true;
- btnConnect.disabled=false;
- isfilemode=false;
- }
- else
- {
- document.getElementById("mic_mode_div").style.display = 'none';
- document.getElementById("rec_mode_div").style.display = 'block';
-
- btnStart.disabled = true;
- btnStop.disabled = true;
- btnConnect.disabled=true;
- isfilemode=true;
- info_div.innerHTML='请点击选择文件';
-
-
- }
- }
- function getHotwords(){
-
- var obj = document.getElementById("varHot");
- if(typeof(obj) == 'undefined' || obj==null || obj.value.length<=0){
- return null;
- }
- let val = obj.value.toString();
-
- console.log("hotwords="+val);
- let items = val.split(/[(\r\n)\r\n]+/); //split by \r\n
- var jsonresult = {};
- const regexNum = /^[0-9]*$/; // test number
- for (item of items) {
-
- let result = item.split(" ");
- if(result.length>=2 && regexNum.test(result[result.length-1]))
- {
- var wordstr="";
- for(var i=0;i<result.length-1;i++)
- wordstr=wordstr+result[i]+" ";
-
- jsonresult[wordstr.trim()]= parseInt(result[result.length-1]);
- }
- }
- console.log("jsonresult="+JSON.stringify(jsonresult));
- return JSON.stringify(jsonresult);
- }
- function getAsrMode(){
- var item = null;
- var obj = document.getElementsByName("asr_mode");
- for (var i = 0; i < obj.length; i++) { //遍历Radio
- if (obj[i].checked) {
- item = obj[i].value;
- break;
- }
-
- }
- if(isfilemode)
- {
- item= "offline";
- }
- console.log("asr mode"+item);
-
- return item;
- }
-
- function handleWithTimestamp(tmptext,tmptime)
- {
- console.log( "tmptext: " + tmptext);
- console.log( "tmptime: " + 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;
- }
- console.log("words===",words[i]);
- console.log( "words: " + words[i]+",time="+jsontime[char_index][0]/1000);
- 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{
- // if it is chinese
- 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 ) {
- //console.log(jsonMsg);
- console.log( "message: " + JSON.parse(jsonMsg.data)['text'] );
- 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; //.replace(/ +/g,"");
- }
- var varArea=document.getElementById('varArea');
-
- varArea.value=rec_text;
- console.log( "offline_text: " + asrmodel+","+offline_text);
- console.log( "rec_text: " + rec_text);
- if (isfilemode==true && is_final==false){
- console.log("call stop ws!");
- play_file();
- wsconnecter.wsStop();
-
- info_div.innerHTML="请点击连接";
-
- btnStart.disabled = true;
- btnStop.disabled = true;
- btnConnect.disabled=false;
- }
-
-
-
- }
- // 连接状态响应
- function getConnState( connState ) {
- if ( connState === 0 ) { //on open
-
-
- info_div.innerHTML='连接成功!请点击开始';
- if (isfilemode==true){
- info_div.innerHTML='请耐心等待,大文件等待时间更长';
- start_file_send();
- }
- else
- {
- btnStart.disabled = false;
- btnStop.disabled = true;
- btnConnect.disabled=true;
- }
- } else if ( connState === 1 ) {
- //stop();
- } else if ( connState === 2 ) {
- stop();
- console.log( 'connecttion error' );
-
- alert("连接地址"+document.getElementById('wssip').value+"失败,请检查asr地址和端口。或试试界面上手动授权,再连接。");
- btnStart.disabled = true;
- btnStop.disabled = true;
- btnConnect.disabled=false;
-
-
- info_div.innerHTML='请点击连接';
- }
- }
- function record()
- {
-
- rec.open( function(){
- rec.start();
- console.log("开始");
- btnStart.disabled = true;
- btnStop.disabled = false;
- btnConnect.disabled=true;
- });
-
- }
-
- // 识别启动、停止、清空操作
- function start() {
-
- // 清除显示
- clear();
- //控件状态更新
- console.log("isfilemode"+isfilemode);
-
- //启动连接
- var ret=wsconnecter.wsStart();
- // 1 is ok, 0 is error
- if(ret==1){
- info_div.innerHTML="正在连接asr服务器,请等待...";
- isRec = true;
- btnStart.disabled = true;
- btnStop.disabled = true;
- btnConnect.disabled=true;
-
- return 1;
- }
- else
- {
- info_div.innerHTML="请点击开始";
- btnStart.disabled = true;
- btnStop.disabled = true;
- btnConnect.disabled=false;
-
- return 0;
- }
- }
-
- 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(),
- };
- console.log(request);
- if(sampleBuf.length>0){
- wsconnecter.wsSend(sampleBuf);
- console.log("sampleBuf.length"+sampleBuf.length);
- sampleBuf=new Int16Array();
- }
- wsconnecter.wsSend( JSON.stringify(request) );
-
-
-
-
-
- // 控件状态更新
-
- isRec = false;
- info_div.innerHTML="发送完数据,请等候,正在识别...";
- if(isfilemode==false){
- btnStop.disabled = true;
- btnStart.disabled = true;
- btnConnect.disabled=true;
- //wait 3s for asr result
- setTimeout(function(){
- console.log("call stop ws!");
- wsconnecter.wsStop();
- btnConnect.disabled=false;
- info_div.innerHTML="请点击连接";}, 3000 );
-
-
-
- rec.stop(function(blob,duration){
-
- console.log(blob);
- 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;
- //audio_record.play();
-
- } ,function(msg){
- console.log(msg);
- }
- );
-
-
- },function(errMsg){
- console.log("errMsg: " + errMsg);
- });
- }
- // 停止连接
-
-
- }
- function clear() {
-
- var varArea=document.getElementById('varArea');
-
- varArea.value="";
- rec_text="";
- offline_text="";
-
- }
-
- 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]
- info_div.innerHTML=""+bufferDuration/1000+"s";
- while(sampleBuf.length>=chunk_size){
- sendBuf=sampleBuf.slice(0,chunk_size);
- sampleBuf=sampleBuf.slice(chunk_size,sampleBuf.length);
- wsconnecter.wsSend(sendBuf);
-
-
-
- }
-
-
-
- }
- }
|