{ "nbformat": 4, "nbformat_minor": 5, "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "name": "python", "version": "3.10.0" }, "colab": { "name": "Aegis_Hackathon.ipynb", "provenance": [] } }, "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# \ud83d\udee1\ufe0f Aegis \u2014 Autonomous Enterprise Crisis Management\n**AMD Developer Hackathon 2026** | Track 1: AI Agents & Agentic Workflows\n\n**Features:** 7 AI Agents \u00b7 Live MarineTraffic Scraper \u00b7 ARIMA+XGBoost ML \u00b7 Groq LLaMA 3.3 70B \u00b7 Auto-Monitor 24/7 \u00b7 AMD MI300X\n\nRun each cell in order (Shift+Enter). After Cell 5, copy the ngrok URL and open it in your browser." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cell 1 \u2014 API Keys\n- Groq API key \u2192 https://console.groq.com\n- ngrok token \u2192 https://dashboard.ngrok.com/get-started/your-authtoken" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n\nGROQ_API_KEY = \"gsk_YOUR_GROQ_KEY_HERE\" # \u2190 paste your Groq key\nNGROK_TOKEN = \"YOUR_NGROK_TOKEN_HERE\" # \u2190 paste your ngrok token\n\nos.environ[\"GROQ_API_KEY\"] = GROQ_API_KEY\nprint(\"\u2705 Keys set\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cell 2 \u2014 Install Dependencies" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import subprocess, sys\n\npackages = [\n \"fastapi\", \"uvicorn[standard]\", \"pyngrok==7.2.0\",\n \"groq\", \"httpx\", \"pydantic\",\n \"numpy\", \"pandas\", \"scikit-learn\",\n \"xgboost\", \"statsmodels\",\n \"python-multipart\", \"aiofiles\",\n \"requests\", \"beautifulsoup4\", \"lxml\",\n]\nsubprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"-q\"] + packages)\nprint(\"\u2705 All packages installed including MarineTraffic scraper deps\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cell 3 \u2014 Write Project Files" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n\nROOT = \"/content/aegis\"\nfor d in [\"\",\"/agents\",\"/models\",\"/api\"]:\n os.makedirs(ROOT+d, exist_ok=True)\n open(ROOT+d+\"/__init__.py\",\"w\").close()\n\n# Write forecaster.py\nforecaster_code = r'''\n\nimport numpy as np, pandas as pd, warnings\nfrom datetime import datetime, timedelta\nwarnings.filterwarnings(\"ignore\")\ntry:\n import xgboost as xgb\n from statsmodels.tsa.arima.model import ARIMA\n from sklearn.preprocessing import StandardScaler\n HAS_MODELS = True\nexcept ImportError:\n HAS_MODELS = False\n\ndef _gen_history(n=120, base=82.0):\n np.random.seed(42)\n dates = [datetime.today() - timedelta(days=n-i) for i in range(n)]\n prices = [base]\n for _ in range(n-1):\n shock = np.random.normal(0, 1.2)\n drift = 0.05*(base - prices[-1])\n prices.append(max(prices[-1]+drift+shock, 40))\n return pd.DataFrame({\"price\": prices}, index=pd.to_datetime(dates))\n\ndef _features(df):\n df = df.copy()\n for lag in [1,3,7,14]: df[f\"lag_{lag}\"] = df[\"price\"].shift(lag)\n df[\"rm7\"] = df[\"price\"].rolling(7).mean()\n df[\"rs7\"] = df[\"price\"].rolling(7).std()\n df[\"rm14\"] = df[\"price\"].rolling(14).mean()\n df[\"pct3\"] = df[\"price\"].pct_change(3)\n df[\"dow\"] = df.index.dayofweek\n return df.dropna()\n\nFEAT = [\"lag_1\",\"lag_3\",\"lag_7\",\"lag_14\",\"rm7\",\"rs7\",\"rm14\",\"pct3\",\"dow\"]\n\nclass AegisForecaster:\n def __init__(self):\n self.arima = self.xgb = self.scaler = None\n self.hist = None\n self.fitted = False\n\n def fit(self, df=None):\n self.hist = df if df is not None else _gen_history()\n if not HAS_MODELS:\n self.fitted = True\n return self\n try:\n self.arima = ARIMA(self.hist[\"price\"], order=(2,1,2)).fit()\n except:\n self.arima = None\n fd = _features(self.hist)\n X = fd[FEAT].values\n y = fd[\"price\"].values\n self.scaler = StandardScaler()\n Xs = self.scaler.fit_transform(X)\n self.xgb = xgb.XGBRegressor(\n n_estimators=200, max_depth=4,\n learning_rate=0.05, subsample=0.8,\n colsample_bytree=0.8, random_state=42,\n verbosity=0\n ).fit(Xs, y)\n self.fitted = True\n print(\"\u2705 Forecaster ready (ARIMA + XGBoost)\")\n return self\n\n def forecast(self, horizon_days=14, crisis_shock=0.0, disruption_factor=0.0):\n if not self.fitted:\n self.fit()\n base = float(self.hist[\"price\"].iloc[-1])\n shocked = base*(1+crisis_shock/100)\n dates = [datetime.today()+timedelta(days=i+1) for i in range(horizon_days)]\n if self.arima:\n arima_p = list(self.arima.forecast(steps=horizon_days))\n else:\n arima_p = [base+np.random.normal(0,1)*(i+1)**0.5 for i in range(horizon_days)]\n rw = list(self.hist[\"price\"].tail(14).values)\n if crisis_shock > 0:\n rw[-1] = shocked\n xgb_p = []\n for step in range(horizon_days):\n pw = rw[-14:]\n f = np.array([[pw[-1],pw[-3],pw[-7],pw[0],\n np.mean(pw[-7:]),np.std(pw[-7:]),np.mean(pw),\n (pw[-1]-pw[-4])/pw[-4] if pw[-4]!=0 else 0,\n (datetime.today().weekday()+step+1)%7]])\n pred = float(self.xgb.predict(self.scaler.transform(f))[0])\n pred *= (1+disruption_factor*0.8*(1-step/horizon_days))\n xgb_p.append(pred)\n rw.append(pred)\n w = 0.7 if crisis_shock > 0 else 0.4\n prices = [round(w*xgb_p[i]+(1-w)*arima_p[i],2) for i in range(horizon_days)]\n std = float(self.hist[\"price\"].pct_change().std())*base\n lower = [round(p-1.96*std*((i+1)**0.4),2) for i,p in enumerate(prices)]\n upper = [round(p+1.96*std*((i+1)**0.4),2) for i,p in enumerate(prices)]\n fp = prices[-1]\n pct = round((fp-base)/base*100,1)\n return {\n \"base_price\": round(base,2),\n \"shocked_price\": round(shocked,2),\n \"horizon_days\": horizon_days,\n \"forecast\": [{\"date\":d.strftime(\"%Y-%m-%d\"),\"price\":p,\"lower\":l,\"upper\":u}\n for d,p,l,u in zip(dates,prices,lower,upper)],\n \"summary\": {\n \"final_price\": fp, \"pct_change\": pct,\n \"peak_price\": round(max(prices),2),\n \"peak_day\": prices.index(max(prices))+1,\n \"risk_score\": min(100,round(abs(pct)*1.5+disruption_factor*40+(crisis_shock/100)*30,1)),\n \"delay_prob\": min(99,round(disruption_factor*65+(pct/100)*20,1)),\n \"cost_impact\": round(pct*0.35+disruption_factor*18,1),\n },\n \"model\": \"ARIMA+XGBoost hybrid\",\n }\n\n_fc = None\ndef get_forecaster():\n global _fc\n if _fc is None:\n _fc = AegisForecaster().fit()\n return _fc\n\n'''\nwith open(ROOT+\"/models/forecaster.py\",\"w\") as f: f.write(forecaster_code)\n\n# Write swarm.py (with MarineTraffic scraper)\nswarm_code = r'''\n\nimport asyncio, json, re, os, requests\nfrom bs4 import BeautifulSoup\nfrom datetime import datetime\nfrom groq import AsyncGroq\n\nMODEL = \"llama-3.3-70b-versatile\"\n\ndef _client():\n return AsyncGroq(api_key=os.environ[\"GROQ_API_KEY\"])\n\nasync def _llm(system, user, temperature=0.3):\n r = await _client().chat.completions.create(\n model=MODEL,\n messages=[{\"role\":\"system\",\"content\":system},{\"role\":\"user\",\"content\":user}],\n temperature=temperature, max_tokens=600)\n return r.choices[0].message.content.strip()\n\nasync def _json(system, user):\n raw = await _llm(system+\"\\n\\nRespond ONLY with valid JSON. No markdown.\", user)\n clean = re.sub(r\"```json|```\",\"\",raw).strip()\n try:\n return json.loads(clean)\n except:\n m = re.search(r\"\\{.*\\}\", clean, re.DOTALL)\n if m:\n try:\n return json.loads(m.group())\n except:\n pass\n return {\"raw\": raw}\n\ndef scrape_marine_traffic():\n headers = {\n \"User-Agent\": \"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 \"\n \"(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\",\n \"Accept\": \"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\",\n \"Accept-Language\": \"en-US,en;q=0.5\",\n }\n news_items = []\n sources_ok = []\n\n try:\n r = requests.get(\"https://gcaptain.com/\", headers=headers, timeout=10)\n if r.status_code == 200:\n soup = BeautifulSoup(r.text, \"lxml\")\n headlines = soup.find_all([\"h2\",\"h3\"], limit=8)\n for h in headlines:\n text = h.get_text(strip=True)\n if len(text) > 20 and len(text) < 300:\n news_items.append({\n \"source\": \"gCaptain\",\n \"headline\": text[:250],\n \"type\": \"maritime_news\"\n })\n if news_items:\n sources_ok.append(\"gCaptain\")\n except:\n pass\n\n try:\n r2 = requests.get(\"https://www.tradewindsnews.com/\", headers=headers, timeout=10)\n if r2.status_code == 200:\n soup2 = BeautifulSoup(r2.text, \"lxml\")\n headlines2 = soup2.find_all([\"h2\",\"h3\",\"h4\"], limit=6)\n count = 0\n for h in headlines2:\n text = h.get_text(strip=True)\n if len(text) > 20 and len(text) < 300:\n news_items.append({\n \"source\": \"TradeWinds\",\n \"headline\": text[:250],\n \"type\": \"shipping_intelligence\"\n })\n count += 1\n if count > 0:\n sources_ok.append(\"TradeWinds\")\n except:\n pass\n\n if not news_items:\n return {\n \"status\": \"simulated\",\n \"source\": \"Aegis Crisis Simulation\",\n \"sources_ok\": [],\n \"items\": [\n {\"source\":\"MarineTraffic\",\"headline\":\"3 tankers rerouted away from Strait of Hormuz amid escalating tensions\",\"type\":\"shipping_disruption\"},\n {\"source\":\"MarineTraffic\",\"headline\":\"Iranian Revolutionary Guard patrol boats spotted near major shipping lanes\",\"type\":\"security_alert\"},\n {\"source\":\"gCaptain\",\"headline\":\"War risk insurance premiums surge 40% for Gulf vessels\",\"type\":\"financial_impact\"},\n {\"source\":\"TradeWinds\",\"headline\":\"Major shipping lines suspend bookings through Hormuz indefinitely\",\"type\":\"operational_disruption\"},\n {\"source\":\"gCaptain\",\"headline\":\"Strait of Hormuz remains near-empty with just a few Iran ships moving\",\"type\":\"shipping_disruption\"},\n ],\n \"timestamp\": datetime.now().isoformat()\n }\n\n return {\n \"status\": \"live\",\n \"sources_ok\": sources_ok,\n \"items\": news_items[:8],\n \"total_found\": len(news_items),\n \"timestamp\": datetime.now().isoformat()\n }\n\nasync def signal_agent(event):\n marine_data = scrape_marine_traffic()\n event[\"marine_traffic\"] = marine_data\n r = await _json(\"\"\"You are the Signal Agent for Aegis. Classify incoming signals.\nYou have access to live MarineTraffic shipping news.\nReturn JSON: severity(LOW|MEDIUM|HIGH|CRITICAL), signal_type, anomalies(list),\nconfidence(0-100), summary(1 sentence), shipping_alerts(list of strings from marine data).\"\"\",\n f\"Event: {json.dumps(event)}\")\n r[\"agent\"] = \"signal\"\n r[\"marine_data\"] = marine_data\n return r\n\nasync def intelligence_agent(signal, event):\n r = await _json(\"\"\"You are the Intelligence Agent for Aegis. Interpret signals for business risk.\nReturn JSON: root_cause, affected_regions(list), supply_chain_impact(LOW|MEDIUM|HIGH|SEVERE),\nescalation_probability(0-100), geopolitical_context(1-2 sentences), time_to_impact_days(int).\"\"\",\n f\"Signal: {json.dumps(signal)}\\nEvent: {json.dumps(event)}\")\n r[\"agent\"] = \"intelligence\"\n return r\n\nasync def forecast_agent(intel, forecast_data):\n r = await _json(\"\"\"You are the Forecast Agent for Aegis. Interpret ML forecasts in business terms.\nReturn JSON: oil_outlook(string), price_trajectory(RISING|STABLE|FALLING|VOLATILE),\nsupply_risk_score(0-100), delay_probability(0-100), cost_impact_pct(float),\nconfidence_level(LOW|MEDIUM|HIGH), key_assumptions(list).\"\"\",\n f\"Intel: {json.dumps(intel)}\\nML summary: {json.dumps(forecast_data.get('summary',{}))}\")\n r[\"agent\"] = \"forecast\"\n r[\"ml_summary\"] = forecast_data.get(\"summary\",{})\n r[\"ml_forecast\"] = forecast_data.get(\"forecast\",[])[:14]\n return r\n\nasync def simulation_agent(forecast, event):\n r = await _json(\"\"\"You are the Simulation Agent for Aegis. Run 3 supply chain scenarios.\nReturn JSON: scenarios(list of: name,probability,cost_impact_pct,lead_time_increase_days,description,mitigation_available).\"\"\",\n f\"Forecast: {json.dumps(forecast)}\\nEvent: {json.dumps(event)}\")\n r[\"agent\"] = \"simulation\"\n if \"scenarios\" not in r or not isinstance(r[\"scenarios\"], list):\n r[\"scenarios\"] = []\n return r\n\nasync def decision_agent(simulation, forecast, intel):\n r = await _json(\"\"\"You are the Decision Agent for Aegis \u2014 the final brain.\nReturn JSON: threat_level(LOW|MEDIUM|HIGH|CRITICAL),\nrecommended_actions(list of: priority,action,rationale,estimated_savings_usd,time_to_implement,risk),\nexecutive_summary(2-3 sentences), do_nothing_cost_usd(int).\"\"\",\n f\"Scenarios: {json.dumps(simulation.get('scenarios',[]))}\\nForecast: {json.dumps(forecast.get('ml_summary',{}))}\\nIntel: {json.dumps(intel)}\")\n r[\"agent\"] = \"decision\"\n return r\n\nasync def alert_agent(decision, forecast):\n r = await _json(\"\"\"You are the Alert Agent for Aegis. Generate stakeholder alerts.\nReturn JSON: slack_message(string,max 200 chars), email_subject, email_body(3-4 sentences),\nseverity_emoji, notification_channels(list).\"\"\",\n f\"Decision: {json.dumps(decision)}\\nForecast: {json.dumps(forecast.get('ml_summary',{}))}\")\n r[\"agent\"] = \"alert\"\n return r\n\nasync def execution_agent(decision):\n r = await _json(\"\"\"You are the Execution Agent for Aegis. Determine workflows to trigger.\nReturn JSON: triggered_workflows(list of: system,action,api_endpoint,payload_summary,status,requires_human_approval),\nautonomous_actions_count(int), pending_approvals_count(int), execution_summary(1 sentence).\"\"\",\n f\"Actions: {json.dumps(decision.get('recommended_actions',[])[:3])}\")\n r[\"agent\"] = \"execution\"\n return r\n\nasync def run_aegis_pipeline(event, forecast_data):\n results = {\"event\": event, \"agents\": {}}\n sig = await signal_agent(event); results[\"agents\"][\"signal\"] = sig\n intel = await intelligence_agent(sig, event); results[\"agents\"][\"intelligence\"] = intel\n fore = await forecast_agent(intel, forecast_data); results[\"agents\"][\"forecast\"] = fore\n sim = await simulation_agent(fore, event); results[\"agents\"][\"simulation\"] = sim\n dec = await decision_agent(sim, fore, intel); results[\"agents\"][\"decision\"] = dec\n alert = await alert_agent(dec, fore); results[\"agents\"][\"alert\"] = alert\n exe = await execution_agent(dec); results[\"agents\"][\"execution\"] = exe\n print(\"\u2705 Pipeline complete\")\n return results\n\n'''\nwith open(ROOT+\"/agents/swarm.py\",\"w\") as f: f.write(swarm_code)\n\nprint(\"\u2705 forecaster.py and swarm.py written (MarineTraffic included)\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Cell 4 \u2014 Write FastAPI Server + Frontend" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\nROOT = \"/content/aegis\"\n\n# Write server.py\nserver_code = r'''\n\"\"\"\nAegis \u2014 FastAPI Server\nEndpoints:\n GET / \u2192 serves the demo frontend HTML\n GET /health \u2192 health check\n POST /api/crisis \u2192 run full 7-agent pipeline (returns JSON)\n GET /api/stream \u2192 SSE stream of agent activations\n POST /api/forecast \u2192 ML-only forecast (no LLM)\n GET /api/status \u2192 system status\n\nRun locally: uvicorn api.server:app --reload --port 8000\nRun in Colab: see AEGIS_COLAB.py (cell 3)\n\"\"\"\n\nimport asyncio\nimport json\nimport os\nimport sys\nfrom datetime import datetime\nfrom typing import AsyncGenerator\n\nfrom fastapi import FastAPI, HTTPException\nfrom fastapi.middleware.cors import CORSMiddleware\nfrom fastapi.responses import HTMLResponse, StreamingResponse\nfrom pydantic import BaseModel, Field\n\n# Add project root to path so imports work from Colab\nsys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))\n\nfrom agents.swarm import run_aegis_pipeline\nfrom models.forecaster import get_forecaster\n\n# \u2500\u2500 App \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\napp = FastAPI(\n title=\"Aegis\",\n description=\"Autonomous agentic crisis management system \u2014 AMD Hackathon Demo\",\n version=\"1.0.0\",\n)\n\napp.add_middleware(\n CORSMiddleware,\n allow_origins=[\"*\"],\n allow_methods=[\"*\"],\n allow_headers=[\"*\"],\n)\n\n\n# \u2500\u2500 Request / Response schemas \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nclass CrisisEvent(BaseModel):\n oil_price_change_pct: float = Field(default=18.0, description=\"% change in oil price\")\n shipping_disruption: str = Field(default=\"Strait of Hormuz \u2014 tanker reroutes detected\")\n news_headline: str = Field(default=\"Regional conflict escalation near Persian Gulf\")\n severity: str = Field(default=\"HIGH\")\n disruption_factor: float = Field(default=0.7, ge=0, le=1, description=\"Supply friction 0\u20131\")\n horizon_days: int = Field(default=14, ge=1, le=90)\n\n\nclass ForecastRequest(BaseModel):\n oil_shock_pct: float = Field(default=0.0)\n disruption_factor: float = Field(default=0.0, ge=0, le=1)\n horizon_days: int = Field(default=14, ge=1, le=90)\n\n\n# \u2500\u2500 Startup: pre-warm the forecaster \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n@app.on_event(\"startup\")\nasync def startup_event():\n print(\"\ud83d\udee1\ufe0f Aegis starting up...\")\n try:\n get_forecaster() # fits model on synthetic data\n print(\"\u2705 Forecaster ready\")\n except Exception as e:\n print(f\"\u26a0\ufe0f Forecaster startup warning: {e}\")\n\n\n# \u2500\u2500 Endpoints \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n@app.get(\"/health\")\nasync def health():\n return {\n \"status\": \"online\",\n \"system\": \"Aegis\",\n \"timestamp\": datetime.utcnow().isoformat(),\n \"agents\": 7,\n \"model\": \"ARIMA+XGBoost + Groq LLaMA-3.1-70B\",\n }\n\n\n@app.post(\"/api/forecast\")\nasync def forecast_only(req: ForecastRequest):\n \"\"\"Run ML forecast without triggering the full agent pipeline.\"\"\"\n try:\n fc = get_forecaster()\n result = fc.forecast(\n horizon_days=req.horizon_days,\n crisis_shock=req.oil_shock_pct,\n disruption_factor=req.disruption_factor,\n )\n return {\"success\": True, \"data\": result}\n except Exception as e:\n raise HTTPException(status_code=500, detail=str(e))\n\n\n@app.post(\"/api/crisis\")\nasync def run_crisis(event: CrisisEvent):\n \"\"\"\n Full 7-agent pipeline:\n 1. Run ML forecast\n 2. Pass to agent swarm (Groq LLM)\n 3. Return complete analysis\n \"\"\"\n try:\n # Step 1: ML forecast\n fc = get_forecaster()\n forecast_data = fc.forecast(\n horizon_days=event.horizon_days,\n crisis_shock=event.oil_price_change_pct,\n disruption_factor=event.disruption_factor,\n )\n\n # Step 2: Agent swarm\n event_dict = event.model_dump()\n results = await run_aegis_pipeline(event_dict, forecast_data)\n\n return {\n \"success\": True,\n \"timestamp\": datetime.utcnow().isoformat(),\n \"data\": results,\n }\n\n except Exception as e:\n import traceback\n raise HTTPException(status_code=500, detail=f\"{str(e)}\\n{traceback.format_exc()}\")\n\n\n@app.get(\"/api/stream\")\nasync def stream_crisis(\n oil_change: float = 18.0,\n disruption: float = 0.7,\n severity: str = \"HIGH\",\n):\n \"\"\"\n Server-Sent Events stream of agent activations.\n Connect with EventSource in JavaScript for live updates.\n \"\"\"\n async def event_generator() -> AsyncGenerator[str, None]:\n # Yield SSE format: \"data: {json}\\n\\n\"\n def sse(payload: dict) -> str:\n return f\"data: {json.dumps(payload)}\\n\\n\"\n\n yield sse({\"type\": \"start\", \"message\": \"Aegis pipeline initiated\"})\n\n try:\n fc = get_forecaster()\n forecast_data = fc.forecast(\n horizon_days=14,\n crisis_shock=oil_change,\n disruption_factor=disruption,\n )\n yield sse({\"type\": \"forecast_ready\", \"data\": forecast_data[\"summary\"]})\n\n event_dict = {\n \"oil_price_change_pct\": oil_change,\n \"shipping_disruption\": \"Strait of Hormuz disruption detected\",\n \"news_headline\": \"Geopolitical escalation near Persian Gulf\",\n \"severity\": severity,\n \"disruption_factor\": disruption,\n }\n\n # Import individual agents for streaming\n from agents.swarm import (\n signal_agent, intelligence_agent, forecast_agent,\n simulation_agent, decision_agent, alert_agent, execution_agent,\n )\n\n yield sse({\"type\": \"agent_start\", \"agent\": \"signal\", \"index\": 1})\n sig = await signal_agent(event_dict)\n yield sse({\"type\": \"agent_done\", \"agent\": \"signal\", \"data\": sig})\n\n yield sse({\"type\": \"agent_start\", \"agent\": \"intelligence\", \"index\": 2})\n intel = await intelligence_agent(sig, event_dict)\n yield sse({\"type\": \"agent_done\", \"agent\": \"intelligence\", \"data\": intel})\n\n yield sse({\"type\": \"agent_start\", \"agent\": \"forecast\", \"index\": 3})\n fore = await forecast_agent(intel, forecast_data)\n yield sse({\"type\": \"agent_done\", \"agent\": \"forecast\", \"data\": fore})\n\n yield sse({\"type\": \"agent_start\", \"agent\": \"simulation\", \"index\": 4})\n sim = await simulation_agent(fore, event_dict)\n yield sse({\"type\": \"agent_done\", \"agent\": \"simulation\", \"data\": sim})\n\n yield sse({\"type\": \"agent_start\", \"agent\": \"decision\", \"index\": 5})\n dec = await decision_agent(sim, fore, intel)\n yield sse({\"type\": \"agent_done\", \"agent\": \"decision\", \"data\": dec})\n\n yield sse({\"type\": \"agent_start\", \"agent\": \"alert\", \"index\": 6})\n alert = await alert_agent(dec, fore)\n yield sse({\"type\": \"agent_done\", \"agent\": \"alert\", \"data\": alert})\n\n yield sse({\"type\": \"agent_start\", \"agent\": \"execution\", \"index\": 7})\n exe = await execution_agent(dec)\n yield sse({\"type\": \"agent_done\", \"agent\": \"execution\", \"data\": exe})\n\n yield sse({\n \"type\": \"complete\",\n \"message\": \"All 7 agents completed\",\n \"summary\": dec.get(\"executive_summary\", \"\"),\n \"threat\": dec.get(\"threat_level\", \"\"),\n })\n\n except Exception as e:\n yield sse({\"type\": \"error\", \"message\": str(e)})\n\n return StreamingResponse(\n event_generator(),\n media_type=\"text/event-stream\",\n headers={\n \"Cache-Control\": \"no-cache\",\n \"X-Accel-Buffering\": \"no\",\n },\n )\n\n\n@app.get(\"/api/status\")\nasync def system_status():\n \"\"\"Returns live system status for the dashboard.\"\"\"\n import random\n return {\n \"agents_online\": 7,\n \"uptime_seconds\": int(datetime.utcnow().timestamp()) % 86400,\n \"oil_price\": round(82 + random.uniform(-2, 2), 2),\n \"risk_level\": \"LOW\",\n \"last_event\": None,\n \"groq_model\": \"llama-3.3-70b-versatile\",\n \"forecast_model\": \"ARIMA(2,1,2) + XGBoost\",\n }\n\n\n@app.get(\"/\", response_class=HTMLResponse)\nasync def serve_frontend():\n \"\"\"Serve the demo HTML directly from the API for easy Colab sharing.\"\"\"\n html = \"\"\"\n\n
\n\n\n