petter2025 commited on
Commit
bd96870
·
verified ·
1 Parent(s): 077a552

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +218 -165
app.py CHANGED
@@ -30,35 +30,41 @@ logger = logging.getLogger(__name__)
30
  # Add parent directory to path
31
  sys.path.insert(0, str(Path(__file__).parent))
32
 
33
- # Import async utilities FIRST
34
- try:
35
- from utils.async_runner import AsyncRunner, async_to_sync
36
- ASYNC_UTILS_AVAILABLE = True
37
- except ImportError as e:
38
- logger.error(f"Failed to import async utilities: {e}")
39
- ASYNC_UTILS_AVAILABLE = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
 
41
- # Import settings
42
- try:
43
- from config.settings import settings
44
- SETTINGS_AVAILABLE = True
45
- except ImportError as e:
46
- logger.error(f"Failed to import settings: {e}")
47
- SETTINGS_AVAILABLE = False
48
- # Create minimal settings
49
- class Settings:
50
- arf_mode = "demo"
51
- use_mock_arf = True
52
- default_scenario = "Cache Miss Storm"
53
- settings = Settings()
54
 
55
- # Import scenario registry
56
- try:
57
- from config.scenario_registry import ScenarioRegistry
58
- SCENARIO_REGISTRY_AVAILABLE = True
59
- except ImportError as e:
60
- logger.error(f"Failed to import scenario registry: {e}")
61
- SCENARIO_REGISTRY_AVAILABLE = False
62
 
63
  # ===========================================
64
  # IMPORT MODULAR COMPONENTS - SAFE IMPORTS
@@ -66,42 +72,119 @@ except ImportError as e:
66
  def import_components():
67
  """Safely import all components with proper error handling"""
68
  try:
69
- # Import scenarios from registry
70
- if SCENARIO_REGISTRY_AVAILABLE:
71
- INCIDENT_SCENARIOS = ScenarioRegistry.load_scenarios()
72
- else:
73
  from demo.scenarios import INCIDENT_SCENARIOS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
74
 
75
  # Import orchestrator
76
- from demo.orchestrator import DemoOrchestrator
 
 
 
 
 
 
77
 
78
- # Import ROI calculator
79
  try:
80
  from core.calculators import EnhancedROICalculator
81
  roi_calculator_available = True
 
82
  except ImportError as e:
83
  logger.warning(f"EnhancedROICalculator not available: {e}")
84
- from core.calculators import EnhancedROICalculator
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  roi_calculator_available = True
86
 
87
- # Import visualizations
88
  try:
89
  from core.visualizations import EnhancedVisualizationEngine
90
  viz_engine_available = True
 
91
  except ImportError as e:
92
  logger.warning(f"EnhancedVisualizationEngine not available: {e}")
93
- from core.visualizations import EnhancedVisualizationEngine
 
 
 
 
 
 
94
  viz_engine_available = True
95
 
96
  # Import UI components
