janrakshak-ml-api / api /router_scam.py
Archit
Deploy FastAPI Backend to HF Space
96ac3c1
Raw
History Blame Contribute Delete
4.89 kB
import tempfile
import os
from fastapi import APIRouter, UploadFile, File, Depends, HTTPException, status
from core.security import verify_api_key
from ml_services.audio_ai import audio_service
from ml_services.nlp_graph_ai import nlp_graph_service
from models.schemas import IncidentReport
from datetime import datetime
import uuid
from core.db import db_handler
router = APIRouter(prefix="/api/v1/scam", tags=["Scam Detection"])
@router.post("/analyze", response_model=IncidentReport)
async def analyze_scam_audio(
file: UploadFile = File(...),
api_key: str = Depends(verify_api_key)
):
if not file.filename.endswith(('.wav', '.mp3', '.ogg', '.flac')):
raise HTTPException(status_code=400, detail="Unsupported audio format.")
temp_file_path = ""
try:
# Save upload to a temporary file asynchronously
fd, temp_file_path = tempfile.mkstemp(suffix=f".{file.filename.split('.')[-1]}")
os.close(fd) # Close the synchronous fd immediately
import aiofiles
async with aiofiles.open(temp_file_path, 'wb') as f:
while chunk := await file.read(1024 * 1024): # 1MB chunks
await f.write(chunk)
# 1. Process Audio (STT + Deepfake check)
transcription, fake_prob = await audio_service.process_audio(temp_file_path)
# 2. Translate to English (assuming Hindi or other regional language as source for robust pipeline,
# but Whisper might output English directly if translated, or source language.
# Let's assume whisper gives text, and we pass to translator if we want to ensure English,
# but for now we'll pass to intent directly to save overhead unless explicitly requested).
# We'll use the LLM to classify intent directly as mistral handles multilingual.
intent_and_risk = await nlp_graph_service.classify_intent(transcription)
# 3. Extract Entities
entities = await nlp_graph_service.extract_entities(transcription)
# 4. Agentic AI Fusion (Threat Dossier)
from ml_services.agentic_fusion import agent
dossier = await agent.generate_threat_dossier(transcription, entities)
# 5. DPDP Act Compliance (PII Redaction)
redacted_transcription = nlp_graph_service.redact_pii(transcription, entities)
# 6. Construct Report
report = IncidentReport(
incident_id=str(uuid.uuid4()),
type="audio",
timestamp=datetime.utcnow(),
extracted_entities=entities,
risk_score=fake_prob if fake_prob > 0.5 else (0.8 if intent_and_risk.get("risk") == "High" else 0.2),
threat_dossier=dossier,
explainability_report=intent_and_risk.get("explainability_report"),
details={
"transcription": redacted_transcription,
"intent": intent_and_risk.get("intent", ""),
"scam_stage": intent_and_risk.get("scam_stage", ""),
"deepfake_probability": fake_prob
}
)
# 7. Generate Immutable Evidence Hash
db_payload = report.model_dump()
sig = await db_handler.generate_evidence_hash(db_payload, file_path=temp_file_path)
report.digital_signature = sig
db_payload["digital_signature"] = sig
# 7. Save to MongoDB atomically
if db_handler.db is not None:
await db_handler.db["incidents"].insert_one(db_payload)
return report
except Exception as e:
raise HTTPException(status_code=500, detail=f"Internal Server Error: {str(e)}")
finally:
# Cleanup temp file
if temp_file_path and os.path.exists(temp_file_path):
os.remove(temp_file_path)
from models.schemas import VideoAnalysisResponse
from ml_services.vision_ai import vision_service
@router.post("/video-analysis", response_model=VideoAnalysisResponse)
async def analyze_scam_video(
file: UploadFile = File(...),
api_key: str = Depends(verify_api_key)
):
if not file.filename.lower().endswith(('.png', '.jpg', '.jpeg', '.webp')):
raise HTTPException(status_code=400, detail="Unsupported image format.")
temp_file_path = ""
try:
fd, temp_file_path = tempfile.mkstemp(suffix=f".{file.filename.split('.')[-1]}")
os.close(fd)
import aiofiles
async with aiofiles.open(temp_file_path, 'wb') as f:
while chunk := await file.read(1024 * 1024):
await f.write(chunk)
result = await vision_service.analyze_video_call(temp_file_path)
return VideoAnalysisResponse(**result)
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
finally:
if temp_file_path and os.path.exists(temp_file_path):
os.remove(temp_file_path)