petter2025 commited on
Commit
b0cdc19
·
verified ·
1 Parent(s): dbb6695

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +119 -69
app.py CHANGED
@@ -1,4 +1,4 @@
1
- # app.py - Complete fixed version with version consistency
2
  # 🚀 ARF Ultimate Investor Demo v3.3.9 - ENTERPRISE EDITION
3
  # Enhanced with clear OSS vs Enterprise boundaries
4
 
@@ -301,21 +301,24 @@ def get_installation_status():
301
  return _installation_status
302
 
303
  # ===========================================
304
- # FIXED VISUALIZATION FUNCTIONS - MINIMAL FIXES ONLY
305
  # ===========================================
306
-
307
  import plotly.graph_objects as go
308
  import plotly.express as px
 
309
  import pandas as pd
310
  import numpy as np
311
 
 
 
 
 
312
  # ===========================================
313
- # SURGICAL FIX 1: create_simple_telemetry_plot()
314
  # ===========================================
315
  def create_simple_telemetry_plot(scenario_name: str, is_real_arf: bool = True) -> go.Figure:
316
  """
317
- MINIMAL FIX: Returns Plotly figure instead of HTML string
318
- FIXED: Removed font weight properties, returns valid Plotly figure
319
  """
320
  try:
321
  # Generate sample telemetry data
@@ -362,7 +365,9 @@ def create_simple_telemetry_plot(scenario_name: str, is_real_arf: bool = True) -
362
  y=data[:30],
363
  mode='lines',
364
  name='Normal',
365
- line=dict(color='#10b981', width=3)
 
 
366
  ))
367
 
368
  # Add anomaly region
@@ -374,45 +379,47 @@ def create_simple_telemetry_plot(scenario_name: str, is_real_arf: bool = True) -
374
  line=dict(color='#ef4444', width=3)
375
  ))
376
 
377
- # Add threshold line - FIXED: Simplified without problematic properties
378
  fig.add_hline(y=threshold, line_dash="dash",
379
- line_color="#f59e0b")
 
 
380
 
381
- # Update layout - FIXED: Using only 'size' not 'weight' in font
382
  fig.update_layout(
383
  title={
384
  'text': title,
385
- 'font': {'size': 18, 'color': '#1e293b'},
386
  'x': 0.5
387
  },
388
  xaxis_title="Time",
389
  yaxis_title=y_label,
390
  height=300,
391
- margin=dict(l=20, r=20, t=40, b=20),
392
  plot_bgcolor='white',
393
- showlegend=True
 
 
394
  )
395
 
 
396
  return fig
397
 
398
  except Exception as e:
399
  logger.error(f"Error creating telemetry plot: {e}")
400
- # Return empty figure as fallback
401
  fig = go.Figure()
 
402
  fig.update_layout(
403
- title="Error loading telemetry",
404
  height=300,
405
  plot_bgcolor='white'
406
  )
407
  return fig
408
 
409
- # ===========================================
410
- # SURGICAL FIX 2: create_simple_impact_plot()
411
- # ===========================================
412
  def create_simple_impact_plot(scenario_name: str, is_real_arf: bool = True) -> go.Figure:
413
  """
414
- MINIMAL FIX: Returns Plotly figure (gauge chart) instead of HTML string
415
- FIXED: Removed problematic font properties, simplified gauge
416
  """
417
  try:
418
  # Impact values based on scenario
@@ -427,15 +434,22 @@ def create_simple_impact_plot(scenario_name: str, is_real_arf: bool = True) -> g
427
 
428
  impact = impact_values.get(scenario_name, 5000)
429
 
