Spaces:
Running
Running
| #main.py | |
| from fastapi import FastAPI, HTTPException, Depends, status | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel, Field | |
| from sqlalchemy.orm import Session | |
| import models | |
| from database import engine, SessionLocal | |
| from ml_utils import ScamDetectionService | |
| from typing import Optional | |
| import time | |
| from datetime import datetime | |
| # Create FastAPI app | |
| app = FastAPI( | |
| title="Multilingual Scam Detection API", | |
| description="Simple API to detect scams in text messages and URLs", | |
| version="1.0.0" | |
| ) | |
| # Add CORS middleware | |
| # app.add_middleware( | |
| # CORSMiddleware, | |
| # allow_origins=["*"], # Configure for production | |
| # allow_credentials=True, | |
| # allow_methods=["*"], | |
| # allow_headers=["*"], | |
| # ) | |
| # Create database tables | |
| models.Base.metadata.create_all(bind=engine) | |
| # Initialize scam detection service | |
| scam_service = ScamDetectionService() | |
| # Database dependency | |
| def get_db(): | |
| db = SessionLocal() | |
| try: | |
| yield db | |
| finally: | |
| db.close() | |
| # Pydantic models for requests/responses | |
| class TextAnalysisRequest(BaseModel): | |
| text: str = Field(min_length=1, max_length=5000) | |
| language: Optional[str] = Field(default=None, description="Language code (en, es, fr)") | |
| class URLAnalysisRequest(BaseModel): | |
| url: str = Field(min_length=1) | |
| context: Optional[str] = Field(default="", description="Additional context") | |
| class ScamAnalysisResponse(BaseModel): | |
| risk_level: str | |
| confidence: float | |
| reasoning: str | |
| detected_language: Optional[str] = None | |
| processing_time: float | |
| timestamp: datetime | |
| class URLAnalysisResponse(ScamAnalysisResponse): | |
| url_status: str | |
| domain: str | |
| # Root endpoint | |
| def root(): | |
| return { | |
| "message": "Multilingual Scam Detection API", | |
| "version": "1.0.0", | |
| "endpoints": { | |
| "analyze_text": "/analyze/text/", | |
| "analyze_url": "/analyze/url/", | |
| "health": "/health/", | |
| "analytics": "/analytics/summary/" | |
| } | |
| } | |
| # Health check | |
| def health_check(): | |
| return { | |
| "status": "healthy", | |
| "timestamp": datetime.now(), | |
| "database": "connected", | |
| "ml_service": "active" | |
| } | |
| # Text analysis endpoint | |
| def analyze_text(request: TextAnalysisRequest, db: Session = Depends(get_db)): | |
| """Analyze text message for scam indicators""" | |
| start_time = time.time() | |
| try: | |
| # Detect language if not provided | |
| detected_language = request.language or scam_service.detect_language(request.text) | |
| # Analyze for scam | |
| analysis = scam_service.analyze_text_scam( | |
| text=request.text, | |
| language=detected_language | |
| ) | |
| processing_time = time.time() - start_time | |
| # Save to database | |
| scam_record = models.ScamAnalysis( | |
| content=request.text, | |
| content_type="text", | |
| risk_level=analysis["risk_level"], | |
| confidence=analysis["confidence"], | |
| reasoning=analysis["reasoning"], | |
| detected_language=detected_language, | |
| processing_time=processing_time | |
| ) | |
| db.add(scam_record) | |
| db.commit() | |
| return ScamAnalysisResponse( | |
| risk_level=analysis["risk_level"], | |
| confidence=analysis["confidence"], | |
| reasoning=analysis["reasoning"], | |
| detected_language=detected_language, | |
| processing_time=round(processing_time, 3), | |
| timestamp=datetime.now() | |
| ) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Analysis failed: {str(e)}" | |
| ) | |
| # URL analysis endpoint | |
| def analyze_url(request: URLAnalysisRequest, db: Session = Depends(get_db)): | |
| """Analyze URL for phishing/malicious behavior""" | |
| start_time = time.time() | |
| try: | |
| # Analyze URL | |
| analysis = scam_service.analyze_url_scam( | |
| url=request.url, | |
| context=request.context | |
| ) | |
| processing_time = time.time() - start_time | |
| # Save to database | |
| scam_record = models.ScamAnalysis( | |
| content=request.url, | |
| content_type="url", | |
| risk_level=analysis["risk_level"], | |
| confidence=analysis["confidence"], | |
| reasoning=analysis["reasoning"], | |
| processing_time=processing_time, | |
| additional_data={"domain": analysis["domain"], "url_status": analysis["url_status"]} | |
| ) | |
| db.add(scam_record) | |
| db.commit() | |
| return URLAnalysisResponse( | |
| risk_level=analysis["risk_level"], | |
| confidence=analysis["confidence"], | |
| reasoning=analysis["reasoning"], | |
| url_status=analysis["url_status"], | |
| domain=analysis["domain"], | |
| processing_time=round(processing_time, 3), | |
| timestamp=datetime.now() | |
| ) | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"URL analysis failed: {str(e)}" | |
| ) | |
| # Language detection endpoint | |
| def detect_language(text: str): | |
| """Detect language of input text""" | |
| try: | |
| detected_lang = scam_service.detect_language(text) | |
| confidence = scam_service.get_language_confidence(text) | |
| return { | |
| "text_preview": text[:100] + "..." if len(text) > 100 else text, | |
| "detected_language": detected_lang, | |
| "confidence": confidence, | |
| "supported_languages": ["en", "es", "fr"] | |
| } | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Language detection failed: {str(e)}" | |
| ) | |
| # Basic analytics | |
| def get_analytics(db: Session = Depends(get_db)): | |
| """Get basic analytics summary""" | |
| try: | |
| total_analyses = db.query(models.ScamAnalysis).count() | |
| # Count by risk level | |
| safe_count = db.query(models.ScamAnalysis).filter( | |
| models.ScamAnalysis.risk_level == "Safe" | |
| ).count() | |
| suspicious_count = db.query(models.ScamAnalysis).filter( | |
| models.ScamAnalysis.risk_level == "Suspicious" | |
| ).count() | |
| scam_count = db.query(models.ScamAnalysis).filter( | |
| models.ScamAnalysis.risk_level == "Scam" | |
| ).count() | |
| # Count by content type | |
| text_count = db.query(models.ScamAnalysis).filter( | |
| models.ScamAnalysis.content_type == "text" | |
| ).count() | |
| url_count = db.query(models.ScamAnalysis).filter( | |
| models.ScamAnalysis.content_type == "url" | |
| ).count() | |
| return { | |
| "total_analyses": total_analyses, | |
| "risk_distribution": { | |
| "Safe": safe_count, | |
| "Suspicious": suspicious_count, | |
| "Scam": scam_count | |
| }, | |
| "content_distribution": { | |
| "text": text_count, | |
| "url": url_count | |
| }, | |
| "supported_languages": ["en", "es", "fr"] | |
| } | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"Analytics failed: {str(e)}" | |
| ) | |
| # Recent analyses | |
| def get_recent_analyses(limit: int = 10, db: Session = Depends(get_db)): | |
| """Get recent scam analyses""" | |
| try: | |
| recent = db.query(models.ScamAnalysis).order_by( | |
| models.ScamAnalysis.created_at.desc() | |
| ).limit(limit).all() | |
| return { | |
| "recent_analyses": [ | |
| { | |
| "id": analysis.id, | |
| "content_type": analysis.content_type, | |
| "risk_level": analysis.risk_level, | |
| "confidence": analysis.confidence, | |
| "detected_language": analysis.detected_language, | |
| "created_at": analysis.created_at, | |
| "content_preview": ( | |
| analysis.content[:50] + "..." | |
| if len(analysis.content) > 50 | |
| else analysis.content | |
| ) | |
| } | |
| for analysis in recent | |
| ], | |
| "total_shown": len(recent) | |
| } | |
| except Exception as e: | |
| raise HTTPException( | |
| status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, | |
| detail=f"History retrieval failed: {str(e)}" | |
| ) | |
| # Test endpoint with sample data | |
| def test_samples(): | |
| """Test with sample scam messages""" | |
| samples = [ | |
| { | |
| "text": "URGENT! Your bank account will be suspended. Click here: bit.ly/urgent-bank", | |
| "expected_risk": "Scam" | |
| }, | |
| { | |
| "text": "Hello, how are you today? Hope you're doing well!", | |
| "expected_risk": "Safe" | |
| }, | |
| { | |
| "text": "Congratulations! You've won $1000. Click to claim your prize now!", | |
| "expected_risk": "Suspicious" | |
| } | |
| ] | |
| results = [] | |
| for sample in samples: | |
| analysis = scam_service.analyze_text_scam(sample["text"]) | |
| results.append({ | |
| "text": sample["text"], | |
| "expected": sample["expected_risk"], | |
| "detected": analysis["risk_level"], | |
| "confidence": analysis["confidence"], | |
| "reasoning": analysis["reasoning"] | |
| }) | |
| return { | |
| "test_results": results, | |
| "total_tests": len(results) | |
| } | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=8000) |