97
- from ui.components import (
98
- create_header, create_status_bar, create_tab1_incident_demo,
99
- create_tab2_business_roi, create_tab3_enterprise_features,
100
- create_tab4_audit_trail, create_tab5_learning_engine,
101
- create_footer
102
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
- # Import styles
105
  try:
106
  from ui.styles import get_styles
107
  styles_available = True
@@ -115,8 +198,8 @@ def import_components():
115
  return {
116
  "INCIDENT_SCENARIOS": INCIDENT_SCENARIOS,
117
  "DemoOrchestrator": DemoOrchestrator,
118
- "EnhancedROICalculator": EnhancedROICalculator if roi_calculator_available else None,
119
- "EnhancedVisualizationEngine": EnhancedVisualizationEngine if viz_engine_available else None,
120
  "create_header": create_header,
121
  "create_status_bar": create_status_bar,
122
  "create_tab1_incident_demo": create_tab1_incident_demo,
@@ -129,50 +212,58 @@ def import_components():
129
  "all_available": True
130
  }
131
 
132
- except ImportError as e:
133
  logger.error(f"❌ CRITICAL IMPORT ERROR: {e}")
134
  logger.error(traceback.format_exc())
135
- return {"all_available": False, "error": str(e)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
  # Import components safely
138
  components = import_components()
139
 
140
- if not components.get("all_available", False):
141
- logger.error("Failed to import required components, starting with minimal functionality")
142
-
143
- import gradio as gr
144
-
145
- # Minimal fallback components
146
- INCIDENT_SCENARIOS = {
147
- "Cache Miss Storm": {
148
- "component": "Redis Cache Cluster",
149
- "severity": "HIGH",
150
- "impact_radius": "85% of users",
151
- "business_impact": {"revenue_loss_per_hour": 8500},
152
- "detection_time": "45 seconds",
153
- "tags": ["cache", "redis", "latency"]
154
- }
155
- }
156
-
157
- class DemoOrchestrator:
158
- async def analyze_incident(self, name, scenario):
159
- return {"status": "Mock analysis"}
160
-
161
- components = {
162
- "INCIDENT_SCENARIOS": INCIDENT_SCENARIOS,
163
- "DemoOrchestrator": DemoOrchestrator(),
164
- "create_header": lambda version, mock: gr.HTML(f"<h2>🚀 ARF v{version}</h2>"),
165
- "create_status_bar": lambda: gr.HTML("<div>Status</div>"),
166
- "create_tab1_incident_demo": lambda *args: [gr.Dropdown()] * 24,
167
- "create_tab2_business_roi": lambda *args: [gr.Plot()] * 7,
168
- "create_tab3_enterprise_features": lambda: [gr.JSON()] * 8,
169
- "create_tab4_audit_trail": lambda: [gr.Button()] * 6,
170
- "create_tab5_learning_engine": lambda: [gr.Plot()] * 10,
171
- "create_footer": lambda: gr.HTML("<footer>ARF</footer>"),
172
- "get_styles": lambda: "",
173
- "all_available": True
174
- }
175
-
176
  # Extract components
177
  INCIDENT_SCENARIOS = components["INCIDENT_SCENARIOS"]
178
  DemoOrchestrator = components["DemoOrchestrator"]
@@ -192,12 +283,11 @@ get_styles = components["get_styles"]
192
  # AUDIT TRAIL MANAGER - ENHANCED
193
  # ===========================================
194
  class AuditTrailManager:
195
- """Enhanced audit trail manager with persistence"""
196
 
197
  def __init__(self):
198
  self.executions = []
199
  self.incidents = []
200
- self._max_history = settings.max_history_items if SETTINGS_AVAILABLE else 100
201
 
202
  def add_execution(self, scenario: str, mode: str, success: bool = True, savings: float = 0) -> Dict:
203
  """Add execution to audit trail"""
@@ -210,12 +300,6 @@ class AuditTrailManager:
210
  "details": f"{mode} execution at {datetime.datetime.now().isoformat()}"
211
  }
212
  self.executions.insert(0, entry)
213
-
214
- # Limit history
215
- if len(self.executions) > self._max_history:
216
- self.executions = self.executions[:self._max_history]
217
-
218
- logger.info(f"Added execution: {scenario} ({mode})")
219
  return entry
220
 
221
  def add_incident(self, scenario: str, severity: str = "HIGH") -> Dict:
@@ -228,12 +312,6 @@ class AuditTrailManager:
228
  "status": "Analyzed"
229
  }
230
  self.incidents.insert(0, entry)
231
-
232
- # Limit history
233
- if len(self.incidents) > self._max_history:
234
- self.incidents = self.incidents[:self._max_history]
235
-
236
- logger.info(f"Added incident: {scenario} ({severity})")
237
  return entry
238
 
239
  def get_execution_table(self) -> List[List]:
@@ -250,34 +328,10 @@ class AuditTrailManager:
250
  for e in self.incidents[:15]
251
  ]
252
 
