| |
| |
| |
| |
| |
| |
| |
| |
|
|
| 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 |
|
|
| |
| |
| |
| 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__) |
|
|
| |
| sys.path.insert(0, str(Path(__file__).parent)) |
|
|
| |
| |
| |
| |
| FEATURE_FLAGS = { |
| 'modern_ui': True, |
| 'dark_mode': True, |
| 'responsive_design': True, |
| 'progressive_disclosure': False, |
| 'keyboard_nav': False, |
| 'realtime_updates': False |
| } |
|
|
| |
| def get_feature_flags(): |
| flags = FEATURE_FLAGS.copy() |
| |
| return flags |
|
|
| |
| |
| |
| 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") |
|
|
| |
| |
| |
| from utils.installation import InstallationHelper |
| from demo.guidance import DemoPsychologyController, get_demo_controller |
|
|
| |
| |
| |
| 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> |
| """ |
|
|
| |
| |
| |
| class AsyncRunner: |
| """Enhanced async runner with better error handling - FIXED to preserve return contracts""" |
| |
| @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}") |
| |
| 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;">Async Error</h4> |
| <p style="font-size: 13px; color: #64748b; margin-bottom: 12px; line-height: 1.4;"> |
| Async operation failed |
| </p> |
| </div> |
| </div> |
| """ |
| |
| error_dict = { |
| "status": "error", |
| "error": str(e), |
| "scenario": "Unknown", |
| "arf_version": "3.3.9", |
| "boundary_note": "Async execution boundary reached" |
| } |
| |
| error_df = pd.DataFrame(columns=["Error", "Message"]).from_records([ |
| {"Error": "Async Execution Failed", "Message": str(e)} |
| ]) |
| |
| |
| return error_html, error_html, error_html, error_dict, error_df |
| |
| @staticmethod |
| def async_to_sync(async_func): |
| """Decorator to convert async function to sync - FIXED to preserve return contract""" |
| def wrapper(*args, **kwargs): |
| try: |
| |
| result = AsyncRunner.run_async(async_func(*args, **kwargs)) |
| |
| |
| if isinstance(result, tuple) and len(result) == 5: |
| return result |
| else: |
| |
| logger.warning(f"Contract violation: Expected 5-tuple, got {type(result)}") |
| error_html = f""" |
| <div style="border: 2px solid #f59e0b; border-radius: 14px; padding: 18px; |
| background: linear-gradient(135deg, #fef3c7 0%, #ffffff 100%); |
| text-align: center; flex: 1; margin: 5px; min-height: 180px;"> |
| <div style="font-size: 32px; margin-bottom: 10px; color: #f59e0b;">β οΈ</div> |
| <div style="width: 100%;"> |
| <h4 style="margin: 0 0 8px 0; font-size: 16px; color: #1e293b;">Contract Violation</h4> |
| <p style="font-size: 13px; color: #64748b; margin-bottom: 12px; line-height: 1.4;"> |
| Expected 5-tuple, got {type(result).__name__} |
| </p> |
| </div> |
| </div> |
| """ |
| |
| error_dict = { |
| "status": "contract_error", |
| "error": f"Expected 5-tuple, got {type(result)}", |
| "scenario": args[0] if args else "Unknown", |
| "arf_version": "3.3.9", |
| "boundary_note": "Return contract violation" |
| } |
| |
| error_df = pd.DataFrame(columns=["Error", "Message"]).from_records([ |
| {"Error": "Contract Error", "Message": "Return shape violation"} |
| ]) |
| |
| return error_html, error_html, error_html, error_dict, error_df |
| |
| except Exception as e: |
| logger.error(f"Async to sync conversion failed: {e}") |
| |
| 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;">Conversion Error</h4> |
| <p style="font-size: 13px; color: #64748b; margin-bottom: 12px; line-height: 1.4;"> |
| Async to sync failed |
| </p> |
| </div> |
| </div> |
| """ |
| |
| error_dict = { |
| "status": "error", |
| "error": str(e), |
| "scenario": args[0] if args else "Unknown", |
| "arf_version": "3.3.9", |
| "boundary_context": "OSS advisory only - execution requires Enterprise" |
| } |
| |
| error_df = pd.DataFrame(columns=["Error", "Message"]).from_records([ |
| {"Error": "Conversion Failed", "Message": str(e)} |
| ]) |
| |
| |
| return error_html, error_html, error_html, error_dict, error_df |
| return wrapper |
|
|
| |
| |
| |
| 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 |
|
|
| settings = Settings() |
|
|
| |
| |
| |
| 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() |
| } |
| |
| |
| 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: |
| results["badges"]["enterprise"] = { |
| "text": "π’ Enterprise Edition", |
| "color": "#3b82f6", |
| "icon": "π’" |
| } |
| 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 |
|
|
| |
| |
| |
| import plotly.graph_objects as go |
| import plotly.express as px |
| import plotly.io as pio |
| import pandas as pd |
| import numpy as np |
|
|
| |
| pio.templates.default = "plotly_white" |
| logger.info("β
Plotly configured for Gradio compatibility") |
|
|
| |
| |
| |
| |
| try: |
| from ui.modern_components import ( |
| initialize_modern_ui, |
| Card, Grid, ObservationGate, |
| SequencingFlow, ProcessDisplay, |
| DESIGN_TOKENS, Button, Badge, |
| ResponsiveUtils, Accessibility, DarkMode, |
| create_example_dashboard |
| ) |
| MODERN_UI_AVAILABLE = True |
| logger.info("β
Modern UI components loaded successfully") |
| except ImportError as e: |
| MODERN_UI_AVAILABLE = False |
| logger.warning(f"β οΈ Modern UI components not available: {e}") |
| |
| |
| class Card: |
| @staticmethod |
| def create(content, **kwargs): |
| return f"<div class='card'>{content}</div>" |
| |
| class ObservationGate: |
| @staticmethod |
| def create(confidence=65.0, **kwargs): |
| return f"<div>Observation Gate: {confidence}%</div>" |
|
|
| |
| |
| |
| def load_css_files(): |
| """Load CSS files for modern UI with fallback""" |
| css_content = "" |
| |
| if get_feature_flags().get('modern_ui', False) and MODERN_UI_AVAILABLE: |
| try: |
| |
| with open("ui/styles/modern.css", "r") as f: |
| css_content += f.read() |
| logger.info("β
Loaded modern.css") |
| except FileNotFoundError: |
| |
| css_content += """ |
| :root { |
| --color-primary: #3b82f6; |
| --color-success: #10b981; |
| --color-warning: #f59e0b; |
| --color-danger: #ef4444; |
| --bg-primary: #ffffff; |
| --text-primary: #1e293b; |
| --border-color: #e2e8f0; |
| } |
| |
| .container { |
| width: 100%; |
| max-width: 1200px; |
| margin: 0 auto; |
| padding: 0 1rem; |
| } |
| |
| .grid { |
| display: grid; |
| gap: 1rem; |
| } |
| |
| @media (min-width: 640px) { |
| .grid-2 { grid-template-columns: repeat(2, 1fr); } |
| .grid-4 { grid-template-columns: repeat(4, 1fr); } |
| } |
| |
| @media (max-width: 640px) { |
| .grid-2, .grid-4 { grid-template-columns: 1fr; } |
| } |
| """ |
| |
| try: |
| with open("ui/styles/responsive.css", "r") as f: |
| css_content += f.read() |
| logger.info("β
Loaded responsive.css") |
| except FileNotFoundError: |
| |
| css_content += """ |
| .mobile-only { display: block; } |
| .desktop-only { display: none; } |
| |
| @media (min-width: 768px) { |
| .mobile-only { display: none; } |
| .desktop-only { display: block; } |
| } |
| |
| @media (max-width: 768px) { |
| .grid-2, .grid-4 { grid-template-columns: 1fr !important; } |
| } |
| """ |
| else: |
| |
| css_content = """ |
| :root { --color-primary: #3b82f6; } |
| .container { max-width: 1200px; margin: 0 auto; } |
| """ |
| |
| return f"<style>{css_content}</style>" |
|
|
| |
| |
| |
| 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: |
| |
| times = pd.date_range(start=datetime.datetime.now() - datetime.timedelta(minutes=10), |
| end=datetime.datetime.now(), |
| periods=60) |
| |
| |
| 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 |
| |
| |
| fig = go.Figure() |
| |
| |
| 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)' |
| )) |
| |
| |
| fig.add_trace(go.Scatter( |
| x=times[30:], |
| y=data[30:], |
| mode='lines', |
| name='Anomaly', |
| line=dict(color='#ef4444', width=3) |
| )) |
| |
| |
| fig.add_hline(y=threshold, line_dash="dash", |
| line_color="#f59e0b", |
| annotation_text="Alert Threshold", |
| annotation_position="top right") |
| |
| |
| 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}") |
| |
| 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 = { |
| "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) |
| |
| |
| 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 |
| } |
| } |
| )) |
| |
| |
| 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}") |
| |
| 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() |
| |
| |
| 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" |
| ) |
| |
| |
| 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}") |
| |
| fig = go.Figure() |
| fig.update_layout(height=300) |
| return fig |
|
|
| |
| |
| |
|
|
| def transform_arf_output_for_ui(raw_result: dict, scenario_name: str) -> dict: |
| """ |
| TRANSLATOR FUNCTION - NOT AN ANALYST |
| |
| Extracts existing intelligence from real ARF OSS output and transforms |
| to UI-expected format. Does not compute, infer, or enhance. |
| |
| Rules: |
| 1. Source of truth: raw_result["oss_analysis"]["analysis"] |
| 2. Extract only what exists |
| 3. Derive UI fields mechanically from existing data |
| 4. Never invent intelligence |
| 5. Defaults must be visibly conservative, not plausible |
| 6. Status must reflect contribution, not invocation |
| |
| Returns: UI-compatible dict with populated analysis and agents fields |
| """ |
| |
| |
| |
| |
| |
| |
| if "oss_analysis" in raw_result and raw_result["oss_analysis"]: |
| oss_analysis = raw_result["oss_analysis"] |
| source_analysis = oss_analysis.get("analysis", {}) if isinstance(oss_analysis, dict) else {} |
| is_real_oss = True |
| |
| |
| elif "analysis" in raw_result and raw_result["analysis"]: |
| source_analysis = raw_result["analysis"] |
| is_real_oss = False |
| |
| |
| else: |
| |
| return { |
| "status": raw_result.get("status", "error"), |
| "scenario": scenario_name, |
| "arf_version": raw_result.get("arf_version", "3.3.9"), |
| "analysis": { |
| "detected": False, |
| "confidence": 0, |
| "similar_incidents": 0, |
| "healing_intent_created": False, |
| "recommended_action": "Check OSS analysis output", |
| "estimated_recovery": "Unknown" |
| }, |
| "agents": { |
| "detection": {"status": "error", "confidence": 0}, |
| "recall": {"status": "error", "similar_incidents": 0}, |
| "decision": {"status": "error", "healing_intent_created": False} |
| }, |
| "boundary_note": "OSS analysis output malformed", |
| "installation": { |
| "oss_installed": True, |
| "version": "3.3.9", |
| "edition": "oss" |
| } |
| } |
| |
| |
| |
| |
| |
| |
| detection_data = source_analysis.get("detection", {}) if isinstance(source_analysis, dict) else {} |
| recall_data = source_analysis.get("recall", {}) if isinstance(source_analysis, dict) else {} |
| decision_data = source_analysis.get("decision", {}) if isinstance(source_analysis, dict) else {} |
| |
| |
| |
| |
| |
| |
| detected = False |
| if isinstance(detection_data, dict): |
| if "anomaly_detected" in detection_data: |
| detected = bool(detection_data["anomaly_detected"]) |
| elif "detected" in detection_data: |
| detected = bool(detection_data["detected"]) |
| |
| |
| confidence = 0 |
| |
| if detected and isinstance(detection_data, dict) and "confidence" in detection_data: |
| confidence = detection_data["confidence"] |
| elif isinstance(decision_data, dict) and "confidence" in decision_data: |
| confidence = decision_data["confidence"] |
| |
| |
| similar_incidents = 0 |
| if isinstance(recall_data, dict) and "results" in recall_data: |
| if isinstance(recall_data["results"], list): |
| similar_incidents = len(recall_data["results"]) |
| elif "similar_incidents" in recall_data: |
| similar_incidents = recall_data["similar_incidents"] |
| |
| |
| healing_intent_created = False |
| if isinstance(decision_data, dict): |
| |
| healing_intent_created = bool( |
| decision_data.get("healing_intent_created", False) |
| or decision_data.get("action") |
| or decision_data.get("recommended_action") |
| ) |
| |
| |
| recommended_action = "No actionable intelligence found" |
| if isinstance(decision_data, dict): |
| if "action" in decision_data: |
| recommended_action = decision_data["action"] |
| elif "recommended_action" in decision_data: |
| recommended_action = decision_data["recommended_action"] |
| |
| |
| estimated_recovery = "Unknown" |
| |
| |
| |
| |
| |
| |
| |
| detection_status = "active" if detected else "inactive" |
| |
| |
| recall_status = "active" if similar_incidents > 0 else "inactive" |
| |
| |
| decision_status = "active" if healing_intent_created else "inactive" |
| |
| |
| if raw_result.get("status") == "error": |
| detection_status = "error" |
| recall_status = "error" |
| decision_status = "error" |
| |
| |
| |
| |
| |
| result = { |
| "status": raw_result.get("status", "success"), |
| "scenario": raw_result.get("scenario", scenario_name), |
| "arf_version": raw_result.get("arf_version", "3.3.9"), |
| "analysis": { |
| "detected": detected, |
| "confidence": confidence, |
| "similar_incidents": similar_incidents, |
| "healing_intent_created": healing_intent_created, |
| "recommended_action": recommended_action, |
| "estimated_recovery": estimated_recovery |
| }, |
| "agents": { |
| "detection": { |
| "status": detection_status, |
| "confidence": confidence if detection_status == "active" else 0 |
| }, |
| "recall": { |
| "status": recall_status, |
| "similar_incidents": similar_incidents if recall_status == "active" else 0 |
| }, |
| "decision": { |
| "status": decision_status, |
| "healing_intent_created": healing_intent_created if decision_status == "active" else False |
| } |
| }, |
| "boundary_note": raw_result.get("boundary_note", |
| "Real ARF OSS 3.3.9 analysis complete β Ready for Enterprise execution"), |
| "installation": { |
| "oss_installed": True, |
| "version": "3.3.9", |
| "edition": "oss" |
| } |
| } |
| |
| |
| if is_real_oss: |
| result["_original_oss_analysis"] = raw_result.get("oss_analysis") |
| |
| return result |
| |
| |
| |
| |
|
|
| @AsyncRunner.async_to_sync |
| async def run_true_arf_analysis(scenario_name: str) -> tuple: |
| """ |
| DOCTRINALLY PURE VERSION: Adapter transforms ARF OSS output with epistemic honesty |
| 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: |
| |
| orchestrator = components["DemoOrchestrator"]() |
| |
| |
| scenarios = components["INCIDENT_SCENARIOS"] |
| scenario_data = scenarios.get(scenario_name, {}) |
| |
| |
| |
| |
| raw_result = await orchestrator.analyze_incident(scenario_name, scenario_data) |
| |
| |
| |
| |
| transformed_result = transform_arf_output_for_ui(raw_result, scenario_name) |
| |
| |
| |
| |
| |
| get_audit_manager().add_incident(scenario_name, transformed_result) |
| |
| |
| boundary_color = boundaries["oss"]["color"] |
| |
| |
| analysis = transformed_result.get("analysis", {}) |
| agents = transformed_result.get("agents", {}) |
| |
| |
| confidence = analysis.get("confidence", 0) |
| similar_incidents = analysis.get("similar_incidents", 0) |
| detection_agent = agents.get("detection", {}) |
| recall_agent = agents.get("recall", {}) |
| decision_agent = agents.get("decision", {}) |
| |
| |
| detection_status = detection_agent.get("status", "inactive") |
| detection_status_text = detection_status.capitalize() |
| |
| |
| if detection_status == "active": |
| detection_badge = "DETECTED" |
| confidence_text = f"Anomaly detected with {confidence}% confidence" |
| elif detection_status == "inactive": |
| detection_badge = "ANALYZING" |
| confidence_text = "No anomaly signal found" |
| else: |
| detection_badge = "ERROR" |
| confidence_text = "Detection analysis failed" |
| |
| 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 Process</h4> |
| <p style="font-size: 13px; color: #64748b; margin-bottom: 12px; line-height: 1.4;"> |
| {confidence_text} |
| </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: {detection_status_text} |
| </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;"> |
| {detection_badge} |
| </div> |
| </div> |
| </div> |
| """ |
| |
| |
| recall_status = recall_agent.get("status", "inactive") |
| recall_status_text = recall_status.capitalize() |
| |
| |
| if recall_status == "active": |
| recall_badge = "RECALLED" |
| recall_text = f"Found {similar_incidents} similar incident{'s' if similar_incidents != 1 else ''}" |
| elif recall_status == "inactive": |
| recall_badge = "SEARCHING" |
| recall_text = "No similar incidents found" |
| else: |
| recall_badge = "ERROR" |
| recall_text = "Recall analysis failed" |
| |
| 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 Process</h4> |
| <p style="font-size: 13px; color: #64748b; margin-bottom: 12px; line-height: 1.4;"> |
| {recall_text} |
| </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: {recall_status_text} |
| </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;"> |
| {recall_badge} |
| </div> |
| </div> |
| </div> |
| """ |
| |
| |
| decision_status = decision_agent.get("status", "inactive") |
| decision_status_text = decision_status.capitalize() |
| |
| |
| if decision_status == "active": |
| decision_badge = "DECIDED" |
| decision_text = analysis.get('recommended_action', 'Action recommended') |
| elif decision_status == "inactive": |
| decision_badge = "EVALUATING" |
| decision_text = "No action recommended" |
| else: |
| decision_badge = "ERROR" |
| decision_text = "Decision analysis failed" |
| |
| 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 Process</h4> |
| <p style="font-size: 13px; color: #64748b; margin-bottom: 12px; line-height: 1.4;"> |
| {decision_text} |
| </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: {decision_status_text} |
| </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;"> |
| {decision_badge} |
| </div> |
| </div> |
| </div> |
| """ |
| |
| |
| oss_results_dict = transformed_result |
| |
| |
| incident_df = get_audit_manager().get_incident_dataframe() |
| |
| logger.info(f"β
True ARF analysis complete for {scenario_name}") |
| logger.info(f" Detection: {'ACTIVE' if detection_status == 'active' else 'INACTIVE'} (confidence: {confidence})") |
| logger.info(f" Recall: {'ACTIVE' if recall_status == 'active' else 'INACTIVE'} (incidents: {similar_incidents})") |
| logger.info(f" Decision: {'ACTIVE' if decision_status == 'active' else 'INACTIVE'}") |
| |
| return detection_html, recall_html, decision_html, oss_results_dict, incident_df |
| |
| except Exception as e: |
| logger.error(f"True ARF analysis failed: {e}") |
| |
| |
| 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", |
| "analysis": { |
| "detected": False, |
| "confidence": 0, |
| "similar_incidents": 0, |
| "healing_intent_created": False, |
| "recommended_action": "Check ARF installation", |
| "estimated_recovery": "Unknown" |
| }, |
| "agents": { |
| "detection": {"status": "error", "confidence": 0}, |
| "recall": {"status": "error", "similar_incidents": 0}, |
| "decision": {"status": "error", "healing_intent_created": False} |
| } |
| } |
| |
| |
| 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 |
|
|
| |
| |
| |
| 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...") |
| |
| |
| import gradio as gr |
| components["gr"] = gr |
| |
| |
| from ui.styles import get_styles |
| components["get_styles"] = get_styles |
| |
| |
| 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 |
| ) |
| |
| 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 |
| }) |
| |
| |
| from demo.scenarios import INCIDENT_SCENARIOS |
| components["INCIDENT_SCENARIOS"] = INCIDENT_SCENARIOS |
| |
| |
| try: |
| from core.true_arf_orchestrator import TrueARFOrchestrator |
| components["DemoOrchestrator"] = TrueARFOrchestrator |
| except ImportError: |
| |
| try: |
| from core.true_arf_orchestrator import TrueARF337Orchestrator |
| components["DemoOrchestrator"] = TrueARF337Orchestrator |
| logger.warning("β οΈ Using TrueARF337Orchestrator - rename to TrueARFOrchestrator for version consistency") |
| except ImportError: |
| |
| try: |
| from core.real_arf_integration import RealARFIntegration |
| components["DemoOrchestrator"] = RealARFIntegration |
| except ImportError: |
| |
| 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 |
| |
| |
| try: |
| from core.calculators import EnhancedROICalculator |
| components["EnhancedROICalculator"] = EnhancedROICalculator() |
| logger.info("β
Real EnhancedROICalculator loaded") |
| except ImportError: |
| |
| 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 |
| |
| |
| 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: |
| 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 |
| |
| |
| 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" |
| } |
| } |
| |
| |
| 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() |
| |
| |
| 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 |
|
|
| |
| |
| |
| 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] |
| |
| |
| 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 pd.DataFrame(columns=[ |
| "Execution ID", "Scenario", "Status", "Mode", |
| "Start Time", "End Time", "Duration", "Boundary" |
| ]) |
| |
| |
| data = [] |
| for i, execution in enumerate(self.executions): |
| try: |
| |
| result = execution.get("result", {}) |
| |
| |
| exec_id = result.get("execution_id", f"exec_{i:03d}") |
| |
| |
| 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: |
| |
| if result.get("error"): |
| status_text = "Failed" |
| else: |
| status_text = "Success" |
| |
| |
| mode = execution.get("mode", "unknown") |
| |
| |
| scenario = execution.get("scenario", "Unknown") |
| |
| |
| timestamp = execution.get("timestamp", "") |
| start_time = "" |
| if timestamp and len(timestamp) > 10: |
| try: |
| |
| start_time = timestamp[:19] |
| except Exception: |
| start_time = timestamp |
| |
| |
| 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 |
| |
| |
| duration = "12m" |
| if telemetry and "estimated_duration" in telemetry: |
| duration = telemetry.get("estimated_duration", "12m") |
| |
| |
| 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}") |
| |
| 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" |
| ]) |
| |
| |
| df = pd.DataFrame(data) |
| |
| |
| if not df.empty and "Start Time" in df.columns: |
| |
| valid_times = df["Start Time"].apply( |
| lambda x: isinstance(x, str) and len(x) > 0 and x != "None" |
| ) |
| |
| if valid_times.any(): |
| try: |
| |
| df = df.sort_values("Start Time", ascending=False) |
| except Exception as sort_error: |
| logger.warning(f"Could not sort DataFrame: {sort_error}") |
| |
| 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}") |
| |
| 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 pd.DataFrame(columns=[ |
| "Scenario", "Status", "Boundary", "Time", |
| "Confidence", "Action", "Target" |
| ]) |
| |
| |
| data = [] |
| for i, incident in enumerate(self.incidents): |
| try: |
| |
| scenario = incident.get("scenario", "Unknown") |
| boundary = incident.get("boundary_context", "OSS analysis") |
| |
| |
| analysis = incident.get("analysis", {}) |
| |
| |
| status = "Analyzed" |
| if isinstance(analysis, dict): |
| analysis_status = analysis.get("status", "").lower() |
| if analysis_status: |
| status = analysis_status.capitalize() |
| else: |
| |
| if analysis.get("error"): |
| status = "Error" |
| elif analysis.get("analysis") or analysis.get("oss_analysis"): |
| status = "Success" |
| |
| |
| timestamp = incident.get("timestamp", "") |
| time_display = "" |
| if timestamp and len(timestamp) > 10: |
| try: |
| |
| time_display = timestamp[11:19] |
| except Exception: |
| time_display = timestamp[:8] if len(timestamp) >= 8 else timestamp |
| |
| |
| confidence = 0.85 |
| action = "Analysis" |
| target = "system" |
| |
| |
| healing_intent = None |
| |
| |
| 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", {}) |
| |
| |
| if not healing_intent and isinstance(analysis.get("analysis", {}), dict): |
| healing_intent = analysis["analysis"].get("decision", {}) |
| |
| |
| 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") |
| |
| |
| confidence_display = f"{confidence * 100:.1f}%" |
| |
| data.append({ |
| "Scenario": scenario, |
| "Status": status, |
| "Boundary": boundary, |
| "Time": time_display, |
| "Confidence": confidence_display, |
| "Action": action[:50], |
| "Target": target[:30] |
| }) |
| |
| except Exception as row_error: |
| logger.warning(f"Error processing incident row {i}: {row_error}") |
| |
| 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" |
| ]) |
| |
| |
| df = pd.DataFrame(data) |
| |
| |
| if not df.empty and "Time" in df.columns: |
| |
| valid_times = df["Time"].apply( |
| lambda x: isinstance(x, str) and len(x) > 0 and x != "None" |
| ) |
| |
| if valid_times.any(): |
| try: |
| |
| df = df.sort_values("Time", ascending=False) |
| except Exception as sort_error: |
| logger.warning(f"Could not sort incident DataFrame: {sort_error}") |
| |
| 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}") |
| |
| 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 |
|
|
| |
| |
| |
| 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 |
|
|
| |
| |
| |
| 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" |
| }) |
| |
| |
| if get_feature_flags().get('modern_ui', False) and MODERN_UI_AVAILABLE: |
| |
| scenario_card_html = Card.create( |
| title=scenario_name, |
| content=f""" |
| <div style="margin: 15px 0;"> |
| <div style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;"> |
| <div style="padding: 4px 12px; background: var(--color-primary); color: white; |
| border-radius: 12px; font-size: 12px; font-weight: bold;"> |
| {scenario["severity"]} SEVERITY |
| </div> |
| <div style="font-size: 13px; color: var(--text-secondary);"> |
| {scenario["component"]} |
| </div> |
| </div> |
| |
| <div style="font-size: 14px; color: var(--text-secondary); line-height: 1.5;"> |
| <strong>Boundary Context:</strong> {scenario.get('boundary_note', 'OSS analyzes, Enterprise executes')} |
| </div> |
| </div> |
| """, |
| footer=f"Revenue Impact: ${scenario['business_impact'].get('revenue_loss_per_hour', get_scenario_impact(scenario_name)):,}/hour" |
| ) |
| else: |
| |
| 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> |
| """ |
| |
| |
| 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) |
| |
| |
| try: |
| |
| realism_html = components["create_realism_panel"](scenario, scenario_name) |
| except (ImportError, KeyError): |
| |
| 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") |
| |
| |
| return scenario_card_html, telemetry_fig, impact_fig, timeline_fig, realism_html |
|
|
| |
| |
| |
|
|
| def update_scenario_display_with_metrics(scenario_name: str) -> tuple: |
| """Combined update function - doctrinally compliant""" |
| |
| scenario_card, telemetry_fig, impact_fig, timeline_fig, _ = update_scenario_display(scenario_name) |
| |
| |
| components = get_components() |
| detection_time, recall_quality, confidence_score, sequencing_stage = components["update_performance_metrics"](scenario_name) |
| |
| return (scenario_card, telemetry_fig, impact_fig, timeline_fig, |
| detection_time, recall_quality, confidence_score, sequencing_stage) |
|
|
| |
| |
| |
| 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}") |
| |
| |
| is_real_enterprise = installation["enterprise_installed"] |
| is_simulated = not is_real_enterprise |
| |
| |
| 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) |
| |
| |
| 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> |
| """ |
| |
| |
| @AsyncRunner.async_to_sync |
| async def execute_async(): |
| try: |
| orchestrator = components["DemoOrchestrator"]() |
| execution_result = await orchestrator.execute_healing(scenario_name, "autonomous") |
| |
| |
| 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() |
| |
| |
| 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)" |
| ] |
| } |
| |
| |
| execution_df = get_audit_manager().get_execution_dataframe() |
| |
| return approval_display, enterprise_results, execution_df |
|
|
| |
| |
| |
| 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: |
| |
| 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}") |
| |
| 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" |
| } |
| |
| |
| 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 roi_result, fig |
|
|
| |
| |
| |
| def create_demo_interface(): |
| """Create demo interface using modular components with boundary awareness and modern UI""" |
| |
| import gradio as gr |
| |
| |
| components = get_components() |
| |
| |
| css_styles = load_css_files() |
| |
| |
| global _demo_css |
| _demo_css = css_styles |
| |
| |
| with gr.Blocks( |
| title=f"π ARF Investor Demo v3.3.9 - TRUE ARF OSS Integration", |
| css=css_styles |
| ) as demo: |
| |
| |
| if get_feature_flags().get('modern_ui', False) and MODERN_UI_AVAILABLE: |
| modern_ui_init = gr.HTML(initialize_modern_ui()) |
| logger.info("β
Modern UI initialized") |
| else: |
| modern_ui_init = gr.HTML("<!-- Modern UI not enabled -->") |
| |
| |
| header_html = components["create_header"]("3.3.9") |
| |
| |
| status_html = components["create_status_bar"]() |
| |
| |
| |
| with gr.Tabs(elem_classes="tab-nav"): |
| |
| |
| with gr.TabItem("π₯ Live Incident Demo", id="tab1"): |
| |
| try: |
| logger.info("π§ Extracting Tab1 components with safe unpacking...") |
| |
| |
| tab1_result = components["create_tab1_incident_demo"]() |
| |
| |
| logger.info(f"π Tab1 result type: {type(tab1_result)}") |
| if hasattr(tab1_result, '__len__'): |
| logger.info(f"π Tab1 result length: {len(tab1_result)}") |
| for i, item in enumerate(tab1_result): |
| item_type = type(item).__name__ if hasattr(item, '__name__') else type(item) |
| logger.debug(f" Index {i}: {item_type}") |
| |
| |
| |
| scenario_dropdown = tab1_result[0] |
| historical_panel = tab1_result[1] |
| scenario_card = tab1_result[2] |
| telemetry_viz = tab1_result[3] |
| impact_viz = tab1_result[4] |
| observation_gate_placeholder = tab1_result[5] |
| sequencing_panel = tab1_result[6] |
| workflow_header = tab1_result[7] |
| detection_process = tab1_result[8] |
| recall_process = tab1_result[9] |
| decision_process = tab1_result[10] |
| oss_section = tab1_result[11] |
| enterprise_section = tab1_result[12] |
| oss_btn = tab1_result[13] |
| enterprise_btn = tab1_result[14] |
| approval_toggle = tab1_result[15] |
| mcp_mode = tab1_result[16] |
| timeline_viz = tab1_result[17] |
| detection_time = tab1_result[18] |
| recall_quality = tab1_result[19] |
| confidence_score = tab1_result[20] |
| sequencing_stage = tab1_result[21] |
| oss_results_display = tab1_result[22] |
| enterprise_results_display = tab1_result[23] |
| approval_display = tab1_result[24] |
| demo_btn = tab1_result[25] |
| |
| logger.info("β
Tab1 components successfully extracted with correct contract") |
| |
| except Exception as e: |
| logger.error(f"β Tab1 component extraction failed: {e}") |
| logger.error("π Creating fallback components to maintain system integrity...") |
| |
| |
| import gradio as gr |
| |
| |
| scenario_dropdown = gr.Dropdown(choices=["Error Mode"], value="Error Mode") |
| historical_panel = gr.DataFrame(value=[["System in recovery mode"]]) |
| scenario_card = gr.Markdown("### System Initialization Issue") |
| telemetry_viz = gr.Plot() |
| impact_viz = gr.Plot() |
| observation_gate_placeholder = gr.Markdown("**Observation Gate:** System integrity check") |
| sequencing_panel = gr.Markdown("**Sequencing:** Initializing...") |
| workflow_header = gr.Markdown("### Policy Recovery Mode") |
| detection_process = gr.Textbox(value="DETECTION: ERROR") |
| recall_process = gr.Textbox(value="RECALL: ERROR") |
| decision_process = gr.Textbox(value="DECISION: ERROR") |
| oss_section = gr.Markdown("#### OSS: Unavailable") |
| enterprise_section = gr.Markdown("#### Enterprise: Unavailable") |
| oss_btn = gr.Button("Unavailable", variant="secondary") |
| enterprise_btn = gr.Button("Unavailable", variant="secondary") |
| approval_toggle = gr.Checkbox(label="Approval: Error", value=False) |
| mcp_mode = gr.Radio(choices=["Error"], value="Error") |
| timeline_viz = gr.Plot() |
| detection_time = gr.Number(value=0) |
| recall_quality = gr.Number(value=0) |
| confidence_score = gr.Number(value=0) |
| sequencing_stage = gr.Textbox(value="Error") |
| oss_results_display = gr.Markdown("### Results: Unavailable") |
| enterprise_results_display = gr.Markdown("### Results: Unavailable") |
| approval_display = gr.Markdown("**Status:** System recovery in progress") |
| demo_btn = gr.Button("π System Recovery Required", variant="secondary", size="lg") |
| |
| logger.warning("β οΈ Using fallback components - full functionality limited") |
| |
| |
| |
| 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"]) |
| |
| |
| 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"]() |
| |
| |
| 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"]() |
| |
| |
| 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_html = components["create_footer"]() |
| |
| |
| |
| |
| scenario_dropdown.change( |
| fn=update_scenario_display_with_metrics, |
| inputs=[scenario_dropdown], |
| outputs=[ |
| scenario_card, telemetry_viz, impact_viz, timeline_viz, |
| detection_time, recall_quality, confidence_score, sequencing_stage |
| ] |
| ) |
| |
| |
| |
| |
| def run_oss_analysis_real_arf(scenario_name: str) -> tuple: |
| """ |
| Simple passthrough to run_true_arf_analysis() |
| The decorator now handles contract preservation |
| """ |
| logger.info(f"π Running TRUE ARF OSS analysis for: {scenario_name}") |
| return run_true_arf_analysis(scenario_name) |
| |
| |
| oss_btn.click( |
| fn=run_oss_analysis_real_arf, |
| inputs=[scenario_dropdown], |
| outputs=[ |
| detection_process, recall_process, decision_process, |
| oss_results_display, incident_table |
| ] |
| ) |
| |
| |
| enterprise_btn.click( |
| fn=execute_enterprise_healing, |
| inputs=[scenario_dropdown, approval_toggle, mcp_mode], |
| outputs=[approval_display, enterprise_results_display, execution_table] |
| ) |
| |
| |
| @AsyncRunner.async_to_sync |
| async def run_complete_demo_async(scenario_name): |
| """Run a complete demo walkthrough with true ARF and boundary awareness""" |
| |
| update_result = update_scenario_display_with_metrics(scenario_name) |
| |
| |
| oss_result = run_oss_analysis_real_arf(scenario_name) |
| |
| |
| 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) |
| |
| |
| boundaries = BoundaryManager.get_system_boundaries() |
| |
| |
| 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" |
| } |
| |
| |
| 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> |
| """ |
| |
| |
| enterprise_results["demo_completion_message"] = demo_message |
| |
| |
| incident_df = get_audit_manager().get_incident_dataframe() |
| execution_df = get_audit_manager().get_execution_dataframe() |
| |
| |
| return ( |
| *update_result, |
| *oss_result[:3], |
| oss_result[3], |
| enterprise_results, |
| demo_message, |
| incident_df, |
| execution_df |
| ) |
| |
| |
| demo_btn.click( |
| fn=run_complete_demo_async, |
| inputs=[scenario_dropdown], |
| outputs=[ |
| scenario_card, telemetry_viz, impact_viz, timeline_viz, |
| detection_time, recall_quality, confidence_score, sequencing_stage, |
| detection_process, recall_process, decision_process, |
| oss_results_display, |
| enterprise_results_display, |
| approval_display, |
| incident_table, |
| execution_table |
| ] |
| ) |
| |
| |
| calculate_btn.click( |
| fn=calculate_roi, |
| inputs=[roi_scenario_dropdown, monthly_slider, team_slider], |
| outputs=[roi_output, roi_chart] |
| ) |
| |
| |
| roi_scenario_dropdown.change( |
| fn=lambda x: get_components()["EnhancedROICalculator"].calculate_comprehensive_roi(scenario_name=x), |
| inputs=[roi_scenario_dropdown], |
| outputs=[roi_output] |
| ) |
| |
| |
| 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] |
| ) |
| |
| |
| def refresh_audit_trail(): |
| """Refresh audit trail tables - FIXED to return DataFrames""" |
| return ( |
| get_audit_manager().get_execution_dataframe(), |
| get_audit_manager().get_incident_dataframe() |
| ) |
| |
| def clear_audit_trail(): |
| """Clear audit trail - FIXED to return empty DataFrames""" |
| get_audit_manager().clear() |
| |
| 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] |
| ) |
| |
| |
| 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] |
| ) |
| |
| |
| demo.load( |
| fn=lambda: update_scenario_display_with_metrics(settings.default_scenario), |
| inputs=[], |
| outputs=[ |
| scenario_card, telemetry_viz, impact_viz, timeline_viz, |
| detection_time, recall_quality, confidence_score, sequencing_stage |
| ] |
| ) |
| |
| |
| demo.load( |
| fn=lambda: calculate_roi(settings.default_scenario, 15, 5), |
| inputs=[], |
| outputs=[roi_output, roi_chart] |
| ) |
| |
| logger.info("β
Demo interface created successfully with modern UI integration") |
| |
| return demo |
| |
| |
| |
| def launch_demo(): |
| """Launch the demo application with proper configuration""" |
| try: |
| logger.info("π Starting ARF Ultimate Investor Demo v3.3.9 - ENTERPRISE EDITION") |
| |
| |
| 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(f" Modern UI: {'Enabled' if get_feature_flags().get('modern_ui', False) else 'Disabled'}") |
| logger.info("=" * 60) |
| |
| |
| demo = create_demo_interface() |
| |
| |
| 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, |
| } |
| |
| |
| css_styles = load_css_files() |
| 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) |
| |
| |
| 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} |
|
|
| |
| |
| |
| 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("DOCTRINAL COMPLIANCE: Historical Evidence, Observation Gate, Sequencing") |
| logger.info("PHASE 2: Dynamic Performance Metrics by Scenario") |
| logger.info(f"Modern UI: {'Enabled' if get_feature_flags().get('modern_ui', False) else 'Disabled'}") |
| logger.info(f"True ARF OSS v3.3.9 integration with simulated Enterprise execution") |
| logger.info("=" * 60) |
| |
| |
| demo, config = launch_demo() |
| |
| print("\n" + "="*60) |
| print("π ARF Ultimate Investor Demo v3.3.9 - ENTERPRISE EDITION") |
| print("π Architecture: OSS advises β Enterprise executes") |
| print("π DOCTRINAL: Historical Evidence + Observation Gate + Sequencing") |
| print("π¨ MODERN UI: Design system with responsive components") |
| print("π Starting on http://localhost:7860") |
| print("="*60 + "\n") |
| |
| |
| try: |
| demo.launch(**config) |
| except Exception as launch_error: |
| logger.error(f"β Launch error: {launch_error}") |
| |
| |
| if "css" in config: |
| logger.info("β οΈ Retrying without CSS...") |
| config.pop("css", None) |
| demo.launch(**config) |
| else: |
| |
| 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) |