petter2025 commited on
Commit
ecfa053
Β·
verified Β·
1 Parent(s): d400e39

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +202 -59
app.py CHANGED
@@ -32,6 +32,108 @@ logger = logging.getLogger(__name__)
32
  # Add parent directory to path
33
  sys.path.insert(0, str(Path(__file__).parent))
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  # ===========================================
36
  # ASYNC UTILITIES - ENHANCED VERSION
37
  # ===========================================
@@ -511,7 +613,7 @@ def update_scenario_display(scenario_name: str) -> tuple:
511
  )
512
 
513
  # ===========================================
514
- # TRUE ARF ANALYSIS HANDLER - UPDATED VERSION
515
  # ===========================================
516
  @AsyncRunner.async_to_sync
517
  async def run_true_arf_analysis(scenario_name: str):
@@ -524,7 +626,11 @@ async def run_true_arf_analysis(scenario_name: str):
524
  if not scenario:
525
  raise ValueError(f"Scenario '{scenario_name}' not found")
526
 
527
- # Use TrueARF337Orchestrator
 
 
 
 
528
  orchestrator = get_components()["DemoOrchestrator"]()
529
  analysis = await orchestrator.analyze_incident(scenario_name, scenario)
530
 
@@ -611,7 +717,7 @@ async def run_true_arf_analysis(scenario_name: str):
611
  success_rate = healing_intent.get("success_rate", 0.87)
612
 
613
  oss_results = {
614
- "status": "βœ… OSS Analysis Complete (Enhanced Mock)",
615
  "arf_version": "mock",
616
  "scenario": scenario_name,
617
  "confidence": decision_confidence,
@@ -633,51 +739,36 @@ async def run_true_arf_analysis(scenario_name: str):
633
  "install_command": "pip install agentic-reliability-framework==3.3.7"
634
  }
635
 
636
- # Update agent status HTML
637
- detection_html = f"""
638
- <div style="border: 2px solid #3b82f6; border-radius: 14px; padding: 18px; background: #eff6ff; text-align: center; min-height: 180px; display: flex; flex-direction: column; align-items: center; justify-content: center;">
639
- <div style="font-size: 32px; margin-bottom: 10px;">πŸ•΅οΈβ€β™‚οΈ</div>
640
- <div style="width: 100%;">
641
- <h4 style="margin: 0 0 8px 0; font-size: 16px; color: #1e293b;">Detection Agent</h4>
642
- <p style="font-size: 13px; color: #475569; margin-bottom: 12px; line-height: 1.4;">Anomaly detected: <strong>{detection_confidence:.1%} confidence</strong></p>
643
- <div style="display: flex; justify-content: space-around; margin-bottom: 12px;">
644
- <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">Response: {detection_time_seconds:.1f}s</span>
645
- <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">True ARF: {'βœ…' if true_oss_used else '⚠️'}</span>
646
- </div>
647
- <div style="display: inline-block; padding: 5px 14px; background: linear-gradient(135deg, #10b981 0%, #059669 100%); border-radius: 20px; font-size: 12px; font-weight: bold; color: white; text-transform: uppercase; letter-spacing: 0.5px;">ACTIVE</div>
648
- </div>
649
- </div>
650
- """
651
 
652
- recall_html = f"""
653
- <div style="border: 2px solid #8b5cf6; border-radius: 14px; padding: 18px; background: #f5f3ff; text-align: center; min-height: 180px; display: flex; flex-direction: column; align-items: center; justify-content: center;">
654
- <div style="font-size: 32px; margin-bottom: 10px;">🧠</div>
655
- <div style="width: 100%;">
656
- <h4 style="margin: 0 0 8px 0; font-size: 16px; color: #1e293b;">Recall Agent</h4>
657
- <p style="font-size: 13px; color: #475569; margin-bottom: 12px; line-height: 1.4;"><strong>{similar_count} similar incidents</strong> found in RAG memory</p>
658
- <div style="display: flex; justify-content: space-around; margin-bottom: 12px;">
659
- <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">Recall: 92%</span>
660
- <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">Patterns: {similar_count}</span>
661
- </div>
662
- <div style="display: inline-block; padding: 5px 14px; background: linear-gradient(135deg, #10b981 0%, #059669 100%); border-radius: 20px; font-size: 12px; font-weight: bold; color: white; text-transform: uppercase; letter-spacing: 0.5px;">ACTIVE</div>
663
- </div>
664
- </div>
665
- """
666
 
