petter2025 commited on
Commit
7450c87
Β·
verified Β·
1 Parent(s): 7c722fd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +359 -19
app.py CHANGED
@@ -1,7 +1,7 @@
1
  """
2
  πŸš€ ARF ULTIMATE INVESTOR DEMO v3.4.0
3
  Enhanced with professional visualizations, export features, and data persistence
4
- FINAL ENHANCED VERSION: All visualizations working + Interactive Capability Matrix
5
  """
6
 
7
  import asyncio
@@ -52,8 +52,37 @@ class VisualizationEngine:
52
  def __init__(self):
53
  self.performance_data = deque(maxlen=100)
54
  self.incident_history = []
 
55
  self.color_palette = px.colors.qualitative.Set3
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  def create_performance_radar(self, metrics: Dict[str, float]) -> go.Figure:
58
  """Create performance radar chart"""
59
  categories = list(metrics.keys())
@@ -109,7 +138,7 @@ class VisualizationEngine:
109
 
110
  # Prepare data for heatmap
111
  hours = list(range(24))
112
- services = sorted(list(set(inc['service'] for inc in incidents if 'service' in inc)))
113
 
114
  if not services:
115
  services = ["Service A", "Service B", "Service C", "Service D", "Service E"]
@@ -118,10 +147,13 @@ class VisualizationEngine:
118
  severity_matrix = np.zeros((len(services), len(hours)))
119
 
120
  for inc in incidents:
121
- if 'service' in inc and 'hour' in inc:
122
  try:
123
- service_idx = services.index(inc['service'])
124
- hour_idx = int(inc['hour']) % 24
 
 
 
125
  severity = inc.get('severity', 1)
