Spaces:
Sleeping
Sleeping
| from fastapi import FastAPI, HTTPException | |
| from pydantic import BaseModel | |
| import torch | |
| import os | |
| import socket | |
| from urllib.parse import urlparse | |
| from models.gnn import PhishingGNN_Model | |
| from pipeline.graph_engine import TopologicalGraphEngine | |
| from config import * | |
| import uvicorn | |
| app = FastAPI(title="Defender V5 Sovereign Threat Analysis API") | |
| # Define node dimension configurations | |
| in_channels_dict = { | |
| 'ip': 16, | |
| 'domain': 32, | |
| 'asn': 8, | |
| 'cert': 16 | |
| } | |
| # Load model directly into state memory matching training dimension maps | |
| model = PhishingGNN_Model( | |
| metadata=GRAPH_METADATA, | |
| in_channels_dict=in_channels_dict, | |
| hidden_channels=HIDDEN_CHANNELS, | |
| num_heads=NUM_HEADS, | |
| num_layers=NUM_LAYERS, | |
| dropout_rate=0.0 | |
| ) | |
| if os.path.exists(MODEL_SAVE_PATH): | |
| model.load_state_dict(torch.load(MODEL_SAVE_PATH, map_location='cpu', weights_only=True)) | |
| model.eval() | |
| # Payload model expects a URL | |
| class URLPayload(BaseModel): | |
| url: str | |
| async def analyze_url(payload: URLPayload): | |
| try: | |
| # 1. Parse the URL to extract the domain | |
| parsed_url = urlparse(payload.url) | |
| domain = parsed_url.netloc or parsed_url.path.split('/')[0] | |
| if ':' in domain: | |
| domain = domain.split(':')[0] | |
| if not domain: | |
| raise HTTPException(status_code=400, detail="Invalid URL format.") | |
| # 2. Resolve the domain to an IP address | |
| try: | |
| ip = socket.gethostbyname(domain) | |
| except socket.gaierror: | |
| raise HTTPException(status_code=400, detail=f"DNS Resolution failed for domain: {domain}") | |
| # 3. Build telemetry dictionary | |
| telemetry_log = { | |
| "ip": ip, | |
| "domain": domain, | |
| "asn": None | |
| } | |
| # 4. Pass through Graph Engine | |
| engine = TopologicalGraphEngine() | |
| x_dict, edge_index_dict = engine.extract_and_build([telemetry_log]) | |
| with torch.no_grad(): | |
| raw_scores = model(x_dict, edge_index_dict) | |
| threat_probability = float(raw_scores.max().item()) | |
| return { | |
| "input_url": payload.url, | |
| "resolved_domain": domain, | |
| "resolved_ip": ip, | |
| "structural_anomaly_score": round(threat_probability, 5), | |
| "remediation_verdict": "ISOLATE_ROUTING" if threat_probability > 0.70 else "ALLOW" | |
| } | |
| except HTTPException: | |
| raise | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"Graph Engine Exception: {str(e)}") | |
| if __name__ == "__main__": | |
| uvicorn.run(app, host="127.0.0.1", port=8005) |