/****************** 《【教程】【ASR】实时语音识别、音频文件转文字-阿里云版》 作者:高坚果 时间:2020-7-22 22:37:09 通过阿里云语音识别(语音转文字)插件 /src/extensions/asr.aliyun.short.js,可实现实时语音识别、单个语音文件转文字。 只需要后端提供一个Token生成接口,就能进行语音识别,可直接参考或本地运行此NodeJs后端测试程序:/assets/demo-asr/NodeJsServer_asr.aliyun.short.js,配置好代码里的阿里云账号后,在目录内直接命令行执行`node NodeJsServer_asr.aliyun.short.js`即可运行提供本地测试接口。 目前暂未提供其他版本的语音识别插件,比如腾讯云、讯飞等,搭配使用Recorder的onProcess实时处理,可根据自己的业务需求选择对应厂家自行对接即可,如需定制开发请联系作者。 ******************/ var asr; /*************单个语音文件转文字例子,你也可以录完音后再一次性进行识别***************/ //将录音文件进行语音识别,支持的录音格式取决于浏览器的支持,兼容性mp3最好,wav次之,其他格式不一定能够解码 var fileToText=function(audioBlob,fileName){ if(asr){ Runtime.Log("上次asr未关闭",1); return; }; Runtime.Log("开始识别文件:《"+fileName+"》,asrProcess中已限制最多识别前60*3-5*(3-1)=170秒 ..."); $(".recAsrTxt").text(""); $(".recAsrTime").html(""); var url=$(".asrTokenApi").val(); var urlReq=null; if(/^\s*\{.*\}\s*$/.test(url)){ //这里是输入框里面填的json数据,直接success回调即可 urlReq=function(url,args,success,fail){ var data; try{ data=JSON.parse(url); }catch(e){}; if(!data || !data.appkey || !data.token){ fail("填写的json数据"+(!data?"解析失败":"中缺少appkey或token")); }else{ success({ appkey:data.appkey, token:data.token }); } } }; var asr2=asr=Recorder.ASR_Aliyun_Short({ tokenApi:url ,apiArgs:{ lang:$("[name=arsLang]:checked").val() ,xxx:"其他请求参数" } ,apiRequest:urlReq //如果提供了token数据,可不发起api请求 ,asrProcess:function(text,nextDuration,abortMsg){ /***识别中间结果实回调,必须返回true才能继续识别,否则立即超时停止识别***/ if(abortMsg){ //语音识别中途出错,单个文件识别无需任何处理,会自动回调结果 Runtime.Log("[asrProcess回调]被终止:"+abortMsg,1); return false; }; $(".recAsrTxt").text(text); $(".recAsrTime").html("识别时长: "+formatTime(asr2.asrDuration()) +" 已发送数据时长: "+formatTime(asr2.sendDuration())); return nextDuration<=3*60*1000;//允许识别3分钟的识别时长(比音频时长小5*2秒) } ,log:function(msg,color){ Runtime.Log(''+msg+'',color); } }); Runtime.Log("语言:"+asr.set.apiArgs.lang); //语音文件识别只需调用audioToText即可完成识别,简单快速 asr.audioToText(audioBlob,function(text,abortMsg){ asr=null; if(abortMsg){ Runtime.Log("发现识别中途被终止(一般无需特别处理):"+abortMsg,"#fb8"); }; Runtime.Log("文件识别最终结果:"+text, 2); },function(errMsg){ asr=null; Runtime.Log("文件识别结束失败:"+errMsg, 1); }); }; /*************单个语音文件转文字例子 END***************/ /*************实时语音识别例子*************************/ /******界面交互处理、打开录音权限******/ //使用长按录音的方式,可有效控制转换时长,避免不必要的资源浪费 //长按按钮功能已经封装好了,直接调用 BindTouchButton 即可快速实现长按 var bindTouchButton=function(){ DemoFragment.BindTouchButton( "recTouchBtn" ,"按住进行录音+识别" ,"松开结束" ,{} ,asrOnTouchStart ,asrOnTouchEnd ); }; var rec; /**打开录音,先得到录音权限**/ function recOpenClick(){ $(".recOpenBtn").hide(); $(".recCloseBtn").show(); var end=function(isOk){ if(isOk){ $(".asrStartBtns").show(); $(".asrStopBtn").show(); }; }; rec=Recorder({ type:"wav" ,sampleRate:16000 ,bitRate:16 ,onProcess:function(buffers,powerLevel,bufferDuration,bufferSampleRate,newBufferIdx,asyncEnd){ Runtime.Process.apply(null,arguments); //实时推入asr处理。asr.input随时都可以调用,就算asr并未start,会缓冲到asr.start完成然后将已input的数据进行识别 if(asr){ //buffers是从录音开头到现在的缓冲,因此需要提供 buffersOffset=newBufferIdx asr.input(buffers, bufferSampleRate, newBufferIdx); }; } }); var t=setTimeout(function(){ recAsrStatus("无法录音:权限请求被忽略(超时假装手动点击了确认对话框)",1); rec=null; end(false); },8000); recAsrStatus("正在打开录音权限,请稍后..."); rec.open(function(){//打开麦克风授权获得相关资源 clearTimeout(t); recAsrStatus("录音已打开,可以长按录音+识别了",2); end(true); },function(msg,isUserNotAllow){//用户拒绝未授权或不支持 clearTimeout(t); recAsrStatus((isUserNotAllow?"UserNotAllow,":"")+"无法录音:"+msg, 1); rec=null; end(false); }); }; var recCloseClick=function(){ $(".recOpenBtn").show(); $(".recCloseBtn").hide(); $(".asrStartBtns").hide(); if(rec){ Runtime.Log("已关闭录音"); rec.close(); rec=null; }else{ Runtime.Log("未打开录音",1); } }; //免长按,这里就是调用的长按时的两个状态方法 功能是一样的 var asrStartClick_NoTouch=function(){ asrOnTouchStart(function(){}); }; var asrStopClick_NoTouch=function(){ if(!asr){ Runtime.Log("未开始识别",1); return; }; asrOnTouchEnd(false,true); }; /******核心的长按录音识别******/ /**长按开始录音**/ var asrOnTouchStart=function(cancel){ if(!rec){ cancel("未打开录音"); recAsrStatus("未打开录音",1); return; }; rec.s_isStart=false; if(asr){ cancel("上次asr未关闭"); recAsrStatus("上次asr未关闭",1); return; }; $(".recAsrTxt").text(""); $(".recAsrTime").html(""); var url=$(".asrTokenApi").val(); var urlReq=null; if(/^\s*\{.*\}\s*$/.test(url)){ //这里是输入框里面填的json数据,直接success回调即可 urlReq=function(url,args,success,fail){ var data; try{ data=JSON.parse(url); }catch(e){}; if(!data || !data.appkey || !data.token){ fail("填写的json数据"+(!data?"解析失败":"中缺少appkey或token")); }else{ success({ appkey:data.appkey, token:data.token }); } } }; //创建语音识别对象,每次识别都要新建,asr不能共用 var asr2=asr=Recorder.ASR_Aliyun_Short({ tokenApi:url ,apiArgs:{ lang:$("[name=arsLang]:checked").val() ,xxx:"其他请求参数" } ,apiRequest:urlReq //如果提供了token数据,可不发起api请求 ,asrProcess:function(text,nextDuration,abortMsg){ /***实时识别结果,必须返回true才能继续识别,否则立即超时停止识别***/ if(abortMsg){ //语音识别中途出错 recAsrStatus("[asrProcess回调]被终止:"+abortMsg,1); cancel("语音识别出错");//立即结束录音,就算继续录音也不会识别 return false; }; $(".recAsrTxt").text(text); $(".recAsrTime").html("识别时长: "+formatTime(asr2.asrDuration()) +" 已发送数据时长: "+formatTime(asr2.sendDuration())); return nextDuration<=2*60*1000;//允许识别2分钟的识别时长(比录音时长小5秒) } ,log:function(msg,color){ Runtime.Log(''+msg+'',color); } }); Runtime.Log("语言:"+asr.set.apiArgs.lang); recAsrStatus("连接服务器中,请稍后..."); //打开语音识别,建议先打开asr,成功后再开始录音 asr.start(function(){//无需特殊处理start和stop的关系,只要调用了stop,会阻止未完成的start,不会执行回调 //开始录音 Runtime.Log("开始录音..."); rec.start(); rec.s_isStart=true; recAsrStatus("滴~~ 已开始语音识别,请讲话(asrProcess中已限制最多识别60*2-5*(2-1)=115秒)...",2); },function(errMsg){ recAsrStatus("语音识别开始失败,请重试:"+errMsg,1); cancel("语音识别开始失败"); }); }; /**松开停止录音**/ var asrOnTouchEnd=function(isCancel,isUser){ recAsrStatus(isCancel?"已取消":isUser?"已松开":"长按被取消",isUser?0:1); var asr2=asr;asr=null;//先干掉asr,防止重复stop if(!asr2){ Runtime.Log("未开始识别",1); }else{ //asr.stop 和 rec.stop 无需区分先后,同时执行就ok了 asr2.stop(function(text,abortMsg){ if(abortMsg){ abortMsg="发现识别中途被终止(一般无需特别处理):"+abortMsg; }; recAsrStatus("语音识别完成"+(abortMsg?","+abortMsg:""),abortMsg?"#f60":2); Runtime.Log("识别最终结果:"+text, 2); },function(errMsg){ recAsrStatus("语音识别"+(!isUser?"被取消":"结束失败")+":"+errMsg, 1); }); }; var rec2=rec; if(rec2.s_isStart){ rec2.s_isStart=false; rec2.stop(function(blob,duration){ Runtime.LogAudio(blob,duration,rec2); },function(errMsg){ Runtime.Log("录音失败:"+errMsg, 1); }); }; }; /**更新状态**/ var recAsrStatus=function(html,color){ var elem=document.querySelector(".recAsrStatus"); elem.style.color=color==1?"red":color==2?"#0b1":(color||null); elem.innerHTML=html; Runtime.Log(html,color); }; /*************实时语音识别例子 END***************/ //破坏环境,测试错误是否被正确处理 var killToken=function(){ if(!asr){ Runtime.Log("未开始语音识别",1); return; } asr.set.apiRequest=function(url,args,success,fail){ fail("不让获取Token"); } Runtime.Log("已设置ASR的apiRequest,下一分钟将无法获得Token"); }; var killWs=function(){ if(!asr || !asr.wsCur){ Runtime.Log("未开始语音识别",1); return; } asr.wsCur.close(); Runtime.Log("已强制关闭了ASR的WebSocket连接"); }; //=====以下代码无关紧要,音频数据源和界面================== //加载录音框架 Runtime.Import([ {url:RootFolder+"/src/recorder-core.js",check:function(){return !window.Recorder}} ,{url:RootFolder+"/src/engine/wav.js",check:function(){return !Recorder.prototype.wav}} ,{url:RootFolder+"/src/extensions/asr.aliyun.short.js",check:function(){return !Recorder.ASR_Aliyun_Short}} ,{url:RootFolder+"/assets/runtime-codes/fragment.touch_button.js",check:function(){return !window.DemoFragment||!DemoFragment.BindTouchButton}}//引入BindTouchButton ]); //显示控制按钮 Runtime.Ctrls([ {html:'\