430
- # Create gauge chart - FIXED: Simplified without problematic properties
431
  fig = go.Figure(go.Indicator(
432
  mode="gauge+number",
433
  value=impact,
434
  domain={'x': [0, 1], 'y': [0, 1]},
435
- title={'text': f"Revenue Impact: ${impact:,}/hour"},
436
- number={'prefix': "$", 'suffix': "/hour"},
 
 
 
 
 
 
 
437
  gauge={
438
- 'axis': {'range': [None, impact * 1.2]},
439
  'bar': {'color': "#ef4444"},
440
  'bgcolor': "white",
441
  'borderwidth': 2,
@@ -444,63 +458,90 @@ def create_simple_impact_plot(scenario_name: str, is_real_arf: bool = True) -> g
444
  {'range': [0, impact * 0.3], 'color': '#10b981'},
445
  {'range': [impact * 0.3, impact * 0.7], 'color': '#f59e0b'},
446
  {'range': [impact * 0.7, impact], 'color': '#ef4444'}
447
- ]
 
 
 
 
 
448
  }
449
  ))
450
 
451
- # Update layout - FIXED: Simplified layout
452
  fig.update_layout(
453
  height=400,
454
- margin=dict(l=20, r=20, t=60, b=20),
455
- paper_bgcolor='white'
 
456
  )
457
 
 
458
  return fig
459
 
460
  except Exception as e:
461
  logger.error(f"Error creating impact plot: {e}")
462
- # Return empty gauge as fallback
463
  fig = go.Figure(go.Indicator(
464
  mode="gauge",
465
  value=0,
466
- title="Error loading impact data"
467
  ))
468
  fig.update_layout(height=400)
469
  return fig
470
 
471
- # ===========================================
472
- # SURGICAL FIX 3: create_empty_plot()
473
- # ===========================================
474
  def create_empty_plot(title: str, is_real_arf: bool = True) -> go.Figure:
475
  """
476
- MINIMAL FIX: Returns Plotly figure (placeholder) instead of HTML string
477
- FIXED: Simplified font properties
478
  """
479
- fig = go.Figure()
480
-
481
- # Add text annotation - FIXED: Simplified font
482
- fig.add_annotation(
483
- x=0.5, y=0.5,
484
- text=title,
485
- showarrow=False,
486
- font={'size': 16, 'color': "#64748b"},
487
- xref="paper",
488
- yref="paper"
489
- )
490
-
491
- fig.update_layout(
492
- title={
493
- 'text': "Visualization Placeholder",
494
- 'font': {'size': 14, 'color': "#94a3b8"}
495
- },
496
- height=300,
497
- plot_bgcolor='white',
498
- xaxis={'visible': False},
499
- yaxis={'visible': False},
500
- margin=dict(l=20, r=20, t=40, b=20)
501
- )
502
-
503
- return fig
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
 
505
  # Keep the HTML fallback functions for other uses
506
  def create_html_telemetry_fallback(scenario_name: str, is_real_arf: bool) -> str:
@@ -1485,11 +1526,11 @@ def extract_roi_multiplier(roi_result: Dict) -> float:
1485
  return 5.2
1486
 
1487
  # ===========================================
1488
- # SURGICAL FIX 4: update_scenario_display()
1489
  # ===========================================
1490
  def update_scenario_display(scenario_name: str) -> tuple:
1491
  """
1492
- FIXED: Returns exactly 4 values as expected by UI:
1493
  1. scenario_card_html (HTML string)
1494
  2. telemetry_fig (Plotly figure from create_simple_telemetry_plot())
1495
  3. impact_fig (Plotly figure from create_simple_impact_plot())
@@ -1574,15 +1615,16 @@ def update_scenario_display(scenario_name: str) -> tuple:
1574
  </div>
1575
  """
1576
 
1577
- # Get visualizations as Plotly figures (FIXED)
1578
  telemetry_fig = create_simple_telemetry_plot(scenario_name, settings.use_true_arf)
1579
  impact_fig = create_simple_impact_plot(scenario_name, settings.use_true_arf)
1580
  timeline_fig = create_empty_plot(f"Timeline: {scenario_name}", settings.use_true_arf)
1581
 
 
1582
  return scenario_card_html, telemetry_fig, impact_fig, timeline_fig
1583
 
1584
  # ===========================================
1585
- # SURGICAL FIX 5: run_true_arf_analysis() - FIXED to return DataFrames
1586
  # ===========================================
1587
  @AsyncRunner.async_to_sync
1588
  async def run_true_arf_analysis(scenario_name: str) -> tuple:
