// let barrierFreeOpenSpeech; (function () { var APPID = "43341b7e"; var API_SECRET = "MWQzMWEyYTAyYzVlZWRjOTM1NjE0MjI4"; var API_KEY = "a46e1fc5d062a14b28cde0ff2c0046e1"; let btnStatus = "UNDEFINED"; // "UNDEFINED" "CONNECTING" "OPEN" "CLOSING" "CLOSED" const btnControl = document.getElementById("speechStartButton"); const recorder = new RecorderManager("./dist"); recorder.onStart = () => { changeBtnStatus("OPEN"); } let iatWS; let resultText = ""; let resultTextTemp = ""; let countdownInterval; /** * 获取websocket url * 该接口需要后端提供,这里为了方便前端处理 */ function getWebSocketUrl() { // 请求地址根据语种不同变化 var url = "wss://iat-api.xfyun.cn/v2/iat"; var host = "iat-api.xfyun.cn"; var apiKey = API_KEY; var apiSecret = API_SECRET; var date = new Date().toGMTString(); var algorithm = "hmac-sha256"; var headers = "host date request-line"; var signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`; var signatureSha = CryptoJS.HmacSHA256(signatureOrigin, apiSecret); var signature = CryptoJS.enc.Base64.stringify(signatureSha); var authorizationOrigin = `api_key="${apiKey}", algorithm="${algorithm}", headers="${headers}", signature="${signature}"`; var authorization = btoa(authorizationOrigin); url = `${url}?authorization=${authorization}&date=${date}&host=${host}`; return url; } function toBase64(buffer) { var binary = ""; var bytes = new Uint8Array(buffer); var len = bytes.byteLength; for (var i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } return window.btoa(binary); } function countdown() { let seconds = 60; btnControl.innerText = `录音中(${seconds}s)`; countdownInterval = setInterval(() => { seconds = seconds - 1; if (seconds <= 0) { clearInterval(countdownInterval); recorder.stop(); } else { btnControl.innerText = `录音中(${seconds}s)`; } }, 1000); } function changeBtnStatus(status) { btnStatus = status; if (status === "CONNECTING") { btnControl.innerText = "建立连接中"; document.getElementById("speechPartialResult").innerText = ""; resultText = ""; resultTextTemp = ""; } else if (status === "OPEN") { countdown(); } else if (status === "CLOSING") { btnControl.innerText = "关闭连接中"; } else if (status === "CLOSED") { btnControl.innerText = "开始录音"; } } function renderResult(resultData) { // 识别结束 let jsonData = JSON.parse(resultData); if (jsonData.data && jsonData.data.result) { let data = jsonData.data.result; let str = ""; let ws = data.ws; for (let i = 0; i < ws.length; i++) { str = str + ws[i].cw[0].w; } // 开启wpgs会有此字段(前提:在控制台开通动态修正功能) // 取值为 "apd"时表示该片结果是追加到前面的最终结果;取值为"rpl" 时表示替换前面的部分结果,替换范围为rg字段 if (data.pgs) { if (data.pgs === "apd") { // 将resultTextTemp同步给resultText resultText = resultTextTemp; } // 将结果存储在resultTextTemp中 resultTextTemp = resultText + str; } else { resultText = resultText + str; } document.getElementById("speechPartialResult").innerText = resultTextTemp || resultText || ""; // 调用方法传输文字 // console.log("sendSpeechText", resultTextTemp || resultText || ""); checkVoiceCommand(resultTextTemp || resultText || ""); // 网页间通信 htmlPostMessage( { type: "语音识别", status: "process", data: resultTextTemp || resultText || "", } ); } if (jsonData.code === 0 && jsonData.data.status === 2) { iatWS.close(); } if (jsonData.code !== 0) { iatWS.close(); console.error(jsonData); } } function connectWebSocket() { const websocketUrl = getWebSocketUrl(); if ("WebSocket" in window) { iatWS = new WebSocket(websocketUrl); } else if ("MozWebSocket" in window) { iatWS = new MozWebSocket(websocketUrl); } else { alert("浏览器不支持WebSocket"); return; } changeBtnStatus("CONNECTING"); iatWS.onopen = (e) => { // 开始录音 recorder.start({ sampleRate: 16000, frameSize: 1280, }); var params = { common: { app_id: APPID, }, business: { language: "zh_cn", domain: "iat", accent: "mandarin", vad_eos: 5000, dwa: "wpgs", }, data: { status: 0, format: "audio/L16;rate=16000", encoding: "raw", }, }; iatWS.send(JSON.stringify(params)); // 网页间通信 htmlPostMessage( { type: "语音识别", status: "start", data: "", } ); }; iatWS.onmessage = (e) => { renderResult(e.data); // console.log(e.data); }; iatWS.onerror = (e) => { console.error(e); recorder.stop(); changeBtnStatus("CLOSED"); }; iatWS.onclose = (e) => { recorder.stop(); changeBtnStatus("CLOSED"); // 网页间通信 htmlPostMessage( { type: "语音识别", status: "end", data: "", } ); }; } recorder.onFrameRecorded = ({ isLastFrame, frameBuffer }) => { if (iatWS.readyState === iatWS.OPEN) { iatWS.send( JSON.stringify({ data: { status: isLastFrame ? 2 : 1, format: "audio/L16;rate=16000", encoding: "raw", audio: toBase64(frameBuffer), }, }) ); if (isLastFrame) { changeBtnStatus("CLOSING"); } } }; recorder.onStop = () => { clearInterval(countdownInterval); }; btnControl.onclick = function () { if (btnStatus === "UNDEFINED" || btnStatus === "CLOSED" || btnStatus === "CONNECTING") { connectWebSocket(); } else { // 结束录音 recorder.stop(); } }; barrierFreeOpenSpeech = function () { // console.log("barrierFreeOpenSpeech", btnStatus); if (btnStatus === "UNDEFINED" || btnStatus === "CLOSED" || btnStatus === "OPEN") { connectWebSocket(); } else { // 结束录音 recorder.stop(); } }; })(); function showSpeech() { let speechDom = document.getElementsByClassName("box-speech")[0]; speechDom.style.display = speechDom.style.display == 'none' ? 'block' : 'none'; voiceBroadcast(`${speechDom.style.display == 'block' ? '开启' : '关闭'}语音识别`); // 无障碍模式 if (window.location.href.indexOf("courseHomeBarrierFree.html") !== -1) { barrierFreeOpenSpeech(); } } // 检查语音命令 function checkVoiceCommand(text) { if (!text) return false; // 语音命令配置 const voiceCommands = [ { keywords: ['打开首页', '跳转首页', '回到首页'], action: () => { window.open('./indexHome.html', '_blank'); }, description: '打开首页' }, { keywords: ['打开百度', '跳转百度', '搜索'], action: () => { window.open('https://www.baidu.com', '_blank'); }, description: '打开百度' }, ]; // 将文本转换为小写,去除标点符号和空格,以便更好地匹配 const cleanText = text.toLowerCase().replace(/[.,,。?!、;:""''()]/g, '').replace(/\s+/g, ''); console.log("checkVoiceCommand", cleanText); // 检查是否匹配任何命令 for (const command of voiceCommands) { for (const keyword of command.keywords) { // 同样处理关键词,去除空格 const cleanKeyword = keyword.replace(/\s+/g, ''); if (cleanText.includes(cleanKeyword)) { // 执行命令动作 command.action(); return true; } } } return false; }