xfyun-sdk
Version:
科大讯飞语音识别 SDK,支持浏览器中实时语音听写功能
3 lines (2 loc) • 12.8 kB
JavaScript
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("crypto-js"),require("react")):"function"==typeof define&&define.amd?define(["exports","crypto-js","react"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).XfyunSDK={},t.CryptoJS,t.React)}(this,(function(t,e,o){"use strict";function n(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var r=n(e),a=n(o),i=function(){return i=Object.assign||function(t){for(var e,o=1,n=arguments.length;o<n;o++)for(var r in e=arguments[o])Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t},i.apply(this,arguments)};function s(t,e,o,n){return new(o||(o=Promise))((function(r,a){function i(t){try{c(n.next(t))}catch(t){a(t)}}function s(t){try{c(n.throw(t))}catch(t){a(t)}}function c(t){var e;t.done?r(t.value):(e=t.value,e instanceof o?e:new o((function(t){t(e)}))).then(i,s)}c((n=n.apply(t,e||[])).next())}))}function c(t,e){var o,n,r,a={label:0,sent:function(){if(1&r[0])throw r[1];return r[1]},trys:[],ops:[]},i=Object.create(("function"==typeof Iterator?Iterator:Object).prototype);return i.next=s(0),i.throw=s(1),i.return=s(2),"function"==typeof Symbol&&(i[Symbol.iterator]=function(){return this}),i;function s(s){return function(c){return function(s){if(o)throw new TypeError("Generator is already executing.");for(;i&&(i=0,s[0]&&(a=0)),a;)try{if(o=1,n&&(r=2&s[0]?n.return:s[0]?n.throw||((r=n.return)&&r.call(n),0):n.next)&&!(r=r.call(n,s[1])).done)return r;switch(n=0,r&&(s=[2&s[0],r.value]),s[0]){case 0:case 1:r=s;break;case 4:return a.label++,{value:s[1],done:!1};case 5:a.label++,n=s[1],s=[0];continue;case 7:s=a.ops.pop(),a.trys.pop();continue;default:if(!(r=a.trys,(r=r.length>0&&r[r.length-1])||6!==s[0]&&2!==s[0])){a=0;continue}if(3===s[0]&&(!r||s[1]>r[0]&&s[1]<r[3])){a.label=s[1];break}if(6===s[0]&&a.label<r[1]){a.label=r[1],r=s;break}if(r&&a.label<r[2]){a.label=r[2],a.ops.push(s);break}r[2]&&a.ops.pop(),a.trys.pop();continue}s=e.call(t,a)}catch(t){s=[6,t],n=0}finally{o=r=0}if(5&s[0])throw s[1];return{value:s[0]?s[1]:void 0,done:!0}}([s,c])}}}function u(t,e,o){void 0===o&&(o="iat-api.xfyun.cn");var n="wss://"+o+"/v2/iat",a=(new Date).toUTCString(),i="host: ".concat(o,"\ndate: ").concat(a,"\nGET /v2/iat HTTP/1.1"),s=r.default.HmacSHA256(i,e),c=r.default.enc.Base64.stringify(s),u='api_key="'.concat(t,'", algorithm="').concat("hmac-sha256",'", headers="host date request-line", signature="').concat(c,'"'),d=btoa(u);return"".concat(n,"?authorization=").concat(encodeURI(d),"&date=").concat(encodeURI(a),"&host=").concat(encodeURI(o))}function d(t){for(var e=0,o=0;o<t.length;o++)e+=t[o]*t[o];return 100*Math.sqrt(e/t.length)}function l(t){for(var e=new Uint8Array(t),o="",n=0;n<e.byteLength;n++)o+=String.fromCharCode(e[n]);return window.btoa(o)}function h(t){return t&&t.ws?t.ws.map((function(t){return t.cw.map((function(t){return t.w})).join("")})).join(""):""}"function"==typeof SuppressedError&&SuppressedError;var p={language:"zh_cn",domain:"iat",accent:"mandarin",vadEos:3e3,maxAudioSize:1048576,autoStart:!1,audioFormat:"audio/L16;rate=16000"},f=function(){function t(t,e){if(void 0===e&&(e={}),this.websocket=null,this.recorder=null,this.audioContext=null,this.analyser=null,this.audioChunks=[],this.state="idle",this.audioDataQueue=[],this.recognitionResult="",this.volumeTimer=null,this.microphoneStream=null,!t.appId||!t.apiKey||!t.apiSecret)throw new Error("缺少必要参数: appId, apiKey, apiSecret 不能为空");this.options=i(i({},p),t),this.handlers=e,this.options.autoStart&&this.start()}return t.prototype.start=function(){return s(this,void 0,void 0,(function(){var t;return c(this,(function(e){switch(e.label){case 0:return e.trys.push([0,2,,3]),navigator.mediaDevices&&window.WebSocket?"idle"!==this.state&&"stopped"!==this.state&&"error"!==this.state?(this.handleError({code:10002,message:"语音识别已在进行中"}),[2]):(this.setState("connecting"),this.recognitionResult="",this.audioChunks=[],this.audioDataQueue=[],[4,this.initMicrophone()]):(this.handleError({code:10001,message:"浏览器不支持语音识别功能,请使用现代浏览器"}),[2]);case 1:return e.sent(),this.initWebSocket(),this.handlers.onStart&&this.handlers.onStart(),[3,3];case 2:return t=e.sent(),this.handleError({code:10003,message:"启动语音识别失败",data:t}),[3,3];case 3:return[2]}}))}))},t.prototype.stop=function(){var t=this;try{this.setState("stopped"),this.recorder&&"inactive"!==this.recorder.state&&this.recorder.stop(),this.volumeTimer&&(window.clearInterval(this.volumeTimer),this.volumeTimer=null),this.sendEndFrame(),setTimeout((function(){t.websocket&&(t.websocket.close(),t.websocket=null)}),1e3),this.microphoneStream&&(this.microphoneStream.getTracks().forEach((function(t){return t.stop()})),this.microphoneStream=null),this.audioContext&&(this.audioContext.close(),this.audioContext=null),this.handlers.onStop&&this.handlers.onStop()}catch(t){this.handleError({code:10004,message:"停止语音识别失败",data:t})}},t.prototype.getResult=function(){return this.recognitionResult},t.prototype.getState=function(){return this.state},t.prototype.clearResult=function(){this.recognitionResult=""},t.prototype.initMicrophone=function(){return s(this,void 0,void 0,(function(){var t,e,o=this;return c(this,(function(n){switch(n.label){case 0:return n.trys.push([0,2,,3]),t=this,[4,navigator.mediaDevices.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,autoGainControl:!0},video:!1})];case 1:return t.microphoneStream=n.sent(),this.audioContext=new(window.AudioContext||window.webkitAudioContext),this.analyser=this.audioContext.createAnalyser(),this.analyser.fftSize=2048,this.audioContext.createMediaStreamSource(this.microphoneStream).connect(this.analyser),this.recorder=new MediaRecorder(this.microphoneStream,{mimeType:"audio/webm"}),this.recorder.ondataavailable=function(t){if(t.data.size>0){o.audioChunks.push(t.data);var e=new FileReader;e.onload=function(){if("recording"===o.state&&e.result instanceof ArrayBuffer){var t=l(e.result);o.audioDataQueue.push(t),o.sendAudioData()}},e.readAsArrayBuffer(t.data)}},this.recorder.start(500),this.startVolumeDetection(),[3,3];case 2:throw e=n.sent(),new Error("获取麦克风权限失败: ".concat(e));case 3:return[2]}}))}))},t.prototype.initWebSocket=function(){var t=this;try{var e=u(this.options.apiKey,this.options.apiSecret);this.websocket=new WebSocket(e),this.websocket.onopen=function(){t.setState("connected"),t.sendStartFrame()},this.websocket.onmessage=function(e){try{var o=JSON.parse(e.data);if(0!==o.code)return void t.handleError({code:o.code,message:o.message||"识别错误"});if(o.data&&o.data.result){var n=h(o.data.result),r=o.data.result.ls;t.recognitionResult+=n,t.handlers.onRecognitionResult&&t.handlers.onRecognitionResult(n,r)}}catch(e){t.handleError({code:10005,message:"解析消息失败",data:e})}},this.websocket.onerror=function(e){t.handleError({code:10006,message:"WebSocket连接错误",data:e})},this.websocket.onclose=function(){"stopped"!==t.state&&"error"!==t.state&&t.setState("idle")}}catch(t){throw new Error("初始化WebSocket失败: ".concat(t))}},t.prototype.sendStartFrame=function(){if(this.websocket&&this.websocket.readyState===WebSocket.OPEN){var t={common:{app_id:this.options.appId},business:{language:this.options.language,domain:this.options.domain,accent:this.options.accent,vad_eos:this.options.vadEos,dwa:"wpgs",pd:"speech",ptt:0,rlang:"zh-cn",vinfo:1,nunum:1,speex_size:70,nbest:1,wbest:5},data:{status:0,format:this.options.audioFormat||"audio/L16;rate=16000",encoding:"raw"}};this.options.hotWords&&this.options.hotWords.length>0&&(t.business.hotwords=this.options.hotWords.join(",")),this.websocket.send(JSON.stringify(t)),this.setState("recording")}},t.prototype.sendAudioData=function(){if(this.websocket&&this.websocket.readyState===WebSocket.OPEN&&"recording"===this.state)for(;this.audioDataQueue.length>0;){var t=this.audioDataQueue.shift();if(t){var e={common:{app_id:this.options.appId},business:{language:this.options.language,domain:this.options.domain,accent:this.options.accent,vad_eos:this.options.vadEos,dwa:"wpgs",pd:"speech",ptt:0,rlang:"zh-cn",vinfo:1,nunum:1,speex_size:70,nbest:1,wbest:5},data:{status:1,format:this.options.audioFormat||"audio/L16;rate=16000",encoding:"raw",audio:t}};this.websocket.send(JSON.stringify(e))}}},t.prototype.sendEndFrame=function(){if(this.websocket&&this.websocket.readyState===WebSocket.OPEN){var t={common:{app_id:this.options.appId},business:{language:this.options.language,domain:this.options.domain,accent:this.options.accent,vad_eos:this.options.vadEos,dwa:"wpgs",pd:"speech",ptt:0,rlang:"zh-cn",vinfo:1,nunum:1,speex_size:70,nbest:1,wbest:5},data:{status:2,format:this.options.audioFormat||"audio/L16;rate=16000",encoding:"raw",audio:""}};this.websocket.send(JSON.stringify(t))}},t.prototype.startVolumeDetection=function(){var t=this;if(this.analyser){var e=this.analyser.frequencyBinCount,o=new Float32Array(e);this.volumeTimer=window.setInterval((function(){if(t.analyser&&"recording"===t.state){t.analyser.getFloatTimeDomainData(o);var e=d(o);t.handlers.onProcess&&t.handlers.onProcess(e)}}),100)}},t.prototype.setState=function(t){this.state=t,this.handlers.onStateChange&&this.handlers.onStateChange(t)},t.prototype.handleError=function(t){this.setState("error"),this.handlers.onError&&this.handlers.onError(t),console.error("讯飞语音识别错误:",t)},t}(),m={container:{display:"flex",flexDirection:"column",alignItems:"center",padding:"20px",fontFamily:"Arial, sans-serif"},button:{padding:"12px 24px",fontSize:"16px",border:"none",borderRadius:"50px",backgroundColor:"#2196F3",color:"white",cursor:"pointer",outline:"none",transition:"background-color 0.3s"},buttonHover:{backgroundColor:"#1976D2"},buttonRecording:{backgroundColor:"#F44336"},buttonRecordingHover:{backgroundColor:"#D32F2F"},buttonDisabled:{backgroundColor:"#BDBDBD",cursor:"not-allowed"},status:{marginTop:"10px",fontSize:"14px",color:"#757575"},volumeContainer:{width:"100%",margin:"15px 0"},volumeBarContainer:{width:"100%",height:"10px",backgroundColor:"#EEEEEE",borderRadius:"5px",overflow:"hidden"},volumeBar:function(t){return{height:"100%",backgroundColor:"#4CAF50",transition:"width 0.1s",width:t}},result:{marginTop:"20px",padding:"15px",width:"100%",minHeight:"100px",maxHeight:"200px",overflowY:"auto",border:"1px solid #E0E0E0",borderRadius:"4px",backgroundColor:"#F5F5F5",fontSize:"16px",lineHeight:"1.5",whiteSpace:"pre-wrap",wordBreak:"break-word"}};t.SpeechRecognizer=function(t){var e=t.appId,n=t.apiKey,r=t.apiSecret,s=t.language,c=void 0===s?"zh_cn":s,u=t.domain,d=void 0===u?"iat":u,l=t.accent,h=void 0===l?"mandarin":l,p=t.hotWords,g=t.punctuation,b=void 0===g||g,v=t.autoStart,w=void 0!==v&&v,y=t.onStart,S=t.onStop,k=t.onResult,E=t.onError,x=t.className,C=void 0===x?"":x,R=t.buttonClassName,D=void 0===R?"":R,T=t.buttonStartText,F=void 0===T?"开始录音":T,z=t.buttonStopText,A=void 0===z?"停止录音":z,I=t.showVolume,B=void 0===I||I,W=t.showStatus,_=void 0===W||W,O=o.useState(""),j=O[0],N=O[1],P=o.useState("idle"),H=P[0],M=P[1],K=o.useState(0),U=K[0],q=K[1],J=o.useRef(null);o.useEffect((function(){if(e&&n&&r){var t={appId:e,apiKey:n,apiSecret:r,language:c,domain:d,accent:h,hotWords:p,punctuation:b,autoStart:w};return J.current=new f(t,{onStart:function(){y&&y()},onStop:function(){S&&S()},onRecognitionResult:function(t,e){N((function(e){return e+t})),k&&k(t,e)},onProcess:function(t){q(t)},onError:function(t){E&&E(t)},onStateChange:function(t){M(t)}}),function(){J.current&&"recording"===H&&J.current.stop()}}console.error("缺少必要参数: appId, apiKey, apiSecret")}),[e,n,r]);return a.default.createElement("div",{style:m.container,className:C},a.default.createElement("button",{style:"connecting"===H||"error"===H?i(i({},m.button),m.buttonDisabled):"recording"===H?i(i({},m.button),m.buttonRecording):m.button,className:D,onClick:function(){"recording"===H?J.current&&J.current.stop():J.current&&(N(""),J.current.start())},disabled:"connecting"===H||"error"===H},"recording"===H?A:F),_&&a.default.createElement("div",{style:m.status},"状态: ",function(){switch(H){case"idle":return"空闲";case"connecting":return"连接中...";case"connected":return"已连接";case"recording":return"录音中...";case"stopped":return"已停止";case"error":return"错误";default:return"未知状态"}}()),B&&"recording"===H&&a.default.createElement("div",{style:m.volumeContainer},a.default.createElement("div",{style:m.volumeBarContainer},a.default.createElement("div",{style:m.volumeBar("".concat(Math.min(100,U),"%"))}))),a.default.createElement("div",{style:m.result},j))},t.XfyunASR=f,t.arrayBufferToBase64=l,t.calculateVolume=d,t.generateAuthUrl=u,t.parseXfyunResult=h,Object.defineProperty(t,"__esModule",{value:!0})}));
//# sourceMappingURL=index.umd.js.map