667
- decision_html = f"""
668
- <div style="border: 2px solid #10b981; border-radius: 14px; padding: 18px; background: #f0fdf4; text-align: center; min-height: 180px; display: flex; flex-direction: column; align-items: center; justify-content: center;">
669
- <div style="font-size: 32px; margin-bottom: 10px;">🎯</div>
670
- <div style="width: 100%;">
671
- <h4 style="margin: 0 0 8px 0; font-size: 16px; color: #1e293b;">Decision Agent</h4>
672
- <p style="font-size: 13px; color: #475569; margin-bottom: 12px; line-height: 1.4;">Generating healing intent with <strong>{decision_confidence:.1%} confidence</strong></p>
673
- <div style="display: flex; justify-content: space-around; margin-bottom: 12px;">
674
- <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">Success Rate: {success_rate:.1%}</span>
675
- <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">Enterprise: {'βœ…' if enterprise_simulated else '⚠️'}</span>
676
- </div>
677
- <div style="display: inline-block; padding: 5px 14px; background: linear-gradient(135deg, #10b981 0%, #059669 100%); border-radius: 20px; font-size: 12px; font-weight: bold; color: white; text-transform: uppercase; letter-spacing: 0.5px;">ACTIVE</div>
678
- </div>
679
- </div>
680
- """
681
 
682
  logger.info(f"Analysis completed successfully for {scenario_name} (True ARF: {real_arf_version})")
683
  return (
@@ -712,6 +803,43 @@ async def run_true_arf_analysis(scenario_name: str):
712
  error_results, []
713
  )
714
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
715
  # ===========================================
716
  # ENTERPRISE EXECUTION HANDLER - UPDATED FOR TRUE ARF
717
  # ===========================================
@@ -1184,15 +1312,16 @@ def create_demo_interface():
1184
  # ============ TAB 3 HANDLERS ============
1185
 
1186
  def validate_license():
 
1187
  return {
1188
- "status": "βœ… Valid",
1189
  "tier": "OSS (Apache 2.0)",
1190
- "expires": "Never (OSS)",
1191
- "message": "OSS license validated successfully",
1192
- "arf_version": "3.3.7",
1193
- "novel_execution": "Enterprise Only",
1194
- "rollback_guarantees": "Enterprise Only",
1195
- "upgrade_cta": "Contact sales@arf.dev for Enterprise trial"
1196
  }
1197
 
1198
  def start_trial():
@@ -1223,6 +1352,7 @@ def create_demo_interface():
1223
  upgrade_btn.click(fn=upgrade_license, outputs=[license_display])
1224
 
1225
  def update_mcp_mode(mode):
 
1226
  mode_info = {
1227
  "advisory": {
1228
  "current_mode": "advisory",
@@ -1230,7 +1360,8 @@ def create_demo_interface():
1230
  "features": ["Incident analysis", "RAG similarity", "HealingIntent creation"],
1231
  "arf_version": "3.3.7 OSS",
1232
  "package": "agentic-reliability-framework==3.3.7",
1233
- "license": "Apache 2.0"
 
1234
  },
1235
  "approval": {
1236
  "current_mode": "approval",
@@ -1238,7 +1369,8 @@ def create_demo_interface():
1238
  "features": ["All OSS features", "Approval workflows", "Audit trail", "Compliance", "Enhanced healing policies"],
1239
  "arf_version": "3.3.7 Enterprise",
1240
  "package": "arf_enterprise",
1241
- "license": "Commercial"
 
1242
  },
1243
  "autonomous": {
1244
  "current_mode": "autonomous",
@@ -1246,7 +1378,8 @@ def create_demo_interface():
1246
  "features": ["All approval features", "Auto-execution", "Predictive healing", "ML optimization", "Novel execution protocols"],
1247
  "arf_version": "3.3.7 Enterprise+",
1248
  "package": "arf_enterprise[plus]",
1249
- "license": "Commercial Plus"
 
1250
  }
1251
  }
