This commit is contained in:
2025-08-28 11:04:23 +08:00
parent df9badeec6
commit 177bfb36e4

View File

@@ -1153,6 +1153,143 @@ select { padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; backgrou
</div>
<script src="https://l2dwidget.js.org/lib/L2Dwidget.min.js"></script>
<script>
// 录音相关变量
let mediaRecorder; let audioChunks = []; let isRecording = false;
// 音频播放相关变量
let audioElement = null; let isPlaying = false;
// 开始录音
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); }
document.getElementById('playAudioBtn').style.display = 'flex';
};
audioElement.ontimeupdate = function() { updateAudioProgress(); updateAudioTimeDisplay(); };
audioElement.onended = function() { isPlaying = false; updatePlayButton(); };
document.getElementById('playAudioBtn').onclick = togglePlayAudio;
document.getElementById('audioProgress').onclick = function(e) {
if (!audioElement) return;
const rect = this.getBoundingClientRect();
const clickPosition = (e.clientX - rect.left) / rect.width;
audioElement.currentTime = clickPosition * 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" xmlns="http://www.w3.org/2000/svg">
<path d="M6 19H10V5H6V19ZM14 19H18V5H14V19Z" fill="white"/>
</svg>` : `
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 5V19L19 12L8 5Z" fill="white"/>
</svg>`;
}
function updateAudioProgress() { if (audioElement) document.getElementById('progressBar').style.width = `${(audioElement.currentTime/audioElement.duration)*100}%`; }
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)}`;
}
// 模型配置映射
const modelConfig = {
shizuku: {
@@ -1264,5 +1401,8 @@ select { padding: 8px 12px; border: 1px solid #ccc; border-radius: 4px; backgrou
// 初始加载默认模型
document.addEventListener('DOMContentLoaded', function() {
initL2DWidget();
// 添加录音按钮事件绑定
document.getElementById('startRecordBtn').addEventListener('click', startRecording);
document.getElementById('stopRecordBtn').addEventListener('click', stopRecording);
});
</script>