main.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /**
  2. * Copyright FunASR (https://github.com/alibaba-damo-academy/FunASR). All Rights
  3. * Reserved. MIT License (https://opensource.org/licenses/MIT)
  4. */
  5. /* 2022-2023 by zhaoming,mali aihealthx.com */
  6. // 连接; 定义socket连接类对象与语音对象
  7. var wsconnecter = new WebSocketConnectMethod({msgHandle:getJsonMessage,stateHandle:getConnState});
  8. var audioBlob;
  9. // 录音; 定义录音对象,wav格式
  10. var rec = Recorder({
  11. type:"pcm",
  12. bitRate:16,
  13. sampleRate:16000,
  14. onProcess:recProcess
  15. });
  16. var sampleBuf=new Int16Array();
  17. // 定义按钮响应事件
  18. var btnStart = document.getElementById('btnStart');
  19. btnStart.onclick = record;
  20. var btnStop = document.getElementById('btnStop');
  21. btnStop.onclick = stop;
  22. btnStop.disabled = true;
  23. btnStart.disabled = true;
  24. btnConnect= document.getElementById('btnConnect');
  25. btnConnect.onclick = start;
  26. var awsslink= document.getElementById('wsslink');
  27. var rec_text=""; // for online rec asr result
  28. var offline_text=""; // for offline rec asr result
  29. var info_div = document.getElementById('info_div');
  30. var upfile = document.getElementById('upfile');
  31. var isfilemode=false; // if it is in file mode
  32. var file_ext="";
  33. var file_data_array; // array to save file data
  34. var totalsend=0;
  35. var now_ipaddress=window.location.href;
  36. now_ipaddress=now_ipaddress.replace("https://","wss://");
  37. now_ipaddress=now_ipaddress.replace("static/index.html","");
  38. var localport=window.location.port;
  39. now_ipaddress=now_ipaddress.replace(localport,"10095");
  40. document.getElementById('wssip').value=now_ipaddress;
  41. addresschange();
  42. function addresschange()
  43. {
  44. var Uri = document.getElementById('wssip').value;
  45. document.getElementById('info_wslink').innerHTML="点此处手工授权(IOS手机)";
  46. Uri=Uri.replace(/wss/g,"https");
  47. console.log("addresschange uri=",Uri);
  48. awsslink.onclick=function(){
  49. window.open(Uri, '_blank');
  50. }
  51. }
  52. upfile.onclick=function()
  53. {
  54. btnStart.disabled = true;
  55. btnStop.disabled = true;
  56. btnConnect.disabled=false;
  57. }
  58. upfile.onchange = function () {
  59.       var len = this.files.length;
  60. for(let i = 0; i < len; i++) {
  61. let fileAudio = new FileReader();
  62. fileAudio.readAsArrayBuffer(this.files[i]);
  63. file_ext=this.files[i].name.split('.').pop().toLowerCase();
  64. if(file_ext==="wav"){
  65. file_ext="pcm";
  66. }
  67. fileAudio.onload = function() {
  68. var audioblob= fileAudio.result;
  69. file_data_array=audioblob;
  70. console.log(audioblob);
  71. info_div.innerHTML='请点击连接进行识别';
  72. }
  73.           fileAudio.onerror = function(e) {
  74.             console.log('error' + e);
  75.           }
  76. }
  77. }
  78. function play_file()
  79. {
  80. var audioblob=new Blob( [ new Uint8Array(file_data_array)] , {type :"audio/wav"});
  81. var audio_record = document.getElementById('audio_record');
  82. audio_record.src = (window.URL||webkitURL).createObjectURL(audioblob);
  83. audio_record.controls=true;
  84. //audio_record.play(); //not auto play
  85. }
  86. function start_file_send()
  87. {
  88. sampleBuf=new Int16Array( file_data_array );
  89. var chunk_size=960; // for asr chunk_size [5, 10, 5]
  90. while(sampleBuf.length>=chunk_size){
  91. sendBuf=sampleBuf.slice(0,chunk_size);
  92. totalsend=totalsend+sampleBuf.length;
  93. sampleBuf=sampleBuf.slice(chunk_size,sampleBuf.length);
  94. wsconnecter.wsSend(sendBuf);
  95. }
  96. stop();
  97. }
  98. function on_recoder_mode_change()
  99. {
  100. var item = null;
  101. var obj = document.getElementsByName("recoder_mode");
  102. for (var i = 0; i < obj.length; i++) { //遍历Radio
  103. if (obj[i].checked) {
  104. item = obj[i].value;
  105. break;
  106. }
  107. }
  108. if(item=="mic")
  109. {
  110. document.getElementById("mic_mode_div").style.display = 'block';
  111. document.getElementById("rec_mode_div").style.display = 'none';
  112. btnStart.disabled = true;
  113. btnStop.disabled = true;
  114. btnConnect.disabled=false;
  115. isfilemode=false;
  116. }
  117. else
  118. {
  119. document.getElementById("mic_mode_div").style.display = 'none';
  120. document.getElementById("rec_mode_div").style.display = 'block';
  121. btnStart.disabled = true;
  122. btnStop.disabled = true;
  123. btnConnect.disabled=true;
  124. isfilemode=true;
  125. info_div.innerHTML='请点击选择文件';
  126. }
  127. }
  128. function getHotwords(){
  129. var obj = document.getElementById("varHot");
  130. if(typeof(obj) == 'undefined' || obj==null || obj.value.length<=0){
  131. return "";
  132. }
  133. let val = obj.value.toString();
  134. console.log("hotwords="+val);
  135. return val;
  136. }
  137. function getAsrMode(){
  138. var item = null;
  139. var obj = document.getElementsByName("asr_mode");
  140. for (var i = 0; i < obj.length; i++) { //遍历Radio
  141. if (obj[i].checked) {
  142. item = obj[i].value;
  143. break;
  144. }
  145. }
  146. if(isfilemode)
  147. {
  148. item= "offline";
  149. }
  150. console.log("asr mode"+item);
  151. return item;
  152. }
  153. function handleWithTimestamp(tmptext,tmptime)
  154. {
  155. console.log( "tmptext: " + tmptext);
  156. console.log( "tmptime: " + tmptime);
  157. if(tmptime==null || tmptime=="undefined" || tmptext.length<=0)
  158. {
  159. return tmptext;
  160. }
  161. tmptext=tmptext.replace(/。/g, ","); // in case there are a lot of "。"
  162. var words=tmptext.split(",");
  163. var jsontime=JSON.parse(tmptime); //JSON.parse(tmptime.replace(/\]\]\[\[/g, "],[")); // in case there are a lot segments by VAD
  164. var char_index=0;
  165. var text_withtime="";
  166. for(var i=0;i<words.length;i++)
  167. {
  168. if(words[i]=="undefined" || words[i].length<=0)
  169. {
  170. continue;
  171. }
  172. console.log("words===",words[i]);
  173. console.log( "words: " + words[i]+",time="+jsontime[char_index][0]/1000);
  174. text_withtime=text_withtime+jsontime[char_index][0]/1000+":"+words[i]+"\n";
  175. char_index=char_index+words[i].length;
  176. }
  177. return text_withtime;
  178. }
  179. // 语音识别结果; 对jsonMsg数据解析,将识别结果附加到编辑框中
  180. function getJsonMessage( jsonMsg ) {
  181. //console.log(jsonMsg);
  182. console.log( "message: " + JSON.parse(jsonMsg.data)['text'] );
  183. var rectxt=""+JSON.parse(jsonMsg.data)['text'];
  184. var asrmodel=JSON.parse(jsonMsg.data)['mode'];
  185. var is_final=JSON.parse(jsonMsg.data)['is_final'];
  186. var timestamp=JSON.parse(jsonMsg.data)['timestamp'];
  187. if(asrmodel=="2pass-offline" || asrmodel=="offline")
  188. {
  189. offline_text=offline_text+handleWithTimestamp(rectxt,timestamp); //rectxt; //.replace(/ +/g,"");
  190. rec_text=offline_text;
  191. }
  192. else
  193. {
  194. rec_text=rec_text+rectxt; //.replace(/ +/g,"");
  195. }
  196. var varArea=document.getElementById('varArea');
  197. varArea.value=rec_text;
  198. console.log( "offline_text: " + asrmodel+","+offline_text);
  199. console.log( "rec_text: " + rec_text);
  200. if (isfilemode==true && is_final==false){
  201. console.log("call stop ws!");
  202. play_file();
  203. wsconnecter.wsStop();
  204. info_div.innerHTML="请点击连接";
  205. btnStart.disabled = true;
  206. btnStop.disabled = true;
  207. btnConnect.disabled=false;
  208. }
  209. }
  210. // 连接状态响应
  211. function getConnState( connState ) {
  212. if ( connState === 0 ) { //on open
  213. info_div.innerHTML='连接成功!请点击开始';
  214. if (isfilemode==true){
  215. info_div.innerHTML='请耐心等待,大文件等待时间更长';
  216. start_file_send();
  217. }
  218. else
  219. {
  220. btnStart.disabled = false;
  221. btnStop.disabled = true;
  222. btnConnect.disabled=true;
  223. }
  224. } else if ( connState === 1 ) {
  225. //stop();
  226. } else if ( connState === 2 ) {
  227. stop();
  228. console.log( 'connecttion error' );
  229. alert("连接地址"+document.getElementById('wssip').value+"失败,请检查asr地址和端口。或试试界面上手动授权,再连接。");
  230. btnStart.disabled = true;
  231. btnStop.disabled = true;
  232. btnConnect.disabled=false;
  233. info_div.innerHTML='请点击连接';
  234. }
  235. }
  236. function record()
  237. {
  238. rec.open( function(){
  239. rec.start();
  240. console.log("开始");
  241. btnStart.disabled = true;
  242. btnStop.disabled = false;
  243. btnConnect.disabled=true;
  244. });
  245. }
  246. // 识别启动、停止、清空操作
  247. function start() {
  248. // 清除显示
  249. clear();
  250. //控件状态更新
  251. console.log("isfilemode"+isfilemode);
  252. //启动连接
  253. var ret=wsconnecter.wsStart();
  254. // 1 is ok, 0 is error
  255. if(ret==1){
  256. info_div.innerHTML="正在连接asr服务器,请等待...";
  257. isRec = true;
  258. btnStart.disabled = true;
  259. btnStop.disabled = true;
  260. btnConnect.disabled=true;
  261. return 1;
  262. }
  263. else
  264. {
  265. info_div.innerHTML="请点击开始";
  266. btnStart.disabled = true;
  267. btnStop.disabled = true;
  268. btnConnect.disabled=false;
  269. return 0;
  270. }
  271. }
  272. function stop() {
  273. var chunk_size = new Array( 5, 10, 5 );
  274. var request = {
  275. "chunk_size": chunk_size,
  276. "wav_name": "h5",
  277. "is_speaking": false,
  278. "chunk_interval":10,
  279. "mode":getAsrMode(),
  280. };
  281. console.log(request);
  282. if(sampleBuf.length>0){
  283. wsconnecter.wsSend(sampleBuf);
  284. console.log("sampleBuf.length"+sampleBuf.length);
  285. sampleBuf=new Int16Array();
  286. }
  287. wsconnecter.wsSend( JSON.stringify(request) );
  288. // 控件状态更新
  289. isRec = false;
  290. info_div.innerHTML="发送完数据,请等候,正在识别...";
  291. if(isfilemode==false){
  292. btnStop.disabled = true;
  293. btnStart.disabled = true;
  294. btnConnect.disabled=true;
  295. //wait 3s for asr result
  296. setTimeout(function(){
  297. console.log("call stop ws!");
  298. wsconnecter.wsStop();
  299. btnConnect.disabled=false;
  300. info_div.innerHTML="请点击连接";}, 3000 );
  301. rec.stop(function(blob,duration){
  302. console.log(blob);
  303. var audioBlob = Recorder.pcm2wav(data = {sampleRate:16000, bitRate:16, blob:blob},
  304. function(theblob,duration){
  305. console.log(theblob);
  306. var audio_record = document.getElementById('audio_record');
  307. audio_record.src = (window.URL||webkitURL).createObjectURL(theblob);
  308. audio_record.controls=true;
  309. //audio_record.play();
  310. } ,function(msg){
  311. console.log(msg);
  312. }
  313. );
  314. },function(errMsg){
  315. console.log("errMsg: " + errMsg);
  316. });
  317. }
  318. // 停止连接
  319. }
  320. function clear() {
  321. var varArea=document.getElementById('varArea');
  322. varArea.value="";
  323. rec_text="";
  324. offline_text="";
  325. }
  326. function recProcess( buffer, powerLevel, bufferDuration, bufferSampleRate,newBufferIdx,asyncEnd ) {
  327. if ( isRec === true ) {
  328. var data_48k = buffer[buffer.length-1];
  329. var array_48k = new Array(data_48k);
  330. var data_16k=Recorder.SampleData(array_48k,bufferSampleRate,16000).data;
  331. sampleBuf = Int16Array.from([...sampleBuf, ...data_16k]);
  332. var chunk_size=960; // for asr chunk_size [5, 10, 5]
  333. info_div.innerHTML=""+bufferDuration/1000+"s";
  334. while(sampleBuf.length>=chunk_size){
  335. sendBuf=sampleBuf.slice(0,chunk_size);
  336. sampleBuf=sampleBuf.slice(chunk_size,sampleBuf.length);
  337. wsconnecter.wsSend(sendBuf);
  338. }
  339. }
  340. }