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

205 lines
7.3 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');
// 开始录音
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;
}
});
// 检测浏览器支持的录制格式
const getSupportedMimeType = () => {
const options = [
'audio/webm; codecs=opus',
'audio/webm',
'audio/mp4',
'' // 空字符串表示使用浏览器默认格式
];
for (const option of options) {
if (MediaRecorder.isTypeSupported(option)) return option;
}
return '';
};
// 使用检测到的格式初始化
mediaRecorder = new MediaRecorder(stream, {
mimeType: getSupportedMimeType(),
audioBitsPerSecond: 16000
});
// 同时修正Blob类型确保前后一致
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) {
showError("评测结果格式错误");
return;
}
if (results.fluency_score !== undefined) {
html += `<p><strong>流利度:</strong> ${results.fluency_score.toFixed(4)}</p>`;
} else {
html += `<p><strong>流利度:</strong> 未获取</p>`; // 添加默认值
}
if (results.completeness_score !== undefined) {
html += `<p><strong>完整度:</strong> ${results.completeness_score.toFixed(4)}</p>`;
} else {
html += `<p><strong>完整度:</strong> 未获取</p>`; // 添加默认值
}
html += '</div>';
// 显示单词级评分
if (results.words && results.words.length > 0) {
html += '<div class="word-scores"><h4>单词评分:</h4><ul>';
results.words.forEach(word => {
// 为单词评分添加空值检查
const score = word.score !== undefined ? word.score.toFixed(4) : '无';
html += `<li>${word.content}: ${score}</li>`;
});
html += '</ul></div>';
}
resultContent.innerHTML = html;
}