const chatIcon = document.getElementById('chatIcon'); const chatDialog = document.getElementById('chatDialog'); const closeChat = document.getElementById('closeChat'); const voiceInputBtn = document.getElementById('voiceInputBtn'); const voiceStatus = document.getElementById('voiceStatus'); const notificationBadge = document.querySelector('.notification-badge'); var APPID = "43341b7e"; var API_SECRET = "MWQzMWEyYTAyYzVlZWRjOTM1NjE0MjI4"; var API_KEY = "a46e1fc5d062a14b28cde0ff2c0046e1"; let btnStatus = "UNDEFINED"; // "UNDEFINED" "CONNECTING" "OPEN" "CLOSING" "CLOSED" //大模型调用部分 const apiPassword = "xozAvYSDDAUrZtmZAMHe:BesWfhINSVtAumsVcxCt"; // 注意:请将 123456 替换为你自己的 APIPassword let chatList = [ { "role": "system", "content": "请你扮演一名幼师,跟我聊聊天吧!" } ] async function sendRequest(str,callback) { chatList.push({ "role": "user", "content": str }) const body = { "apiPassword": apiPassword, "chatList": chatList } let data= await fetch('http://w.textbox.wang/index.php/english/Index/xhchat', { method: 'POST', // 或者使用 'GET' 取决于API的要求 headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(body) }) .then(response => response.json()) // 解析JSON响应 .then(data => { // 处理响应数据 console.log(data.choices[0].message.content); chatList.push({ "role": "assistant", "content": data.choices[0].message.content }) callback(data.choices[0].message.content) // document.getElementById('output').innerText = data.text; // 假设响应中包含文本字段 }) .catch(error => console.error('Error:', error)); // 捕获并处理错误 } // 执行请求 //语音播报部分 let preText = ""; function speakFly(text) { if (preText == text) { return } preText = text; const audioPlayer = document.getElementById('chatAudio'); const vcn = ["x4_lingxiaoqi_cts", "x4_lingyouyou", "x4_lingfeizhe_zl", "aisjinger", "aisbabyxu"]; $.ajax({ url: 'http://rgclass.iflysse.com:8200/text2audio', type: 'POST', contentType: 'application/x-www-form-urlencoded', data: { text: text, vcn: vcn[1], speed: 50 }, headers: { 'Cache-Control': 'no-store' }, success: function (data) { let timer01 = setTimeout(function () { $(".message-content:last").text(text) $(".chat-content").animate({ scrollTop: $(".chat-content")[0].scrollHeight }, 1000); const url = `http://rgclass.iflysse.com:8200${data}`; audioPlayer.src = url; audioPlayer.load(); audioPlayer.play(); audioPlayer.onerror = function (e) { setTimeout(function () { audioPlayer.load(); audioPlayer.play(); }, 500); console.error(e); }; audioPlayer.addEventListener('ended', () => {//连续对话 voiceInputBtn.click(); }); clearTimeout(timer01); // console.log("text2audio success", url, audioPlayer); }, 1000); }, error: function (jqXHR, textStatus, errorThrown) { console.error('text2audio error:', textStatus, errorThrown); } }); let timer02 = setTimeout(function () { preText = ""; clearTimeout(timer02); }, 5000); } const recorder = new RecorderManager("./dist"); recorder.onStart = () => { changeBtnStatus("OPEN"); } let iatWS; let resultText = ""; let resultTextTemp = ""; let countdownInterval; let isListening = false; /** * 获取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 changeBtnStatus(status) { btnStatus = status; if (status === "CONNECTING") { // btnControl.innerText = "建立连接中"; // document.getElementById("partial-result").innerText = ""; resultText = ""; resultTextTemp = ""; } } let lydjs=null; function renderResult(resultData) { clearTimeout(lydjs); lydjs=setTimeout(function(){ iatWS.close(); },3000); // 识别结束 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; } console.log(str); // 开启wpgs会有此字段(前提:在控制台开通动态修正功能) // 取值为 "apd"时表示该片结果是追加到前面的最终结果;取值为"rpl" 时表示替换前面的部分结果,替换范围为rg字段 if (data.pgs) { if (data.pgs === "apd") { // 将resultTextTemp同步给resultText resultText = resultTextTemp; // 移除打字指示器 } // 将结果存储在resultTextTemp中 resultTextTemp = resultText + str; } else { resultText = resultText + str; } $(".typing-indicator").text(resultTextTemp); // document.getElementById("partial-result").innerText = // 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"); console.log(iatWS); iatWS.onopen = (e) => { isListening = true; voiceInputBtn.classList.add('active'); voiceInputBtn.innerHTML = ''; voiceStatus.textContent = '正在聆听...'; // 添加用户正在说话的UI反馈 addMessage('user', '
'); // 开始录音 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", }, }; console.log("asd"); iatWS.send(JSON.stringify(params)); clearTimeout(lydjs); lydjs=setTimeout(function(){ iatWS.close(); },3000); }; iatWS.onmessage = (e) => { console.log("asdas") renderResult(e.data); console.log(e.data); }; iatWS.onerror = (e) => { console.error(e); recorder.stop(); changeBtnStatus("CLOSED"); }; iatWS.onclose = (e) => { removeLastUserMessage(); if(resultTextTemp!=''){ // 显示用户的语音输入 addMessage('user', resultTextTemp); // 模拟AI回复 // setTimeout(() => { addMessage('bot', '我正在处理你的请求...'); // }, 1000); sendRequest(resultTextTemp,function(response){ speakFly(response) }); } voiceInputBtn.innerHTML = ''; voiceInputBtn.classList.remove('active'); voiceStatus.textContent = ''; isListening = false; recorder.stop(); changeBtnStatus("CLOSED"); }; } 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); }; voiceInputBtn.onclick = function () { if (btnStatus === "UNDEFINED" || btnStatus === "CLOSED") { connectWebSocket(); } else if (btnStatus === "CONNECTING" || btnStatus === "OPEN") { // 结束录音 recorder.stop(); } }; // 打开/关闭聊天对话框 chatIcon.addEventListener('click', () => { chatDialog.classList.toggle('open'); // 打开对话框后移除通知徽章 // if (chatDialog.classList.contains('open')) { // notificationBadge.classList.remove('active'); // setTimeout(() => { // notificationBadge.style.display = 'none'; // }, 300); // } }); closeChat.addEventListener('click', () => { chatDialog.classList.remove('open'); }); // 添加消息到聊天界面 function addMessage(type, content) { const chatContent = document.querySelector('.chat-content'); const messageDiv = document.createElement('div'); messageDiv.className = `message ${type}`; messageDiv.innerHTML = `
${content}
`; chatContent.appendChild(messageDiv); // 滚动到底部 chatContent.scrollTop = chatContent.scrollHeight; } // 移除最后一条用户消息(用于移除打字指示器) function removeLastUserMessage() { const chatContent = document.querySelector('.chat-content'); const messages = chatContent.querySelectorAll('.message'); if (messages.length > 0) { const lastMessage = messages[messages.length - 1]; if (lastMessage.classList.contains('user')) { chatContent.removeChild(lastMessage); } } } // 添加窗口点击事件,点击外部关闭聊天框 window.addEventListener('click', (event) => { if (event.target === chatDialog) { chatDialog.classList.remove('open'); } });