""" 声纹采集API接口 """ from fastapi import APIRouter, Depends, UploadFile, File, HTTPException from typing import Optional from pathlib import Path import datetime from app.models.models import VoiceprintStatus, VoiceprintTemplate from app.core.auth import get_current_user from app.core.response import create_api_response from app.services.voiceprint_service import voiceprint_service import app.core.config as config_module router = APIRouter() @router.get("/voiceprint/template", response_model=None) def get_voiceprint_template(current_user: dict = Depends(get_current_user)): """ 获取声纹采集朗读模板配置 权限:需要登录 """ try: template_data = VoiceprintTemplate(**config_module.VOICEPRINT_CONFIG) return create_api_response(code="200", message="获取朗读模板成功", data=template_data.dict()) except Exception as e: return create_api_response(code="500", message=f"获取朗读模板失败: {str(e)}") @router.get("/voiceprint/{user_id}", response_model=None) def get_voiceprint_status(user_id: int, current_user: dict = Depends(get_current_user)): """ 获取用户声纹采集状态 权限:用户只能查询自己的声纹状态,管理员可查询所有 """ # 权限检查:只能查询自己的声纹,或者是管理员 if current_user['user_id'] != user_id and current_user['role_id'] != 1: return create_api_response(code="403", message="无权限查询其他用户的声纹状态") try: status_data = voiceprint_service.get_user_voiceprint_status(user_id) return create_api_response(code="200", message="获取声纹状态成功", data=status_data) except Exception as e: return create_api_response(code="500", message=f"获取声纹状态失败: {str(e)}") @router.post("/voiceprint/{user_id}", response_model=None) async def upload_voiceprint( user_id: int, audio_file: UploadFile = File(...), current_user: dict = Depends(get_current_user) ): """ 上传声纹音频文件(同步处理) 权限:用户只能上传自己的声纹,管理员可操作所有 """ # 权限检查 if current_user['user_id'] != user_id and current_user['role_id'] != 1: return create_api_response(code="403", message="无权限上传其他用户的声纹") # 检查文件格式 file_ext = Path(audio_file.filename).suffix.lower() if file_ext not in config_module.ALLOWED_VOICEPRINT_EXTENSIONS: return create_api_response( code="400", message=f"不支持的文件格式,仅支持: {', '.join(config_module.ALLOWED_VOICEPRINT_EXTENSIONS)}" ) # 检查文件大小 max_size = config_module.VOICEPRINT_CONFIG.get('max_file_size', 5242880) # 默认5MB content = await audio_file.read() file_size = len(content) if file_size > max_size: return create_api_response( code="400", message=f"文件过大,最大允许 {max_size / 1024 / 1024:.1f}MB" ) try: # 确保用户目录存在 user_voiceprint_dir = config_module.VOICEPRINT_DIR / str(user_id) user_voiceprint_dir.mkdir(parents=True, exist_ok=True) # 生成文件名:时间戳.wav timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") filename = f"{timestamp}.wav" file_path = user_voiceprint_dir / filename # 保存文件 with open(file_path, "wb") as f: f.write(content) # 调用服务处理声纹(提取特征向量,保存到数据库) result = voiceprint_service.save_voiceprint(user_id, str(file_path), file_size) return create_api_response(code="200", message="声纹采集成功", data=result) except Exception as e: # 如果出错,删除已上传的文件 if 'file_path' in locals() and Path(file_path).exists(): Path(file_path).unlink() return create_api_response(code="500", message=f"声纹采集失败: {str(e)}") @router.delete("/voiceprint/{user_id}", response_model=None) def delete_voiceprint(user_id: int, current_user: dict = Depends(get_current_user)): """ 删除用户声纹数据,允许重新采集 权限:用户只能删除自己的声纹,管理员可操作所有 """ # 权限检查 if current_user['user_id'] != user_id and current_user['role_id'] != 1: return create_api_response(code="403", message="无权限删除其他用户的声纹") try: success = voiceprint_service.delete_voiceprint(user_id) if success: return create_api_response(code="200", message="声纹删除成功") else: return create_api_response(code="404", message="未找到该用户的声纹数据") except Exception as e: return create_api_response(code="500", message=f"删除声纹失败: {str(e)}")