'commit'
This commit is contained in:
@@ -94,3 +94,9 @@ HS_VOICE_TYPE_QINCANG = "BV701_V2_streaming" # 中年男声,用于朗读古
|
|||||||
LIBLIB_URL="https://openapi.liblibai.cloud"
|
LIBLIB_URL="https://openapi.liblibai.cloud"
|
||||||
LIBLIB_ACCESSKEY="sOCtVLVTNOZkRMajlhzCmg"
|
LIBLIB_ACCESSKEY="sOCtVLVTNOZkRMajlhzCmg"
|
||||||
LIBLIB_SECRETKEY="PUe8QTRG9i0G9EbpedHmIpLQ0FyxoYY9"
|
LIBLIB_SECRETKEY="PUe8QTRG9i0G9EbpedHmIpLQ0FyxoYY9"
|
||||||
|
|
||||||
|
|
||||||
|
# 科大讯飞
|
||||||
|
XF_APPID="5b83f8d6"
|
||||||
|
XF_APISECRET="604fa6cb9c5ab664a0d153fe0ccc6802"
|
||||||
|
XF_APIKEY="5beb887923204000bfcb402046bb05a6"
|
Binary file not shown.
@@ -2,12 +2,12 @@ import logging
|
|||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
import time
|
import time
|
||||||
from fastapi import APIRouter, HTTPException, BackgroundTasks, Query, UploadFile, File
|
from fastapi import APIRouter, HTTPException, BackgroundTasks, Query, UploadFile, File, Form
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
import tempfile
|
import tempfile
|
||||||
from Util.ObsUtil import ObsUploader
|
from Util.ObsUtil import ObsUploader
|
||||||
from Config.Config import OBS_BUCKET, OBS_SERVER
|
from Config.Config import OBS_BUCKET, OBS_SERVER, XF_APPID, XF_APISECRET, XF_APIKEY
|
||||||
from fastapi.responses import StreamingResponse
|
from fastapi.responses import StreamingResponse
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
@@ -36,19 +36,19 @@ class AudioEvaluationResponse(BaseModel):
|
|||||||
|
|
||||||
# 科大讯飞API配置(需要根据实际情况配置)
|
# 科大讯飞API配置(需要根据实际情况配置)
|
||||||
XUNFEI_CONFIG = {
|
XUNFEI_CONFIG = {
|
||||||
"appid": "your_appid_here",
|
"appid": XF_APPID,
|
||||||
"api_key": "your_api_key_here",
|
"api_key": XF_APISECRET,
|
||||||
"api_secret": "your_api_secret_here"
|
"api_secret": XF_APIKEY
|
||||||
}
|
}
|
||||||
|
|
||||||
@router.post("/evaluate-audio", response_model=AudioEvaluationResponse)
|
@router.post("/evaluate-audio", response_model=AudioEvaluationResponse)
|
||||||
async def evaluate_audio(
|
async def evaluate_audio(
|
||||||
background_tasks: BackgroundTasks,
|
background_tasks: BackgroundTasks,
|
||||||
language: str = Query("chinese", description="评测语言: chinese 或 english"),
|
language: str = Form("chinese", description="评测语言: chinese 或 english"),
|
||||||
text: str = Query(..., description="评测文本内容"),
|
text: str = Form(..., description="评测文本内容"),
|
||||||
group: str = Query("adult", description="群体类型: adult, youth, pupil"),
|
group: str = Form("adult", description="群体类型: adult, youth, pupil"),
|
||||||
check_type: str = Query("common", description="检错严格程度: easy, common, hard"),
|
check_type: str = Form("common", description="检错严格程度: easy, common, hard"),
|
||||||
grade: str = Query("middle", description="学段: junior, middle, senior"),
|
grade: str = Form("middle", description="学段: junior, middle, senior"),
|
||||||
audio_file: UploadFile = File(...)):
|
audio_file: UploadFile = File(...)):
|
||||||
"""
|
"""
|
||||||
语音评测接口 - 支持中文和英文篇章朗读判分
|
语音评测接口 - 支持中文和英文篇章朗读判分
|
||||||
|
Binary file not shown.
@@ -104,7 +104,6 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<button id="recordBtn" class="btn btn-record">开始录音</button>
|
<button id="recordBtn" class="btn btn-record">开始录音</button>
|
||||||
<button id="stopBtn" class="btn btn-stop" disabled>停止录音</button>
|
<button id="stopBtn" class="btn btn-stop" disabled>停止录音</button>
|
||||||
<button id="evaluateBtn" class="btn" disabled>提交评测</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="status" class="status">准备就绪</div>
|
<div id="status" class="status">准备就绪</div>
|
||||||
@@ -125,7 +124,7 @@
|
|||||||
const textInput = document.getElementById('text');
|
const textInput = document.getElementById('text');
|
||||||
const recordBtn = document.getElementById('recordBtn');
|
const recordBtn = document.getElementById('recordBtn');
|
||||||
const stopBtn = document.getElementById('stopBtn');
|
const stopBtn = document.getElementById('stopBtn');
|
||||||
const evaluateBtn = document.getElementById('evaluateBtn');
|
// 删除提交按钮引用
|
||||||
const statusDiv = document.getElementById('status');
|
const statusDiv = document.getElementById('status');
|
||||||
const resultDiv = document.getElementById('result');
|
const resultDiv = document.getElementById('result');
|
||||||
const resultContent = document.getElementById('resultContent');
|
const resultContent = document.getElementById('resultContent');
|
||||||
@@ -150,6 +149,24 @@
|
|||||||
statusDiv.textContent = '正在获取麦克风权限...';
|
statusDiv.textContent = '正在获取麦克风权限...';
|
||||||
statusDiv.className = 'status';
|
statusDiv.className = 'status';
|
||||||
|
|
||||||
|
// ==== 插入WebSocket认证代码 ====
|
||||||
|
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
|
const wsUrl = `${wsProtocol}//${window.location.host}/ws/audio-evaluation?token=${getAuthToken()}`;
|
||||||
|
const ws = new WebSocket(wsUrl);
|
||||||
|
|
||||||
|
// WebSocket事件处理
|
||||||
|
ws.onopen = () => {
|
||||||
|
console.log('WebSocket连接已建立');
|
||||||
|
statusDiv.textContent = 'WebSocket连接已建立,准备录音...';
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = (error) => {
|
||||||
|
console.error('WebSocket错误:', error);
|
||||||
|
statusDiv.textContent = 'WebSocket连接失败,请刷新页面重试';
|
||||||
|
statusDiv.className = 'status error';
|
||||||
|
};
|
||||||
|
// ==== 插入结束 ====
|
||||||
|
|
||||||
// 使用更明确的提示并添加详细的错误处理
|
// 使用更明确的提示并添加详细的错误处理
|
||||||
const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
|
const stream = await navigator.mediaDevices.getUserMedia({ audio: true })
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
@@ -174,8 +191,10 @@
|
|||||||
|
|
||||||
mediaRecorder.onstop = () => {
|
mediaRecorder.onstop = () => {
|
||||||
audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
|
audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
|
||||||
statusDiv.textContent = '录音完成,可以提交评测';
|
statusDiv.textContent = '录音完成,正在自动提交评测...';
|
||||||
evaluateBtn.disabled = false;
|
// 添加WebSocket关闭逻辑
|
||||||
|
if (ws) ws.close(1000, '录音已完成');
|
||||||
|
submitEvaluation();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 添加录音最大时长限制(60秒)
|
// 添加录音最大时长限制(60秒)
|
||||||
@@ -218,8 +237,8 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 提交评测
|
// 将提交评测逻辑提取为独立函数
|
||||||
evaluateBtn.addEventListener('click', async () => {
|
async function submitEvaluation() {
|
||||||
if (!audioBlob) {
|
if (!audioBlob) {
|
||||||
statusDiv.textContent = '请先完成录音';
|
statusDiv.textContent = '请先完成录音';
|
||||||
statusDiv.className = 'status error';
|
statusDiv.className = 'status error';
|
||||||
@@ -235,7 +254,6 @@
|
|||||||
try {
|
try {
|
||||||
statusDiv.textContent = '正在提交评测...';
|
statusDiv.textContent = '正在提交评测...';
|
||||||
statusDiv.className = 'status';
|
statusDiv.className = 'status';
|
||||||
evaluateBtn.disabled = true;
|
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('audio_file', audioBlob, 'recording.webm');
|
formData.append('audio_file', audioBlob, 'recording.webm');
|
||||||
@@ -268,10 +286,8 @@
|
|||||||
console.error('评测失败:', error);
|
console.error('评测失败:', error);
|
||||||
statusDiv.textContent = '评测失败: ' + error.message;
|
statusDiv.textContent = '评测失败: ' + error.message;
|
||||||
statusDiv.className = 'status error';
|
statusDiv.className = 'status error';
|
||||||
} finally {
|
|
||||||
evaluateBtn.disabled = false;
|
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
// 显示评测结果
|
// 显示评测结果
|
||||||
function displayResults(results) {
|
function displayResults(results) {
|
||||||
@@ -313,6 +329,16 @@
|
|||||||
|
|
||||||
resultContent.innerHTML = html;
|
resultContent.innerHTML = html;
|
||||||
}
|
}
|
||||||
|
// 在<script>标签内添加getAuthToken实现
|
||||||
|
function getAuthToken() {
|
||||||
|
// 实际项目中应从Cookie、localStorage或后端API获取
|
||||||
|
return 'your_auth_token_here'; // 临时占位,需替换为真实认证逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
// 页面卸载时关闭连接
|
||||||
|
window.addEventListener('beforeunload', () => {
|
||||||
|
if (ws) ws.close(1001, '页面即将关闭');
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Reference in New Issue
Block a user