1252
  return mode_info.get(mode, mode_info["advisory"])
@@ -1341,14 +1474,24 @@ def main():
1341
  """Main entry point - Hugging Face Spaces compatible"""
1342
  print("πŸš€ Starting ARF Ultimate Investor Demo v3.8.0 with TRUE ARF v3.3.7...")
1343
  print("=" * 70)
 
 
 
 
 
 
 
 
1344
  print(f"πŸ“Š Mode: {settings.arf_mode.upper()}")
1345
  print(f"πŸ€– Using TRUE ARF: {settings.use_true_arf}")
1346
  print(f"🎯 Default Scenario: {settings.default_scenario}")
1347
  print(f"🏒 ARF Version: 3.3.7 with True OSS + Enterprise Simulation")
1348
  print("=" * 70)
1349
- print("πŸ“¦ Packages:")
1350
- print(" β€’ OSS: agentic-reliability-framework==3.3.7")
1351
- print(" β€’ Enterprise: arf_enterprise (simulated)")
 
 
1352
  print("=" * 70)
1353
 
1354
  import gradio as gr
 
32
  # Add parent directory to path
33
  sys.path.insert(0, str(Path(__file__).parent))
34
 
35
+ # ===========================================
36
+ # ARF INSTALLATION CHECK SYSTEM - NEW
37
+ # ===========================================
38
+ def check_arf_installation():
39
+ """
40
+ Check if real ARF packages are installed
41
+ Returns detailed installation status
42
+ """
43
+ results = {
44
+ "oss_installed": False,
45
+ "enterprise_installed": False,
46
+ "oss_version": None,
47
+ "enterprise_version": None,
48
+ "oss_edition": "unknown",
49
+ "oss_license": "unknown",
50
+ "execution_allowed": False,
51
+ "recommendations": [],
52
+ "badges": {
53
+ "oss": {"text": "⚠️ Mock ARF", "color": "#f59e0b", "icon": "⚠️"},
54
+ "enterprise": {"text": "πŸ”’ Enterprise Required", "color": "#64748b", "icon": "πŸ”’"}
55
+ },
56
+ "timestamp": datetime.datetime.now().isoformat()
57
+ }
58
+
59
+ # Check OSS package
60
+ try:
61
+ import agentic_reliability_framework as arf_oss
62
+ results["oss_installed"] = True
63
+ results["oss_version"] = getattr(arf_oss, '__version__', '3.3.7')
64
+
65
+ # Try to get more info
66
+ try:
67
+ results["oss_edition"] = arf_oss.OSS_EDITION
68
+ results["oss_license"] = arf_oss.OSS_LICENSE
69
+ results["execution_allowed"] = arf_oss.EXECUTION_ALLOWED
70
+ except Exception as e:
71
+ logger.debug(f"Could not get OSS details: {e}")
72
+
73
+ results["badges"]["oss"] = {
74
+ "text": f"βœ… ARF OSS v{results['oss_version']}",
75
+ "color": "#10b981",
76
+ "icon": "βœ…"
77
+ }
78
+
79
+ logger.info(f"βœ… ARF OSS v{results['oss_version']} detected")
80
+
81
+ except ImportError as e:
82
+ results["recommendations"].append(
83
+ "Install real ARF OSS: `pip install agentic-reliability-framework==3.3.7`"
84
+ )
85
+ logger.info("⚠️ ARF OSS not installed - using mock mode")
86
+
87
+ # Check Enterprise package
88
+ try:
89
+ import arf_enterprise
90
+ results["enterprise_installed"] = True
91
+ results["enterprise_version"] = getattr(arf_enterprise, '__version__', '1.0.2')
92
+ results["badges"]["enterprise"] = {
93
+ "text": f"πŸš€ Enterprise v{results['enterprise_version']}",
94
+ "color": "#8b5cf6",
95
+ "icon": "πŸš€"
96
+ }
97
+ logger.info(f"βœ… ARF Enterprise v{results['enterprise_version']} detected")
98
+ except ImportError as e:
99
+ results["recommendations"].append(
100
+ "Install ARF Enterprise: `pip install agentic-reliability-enterprise` (requires license)"
101
+ )
102
+ logger.info("⚠️ ARF Enterprise not installed - using simulation")
103
+
104
+ return results
105
+
106
+ # Global installation status cache
107
+ _installation_status = None
108
+
109
+ def get_installation_status():
110
+ """Get cached installation status"""
111
+ global _installation_status
112
+ if _installation_status is None:
113
+ _installation_status = check_arf_installation()
114
+ return _installation_status
115
+
116
+ def get_installation_badges():
117
+ """Get formatted badge HTML for UI"""
118
+ installation = get_installation_status()
119
+ oss_badge = installation["badges"]["oss"]
120
+ enterprise_badge = installation["badges"]["enterprise"]
121
+
122
+ return f"""
123
+ <div style="display: flex; justify-content: center; gap: 10px; margin-top: 10px; flex-wrap: wrap;">
124
+ <span style="padding: 4px 12px; background: {oss_badge['color']};
125
+ color: white; border-radius: 20px; font-size: 12px; font-weight: bold;
126
+ display: flex; align-items: center; gap: 6px;">
127
+ {oss_badge['icon']} {oss_badge['text']}
128
+ </span>
129
+ <span style="padding: 4px 12px; background: {enterprise_badge['color']};
130
+ color: white; border-radius: 20px; font-size: 12px; font-weight: bold;
131
+ display: flex; align-items: center; gap: 6px;">
132
+ {enterprise_badge['icon']} {enterprise_badge['text']}
133
+ </span>
134
+ </div>
135
+ """
136
+
137
  # ===========================================
