import math import os import sys from pydantic import BaseModel, Field # ── Import your existing cli.py functions directly ─────────────────────────── try: from cli import clean_text, predict, load_models as cli_load_models except ImportError: # Fallback to handle relative imports if invoked directly by master gateway from Version_3.cli import clean_text, predict, load_models as cli_load_models # ───────────────────────────────────────────────────────────────────────────── # 1. REQUIRED SCHEMAS FOR MASTER GATEWAY COMPATIBILITY # ───────────────────────────────────────────────────────────────────────────── class EmailScanRequest(BaseModel): """ Must use 'email_body' to match app.js and the validation expected by main.py """ email_body: str = Field(..., description="The raw email text or headers to scan") class EmailScanResponse(BaseModel): """ Must match the exact structure enforced by response_model in master main.py """ verdict: str confidence: float # ───────────────────────────────────────────────────────────────────────────── # 2. REQUIRED GLOBAL CONTEXT VARIABLES # ───────────────────────────────────────────────────────────────────────────── _vectorizer = None _model = None _load_error = None def load_models(): """ Called automatically by the master gateway bootstrapper. """ global _vectorizer, _model, _load_error try: _vectorizer, _model = cli_load_models() print("[Chimera V3] SVM Models loaded successfully via master handshake.") return _vectorizer, _model except SystemExit: _load_error = "Model files not found. Check models/SVM_model.pkl and models/vectorizer.pkl exist." print(f"[Chimera V3] WARNING: {_load_error}") except Exception as e: _load_error = str(e) print(f"[Chimera V3] WARNING: Could not load models — {_load_error}") return None, None # ───────────────────────────────────────────────────────────────────────────── # 3. CORE ROUTING EXECUTION ENTRYPOINT # ───────────────────────────────────────────────────────────────────────────── def scan_email(payload: EmailScanRequest) -> EmailScanResponse: """ Direct functional endpoint executed by the master route handler. """ global _model, _vectorizer, _load_error # Lazy loading safe-state fallback for mounted instances if _model is None or _vectorizer is None: _vectorizer, _model = load_models() # If models are genuinely unavailable, fallback gracefully if _model is None or _vectorizer is None: return EmailScanResponse( verdict="Suspicious (Model Offline)", confidence=0.50 ) text_to_analyze = payload.email_body # Guard: empty body text check if not text_to_analyze.strip(): return EmailScanResponse(verdict="Clean", confidence=0.0) # ── Run your underlying SVM model prediction ───────────────────────────── # Emulating a blank display_name context to feed into your cli pipeline combined_text = f"\n{text_to_analyze}" label, confidence, spam_score = predict(combined_text, _vectorizer, _model) # Calculate normalized confidence float (0.0 to 1.0) risk_score = spam_score if spam_score is not None else (100.0 if label == "Spam" else 0.0) final_confidence = (confidence / 100.0) if (confidence is not None) else (risk_score / 100.0) # ── Map results to match standard frontend badge expectation ────────────── if risk_score >= 70: assigned_verdict = "phishing" elif risk_score >= 40: assigned_verdict = "suspicious" else: assigned_verdict = "clean" return EmailScanResponse( verdict=assigned_verdict, confidence=final_confidence )