Spaces:
Sleeping
Sleeping
| """API Routes for VoiceGuard - Matching Hackathon Requirements Exactly. | |
| Endpoint: POST /api/voice-detection | |
| Auth: x-api-key header | |
| Request: {language, audioFormat, audioBase64} | |
| Response: {status, language, classification, confidenceScore, explanation} | |
| """ | |
| import time | |
| from fastapi import APIRouter, HTTPException, Header, UploadFile, File, Form | |
| from typing import Optional | |
| from app.api.schemas import ( | |
| VoiceDetectionRequest, | |
| VoiceDetectionResponse, | |
| ErrorResponse, | |
| HealthResponse | |
| ) | |
| from app.core.audio_processor import ( | |
| audio_processor, | |
| AudioProcessingError, | |
| InvalidBase64Error, | |
| ) | |
| from app.core.detector import detector | |
| from app.config import settings | |
| # Create router | |
| router = APIRouter() | |
| # ============== API KEY VALIDATION ============== | |
| def validate_api_key(x_api_key: Optional[str] = Header(None, alias="x-api-key")) -> str: | |
| """Validate API key from header.""" | |
| if not x_api_key: | |
| raise HTTPException( | |
| status_code=401, | |
| detail={"status": "error", "message": "Missing API key. Use x-api-key header."} | |
| ) | |
| if x_api_key != settings.API_KEY: | |
| raise HTTPException( | |
| status_code=401, | |
| detail={"status": "error", "message": "Invalid API key"} | |
| ) | |
| return x_api_key | |
| # ============== LOGIC HELPER ============== | |
| async def _process_detection_logic( | |
| audio_bytes: bytes, | |
| language: str | |
| ) -> VoiceDetectionResponse: | |
| """Core logic to process audio/bytes and generate response using Hybrid Detector.""" | |
| start_time = time.time() | |
| # Step 1: Process audio (bytes → convert → resample to 16kHz) | |
| print(f"📝 Processing audio for language: {language}") | |
| waveform, duration = audio_processor.process_bytes(audio_bytes) | |
| print(f"✅ Audio processed: {duration:.2f}s duration") | |
| # Step 2: Run Detection (HuBERT Model) | |
| print("🔍 Running deepfake detection...") | |
| result = detector.detect(waveform, language=language) | |
| # Calculate processing time | |
| processing_time_ms = int((time.time() - start_time) * 1000) | |
| print(f"⏱️ Total processing time: {processing_time_ms}ms") | |
| # Build response | |
| return VoiceDetectionResponse( | |
| status="success", | |
| language=language.capitalize(), | |
| classification=result.classification, | |
| confidenceScore=round(result.confidence, 2), | |
| explanation=result.explanation | |
| ) | |
| # ============== MAIN DETECTION ENDPOINT (Reference Implementation) ============== | |
| # Matches exact hackathon requirements (JSON Base64) | |
| async def detect_voice_json( | |
| request: VoiceDetectionRequest, | |
| x_api_key: str = Header(..., alias="x-api-key") | |
| ): | |
| """Main detection endpoint (JSON/Base64).""" | |
| validate_api_key(x_api_key) | |
| try: | |
| # Decode base64 to bytes locally to reuse common logic | |
| # audio_processor.decode_base64 raises InvalidBase64Error | |
| audio_bytes = audio_processor.decode_base64(request.audioBase64) | |
| return await _process_detection_logic(audio_bytes, request.language) | |
| except InvalidBase64Error as e: | |
| raise HTTPException( | |
| status_code=400, | |
| detail={"status": "error", "message": f"Invalid Base64 encoding: {str(e)}"} | |
| ) | |
| except AudioProcessingError as e: | |
| raise HTTPException( | |
| status_code=400, | |
| detail={"status": "error", "message": str(e)} | |
| ) | |
| except Exception as e: | |
| print(f"❌ Error during detection: {e}") | |
| raise HTTPException( | |
| status_code=500, | |
| detail={"status": "error", "message": f"Detection failed: {str(e)}"} | |
| ) | |
| # ============== FILE UPLOAD ENDPOINT (For Testing/Ease of Use) ============== | |
| async def detect_voice_file( | |
| file: UploadFile = File(..., description="Audio file (MP3/WAV)"), | |
| language: str = Form(..., description="Language: Tamil, English, Hindi, Malayalam, Telugu"), | |
| x_api_key: str = Header(..., alias="x-api-key") | |
| ): | |
| """File upload detection endpoint.""" | |
| validate_api_key(x_api_key) | |
| try: | |
| content = await file.read() | |
| return await _process_detection_logic(content, language) | |
| except AudioProcessingError as e: | |
| raise HTTPException( | |
| status_code=400, | |
| detail={"status": "error", "message": str(e)} | |
| ) | |
| except Exception as e: | |
| print(f"❌ Error during detection: {e}") | |
| raise HTTPException( | |
| status_code=500, | |
| detail={"status": "error", "message": f"Detection failed: {str(e)}"} | |
| ) | |
| # ============== HEALTH CHECK (bonus) ============== | |
| async def health_check(): | |
| """Health check endpoint.""" | |
| return HealthResponse( | |
| status="healthy", | |
| model_loaded=detector.is_loaded, | |
| version="1.0.0" | |
| ) | |