Spaces:
Sleeping
Sleeping
| """DeltaMind FastAPI Application - Main Entry Point.""" | |
| import logging, json, asyncio | |
| from pathlib import Path | |
| from typing import Optional | |
| from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Query | |
| from fastapi.staticfiles import StaticFiles | |
| from fastapi.responses import HTMLResponse | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel | |
| from apscheduler.schedulers.asyncio import AsyncIOScheduler | |
| from datetime import datetime | |
| from app.core.config import settings, ensure_directories | |
| from app.core.database import (init_database, init_chromadb, seed_knowledge_base, | |
| get_recent_alerts, get_dashboard_stats, get_production_data, get_chat_history, insert_alert) | |
| from app.llm_router import llm_router | |
| from app.rag_engine import rag_engine | |
| from app.data_sources.firms import firms_client | |
| from app.data_sources.nosdra import nosdra_client | |
| from app.data_sources.weather import weather_client | |
| from app.data_sources.satellite import satellite_client | |
| from app.models.anomaly import anomaly_detector | |
| from app.models.predictive import predictive_model | |
| from app.reports.generator import report_generator | |
| from app.seed_data import seed_production | |
| from app.services.notifications import send_critical_alert_email | |
| logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(name)s] %(levelname)s: %(message)s") | |
| logger = logging.getLogger("deltamind") | |
| app = FastAPI(title="DeltaMind", version="3.0.0", | |
| description="AI-Powered Operational Intelligence - Renaissance Africa Energy") | |
| app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]) | |
| scheduler = AsyncIOScheduler() | |
| class ChatRequest(BaseModel): | |
| query: str | |
| session_id: Optional[str] = None | |
| class AnomalyRequest(BaseModel): | |
| oil_rate: float | |
| pressure: float | |
| water_cut: float | |
| temperature: float | |
| class PredictRequest(BaseModel): | |
| id: str = "EQ-001" | |
| type: str = "ESP" | |
| vibration: float = 0.3 | |
| temperature: float = 70 | |
| runtime_hours: int = 4000 | |
| pressure: float = 150 | |
| class ReportRequest(BaseModel): | |
| report_type: str = "daily" | |
| partner: Optional[str] = None | |
| agency: Optional[str] = None | |
| async def startup(): | |
| ensure_directories() | |
| init_database() | |
| init_chromadb() | |
| seed_knowledge_base() | |
| scheduler.add_job(firms_client.summary, 'interval', hours=6) | |
| scheduler.add_job(weather_client.all_locations, 'interval', hours=1) | |
| scheduler.start() | |
| logger.info("DeltaMind started with background schedulers active") | |
| frontend_path = Path(__file__).parent.parent / "frontend" | |
| if frontend_path.exists(): | |
| app.mount("/static", StaticFiles(directory=str(frontend_path)), name="static") | |
| async def root(): | |
| idx = frontend_path / "index.html" | |
| if idx.exists(): | |
| # FIXED: Added encoding="utf-8" to prevent Windows charmap decoding errors | |
| return HTMLResponse(idx.read_text(encoding="utf-8")) | |
| return HTMLResponse("<h1>DeltaMind API</h1><p>Frontend not found.</p>") | |
| async def health(): | |
| return {"status": "ok", "version": settings.app_version, | |
| "llm": llm_router.status(), "timestamp": datetime.now().isoformat()} | |
| async def llm_status(): | |
| return llm_router.status() | |
| async def dashboard(): | |
| stats = get_dashboard_stats() | |
| flares_summary = firms_client.summary() | |
| spill_summary = nosdra_client.summary() | |
| corridors = satellite_client.corridor_status() | |
| fleet = predictive_model.fleet_health() | |
| weather = weather_client.all_locations() | |
| return {"stats": stats, "flares": flares_summary, "spills": spill_summary, | |
| "corridors": corridors, "fleet": fleet, "weather": weather} | |
| async def alerts(limit: int = 50): | |
| return {"alerts": get_recent_alerts(limit)} | |
| async def flares(): | |
| df = firms_client.get_fires(3) | |
| processed = firms_client.process(df) | |
| firms_client.store(processed) | |
| return {"flares": processed, "count": len(processed)} | |
| async def spills(): | |
| return {"spills": nosdra_client.get_spills()} | |
| async def weather(): | |
| data = weather_client.all_locations() | |
| risks = [weather_client.risk(w) for w in data] | |
| return {"weather": data, "risks": risks} | |
| async def sat_corridors(): | |
| return {"corridors": satellite_client.corridor_status()} | |
| async def production(oml_id: Optional[str] = None, limit: int = 200): | |
| return {"data": get_production_data(oml_id, limit)} | |
| async def chat(req: ChatRequest): | |
| return await rag_engine.chat(req.query, req.session_id) | |
| async def chat_history(session_id: str): | |
| return {"messages": get_chat_history(session_id)} | |
| async def detect_anomaly(req: AnomalyRequest): | |
| return anomaly_detector.detect(req.dict()) | |
| async def detect_leak(flow_in: float = Query(...), flow_out: float = Query(...), pressure_drop: float = Query(0)): | |
| return anomaly_detector.pipeline_leak_detection(flow_in, flow_out, pressure_drop) | |
| async def predict_maintenance(req: PredictRequest): | |
| return predictive_model.predict(req.dict()) | |
| async def fleet_health(): | |
| return predictive_model.fleet_health() | |
| async def generate_report(req: ReportRequest): | |
| if req.report_type == "daily": | |
| return await report_generator.daily_production() | |
| elif req.report_type == "partner": | |
| return await report_generator.partner_report(req.partner or "NNPC") | |
| elif req.report_type == "regulatory": | |
| return await report_generator.regulatory_filing(req.agency or "NUPRC") | |
| return {"error": "Unknown report type"} | |
| async def seed(): | |
| count = seed_production(30) | |
| return {"seeded": count, "message": f"Seeded {count} production records"} | |
| async def test_critical_alert(): | |
| """Simulate a critical alert to demonstrate push notifications and AI email.""" | |
| alert_data = { | |
| "alert_type": "security", | |
| "severity": "critical", | |
| "title": "Pipeline Pressure Drop", | |
| "message": "SCADA detected a 15% pressure drop in Segment 4. Possible vandalism or leak.", | |
| "source": "SCADA_AI", | |
| "latitude": 5.5, | |
| "longitude": 5.9, | |
| "oml_id": "OML-18" | |
| } | |
| alert_id = insert_alert(alert_data) | |
| alert_data["id"] = alert_id | |
| alert_data["created_at"] = datetime.now().isoformat() | |
| # Trigger AI Email Dispatch | |
| await send_critical_alert_email(alert_data) | |
| # Broadcast via WebSocket to all connected dashboards | |
| await manager.broadcast({ | |
| "type": "critical_alert", | |
| "data": alert_data | |
| }) | |
| return {"status": "success", "message": "Alert created, email drafted, and push notification sent."} | |
| class ConnectionManager: | |
| def __init__(self): | |
| self.active = [] | |
| async def connect(self, ws: WebSocket): | |
| await ws.accept() | |
| self.active.append(ws) | |
| def disconnect(self, ws: WebSocket): | |
| if ws in self.active: self.active.remove(ws) | |
| async def broadcast(self, msg: dict): | |
| for ws in self.active: | |
| try: await ws.send_json(msg) | |
| except: pass | |
| manager = ConnectionManager() | |
| async def ws_alerts(ws: WebSocket): | |
| await manager.connect(ws) | |
| try: | |
| while True: | |
| await asyncio.sleep(30) | |
| await ws.send_json({"type": "ping", "message": "DeltaMind connection active"}) | |
| except WebSocketDisconnect: | |
| manager.disconnect(ws) |