253
- def get_total_savings(self) -> float:
254
- """Calculate total savings"""
255
- total = 0
256
- for e in self.executions:
257
- try:
258
- # Extract numeric value from savings string
259
- savings_str = e["savings"].replace("$", "").replace(",", "")
260
- total += float(savings_str)
261
- except (ValueError, AttributeError):
262
- continue
263
- return total
264
-
265
  def clear(self) -> None:
266
  """Clear audit trail"""
267
  self.executions = []
268
  self.incidents = []
269
- logger.info("Audit trail cleared")
270
-
271
-
272
- # ===========================================
273
- # ARF ADAPTER INTEGRATION
274
- # ===========================================
275
- try:
276
- from core.arf_adapter import get_arf_adapter
277
- ARF_ADAPTER_AVAILABLE = True
278
- except ImportError:
279
- ARF_ADAPTER_AVAILABLE = False
280
- logger.warning("ARF adapter not available, using direct mock imports")
281
 
282
  # ===========================================
283
  # HELPER FUNCTIONS
@@ -294,7 +348,6 @@ def get_scenario_impact(scenario_name: str) -> float:
294
  }
295
  return impact_map.get(scenario_name, 5000)
296
 
297
-
298
  def extract_roi_multiplier(roi_result: Dict) -> float:
299
  """Extract ROI multiplier from EnhancedROICalculator result"""
300
  try:
@@ -324,7 +377,6 @@ def extract_roi_multiplier(roi_result: Dict) -> float:
324
  logger.warning(f"Failed to extract ROI multiplier: {e}, using default 5.2")
325
  return 5.2
326
 
327
-
328
  # ===========================================
329
  # VISUALIZATION HELPERS
330
  # ===========================================
@@ -417,7 +469,6 @@ def create_telemetry_plot(scenario_name: str):
417
 
418
  return fig
419
 
420
-
421
  def create_impact_plot(scenario_name: str):
422
  """Create a business impact visualization"""
423
  import plotly.graph_objects as go
@@ -464,7 +515,6 @@ def create_impact_plot(scenario_name: str):
464
 
465
  return fig
466
 
467
-
468
  def create_timeline_plot(scenario_name: str):
469
  """Create an incident timeline visualization"""
470
  import plotly.graph_objects as go
@@ -510,46 +560,44 @@ def create_timeline_plot(scenario_name: str):
510
 
511
  return fig
512
 
513
-
514
  # ===========================================
515
- # SCENARIO UPDATE HANDLER - ASYNC FIXED
516
  # ===========================================
517
- @async_to_sync
518
- async def update_scenario_display(scenario_name: str) -> tuple:
519
- """Update all scenario-related displays - ASYNC VERSION"""
520
  scenario = INCIDENT_SCENARIOS.get(scenario_name, {})
521
  impact = scenario.get("business_impact", {})
522
  metrics = scenario.get("metrics", {})
523
 
524
  # Create scenario card HTML
