// 学伴录音功能核心逻辑 // 模型配置 // 录音相关变量 let mediaRecorder; let audioChunks = []; let isRecording = false; // 音频播放相关变量 let audioElement = null; let isPlaying = false; // 获取URL参数 function getUrlParam(name) { const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)'); const r = window.location.search.substr(1).match(reg); return r ? unescape(r[2]) : null; } // 开始录音 function startRecording() { if (isRecording) return; console.log("尝试开始录音"); navigator.mediaDevices.getUserMedia({ audio: true }) .then(stream => { mediaRecorder = new MediaRecorder(stream); audioChunks = []; mediaRecorder.ondataavailable = event => { if (event.data.size > 0) audioChunks.push(event.data); }; mediaRecorder.onstop = () => { const audioBlob = new Blob(audioChunks, { type: 'audio/wav' }); console.log("录音完成,音频数据大小:", audioBlob.size); uploadAudioToServer(audioBlob); }; mediaRecorder.start(); isRecording = true; document.getElementById('recordingIndicator').style.display = 'flex'; document.getElementById('startRecordBtn').style.display = 'none'; document.getElementById('stopRecordBtn').style.display = 'flex'; console.log("开始录音成功"); // 设置最长录音时间为60秒 setTimeout(stopRecording, 60000); }) .catch(error => { console.error("获取麦克风权限失败:", error); alert("请授权麦克风权限以使用录音功能"); }); } // 停止录音 function stopRecording() { if (!isRecording || !mediaRecorder) return; mediaRecorder.stop(); isRecording = false; document.getElementById('recordingIndicator').style.display = 'none'; document.getElementById('startRecordBtn').style.display = 'flex'; document.getElementById('stopRecordBtn').style.display = 'none'; console.log("停止录音"); if (mediaRecorder.stream) { mediaRecorder.stream.getTracks().forEach(track => track.stop()); } } // 上传音频到服务器 function uploadAudioToServer(audioBlob) { console.log("开始上传音频到服务器"); document.getElementById('thinkingIndicator').style.display = 'flex'; const formData = new FormData(); formData.append('file', audioBlob, 'recording.wav'); fetch('/api/xueban/upload-audio', { method: 'POST', body: formData }) .then(response => { if (!response.ok) throw new Error('服务器响应错误'); return response.json(); }) .then(data => { console.log("处理结果:", data); document.getElementById('thinkingIndicator').style.display = 'none'; if (data.success) { showResults(data.data); } else { alert('音频处理失败: ' + data.message); } }) .catch(error => { console.error("上传音频失败:", error); document.getElementById('thinkingIndicator').style.display = 'none'; alert('上传音频失败: ' + error.message); }); } // 显示ASR识别结果和反馈 function showResults(data) { const resultContainer = document.getElementById('resultContainer'); resultContainer.style.display = 'flex'; document.getElementById('asrResultText').textContent = data.asr_text || '未识别到内容'; document.getElementById('feedbackResultText').textContent = data.feedback_text || '无反馈内容'; if (data.audio_url) { if (audioElement) audioElement.pause(); audioElement = new Audio(data.audio_url); audioElement.onloadedmetadata = function() { updateAudioTimeDisplay(); try { audioElement.play(); isPlaying = true; updatePlayButton(); } catch (e) { console.error("自动播放失败:", e); } }; audioElement.ontimeupdate = function() { updateAudioProgress(); updateAudioTimeDisplay(); }; audioElement.onended = function() { isPlaying = false; updatePlayButton(); }; document.getElementById('playAudioBtn').onclick = togglePlayAudio; document.getElementById('audioProgress').onclick = function(e) { const rect = this.getBoundingClientRect(); audioElement.currentTime = (e.clientX - rect.left) / rect.width * audioElement.duration; }; } } // 音频播放控制函数 function togglePlayAudio() { if (!audioElement) return; isPlaying ? audioElement.pause() : audioElement.play(); isPlaying = !isPlaying; updatePlayButton(); } function updatePlayButton() { const btn = document.getElementById('playAudioBtn'); btn.innerHTML = isPlaying ? '' : ''; } function updateAudioProgress() { if (!audioElement) return; const progress = (audioElement.currentTime / audioElement.duration) * 100; document.getElementById('progressBar').style.width = `${progress}%`; } function updateAudioTimeDisplay() { if (!audioElement) return; const format = s => `${Math.floor(s/60).toString().padStart(2,'0')}:${Math.floor(s%60).toString().padStart(2,'0')}`; document.getElementById('audioTime').textContent = `${format(audioElement.currentTime)} / ${format(audioElement.duration)}`; }