138
  # ASYNC UTILITIES - ENHANCED VERSION
139
  # ===========================================
 
613
  )
614
 
615
  # ===========================================
616
+ # TRUE ARF ANALYSIS HANDLER - UPDATED WITH REAL ARF INDICATORS
617
  # ===========================================
618
  @AsyncRunner.async_to_sync
619
  async def run_true_arf_analysis(scenario_name: str):
 
626
  if not scenario:
627
  raise ValueError(f"Scenario '{scenario_name}' not found")
628
 
629
+ # Check installation status
630
+ installation = get_installation_status()
631
+ real_arf_available = installation["oss_installed"]
632
+
633
+ # Use TrueARF337Orchestrator if available
634
  orchestrator = get_components()["DemoOrchestrator"]()
635
  analysis = await orchestrator.analyze_incident(scenario_name, scenario)
636
 
 
717
  success_rate = healing_intent.get("success_rate", 0.87)
718
 
719
  oss_results = {
720
+ "status": "⚠️ Enhanced Mock Analysis",
721
  "arf_version": "mock",
722
  "scenario": scenario_name,
723
  "confidence": decision_confidence,
 
739
  "install_command": "pip install agentic-reliability-framework==3.3.7"
740
  }
741
 
742
+ # Create agent HTML with real ARF indicators
743
+ detection_html = create_agent_html(
744
+ agent_name="Detection",
745
+ status=f"Anomaly detected: <strong>{detection_confidence:.1%} confidence</strong>",
746
+ metrics=f"""
747
+ <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">Response: {detection_time_seconds:.1f}s</span>
748
+ <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">True ARF: {'βœ…' if true_oss_used else '⚠️'}</span>
749
+ """,
750
+ is_real_arf=true_oss_used
751
+ )
 
 
 
 
 
