import logging import os import uuid import time from fastapi import APIRouter, HTTPException, BackgroundTasks, Query, UploadFile, File, Form from pydantic import BaseModel from typing import Optional import tempfile from Util.ObsUtil import ObsUploader from Config.Config import OBS_BUCKET, OBS_SERVER, XF_APPID, XF_APISECRET, XF_APIKEY from fastapi.responses import StreamingResponse import requests # 导入讯飞语音评测类 from KeDaXunFei.XunFeiAudioEvaluator import XunFeiAudioEvaluator # 配置日志 logger = logging.getLogger(__name__) router = APIRouter(prefix="/api/xunFei", tags=["讯飞"]) # 请求模型 class AudioEvaluationRequest(BaseModel): language: str = "chinese" # chinese 或 english text: str # 评测文本内容 group: Optional[str] = "adult" # 群体:adult, youth, pupil check_type: Optional[str] = "common" # 检错严格程度:easy, common, hard grade: Optional[str] = "middle" # 学段:junior, middle, senior # 响应模型 class AudioEvaluationResponse(BaseModel): evaluation_id: str status: str results: Optional[dict] = None evaluation_time: Optional[float] = None error_message: Optional[str] = None # 科大讯飞API配置(需要根据实际情况配置) XUNFEI_CONFIG = { "appid": XF_APPID, "api_key": XF_APISECRET, "api_secret": XF_APIKEY } @router.post("/evaluate-audio", response_model=AudioEvaluationResponse) async def evaluate_audio( background_tasks: BackgroundTasks, language: str = Form("chinese", 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"), audio_file: UploadFile = File(...)): """ 语音评测接口 - 支持中文和英文篇章朗读判分 """ try: # 验证语言参数 if language not in ["chinese", "english"]: raise HTTPException(status_code=400, detail="language参数必须是'chinese'或'english'") # 验证群体参数 if group not in ["adult", "youth", "pupil"]: raise HTTPException(status_code=400, detail="group参数必须是'adult', 'youth'或'pupil'") # 创建临时文件保存上传的音频 with tempfile.NamedTemporaryFile(delete=False, suffix=".mp3") as temp_audio: audio_content = await audio_file.read() temp_audio.write(audio_content) temp_audio_path = temp_audio.name # 创建评测器实例 evaluator = XunFeiAudioEvaluator( appid=XUNFEI_CONFIG["appid"], api_key=XUNFEI_CONFIG["api_key"], api_secret=XUNFEI_CONFIG["api_secret"], audio_file=temp_audio_path ) # 根据语言设置不同的评测参数 if language == "chinese": # 中文评测配置 evaluator.business_params = { "category": "read_chapter", "ent": "cn_vip", "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}" } # 运行评测 results, eval_time = evaluator.run_evaluation() # 清理临时文件 os.unlink(temp_audio_path) # 生成评测ID evaluation_id = str(uuid.uuid4()) return AudioEvaluationResponse( evaluation_id=evaluation_id, status="success", results=results, evaluation_time=eval_time.total_seconds() if eval_time else None ) except Exception as e: logger.error(f"语音评测失败: {str(e)}") # 确保临时文件被清理 if 'temp_audio_path' in locals() and os.path.exists(temp_audio_path): os.unlink(temp_audio_path) return AudioEvaluationResponse( evaluation_id=str(uuid.uuid4()), status="error", error_message=f"评测失败: {str(e)}" ) @router.get("/evaluation-result/{evaluation_id}") async def get_evaluation_result(evaluation_id: str): """ 获取评测结果(示例接口,实际需要实现结果存储) """ # 这里需要实现从数据库或缓存中获取评测结果 # 目前返回示例数据 return { "evaluation_id": evaluation_id, "status": "completed", "message": "请实现结果存储逻辑" } # 需要修改XunFeiAudioEvaluator类以支持参数配置 # 在XunFeiAudioEvaluator类中添加business_params属性并在on_open方法中使用