525
  scenario_html = f"""
526
- <div class="scenario-card">
527
- <div class="scenario-header">
528
- <h3>🚨 {scenario_name}</h3>
529
- <span class="severity-badge {scenario.get('severity', 'HIGH').lower()}">{scenario.get('severity', 'HIGH')}</span>
530
  </div>
531
- <div class="scenario-details">
532
- <div class="scenario-detail-row">
533
- <span class="detail-label">Component:</span>
534
- <span class="detail-value">{scenario.get('component', 'Unknown').replace('_', ' ').title()}</span>
535
  </div>
536
- <div class="scenario-detail-row">
537
- <span class="detail-label">Affected Users:</span>
538
- <span class="detail-value">{metrics.get('affected_users', 'Unknown') if 'affected_users' in metrics else 'Unknown'}</span>
539
  </div>
540
- <div class="scenario-detail-row">
541
- <span class="detail-label">Revenue Risk:</span>
542
- <span class="detail-value revenue-risk">${impact.get('revenue_loss_per_hour', 0):,}/hour</span>
543
  </div>
544
- <div class="scenario-detail-row">
545
- <span class="detail-label">Detection Time:</span>
546
- <span class="detail-value">45 seconds (ARF AI)</span>
547
  </div>
548
- <div class="scenario-tags">
549
- <span class="scenario-tag">{scenario.get('component', 'unknown').split('_')[0]}</span>
550
- <span class="scenario-tag">{scenario.get('severity', 'high').lower()}</span>
551
- <span class="scenario-tag">production</span>
552
- <span class="scenario-tag">incident</span>
553
  </div>
554
  </div>
555
  </div>
@@ -567,13 +615,12 @@ async def update_scenario_display(scenario_name: str) -> tuple:
567
  timeline_plot
568
  )
569
 
570
-
571
  # ===========================================
572
- # OSS ANALYSIS HANDLER - ASYNC FIXED
573
  # ===========================================
574
- @async_to_sync
575
  async def run_oss_analysis(scenario_name: str):
576
- """Run OSS analysis - ASYNC VERSION"""
577
  scenario = INCIDENT_SCENARIOS.get(scenario_name, {})
578
 
579
  # Use orchestrator
@@ -664,7 +711,6 @@ async def run_oss_analysis(scenario_name: str):
664
  oss_results, incident_table_data
665
  )
666
 
667
-
668
  # ===========================================
669
  # CREATE DEMO INTERFACE
670
  # ===========================================
@@ -674,10 +720,9 @@ def create_demo_interface():
674
  import gradio as gr
675
 
676
  # Initialize components
677
- viz_engine = EnhancedVisualizationEngine()
678
- roi_calculator = EnhancedROICalculator()
679
  audit_manager = AuditTrailManager()
680
- orchestrator = DemoOrchestrator()
681
 
682
  # Get CSS styles
683
  css_styles = get_styles()
@@ -844,11 +889,11 @@ def create_demo_interface():
844
  )
845
 
846
  # Run Complete Demo
847
- @async_to_sync
848
  async def run_complete_demo_async(scenario_name):
849
- """Run a complete demo walkthrough - ASYNC"""
850
  # Step 1: Update scenario
851
- update_result = await update_scenario_display(scenario_name)
852
 
853
  # Step 2: Run OSS analysis
854
  oss_result = await run_oss_analysis(scenario_name)
@@ -1042,7 +1087,15 @@ def create_demo_interface():
1042
 
1043
  def export_audit_trail():
1044
  try:
1045
- total_savings = audit_manager.get_total_savings()
 
 
 
 
 
 
 
 
1046
 
1047
  audit_data = {
1048
  "exported_at": datetime.datetime.now().isoformat(),
@@ -1052,7 +1105,7 @@ def create_demo_interface():
1052
  "total_executions": len(audit_manager.executions),
1053
  "total_incidents": len(audit_manager.incidents),
1054
  "total_savings": f"${total_savings:,}",
1055
- "success_rate": "100%" # Simplified
1056
  }
1057
  }
1058
  return json.dumps(audit_data, indent=2)
 
30
  # Add parent directory to path
31
  sys.path.insert(0, str(Path(__file__).parent))
32
 
33
+ # ===========================================
34
+ # ASYNC UTILITIES
35
+ # ===========================================
36
+ class AsyncRunner:
37
+ """Simple async runner for sync context"""
38
+ @staticmethod
39
+ def run_async(coro):
40
+ """Run async coroutine in sync context"""
41
+ try:
42
+ loop = asyncio.get_event_loop()
43
+ except RuntimeError:
44
+ loop = asyncio.new_event_loop()
45
+ asyncio.set_event_loop(loop)
46
+ return loop.run_until_complete(coro)
47
+
48
+ @staticmethod
49
+ def async_to_sync(async_func):
50
+ """Decorator to convert async function to sync"""
51
+ def wrapper(*args, **kwargs):
52
+ return AsyncRunner.run_async(async_func(*args, **kwargs))
53
+ return wrapper
54
 
55
+ # ===========================================
56
+ # SIMPLE SETTINGS (No pydantic dependency)
57
+ # ===========================================
58
+ class Settings:
59
+ """Simple settings class without external dependencies"""
60
+ def __init__(self):
61
+ self.arf_mode = "demo"
62
+ self.use_mock_arf = True
63
+ self.default_scenario = "Cache Miss Storm"
64
+ self.max_history_items = 100
65
+ self.auto_refresh_seconds = 30
 
 
66
 
67
+ settings = Settings()
 
 
 
 
 
 
68
 
69
  # ===========================================
70
  # IMPORT MODULAR COMPONENTS - SAFE IMPORTS
 
72
  def import_components():
73
  """Safely import all components with proper error handling"""
74
  try:
75
+ # Import scenarios - try demo module first
76
+ try:
 
 
77
  from demo.scenarios import INCIDENT_SCENARIOS
78
+ logger.info(f"Loaded {len(INCIDENT_SCENARIOS)} scenarios from demo module")
79
+ except ImportError as e:
80
+ logger.warning(f"Demo scenarios not available: {e}")
81
+ # Create minimal fallback
82
+ INCIDENT_SCENARIOS = {
83
+ "Cache Miss Storm": {
84
+ "component": "Redis Cache Cluster",
85
+ "severity": "HIGH",
86
+ "impact_radius": "85% of users",
87
+ "business_impact": {"revenue_loss_per_hour": 8500},
88
+ "detection_time": "45 seconds",
89
+ "tags": ["cache", "redis", "latency"]
90
+ }
91
+ }
92
 
93
  # Import orchestrator
94
+ try:
95
+ from demo.orchestrator import DemoOrchestrator
96
+ except ImportError:
97
+ # Create mock orchestrator
98
+ class DemoOrchestrator:
99
+ async def analyze_incident(self, name, scenario):
100
+ return {"status": "Mock analysis", "scenario": name}
101
 
102
+ # Import ROI calculator - with fallback
103
  try:
104
  from core.calculators import EnhancedROICalculator
105
  roi_calculator_available = True
106
+ logger.info("EnhancedROICalculator imported successfully")
107
  except ImportError as e:
108
  logger.warning(f"EnhancedROICalculator not available: {e}")
109
+ # Create mock calculator
110
+ class EnhancedROICalculator:
111
+ def calculate_comprehensive_roi(self, **kwargs):
112
+ return {
113
+ "status": "✅ Calculated Successfully",
114
+ "summary": {
115
+ "your_annual_impact": "$1,530,000",
116
+ "potential_savings": "$1,254,600",
117
+ "enterprise_cost": "$625,000",
118
+ "roi_multiplier": "5.2×",
119
+ "payback_months": "6.0",
120
+ "annual_roi_percentage": "420%"
121
+ }
122
+ }
123
  roi_calculator_available = True
124
 
125
+ # Import visualizations - with fallback
126
  try:
127
  from core.visualizations import EnhancedVisualizationEngine
128
  viz_engine_available = True
129
+ logger.info("EnhancedVisualizationEngine imported successfully")
130
  except ImportError as e:
131
  logger.warning(f"EnhancedVisualizationEngine not available: {e}")
132
+ # Create mock visualization engine
133
+ class EnhancedVisualizationEngine:
134
+ def create_executive_dashboard(self, data=None):
135
+ import plotly.graph_objects as go
136
+ fig = go.Figure()
137
+ fig.update_layout(height=400)
138
+ return fig
139
  viz_engine_available = True
140
 
141
  # Import UI components
142
+ try:
143
+ from ui.components import (
144
+ create_header, create_status_bar, create_tab1_incident_demo,
145
+ create_tab2_business_roi, create_tab3_enterprise_features,
146
+ create_tab4_audit_trail, create_tab5_learning_engine,
147
+ create_footer
148
+ )
149
+ ui_available = True
150
+ logger.info("UI components imported successfully")
151
+ except ImportError as e:
152
+ logger.error(f"UI components not available: {e}")
153
+ ui_available = False
154
+ # Create minimal UI fallbacks
155
+ def create_header(version="3.3.6", mock_mode=False):
156
+ import gradio as gr
157
+ return gr.HTML(f"<h2>🚀 ARF v{version}</h2>")
158
+
159
+ def create_status_bar():
160
+ import gradio as gr
161
+ return gr.HTML("<div>Status</div>")
162
+
163
+ def create_tab1_incident_demo(*args, **kwargs):
164
+ import gradio as gr
165
+ return [gr.Dropdown()] * 24
166
+
167
+ def create_tab2_business_roi(*args, **kwargs):
168
+ import gradio as gr
169
+ return [gr.Plot()] * 7
170
+
171
+ def create_tab3_enterprise_features():
172
+ import gradio as gr
173
+ return [gr.JSON()] * 8
174
+
175
+ def create_tab4_audit_trail():
176
+ import gradio as gr
177
+ return [gr.Button()] * 6
178
+
179
+ def create_tab5_learning_engine():
180
+ import gradio as gr
181
+ return [gr.Plot()] * 10
182
+
183
+ def create_footer():
184
+ import gradio as gr
185
+ return gr.HTML("<footer>ARF</footer>")
186
 
187
+ # Import styles - with fallback
188
  try:
189
  from ui.styles import get_styles
190
  styles_available = True
 
198
  return {
199
  "INCIDENT_SCENARIOS": INCIDENT_SCENARIOS,
200
  "DemoOrchestrator": DemoOrchestrator,
201
+ "EnhancedROICalculator": EnhancedROICalculator() if roi_calculator_available else None,
202
+ "EnhancedVisualizationEngine": EnhancedVisualizationEngine() if viz_engine_available else None,
203
  "create_header": create_header,
204
  "create_status_bar": create_status_bar,
205
  "create_tab1_incident_demo": create_tab1_incident_demo,
 
212
  "all_available": True
213
  }
214
 
215
+ except Exception as e:
216
  logger.error(f"❌ CRITICAL IMPORT ERROR: {e}")
217
  logger.error(traceback.format_exc())
218
+
219
+ # Return minimal components for fallback
220
+ import gradio as gr
221
+
222
+ # Create minimal mock components
223
+ class MockCalculator:
224
+ def calculate_comprehensive_roi(self, **kwargs):
225
+ return {
226
+ "status": "Mock calculation",
227
+ "summary": {"roi_multiplier": "5.2×"},
228
+ "scenarios": {
229
+ "base_case": {"roi": "5.2×"},
230
+ "best_case": {"roi": "6.5×"},
231
+ "worst_case": {"roi": "4.0×"}
232
+ }
233
+ }
234
+
235
+ class MockVisualizationEngine:
236
+ def create_executive_dashboard(self, data=None):
237
+ import plotly.graph_objects as go
238
+ fig = go.Figure()
239
+ fig.update_layout(height=400)
240
+ return fig
241
+
242
+ class MockOrchestrator:
243
+ async def analyze_incident(self, name, scenario):
244
+ return {"status": "mock", "scenario": name}
245
+
246
+ return {
247
+ "all_available": False,
248
+ "error": str(e),
249
+ "INCIDENT_SCENARIOS": {"Cache Miss Storm": {}},
250
+ "DemoOrchestrator": MockOrchestrator(),
251
+ "EnhancedROICalculator": MockCalculator(),
252
+ "EnhancedVisualizationEngine": MockVisualizationEngine(),
253
+ "create_header": lambda version, mock: gr.HTML(f"<h2>🚀 ARF v{version}</h2>"),
254
+ "create_status_bar": lambda: gr.HTML("<div>Status</div>"),
255
+ "create_tab1_incident_demo": lambda *args: [gr.Dropdown()] * 24,
256
+ "create_tab2_business_roi": lambda *args: [gr.Plot()] * 7,
257
+ "create_tab3_enterprise_features": lambda: [gr.JSON()] * 8,
258
+ "create_tab4_audit_trail": lambda: [gr.Button()] * 6,
259
+ "create_tab5_learning_engine": lambda: [gr.Plot()] * 10,
260
+ "create_footer": lambda: gr.HTML("<footer>ARF</footer>"),
261
+ "get_styles": lambda: ""
262
+ }
263
 
264
  # Import components safely
265
  components = import_components()
266
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
  # Extract components
268
  INCIDENT_SCENARIOS = components["INCIDENT_SCENARIOS"]
269
  DemoOrchestrator = components["DemoOrchestrator"]
 
283
  # AUDIT TRAIL MANAGER - ENHANCED
284
  # ===========================================
285
  class AuditTrailManager:
286
+ """Enhanced audit trail manager"""
287
 
288
  def __init__(self):
289
  self.executions = []
290
  self.incidents = []
 
291
 
292
  def add_execution(self, scenario: str, mode: str, success: bool = True, savings: float = 0) -> Dict:
293
  """Add execution to audit trail"""
 
300
  "details": f"{mode} execution at {datetime.datetime.now().isoformat()}"
301
  }
302
  self.executions.insert(0, entry)
 
 
 
 
 
 
303
  return entry
304
 
305
  def add_incident(self, scenario: str, severity: str = "HIGH") -> Dict:
 
312
  "status": "Analyzed"
313
  }
314
  self.incidents.insert(0, entry)
 
 
 
 
 
 
315
  return entry
316
 
317
  def get_execution_table(self) -> List[List]:
 
328
  for e in self.incidents[:15]
329
  ]
330
 
 
 
 
 
 
 
 
 
 
 
 
 
331
  def clear(self) -> None:
332
  """Clear audit trail"""
333
  self.executions = []
334
  self.incidents = []
 
 
 
 
 
 
 
 
 
 
 
 
335
 
336
  # ===========================================
337
  # HELPER FUNCTIONS
 
348
  }
349
  return impact_map.get(scenario_name, 5000)
350
 
 
351
  def extract_roi_multiplier(roi_result: Dict) -> float:
352
  """Extract ROI multiplier from EnhancedROICalculator result"""
353
  try:
 
377
  logger.warning(f"Failed to extract ROI multiplier: {e}, using default 5.2")
378
  return 5.2
379
 
 
380
  # ===========================================
381
  # VISUALIZATION HELPERS
382
  # ===========================================
 
469
 
470
  return fig
471
 
 
472
  def create_impact_plot(scenario_name: str):
473
  """Create a business impact visualization"""
474
  import plotly.graph_objects as go
 
515
 
516
  return fig
517
 
 
518
  def create_timeline_plot(scenario_name: str):
519
  """Create an incident timeline visualization"""
520
  import plotly.graph_objects as go
 
560
 
561
  return fig
562
 
 
563
  # ===========================================
564
+ # SCENARIO UPDATE HANDLER
565
  # ===========================================
566
+ def update_scenario_display(scenario_name: str) -> tuple:
567
+ """Update all scenario-related displays"""
 
568
  scenario = INCIDENT_SCENARIOS.get(scenario_name, {})
569
  impact = scenario.get("business_impact", {})
570
  metrics = scenario.get("metrics", {})
571
 
572
  # Create scenario card HTML
573
  scenario_html = f"""