752
 
753
+ recall_html = create_agent_html(
754
+ agent_name="Recall",
755
+ status=f"<strong>{similar_count} similar incidents</strong> found in RAG memory",
756
+ metrics=f"""
757
+ <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">Recall: 92%</span>
758
+ <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">Patterns: {similar_count}</span>
759
+ """,
760
+ is_real_arf=true_oss_used
761
+ )
 
 
 
 
 
762
 
763
+ decision_html = create_agent_html(
764
+ agent_name="Decision",
765
+ status=f"Generating healing intent with <strong>{decision_confidence:.1%} confidence</strong>",
766
+ metrics=f"""
767
+ <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">Success Rate: {success_rate:.1%}</span>
768
+ <span style="font-size: 11px; padding: 3px 8px; background: rgba(255, 255, 255, 0.8); border-radius: 6px; color: #475569; font-weight: 500;">Enterprise: {'βœ…' if enterprise_simulated else '⚠️'}</span>
769
+ """,
770
+ is_real_arf=true_oss_used
771
+ )
 
 
 
 
 
772
 
773
  logger.info(f"Analysis completed successfully for {scenario_name} (True ARF: {real_arf_version})")
774
  return (
 
803
  error_results, []
804
  )
805
 
806
+ def create_agent_html(agent_name: str, status: str, metrics: str, is_real_arf: bool = True):
807
+ """Create agent HTML with real ARF indicators"""
808
+ icons = {
809
+ "Detection": "πŸ•΅οΈβ€β™‚οΈ",
810
+ "Recall": "🧠",
811
+ "Decision": "🎯"
812
+ }
813
+
814
+ real_arf_badge = """
815
+ <span style="position: absolute; top: 8px; right: 8px; padding: 2px 6px; background: #10b981;
816
+ color: white; border-radius: 4px; font-size: 10px; font-weight: bold;">
817
+ βœ… REAL ARF
818
+ </span>
819
+ """ if is_real_arf else """
820
+ <span style="position: absolute; top: 8px; right: 8px; padding: 2px 6px; background: #f59e0b;
821
+ color: white; border-radius: 4px; font-size: 10px; font-weight: bold;">
822
+ ⚠️ MOCK
823
+ </span>
824
+ """
825
+
826
+ return f"""
827
+ <div style="border: 2px solid {'#10b981' if is_real_arf else '#f59e0b'}; border-radius: 14px; padding: 18px; background: {'#f0fdf4' if is_real_arf else '#fef3c7'}; text-align: center; min-height: 180px; display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative;">
828
+ {real_arf_badge}
829
+ <div style="font-size: 32px; margin-bottom: 10px;">{icons.get(agent_name, 'πŸ€–')}</div>
830
+ <div style="width: 100%;">
831
+ <h4 style="margin: 0 0 8px 0; font-size: 16px; color: #1e293b;">{agent_name} Agent</h4>
832
+ <p style="font-size: 13px; color: #475569; margin-bottom: 12px; line-height: 1.4;">{status}</p>
833
+ <div style="display: flex; justify-content: space-around; margin-bottom: 12px;">
834
+ {metrics}
835
+ </div>
836
+ <div style="display: inline-block; padding: 5px 14px; background: linear-gradient(135deg, {'#10b981' if is_real_arf else '#f59e0b'} 0%, {'#059669' if is_real_arf else '#d97706'} 100%); border-radius: 20px; font-size: 12px; font-weight: bold; color: white; text-transform: uppercase; letter-spacing: 0.5px;">
837
+ {'ACTIVE (REAL)' if is_real_arf else 'MOCK'}
838
+ </div>
839
+ </div>
840
+ </div>
841
+ """
842
+
843
  # ===========================================
844
  # ENTERPRISE EXECUTION HANDLER - UPDATED FOR TRUE ARF
