153 lines
5.7 KiB
JavaScript
153 lines
5.7 KiB
JavaScript
// 学伴录音功能核心逻辑
|
|
// 模型配置
|
|
|
|
// 录音相关变量
|
|
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 ?
|
|
'<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M6 19H10V5H6V19ZM14 19H18V5H14V19Z" fill="white"/></svg>' :
|
|
'<svg width="20" height="20" viewBox="0 0 24 24" fill="none"><path d="M8 5V19L19 12L8 5Z" fill="white"/></svg>';
|
|
}
|
|
|
|
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)}`;
|
|
}
|