574
+ <div style="border: 1px solid #e2e8f0; border-radius: 14px; padding: 20px; background: white; box-shadow: 0 4px 12px rgba(0,0,0,0.05);">
575
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; padding-bottom: 12px; border-bottom: 2px solid #f1f5f9;">
576
+ <h3 style="margin: 0; font-size: 18px; color: #1e293b;">🚨 {scenario_name}</h3>
577
+ <span style="padding: 4px 12px; background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%); border-radius: 20px; font-size: 12px; font-weight: bold; color: white; text-transform: uppercase; letter-spacing: 0.5px;">{scenario.get('severity', 'HIGH')}</span>
578
  </div>
579
+ <div style="margin-top: 15px;">
580
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; padding: 4px 0;">
581
+ <span style="font-size: 13px; color: #64748b; font-weight: 500;">Component:</span>
582
+ <span style="font-size: 14px; color: #1e293b; font-weight: 600;">{scenario.get('component', 'Unknown').replace('_', ' ').title()}</span>
583
  </div>
584
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; padding: 4px 0;">
585
+ <span style="font-size: 13px; color: #64748b; font-weight: 500;">Affected Users:</span>
586
+ <span style="font-size: 14px; color: #1e293b; font-weight: 600;">{metrics.get('affected_users', 'Unknown') if 'affected_users' in metrics else 'Unknown'}</span>
587
  </div>