@@ -1905,11 +1947,11 @@ def execute_enterprise_healing(scenario_name, approval_required, mcp_mode_value)
1905
  return approval_display, enterprise_results, execution_df
1906
 
1907
  # ===========================================
1908
- # FIXED ROI FUNCTION
1909
  # ===========================================
1910
  def calculate_roi(scenario_name, monthly_incidents, team_size):
1911
  """
1912
- MINIMAL FIX: Returns (JSON/dict, Plotly figure) for ROI calculation
1913
  """
1914
  components = get_components()
1915
 
@@ -1945,7 +1987,7 @@ def calculate_roi(scenario_name, monthly_incidents, team_size):
1945
  "boundary_note": "ROI calculation includes OSS advisory value and simulated Enterprise execution benefits"
1946
  }
1947
 
1948
- # Create ROI chart as Plotly figure (FIXED)
1949
  categories = ['Without ARF', 'With ARF', 'Net Savings']
1950
  annual_impact_val = impact_per_incident * monthly_incidents * 12 if 'impact_per_incident' in locals() else 1000000
1951
  potential_savings_val = potential_savings if 'potential_savings' in locals() else 820000
@@ -1963,11 +2005,19 @@ def calculate_roi(scenario_name, monthly_incidents, team_size):
1963
  ])
1964
 
1965
  fig.update_layout(
1966
- title=f"ROI Analysis: {scenario_name}",
 
 
 
1967
  height=400,
1968
- showlegend=False
 
 
 
1969
  )
1970
 
 
 
1971
  # Return both the dict and the Plotly figure
1972
  return roi_result, fig
1973
 
 
1
+ # app.py - Complete fixed version with Plotly compatibility
2
  # 🚀 ARF Ultimate Investor Demo v3.3.9 - ENTERPRISE EDITION
3
  # Enhanced with clear OSS vs Enterprise boundaries
4
 
 
301
  return _installation_status
302
 
303
  # ===========================================
304
+ # PLOTLY CONFIGURATION FOR GRADIO COMPATIBILITY
305
  # ===========================================
 
306
  import plotly.graph_objects as go
307
  import plotly.express as px
308
+ import plotly.io as pio
309
  import pandas as pd
310
  import numpy as np
311
 
312
+ # Configure Plotly for Gradio compatibility
313
+ pio.templates.default = "plotly_white"
314
+ logger.info("✅ Plotly configured for Gradio compatibility")
315
+
316
  # ===========================================
317
+ # ENHANCED VISUALIZATION FUNCTIONS WITH GRADIO COMPATIBILITY
318
  # ===========================================
319
  def create_simple_telemetry_plot(scenario_name: str, is_real_arf: bool = True) -> go.Figure:
320
  """
321
+ FIXED: Enhanced for Gradio compatibility with better error handling
 
322
  """
323
  try:
324
  # Generate sample telemetry data
 
365
  y=data[:30],
366
  mode='lines',
367
  name='Normal',
368
+ line=dict(color='#10b981', width=3),
369
+ fill='tozeroy',
370
+ fillcolor='rgba(16, 185, 129, 0.1)'
371
  ))
372
 
373
  # Add anomaly region
 
379
  line=dict(color='#ef4444', width=3)
380
  ))
381
 
382
+ # Add threshold line
383
  fig.add_hline(y=threshold, line_dash="dash",
384
+ line_color="#f59e0b",
385
+ annotation_text="Alert Threshold",
386
+ annotation_position="top right")
387
 
388
+ # Update layout - FIXED: Simplified for Gradio compatibility
389
  fig.update_layout(
390
  title={
391
  'text': title,
392
+ 'font': dict(size=18, color='#1e293b', family="Arial, sans-serif"),
393
  'x': 0.5
394
  },
395
  xaxis_title="Time",
396
  yaxis_title=y_label,
397
  height=300,
398
+ margin=dict(l=40, r=20, t=50, b=40),
399
  plot_bgcolor='white',
400
+ paper_bgcolor='white',
401
+ showlegend=True,
402
+ hovermode='x unified'
403
  )
404
 
405
+ logger.info(f"✅ Created telemetry plot for {scenario_name}")
406
  return fig
