petter2025's picture
Update app.py
663691e verified
raw
history blame
125 kB
# app.py - Complete fixed version with Plotly compatibility
# πŸš€ ARF Ultimate Investor Demo v3.3.9 - ENTERPRISE EDITION
# Enhanced with clear OSS vs Enterprise boundaries
# UPDATED: Added realism panel integration for enterprise-seasoned SRE experience
# UPDATED: Added dynamic performance metrics for Phase 2
import logging
import sys
import traceback
import json
import datetime
import asyncio
import time
import random
from pathlib import Path
from typing import Dict, List, Any, Optional, Tuple
# ===========================================
# CONFIGURE LOGGING FIRST
# ===========================================
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(sys.stdout),
logging.FileHandler('arf_demo.log')
]
)
logger = logging.getLogger(__name__)
# Add parent directory to path
sys.path.insert(0, str(Path(__file__).parent))
# ===========================================
# FIX FOR ASYNC EVENT LOOP ISSUES
# ===========================================
try:
import nest_asyncio
nest_asyncio.apply()
logger.info("βœ… Applied nest_asyncio for async event loop compatibility")
except ImportError:
logger.warning("⚠️ nest_asyncio not available, async operations may have issues")
# ===========================================
# IMPORT UTILITY CLASSES FIRST
# ===========================================
from utils.installation import InstallationHelper
from demo.guidance import DemoPsychologyController, get_demo_controller
# ===========================================
# BOUNDARY MANAGEMENT SYSTEM
# ===========================================
class BoundaryManager:
"""Manages clear boundaries between OSS and Enterprise"""
@staticmethod
def get_system_boundaries():
"""Get current system boundaries"""
installation = get_installation_status()
return {
"oss": {
"available": installation["oss_installed"],
"version": installation["oss_version"] or "mock",
"label": installation["badges"]["oss"]["text"],
"color": installation["badges"]["oss"]["color"],
"icon": installation["badges"]["oss"]["icon"],
"capabilities": ["advisory_analysis", "rag_search", "healing_intent"],
"license": "Apache 2.0"
},
"enterprise": {
"available": installation["enterprise_installed"],
"version": installation["enterprise_version"] or "simulated",
"label": installation["badges"]["enterprise"]["text"],
"color": installation["badges"]["enterprise"]["color"],
"icon": installation["badges"]["enterprise"]["icon"],
"capabilities": ["autonomous_execution", "rollback_guarantee", "mcp_integration", "enterprise_support"],
"license": "Commercial"
},
"demo_mode": {
"active": True,
"architecture": "OSS advises β†’ Enterprise executes",
"boundary_visible": settings.show_boundaries
}
}
@staticmethod
def get_boundary_badges() -> str:
"""Get HTML badges showing system boundaries"""
boundaries = BoundaryManager.get_system_boundaries()
return f"""
<div style="display: flex; justify-content: center; gap: 20px; margin: 0 auto 25px auto;
max-width: 800px; flex-wrap: wrap;">
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 20px;
background: linear-gradient(135deg, {boundaries['oss']['color']}22 0%, {boundaries['oss']['color']}11 100%);
border: 2px solid {boundaries['oss']['color']}; border-radius: 12px;">
<div style="font-size: 24px;">{boundaries['oss']['icon']}</div>
<div>
<div style="font-size: 14px; font-weight: 600; color: {boundaries['oss']['color']};">
{boundaries['oss']['label']}
</div>
<div style="font-size: 11px; color: #64748b;">
Apache 2.0 β€’ Advisory Intelligence
</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 20px;
background: linear-gradient(135deg, {boundaries['enterprise']['color']}22 0%, {boundaries['enterprise']['color']}11 100%);
border: 2px solid {boundaries['enterprise']['color']}; border-radius: 12px;">
<div style="font-size: 24px;">{boundaries['enterprise']['icon']}</div>
<div>
<div style="font-size: 14px; font-weight: 600; color: {boundaries['enterprise']['color']};">
{boundaries['enterprise']['label']}
</div>
<div style="font-size: 11px; color: #64748b;">
Commercial β€’ Autonomous Execution
</div>
</div>
</div>
<div style="display: flex; align-items: center; gap: 10px; padding: 12px 20px;
background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
border: 2px dashed #94a3b8; border-radius: 12px;">
<div style="font-size: 24px;">πŸ—οΈ</div>
<div>
<div style="font-size: 14px; font-weight: 600; color: #475569;">
Architecture Boundary
</div>
<div style="font-size: 11px; color: #64748b;">
OSS advises β†’ Enterprise executes
</div>
</div>
</div>
</div>
"""
@staticmethod
def create_boundary_indicator(action: str, is_simulated: bool = True) -> str:
"""Create clear execution boundary indicator"""
if is_simulated:
return f"""
<div style="border: 3px dashed #f59e0b; border-radius: 16px; padding: 25px;
background: linear-gradient(135deg, #fef3c7 0%, #fde68a 100%);
text-align: center; margin: 20px 0;">
<div style="font-size: 36px; margin-bottom: 15px;">🎭</div>
<h4 style="margin: 0 0 12px 0; font-size: 20px; color: #92400e; font-weight: 700;">
SIMULATED ENTERPRISE EXECUTION
</h4>
<p style="font-size: 15px; color: #92400e; margin-bottom: 15px; line-height: 1.6;">
<strong>Action:</strong> {action}<br>
<strong>Mode:</strong> Enterprise Simulation (not real execution)<br>
<strong>Boundary:</strong> OSS advises β†’ Enterprise would execute
</p>
<div style="display: inline-block; padding: 10px 24px; background: #92400e;
border-radius: 20px; font-size: 14px; font-weight: bold; color: white;
text-transform: uppercase; letter-spacing: 1px;">
DEMO BOUNDARY
</div>
<p style="font-size: 13px; color: #92400e; margin-top: 15px; font-style: italic;">
In production, Enterprise edition would execute against real infrastructure
</p>
</div>
"""
else:
return f"""
<div style="border: 3px solid #10b981; border-radius: 16px; padding: 25px;
background: linear-gradient(135deg, #f0fdf4 0%, #bbf7d0 100%);
text-align: center; margin: 20px 0;">
<div style="font-size: 36px; margin-bottom: 15px;">⚑</div>
<h4 style="margin: 0 0 12px 0; font-size: 20px; color: #065f46; font-weight: 700;">
REAL ENTERPRISE EXECUTION
</h4>
<p style="font-size: 15px; color: #065f46; margin-bottom: 15px; line-height: 1.6;">
<strong>Action:</strong> {action}<br>
<strong>Mode:</strong> Enterprise Autonomous<br>
<strong>Boundary:</strong> Real execution with safety guarantees
</p>
<div style="display: inline-block; padding: 10px 24px; background: #065f46;
border-radius: 20px; font-size=14px; font-weight: bold; color: white;
text-transform: uppercase; letter-spacing: 1px;">
ENTERPRISE+
</div>
</div>
"""
# ===========================================
# ASYNC UTILITIES
# ===========================================
class AsyncRunner:
"""Enhanced async runner with better error handling"""
@staticmethod
def run_async(coro):
"""Run async coroutine in sync context"""
try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
return loop.run_until_complete(coro)
except Exception as e:
logger.error(f"Async execution failed: {e}")
return {"error": str(e), "status": "failed", "boundary_note": "Execution boundary reached"}
@staticmethod
def async_to_sync(async_func):
"""Decorator to convert async function to sync"""
def wrapper(*args, **kwargs):
try:
return AsyncRunner.run_until_complete(async_func(*args, **kwargs))
except Exception as e:
logger.error(f"Async to sync conversion failed: {e}")
return {"error": str(e), "status": "failed", "boundary_context": "OSS advisory only - execution requires Enterprise"}
return wrapper
# ===========================================
# SIMPLE SETTINGS - FIXED: Added missing attribute
# ===========================================
class Settings:
"""Simple settings class - FIXED: Added default_savings_rate"""
def __init__(self):
self.arf_mode = "demo"
self.use_true_arf = True
self.default_scenario = "Cache Miss Storm"
self.max_history_items = 100
self.auto_refresh_seconds = 30
self.show_boundaries = True
self.architectural_honesty = True
self.engineer_annual_cost = 200000
self.default_savings_rate = 0.25 # FIXED: Added missing attribute
settings = Settings()
# ===========================================
# ARF INSTALLATION CHECK - FIXED VERSION
# ===========================================
def check_arf_installation():
"""Check if real ARF packages are installed - Fixed version"""
results = {
"oss_installed": False,
"enterprise_installed": False,
"oss_version": None,
"enterprise_version": None,
"oss_edition": "unknown",
"oss_license": "unknown",
"execution_allowed": False,
"recommendations": [],
"boundaries": {
"oss_can": ["advisory_analysis", "rag_search", "healing_intent"],
"oss_cannot": ["execute", "modify_infra", "autonomous_healing"],
"enterprise_requires": ["license", "infra_access", "safety_controls"]
},
"badges": {
"oss": {"text": "⚠️ Mock ARF", "color": "#f59e0b", "icon": "⚠️"},
"enterprise": {"text": "πŸ”’ Enterprise Required", "color": "#64748b", "icon": "πŸ”’"}
},
"timestamp": datetime.datetime.now().isoformat()
}
# Check OSS package using InstallationHelper
installation_helper = InstallationHelper()
status = installation_helper.check_installation()
results["oss_installed"] = status["oss_installed"]
results["oss_version"] = status["oss_version"]
results["enterprise_installed"] = status["enterprise_installed"]
results["enterprise_version"] = status["enterprise_version"]
results["recommendations"] = status["recommendations"]
if results["oss_installed"]:
results["badges"]["oss"] = {
"text": f"βœ… ARF OSS v{results['oss_version']}",
"color": "#10b981",
"icon": "βœ…"
}
logger.info(f"βœ… ARF OSS v{results['oss_version']} detected")
else:
results["badges"]["oss"] = {
"text": "βœ… ARF OSS v3.3.9",
"color": "#10b981",
"icon": "βœ…"
}
logger.info("βœ… ARF OSS v3.3.9 (demo mode)")
if results["enterprise_installed"]:
results["badges"]["enterprise"] = {
"text": f"πŸš€ Enterprise v{results['enterprise_version']}",
"color": "#8b5cf6",
"icon": "πŸš€"
}
logger.info(f"βœ… ARF Enterprise v{results['enterprise_version']} detected")
else:
# βœ… ADD THIS MISSING ENTERPRISE ELSE BLOCK:
results["badges"]["enterprise"] = {
"text": "🏒 Enterprise Edition", # Changed from "πŸ”’ Enterprise Required"
"color": "#3b82f6", # Changed from "#64748b" (gray to blue)
"icon": "🏒" # Changed from "πŸ”’"
}
logger.info("🏒 Enterprise Edition (simulated)")
return results
_installation_status = None
def get_installation_status():
"""Get cached installation status"""
global _installation_status
if _installation_status is None:
_installation_status = check_arf_installation()
return _installation_status
# ===========================================
# PLOTLY CONFIGURATION FOR GRADIO COMPATIBILITY
# ===========================================
import plotly.graph_objects as go
import plotly.express as px
import plotly.io as pio
import pandas as pd
import numpy as np
# Configure Plotly for Gradio compatibility
pio.templates.default = "plotly_white"
logger.info("βœ… Plotly configured for Gradio compatibility")
# ===========================================
# ENHANCED VISUALIZATION FUNCTIONS WITH GRADIO COMPATIBILITY
# ===========================================
def create_simple_telemetry_plot(scenario_name: str, is_real_arf: bool = True) -> go.Figure:
"""
FIXED: Enhanced for Gradio compatibility with better error handling
"""
try:
# Generate sample telemetry data
times = pd.date_range(start=datetime.datetime.now() - datetime.timedelta(minutes=10),
end=datetime.datetime.now(),
periods=60)
# Different patterns based on scenario
if "Cache" in scenario_name:
normal_values = np.random.normal(30, 5, 30).tolist()
anomaly_values = np.random.normal(85, 10, 30).tolist()
data = normal_values + anomaly_values
title = f"Cache Hit Rate: {scenario_name}"
y_label = "Hit Rate (%)"
threshold = 75
elif "Database" in scenario_name:
normal_values = np.random.normal(15, 3, 30).tolist()
anomaly_values = np.random.normal(95, 5, 30).tolist()
data = normal_values + anomaly_values
title = f"Database Connections: {scenario_name}"
y_label = "Connections (%)"
threshold = 90
elif "Kubernetes" in scenario_name:
normal_values = np.random.normal(40, 8, 30).tolist()
anomaly_values = np.random.normal(95, 2, 30).tolist()
data = normal_values + anomaly_values
title = f"Memory Usage: {scenario_name}"
y_label = "Memory (%)"
threshold = 85
else:
normal_values = np.random.normal(50, 10, 30).tolist()
anomaly_values = np.random.normal(90, 5, 30).tolist()
data = normal_values + anomaly_values
title = f"System Metrics: {scenario_name}"
y_label = "Metric (%)"
threshold = 80
# Create Plotly figure
fig = go.Figure()
# Add normal region
fig.add_trace(go.Scatter(
x=times[:30],
y=data[:30],
mode='lines',
name='Normal',
line=dict(color='#10b981', width=3),
fill='tozeroy',
fillcolor='rgba(16, 185, 129, 0.1)'
))
# Add anomaly region
fig.add_trace(go.Scatter(
x=times[30:],
y=data[30:],
mode='lines',
name='Anomaly',
line=dict(color='#ef4444', width=3)
))
# Add threshold line
fig.add_hline(y=threshold, line_dash="dash",
line_color="#f59e0b",
annotation_text="Alert Threshold",
annotation_position="top right")
# Update layout - FIXED: Simplified for Gradio compatibility
fig.update_layout(
title={
'text': title,
'font': dict(size=18, color='#1e293b', family="Arial, sans-serif"),
'x': 0.5
},
xaxis_title="Time",
yaxis_title=y_label,
height=300,
margin=dict(l=40, r=20, t=50, b=40),
plot_bgcolor='white',
paper_bgcolor='white',
showlegend=True,
hovermode='x unified'
)
logger.info(f"βœ… Created telemetry plot for {scenario_name}")
return fig
except Exception as e:
logger.error(f"Error creating telemetry plot: {e}")
# Return a simple valid Plotly figure as fallback
fig = go.Figure()
fig.add_trace(go.Scatter(x=[0, 1], y=[0, 1], mode='lines', name='Fallback'))
fig.update_layout(
title=f"Telemetry: {scenario_name}",
height=300,
plot_bgcolor='white'
)
return fig
def create_simple_impact_plot(scenario_name: str, is_real_arf: bool = True) -> go.Figure:
"""
FIXED: Enhanced for Gradio compatibility
"""
try:
# Impact values based on scenario
impact_values = {
"Cache Miss Storm": 8500,
"Database Connection Pool Exhaustion": 4200,
"Kubernetes Memory Leak": 5500,
"API Rate Limit Storm": 3800,
"Network Partition": 12000,
"Storage I/O Saturation": 6800
}
impact = impact_values.get(scenario_name, 5000)
# Create gauge chart - FIXED: Enhanced for Gradio
fig = go.Figure(go.Indicator(
mode="gauge+number",
value=impact,
domain={'x': [0, 1], 'y': [0, 1]},
title={
'text': f"Revenue Impact: ${impact:,}/hour",
'font': dict(size=16, family="Arial, sans-serif")
},
number={
'prefix': "$",
'suffix': "/hour",
'font': dict(size=28, family="Arial, sans-serif")
},
gauge={
'axis': {'range': [None, impact * 1.2], 'tickwidth': 1},
'bar': {'color': "#ef4444"},
'bgcolor': "white",
'borderwidth': 2,
'bordercolor': "gray",
'steps': [
{'range': [0, impact * 0.3], 'color': '#10b981'},
{'range': [impact * 0.3, impact * 0.7], 'color': '#f59e0b'},
{'range': [impact * 0.7, impact], 'color': '#ef4444'}
],
'threshold': {
'line': {'color': "black", 'width': 4},
'thickness': 0.75,
'value': impact
}
}
))
# Update layout - FIXED: Enhanced for Gradio
fig.update_layout(
height=400,
margin=dict(l=30, r=30, t=70, b=30),
paper_bgcolor='white',
font=dict(family="Arial, sans-serif")
)
logger.info(f"βœ… Created impact plot for {scenario_name}")
return fig
except Exception as e:
logger.error(f"Error creating impact plot: {e}")
# Return a simple valid gauge as fallback
fig = go.Figure(go.Indicator(
mode="gauge",
value=0,
title={'text': "Impact (fallback)"}
))
fig.update_layout(height=400)
return fig
def create_empty_plot(title: str, is_real_arf: bool = True) -> go.Figure:
"""
FIXED: Enhanced for Gradio compatibility
"""
try:
fig = go.Figure()
# Add text annotation - FIXED: Enhanced
fig.add_annotation(
x=0.5, y=0.5,
text=title,
showarrow=False,
font=dict(size=18, color="#64748b", family="Arial, sans-serif"),
xref="paper",
yref="paper"
)
# Add boundary indicator if needed
if is_real_arf:
fig.add_annotation(
x=0.02, y=0.98,
text="βœ… REAL ARF",
showarrow=False,
font=dict(size=12, color="#10b981", family="Arial, sans-serif"),
xref="paper",
yref="paper",
bgcolor="white",
bordercolor="#10b981",
borderwidth=1,
borderpad=4
)
fig.update_layout(
title={
'text': "Visualization Placeholder",
'font': dict(size=14, color="#94a3b8", family="Arial, sans-serif")
},
height=300,
plot_bgcolor='white',
paper_bgcolor='white',
xaxis={'visible': False},
yaxis={'visible': False},
margin=dict(l=20, r=20, t=50, b=20)
)
return fig
except Exception as e:
logger.error(f"Error creating empty plot: {e}")
# Ultra-simple fallback
fig = go.Figure()
fig.update_layout(height=300)
return fig
# Keep the HTML fallback functions for other uses
def create_html_telemetry_fallback(scenario_name: str, is_real_arf: bool) -> str:
"""HTML fallback for telemetry visualization (unchanged)"""
severity_colors = {
"Cache Miss Storm": "#f59e0b",
"Database Connection Pool Exhaustion": "#ef4444",
"Kubernetes Memory Leak": "#8b5cf6",
"API Rate Limit Storm": "#ec4899",
"Network Partition": "#14b8a6",
"Storage I/O Saturation": "#84cc16"
}
color = severity_colors.get(scenario_name, "#64748b")
boundary_indicator = "🏒 ENTERPRISE" if is_real_arf else "πŸ”“ OSS ONLY"
return f"""
<div style="border: 1px solid {color}; border-radius: 14px; padding: 20px;
background: linear-gradient(135deg, {color}10 0%, #ffffff 100%);
position: relative; overflow: hidden;">
<!-- Boundary indicator -->
<div style="position: absolute; top: 10px; right: 10px; background: {color};
color: white; padding: 4px 10px; border-radius: 12px; font-size: 11px;
font-weight: bold;">
{boundary_indicator}
</div>
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
<div>
<h4 style="margin: 0 0 10px 0; font-size: 16px; color: #1e293b; font-weight: 600;">
πŸ“Š Telemetry: {scenario_name}
</h4>
<p style="margin: 0; font-size: 13px; color: #64748b; max-width: 300px;">
Real-time metrics showing anomalous behavior pattern detection.
ARF analyzes 45+ data points per second.
</p>
</div>
<div style="text-align: right;">
<div style="font-size: 28px; font-weight: 700; color: {color}; margin-bottom: 5px;">
94%
</div>
<div style="font-size: 12px; color: #64748b;">
Anomaly Confidence
</div>
</div>
</div>
<!-- Simulated telemetry chart -->
<div style="margin-top: 20px; height: 100px; position: relative;">
<div style="position: absolute; bottom: 0; left: 0; width: 100%; height: 2px;
background: #e2e8f0;"></div>
<!-- Anomaly region -->
<div style="position: absolute; bottom: 0; left: 60%; width: 30%; height: 80px;
background: linear-gradient(90deg, {color}20, {color}40); border-radius: 6px 6px 0 0;
border: 2px solid {color}; border-bottom: none;">
<div style="position: absolute; top: -25px; left: 50%; transform: translateX(-50%);
background: {color}; color: white; padding: 2px 8px; border-radius: 10px;
font-size: 11px; font-weight: bold; white-space: nowrap;">
ANOMALY
</div>
</div>
<!-- Data points -->
<div style="position: absolute; bottom: 0; left: 0; width: 60%; height: 40px;
background: linear-gradient(90deg, #10b98120, #10b98140); border-radius: 6px 0 0 0;">
</div>
</div>
<!-- Metrics row -->
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin-top: 20px;">
<div style="text-align: center;">
<div style="font-size: 14px; font-weight: 600; color: {color};">45s</div>
<div style="font-size: 11px; color: #64748b;">Detection Time</div>
</div>
<div style="text-align: center;">
<div style="font-size: 14px; font-weight: 600; color: {color};">12/min</div>
<div style="font-size: 11px; color: #64748b;">Data Points</div>
</div>
<div style="text-align: center;">
<div style="font-size: 14px; font-weight: 600; color: {color};">3</div>
<div style="font-size: 11px; color: #64748b;">Similar Patterns</div>
</div>
</div>
<!-- Boundary note -->
<div style="margin-top: 15px; padding: 10px; background: #f8fafc; border-radius: 8px;
border-left: 3px solid {color}; font-size: 12px; color: #475569;">
<strong>Boundary:</strong> This visualization shows {'real' if is_real_arf else 'simulated'}
telemetry analysis. {'Enterprise' if is_real_arf else 'OSS'} edition provides enhanced
anomaly detection.
</div>
</div>
"""
def create_html_impact_fallback(scenario_name: str, is_real_arf: bool) -> str:
"""HTML fallback for impact visualization (unchanged)"""
impact_values = {
"Cache Miss Storm": 8500,
"Database Connection Pool Exhaustion": 4200,
"Kubernetes Memory Leak": 5500,
"API Rate Limit Storm": 3800,
"Network Partition": 12000,
"Storage I/O Saturation": 6800
}
impact = impact_values.get(scenario_name, 5000)
savings = int(impact * 0.85)
boundary_text = "Enterprise Autonomous" if is_real_arf else "OSS Advisory"
boundary_color = "#8b5cf6" if is_real_arf else "#10b981"
return f"""
<div style="border: 1px solid {boundary_color}; border-radius: 14px; padding: 20px;
background: linear-gradient(135deg, {boundary_color}10 0%, #ffffff 100%);">
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 20px;">
<div>
<h4 style="margin: 0 0 8px 0; font-size: 16px; color: #1e293b; font-weight: 600;">
πŸ’° Business Impact Analysis
</h4>
<div style="display: inline-block; padding: 4px 10px; background: {boundary_color};
color: white; border-radius: 12px; font-size: 11px; font-weight: bold;">
{boundary_text}
</div>
</div>
<div style="text-align: right;">
<div style="font-size: 24px; font-weight: 700; color: {boundary_color};">
${impact:,}
</div>
<div style="font-size: 12px; color: #64748b;">
Revenue Loss/Hour
</div>
</div>
</div>
<!-- Gauge visualization -->
<div style="position: relative; height: 80px; margin: 20px 0;">
<!-- Gauge background -->
<div style="position: absolute; top: 0; left: 0; width: 100%; height: 40px;
background: #f1f5f9; border-radius: 20px; overflow: hidden;">
<!-- Impact fill -->
<div style="position: absolute; top: 0; left: 0; width: 85%; height: 100%;
background: linear-gradient(90deg, {boundary_color}, {boundary_color}aa);">
</div>
<!-- Savings indicator -->
<div style="position: absolute; top: 0; left: 85%; width: 2px; height: 100%;
background: #10b981; z-index: 2;"></div>
</div>
<!-- Labels -->
<div style="position: absolute; top: 50px; left: 0; font-size: 12px; color: #64748b;">
$0
</div>
<div style="position: absolute; top: 50px; left: 50%; transform: translateX(-50%);
font-size: 12px; color: #64748b;">
${impact//2:,}
</div>
<div style="position: absolute; top: 50px; right: 0; font-size: 12px; color: #64748b;">
${impact:,}
</div>
<!-- Savings marker -->
<div style="position: absolute; top: -25px; left: 85%; transform: translateX(-50%);
text-align: center;">
<div style="width: 0; height: 0; border-left: 6px solid transparent;
border-right: 6px solid transparent; border-top: 10px solid #10b981;
margin: 0 auto 5px auto;"></div>
<div style="font-size: 11px; color: #10b981; font-weight: bold; white-space: nowrap;">
${savings:,} SAVED
</div>
</div>
</div>
<!-- Impact breakdown -->
<div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 15px; margin-top: 25px;">
<div style="padding: 12px; background: #f8fafc; border-radius: 8px;">
<div style="font-size: 13px; color: #64748b; margin-bottom: 5px;">Without ARF</div>
<div style="font-size: 16px; font-weight: 700; color: #ef4444;">45 min</div>
<div style="font-size: 11px; color: #94a3b8;">Mean time to resolve</div>
</div>
<div style="padding: 12px; background: #f8fafc; border-radius=8px;">
<div style="font-size: 13px; color: #64748b; margin-bottom: 5px;">With ARF</div>
<div style="font-size: 16px; font-weight: 700; color: #10b981;">12 min</div>
<div style="font-size: 11px; color: #94a3b8;">Autonomous recovery</div>
</div>
</div>
<!-- ROI indicator -->
<div style="margin-top: 20px; padding: 12px; background: #f0fdf4; border-radius: 8px;
border: 1px solid #d1fae5; display: flex; align-items: center; gap: 12px;">
<div style="font-size: 24px; color: #10b981;">πŸ“ˆ</div>
<div>
<div style="font-size: 14px; font-weight: 600; color: #065f46;">
Potential ROI: 5.2Γ—
</div>
<div style="font-size: 12px; color: #059669;">
ARF saves 85% of potential revenue loss through autonomous recovery
</div>
</div>
</div>
<!-- Boundary context -->
<div style="margin-top: 15px; padding-top: 15px; border-top: 1px dashed #e2e8f0;
font-size: 12px; color: #64748b; line-height: 1.5;">
<strong>Boundary Context:</strong> {'Enterprise' if is_real_arf else 'OSS'} analysis shows
{'real' if is_real_arf else 'simulated'} impact metrics.
{'Commercial license enables autonomous execution.' if is_real_arf else 'Upgrade to Enterprise for autonomous recovery.'}
</div>
</div>
"""
def get_inactive_agent_html(agent_name: str, description: str, is_real_arf: bool = False):
"""Get HTML for inactive agent state with boundary indicators (unchanged)"""
boundary_color = "#8b5cf6" if is_real_arf else "#10b981"
status_color = "#64748b"
return f"""
<div style="border: 1px solid {status_color}40; border-radius: 12px; padding: 20px;
background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
position: relative; min-height: 120px;">
<!-- Status indicator -->
<div style="position: absolute; top: 15px; right: 15px; width: 12px; height: 12px;
background: {status_color}60; border-radius: 50%;"></div>
<!-- Agent header -->
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 15px;">
<div style="width: 40px; height: 40px; background: {status_color}20; border-radius: 10px;
display: flex; align-items: center; justify-content: center; font-size: 18px; color: {status_color};">
πŸ€–
</div>
<div>
<h4 style="margin: 0 0 4px 0; font-size: 16px; color: #475569; font-weight: 600;">
{agent_name}
</h4>
<div style="display: inline-block; padding: 3px 8px; background: {status_color}20;
color: {status_color}; border-radius: 10px; font-size: 11px; font-weight: bold;">
INACTIVE
</div>
</div>
</div>
<!-- Agent description -->
<p style="margin: 0; font-size: 13px; color: #64748b; line-height: 1.5;">
{description}
</p>
<!-- Boundary note -->
<div style="margin-top: 15px; padding-top: 15px; border-top: 1px dashed #e2e8f0;">
<div style="font-size: 11px; color: #94a3b8; display: flex; align-items: center; gap: 6px;">
<span style="display: inline-block; width: 8px; height: 8px; background: {boundary_color}; border-radius: 50%;"></span>
Requires { 'Enterprise' if is_real_arf else 'OSS' } activation
</div>
</div>
</div>
"""
# ===========================================
# IMPORT MODULAR COMPONENTS - FIXED: Added MockEnhancedROICalculator
# ===========================================
def import_components() -> Dict[str, Any]:
"""Safely import all components with proper error handling - FIXED: Added mock ROI calculator"""
components = {
"all_available": False,
"error": None,
"get_styles": lambda: "",
"show_boundaries": settings.show_boundaries,
}
try:
logger.info("Starting component import...")
# First, import gradio
import gradio as gr
components["gr"] = gr
# Import UI styles
from ui.styles import get_styles
components["get_styles"] = get_styles
# Import UI components - IMPORTANT: Now includes create_realism_panel AND update_performance_metrics
from ui.components import (
create_header, create_status_bar, create_tab1_incident_demo,
create_tab2_business_roi, create_tab3_enterprise_features,
create_tab4_audit_trail, create_tab5_learning_engine,
create_footer, create_realism_panel, update_performance_metrics # Added update_performance_metrics
)
components.update({
"create_header": create_header,
"create_status_bar": create_status_bar,
"create_tab1_incident_demo": create_tab1_incident_demo,
"create_tab2_business_roi": create_tab2_business_roi,
"create_tab3_enterprise_features": create_tab3_enterprise_features,
"create_tab4_audit_trail": create_tab4_audit_trail,
"create_tab5_learning_engine": create_tab5_learning_engine,
"create_footer": create_footer,
"create_realism_panel": create_realism_panel,
"update_performance_metrics": update_performance_metrics # Added for dynamic metrics
})
# Import scenarios
from demo.scenarios import INCIDENT_SCENARIOS
components["INCIDENT_SCENARIOS"] = INCIDENT_SCENARIOS
# Try to import TrueARFOrchestrator (renamed for version consistency)
try:
from core.true_arf_orchestrator import TrueARFOrchestrator
components["DemoOrchestrator"] = TrueARFOrchestrator
except ImportError:
# Fallback to old name for compatibility during transition
try:
from core.true_arf_orchestrator import TrueARF337Orchestrator
components["DemoOrchestrator"] = TrueARF337Orchestrator
logger.warning("⚠️ Using TrueARF337Orchestrator - rename to TrueARFOrchestrator for version consistency")
except ImportError:
# Fallback to real ARF integration
try:
from core.real_arf_integration import RealARFIntegration
components["DemoOrchestrator"] = RealARFIntegration
except ImportError:
# Create a minimal mock orchestrator
class MockOrchestrator:
async def analyze_incident(self, scenario_name, scenario_data):
return {
"status": "mock",
"scenario": scenario_name,
"message": "Mock analysis (no real ARF available)",
"boundary_note": "OSS advisory mode - execution requires Enterprise",
"demo_display": {
"real_arf_version": "mock",
"true_oss_used": False,
"enterprise_simulated": True,
"architectural_boundary": "OSS advises β†’ Enterprise would execute"
}
}
async def execute_healing(self, scenario_name, mode="autonomous"):
return {
"status": "mock",
"scenario": scenario_name,
"message": "Mock execution (no real ARF available)",
"boundary_note": "Simulated Enterprise execution - real execution requires infrastructure",
"enterprise_features_used": ["simulated_execution", "mock_rollback", "demo_mode"]
}
components["DemoOrchestrator"] = MockOrchestrator
# FIXED: EnhancedROICalculator with proper mock fallback
try:
from core.calculators import EnhancedROICalculator
components["EnhancedROICalculator"] = EnhancedROICalculator()
logger.info("βœ… Real EnhancedROICalculator loaded")
except ImportError:
# Create comprehensive mock ROI calculator
class MockEnhancedROICalculator:
"""Mock ROI calculator for demo purposes - FIXED to prevent KeyError"""
def calculate_comprehensive_roi(self, scenario_name=None, monthly_incidents=15, team_size=5, **kwargs):
"""Calculate comprehensive ROI metrics with realistic mock data"""
from datetime import datetime
# Mock ROI calculation with realistic values
impact_map = {
"Cache Miss Storm": 8500,
"Database Connection Pool Exhaustion": 4200,
"Kubernetes Memory Leak": 5500,
"API Rate Limit Storm": 3800,
"Network Partition": 12000,
"Storage I/O Saturation": 6800
}
impact_per_incident = impact_map.get(scenario_name or "Cache Miss Storm", 5000)
annual_impact = impact_per_incident * monthly_incidents * 12
potential_savings = int(annual_impact * 0.82)
enterprise_cost = 625000
roi_multiplier = round(potential_savings / enterprise_cost, 1)
payback_months = round((enterprise_cost / (potential_savings / 12)), 1)
return {
"status": "βœ… Calculated Successfully",
"scenario": scenario_name or "Cache Miss Storm",
"timestamp": datetime.now().isoformat(),
"calculator": "MockEnhancedROICalculator",
"summary": {
"your_annual_impact": f"${annual_impact:,}",
"potential_savings": f"${potential_savings:,}",
"enterprise_cost": f"${enterprise_cost:,}",
"roi_multiplier": f"{roi_multiplier}Γ—",
"payback_months": f"{payback_months}",
"annual_roi_percentage": f"{int((potential_savings - enterprise_cost) / enterprise_cost * 100)}%",
"boundary_context": "Based on OSS analysis + simulated Enterprise execution"
},
"breakdown": {
"direct_cost_savings": f"${int(potential_savings * 0.7):,}",
"productivity_gains": f"${int(potential_savings * 0.2):,}",
"risk_reduction": f"${int(potential_savings * 0.1):,}"
},
"annual_projection": {
"incidents_prevented": monthly_incidents * 12,
"annual_savings": f"${potential_savings:,}",
"roi": f"{roi_multiplier}Γ—"
},
"notes": [
"πŸ“Š ROI calculation using mock data",
"πŸ’‘ Real enterprise ROI includes additional factors",
"πŸ”’ Full ROI requires Enterprise edition",
f"πŸ“ˆ Based on {monthly_incidents} incidents/month"
]
}
def get_roi_visualization_data(self):
"""Get data for ROI visualization"""
return {
"labels": ["Direct Savings", "Productivity", "Risk Reduction", "Upsell"],
"values": [65, 20, 10, 5],
"colors": ["#10b981", "#3b82f6", "#8b5cf6", "#f59e0b"]
}
components["EnhancedROICalculator"] = MockEnhancedROICalculator()
logger.info("βœ… Mock EnhancedROICalculator created (preventing KeyError)")
# Try to import visualization engine
try:
from core.visualizations import EnhancedVisualizationEngine
components["EnhancedVisualizationEngine"] = EnhancedVisualizationEngine()
except ImportError:
class MockVisualizationEngine:
def create_executive_dashboard(self, data=None, is_real_arf=True):
return create_empty_plot("Executive Dashboard", is_real_arf)
def create_telemetry_plot(self, scenario_name, anomaly_detected=True, is_real_arf=True):
return create_simple_telemetry_plot(scenario_name, is_real_arf)
def create_impact_gauge(self, scenario_name, is_real_arf=True):
return create_simple_impact_plot(scenario_name, is_real_arf)
def create_timeline_comparison(self, is_real_arf=True):
return create_empty_plot("Timeline Comparison", is_real_arf)
components["EnhancedVisualizationEngine"] = MockVisualizationEngine()
components["all_available"] = True
components["error"] = None
logger.info("βœ… Successfully imported all modular components including update_performance_metrics")
except Exception as e:
logger.error(f"❌ IMPORT ERROR: {e}")
components["error"] = str(e)
components["all_available"] = False
# Ensure we have minimal components
if "gr" not in components:
import gradio as gr
components["gr"] = gr
if "INCIDENT_SCENARIOS" not in components:
components["INCIDENT_SCENARIOS"] = {
"Cache Miss Storm": {
"component": "Redis Cache Cluster",
"severity": "HIGH",
"business_impact": {"revenue_loss_per_hour": 8500},
"boundary_note": "OSS analysis only - execution requires Enterprise"
}
}
# Ensure EnhancedROICalculator exists
if "EnhancedROICalculator" not in components:
class MinimalROICalculator:
def calculate_comprehensive_roi(self, **kwargs):
return {
"status": "βœ… Minimal ROI Calculation",
"summary": {"roi_multiplier": "5.2Γ—"}
}
components["EnhancedROICalculator"] = MinimalROICalculator()
# Ensure update_performance_metrics exists
if "update_performance_metrics" not in components:
def fallback_performance_metrics(scenario_name: str):
"""Fallback function if the real one fails"""
logger.warning(f"Using fallback performance metrics for {scenario_name}")
return (
"""<div style="border: 1px solid #e2e8f0; border-radius: 12px; padding: 18px; background: white; margin: 8px; text-align: center; flex: 1; min-width: 140px; border-left: 4px solid #3b82f6;">
<div style="font-size: 28px; margin-bottom: 10px;">⏱️</div>
<div>
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64748b; font-weight: 600;">Detection Time</h4>
<p style="font-size: 28px; font-weight: bold; color: #1e40af; margin: 8px 0;">42s</p>
<p style="font-size: 12px; color: #64748b; margin: 0;">↓ 90% faster than average</p>
</div>
</div>""",
"""<div style="border: 1px solid #e2e8f0; border-radius: 12px; padding: 18px; background: white; margin: 8px; text-align: center; flex: 1; min-width: 140px; border-left: 4px solid #10b981;">
<div style="font-size: 28px; margin-bottom: 10px;">⚑</div>
<div>
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64748b; font-weight: 600;">Mean Time to Resolve</h4>
<p style="font-size: 28px; font-weight: bold; color: #10b981; margin: 8px 0;">14m</p>
<p style="font-size: 12px; color: #64748b; margin: 0;">↓ 70% faster than manual</p>
</div>
</div>""",
"""<div style="border: 1px solid #e2e8f0; border-radius: 12px; padding: 18px; background: white; margin: 8px; text-align: center; flex: 1; min-width: 140px; border-left: 4px solid #8b5cf6;">
<div style="font-size: 28px; margin-bottom: 10px;">πŸ€–</div>
<div>
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64748b; font-weight: 600;">Auto-Heal Rate</h4>
<p style="font-size: 28px; font-weight: bold; color: #8b5cf6; margin: 8px 0;">78.9%</p>
<p style="font-size: 12px; color: #64748b; margin: 0;">↑ 5.0Γ— industry average</p>
</div>
</div>""",
"""<div style="border: 1px solid #e2e8f0; border-radius: 12px; padding: 18px; background: white; margin: 8px; text-align: center; flex: 1; min-width: 140px; border-left: 4px solid #f59e0b;">
<div style="font-size: 28px; margin-bottom: 10px;">πŸ’°</div>
<div>
<h4 style="margin: 0 0 8px 0; font-size: 14px; color: #64748b; font-weight: 600;">Cost Saved</h4>
<p style="font-size: 28px; font-weight: bold; color: #f59e0b; margin: 8px 0;">$7.2K</p>
<p style="font-size: 12px; color: #64748b; margin: 0;">Per incident avoided</p>
</div>
</div>"""
)
components["update_performance_metrics"] = fallback_performance_metrics
return components
_components = None
_audit_manager = None
def get_components() -> Dict[str, Any]:
"""Lazy load components singleton"""
global _components
if _components is None:
_components = import_components()
return _components
# ===========================================
# AUDIT TRAIL MANAGER - FIXED: Returns DataFrames instead of HTML
# ===========================================
class AuditTrailManager:
"""Enhanced audit trail manager with boundary tracking - FIXED to return DataFrames"""
def __init__(self):
self.executions = []
self.incidents = []
self.boundary_crossings = []
self.max_items = settings.max_history_items
def add_execution(self, scenario_name: str, mode: str, result: Dict):
"""Add an execution record"""
record = {
"timestamp": datetime.datetime.now().isoformat(),
"scenario": scenario_name,
"mode": mode,
"result": result,
"boundary_context": "Enterprise execution simulated" if "simulated" in str(result) else "OSS advisory"
}
self.executions.insert(0, record)
if len(self.executions) > self.max_items:
self.executions = self.executions[:self.max_items]
# Track boundary crossing
if "enterprise" in mode.lower():
self.boundary_crossings.append({
"timestamp": record["timestamp"],
"from": "OSS",
"to": "Enterprise",
"action": scenario_name
})
logger.info(f"πŸ“ Execution recorded: {scenario_name} ({mode})")
return record
def add_incident(self, scenario_name: str, analysis_result: Dict):
"""Add an incident analysis record"""
record = {
"timestamp": datetime.datetime.now().isoformat(),
"scenario": scenario_name,
"analysis": analysis_result,
"boundary_context": analysis_result.get("boundary_note", "OSS analysis")
}
self.incidents.insert(0, record)
if len(self.incidents) > self.max_items:
self.incidents = self.incidents[:self.max_items]
logger.info(f"πŸ“ Incident analysis recorded: {scenario_name}")
return record
def get_execution_dataframe(self) -> pd.DataFrame:
"""
FIXED: Robust pandas DataFrame creation for Gradio DataFrame component
"""
try:
if not self.executions:
# Return empty DataFrame with correct columns
return pd.DataFrame(columns=[
"Execution ID", "Scenario", "Status", "Mode",
"Start Time", "End Time", "Duration", "Boundary"
])
# Build DataFrame from executions with safe access
data = []
for i, execution in enumerate(self.executions):
try:
# Safe access to nested dictionaries
result = execution.get("result", {})
# Execution ID - safe extraction with fallback
exec_id = result.get("execution_id", f"exec_{i:03d}")
# Status determination with multiple fallbacks
status_text = "Unknown"
if isinstance(result, dict):
status_lower = str(result.get("status", "")).lower()
if "success" in status_lower:
status_text = "Success"
elif "failed" in status_lower or "error" in status_lower:
status_text = "Failed"
else:
# Check if there's an error key
if result.get("error"):
status_text = "Failed"
else:
status_text = "Success"
# Mode extraction
mode = execution.get("mode", "unknown")
# Scenario extraction
scenario = execution.get("scenario", "Unknown")
# Timestamp formatting with validation
timestamp = execution.get("timestamp", "")
start_time = ""
if timestamp and len(timestamp) > 10:
try:
# Format: YYYY-MM-DD HH:MM:SS
start_time = timestamp[:19]
except Exception:
start_time = timestamp # Fallback to raw string
# End time extraction from telemetry
end_time = ""
telemetry = result.get("telemetry", {})
if telemetry:
end_timestamp = telemetry.get("end_time", "")
if end_timestamp and len(end_timestamp) > 10:
try:
end_time = end_timestamp[:19]
except Exception:
end_time = end_timestamp # Fallback
# Duration - mock or extract from execution
duration = "12m" # Default mock duration
if telemetry and "estimated_duration" in telemetry:
duration = telemetry.get("estimated_duration", "12m")
# Boundary context
boundary = execution.get("boundary_context", "Unknown")
data.append({
"Execution ID": exec_id,
"Scenario": scenario,
"Status": status_text,
"Mode": mode,
"Start Time": start_time,
"End Time": end_time,
"Duration": duration,
"Boundary": boundary
})
except Exception as row_error:
logger.warning(f"Error processing execution row {i}: {row_error}")
# Add error row for debugging
data.append({
"Execution ID": f"error_{i}",
"Scenario": "Error",
"Status": "Failed",
"Mode": "error",
"Start Time": datetime.datetime.now().isoformat()[:19],
"End Time": "",
"Duration": "0m",
"Boundary": "Error processing"
})
if not data:
logger.warning("No valid execution data found, returning empty DataFrame")
return pd.DataFrame(columns=[
"Execution ID", "Scenario", "Status", "Mode",
"Start Time", "End Time", "Duration", "Boundary"
])
# Create DataFrame
df = pd.DataFrame(data)
# Safe sorting - only if we have valid Start Time data
if not df.empty and "Start Time" in df.columns:
# Check if Start Time column has valid data
valid_times = df["Start Time"].apply(
lambda x: isinstance(x, str) and len(x) > 0 and x != "None"
)
if valid_times.any():
try:
# Sort by time (newest first)
df = df.sort_values("Start Time", ascending=False)
except Exception as sort_error:
logger.warning(f"Could not sort DataFrame: {sort_error}")
# Keep unsorted if sorting fails
else:
logger.debug("No valid timestamps for sorting")
logger.info(f"βœ… Created execution DataFrame with {len(df)} rows")
return df
except Exception as e:
logger.error(f"❌ Error creating execution DataFrame: {e}")
# Return informative error DataFrame
error_df = pd.DataFrame(columns=[
"Error", "Message", "Timestamp"
]).from_records([{
"Error": "DataFrame Creation Failed",
"Message": str(e),
"Timestamp": datetime.datetime.now().isoformat()[:19]
}])
return error_df
def get_incident_dataframe(self) -> pd.DataFrame:
"""
FIXED: Robust pandas DataFrame creation for Gradio DataFrame component
"""
try:
if not self.incidents:
# Return empty DataFrame with correct columns
return pd.DataFrame(columns=[
"Scenario", "Status", "Boundary", "Time",
"Confidence", "Action", "Target"
])
# Build DataFrame from incidents with safe access
data = []
for i, incident in enumerate(self.incidents):
try:
# Safe extraction of basic fields
scenario = incident.get("scenario", "Unknown")
boundary = incident.get("boundary_context", "OSS analysis")
# Analysis data extraction
analysis = incident.get("analysis", {})
# Status determination
status = "Analyzed"
if isinstance(analysis, dict):
analysis_status = analysis.get("status", "").lower()
if analysis_status:
status = analysis_status.capitalize()
else:
# Fallback status determination
if analysis.get("error"):
status = "Error"
elif analysis.get("analysis") or analysis.get("oss_analysis"):
status = "Success"
# Timestamp formatting
timestamp = incident.get("timestamp", "")
time_display = ""
if timestamp and len(timestamp) > 10:
try:
# Extract HH:MM:SS
time_display = timestamp[11:19]
except Exception:
time_display = timestamp[:8] if len(timestamp) >= 8 else timestamp
# Extract healing intent details with multiple fallback paths
confidence = 0.85 # Default confidence
action = "Analysis"
target = "system"
# Try multiple paths to find healing intent
healing_intent = None
# Path 1: oss_analysis -> analysis -> decision
oss_analysis = analysis.get("oss_analysis", {})
if isinstance(oss_analysis, dict):
oss_analysis_inner = oss_analysis.get("analysis", {})
if isinstance(oss_analysis_inner, dict):
healing_intent = oss_analysis_inner.get("decision", {})
# Path 2: direct analysis -> decision
if not healing_intent and isinstance(analysis.get("analysis", {}), dict):
healing_intent = analysis["analysis"].get("decision", {})
# Path 3: direct healing_intent
if not healing_intent:
healing_intent = analysis.get("healing_intent", {})
if healing_intent and isinstance(healing_intent, dict):
confidence = healing_intent.get("confidence", 0.85)
action = healing_intent.get("action", "Analysis")
target = healing_intent.get("target", "system")
# Format confidence as percentage
confidence_display = f"{confidence * 100:.1f}%"
data.append({
"Scenario": scenario,
"Status": status,
"Boundary": boundary,
"Time": time_display,
"Confidence": confidence_display,
"Action": action[:50], # Limit action length
"Target": target[:30] # Limit target length
})
except Exception as row_error:
logger.warning(f"Error processing incident row {i}: {row_error}")
# Add error row for debugging
data.append({
"Scenario": "Error",
"Status": "Failed",
"Boundary": "Error processing",
"Time": datetime.datetime.now().isoformat()[11:19],
"Confidence": "0.0%",
"Action": "Error",
"Target": "system"
})
if not data:
logger.warning("No valid incident data found, returning empty DataFrame")
return pd.DataFrame(columns=[
"Scenario", "Status", "Boundary", "Time",
"Confidence", "Action", "Target"
])
# Create DataFrame
df = pd.DataFrame(data)
# Safe sorting - only if we have valid Time data
if not df.empty and "Time" in df.columns:
# Check if Time column has valid data
valid_times = df["Time"].apply(
lambda x: isinstance(x, str) and len(x) > 0 and x != "None"
)
if valid_times.any():
try:
# Sort by time (newest first)
df = df.sort_values("Time", ascending=False)
except Exception as sort_error:
logger.warning(f"Could not sort incident DataFrame: {sort_error}")
# Keep unsorted if sorting fails
else:
logger.debug("No valid timestamps for sorting in incident DataFrame")
logger.info(f"βœ… Created incident DataFrame with {len(df)} rows")
return df
except Exception as e:
logger.error(f"❌ Error creating incident DataFrame: {e}")
# Return informative error DataFrame
error_df = pd.DataFrame(columns=[
"Error", "Message", "Timestamp"
]).from_records([{
"Error": "DataFrame Creation Failed",
"Message": str(e),
"Timestamp": datetime.datetime.now().isoformat()[:19]
}])
return error_df
def get_execution_table_html(self):
"""Legacy HTML method for backward compatibility"""
if not self.executions:
return """
<div style="text-align: center; padding: 30px; color: #64748b;">
<div style="font-size: 48px; margin-bottom: 10px;">πŸ“­</div>
<h4 style="margin: 0 0 10px 0;">No executions yet</h4>
<p style="margin: 0; font-size: 13px;">Run scenarios to see execution history</p>
</div>
"""
rows = []
for i, exec in enumerate(self.executions[:10]):
status = "βœ…" if "success" in exec["result"].get("status", "").lower() else "⚠️"
boundary = exec["boundary_context"]
boundary_color = "#10b981" if "OSS" in boundary else "#8b5cf6"
rows.append(f"""
<tr style="border-bottom: 1px solid #f1f5f9;">
<td style="padding: 12px; font-size: 13px; color: #1e293b;">
{status} {exec["scenario"]}
</td>
<td style="padding: 12px; font-size: 13px; color: #64748b;">
{exec["mode"]}
</td>
<td style="padding: 12px; font-size: 13px;">
<div style="display: inline-block; padding: 4px 10px; background: {boundary_color}20;
color: {boundary_color}; border-radius: 12px; font-size: 11px; font-weight: bold;">
{boundary}
</div>
</td>
<td style="padding: 12px; font-size: 13px; color: #94a3b8;">
{exec["timestamp"][11:19]}
</td>
</tr>
""")
return f"""
<div style="border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden;">
<table style="width: 100%; border-collapse: collapse;">
<thead style="background: #f8fafc;">
<tr style="border-bottom: 2px solid #e2e8f0;">
<th style="padding: 15px; text-align: left; font-size: 13px; color: #475569; font-weight: 600;">Scenario</th>
<th style="padding: 15px; text-align: left; font-size: 13px; color: #475569; font-weight: 600;">Mode</th>
<th style="padding: 15px; text-align: left; font-size: 13px; color: #475569; font-weight: 600;">Boundary</th>
<th style="padding: 15px; text-align: left; font-size: 13px; color: #475569; font-weight: 600;">Time</th>
</tr>
</thead>
<tbody>
{''.join(rows)}
</tbody>
</table>
</div>
"""
def get_incident_table_html(self):
"""Legacy HTML method for backward compatibility"""
if not self.incidents:
return """
<div style="text-align: center; padding: 30px; color: #64748b;">
<div style="font-size: 48px; margin-bottom: 10px;">πŸ“­</div>
<h4 style="margin: 0 0 10px 0;">No incidents analyzed yet</h4>
<p style="margin: 0; font-size: 13px;">Run OSS analysis to see incident history</p>
</div>
"""
rows = []
for i, incident in enumerate(self.incidents[:10]):
scenario = incident["scenario"]
analysis = incident["analysis"]
boundary = incident["boundary_context"]
boundary_color = "#10b981" if "OSS" in boundary else "#8b5cf6"
rows.append(f"""
<tr style="border-bottom: 1px solid #f1f5f9;">
<td style="padding: 12px; font-size: 13px; color: #1e293b; font-weight: 500;">
{scenario}
</td>
<td style="padding: 12px; font-size: 13px; color: #64748b;">
{analysis.get('status', 'analyzed')}
</td>
<td style="padding: 12px; font-size: 13px;">
<div style="display: inline-block; padding: 4px 10px; background: {boundary_color}20;
color: {boundary_color}; border-radius: 12px; font-size: 11px; font-weight: bold;">
{boundary}
</div>
</td>
<td style="padding: 12px; font-size: 13px; color: #94a3b8;">
{incident["timestamp"][11:19]}
</td>
</tr>
""")
return f"""
<div style="border: 1px solid #e2e8f0; border-radius: 12px; overflow: hidden;">
<table style="width: 100%; border-collapse: collapse;">
<thead style="background: #f8fafc;">
<tr style="border-bottom: 2px solid #e2e8f0;">
<th style="padding: 15px; text-align: left; font-size: 13px; color: #475569; font-weight: 600;">Scenario</th>
<th style="padding: 15px; text-align: left; font-size: 13px; color: #475569; font-weight: 600;">Status</th>
<th style="padding: 15px; text-align: left; font-size: 13px; color: #475569; font-weight: 600;">Boundary</th>
<th style="padding: 15px; text-align: left; font-size: 13px; color: #475569; font-weight=600;">Time</th>
</tr>
</thead>
<tbody>
{''.join(rows)}
</tbody>
</table>
</div>
"""
def clear(self):
"""Clear all audit trails"""
self.executions = []
self.incidents = []
self.boundary_crossings = []
logger.info("🧹 Audit trail cleared")
def export_json(self):
"""Export audit trail as JSON"""
return {
"executions": self.executions,
"incidents": self.incidents,
"boundary_crossings": self.boundary_crossings,
"export_time": datetime.datetime.now().isoformat(),
"version": "3.3.9",
"architecture": "OSS advises β†’ Enterprise executes"
}
def get_audit_manager() -> AuditTrailManager:
"""Lazy load audit manager singleton"""
global _audit_manager
if _audit_manager is None:
_audit_manager = AuditTrailManager()
return _audit_manager
# ===========================================
# HELPER FUNCTIONS
# ===========================================
def get_scenario_impact(scenario_name: str) -> float:
"""Get average impact for a given scenario"""
impact_map = {
"Cache Miss Storm": 8500,
"Database Connection Pool Exhaustion": 4200,
"Kubernetes Memory Leak": 5500,
"API Rate Limit Storm": 3800,
"Network Partition": 12000,
"Storage I/O Saturation": 6800
}
return impact_map.get(scenario_name, 5000)
def extract_roi_multiplier(roi_result: Dict) -> float:
"""Extract ROI multiplier from EnhancedROICalculator result"""
try:
if "summary" in roi_result and "roi_multiplier" in roi_result["summary"]:
roi_str = roi_result["summary"]["roi_multiplier"]
if "Γ—" in roi_str:
return float(roi_str.replace("Γ—", ""))
return float(roi_str)
return 5.2
except Exception as e:
logger.warning(f"Failed to extract ROI multiplier: {e}")
return 5.2
# ===========================================
# SURGICAL FIX: update_scenario_display() - ENHANCED WITH REALISM PANEL
# ===========================================
def update_scenario_display(scenario_name: str) -> tuple:
"""
ENHANCED: Returns Plotly figures AND realism panel
Returns 5 values: (scenario_card_html, telemetry_fig, impact_fig, timeline_fig, realism_html)
"""
components = get_components()
scenarios = components["INCIDENT_SCENARIOS"]
scenario = scenarios.get(scenario_name, {
"component": "Unknown System",
"severity": "MEDIUM",
"business_impact": {"revenue_loss_per_hour": 5000},
"boundary_note": "Scenario not found"
})
# Create scenario card HTML (unchanged)
severity_colors = {
"HIGH": "#ef4444",
"MEDIUM": "#f59e0b",
"LOW": "#10b981"
}
severity_color = severity_colors.get(scenario["severity"], "#64748b")
impact = scenario["business_impact"].get("revenue_loss_per_hour", get_scenario_impact(scenario_name))
scenario_card_html = f"""
<div style="border: 1px solid {severity_color}; border-radius: 14px; padding: 20px;
background: linear-gradient(135deg, {severity_color}10 0%, #ffffff 100%);">
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 15px;">
<div>
<h3 style="margin: 0 0 8px 0; font-size: 18px; color: #1e293b; font-weight: 700;">
{scenario_name}
</h3>
<div style="display: flex; align-items: center; gap: 10px;">
<div style="padding: 4px 12px; background: {severity_color}; color: white;
border-radius: 12px; font-size: 12px; font-weight: bold;">
{scenario["severity"]} SEVERITY
</div>
<div style="font-size: 13px; color: #64748b;">
{scenario["component"]}
</div>
</div>
</div>
<div style="text-align: right;">
<div style="font-size: 28px; font-weight: 700; color: {severity_color};">
${impact:,}
</div>
<div style="font-size: 12px; color: #64748b;">
Revenue Loss/Hour
</div>
</div>
</div>
<!-- Impact breakdown -->
<div style="margin-top: 20px; padding-top: 20px; border-top: 1px solid #f1f5f9;">
<div style="font-size: 14px; color: #475569; font-weight: 600; margin-bottom: 10px;">
Business Impact Analysis
</div>
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px;">
<div style="text-align: center;">
<div style="font-size: 16px; font-weight: 700; color: {severity_color};">45 min</div>
<div style="font-size: 11px; color: #64748b;">Without ARF</div>
</div>
<div style="text-align: center;">
<div style="font-size: 16px; font-weight: 700; color: #10b981;">12 min</div>
<div style="font-size: 11px; color: #64748b;">With ARF</div>
</div>
<div style="text-align: center;">
<div style="font-size: 16px; font-weight: 700; color: #10b981;">${int(impact * 0.85):,}</div>
<div style="font-size: 11px; color: #64748b;">Savings</div>
</div>
</div>
</div>
<!-- Boundary context -->
<div style="margin-top: 20px; padding: 12px; background: #f8fafc; border-radius: 8px;
border-left: 3px solid {severity_color}; font-size: 12px; color: #475569;">
<strong>Boundary Context:</strong> {scenario.get('boundary_note', 'OSS analyzes, Enterprise executes')}
</div>
</div>
"""
# Get visualizations as Plotly figures (ENHANCED)
telemetry_fig = create_simple_telemetry_plot(scenario_name, settings.use_true_arf)
impact_fig = create_simple_impact_plot(scenario_name, settings.use_true_arf)
timeline_fig = create_empty_plot(f"Timeline: {scenario_name}", settings.use_true_arf)
# ============ NEW: Create realism panel ============
try:
# Use the imported create_realism_panel function
realism_html = components["create_realism_panel"](scenario, scenario_name)
except (ImportError, KeyError):
# Fallback if realism function isn't available yet
realism_html = """
<div style="border: 2px solid #f59e0b; border-radius: 14px; padding: 20px;
background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);
text-align: center; margin-top: 20px;">
<div style="font-size: 36px; margin-bottom: 10px;">πŸ”§</div>
<h4 style="margin: 0 0 10px 0; color: #92400e;">Realism Panel Loading...</h4>
<p style="color: #b45309; font-size: 14px;">
Trade-offs, risk assessments, and ranked actions will appear here
</p>
</div>
"""
logger.info(f"βœ… Updated scenario display for {scenario_name} with realism panel")
# ============ CHANGE HERE: Add realism_html to return tuple ============
return scenario_card_html, telemetry_fig, impact_fig, timeline_fig, realism_html
# ===========================================
# ENHANCED: Combined update function for scenario display + performance metrics
# ===========================================
def update_scenario_display_with_metrics(scenario_name: str) -> tuple:
"""
Combined update function that returns both scenario display AND performance metrics.
Returns 9 values: (scenario_card, telemetry_viz, impact_viz, timeline_viz, realism_panel,
detection_time_html, mttr_html, auto_heal_html, savings_html)
"""
# Get the scenario display components (5 outputs)
scenario_card, telemetry_fig, impact_fig, timeline_fig, realism_html = update_scenario_display(scenario_name)
# Get performance metrics (4 outputs)
components = get_components()
detection_time_html, mttr_html, auto_heal_html, savings_html = components["update_performance_metrics"](scenario_name)
return (scenario_card, telemetry_fig, impact_fig, timeline_fig, realism_html,
detection_time_html, mttr_html, auto_heal_html, savings_html)
# ===========================================
# SURGICAL FIX: run_true_arf_analysis() - FIXED to return DataFrames
# ===========================================
@AsyncRunner.async_to_sync
async def run_true_arf_analysis(scenario_name: str) -> tuple:
"""
FIXED: Returns exactly 5 values as expected by UI:
1. detection_html (HTML string)
2. recall_html (HTML string)
3. decision_html (HTML string)
4. oss_results_dict (Python dict for JSON display)
5. incident_df (DataFrame for Gradio DataFrame component)
"""
components = get_components()
installation = get_installation_status()
boundaries = BoundaryManager.get_system_boundaries()
logger.info(f"πŸ” Running True ARF analysis for: {scenario_name}")
try:
# Get orchestrator
orchestrator = components["DemoOrchestrator"]()
# Get scenario data
scenarios = components["INCIDENT_SCENARIOS"]
scenario_data = scenarios.get(scenario_name, {})
# Run analysis
analysis_result = await orchestrator.analyze_incident(scenario_name, scenario_data)
# Add to audit trail
get_audit_manager().add_incident(scenario_name, analysis_result)
# Check if we have real ARF
is_real_arf = installation["oss_installed"] or settings.use_true_arf
# Create HTML for active agents
boundary_color = boundaries["oss"]["color"] if is_real_arf else "#f59e0b"
boundary_text = boundaries["oss"]["label"] if is_real_arf else "Mock ARF"
# Detection Agent HTML
detection_html = f"""
<div style="border: 2px solid {boundary_color}; border-radius: 14px; padding: 18px;
background: linear-gradient(135deg, {boundary_color}10 0%, #ffffff 100%);
text-align: center; flex: 1; margin: 5px; min-height: 180px;">
<div style="font-size: 32px; margin-bottom: 10px; color: {boundary_color};">πŸ•΅οΈβ€β™‚οΈ</div>
<div style="width: 100%;">
<h4 style="margin: 0 0 8px 0; font-size: 16px; color: #1e293b;">Detection Agent</h4>
<p style="font-size: 13px; color: #64748b; margin-bottom: 12px; line-height: 1.4;">
Anomaly detected with 94% confidence
</p>
<div style="display: flex; justify-content: space-around; margin-bottom: 12px;">
<span style="font-size: 11px; padding: 3px 8px; background: {boundary_color}20;
border-radius: 6px; color: {boundary_color}; font-weight: 500;">
Status: Active
</span>
</div>
<div style="display: inline-block; padding: 5px 14px; background: {boundary_color};
border-radius: 20px; font-size: 12px; font-weight: bold; color: white;
text-transform: uppercase; letter-spacing: 0.5px;">
DETECTED
</div>
</div>
</div>
"""
# Recall Agent HTML
recall_html = f"""
<div style="border: 2px solid {boundary_color}; border-radius: 14px; padding: 18px;
background: linear-gradient(135deg, {boundary_color}10 0%, #ffffff 100%);
text-align: center; flex: 1; margin: 5px; min-height: 180px;">
<div style="font-size: 32px; margin-bottom: 10px; color: {boundary_color};">🧠</div>
<div style="width: 100%;">
<h4 style="margin: 0 0 8px 0; font-size: 16px; color: #1e293b;">Recall Agent</h4>
<p style="font-size: 13px; color: #64748b; margin-bottom: 12px; line-height: 1.4;">
3 similar incidents found in RAG memory
</p>
<div style="display: flex; justify-content: space-around; margin-bottom: 12px;">
<span style="font-size: 11px; padding: 3px 8px; background: {boundary_color}20;
border-radius: 6px; color: {boundary_color}; font-weight: 500;">
Status: Active
</span>
</div>
<div style="display: inline-block; padding: 5px 14px; background: {boundary_color};
border-radius: 20px; font-size: 12px; font-weight: bold; color: white;
text-transform: uppercase; letter-spacing: 0.5px;">
RECALLED
</div>
</div>
</div>
"""
# Decision Agent HTML
decision_html = f"""
<div style="border: 2px solid {boundary_color}; border-radius: 14px; padding: 18px;
background: linear-gradient(135deg, {boundary_color}10 0%, #ffffff 100%);
text-align: center; flex: 1; margin: 5px; min-height: 180px;">
<div style="font-size: 32px; margin-bottom: 10px; color: {boundary_color};">🎯</div>
<div style="width: 100%;">
<h4 style="margin: 0 0 8px 0; font-size: 16px; color: #1e293b;">Decision Agent</h4>
<p style="font-size: 13px; color: #64748b; margin-bottom: 12px; line-height: 1.4;">
HealingIntent created: Scale Redis cluster
</p>
<div style="display: flex; justify-content: space-around; margin-bottom: 12px;">
<span style="font-size: 11px; padding: 3px 8px; background: {boundary_color}20;
border-radius: 6px; color: {boundary_color}; font-weight: 500;">
Status: Active
</span>
</div>
<div style="display: inline-block; padding: 5px 14px; background: {boundary_color};
border-radius: 20px; font-size: 12px; font-weight: bold; color: white;
text-transform: uppercase; letter-spacing: 0.5px;">
DECIDED
</div>
</div>
</div>
"""
# OSS Results Dict for JSON display
if is_real_arf and "real" in str(analysis_result).lower():
oss_results_dict = {
"status": "success",
"scenario": scenario_name,
"arf_version": "3.3.9",
"analysis": {
"detected": True,
"confidence": 94,
"similar_incidents": 3,
"healing_intent_created": True,
"recommended_action": "Scale Redis cluster from 3 to 5 nodes",
"estimated_recovery": "12 minutes"
},
"agents": {
"detection": {"status": "active", "confidence": 94},
"recall": {"status": "active", "similar_incidents": 3},
"decision": {"status": "active", "healing_intent_created": True}
},
"boundary_note": f"OSS analysis complete β†’ Ready for Enterprise execution"
}
else:
oss_results_dict = {
"status": "mock_analysis",
"scenario": scenario_name,
"arf_version": "mock",
"analysis": {
"detected": True,
"confidence": 94,
"similar_incidents": 3,
"healing_intent_created": True,
"recommended_action": "Scale Redis cluster from 3 to 5 nodes",
"estimated_recovery": "12 minutes"
},
"agents": {
"detection": {"status": "active", "confidence": 94},
"recall": {"status": "active", "similar_incidents": 3},
"decision": {"status": "active", "healing_intent_created": True}
},
"boundary_note": f"Mock analysis - {boundary_text}"
}
# Incident DataFrame (FIXED: Returns DataFrame instead of HTML)
incident_df = get_audit_manager().get_incident_dataframe()
return detection_html, recall_html, decision_html, oss_results_dict, incident_df
except Exception as e:
logger.error(f"True ARF analysis failed: {e}")
# Return error state with proper types
error_html = f"""
<div style="border: 2px solid #ef4444; border-radius: 14px; padding: 18px;
background: linear-gradient(135deg, #fef2f2 0%, #ffffff 100%);
text-align: center; flex: 1; margin: 5px; min-height: 180px;">
<div style="font-size: 32px; margin-bottom: 10px; color: #ef4444;">❌</div>
<div style="width: 100%;">
<h4 style="margin: 0 0 8px 0; font-size: 16px; color: #1e293b;">Analysis Error</h4>
<p style="font-size: 13px; color: #64748b; margin-bottom: 12px; line-height: 1.4;">
Failed to analyze incident
</p>
<div style="display: flex; justify-content: space-around; margin-bottom: 12px;">
<span style="font-size: 11px; padding: 3px 8px; background: #ef4444;
border-radius: 6px; color: white; font-weight: 500;">
Status: Error
</span>
</div>
</div>
</div>
"""
error_dict = {
"status": "error",
"error": str(e),
"scenario": scenario_name,
"arf_version": "3.3.9",
"recommendation": "Check ARF installation"
}
# Return empty DataFrame on error
error_df = pd.DataFrame(columns=["Error", "Message"]).from_records([
{"Error": "Analysis Failed", "Message": str(e)}
])
return error_html, error_html, error_html, error_dict, error_df
# ===========================================
# FIXED EXECUTION FUNCTION - Returns DataFrames
# ===========================================
def execute_enterprise_healing(scenario_name, approval_required, mcp_mode_value):
"""
MINIMAL FIX: Returns proper data types matching UI expectations
FIXED: Returns DataFrame instead of HTML for execution table
"""
import gradio as gr
components = get_components()
installation = get_installation_status()
boundaries = BoundaryManager.get_system_boundaries()
logger.info(f"⚑ Executing enterprise healing for: {scenario_name}")
# Check if Enterprise is actually available
is_real_enterprise = installation["enterprise_installed"]
is_simulated = not is_real_enterprise
# Get scenario impact
scenario = components["INCIDENT_SCENARIOS"].get(scenario_name, {})
impact = scenario.get("business_impact", {})
revenue_loss = impact.get("revenue_loss_per_hour", get_scenario_impact(scenario_name))
savings = int(revenue_loss * 0.85)
# Create approval display HTML
if approval_required:
approval_display = """
<div style="border: 3px solid #f59e0b; border-radius: 14px; padding: 25px;
background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);
text-align: center; margin-bottom: 20px;">
<div style="font-size: 36px; margin-bottom: 15px;">⏳</div>
<h4 style="margin: 0 0 12px 0; font-size: 20px; color: #92400e; font-weight: 700;">
HUMAN APPROVAL REQUIRED
</h4>
<p style="font-size: 15px; color: #92400e; margin-bottom: 15px; line-height: 1.6;">
Based on your safety settings, this execution requires human approval.
</p>
</div>
"""
else:
approval_display = """
<div style="border: 3px solid #10b981; border-radius: 14px; padding: 25px;
background: linear-gradient(135deg, #f0fdf4 0%, #bbf7d0 100%);
text-align: center; margin-bottom: 20px;">
<div style="font-size: 36px; margin-bottom: 15px;">⚑</div>
<h4 style="margin: 0 0 12px 0; font-size: 20px; color: #065f46; font-weight: 700;">
AUTONOMOUS APPROVAL GRANTED
</h4>
<p style="font-size: 15px; color: #065f46; margin-bottom: 15px; line-height: 1.6;">
Proceeding with autonomous execution.
</p>
</div>
"""
# Execute healing (async)
@AsyncRunner.async_to_sync
async def execute_async():
try:
orchestrator = components["DemoOrchestrator"]()
execution_result = await orchestrator.execute_healing(scenario_name, "autonomous")
# Add to audit trail
get_audit_manager().add_execution(scenario_name, "enterprise_autonomous", execution_result)
return execution_result
except Exception as e:
logger.error(f"Execution failed: {e}")
return {
"status": "failed",
"error": str(e),
"boundary_note": "Execution boundary reached"
}
execution_result = execute_async()
# Create results dict for JSON display
if is_real_enterprise:
enterprise_results = {
"demo_mode": "Real Enterprise",
"scenario": scenario_name,
"arf_version": boundaries["enterprise"]["version"],
"execution_mode": "autonomous" if not approval_required else "human_approved",
"results": {
"recovery_time": "12 minutes",
"cost_saved": f"${savings:,}",
"users_protected": "45,000"
},
"safety_features": [
"Rollback guarantee: 100%",
"Atomic execution",
"MCP validation"
]
}
else:
enterprise_results = {
"demo_mode": "Enterprise Simulation",
"scenario": scenario_name,
"arf_version": boundaries["enterprise"]["version"],
"execution_mode": "simulated_autonomous",
"results": {
"recovery_time": "12 minutes (simulated)",
"cost_saved": f"${savings:,} (simulated)",
"users_protected": "45,000 (simulated)"
},
"safety_features": [
"Rollback guarantee: 100% (simulated)",
"Atomic execution (simulated)"
]
}
# Get execution DataFrame (FIXED: Returns DataFrame instead of HTML)
execution_df = get_audit_manager().get_execution_dataframe()
return approval_display, enterprise_results, execution_df
# ===========================================
# FIXED ROI FUNCTION - Enhanced for Gradio
# ===========================================
def calculate_roi(scenario_name, monthly_incidents, team_size):
"""
ENHANCED: Returns (JSON/dict, Plotly figure) for ROI calculation with Gradio compatibility
"""
components = get_components()
try:
# Try to use real ROI calculator
calculator = components["EnhancedROICalculator"]
roi_result = calculator.calculate_comprehensive_roi(
scenario_name=scenario_name,
monthly_incidents=monthly_incidents,
team_size=team_size
)
except Exception as e:
logger.warning(f"ROI calculation failed, using mock: {e}")
# Mock ROI calculation
impact_per_incident = get_scenario_impact(scenario_name)
annual_impact = impact_per_incident * monthly_incidents * 12
potential_savings = int(annual_impact * 0.82)
enterprise_cost = 625000
roi_multiplier = round(potential_savings / enterprise_cost, 1)
payback_months = round((enterprise_cost / (potential_savings / 12)), 1)
roi_result = {
"status": "βœ… Calculated Successfully",
"summary": {
"your_annual_impact": f"${annual_impact:,}",
"potential_savings": f"${potential_savings:,}",
"enterprise_cost": f"${enterprise_cost:,}",
"roi_multiplier": f"{roi_multiplier}Γ—",
"payback_months": f"{payback_months}",
"annual_roi_percentage": f"{int((potential_savings - enterprise_cost) / enterprise_cost * 100)}%",
"boundary_context": "Based on OSS analysis + simulated Enterprise execution"
},
"boundary_note": "ROI calculation includes OSS advisory value and simulated Enterprise execution benefits"
}
# Create ROI chart as Plotly figure (ENHANCED for Gradio)
categories = ['Without ARF', 'With ARF', 'Net Savings']
annual_impact_val = impact_per_incident * monthly_incidents * 12 if 'impact_per_incident' in locals() else 1000000
potential_savings_val = potential_savings if 'potential_savings' in locals() else 820000
enterprise_cost_val = enterprise_cost if 'enterprise_cost' in locals() else 625000
values = [annual_impact_val, annual_impact_val - potential_savings_val, potential_savings_val - enterprise_cost_val]
fig = go.Figure(data=[
go.Bar(
name='Cost',
x=categories,
y=values,
marker_color=['#ef4444', '#10b981', '#8b5cf6']
)
])
fig.update_layout(
title={
'text': f"ROI Analysis: {scenario_name}",
'font': dict(size=18, color='#1e293b', family="Arial, sans-serif")
},
height=400,
plot_bgcolor='white',
paper_bgcolor='white',
showlegend=False,
margin=dict(l=40, r=20, t=60, b=40)
)
logger.info(f"βœ… Created ROI plot for {scenario_name}")
# Return both the dict and the Plotly figure
return roi_result, fig
# ===========================================
# CREATE DEMO INTERFACE - UPDATED WITH REALISM PANEL INTEGRATION
# ===========================================
def create_demo_interface():
"""Create demo interface using modular components with boundary awareness and realism panel"""
import gradio as gr
# Get components
components = get_components()
# Get CSS styles
css_styles = components["get_styles"]()
# Store CSS for later use in launch()
global _demo_css
_demo_css = css_styles
# Get boundary badges for the interface
boundary_badges = BoundaryManager.get_boundary_badges()
# Create interface without css parameter (will be added in launch)
with gr.Blocks(
title=f"πŸš€ ARF Investor Demo v3.3.9 - TRUE ARF OSS Integration"
) as demo:
# Header
header_html = components["create_header"]("3.3.9")
# Status bar with boundary badges
status_html = components["create_status_bar"]()
# ============ 5 TABS ============
with gr.Tabs(elem_classes="tab-nav"):
# TAB 1: Live Incident Demo - NOW WITH REALISM PANEL
with gr.TabItem("πŸ”₯ Live Incident Demo", id="tab1"):
(scenario_dropdown, scenario_card, telemetry_viz, impact_viz,
workflow_header, detection_agent, recall_agent, decision_agent,
oss_section, enterprise_section, oss_btn, enterprise_btn,
approval_toggle, mcp_mode, timeline_viz, realism_panel,
detection_time, mttr, auto_heal, savings,
oss_results_display, enterprise_results_display, approval_display, demo_btn) = components["create_tab1_incident_demo"]()
# TAB 2: Business ROI
with gr.TabItem("πŸ’° Business Impact & ROI", id="tab2"):
(dashboard_output, roi_scenario_dropdown, monthly_slider, team_slider,
calculate_btn, roi_output, roi_chart) = components["create_tab2_business_roi"](components["INCIDENT_SCENARIOS"])
# TAB 3: Enterprise Features
with gr.TabItem("🏒 Enterprise Features", id="tab3"):
(license_display, validate_btn, trial_btn, upgrade_btn,
mcp_mode_tab3, mcp_mode_info, features_table, integrations_table) = components["create_tab3_enterprise_features"]()
# TAB 4: Audit Trail
with gr.TabItem("πŸ“œ Audit Trail & History", id="tab4"):
(refresh_btn, clear_btn, export_btn, execution_table,
incident_table, export_text) = components["create_tab4_audit_trail"]()
# TAB 5: Learning Engine
with gr.TabItem("🧠 Learning Engine", id="tab5"):
(learning_graph, graph_type, show_labels, search_query, search_btn,
clear_btn_search, search_results, stats_display, patterns_display,
performance_display) = components["create_tab5_learning_engine"]()
# Footer
footer_html = components["create_footer"]()
# ============ EVENT HANDLERS ============
# Update scenario display when dropdown changes - NOW INCLUDES PERFORMANCE METRICS
scenario_dropdown.change(
fn=update_scenario_display_with_metrics, # ← Changed to combined function
inputs=[scenario_dropdown],
outputs=[
scenario_card, telemetry_viz, impact_viz, timeline_viz, realism_panel,
detection_time, mttr, auto_heal, savings # 4 new outputs for metrics
]
)
# Run OSS Analysis - FIXED: Now returns DataFrame for incident_table
oss_btn.click(
fn=run_true_arf_analysis,
inputs=[scenario_dropdown],
outputs=[
detection_agent, recall_agent, decision_agent,
oss_results_display, incident_table
]
)
# Execute Enterprise Healing - FIXED: Now returns DataFrame for execution_table
enterprise_btn.click(
fn=execute_enterprise_healing,
inputs=[scenario_dropdown, approval_toggle, mcp_mode],
outputs=[approval_display, enterprise_results_display, execution_table]
)
# Run Complete Demo with boundary progression
@AsyncRunner.async_to_sync
async def run_complete_demo_async(scenario_name):
"""Run a complete demo walkthrough with true ARF and boundary awareness"""
# Step 1: Update scenario with metrics
update_result = update_scenario_display_with_metrics(scenario_name)
# Step 2: Run true ARF analysis
oss_result = await run_true_arf_analysis(scenario_name)
# Step 3: Execute Enterprise (simulation) with boundary context
await asyncio.sleep(1)
scenario = components["INCIDENT_SCENARIOS"].get(scenario_name, {})
impact = scenario.get("business_impact", {})
revenue_loss = impact.get("revenue_loss_per_hour", get_scenario_impact(scenario_name))
savings_amount = int(revenue_loss * 0.85)
# Get boundary context
boundaries = BoundaryManager.get_system_boundaries()
# Get orchestrator for execution simulation
orchestrator = components["DemoOrchestrator"]()
execution_result = await orchestrator.execute_healing(scenario_name, "autonomous")
enterprise_results = {
"demo_mode": "Complete Walkthrough",
"scenario": scenario_name,
"arf_version": "3.3.9",
"true_oss_used": True,
"enterprise_simulated": True,
"boundary_progression": [
f"1. Incident detected - {boundaries['oss']['label']}",
f"2. OSS analysis completed - {boundaries['oss']['label']}",
f"3. HealingIntent created - {boundaries['oss']['label']}",
f"4. Enterprise license validated ({boundaries['enterprise']['label']})",
f"5. Autonomous execution simulated ({boundaries['enterprise']['label']}+)",
f"6. Outcome recorded in RAG memory"
],
"execution_result": execution_result,
"outcome": {
"recovery_time": "12 minutes",
"manual_comparison": "45 minutes",
"cost_saved": f"${savings_amount:,}",
"users_protected": "45,000",
"learning": "Pattern added to RAG memory"
},
"architectural_summary": f"This demonstrates the complete ARF v3.3.9 architecture: {boundaries['oss']['label']} for advisory analysis β†’ {boundaries['enterprise']['label']} for autonomous execution"
}
# Create demo completion message with enhanced boundary context
demo_message = f"""
<div style="border: 1px solid #e2e8f0; border-radius: 14px; padding: 20px;
background: linear-gradient(135deg, #f0fdf4 0%, #e9d5ff 100%); margin-top: 20px;
box-shadow: 0 8px 32px rgba(16, 185, 129, 0.1);">
<!-- Header with dual-color badge showing boundary -->
<div style="display: flex; justify-content: space-between; align-items: center;
margin-bottom: 20px; padding-bottom: 12px; border-bottom: 2px solid #e2e8f0;">
<div>
<h3 style="margin: 0; font-size: 18px; color: #1e293b; font-weight: 700;">
βœ… Complete Demo: Architecture Validated
</h3>
<p style="margin: 5px 0 0 0; font-size: 13px; color: #64748b;">
ARF v3.3.9 β€’ OSS advises β†’ Enterprise executes
</p>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<span style="padding: 6px 14px; background: linear-gradient(90deg, #10b981 0%, #10b981 50%, #8b5cf6 50%, #8b5cf6 100%);
color: white; border-radius: 20px; font-size: 12px; font-weight: bold;">
BOUNDARY VALIDATED
</span>
</div>
</div>
<!-- Key Results Grid -->
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-bottom: 20px;">
<!-- Left Column: OSS Results -->
<div style="border-left: 4px solid #10b981; padding: 12px; background: #f8fafc; border-radius: 8px;">
<div style="font-size: 11px; color: #64748b; text-transform: uppercase; font-weight: 600;
margin-bottom: 5px; display: flex; align-items: center; gap: 6px;">
<span style="display: inline-block; width: 8px; height: 8px; background: #10b981; border-radius: 50%;"></span>
{boundaries['oss']['label']}
</div>
<div style="font-size: 14px; color: #475569; line-height: 1.5;">
β€’ Anomaly detected in 45s<br>
β€’ 3 similar incidents recalled<br>
β€’ 94% confidence healing plan<br>
β€’ Apache 2.0 license validated
</div>
</div>
<!-- Right Column: Enterprise Results -->
<div style="border-left: 4px solid #8b5cf6; padding: 12px; background: #f8fafc; border-radius: 8px;">
<div style="font-size: 11px; color: #64748b; text-transform: uppercase; font-weight: 600;
margin-bottom: 5px; display: flex; align-items: center; gap: 6px;">
<span style="display: inline-block; width: 8px; height: 8px; background: #8b5cf6; border-radius: 50%;"></span>
{boundaries['enterprise']['label']}
</div>
<div style="font-size: 14px; color: #475569; line-height: 1.5;">
β€’ Autonomous execution simulated<br>
β€’ Rollback guarantee: 100%<br>
β€’ 12min vs 45min recovery<br>
β€’ ${savings_amount:,} saved
</div>
</div>
</div>
<!-- Boundary Progression Visualization -->
<div style="margin-bottom: 20px;">
<div style="font-size: 12px; color: #64748b; text-transform: uppercase; font-weight: 600;
margin-bottom: 12px; text-align: center;">
πŸ—οΈ Architecture Flow
</div>
<div style="display: flex; align-items: center; justify-content: center; gap: 0;">
<!-- OSS -->
<div style="text-align: center; padding: 12px 16px; background: #f0fdf4; border-radius: 10px 0 0 10px;
border: 2px solid #10b981; border-right: none; min-width: 140px;">
<div style="font-size: 14px; color: #065f46; font-weight: 700;">OSS Advisory</div>
<div style="font-size: 11px; color: #059669; margin-top: 3px;">Apache 2.0</div>
</div>
<!-- Arrow -->
<div style="padding: 0 5px; background: #f1f5f9; position: relative;">
<div style="width: 0; height: 0; border-top: 15px solid transparent;
border-bottom: 15px solid transparent; border-left: 15px solid #10b981;"></div>
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
background: white; padding: 2px 6px; border-radius: 10px; font-size: 11px;
color: #64748b; border: 1px solid #e2e8f0; white-space: nowrap;">
advises
</div>
</div>
<!-- Enterprise -->
<div style="text-align: center; padding: 12px 16px; background: #f5f3ff; border-radius: 0 10px 10px 0;
border: 2px solid #8b5cf6; border-left: none; min-width: 140px;">
<div style="font-size: 14px; color: #5b21b6; font-weight: 700;">Enterprise</div>
<div style="font-size: 11px; color: #7c3aed; margin-top: 3px;">Commercial</div>
</div>
</div>
</div>
<!-- ROI Summary -->
<div style="background: linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%);
border-radius: 10px; padding: 15px; margin-bottom: 15px;">
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; text-align: center;">
<div>
<div style="font-size: 11px; color: #64748b; margin-bottom: 5px;">Time Saved</div>
<div style="font-size: 18px; font-weight: 700; color: #10b981;">73%</div>
</div>
<div>
<div style="font-size: 11px; color: #64748b; margin-bottom: 5px;">Cost Saved</div>
<div style="font-size: 18px; font-weight: 700; color: #10b981;">${savings_amount:,}</div>
</div>
<div>
<div style="font-size: 11px; color: #64748b; margin-bottom: 5px;">ROI Multiplier</div>
<div style="font-size: 18px; font-weight: 700; color: #8b5cf6;">5.2Γ—</div>
</div>
</div>
</div>
<!-- Architecture Validation -->
<div style="margin-top: 15px; padding: 12px; background: #f0fdf4; border-radius: 8px; border: 1px solid #d1fae5;">
<div style="display: flex; align-items: center; gap: 10px;">
<div style="font-size: 20px;">βœ…</div>
<div>
<div style="font-size: 13px; color: #065f46; font-weight: 600; margin-bottom: 2px;">
Architecture Successfully Validated
</div>
<div style="font-size: 12px; color: #059669;">
Clear separation maintained: OSS for advisory intelligence, Enterprise for autonomous execution
</div>
</div>
</div>
</div>
<!-- Call to action -->
<div style="margin-top: 15px; padding-top: 15px; border-top: 1px dashed #e2e8f0;
text-align: center; font-size: 12px; color: #64748b;">
Ready for production? <a href="#" style="color: #8b5cf6; font-weight: 600; text-decoration: none;">
Install ARF Enterprise β†’</a>
</div>
</div>
"""
# Update the enterprise_results_display to include demo completion info
enterprise_results["demo_completion_message"] = demo_message
# Get updated DataFrames (FIXED: Returns DataFrames)
incident_df = get_audit_manager().get_incident_dataframe()
execution_df = get_audit_manager().get_execution_dataframe()
# Combine all results
return (
*update_result, # 9 outputs: scenario_card, telemetry_viz, impact_viz, timeline_viz, realism_panel, detection_time, mttr, auto_heal, savings
*oss_result[:3], # 3 outputs: detection_agent, recall_agent, decision_agent
oss_result[3], # 1 output: oss_results_display
enterprise_results, # 1 output: enterprise_results_display
demo_message, # 1 output: approval_display
incident_df, # 1 output: incident_table (DataFrame)
execution_df # 1 output: execution_table (DataFrame)
)
# FIXED: demo_btn.click with correct output count
demo_btn.click(
fn=run_complete_demo_async,
inputs=[scenario_dropdown],
outputs=[
scenario_card, telemetry_viz, impact_viz, timeline_viz, realism_panel,
detection_time, mttr, auto_heal, savings, # 9
detection_agent, recall_agent, decision_agent, # 3
oss_results_display, # 1
enterprise_results_display, # 1
approval_display, # 1
incident_table, # 1
execution_table # 1
]
)
# ROI Calculation
calculate_btn.click(
fn=calculate_roi,
inputs=[roi_scenario_dropdown, monthly_slider, team_slider],
outputs=[roi_output, roi_chart]
)
# Update ROI scenario - FIXED: Use the EnhancedROICalculator
roi_scenario_dropdown.change(
fn=lambda x: get_components()["EnhancedROICalculator"].calculate_comprehensive_roi(scenario_name=x),
inputs=[roi_scenario_dropdown],
outputs=[roi_output]
)
# Update ROI chart
monthly_slider.change(
fn=lambda x, y: calculate_roi(roi_scenario_dropdown.value, x, y)[1],
inputs=[monthly_slider, team_slider],
outputs=[roi_chart]
)
team_slider.change(
fn=lambda x, y: calculate_roi(roi_scenario_dropdown.value, x, y)[1],
inputs=[monthly_slider, team_slider],
outputs=[roi_chart]
)
# Audit Trail Functions - FIXED: Returns DataFrames
def refresh_audit_trail():
"""Refresh audit trail tables - FIXED to return DataFrames"""
return (
get_audit_manager().get_execution_dataframe(), # DataFrame
get_audit_manager().get_incident_dataframe() # DataFrame
)
def clear_audit_trail():
"""Clear audit trail - FIXED to return empty DataFrames"""
get_audit_manager().clear()
# Return empty DataFrames with correct columns
exec_df = pd.DataFrame(columns=["Execution ID", "Scenario", "Status", "Mode", "Start Time"])
incident_df = pd.DataFrame(columns=["Scenario", "Status", "Boundary", "Time"])
return exec_df, incident_df
def export_audit_trail():
"""Export audit trail as JSON"""
audit_data = {
"executions": get_audit_manager().executions,
"incidents": get_audit_manager().incidents,
"boundary_crossings": get_audit_manager().boundary_crossings,
"export_time": datetime.datetime.now().isoformat(),
"arf_version": "3.3.9",
"architecture": "OSS advises β†’ Enterprise executes"
}
return json.dumps(audit_data, indent=2)
refresh_btn.click(
fn=refresh_audit_trail,
inputs=[],
outputs=[execution_table, incident_table]
)
clear_btn.click(
fn=clear_audit_trail,
inputs=[],
outputs=[execution_table, incident_table]
)
export_btn.click(
fn=export_audit_trail,
inputs=[],
outputs=[export_text]
)
# Enterprise Features
def validate_license():
"""Validate enterprise license with boundary context"""
boundaries = BoundaryManager.get_system_boundaries()
if boundaries["enterprise"]["available"]:
return {
"status": "βœ… Valid License",
"license_type": "Enterprise",
"version": boundaries["enterprise"]["version"],
"expires": "2025-12-31",
"capabilities": boundaries["enterprise"]["capabilities"],
"boundary_context": f"Real {boundaries['enterprise']['label']} detected"
}
else:
return {
"status": "⚠️ Demo Mode",
"license_type": "Simulated",
"version": boundaries["enterprise"]["version"],
"expires": "Demo only",
"capabilities": boundaries["enterprise"]["capabilities"],
"boundary_context": f"Simulating {boundaries['enterprise']['label']} - requires license",
"contact": "sales@arf.dev"
}
validate_btn.click(
fn=validate_license,
inputs=[],
outputs=[license_display]
)
# Load default scenario - UPDATE outputs with realism_panel AND performance metrics
demo.load(
fn=lambda: update_scenario_display_with_metrics(settings.default_scenario),
inputs=[],
outputs=[
scenario_card, telemetry_viz, impact_viz, timeline_viz, realism_panel,
detection_time, mttr, auto_heal, savings
]
)
# Load ROI data
demo.load(
fn=lambda: calculate_roi(settings.default_scenario, 15, 5),
inputs=[],
outputs=[roi_output, roi_chart]
)
logger.info("βœ… Demo interface created successfully with boundary awareness, realism panel, and dynamic performance metrics")
return demo
# ===========================================
# LAUNCH FUNCTION
# ===========================================
def launch_demo():
"""Launch the demo application with proper configuration"""
try:
logger.info("πŸš€ Starting ARF Ultimate Investor Demo v3.3.9 - ENTERPRISE EDITION")
# Check installation
installation = get_installation_status()
boundaries = BoundaryManager.get_system_boundaries()
logger.info("=" * 60)
logger.info("πŸ—οΈ SYSTEM ARCHITECTURE BOUNDARIES:")
logger.info(f" OSS: {boundaries['oss']['label']} v{boundaries['oss']['version']}")
logger.info(f" Enterprise: {boundaries['enterprise']['label']} v{boundaries['enterprise']['version']}")
logger.info(f" Mode: {boundaries['demo_mode']['architecture']}")
logger.info("=" * 60)
# Create interface
demo = create_demo_interface()
# Get CSS styles
components = get_components()
css_styles = components["get_styles"]()
# Configure for Hugging Face Spaces
launch_config = {
"server_name": "0.0.0.0",
"server_port": 7860,
"share": False,
"favicon_path": None,
"quiet": False,
"show_error": True,
"debug": False,
"max_threads": 40,
}
# Add CSS if available
if css_styles:
launch_config["css"] = css_styles
logger.info("βœ… Launch configuration ready")
return demo, launch_config
except Exception as e:
logger.error(f"❌ Launch failed: {e}", exc_info=True)
# Create minimal fallback interface
import gradio as gr
with gr.Blocks(title="ARF Demo - Fallback Mode") as fallback_demo:
gr.HTML(f"""
<div style="text-align: center; padding: 50px;">
<h1 style="color: #ef4444;">🚨 ARF Demo Failed to Start</h1>
<p style="color: #64748b; font-size: 16px;">Error: {str(e)}</p>
<div style="margin-top: 30px; padding: 20px; background: #fef2f2; border-radius: 10px; display: inline-block;">
<p style="color: #dc2626; font-weight: bold;">Troubleshooting Steps:</p>
<ol style="text-align: left; color: #475569;">
<li>Check logs for detailed error</li>
<li>Ensure all dependencies are installed</li>
<li>Try: pip install agentic-reliability-framework==3.3.9</li>
<li>Restart the application</li>
</ol>
</div>
</div>
""")
return fallback_demo, {"server_name": "0.0.0.0", "server_port": 7860}
# ===========================================
# MAIN EXECUTION
# ===========================================
if __name__ == "__main__":
try:
logger.info("πŸš€ ARF Ultimate Investor Demo v3.3.9 - ENTERPRISE EDITION")
logger.info("=" * 60)
logger.info("Enhanced with clear OSS vs Enterprise boundaries")
logger.info("Now with Realism Panel for enterprise-seasoned SRE experience")
logger.info("PHASE 2: Dynamic Performance Metrics by Scenario Type")
logger.info(f"True ARF OSS v3.3.9 integration with simulated Enterprise execution")
logger.info("=" * 60)
# Launch the demo
demo, config = launch_demo()
print("\n" + "="*60)
print("πŸš€ ARF Ultimate Investor Demo v3.3.9 - ENTERPRISE EDITION")
print("πŸ“Š Architecture: OSS advises β†’ Enterprise executes")
print("🎭 Phase 2: Dynamic Performance Metrics by Scenario")
print("🌐 Starting on http://localhost:7860")
print("="*60 + "\n")
# Launch with error handling
try:
demo.launch(**config)
except Exception as launch_error:
logger.error(f"❌ Launch error: {launch_error}")
# Try alternative launch without CSS
if "css" in config:
logger.info("⚠️ Retrying without CSS...")
config.pop("css", None)
demo.launch(**config)
else:
# Last resort: simple launch
demo.launch(server_name="0.0.0.0", server_port=7860)
except KeyboardInterrupt:
logger.info("πŸ‘‹ Demo stopped by user")
except Exception as e:
logger.error(f"❌ Fatal error: {e}", exc_info=True)
sys.exit(1)