588
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; padding: 4px 0;">
589
+ <span style="font-size: 13px; color: #64748b; font-weight: 500;">Revenue Risk:</span>
590
+ <span style="font-size: 14px; color: #ef4444; font-weight: 700;">${impact.get('revenue_loss_per_hour', 0):,}/hour</span>
591
  </div>
592
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; padding: 4px 0;">
593
+ <span style="font-size: 13px; color: #64748b; font-weight: 500;">Detection Time:</span>
594
+ <span style="font-size: 14px; color: #1e293b; font-weight: 600;">45 seconds (ARF AI)</span>
595
  </div>
596
+ <div style="display: flex; flex-wrap: wrap; gap: 6px; margin-top: 15px; padding-top: 12px; border-top: 1px solid #f1f5f9;">
597
+ <span style="padding: 3px 8px; background: #f1f5f9; border-radius: 6px; font-size: 11px; color: #475569; font-weight: 500;">{scenario.get('component', 'unknown').split('_')[0]}</span>
598
+ <span style="padding: 3px 8px; background: #f1f5f9; border-radius: 6px; font-size: 11px; color: #475569; font-weight: 500;">{scenario.get('severity', 'high').lower()}</span>
599
+ <span style="padding: 3px 8px; background: #f1f5f9; border-radius: 6px; font-size: 11px; color: #475569; font-weight: 500;">production</span>
600
+ <span style="padding: 3px 8px; background: #f1f5f9; border-radius: 6px; font-size: 11px; color: #475569; font-weight: 500;">incident</span>
601
  </div>