126
  severity_matrix[service_idx, hour_idx] = max(
127
  severity_matrix[service_idx, hour_idx], severity
@@ -129,6 +161,13 @@ class VisualizationEngine:
129
  except (ValueError, IndexError):
130
  continue
131
 
 
 
 
 
 
 
 
132
  # Create heatmap with corrected colorbar configuration
133
  fig = go.Figure(data=go.Heatmap(
134
  z=severity_matrix,
@@ -174,6 +213,143 @@ class VisualizationEngine:
174
 
175
  return fig
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  def create_stream_graph(self, metrics_history: List[Dict]) -> go.Figure:
178
  """Create streaming metrics visualization"""
179
  if not metrics_history:
@@ -785,9 +961,10 @@ class OSSModel:
785
  class EnterpriseModel:
786
  """Enterprise Edition Model (Autonomous Execution)"""
787
 
788
- def __init__(self):
789
  self.execution_history = []
790
  self.learning_engine = LearningEngine()
 
791
 
792
  def execute_healing(self, scenario: Dict, approval_required: bool = True) -> Dict[str, Any]:
793
  """Execute healing actions with optional approval"""
@@ -820,6 +997,18 @@ class EnterpriseModel:
820
  oss_time = scenario.get("business_impact", {}).get("recovery_time_oss", "60 minutes")
821
  ent_time = scenario.get("business_impact", {}).get("recovery_time_enterprise", "10 minutes")
822
  cost_saved = execution_results.get("business_outcomes", {}).get("cost_saved", "$0")
 
 
 
 
 
 
 
 
 
 
 
 
823
 
824
  return {
825
  "execution_id": execution_id,
@@ -827,7 +1016,7 @@ class EnterpriseModel:
827
  "actions_executed": len(actions),
828
  "results": execution_results,
829
  "status": status,
830
- "time_savings": f"{oss_time} β†’ {ent_time}",
831
  "cost_saved": cost_saved,
832
  "learning_applied": True,
833
  "compliance_logged": True,
@@ -939,7 +1128,7 @@ class ROICalculator:
939
  }
940
 
941
  # ===========================================
942
- # MAIN ENHANCED APPLICATION
943
  # ===========================================
944
 
945
  class ARFUltimateInvestorDemo:
@@ -949,7 +1138,7 @@ class ARFUltimateInvestorDemo:
949
  self.viz_engine = VisualizationEngine()
950
  self.incident_scenarios = IncidentScenarios()
951
  self.oss_model = OSSModel()
952
- self.enterprise_model = EnterpriseModel()
953
  self.roi_calculator = ROICalculator()
954
 
955
  # Initialize incident history for visualizations
@@ -958,22 +1147,31 @@ class ARFUltimateInvestorDemo:
958
  def _init_incident_history(self):
959
  """Initialize sample incident history for visualizations"""
960
  services = ["API Gateway", "Database", "Cache", "Auth Service", "Payment Service"]
 
961
 
962
  for i in range(20):
963
  hour = random.randint(0, 23)
964
  severity = random.choices([0, 1, 2, 3], weights=[0.3, 0.4, 0.2, 0.1])[0]
965
 
966
  if severity > 0: # Only record actual incidents
967
- self.viz_engine.incident_history.append({
 
 
 
968
  "timestamp": datetime.datetime.now() - datetime.timedelta(hours=24-i),
969
  "hour": hour,
970
- "service": random.choice(services),
971
  "severity": severity,
972
- "type": random.choice(["latency", "error", "timeout", "crash"])
973
- })
 
 
 
 
 
974
 
975
  def create_demo_interface(self):
976
- """Create the main Gradio interface"""
977
 
978
  # CSS for professional styling
979
  css = """
@@ -1002,6 +1200,9 @@ class ARFUltimateInvestorDemo:
1002
  .oss-card {
1003
  border-left: 4px solid #f59e0b;
1004
  }
 
 
 
1005
  .capability-table {
1006
  width: 100%;
1007
  border-collapse: collapse;
@@ -1023,6 +1224,9 @@ class ARFUltimateInvestorDemo:
1023
  .demo-button {
1024
  margin: 5px;
1025
  }
 
 
 
1026
  """
1027
 
1028
  with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
@@ -1064,7 +1268,7 @@ class ARFUltimateInvestorDemo:
1064
 
1065
  gr.Markdown("### πŸ“Š Visualization Type")
1066
  viz_type = gr.Radio(
1067
- choices=["Radar Chart", "Heatmap", "Stream"],
1068
  label="Choose how to visualize the metrics",
1069
  value="Radar Chart"
1070
  )
@@ -1125,7 +1329,50 @@ class ARFUltimateInvestorDemo:
1125
  roi_results = gr.JSON(value={})
1126
  calculate_roi_btn = gr.Button("πŸ“Š Calculate ROI", variant="primary")
1127
 
1128
- # ============ TAB 3: INTERACTIVE CAPABILITY MATRIX ============
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1129
  with gr.TabItem("πŸ“Š Capability Matrix"):
1130
  with gr.Column():
1131
  gr.Markdown("### πŸš€ Ready to transform your reliability operations?")
@@ -1200,6 +1447,8 @@ class ARFUltimateInvestorDemo:
1200
  viz = self.viz_engine.create_performance_radar(metrics)
1201
  elif viz_type == "Heatmap":
1202
  viz = self.viz_engine.create_heatmap_timeline(self.viz_engine.incident_history)
 
 
1203
  else: # Stream
1204
  # Create sample stream data
1205
  stream_data = []
@@ -1223,6 +1472,67 @@ class ARFUltimateInvestorDemo:
1223
  heatmap_output: incident_heatmap
1224
  }
1225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1226
  def run_oss_analysis(scenario_id: str):
1227
  """Run OSS analysis on selected scenario"""
1228
  scenario = self.incident_scenarios.get_scenario(scenario_id)
@@ -1240,10 +1550,14 @@ class ARFUltimateInvestorDemo:
1240
  # Update visualizations
1241
  predictive_viz = self.viz_engine.create_predictive_timeline(self.viz_engine.incident_history)
1242
 
 
 
 
1243
  return {
1244
  enterprise_results: results,
1245
  roi_results: roi,
1246
- predictive_timeline: predictive_viz
 
1247
  }
1248
 
1249
  def calculate_comprehensive_roi():
@@ -1425,7 +1739,9 @@ class ARFUltimateInvestorDemo:
1425
  execute_btn.click(
1426
  fn=run_enterprise_execution,
1427
  inputs=[scenario_dropdown, approval_toggle],
1428
- outputs=[enterprise_results, roi_results, predictive_timeline]
 
 
1429
  )
1430
 
1431
  # ROI Calculation
@@ -1435,6 +1751,21 @@ class ARFUltimateInvestorDemo:
1435
  outputs=[roi_results, performance_radar, learning_insights]
1436
  )
1437
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1438
  # Capability Matrix Interactions
1439
  capability_select.change(
1440
  fn=update_capability_demo,
@@ -1458,7 +1789,9 @@ class ARFUltimateInvestorDemo:
1458
  run_enterprise_demo.click(
1459
  fn=lambda: run_enterprise_execution("cache_miss_storm", False),
1460
  inputs=[],
1461
- outputs=[enterprise_results, roi_results, predictive_timeline]
 
 
1462
  )
1463
 
1464
  # Initial load
@@ -1474,6 +1807,13 @@ class ARFUltimateInvestorDemo:
1474
  outputs=[roi_results, performance_radar, learning_insights]
1475
  )
1476
 
 
 
 
 
 
 
 
1477
  # Footer
1478
  gr.Markdown("""
1479
  ---
 
1
  """
2
  πŸš€ ARF ULTIMATE INVESTOR DEMO v3.4.0
3
  Enhanced with professional visualizations, export features, and data persistence
4
+ FINAL ENHANCED VERSION WITH INCIDENT HISTORY & AUDIT TRAIL
5
  """
6
 
7
  import asyncio
 
52
  def __init__(self):
53
  self.performance_data = deque(maxlen=100)
54
  self.incident_history = []
55
+ self.execution_history = [] # NEW: Store execution history
56
  self.color_palette = px.colors.qualitative.Set3
57
 
58
+ def add_to_history(self, incident: Dict):
59
+ """Add incident to history"""
60
+ self.incident_history.append({
61
+ **incident,
62
+ "id": str(uuid.uuid4())[:8],
63
+ "timestamp": datetime.datetime.now()
64
+ })
65
+
66
+ def add_execution_to_history(self, execution: Dict):
67
+ """Add execution to history"""
68
+ self.execution_history.append({
69
+ **execution,
70
+ "id": str(uuid.uuid4())[:8],
71
+ "timestamp": datetime.datetime.now()
72
+ })
73
+
74
+ def get_incident_history(self, limit: int = 20) -> List[Dict]:
75
+ """Get recent incident history"""
76
+ return sorted(self.incident_history[-limit:],
77
+ key=lambda x: x.get('timestamp', datetime.datetime.min),
78
+ reverse=True)
79
+
80
+ def get_execution_history(self, limit: int = 20) -> List[Dict]:
81
+ """Get recent execution history"""
82
+ return sorted(self.execution_history[-limit:],
83
+ key=lambda x: x.get('timestamp', datetime.datetime.min),
84
+ reverse=True)
85
+
86
  def create_performance_radar(self, metrics: Dict[str, float]) -> go.Figure:
87
  """Create performance radar chart"""
88
  categories = list(metrics.keys())
 
138
 
139
  # Prepare data for heatmap
140
  hours = list(range(24))
141
+ services = sorted(list(set(inc.get('service', 'Unknown') for inc in incidents if inc.get('service'))))
142
 
143
  if not services:
144
  services = ["Service A", "Service B", "Service C", "Service D", "Service E"]
 
147
  severity_matrix = np.zeros((len(services), len(hours)))
148
 
149
  for inc in incidents:
150
+ if inc.get('service') and inc.get('hour') is not None:
151
  try:
152
+ service = inc.get('service', 'Unknown')
153
+ if service not in services:
154
+ services.append(service)
155
+ service_idx = services.index(service)
156
+ hour_idx = int(inc.get('hour', 0)) % 24
157
  severity = inc.get('severity', 1)
158
  severity_matrix[service_idx, hour_idx] = max(
159
  severity_matrix[service_idx, hour_idx], severity
 
161
  except (ValueError, IndexError):
162
  continue
163
 
164
+ # Ensure matrix matches services length
165
+ if len(severity_matrix) < len(services):
166
+ severity_matrix = np.vstack([
167
+ severity_matrix,
168
+ np.zeros((len(services) - len(severity_matrix), len(hours)))
169
+ ])
170
+
171
  # Create heatmap with corrected colorbar configuration
172
  fig = go.Figure(data=go.Heatmap(
173
  z=severity_matrix,
 
213
 
214
  return fig
215
 
216
+ def create_incident_timeline(self, incidents: List[Dict]) -> go.Figure:
217
+ """Create interactive incident timeline"""
218
+ if not incidents:
219
+ return self._create_empty_figure("No incident history available")
220
+
221
+ # Prepare timeline data
222
+ timeline_data = []
223
+ for inc in incidents:
224
+ timeline_data.append({
225
+ 'timestamp': inc.get('timestamp', datetime.datetime.now()),
226
+ 'service': inc.get('service', 'Unknown'),
227
+ 'severity': inc.get('severity', 1),
228
+ 'type': inc.get('type', 'incident'),
229
+ 'description': inc.get('description', ''),
230
+ 'id': inc.get('id', '')
231
+ })
232
+
233
+ df = pd.DataFrame(timeline_data)
234
+ df['timestamp'] = pd.to_datetime(df['timestamp'])
235
+ df = df.sort_values('timestamp')
236
+
237
+ # Map severity to colors and sizes
238
+ severity_colors = {
239
+ 1: 'green',
240
+ 2: 'orange',
241
+ 3: 'red'
242
+ }
243
+
244
+ fig = go.Figure()
245
+
246
+ # Group by service for better visualization
247
+ services = df['service'].unique()
248
+
249
+ for service in services:
250
+ service_df = df[df['service'] == service]
251
+ fig.add_trace(go.Scatter(
252
+ x=service_df['timestamp'],
253
+ y=[service] * len(service_df),
254
+ mode='markers',
255
+ name=service,
256
+ marker=dict(
257
+ size=[s * 10 for s in service_df['severity']],
258
+ color=[severity_colors.get(s, 'gray') for s in service_df['severity']],
259
+ symbol='circle',
260
+ line=dict(width=2, color='white')
261
+ ),
262
+ text=[f"<b>{row['service']}</b><br>Severity: {row['severity']}/3<br>Time: {row['timestamp'].strftime('%H:%M')}<br>{row.get('description', '')}"
263
+ for _, row in service_df.iterrows()],
264
+ hoverinfo='text'
265
+ ))
266
+
267
+ fig.update_layout(
268
+ title="Incident Timeline (Last 24h)",
269
+ xaxis_title="Time",
270
+ yaxis_title="Service",
271
+ paper_bgcolor='rgba(0,0,0,0)',
272
+ plot_bgcolor='rgba(0,0,0,0)',
273
+ height=400,
274
+ hovermode='closest',
275
+ showlegend=True
276
+ )
277
+
278
+ return fig
279
+
280
+ def create_execution_history_chart(self, executions: List[Dict]) -> go.Figure:
281
+ """Create execution history visualization"""
282
+ if not executions:
283
+ return self._create_empty_figure("No execution history available")
284
+
285
+ # Prepare data
286
+ timeline_data = []
287
+ for exec in executions:
288
+ timeline_data.append({
289
+ 'timestamp': exec.get('timestamp', datetime.datetime.now()),
290
+ 'scenario': exec.get('scenario', 'Unknown'),
291
+ 'actions': len(exec.get('actions', [])),
292
+ 'status': exec.get('status', ''),
293
+ 'time_savings': exec.get('time_savings', ''),
294
+ 'cost_saved': exec.get('cost_saved', '$0')
295
+ })
296
+
297
+ df = pd.DataFrame(timeline_data)
298
+ df['timestamp'] = pd.to_datetime(df['timestamp'])
299
+ df = df.sort_values('timestamp')
300
+
301
+ fig = make_subplots(
302
+ rows=2, cols=1,
303
+ subplot_titles=('Execution Timeline', 'Cost Savings Over Time'),
304
+ vertical_spacing=0.15,
305
+ row_heights=[0.6, 0.4]
306
+ )
307
+
308
+ # Timeline
309
+ for scenario in df['scenario'].unique():
310
+ scenario_df = df[df['scenario'] == scenario]
311
+ fig.add_trace(
312
+ go.Scatter(
313
+ x=scenario_df['timestamp'],
314
+ y=scenario_df['actions'],
315
+ mode='markers+lines',
316
+ name=scenario,
317
+ marker=dict(size=10),
318
+ text=[f"<b>{row['scenario']}</b><br>Actions: {row['actions']}<br>Time: {row['timestamp'].strftime('%H:%M')}<br>{row['status']}<br>{row['time_savings']}"
319
+ for _, row in scenario_df.iterrows()],
320
+ hoverinfo='text'
321
+ ),
322
+ row=1, col=1
323
+ )
324
+
325
+ # Cost savings
326
+ df['cost_numeric'] = df['cost_saved'].apply(lambda x: float(x.replace('$', '').replace(',', '')) if isinstance(x, str) else 0)
327
+ fig.add_trace(
328
+ go.Bar(
329
+ x=df['timestamp'],
330
+ y=df['cost_numeric'],
331
+ name='Cost Saved',
332
+ marker_color='lightseagreen',
333
+ text=[f"${x:,.0f}" for x in df['cost_numeric']],
334
+ textposition='outside'
335
+ ),
336
+ row=2, col=1
337
+ )
338
+
339
+ fig.update_layout(
340
+ height=500,
341
+ paper_bgcolor='rgba(0,0,0,0)',
342
+ plot_bgcolor='rgba(0,0,0,0)',
343
+ showlegend=True
344
+ )
345
+
346
+ fig.update_xaxes(title_text="Time", row=1, col=1)
347
+ fig.update_xaxes(title_text="Time", row=2, col=1)
348
+ fig.update_yaxes(title_text="Actions Executed", row=1, col=1)
349
+ fig.update_yaxes(title_text="Cost Saved ($)", row=2, col=1)
350
+
351
+ return fig
352
+
353
  def create_stream_graph(self, metrics_history: List[Dict]) -> go.Figure:
354
  """Create streaming metrics visualization"""
355
  if not metrics_history:
 
961
  class EnterpriseModel:
962
  """Enterprise Edition Model (Autonomous Execution)"""
963
 
964
+ def __init__(self, viz_engine):
965
  self.execution_history = []
966
  self.learning_engine = LearningEngine()
967
+ self.viz_engine = viz_engine
968
 
969
  def execute_healing(self, scenario: Dict, approval_required: bool = True) -> Dict[str, Any]:
970
  """Execute healing actions with optional approval"""
 
997
  oss_time = scenario.get("business_impact", {}).get("recovery_time_oss", "60 minutes")
998
  ent_time = scenario.get("business_impact", {}).get("recovery_time_enterprise", "10 minutes")
999
  cost_saved = execution_results.get("business_outcomes", {}).get("cost_saved", "$0")
1000
+ time_savings = f"{oss_time} β†’ {ent_time}"
1001
+
1002
+ # Add to visualization engine history
1003
+ self.viz_engine.add_execution_to_history({
1004
+ "execution_id": execution_id,
1005
+ "timestamp": timestamp,
1006
+ "scenario": scenario.get("name"),
1007
+ "actions": len(actions),
1008
+ "status": status,
1009
+ "time_savings": time_savings,
1010
+ "cost_saved": cost_saved
1011
+ })
1012
 
1013
  return {
1014
  "execution_id": execution_id,
 
1016
  "actions_executed": len(actions),
1017
  "results": execution_results,
1018
  "status": status,
1019
+ "time_savings": time_savings,
1020
  "cost_saved": cost_saved,
1021
  "learning_applied": True,
1022
  "compliance_logged": True,
 
1128
  }
1129
 
1130
  # ===========================================
1131
+ # MAIN ENHANCED APPLICATION WITH INCIDENT HISTORY
1132
  # ===========================================
1133
 
1134
  class ARFUltimateInvestorDemo:
 
1138
  self.viz_engine = VisualizationEngine()
1139
  self.incident_scenarios = IncidentScenarios()
1140
  self.oss_model = OSSModel()
1141
+ self.enterprise_model = EnterpriseModel(self.viz_engine)
1142
  self.roi_calculator = ROICalculator()
1143
 
1144
  # Initialize incident history for visualizations
 
1147
  def _init_incident_history(self):
1148
  """Initialize sample incident history for visualizations"""
1149
  services = ["API Gateway", "Database", "Cache", "Auth Service", "Payment Service"]
1150
+ scenario_names = list(self.incident_scenarios.SCENARIOS.keys())
1151
 
1152
  for i in range(20):
1153
  hour = random.randint(0, 23)
1154
  severity = random.choices([0, 1, 2, 3], weights=[0.3, 0.4, 0.2, 0.1])[0]
1155
 
1156
  if severity > 0: # Only record actual incidents
1157
+ scenario = random.choice(scenario_names)
1158
+ scenario_data = self.incident_scenarios.get_scenario(scenario)
1159
+
1160
+ incident_record = {
1161
  "timestamp": datetime.datetime.now() - datetime.timedelta(hours=24-i),
1162
  "hour": hour,
1163
+ "service": random.choice(scenario_data.get("services_affected", services)),
1164
  "severity": severity,
1165
+ "type": scenario_data.get("name", "incident"),
1166
+ "description": scenario_data.get("description", ""),
1167
+ "scenario_id": scenario,
1168
+ "id": str(uuid.uuid4())[:8]
1169
+ }
1170
+
1171
+ self.viz_engine.add_to_history(incident_record)
1172
 
1173
  def create_demo_interface(self):
1174
+ """Create the main Gradio interface with incident history"""
1175
 
1176
  # CSS for professional styling
1177
  css = """
 
1200
  .oss-card {
1201
  border-left: 4px solid #f59e0b;
1202
  }
1203
+ .history-card {
1204
+ border-left: 4px solid #3b82f6;
1205
+ }
1206
  .capability-table {
1207
  width: 100%;
1208
  border-collapse: collapse;
 
1224
  .demo-button {
1225
  margin: 5px;
1226
  }
1227
+ .tab-button {
1228
+ margin: 2px;
1229
+ }
1230
  """
1231
 
1232
  with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
 
1268
 
1269
  gr.Markdown("### πŸ“Š Visualization Type")
1270
  viz_type = gr.Radio(
1271
+ choices=["Radar Chart", "Heatmap", "Stream", "Incident Timeline"],
1272
  label="Choose how to visualize the metrics",
1273
  value="Radar Chart"
1274
  )
 
1329
  roi_results = gr.JSON(value={})
1330
  calculate_roi_btn = gr.Button("πŸ“Š Calculate ROI", variant="primary")
1331
 
1332
+ # ============ TAB 3: INCIDENT HISTORY & AUDIT TRAIL ============
1333
+ with gr.TabItem("πŸ“œ Incident History & Audit"):
1334
+ with gr.Row():
1335
+ with gr.Column(scale=2):
1336
+ gr.Markdown("### πŸ“‹ Recent Incidents (Last 24h)")
1337
+
1338
+ # Incident history controls
1339
+ with gr.Row():
1340
+ refresh_history_btn = gr.Button("πŸ”„ Refresh History", variant="secondary", size="sm")
1341
+ clear_history_btn = gr.Button("πŸ—‘οΈ Clear History", variant="stop", size="sm")
1342
+
1343
+ incident_history_table = gr.Dataframe(
1344
+ label="Incident Log",
1345
+ headers=["Time", "Service", "Type", "Severity", "Description"],
1346
+ datatype=["str", "str", "str", "str", "str"],
1347
+ col_count=(5, "fixed"),
1348
+ height=300,
1349
+ value=[]
1350
+ )
1351
+
1352
+ gr.Markdown("### πŸ“Š Incident Timeline")
1353
+ incident_timeline_viz = gr.Plot()
1354
+
1355
+ with gr.Column(scale=2):
1356
+ gr.Markdown("### πŸ“‹ Execution History (Audit Trail)")
1357
+
1358
+ # Execution history controls
1359
+ with gr.Row():
1360
+ refresh_executions_btn = gr.Button("πŸ”„ Refresh Executions", variant="secondary", size="sm")
1361
+ export_audit_btn = gr.Button("πŸ“₯ Export Audit Trail", variant="secondary", size="sm")
1362
+
1363
+ execution_history_table = gr.Dataframe(
1364
+ label="Execution Audit Trail",
1365
+ headers=["Time", "Scenario", "Actions", "Status", "Time Saved", "Cost Saved"],
1366
+ datatype=["str", "str", "str", "str", "str", "str"],
1367
+ col_count=(6, "fixed"),
1368
+ height=300,
1369
+ value=[]
1370
+ )
1371
+
1372
+ gr.Markdown("### πŸ“ˆ Execution History Chart")
1373
+ execution_history_chart = gr.Plot()
1374
+
1375
+ # ============ TAB 4: INTERACTIVE CAPABILITY MATRIX ============
1376
  with gr.TabItem("πŸ“Š Capability Matrix"):
1377
  with gr.Column():
1378
  gr.Markdown("### πŸš€ Ready to transform your reliability operations?")
 
1447
  viz = self.viz_engine.create_performance_radar(metrics)
1448
  elif viz_type == "Heatmap":
1449
  viz = self.viz_engine.create_heatmap_timeline(self.viz_engine.incident_history)
1450
+ elif viz_type == "Incident Timeline":
1451
+ viz = self.viz_engine.create_incident_timeline(self.viz_engine.incident_history)
1452
  else: # Stream
1453
  # Create sample stream data
1454
  stream_data = []
 
1472
  heatmap_output: incident_heatmap
1473
  }
1474
 
1475
+ def get_incident_history_data():
1476
+ """Get formatted incident history for table"""
1477
+ incidents = self.viz_engine.get_incident_history(limit=20)
1478
+ formatted_data = []
1479
+
1480
+ for inc in incidents:
1481
+ timestamp = inc.get('timestamp', datetime.datetime.now())
1482
+ if isinstance(timestamp, str):
1483
+ timestamp = datetime.datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
1484
+
1485
+ formatted_data.append([
1486
+ timestamp.strftime('%H:%M'),
1487
+ inc.get('service', 'Unknown'),
1488
+ inc.get('type', 'incident'),
1489
+ f"{inc.get('severity', 1)}/3",
1490
+ inc.get('description', '')[:50] + '...' if len(inc.get('description', '')) > 50 else inc.get('description', '')
1491
+ ])
1492
+
1493
+ return formatted_data
1494
+
1495
+ def get_execution_history_data():
1496
+ """Get formatted execution history for table"""
1497
+ executions = self.viz_engine.get_execution_history(limit=20)
1498
+ formatted_data = []
1499
+
1500
+ for exec in executions:
1501
+ timestamp = exec.get('timestamp', datetime.datetime.now())
1502
+ if isinstance(timestamp, str):
1503
+ timestamp = datetime.datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
1504
+
1505
+ formatted_data.append([
1506
+ timestamp.strftime('%H:%M'),
1507
+ exec.get('scenario', 'Unknown'),
1508
+ str(exec.get('actions', 0)),
1509
+ exec.get('status', ''),
1510
+ exec.get('time_savings', 'N/A'),
1511
+ exec.get('cost_saved', '$0')
1512
+ ])
1513
+
1514
+ return formatted_data
1515
+
1516
+ def refresh_history():
1517
+ """Refresh history displays"""
1518
+ incident_data = get_incident_history_data()
1519
+ execution_data = get_execution_history_data()
1520
+ incident_timeline = self.viz_engine.create_incident_timeline(self.viz_engine.incident_history)
1521
+ execution_chart = self.viz_engine.create_execution_history_chart(self.viz_engine.execution_history)
1522
+
1523
+ return {
1524
+ incident_history_table: incident_data,
1525
+ execution_history_table: execution_data,
1526
+ incident_timeline_viz: incident_timeline,
1527
+ execution_history_chart: execution_chart
1528
+ }
1529
+
1530
+ def clear_history():
1531
+ """Clear all history"""
1532
+ self.viz_engine.incident_history.clear()
1533
+ self.viz_engine.execution_history.clear()
1534
+ return refresh_history()
1535
+
1536
  def run_oss_analysis(scenario_id: str):
1537
  """Run OSS analysis on selected scenario"""
1538
  scenario = self.incident_scenarios.get_scenario(scenario_id)
 
1550
  # Update visualizations
1551
  predictive_viz = self.viz_engine.create_predictive_timeline(self.viz_engine.incident_history)
1552
 
1553
+ # Also update history
1554
+ history_update = refresh_history()
1555
+
1556
  return {
1557
  enterprise_results: results,
1558
  roi_results: roi,
1559
+ predictive_timeline: predictive_viz,
1560
+ **history_update
1561
  }
1562
 
1563
  def calculate_comprehensive_roi():
 
1739
  execute_btn.click(
1740
  fn=run_enterprise_execution,
1741
  inputs=[scenario_dropdown, approval_toggle],
1742
+ outputs=[enterprise_results, roi_results, predictive_timeline,
1743
+ incident_history_table, execution_history_table,
1744
+ incident_timeline_viz, execution_history_chart]
1745
  )
1746
 
1747
  # ROI Calculation
 
1751
  outputs=[roi_results, performance_radar, learning_insights]
1752
  )
1753
 
1754
+ # History tab interactions
1755
+ refresh_history_btn.click(
1756
+ fn=refresh_history,
1757
+ inputs=[],
1758
+ outputs=[incident_history_table, execution_history_table,
1759
+ incident_timeline_viz, execution_history_chart]
1760
+ )
1761
+
1762
+ clear_history_btn.click(
1763
+ fn=clear_history,
1764
+ inputs=[],
1765
+ outputs=[incident_history_table, execution_history_table,
1766
+ incident_timeline_viz, execution_history_chart]
1767
+ )
1768
+
1769
  # Capability Matrix Interactions
1770
  capability_select.change(
1771
  fn=update_capability_demo,
 
1789
  run_enterprise_demo.click(
1790
  fn=lambda: run_enterprise_execution("cache_miss_storm", False),
1791
  inputs=[],
1792
+ outputs=[enterprise_results, roi_results, predictive_timeline,
1793
+ incident_history_table, execution_history_table,
1794
+ incident_timeline_viz, execution_history_chart]
1795
  )
1796
 
1797
  # Initial load
 
1807
  outputs=[roi_results, performance_radar, learning_insights]
1808
  )
1809
 
1810
+ demo.load(
1811
+ fn=refresh_history,
1812
+ inputs=[],
1813
+ outputs=[incident_history_table, execution_history_table,
1814
+ incident_timeline_viz, execution_history_chart]
1815
+ )
1816
+
1817
  # Footer
1818
  gr.Markdown("""
1819
  ---