Files
dsProject/dsLightRag/static/XunFei/js/audio_evaluation.js
2025-09-05 21:01:11 +08:00

190 lines
6.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

let mediaRecorder;
let audioChunks = [];
let audioBlob;
// 获取DOM元素
const languageSelect = document.getElementById('language');
const textInput = document.getElementById('text');
const recordBtn = document.getElementById('recordBtn');
const stopBtn = document.getElementById('stopBtn');
const statusDiv = document.getElementById('status');
const resultDiv = document.getElementById('result');
const resultContent = document.getElementById('resultContent');
// 语言切换时自动填充示例文本
languageSelect.addEventListener('change', () => {
if (languageSelect.value === 'chinese') {
textInput.value = '窗前明月光,疑是地上霜。';
} else {
textInput.value = 'Nice to meet you.';
}
});
// 页面加载时自动填充中文示例
window.addEventListener('load', () => {
textInput.value = '窗前明月光,疑是地上霜。';
stopBtn.disabled = true;
});
// 开始录音
recordBtn.addEventListener('click', async () => {
try {
statusDiv.textContent = '正在获取麦克风权限...';
statusDiv.className = 'status';
// 获取麦克风权限并处理可能的错误
const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
.catch(err => {
if (err.name === 'NotAllowedError') {
throw new Error('用户拒绝了麦克风访问权限。请在浏览器设置中允许麦克风访问,或刷新页面重试。');
} else if (err.name === 'NotFoundError') {
throw new Error('未检测到麦克风设备,请确保您的设备已正确连接麦克风。');
} else if (err.name === 'NotReadableError') {
throw new Error('麦克风设备正在被其他程序占用,请关闭其他可能使用麦克风的程序后重试。');
} else {
throw err;
}
});
mediaRecorder = new MediaRecorder(stream);
audioChunks = [];
mediaRecorder.ondataavailable = (event) => {
audioChunks.push(event.data);
};
mediaRecorder.onstop = () => {
audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
statusDiv.textContent = '录音完成,正在自动提交评测...';
submitEvaluation();
// 停止所有音轨以释放麦克风
stream.getTracks().forEach(track => track.stop());
};
// 设置60秒自动停止录音
const maxRecordingTime = 60000; // 60秒
const timeoutId = setTimeout(() => {
if (mediaRecorder && mediaRecorder.state === 'recording') {
alert('已达到最大录音时长60秒');
mediaRecorder.stop();
recordBtn.disabled = false;
stopBtn.disabled = true;
}
}, maxRecordingTime);
mediaRecorder.start();
statusDiv.textContent = '正在录音...最多60秒';
recordBtn.disabled = true;
stopBtn.disabled = false;
} catch (error) {
console.error('录音初始化失败:', error);
alert('录音失败: ' + error.message);
statusDiv.textContent = '录音失败: ' + error.message;
statusDiv.className = 'status error';
recordBtn.disabled = false;
stopBtn.disabled = true;
}
});
// 停止录音
stopBtn.addEventListener('click', () => {
if (mediaRecorder && mediaRecorder.state === 'recording') {
mediaRecorder.stop();
recordBtn.disabled = false;
stopBtn.disabled = true;
}
});
// 提交评测
async function submitEvaluation() {
if (!audioBlob) {
statusDiv.textContent = '请先完成录音';
statusDiv.className = 'status error';
return;
}
if (!textInput.value.trim()) {
statusDiv.textContent = '请输入评测文本内容';
statusDiv.className = 'status error';
return;
}
try {
statusDiv.textContent = '正在提交评测...';
statusDiv.className = 'status';
const formData = new FormData();
formData.append('audio_file', audioBlob, 'recording.webm');
formData.append('language', languageSelect.value);
formData.append('text', textInput.value.trim());
formData.append('group', 'adult');
formData.append('check_type', 'common');
formData.append('grade', 'middle');
const response = await fetch('/api/xunFei/evaluate-audio', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`服务器错误: HTTP状态码 ${response.status}`);
}
const result = await response.json();
if (result.status === 'success') {
displayResults(result.results);
statusDiv.textContent = '评测成功完成';
statusDiv.className = 'status success';
} else {
throw new Error(result.error_message || '评测失败,服务器返回未知错误');
}
} catch (error) {
console.error('评测提交失败:', error);
statusDiv.textContent = '评测失败: ' + error.message;
statusDiv.className = 'status error';
}
}
// 显示评测结果
function displayResults(results) {
resultDiv.style.display = 'block';
if (!results) {
resultContent.innerHTML = '<p>暂无评测结果</p>';
return;
}
let html = '<div class="result-summary">';
// 显示总分
if (results.total_score !== undefined) {
html += `<p><strong>总分:</strong> ${results.total_score.toFixed(4)} / 5.0</p>`;
}
// 显示各项评分
if (results.accuracy_score !== undefined) {
html += `<p><strong>准确度:</strong> ${results.accuracy_score.toFixed(4)}</p>`;
}
if (results.fluency_score !== undefined) {
html += `<p><strong>流利度:</strong> ${results.fluency_score.toFixed(4)}</p>`;
}
if (results.completeness_score !== undefined) {
html += `<p><strong>完整度:</strong> ${results.completeness_score.toFixed(4)}</p>`;
}
html += '</div>';
// 显示单词级评分
if (results.words && results.words.length > 0) {
html += '<div class="word-scores"><h4>单词评分:</h4><ul>';
results.words.forEach(word => {
html += `<li>${word.content}: ${word.score.toFixed(4)}</li>`;
});
html += '</ul></div>';
}
resultContent.innerHTML = html;
}