602
  </div>
603
  </div>
 
615
  timeline_plot
616
  )
617
 
 
618
  # ===========================================
619
+ # OSS ANALYSIS HANDLER
620
  # ===========================================
621
+ @AsyncRunner.async_to_sync
622
  async def run_oss_analysis(scenario_name: str):
623
+ """Run OSS analysis"""
624
  scenario = INCIDENT_SCENARIOS.get(scenario_name, {})
625
 
626
  # Use orchestrator
 
711
  oss_results, incident_table_data
712
  )
713
 
 
714
  # ===========================================
715
  # CREATE DEMO INTERFACE
716
  # ===========================================
 
720
  import gradio as gr
721
 
722
  # Initialize components
723
+ viz_engine = EnhancedVisualizationEngine
724
+ roi_calculator = EnhancedROICalculator
725
  audit_manager = AuditTrailManager()
 
726
 
727
  # Get CSS styles
728
  css_styles = get_styles()
 
889
  )
890
 
891
  # Run Complete Demo
892
+ @AsyncRunner.async_to_sync
893
  async def run_complete_demo_async(scenario_name):
894
+ """Run a complete demo walkthrough"""
895
  # Step 1: Update scenario
896
+ update_result = update_scenario_display(scenario_name)
897
 
898
  # Step 2: Run OSS analysis
899
  oss_result = await run_oss_analysis(scenario_name)
 
1087
 
1088
  def export_audit_trail():
1089
  try:
1090
+ # Calculate total savings
1091
+ total_savings = 0
1092
+ for e in audit_manager.executions:
1093
+ if e['savings'] != '$0':
1094
+ try:
1095
+ savings_str = e['savings'].replace('$', '').replace(',', '')
1096
+ total_savings += int(float(savings_str))
1097
+ except:
1098
+ pass
1099
 
1100
  audit_data = {
1101
  "exported_at": datetime.datetime.now().isoformat(),
 
1105
  "total_executions": len(audit_manager.executions),
1106
  "total_incidents": len(audit_manager.incidents),
1107
  "total_savings": f"${total_savings:,}",
1108
+ "success_rate": "100%"
1109
  }
1110
  }
1111
  return json.dumps(audit_data, indent=2)