845
  # ===========================================
 
1312
  # ============ TAB 3 HANDLERS ============
1313
 
1314
  def validate_license():
1315
+ installation = get_installation_status()
1316
  return {
1317
+ "status": "βœ… OSS Installed" if installation["oss_installed"] else "⚠️ OSS Not Installed",
1318
  "tier": "OSS (Apache 2.0)",
1319
+ "oss_version": installation["oss_version"] or "Not installed",
1320
+ "enterprise_installed": installation["enterprise_installed"],
1321
+ "enterprise_version": installation["enterprise_version"] or "Not installed",
1322
+ "execution_allowed": installation["execution_allowed"],
1323
+ "recommendations": installation["recommendations"],
1324
+ "badges": installation["badges"]
1325
  }
1326
 
1327
  def start_trial():
 
1352
  upgrade_btn.click(fn=upgrade_license, outputs=[license_display])
1353
 
1354
  def update_mcp_mode(mode):
1355
+ installation = get_installation_status()
1356
  mode_info = {
1357
  "advisory": {
1358
  "current_mode": "advisory",
 
1360
  "features": ["Incident analysis", "RAG similarity", "HealingIntent creation"],
1361
  "arf_version": "3.3.7 OSS",
1362
  "package": "agentic-reliability-framework==3.3.7",
1363
+ "license": "Apache 2.0",
1364
+ "installed": installation["oss_installed"]
1365
  },
1366
  "approval": {
1367
  "current_mode": "approval",
 
1369
  "features": ["All OSS features", "Approval workflows", "Audit trail", "Compliance", "Enhanced healing policies"],
1370
  "arf_version": "3.3.7 Enterprise",
1371
  "package": "arf_enterprise",
1372
+ "license": "Commercial",
1373
+ "installed": installation["enterprise_installed"]
1374
  },
1375
  "autonomous": {
1376
  "current_mode": "autonomous",
 
1378
  "features": ["All approval features", "Auto-execution", "Predictive healing", "ML optimization", "Novel execution protocols"],
1379
  "arf_version": "3.3.7 Enterprise+",
1380
  "package": "arf_enterprise[plus]",
1381
+ "license": "Commercial Plus",
1382
+ "installed": installation["enterprise_installed"]
1383
  }
1384
  }
1385
  return mode_info.get(mode, mode_info["advisory"])
 
1474
  """Main entry point - Hugging Face Spaces compatible"""
1475
  print("πŸš€ Starting ARF Ultimate Investor Demo v3.8.0 with TRUE ARF v3.3.7...")
1476
  print("=" * 70)
1477
+
1478
+ # Check installation status first
1479
+ installation = get_installation_status()
1480
+ print(f"πŸ“¦ Package Status:")
1481
+ print(f" β€’ ARF OSS: {'βœ… v' + installation['oss_version'] if installation['oss_installed'] else '⚠️ Not installed'}")
1482
+ print(f" β€’ Enterprise: {'βœ… v' + installation['enterprise_version'] if installation['enterprise_installed'] else '⚠️ Not installed'}")
1483
+ print(f" β€’ Execution Allowed: {'βœ… Yes' if installation['execution_allowed'] else '❌ No (OSS only)'}")
1484
+
1485
  print(f"πŸ“Š Mode: {settings.arf_mode.upper()}")
1486
  print(f"πŸ€– Using TRUE ARF: {settings.use_true_arf}")
1487
  print(f"🎯 Default Scenario: {settings.default_scenario}")
1488
  print(f"🏒 ARF Version: 3.3.7 with True OSS + Enterprise Simulation")
1489
  print("=" * 70)
1490
+
1491
+ if installation["recommendations"]:
1492
+ print("πŸ’‘ Recommendations:")
1493
+ for rec in installation["recommendations"]:
1494
+ print(f" β€’ {rec}")
1495
  print("=" * 70)
1496
 
1497
  import gradio as gr