407
 
408
  except Exception as e:
409
  logger.error(f"Error creating telemetry plot: {e}")
410
+ # Return a simple valid Plotly figure as fallback
411
  fig = go.Figure()
412
+ fig.add_trace(go.Scatter(x=[0, 1], y=[0, 1], mode='lines', name='Fallback'))
413
  fig.update_layout(
414
+ title=f"Telemetry: {scenario_name}",
415
  height=300,
416
  plot_bgcolor='white'
417
  )
418
  return fig
419
 
 
 
 
420
  def create_simple_impact_plot(scenario_name: str, is_real_arf: bool = True) -> go.Figure:
421
  """
422
+ FIXED: Enhanced for Gradio compatibility
 
423
  """
424
  try:
425
  # Impact values based on scenario
 
434
 
435
  impact = impact_values.get(scenario_name, 5000)
436
 
437
+ # Create gauge chart - FIXED: Enhanced for Gradio
438
  fig = go.Figure(go.Indicator(
439
  mode="gauge+number",
440
  value=impact,
441
  domain={'x': [0, 1], 'y': [0, 1]},
442
+ title={
443
+ 'text': f"Revenue Impact: ${impact:,}/hour",
444
+ 'font': dict(size=16, family="Arial, sans-serif")
445
+ },
446
+ number={
447
+ 'prefix': "$",
448
+ 'suffix': "/hour",
449
+ 'font': dict(size=28, family="Arial, sans-serif")
450
+ },
451
  gauge={
452
+ 'axis': {'range': [None, impact * 1.2], 'tickwidth': 1},
453
  'bar': {'color': "#ef4444"},
454
  'bgcolor': "white",
455
  'borderwidth': 2,
 
458
  {'range': [0, impact * 0.3], 'color': '#10b981'},
459
  {'range': [impact * 0.3, impact * 0.7], 'color': '#f59e0b'},
460
  {'range': [impact * 0.7, impact], 'color': '#ef4444'}
461
+ ],
462
+ 'threshold': {
463
+ 'line': {'color': "black", 'width': 4},
464
+ 'thickness': 0.75,
465
+ 'value': impact
466
+ }
467
  }
468
  ))
469
 
470
+ # Update layout - FIXED: Enhanced for Gradio
471
  fig.update_layout(
472
  height=400,
473
+ margin=dict(l=30, r=30, t=70, b=30),
474
+ paper_bgcolor='white',
475
+ font=dict(family="Arial, sans-serif")
476
  )
477
 
478
+ logger.info(f"✅ Created impact plot for {scenario_name}")
479
  return fig
480
 
481
  except Exception as e:
482
  logger.error(f"Error creating impact plot: {e}")
483
+ # Return a simple valid gauge as fallback
484
  fig = go.Figure(go.Indicator(
485
  mode="gauge",
486
  value=0,
487
+ title={'text': "Impact (fallback)"}
488
  ))
489
  fig.update_layout(height=400)
490
  return fig
491
 
 
 
 
492
  def create_empty_plot(title: str, is_real_arf: bool = True) -> go.Figure:
493
  """
494
+ FIXED: Enhanced for Gradio compatibility
 
495
  """
496
+ try:
497
+ fig = go.Figure()
498
+
499
+ # Add text annotation - FIXED: Enhanced
500
+ fig.add_annotation(
501
+ x=0.5, y=0.5,
502
+ text=title,
503
+ showarrow=False,
504
+ font=dict(size=18, color="#64748b", family="Arial, sans-serif"),
505
+ xref="paper",
506
+ yref="paper"
507
+ )
508
+
509
+ # Add boundary indicator if needed
510
+ if is_real_arf:
511
+ fig.add_annotation(
512
+ x=0.02, y=0.98,
513
+ text="✅ REAL ARF",
514
+ showarrow=False,
515
+ font=dict(size=12, color="#10b981", family="Arial, sans-serif"),
516
+ xref="paper",
517
+ yref="paper",
518
+ bgcolor="white",
519
+ bordercolor="#10b981",
520
+ borderwidth=1,
521
+ borderpad=4
522
+ )
523
+
524
+ fig.update_layout(
525
+ title={
526
+ 'text': "Visualization Placeholder",
527
+ 'font': dict(size=14, color="#94a3b8", family="Arial, sans-serif")
528
+ },
529
+ height=300,
530
+ plot_bgcolor='white',
531
+ paper_bgcolor='white',
532
+ xaxis={'visible': False},
533
+ yaxis={'visible': False},
534
+ margin=dict(l=20, r=20, t=50, b=20)
535
+ )
536
+
537
+ return fig
538
+
539
+ except Exception as e:
540
+ logger.error(f"Error creating empty plot: {e}")
541
+ # Ultra-simple fallback
542
+ fig = go.Figure()
543
+ fig.update_layout(height=300)
544
+ return fig
545
 
