diff --git a/dsLightRag/KeDaXunFei/XunFeiAudioEvaluator.py b/dsLightRag/KeDaXunFei/XunFeiAudioEvaluator.py index a922dd35..84057fe7 100644 --- a/dsLightRag/KeDaXunFei/XunFeiAudioEvaluator.py +++ b/dsLightRag/KeDaXunFei/XunFeiAudioEvaluator.py @@ -18,12 +18,13 @@ from Config.Config import XF_APPID, XF_APISECRET, XF_APIKEY class XunFeiAudioEvaluator: """讯飞语音评测类""" - def __init__(self, appid, api_key, api_secret, audio_file): + def __init__(self, appid, api_key, api_secret, audio_file, language): self.appid = appid self.api_key = api_key self.api_secret = api_secret self.audio_file = audio_file - self.host_url = "ws://ise-api.xfyun.cn/v2/open-ise" + self.language = language + self.host_url = "wss://ise-api.xfyun.cn/v2/open-ise" self.websocket_url = "" self.evaluation_results = {} @@ -60,29 +61,29 @@ class XunFeiAudioEvaluator: print(f"Received message: {message}") data = json.loads(message) status = data["data"]["status"] - + if status == 2: # 解析评测结果 xml_data = base64.b64decode(data["data"]["data"]) xml_content = xml_data.decode("utf-8") #print(xml_content) - + # 解析XML并提取得分信息 self.parse_evaluation_results(xml_content) ws.close() - + def on_error(self, ws, error): """错误处理""" print(f"Error: {error},{ws}") - + def on_close(self, ws, reason, res): """连接关闭处理""" print(f"WebSocket connection closed,{ws}") - + def on_open(self, ws): """连接建立处理""" print(f"WebSocket connection opened,{ws},ws连接建立成功...") - + # 发送初始参数 send_dict = { "common": { @@ -93,7 +94,7 @@ class XunFeiAudioEvaluator: "rstcd": "utf8", "sub": "ise", "group": "pupil", - "ent": "en_vip", + "ent": "zh_cn" if self.language == "chinese" else "en_vip", "tte": "utf-8", "cmd": "ssb", "auf": "audio/L16;rate=16000", @@ -106,7 +107,7 @@ class XunFeiAudioEvaluator: } } ws.send(json.dumps(send_dict)) - + # 发送音频数据 with open(self.audio_file, "rb") as file_flag: while True: @@ -115,12 +116,12 @@ class XunFeiAudioEvaluator: # 发送最后一帧 my_dict = { "business": { - "cmd": "auw", - "aus": 4, + "cmd": "auw", + "aus": 4, "aue": "lame" }, "data": { - "status": 2, + "status": 2, "data": str(base64.b64encode(buffer).decode()) } } @@ -157,7 +158,7 @@ class XunFeiAudioEvaluator: self.evaluation_results = { 'accuracy_score': float(read_chapter.get('accuracy_score', 0)), 'fluency_score': float(read_chapter.get('fluency_score', 0)), - 'integrity_score': float(read_chapter.get('integrity_score', 0)), + 'completeness_score': float(read_chapter.get('integrity_score', 0)), # 修复字段名 'standard_score': float(read_chapter.get('standard_score', 0)), 'total_score': float(read_chapter.get('total_score', 0)), 'word_count': int(read_chapter.get('word_count', 0)), diff --git a/dsLightRag/KeDaXunFei/__pycache__/XunFeiAudioEvaluator.cpython-310.pyc b/dsLightRag/KeDaXunFei/__pycache__/XunFeiAudioEvaluator.cpython-310.pyc index aaa495be..baa03fe9 100644 Binary files a/dsLightRag/KeDaXunFei/__pycache__/XunFeiAudioEvaluator.cpython-310.pyc and b/dsLightRag/KeDaXunFei/__pycache__/XunFeiAudioEvaluator.cpython-310.pyc differ diff --git a/dsLightRag/Routes/XunFeiRoute.py b/dsLightRag/Routes/XunFeiRoute.py index a4c3c977..43c6421d 100644 --- a/dsLightRag/Routes/XunFeiRoute.py +++ b/dsLightRag/Routes/XunFeiRoute.py @@ -47,7 +47,6 @@ XUNFEI_CONFIG = { async def evaluate_audio( # 添加async关键字 background_tasks: BackgroundTasks, language: str = Form(..., description="语言类型: chinese/english"), - text: str = Form(..., description="评测文本内容"), group: str = Form("adult", description="群体类型: adult, youth, pupil"), check_type: str = Form("common", description="检错严格程度: easy, common, hard"), grade: str = Form("middle", description="学段: junior, middle, senior"), @@ -72,9 +71,18 @@ async def evaluate_audio( # 添加async关键字 raise HTTPException(status_code=400, detail="group参数必须是'adult', 'youth'或'pupil'") # 创建临时文件保存上传的音频 - with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_audio: + # 修改临时文件处理逻辑 + with tempfile.NamedTemporaryFile(delete=False, suffix=".wav") as temp_audio: + # 先读取音频内容 audio_content = await audio_file.read() - temp_audio.write(audio_content) + # 再进行格式转换 + import wave + with wave.open(temp_audio, 'wb') as wf: + wf.setnchannels(1) + wf.setsampwidth(2) + wf.setframerate(16000) + wf.writeframes(audio_content) + # 移除冗余的temp_audio.write(audio_content),避免重复写入 temp_audio_path = temp_audio.name # 创建评测器实例 @@ -83,7 +91,8 @@ async def evaluate_audio( # 添加async关键字 # 与AudioEvaluator示例用法保持一致 api_key=XUNFEI_CONFIG["api_key"], api_secret=XUNFEI_CONFIG["api_secret"], - audio_file=temp_audio_path + audio_file=temp_audio_path, + language=language # 添加语言参数 ) # 根据语言设置不同的评测参数 @@ -95,14 +104,15 @@ async def evaluate_audio( # 添加async关键字 "group": group, "check_type": check_type, "grade": grade, - "text": '\uFEFF' + f"[content]\n{text}" } else: - # 英文评测配置 + # 英文评测配置 evaluator.business_params = { "category": "read_chapter", "ent": "en_vip", - "text": '\uFEFF' + f"[content]\n{text}" + "group": group, # 添加缺失参数 + "check_type": check_type, # 添加缺失参数 + "grade": grade, # 添加缺失参数 } # 运行评测 @@ -150,5 +160,3 @@ async def get_evaluation_result(evaluation_id: str): "message": "请实现结果存储逻辑" } -# 需要修改XunFeiAudioEvaluator类以支持参数配置 -# 在XunFeiAudioEvaluator类中添加business_params属性并在on_open方法中使用 \ No newline at end of file diff --git a/dsLightRag/Routes/__pycache__/XunFeiRoute.cpython-310.pyc b/dsLightRag/Routes/__pycache__/XunFeiRoute.cpython-310.pyc index b2462abf..a60943b2 100644 Binary files a/dsLightRag/Routes/__pycache__/XunFeiRoute.cpython-310.pyc and b/dsLightRag/Routes/__pycache__/XunFeiRoute.cpython-310.pyc differ diff --git a/dsLightRag/static/XunFei/audio_evaluation.html b/dsLightRag/static/XunFei/audio_evaluation.html index 4de89455..5959033f 100644 --- a/dsLightRag/static/XunFei/audio_evaluation.html +++ b/dsLightRag/static/XunFei/audio_evaluation.html @@ -18,11 +18,6 @@ -
- - -
-
diff --git a/dsLightRag/static/XunFei/js/audio_evaluation.js b/dsLightRag/static/XunFei/js/audio_evaluation.js index ac6b3f2d..ae652a1a 100644 --- a/dsLightRag/static/XunFei/js/audio_evaluation.js +++ b/dsLightRag/static/XunFei/js/audio_evaluation.js @@ -12,19 +12,20 @@ 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.'; - } -}); +// 移除语言切换事件监听 +// languageSelect.addEventListener('change', () => { +// if (languageSelect.value === 'chinese') { +// textInput.value = '窗前明月光,疑是地上霜。'; +// } else { +// textInput.value = 'Nice to meet you.'; +// } +// }); -// 页面加载时自动填充中文示例 -window.addEventListener('load', () => { - textInput.value = '窗前明月光,疑是地上霜。'; - stopBtn.disabled = true; -}); +// 移除页面加载事件监听 +// window.addEventListener('load', () => { +// textInput.value = '窗前明月光,疑是地上霜。'; +// stopBtn.disabled = true; +// }); // 开始录音 recordBtn.addEventListener('click', async () => { @@ -46,15 +47,29 @@ recordBtn.addEventListener('click', async () => { } }); - mediaRecorder = new MediaRecorder(stream); - audioChunks = []; - - mediaRecorder.ondataavailable = (event) => { - audioChunks.push(event.data); + // 检测浏览器支持的录制格式 + 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' }); + audioBlob = new Blob(audioChunks, { type: 'audio/webm' }); // 与录制格式匹配 statusDiv.textContent = '录音完成,正在自动提交评测...'; submitEvaluation(); // 停止所有音轨以释放麦克风 @@ -104,11 +119,12 @@ async function submitEvaluation() { return; } - if (!textInput.value.trim()) { - statusDiv.textContent = '请输入评测文本内容'; - statusDiv.className = 'status error'; - return; - } + // 移除文本验证 + // if (!textInput.value.trim()) { + // statusDiv.textContent = '请输入评测文本内容'; + // statusDiv.className = 'status error'; + // return; + // } try { statusDiv.textContent = '正在提交评测...'; @@ -117,7 +133,8 @@ async function submitEvaluation() { const formData = new FormData(); formData.append('audio_file', audioBlob, 'recording.webm'); formData.append('language', languageSelect.value); - formData.append('text', textInput.value.trim()); + // 移除文本参数 + // formData.append('text', textInput.value.trim()); formData.append('group', 'adult'); formData.append('check_type', 'common'); formData.append('grade', 'middle'); @@ -168,20 +185,33 @@ function displayResults(results) { if (results.accuracy_score !== undefined) { html += `

准确度: ${results.accuracy_score.toFixed(4)}

`; } + // 添加结果对象有效性检查 + if (!results) { + showError("评测结果格式错误"); + return; + } + if (results.fluency_score !== undefined) { html += `

流利度: ${results.fluency_score.toFixed(4)}

`; + } else { + html += `

流利度: 未获取

`; // 添加默认值 } + if (results.completeness_score !== undefined) { html += `

完整度: ${results.completeness_score.toFixed(4)}

`; + } else { + html += `

完整度: 未获取

`; // 添加默认值 } - + html += '
'; // 显示单词级评分 if (results.words && results.words.length > 0) { html += '

单词评分:

'; }