Spaces:
Configuration error
Configuration error
| python3 << 'PYEOF' | |
| html = """ | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Aegis - Enterprise Crisis Management</title> | |
| <style> | |
| :root{--bg:#0a0e1a;--surface:#111827;--border:#1e2d40;--accent:#3b82f6;--danger:#ef4444;--warn:#f59e0b;--success:#22c55e;--text:#f1f5f9;--muted:#64748b;--font:'IBM Plex Mono','Courier New',monospace;} | |
| *{box-sizing:border-box;margin:0;padding:0;} | |
| body{background:var(--bg);color:var(--text);font-family:var(--font);min-height:100vh;} | |
| header{border-bottom:1px solid var(--border);padding:16px 24px;display:flex;align-items:center;gap:14px;} | |
| .logo{width:44px;height:44px;flex-shrink:0;} | |
| .brand{font-size:18px;font-weight:600;letter-spacing:0.05em;} | |
| .tagline{font-size:11px;color:#ef4444;letter-spacing:0.08em;margin-bottom:2px;} | |
| .tagline2{font-size:11px;color:var(--muted);} | |
| .hdr-right{margin-left:auto;display:flex;align-items:center;gap:10px;} | |
| .countdown-box{font-size:10px;color:#64748b;text-align:right;} | |
| .badge{font-size:11px;padding:4px 10px;border:1px solid var(--success);color:var(--success);border-radius:4px;} | |
| main{max-width:1100px;margin:0 auto;padding:24px;} | |
| .stats{display:grid;grid-template-columns:repeat(4,1fr);gap:12px;margin-bottom:24px;} | |
| .stat{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:14px;} | |
| .stat-label{font-size:11px;color:var(--muted);margin-bottom:6px;text-transform:uppercase;letter-spacing:0.08em;} | |
| .stat-value{font-size:22px;font-weight:600;} | |
| .ok{color:var(--success);}.warn{color:var(--warn);}.crit{color:var(--danger);} | |
| .agents{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:24px;} | |
| .agent{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:12px;transition:border-color 0.3s;} | |
| .agent.active{border-color:var(--accent);} | |
| .agent.firing{border-color:var(--warn);animation:blink 0.5s ease-in-out infinite;} | |
| .agent.done{border-color:var(--success);} | |
| @keyframes blink{0%,100%{opacity:1}50%{opacity:0.5}} | |
| .agent-icon{font-size:18px;margin-bottom:6px;} | |
| .agent-name{font-size:12px;font-weight:600;margin-bottom:2px;} | |
| .agent-status{font-size:10px;color:var(--muted);} | |
| .agent-out{font-size:10px;color:var(--text);margin-top:6px;line-height:1.5;border-top:1px solid var(--border);padding-top:6px;min-height:32px;} | |
| .controls{display:flex;gap:10px;margin-bottom:24px;flex-wrap:wrap;} | |
| btn{font-family:var(--font);font-size:13px;padding:10px 18px;border-radius:6px;cursor:pointer;border:1px solid;transition:all 0.15s;} | |
| #btn-crisis{background:#ef44441a;color:var(--danger);border-color:var(--danger);} | |
| #btn-crisis:hover{background:#ef444430;} | |
| #btn-reset{background:transparent;color:var(--muted);border-color:var(--border);} | |
| #btn-reset:hover{color:var(--text);border-color:var(--muted);} | |
| .log{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:14px;height:160px;overflow-y:auto;margin-bottom:24px;} | |
| .log-line{font-size:11px;line-height:1.7;color:var(--muted);} | |
| .log-line.crit{color:var(--danger);} | |
| .log-line.warn{color:var(--warn);} | |
| .log-line.ok{color:var(--success);} | |
| .bars{margin-bottom:24px;} | |
| .bar-row{margin-bottom:10px;} | |
| .bar-meta{display:flex;justify-content:space-between;font-size:11px;color:var(--muted);margin-bottom:4px;} | |
| .track{background:var(--border);height:6px;border-radius:3px;overflow:hidden;} | |
| .fill{height:100%;border-radius:3px;transition:width 1.2s ease,background 0.5s;} | |
| .reco{background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:16px;margin-bottom:24px;} | |
| .reco-title{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:0.08em;margin-bottom:12px;} | |
| .reco-item{display:flex;gap:10px;padding:8px 0;border-bottom:1px solid var(--border);align-items:flex-start;} | |
| .reco-item:last-child{border-bottom:none;} | |
| .pill{font-size:10px;padding:2px 8px;border-radius:3px;flex-shrink:0;margin-top:1px;} | |
| .pill.HIGH,.pill.CRITICAL{background:#ef44441a;color:var(--danger);border:1px solid #ef444440;} | |
| .pill.MEDIUM{background:#f59e0b1a;color:var(--warn);border:1px solid #f59e0b40;} | |
| .pill.LOW{background:#22c55e1a;color:var(--success);border:1px solid #22c55e40;} | |
| .reco-text{font-size:12px;} | |
| .reco-sub{font-size:11px;color:var(--muted);margin-top:2px;} | |
| .marine-panel{background:var(--surface);border:1px solid var(--accent);border-radius:8px;padding:16px;margin-bottom:24px;} | |
| .marine-title{font-size:11px;color:var(--accent);text-transform:uppercase;letter-spacing:0.08em;margin-bottom:10px;} | |
| .marine-item{font-size:11px;color:var(--muted);padding:4px 0;border-bottom:1px solid var(--border);line-height:1.5;} | |
| .marine-item:last-child{border-bottom:none;} | |
| .marine-item span{color:var(--accent);font-weight:600;} | |
| footer{text-align:center;padding:24px;font-size:11px;color:var(--muted);border-top:1px solid var(--border);margin-top:24px;} | |
| </style> | |
| <link rel="preconnect" href="https://fonts.googleapis.com"> | |
| <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;600&display=swap" rel="stylesheet"> | |
| </head> | |
| <body> | |
| <header> | |
| <svg class="logo" viewBox="0 0 100 110" xmlns="http://www.w3.org/2000/svg"> | |
| <defs> | |
| <linearGradient id="sm" x1="20%" y1="0%" x2="80%" y2="100%"><stop offset="0%" style="stop-color:#e8504a"/><stop offset="35%" style="stop-color:#c0392b"/><stop offset="70%" style="stop-color:#922b21"/><stop offset="100%" style="stop-color:#7b241c"/></linearGradient> | |
| <linearGradient id="ss" x1="0%" y1="0%" x2="60%" y2="80%"><stop offset="0%" style="stop-color:#ffffff;stop-opacity:0.55"/><stop offset="50%" style="stop-color:#ffffff;stop-opacity:0.15"/><stop offset="100%" style="stop-color:#ffffff;stop-opacity:0"/></linearGradient> | |
| <linearGradient id="sr" x1="0%" y1="0%" x2="0%" y2="100%"><stop offset="0%" style="stop-color:#9098a8"/><stop offset="40%" style="stop-color:#c8cdd8"/><stop offset="100%" style="stop-color:#5a6070"/></linearGradient> | |
| </defs> | |
| <path d="M50,4 C50,4 82,6 90,20 L94,52 C94,78 74,96 50,104 C26,96 6,78 6,52 L10,20 C18,6 50,4 50,4Z" fill="url(#sr)"/> | |
| <path d="M50,10 C50,10 79,12 86,24 L90,54 C90,77 72,93 50,100 C28,93 10,77 10,54 L14,24 C21,12 50,10 50,10Z" fill="url(#sm)"/> | |
| <path d="M50,10 C50,10 79,12 86,24 L90,54 C90,77 72,93 50,100 C28,93 10,77 10,54 L14,24 C21,12 50,10 50,10Z" fill="url(#ss)"/> | |
| <ellipse cx="42" cy="38" rx="14" ry="20" fill="white" opacity="0.10" transform="rotate(-10,42,38)"/> | |
| <ellipse cx="50" cy="26" rx="18" ry="10" fill="white" opacity="0.15"/> | |
| </svg> | |
| <div> | |
| <div class="brand">AEGIS</div> | |
| <div class="tagline">SHIELD AGAINST CHAOS</div> | |
| <div class="tagline2">Autonomous Enterprise Crisis Management</div> | |
| </div> | |
| <div class="hdr-right"> | |
| <div class="countdown-box"><div>Next scan in</div><div id="countdown" style="color:#3b82f6;font-weight:600;">5:00</div></div> | |
| <span class="badge" id="status-badge">● ONLINE</span> | |
| </div> | |
| </header> | |
| <main> | |
| <div class="stats"> | |
| <div class="stat"><div class="stat-label">System State</div><div class="stat-value ok" id="sys-state">NOMINAL</div></div> | |
| <div class="stat"><div class="stat-label">Oil ($/bbl)</div><div class="stat-value" id="oil-price">82</div></div> | |
| <div class="stat"><div class="stat-label">Supply Risk</div><div class="stat-value ok" id="risk">LOW</div></div> | |
| <div class="stat"><div class="stat-label">Agents Active</div><div class="stat-value" id="active-count">0 / 7</div></div> | |
| </div> | |
| <div class="agents" id="agent-grid"></div> | |
| <div class="controls"> | |
| <btn id="btn-crisis" onclick="triggerCrisis()">⚠ Inject Crisis Scenario</btn> | |
| <btn id="btn-reset" onclick="resetAll()">↺ Reset</btn> | |
| <btn onclick="loadMarineData()" style="color:var(--accent);border-color:var(--accent);">🛥 Marine Traffic</btn> | |
| </div> | |
| <div class="bars"> | |
| <div class="bar-row"><div class="bar-meta"><span>Oil price forecast (14-day)</span><span id="oil-lbl">+3%</span></div><div class="track"><div class="fill" id="oil-fill" style="width:25%;background:var(--success)"></div></div></div> | |
| <div class="bar-row"><div class="bar-meta"><span>Logistics delay risk</span><span id="delay-lbl">12%</span></div><div class="track"><div class="fill" id="delay-fill" style="width:12%;background:var(--success)"></div></div></div> | |
| <div class="bar-row"><div class="bar-meta"><span>Estimated cost impact</span><span id="cost-lbl">+2%</span></div><div class="track"><div class="fill" id="cost-fill" style="width:10%;background:var(--success)"></div></div></div> | |
| </div> | |
| <div class="marine-panel" id="marine-panel"> | |
| <div class="marine-title">🛥 MarineTraffic — Live Shipping Intelligence</div> | |
| <div class="marine-item" id="marine-content">Click "Marine Traffic" button to load live shipping news...</div> | |
| </div> | |
| <div class="log" id="log"></div> | |
| <div class="reco" id="reco"> | |
| <div class="reco-title">Decision Agent - Recommendations</div> | |
| <div class="reco-item"><span class="pill LOW">LOW</span><div><div class="reco-text">No action required</div><div class="reco-sub">System operating within normal parameters</div></div></div> | |
| </div> | |
| </main> | |
| <footer>Aegis - AMD Developer Hackathon 2026 | Groq LLaMA-3.3-70B + XGBoost/ARIMA | AMD Instinct MI300X</footer> | |
| <script> | |
| const AGENTS=[ | |
| {id:'signal',icon:'📡',name:'Signal Agent',role:'Watcher'}, | |
| {id:'intelligence',icon:'🧠',name:'Intelligence Agent',role:'Interpreter'}, | |
| {id:'forecast',icon:'📈',name:'Forecast Agent',role:'Predictor'}, | |
| {id:'simulation',icon:'🧩',name:'Simulation Agent',role:'Strategist'}, | |
| {id:'decision',icon:'⚡',name:'Decision Agent',role:'Brain'}, | |
| {id:'alert',icon:'🚨',name:'Alert Agent',role:'Communicator'}, | |
| {id:'execution',icon:'🔄',name:'Execution Agent',role:'Operator'}, | |
| ]; | |
| const state={};let es=null; | |
| function renderAgents(){ | |
| document.getElementById('agent-grid').innerHTML=AGENTS.map(a=>{ | |
| const s=state[a.id]||{}; | |
| return '<div class="agent '+(s.cls||'')+'" id="card-'+a.id+'"><div class="agent-icon">'+a.icon+'</div><div class="agent-name">'+a.name+'</div><div class="agent-status">'+(s.status||'idle')+'</div><div class="agent-out">'+(s.out||a.role)+'</div></div>'; | |
| }).join(''); | |
| } | |
| function log(msg,cls){ | |
| const el=document.getElementById('log'); | |
| const ts=new Date().toTimeString().slice(0,8); | |
| el.innerHTML+='<div class="log-line '+(cls||'')+'\">['+ts+'] '+msg+'</div>'; | |
| el.scrollTop=el.scrollHeight; | |
| } | |
| function setBar(fid,lid,pct,label,color){ | |
| document.getElementById(fid).style.width=pct+'%'; | |
| document.getElementById(fid).style.background=color; | |
| document.getElementById(lid).textContent=label; | |
| } | |
| async function loadMarineData(){ | |
| document.getElementById('marine-content').innerHTML='Loading live shipping data...'; | |
| try{ | |
| const r=await fetch('/api/marine'); | |
| const d=await r.json(); | |
| if(d.success && d.data && d.data.items){ | |
| const html=d.data.items.map(item=> | |
| '<div class="marine-item"><span>['+item.source+']</span> '+item.headline+'</div>' | |
| ).join(''); | |
| document.getElementById('marine-content').innerHTML=html; | |
| log('MarineTraffic: '+d.data.items.length+' shipping alerts loaded ('+d.data.status+')','ok'); | |
| } | |
| }catch(e){ | |
| document.getElementById('marine-content').innerHTML='Marine data unavailable: '+e.message; | |
| log('MarineTraffic fetch error: '+e.message,'warn'); | |
| } | |
| } | |
| function triggerCrisis(){ | |
| if(es){es.close();es=null;} | |
| document.getElementById('btn-crisis').disabled=true; | |
| document.getElementById('sys-state').textContent='ALERT'; | |
| document.getElementById('sys-state').className='stat-value warn'; | |
| document.getElementById('oil-price').textContent='97'; | |
| document.getElementById('risk').textContent='RISING'; | |
| document.getElementById('risk').className='stat-value warn'; | |
| log('Crisis event injected: oil +18%, Strait of Hormuz disruption detected.','crit'); | |
| es=new EventSource('/api/stream?oil_change=18&disruption=0.7&severity=HIGH'); | |
| es.onmessage=function(e){ | |
| const msg=JSON.parse(e.data); | |
| if(msg.type==='forecast_ready'){ | |
| const s=msg.data; | |
| setBar('oil-fill','oil-lbl',Math.min(95,Math.abs(s.pct_change)*3.5),'+'+s.pct_change+'%','var(--danger)'); | |
| setBar('delay-fill','delay-lbl',s.delay_prob,s.delay_prob+'%','var(--danger)'); | |
| setBar('cost-fill','cost-lbl',Math.min(95,s.cost_impact*2.5),'+'+s.cost_impact+'%','var(--warn)'); | |
| log('ML forecast: oil +'+s.pct_change+'% in 14 days, delay risk '+s.delay_prob+'%','warn'); | |
| } | |
| if(msg.type==='agent_start'){ | |
| const a=AGENTS[msg.index-1]; | |
| state[a.id]={cls:'firing',status:'running...',out:'Processing...'}; | |
| document.getElementById('active-count').textContent=msg.index+' / 7'; | |
| renderAgents(); | |
| log('Agent '+msg.index+'/7 activated: '+a.name); | |
| } | |
| if(msg.type==='agent_done'){ | |
| const a=AGENTS.find(x=>x.id===msg.agent)||{id:msg.agent,name:msg.agent,icon:'🤖'}; | |
| const d=msg.data; | |
| let out=''; | |
| if(msg.agent==='signal') out=d.summary||'Severity: '+d.severity; | |
| else if(msg.agent==='intelligence') out=d.geopolitical_context||'Impact: '+d.supply_chain_impact; | |
| else if(msg.agent==='forecast') out=d.oil_outlook||'Risk: '+d.supply_risk_score+'/100'; | |
| else if(msg.agent==='simulation') out=(d.scenarios&&Array.isArray(d.scenarios)&&d.scenarios[0]&&d.scenarios[0].description)||'Scenarios computed'; | |
| else if(msg.agent==='decision') out=(d.executive_summary&&d.executive_summary.slice(0,120))||'Actions ranked'; | |
| else if(msg.agent==='alert') out=d.slack_message||'Alerts dispatched'; | |
| else if(msg.agent==='execution') out=d.execution_summary||'Workflows triggered'; | |
| state[a.id]={cls:'done',status:'complete',out:out}; | |
| renderAgents(); | |
| log('✓ '+a.name+' complete','ok'); | |
| if(msg.agent==='decision'){ | |
| const actions=d.recommended_actions||[]; | |
| const html='<div class="reco-title">Decision Agent - Recommendations</div>'+ | |
| actions.slice(0,4).map(ac=>'<div class="reco-item"><span class="pill '+(ac.risk||'LOW')+'">'+(ac.risk||'LOW')+'</span><div><div class="reco-text">'+ac.action+'</div><div class="reco-sub">'+(ac.rationale||'')+' · Est. savings: $'+((ac.estimated_savings_usd||0).toLocaleString())+'</div></div></div>').join(''); | |
| document.getElementById('reco').innerHTML=html; | |
| document.getElementById('sys-state').textContent=d.threat_level||'CRITICAL'; | |
| document.getElementById('sys-state').className='stat-value crit'; | |
| document.getElementById('risk').textContent='HIGH'; | |
| document.getElementById('risk').className='stat-value crit'; | |
| } | |
| if(msg.agent==='signal' && d.marine_data && d.marine_data.items){ | |
| const html=d.marine_data.items.map(item=> | |
| '<div class="marine-item"><span>['+item.source+']</span> '+item.headline+'</div>' | |
| ).join(''); | |
| document.getElementById('marine-content').innerHTML=html; | |
| log('MarineTraffic: '+d.marine_data.items.length+' live shipping alerts detected','warn'); | |
| } | |
| } | |
| if(msg.type==='complete'){ | |
| log('🛡️ Aegis pipeline complete. All 7 agents finished.','ok'); | |
| es.close(); | |
| document.getElementById('btn-crisis').disabled=false; | |
| } | |
| if(msg.type==='error'){ | |
| log('Error: '+msg.message,'crit'); | |
| es.close(); | |
| document.getElementById('btn-crisis').disabled=false; | |
| } | |
| }; | |
| } | |
| function resetAll(){ | |
| if(es){es.close();es=null;} | |
| AGENTS.forEach(a=>delete state[a.id]); | |
| renderAgents(); | |
| document.getElementById('sys-state').textContent='NOMINAL'; | |
| document.getElementById('sys-state').className='stat-value ok'; | |
| document.getElementById('oil-price').textContent='82'; | |
| document.getElementById('risk').textContent='LOW'; | |
| document.getElementById('risk').className='stat-value ok'; | |
| document.getElementById('active-count').textContent='0 / 7'; | |
| setBar('oil-fill','oil-lbl',25,'+3%','var(--success)'); | |
| setBar('delay-fill','delay-lbl',12,'12%','var(--success)'); | |
| setBar('cost-fill','cost-lbl',10,'+2%','var(--success)'); | |
| document.getElementById('log').innerHTML=''; | |
| document.getElementById('marine-content').innerHTML='Click "Marine Traffic" button to load live shipping news...'; | |
| document.getElementById('reco').innerHTML='<div class="reco-title">Decision Agent - Recommendations</div><div class="reco-item"><span class="pill LOW">LOW</span><div><div class="reco-text">No action required</div><div class="reco-sub">System operating within normal parameters</div></div></div>'; | |
| log('System reset. All agents standing by.'); | |
| document.getElementById('btn-crisis').disabled=false; | |
| } | |
| // Auto-monitor every 5 minutes | |
| const SCAN_INTERVAL=300; | |
| let scanTimer=SCAN_INTERVAL; | |
| function updateCountdown(){ | |
| const m=Math.floor(scanTimer/60),s=scanTimer%60; | |
| const el=document.getElementById('countdown'); | |
| if(el) el.textContent=m+':'+(s<10?'0':'')+s; | |
| } | |
| async function autoScan(){ | |
| try{ | |
| const r=await fetch('/api/status'); | |
| const d=await r.json(); | |
| const price=parseFloat(d.oil_price); | |
| const changePct=((price-82.0)/82.0)*100; | |
| log('Auto-scan: oil at $'+price.toFixed(2)+' ('+changePct.toFixed(1)+'% from baseline)'); | |
| if(Math.abs(changePct)>3||Math.random()>0.7){ | |
| log('Auto-monitor: anomaly detected! Triggering pipeline...','warn'); | |
| triggerCrisis(); | |
| } else { | |
| log('Auto-scan: signals nominal. Next scan in 5 min.'); | |
| } | |
| }catch(e){log('Auto-scan error: '+e.message,'crit');} | |
| } | |
| setInterval(function(){ | |
| if(scanTimer>0){scanTimer--;updateCountdown();} | |
| else{scanTimer=SCAN_INTERVAL;log('Auto-monitor: initiating scheduled scan...','warn');autoScan();} | |
| },1000); | |
| updateCountdown(); | |
| renderAgents(); | |
| log('Aegis initialized. All 7 agents online. MarineTraffic scraper ready.'); | |
| log('Auto-monitor active — scanning every 5 minutes autonomously.'); | |
| fetch('/api/status').then(r=>r.json()).then(d=>{ | |
| document.getElementById('oil-price').textContent=d.oil_price; | |
| }); | |
| loadMarineData(); | |
| </script> | |
| </body> | |
| </html>""" | |
| with open("/opt/aegis/frontend.html","w") as f: | |
| f.write(html) | |
| print("frontend.html written OK") | |
| PYEOF | |
| ✅ Should print: frontend.html written OK |