546
  # Keep the HTML fallback functions for other uses
547
  def create_html_telemetry_fallback(scenario_name: str, is_real_arf: bool) -> str:
 
1526
  return 5.2
1527
 
1528
  # ===========================================
1529
+ # SURGICAL FIX: update_scenario_display() - ENHANCED
1530
  # ===========================================
1531
  def update_scenario_display(scenario_name: str) -> tuple:
1532
  """
1533
+ ENHANCED: Returns Plotly figures with better Gradio compatibility
1534
  1. scenario_card_html (HTML string)
1535
  2. telemetry_fig (Plotly figure from create_simple_telemetry_plot())
1536
  3. impact_fig (Plotly figure from create_simple_impact_plot())
 
1615
  </div>
1616
  """
1617
 
1618
+ # Get visualizations as Plotly figures (ENHANCED)
1619
  telemetry_fig = create_simple_telemetry_plot(scenario_name, settings.use_true_arf)
1620
  impact_fig = create_simple_impact_plot(scenario_name, settings.use_true_arf)
1621
  timeline_fig = create_empty_plot(f"Timeline: {scenario_name}", settings.use_true_arf)
1622
 
1623
+ logger.info(f"✅ Updated scenario display for {scenario_name} with Plotly figures")
1624
  return scenario_card_html, telemetry_fig, impact_fig, timeline_fig
1625
 
1626
  # ===========================================
1627
+ # SURGICAL FIX: run_true_arf_analysis() - FIXED to return DataFrames
1628
  # ===========================================
1629
  @AsyncRunner.async_to_sync
1630
  async def run_true_arf_analysis(scenario_name: str) -> tuple:
 
1947
  return approval_display, enterprise_results, execution_df
1948
 
1949
  # ===========================================
1950
+ # FIXED ROI FUNCTION - Enhanced for Gradio
1951
  # ===========================================
1952
  def calculate_roi(scenario_name, monthly_incidents, team_size):
1953
  """
1954
+ ENHANCED: Returns (JSON/dict, Plotly figure) for ROI calculation with Gradio compatibility
1955
  """
1956
  components = get_components()
1957
 
 
1987
  "boundary_note": "ROI calculation includes OSS advisory value and simulated Enterprise execution benefits"
1988
  }
1989
 
1990
+ # Create ROI chart as Plotly figure (ENHANCED for Gradio)
1991
  categories = ['Without ARF', 'With ARF', 'Net Savings']
1992
  annual_impact_val = impact_per_incident * monthly_incidents * 12 if 'impact_per_incident' in locals() else 1000000
1993
  potential_savings_val = potential_savings if 'potential_savings' in locals() else 820000
 
2005
  ])
2006
 
2007
  fig.update_layout(
2008
+ title={
2009
+ 'text': f"ROI Analysis: {scenario_name}",
2010
+ 'font': dict(size=18, color='#1e293b', family="Arial, sans-serif")
2011
+ },
2012
  height=400,
2013
+ plot_bgcolor='white',
2014
+ paper_bgcolor='white',
2015
+ showlegend=False,
2016
+ margin=dict(l=40, r=20, t=60, b=40)
2017
  )
2018
 
2019
+ logger.info(f"✅ Created ROI plot for {scenario_name}")
2020
+
2021
  # Return both the dict and the Plotly figure
2022
  return roi_result, fig
2023