| |
| """ |
| ARF OSS v3.3.9 Demo Application |
| Fixed to return correct data types for UI components: |
| - Plotly figures for visualizations |
| - JSON/dict for analysis functions |
| """ |
|
|
| import os |
| import json |
| import plotly.graph_objects as go |
| import plotly.express as px |
| import pandas as pd |
| import numpy as np |
| from datetime import datetime, timedelta |
| import gradio as gr |
| import random |
| import logging |
| from typing import Dict, Any, Optional, Tuple |
|
|
| |
| logging.basicConfig(level=logging.INFO) |
| logger = logging.getLogger(__name__) |
|
|
| |
| try: |
| from arf_core.monitoring import TelemetryCollector |
| from arf_core.analysis import ReliabilityAnalyzer |
| from arf_core.healing import AutoHealingEngine |
| ARF_OSS_AVAILABLE = True |
| logger.info("β
ARF OSS v3.3.9 detected") |
| except ImportError: |
| ARF_OSS_AVAILABLE = False |
| logger.warning("β οΈ ARF OSS components not found, using mock implementations") |
|
|
| |
| DEMO_CONFIG = { |
| "version": "3.3.9", |
| "mode": "demo", |
| "show_boundaries": True, |
| "use_true_arf": True |
| } |
|
|
| |
| |
| |
|
|
| def create_simple_telemetry_plot(scenario_name: str, is_real_arf: bool = True) -> go.Figure: |
| """ |
| Create telemetry plot using Plotly - returns Plotly figure object |
| FIXED: Returns Plotly figure instead of HTML string |
| """ |
| try: |
| |
| times = pd.date_range(start=datetime.now() - timedelta(minutes=10), |
| end=datetime.now(), |
| periods=60) |
| |
| |
| if "Cache" in scenario_name: |
| normal_values = np.random.normal(30, 5, 30).tolist() |
| anomaly_values = np.random.normal(85, 10, 30).tolist() |
| data = normal_values + anomaly_values |
| title = f"Cache Hit Rate: {scenario_name}" |
| y_label = "Hit Rate (%)" |
| threshold = 75 |
| elif "Database" in scenario_name: |
| normal_values = np.random.normal(15, 3, 30).tolist() |
| anomaly_values = np.random.normal(95, 5, 30).tolist() |
| data = normal_values + anomaly_values |
| title = f"Database Connections: {scenario_name}" |
| y_label = "Connections (%)" |
| threshold = 90 |
| elif "Kubernetes" in scenario_name: |
| normal_values = np.random.normal(40, 8, 30).tolist() |
| anomaly_values = np.random.normal(95, 2, 30).tolist() |
| data = normal_values + anomaly_values |
| title = f"Memory Usage: {scenario_name}" |
| y_label = "Memory (%)" |
| threshold = 85 |
| else: |
| normal_values = np.random.normal(50, 10, 30).tolist() |
| anomaly_values = np.random.normal(90, 5, 30).tolist() |
| data = normal_values + anomaly_values |
| title = f"System Metrics: {scenario_name}" |
| y_label = "Metric (%)" |
| threshold = 80 |
| |
| |
| fig = go.Figure() |
| |
| |
| fig.add_trace(go.Scatter( |
| x=times[:30], |
| y=data[:30], |
| mode='lines', |
| name='Normal', |
| line=dict(color='#10b981', width=3), |
| fill='tozeroy', |
| fillcolor='rgba(16, 185, 129, 0.1)' |
| )) |
| |
| |
| fig.add_trace(go.Scatter( |
| x=times[30:], |
| y=data[30:], |
| mode='lines', |
| name='Anomaly', |
| line=dict(color='#ef4444', width=3), |
| fill='tozeroy', |
| fillcolor='rgba(239, 68, 68, 0.1)' |
| )) |
| |
| |
| fig.add_hline(y=threshold, line_dash="dash", |
| line_color="#f59e0b", |
| annotation_text="Threshold", |
| annotation_position="top right") |
| |
| |
| fig.update_layout( |
| title=dict( |
| text=title, |
| font=dict(size=18, color='#1e293b'), |
| x=0.5 |
| ), |
| xaxis_title="Time", |
| yaxis_title=y_label, |
| height=300, |
| margin=dict(l=20, r=20, t=40, b=20), |
| plot_bgcolor='white', |
| showlegend=True, |
| legend=dict( |
| orientation="h", |
| yanchor="bottom", |
| y=1.02, |
| xanchor="right", |
| x=1 |
| ), |
| xaxis=dict( |
| showgrid=True, |
| gridcolor='#f1f5f9', |
| gridwidth=1 |
| ), |
| yaxis=dict( |
| showgrid=True, |
| gridcolor='#f1f5f9', |
| gridwidth=1, |
| range=[0, 100] |
| ) |
| ) |
| |
| |
| if is_real_arf: |
| fig.add_annotation( |
| x=0.01, y=0.99, |
| xref="paper", yref="paper", |
| text="β
ARF OSS v3.3.9", |
| showarrow=False, |
| font=dict(size=10, color="#10b981"), |
| bgcolor="rgba(16, 185, 129, 0.1)", |
| borderpad=4 |
| ) |
| else: |
| fig.add_annotation( |
| x=0.01, y=0.99, |
| xref="paper", yref="paper", |
| text="β οΈ Mock Mode", |
| showarrow=False, |
| font=dict(size=10, color="#f59e0b"), |
| bgcolor="rgba(245, 158, 11, 0.1)", |
| borderpad=4 |
| ) |
| |
| return fig |
| |
| except Exception as e: |
| logger.error(f"Error creating telemetry plot: {e}") |
| |
| fig = go.Figure() |
| fig.update_layout( |
| title="Error loading telemetry", |
| height=300, |
| plot_bgcolor='white' |
| ) |
| return fig |
|
|
| def create_simple_impact_plot(scenario_name: str, is_real_arf: bool = True) -> go.Figure: |
| """ |
| Create impact gauge chart using Plotly - returns Plotly figure object |
| FIXED: Returns Plotly figure instead of HTML string |
| """ |
| try: |
| |
| impact_values = { |
| "Cache Miss Storm": 8500, |
| "Database Connection Pool Exhaustion": 4200, |
| "Kubernetes Memory Leak": 5500, |
| "API Rate Limit Storm": 3800, |
| "Network Partition": 12000, |
| "Storage I/O Saturation": 6800 |
| } |
| |
| impact = impact_values.get(scenario_name, 5000) |
| savings = int(impact * 0.85) |
| |
| |
| fig = go.Figure(go.Indicator( |
| mode = "gauge+number+delta", |
| value = impact, |
| domain = {'x': [0, 1], 'y': [0, 1]}, |
| title = {'text': f"Revenue Impact: {scenario_name}", 'font': {'size': 16}}, |
| delta = {'reference': 0, 'position': "top", 'prefix': "Potential loss: $"}, |
| number = {'prefix': "$", 'suffix': "/hour", 'font': {'size': 28}}, |
| gauge = { |
| 'axis': {'range': [None, impact * 1.2], 'tickwidth': 1, 'tickcolor': "darkblue"}, |
| 'bar': {'color': "#ef4444"}, |
| 'bgcolor': "white", |
| 'borderwidth': 2, |
| 'bordercolor': "gray", |
| 'steps': [ |
| {'range': [0, impact * 0.3], 'color': '#10b981'}, |
| {'range': [impact * 0.3, impact * 0.7], 'color': '#f59e0b'}, |
| {'range': [impact * 0.7, impact], 'color': '#ef4444'} |
| ], |
| 'threshold': { |
| 'line': {'color': "red", 'width': 4}, |
| 'thickness': 0.75, |
| 'value': impact |
| } |
| } |
| )) |
| |
| |
| fig.add_annotation( |
| x=0.5, y=0.2, |
| text=f"ARF saves: ${savings:,}/hour", |
| showarrow=False, |
| font=dict(size=14, color="#10b981", weight="bold"), |
| bgcolor="rgba(16, 185, 129, 0.1)", |
| bordercolor="#10b981", |
| borderwidth=2, |
| borderpad=4 |
| ) |
| |
| |
| fig.update_layout( |
| height=400, |
| margin=dict(l=20, r=20, t=60, b=20), |
| paper_bgcolor='white', |
| font=dict(color='#1e293b') |
| ) |
| |
| |
| if is_real_arf: |
| fig.add_annotation( |
| x=0.99, y=0.99, |
| xref="paper", yref="paper", |
| text="β
Real ARF Analysis", |
| showarrow=False, |
| font=dict(size=10, color="#10b981"), |
| bgcolor="rgba(16, 185, 129, 0.1)", |
| borderpad=4, |
| xanchor="right" |
| ) |
| else: |
| fig.add_annotation( |
| x=0.99, y=0.99, |
| xref="paper", yref="paper", |
| text="β οΈ Mock Analysis", |
| showarrow=False, |
| font=dict(size=10, color="#f59e0b"), |
| bgcolor="rgba(245, 158, 11, 0.1)", |
| borderpad=4, |
| xanchor="right" |
| ) |
| |
| return fig |
| |
| except Exception as e: |
| logger.error(f"Error creating impact plot: {e}") |
| |
| fig = go.Figure(go.Indicator( |
| mode="gauge", |
| value=0, |
| title="Error loading impact data" |
| )) |
| fig.update_layout(height=400) |
| return fig |
|
|
| def create_empty_plot(title: str, is_real_arf: bool = True) -> go.Figure: |
| """ |
| Create empty placeholder plot - returns Plotly figure object |
| FIXED: Returns Plotly figure instead of HTML string |
| """ |
| fig = go.Figure() |
| |
| |
| fig.add_annotation( |
| x=0.5, y=0.5, |
| text=title, |
| showarrow=False, |
| font=dict(size=16, color="#64748b"), |
| xref="paper", |
| yref="paper" |
| ) |
| |
| |
| if is_real_arf: |
| mode_text = "β
ARF OSS v3.3.9" |
| color = "#10b981" |
| else: |
| mode_text = "β οΈ Mock Mode" |
| color = "#f59e0b" |
| |
| fig.add_annotation( |
| x=0.5, y=0.4, |
| text=mode_text, |
| showarrow=False, |
| font=dict(size=12, color=color), |
| xref="paper", |
| yref="paper" |
| ) |
| |
| fig.update_layout( |
| title=dict( |
| text="Visualization Placeholder", |
| font=dict(size=14, color="#94a3b8") |
| ), |
| height=300, |
| plot_bgcolor='white', |
| xaxis=dict(visible=False), |
| yaxis=dict(visible=False), |
| margin=dict(l=20, r=20, t=40, b=20) |
| ) |
| |
| return fig |
|
|
| def create_timeline_plot(scenario_name: str, is_real_arf: bool = True) -> go.Figure: |
| """ |
| Create timeline comparison plot - returns Plotly figure object |
| FIXED: Returns Plotly figure instead of HTML string |
| """ |
| |
| stages = ["Detection", "Analysis", "Response", "Resolution", "Verification"] |
| |
| |
| manual_times = [5, 15, 20, 45, 10] |
| |
| |
| arf_times = [0.75, 2, 5, 12, 2] |
| |
| fig = go.Figure() |
| |
| |
| fig.add_trace(go.Bar( |
| name='Without ARF', |
| x=manual_times, |
| y=stages, |
| orientation='h', |
| marker_color='#ef4444', |
| text=[f'{t}min' for t in manual_times], |
| textposition='auto', |
| )) |
| |
| |
| fig.add_trace(go.Bar( |
| name='With ARF', |
| x=arf_times, |
| y=stages, |
| orientation='h', |
| marker_color='#10b981', |
| text=[f'{t}min' for t in arf_times], |
| textposition='auto', |
| )) |
| |
| |
| total_manual = sum(manual_times) |
| total_arf = sum(arf_times) |
| savings = total_manual - total_arf |
| savings_percent = int((savings / total_manual) * 100) |
| |
| |
| fig.update_layout( |
| title=dict( |
| text=f"Timeline Comparison: {scenario_name}", |
| font=dict(size=18, color='#1e293b'), |
| x=0.5 |
| ), |
| barmode='group', |
| height=400, |
| xaxis_title="Time (minutes)", |
| yaxis_title="Stage", |
| plot_bgcolor='white', |
| showlegend=True, |
| legend=dict( |
| orientation="h", |
| yanchor="bottom", |
| y=1.02, |
| xanchor="right", |
| x=1 |
| ), |
| margin=dict(l=20, r=20, t=60, b=20) |
| ) |
| |
| |
| fig.add_annotation( |
| x=0.5, y=1.12, |
| xref="paper", yref="paper", |
| text=f"ARF saves {savings_percent}% ({savings} minutes)", |
| showarrow=False, |
| font=dict(size=14, color="#10b981", weight="bold"), |
| bgcolor="rgba(16, 185, 129, 0.1)", |
| borderpad=4 |
| ) |
| |
| |
| if is_real_arf: |
| fig.add_annotation( |
| x=0.01, y=1.12, |
| xref="paper", yref="paper", |
| text="β
ARF OSS v3.3.9", |
| showarrow=False, |
| font=dict(size=10, color="#10b981"), |
| bgcolor="rgba(16, 185, 129, 0.1)", |
| borderpad=4 |
| ) |
| |
| return fig |
|
|
| |
| |
| |
|
|
| def run_true_arf_analysis(scenario_name: str) -> Dict[str, Any]: |
| """ |
| Run ARF analysis - returns JSON/dict instead of HTML |
| FIXED: Returns dict for gr.JSON() component |
| """ |
| try: |
| |
| import time |
| time.sleep(0.5) |
| |
| |
| analysis_results = { |
| "status": "success", |
| "scenario": scenario_name, |
| "timestamp": datetime.now().isoformat(), |
| "analysis": { |
| "detection_time": "45 seconds", |
| "confidence": "94%", |
| "similar_incidents_found": 3, |
| "pattern_match": "87% similarity", |
| "severity": "HIGH", |
| "component_affected": "Redis Cache Cluster" if "Cache" in scenario_name else "Database Pool" if "Database" in scenario_name else "Kubernetes Pod", |
| "affected_users": 45000, |
| "revenue_risk_per_hour": 8500 if "Cache" in scenario_name else 4200 |
| }, |
| "agents": { |
| "detection": { |
| "status": "active", |
| "confidence": 94, |
| "data_points_analyzed": 1245, |
| "anomaly_score": 0.92 |
| }, |
| "recall": { |
| "status": "active", |
| "similar_incidents": 3, |
| "best_match_similarity": 87, |
| "previous_success_rate": "92%" |
| }, |
| "decision": { |
| "status": "active", |
| "healing_intent_created": True, |
| "confidence": 89, |
| "recommended_action": "Scale Redis cluster from 3 to 5 nodes", |
| "estimated_recovery": "12 minutes", |
| "safety_check": "passed" |
| } |
| }, |
| "healing_intent": { |
| "action": "Scale Redis cluster from 3 to 5 nodes", |
| "confidence": 89, |
| "estimated_impact": "Reduce MTTR from 45min to 12min", |
| "cost_savings": 6375, |
| "safety_guarantees": ["rollback_available", "atomic_execution", "resource_isolation"] |
| }, |
| "boundary_note": "OSS analysis complete. HealingIntent created. Requires Enterprise license for execution.", |
| "arf_version": "3.3.9", |
| "license_required": "Enterprise for execution" |
| } |
| |
| |
| if ARF_OSS_AVAILABLE: |
| analysis_results["arf_mode"] = "real" |
| analysis_results["arf_components"] = ["TelemetryCollector", "ReliabilityAnalyzer", "AutoHealingEngine"] |
| else: |
| analysis_results["arf_mode"] = "mock" |
| analysis_results["arf_components"] = ["simulated"] |
| |
| logger.info(f"β
ARF analysis completed for {scenario_name}") |
| return analysis_results |
| |
| except Exception as e: |
| logger.error(f"Error in ARF analysis: {e}") |
| return { |
| "status": "error", |
| "error": str(e), |
| "scenario": scenario_name, |
| "timestamp": datetime.now().isoformat(), |
| "arf_version": "3.3.9", |
| "recommendation": "Check ARF installation: pip install agentic-reliability-framework==3.3.9" |
| } |
|
|
| def execute_enterprise_healing(scenario_name: str, approval_required: bool = False, |
| mcp_mode: str = "advisory") -> Dict[str, Any]: |
| """ |
| Execute enterprise healing - returns JSON/dict instead of HTML |
| FIXED: Returns dict for gr.JSON() component |
| """ |
| try: |
| |
| import time |
| time.sleep(0.7) |
| |
| |
| impact_values = { |
| "Cache Miss Storm": 8500, |
| "Database Connection Pool Exhaustion": 4200, |
| "Kubernetes Memory Leak": 5500, |
| "API Rate Limit Storm": 3800, |
| "Network Partition": 12000, |
| "Storage I/O Saturation": 6800 |
| } |
| |
| impact = impact_values.get(scenario_name, 5000) |
| savings = int(impact * 0.85) |
| |
| |
| execution_results = { |
| "status": "success", |
| "scenario": scenario_name, |
| "execution_timestamp": datetime.now().isoformat(), |
| "mode": mcp_mode, |
| "approval_required": approval_required, |
| "approval_status": "auto_approved" if not approval_required else "pending_human", |
| "execution": { |
| "action_executed": "Scale Redis cluster from 3 to 5 nodes", |
| "execution_time": "2 minutes", |
| "start_time": (datetime.now() - timedelta(minutes=2)).isoformat(), |
| "end_time": datetime.now().isoformat(), |
| "status": "completed", |
| "rollback_available": True, |
| "atomic_guarantee": True |
| }, |
| "results": { |
| "recovery_time": "12 minutes", |
| "manual_comparison": "45 minutes", |
| "time_saved": "33 minutes (73%)", |
| "cost_saved": f"${savings:,}", |
| "users_protected": 45000, |
| "services_restored": 12, |
| "error_rate_reduction": "94%", |
| "latency_improvement": "67%" |
| }, |
| "safety_features": { |
| "rollback_guarantee": "100%", |
| "mcp_validation": "passed", |
| "resource_isolation": "enforced", |
| "blast_radius": "2 services", |
| "dry_run_completed": True, |
| "safety_checks_passed": 8 |
| }, |
| "learning": { |
| "pattern_added_to_memory": True, |
| "similarity_score": 87, |
| "success_marked": True, |
| "next_improvement": "Optimize cache eviction policy" |
| }, |
| "enterprise_features": { |
| "autonomous_execution": True, |
| "mcp_integration": True, |
| "audit_trail": True, |
| "compliance_logging": True, |
| "multi_cloud_support": True |
| }, |
| "boundary_context": "Enterprise execution simulated. Real execution requires ARF Enterprise license.", |
| "arf_version": "3.3.9", |
| "enterprise_required": True, |
| "license_status": "simulated" |
| } |
| |
| |
| if approval_required: |
| execution_results["human_workflow"] = { |
| "step": "awaiting_approval", |
| "approver": "system_admin", |
| "timeout": "5 minutes", |
| "escalation_path": "senior_engineer" |
| } |
| |
| logger.info(f"β
Enterprise healing executed for {scenario_name}") |
| return execution_results |
| |
| except Exception as e: |
| logger.error(f"Error in enterprise execution: {e}") |
| return { |
| "status": "error", |
| "error": str(e), |
| "scenario": scenario_name, |
| "timestamp": datetime.now().isoformat(), |
| "recommendation": "Enterprise license required for execution", |
| "contact": "sales@arf.dev" |
| } |
|
|
| |
| |
| |
|
|
| def update_scenario_display(scenario_name: str) -> Tuple[Any, go.Figure, go.Figure, go.Figure]: |
| """ |
| Update scenario display - returns Plotly figures, not HTML strings |
| FIXED: Returns tuple of (scenario_card_html, telemetry_fig, impact_fig, timeline_fig) |
| Note: First element is still HTML for the scenario card, but visualizations are Plotly figures |
| """ |
| try: |
| |
| scenarios = { |
| "Cache Miss Storm": { |
| "component": "Redis Cache Cluster", |
| "severity": "HIGH", |
| "business_impact": {"revenue_loss_per_hour": 8500}, |
| "metrics": {"affected_users": 45000} |
| }, |
| "Database Connection Pool Exhaustion": { |
| "component": "PostgreSQL Database", |
| "severity": "HIGH", |
| "business_impact": {"revenue_loss_per_hour": 4200}, |
| "metrics": {"affected_users": 28000} |
| }, |
| "Kubernetes Memory Leak": { |
| "component": "Kubernetes Worker Node", |
| "severity": "MEDIUM", |
| "business_impact": {"revenue_loss_per_hour": 5500}, |
| "metrics": {"affected_users": 32000} |
| } |
| } |
| |
| scenario = scenarios.get(scenario_name, { |
| "component": "Unknown System", |
| "severity": "MEDIUM", |
| "business_impact": {"revenue_loss_per_hour": 5000}, |
| "metrics": {"affected_users": 25000} |
| }) |
| |
| |
| severity_colors = { |
| "HIGH": "#ef4444", |
| "MEDIUM": "#f59e0b", |
| "LOW": "#10b981" |
| } |
| severity_color = severity_colors.get(scenario["severity"], "#64748b") |
| |
| scenario_card_html = f""" |
| <div style="border: 1px solid {severity_color}; border-radius: 14px; padding: 20px; |
| background: linear-gradient(135deg, {severity_color}10 0%, #ffffff 100%);"> |
| |
| <div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 15px;"> |
| <div> |
| <h3 style="margin: 0 0 8px 0; font-size: 18px; color: #1e293b; font-weight: 700;"> |
| {scenario_name} |
| </h3> |
| <div style="display: flex; align-items: center; gap: 10px;"> |
| <div style="padding: 4px 12px; background: {severity_color}; color: white; |
| border-radius: 12px; font-size: 12px; font-weight: bold;"> |
| {scenario["severity"]} SEVERITY |
| </div> |
| <div style="font-size: 13px; color: #64748b;"> |
| {scenario["component"]} |
| </div> |
| </div> |
| </div> |
| |
| <div style="text-align: right;"> |
| <div style="font-size: 28px; font-weight: 700; color: {severity_color};"> |
| ${scenario["business_impact"]["revenue_loss_per_hour"]:,} |
| </div> |
| <div style="font-size: 12px; color: #64748b;"> |
| Revenue Loss/Hour |
| </div> |
| </div> |
| </div> |
| |
| <!-- Impact breakdown --> |
| <div style="margin-top: 20px; padding-top: 20px; border-top: 1px solid #f1f5f9;"> |
| <div style="font-size: 14px; color: #475569; font-weight: 600; margin-bottom: 10px;"> |
| Business Impact Analysis |
| </div> |
| <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px;"> |
| <div style="text-align: center;"> |
| <div style="font-size: 16px; font-weight: 700; color: {severity_color};">45 min</div> |
| <div style="font-size: 11px; color: #64748b;">Without ARF</div> |
| </div> |
| <div style="text-align: center;"> |
| <div style="font-size: 16px; font-weight: 700; color: #10b981;">12 min</div> |
| <div style="font-size: 11px; color: #64748b;">With ARF</div> |
| </div> |
| <div style="text-align: center;"> |
| <div style="font-size: 16px; font-weight: 700; color: #10b981;">${int(scenario["business_impact"]["revenue_loss_per_hour"] * 0.85):,}</div> |
| <div style="font-size: 11px; color: #64748b;">Savings/Hour</div> |
| </div> |
| </div> |
| </div> |
| |
| <!-- ARF detection info --> |
| <div style="margin-top: 20px; padding: 12px; background: #f8fafc; border-radius: 8px; |
| border-left: 3px solid {severity_color}; font-size: 12px; color: #475569;"> |
| <strong>ARF Detection:</strong> Detected in 45s with 94% confidence. |
| {scenario["metrics"]["affected_users"]:,} users affected. |
| </div> |
| </div> |
| """ |
| |
| |
| telemetry_fig = create_simple_telemetry_plot(scenario_name, DEMO_CONFIG["use_true_arf"]) |
| impact_fig = create_simple_impact_plot(scenario_name, DEMO_CONFIG["use_true_arf"]) |
| timeline_fig = create_timeline_plot(scenario_name, DEMO_CONFIG["use_true_arf"]) |
| |
| return scenario_card_html, telemetry_fig, impact_fig, timeline_fig |
| |
| except Exception as e: |
| logger.error(f"Error updating scenario display: {e}") |
| |
| error_html = f""" |
| <div style="border: 1px solid #ef4444; border-radius: 14px; padding: 20px; background: #fef2f2;"> |
| <h3 style="margin: 0 0 10px 0; color: #dc2626;">Error loading scenario</h3> |
| <p style="margin: 0; color: #b91c1c;">{str(e)}</p> |
| </div> |
| """ |
| return error_html, create_empty_plot("Error"), create_empty_plot("Error"), create_empty_plot("Error") |
|
|
| |
| |
| |
|
|
| def get_installation_status() -> Dict[str, Any]: |
| """ |
| Get installation status - returns JSON/dict |
| FIXED: Returns dict for gr.JSON() component |
| """ |
| installation = { |
| "oss_installed": ARF_OSS_AVAILABLE, |
| "enterprise_installed": False, |
| "oss_version": "3.3.9" if ARF_OSS_AVAILABLE else "not_installed", |
| "enterprise_version": "not_installed", |
| "execution_allowed": False, |
| "recommendations": [ |
| "OSS provides advisory analysis only", |
| "Enterprise required for autonomous execution" |
| ], |
| "badges": { |
| "oss": { |
| "text": "β
ARF OSS v3.3.9" if ARF_OSS_AVAILABLE else "β οΈ Mock ARF", |
| "color": "#10b981" if ARF_OSS_AVAILABLE else "#f59e0b", |
| "icon": "β
" if ARF_OSS_AVAILABLE else "β οΈ" |
| }, |
| "enterprise": { |
| "text": "π Enterprise Required", |
| "color": "#64748b", |
| "icon": "π" |
| } |
| }, |
| "timestamp": datetime.now().isoformat(), |
| "components_available": ["TelemetryCollector", "ReliabilityAnalyzer", "AutoHealingEngine"] if ARF_OSS_AVAILABLE else ["simulated"], |
| "license": "Apache 2.0" if ARF_OSS_AVAILABLE else "demo" |
| } |
| return installation |
|
|
| def get_installation_badges() -> str: |
| """ |
| Get installation badges as HTML |
| This is fine as it's used by gr.HTML() |
| """ |
| installation = get_installation_status() |
| oss_badge = installation["badges"]["oss"] |
| enterprise_badge = installation["badges"]["enterprise"] |
| |
| return f""" |
| <div style="display: flex; justify-content: center; gap: 10px; margin-top: 10px; flex-wrap: wrap;"> |
| <span style="padding: 4px 12px; background: {oss_badge['color']}; |
| color: white; border-radius: 20px; font-size: 12px; font-weight: bold; |
| display: flex; align-items: center; gap: 6px;"> |
| {oss_badge['icon']} {oss_badge['text']} |
| </span> |
| <span style="padding: 4px 12px; background: {enterprise_badge['color']}; |
| color: white; border-radius: 20px; font-size: 12px; font-weight: bold; |
| display: flex; align-items: center; gap: 6px;"> |
| {enterprise_badge['icon']} {enterprise_badge['text']} |
| </span> |
| </div> |
| """ |
|
|
| |
| |
| |
|
|
| def calculate_roi(scenario_name: str, monthly_incidents: int, team_size: int) -> Tuple[Dict[str, Any], go.Figure]: |
| """ |
| Calculate ROI - returns dict and Plotly figure |
| FIXED: Returns (dict, Plotly figure) for (gr.JSON(), gr.Plot()) |
| """ |
| try: |
| |
| impact_per_incident = { |
| "Cache Miss Storm": 8500, |
| "Database Connection Pool Exhaustion": 4200, |
| "Kubernetes Memory Leak": 5500, |
| "API Rate Limit Storm": 3800, |
| "Network Partition": 12000, |
| "Storage I/O Saturation": 6800 |
| }.get(scenario_name, 5000) |
| |
| |
| annual_impact = impact_per_incident * monthly_incidents * 12 |
| potential_savings = int(annual_impact * 0.82) |
| enterprise_cost = 625000 |
| roi_multiplier = round(potential_savings / enterprise_cost, 1) |
| payback_months = round((enterprise_cost / (potential_savings / 12)), 1) |
| annual_roi = int((potential_savings - enterprise_cost) / enterprise_cost * 100) |
| |
| |
| roi_results = { |
| "status": "success", |
| "scenario": scenario_name, |
| "inputs": { |
| "monthly_incidents": monthly_incidents, |
| "team_size": team_size, |
| "impact_per_incident": f"${impact_per_incident:,}" |
| }, |
| "calculations": { |
| "annual_impact_without_arf": f"${annual_impact:,}", |
| "potential_savings_with_arf": f"${potential_savings:,}", |
| "enterprise_annual_cost": f"${enterprise_cost:,}", |
| "roi_multiplier": f"{roi_multiplier}Γ", |
| "payback_months": f"{payback_months}", |
| "annual_roi_percentage": f"{annual_roi}%", |
| "net_annual_savings": f"${potential_savings - enterprise_cost:,}" |
| }, |
| "breakdown": { |
| "engineer_cost_savings": f"${team_size * 200000 * 0.3:,}", |
| "incident_cost_savings": f"${potential_savings - (team_size * 200000 * 0.3):,}", |
| "total_opportunity": f"${potential_savings:,}" |
| }, |
| "recommendation": f"ARF Enterprise provides {roi_multiplier}Γ ROI with {payback_months}-month payback", |
| "timestamp": datetime.now().isoformat(), |
| "arf_version": "3.3.9" |
| } |
| |
| |
| categories = ['Without ARF', 'With ARF', 'Net Savings'] |
| values = [annual_impact, annual_impact - potential_savings, potential_savings - enterprise_cost] |
| colors = ['#ef4444', '#10b981', '#8b5cf6'] |
| |
| fig = go.Figure(data=[ |
| go.Bar( |
| name='Annual Cost', |
| x=categories, |
| y=values, |
| marker_color=colors, |
| text=[f'${v:,.0f}' for v in values], |
| textposition='auto', |
| ) |
| ]) |
| |
| fig.update_layout( |
| title=dict( |
| text=f"ROI Analysis: {scenario_name}", |
| font=dict(size=18, color='#1e293b') |
| ), |
| xaxis_title="Scenario", |
| yaxis_title="Annual Cost ($)", |
| height=400, |
| plot_bgcolor='white', |
| showlegend=False, |
| margin=dict(l=20, r=20, t=60, b=20) |
| ) |
| |
| |
| fig.add_annotation( |
| x=2, y=values[2] * 1.1, |
| text=f"ROI: {roi_multiplier}Γ", |
| showarrow=False, |
| font=dict(size=14, color="#8b5cf6", weight="bold"), |
| bgcolor="rgba(139, 92, 246, 0.1)", |
| borderpad=4 |
| ) |
| |
| logger.info(f"β
ROI calculated for {scenario_name}") |
| return roi_results, fig |
| |
| except Exception as e: |
| logger.error(f"Error calculating ROI: {e}") |
| error_results = { |
| "status": "error", |
| "error": str(e), |
| "scenario": scenario_name, |
| "timestamp": datetime.now().isoformat() |
| } |
| return error_results, create_empty_plot("ROI Calculation Error") |
|
|
| |
| |
| |
|
|
| def create_demo_interface(): |
| """Create the demo interface with fixed data types""" |
| with gr.Blocks(title="ARF OSS v3.3.9 Demo", theme=gr.themes.Soft()) as demo: |
| gr.Markdown("# π ARF OSS v3.3.9 Demo") |
| gr.Markdown("### Agentic Reliability Framework - OSS Edition") |
| |
| |
| installation = get_installation_status() |
| gr.Markdown(f"**Status:** {installation['badges']['oss']['text']}") |
| |
| |
| scenario_dropdown = gr.Dropdown( |
| choices=[ |
| "Cache Miss Storm", |
| "Database Connection Pool Exhaustion", |
| "Kubernetes Memory Leak", |
| "API Rate Limit Storm", |
| "Network Partition", |
| "Storage I/O Saturation" |
| ], |
| value="Cache Miss Storm", |
| label="Select Scenario" |
| ) |
| |
| |
| update_btn = gr.Button("Update Display", variant="primary") |
| |
| |
| with gr.Row(): |
| with gr.Column(scale=1): |
| scenario_card = gr.HTML(label="Scenario Details") |
| |
| with gr.Column(scale=2): |
| telemetry_plot = gr.Plot(label="Telemetry") |
| impact_plot = gr.Plot(label="Business Impact") |
| timeline_plot = gr.Plot(label="Timeline Comparison") |
| |
| |
| with gr.Row(): |
| analyze_btn = gr.Button("π Run OSS Analysis", variant="secondary") |
| execute_btn = gr.Button("β‘ Execute Enterprise Healing", variant="primary") |
| |
| |
| with gr.Row(): |
| with gr.Column(scale=1): |
| analysis_results = gr.JSON(label="OSS Analysis Results") |
| |
| with gr.Column(scale=1): |
| execution_results = gr.JSON(label="Enterprise Execution Results") |
| |
| |
| gr.Markdown("## π° ROI Calculator") |
| with gr.Row(): |
| roi_scenario = gr.Dropdown( |
| choices=[ |
| "Cache Miss Storm", |
| "Database Connection Pool Exhaustion", |
| "Kubernetes Memory Leak" |
| ], |
| value="Cache Miss Storm", |
| label="Scenario" |
| ) |
| monthly_incidents = gr.Slider(1, 50, value=15, label="Monthly Incidents") |
| team_size = gr.Slider(1, 20, value=5, label="Team Size") |
| |
| roi_btn = gr.Button("Calculate ROI", variant="primary") |
| |
| with gr.Row(): |
| roi_output = gr.JSON(label="ROI Results") |
| roi_chart = gr.Plot(label="ROI Visualization") |
| |
| |
| |
| |
| update_btn.click( |
| fn=update_scenario_display, |
| inputs=[scenario_dropdown], |
| outputs=[scenario_card, telemetry_plot, impact_plot, timeline_plot] |
| ) |
| |
| scenario_dropdown.change( |
| fn=update_scenario_display, |
| inputs=[scenario_dropdown], |
| outputs=[scenario_card, telemetry_plot, impact_plot, timeline_plot] |
| ) |
| |
| |
| analyze_btn.click( |
| fn=run_true_arf_analysis, |
| inputs=[scenario_dropdown], |
| outputs=[analysis_results] |
| ) |
| |
| |
| execute_btn.click( |
| fn=execute_enterprise_healing, |
| inputs=[scenario_dropdown], |
| outputs=[execution_results] |
| ) |
| |
| |
| roi_btn.click( |
| fn=calculate_roi, |
| inputs=[roi_scenario, monthly_incidents, team_size], |
| outputs=[roi_output, roi_chart] |
| ) |
| |
| |
| demo.load( |
| fn=lambda: update_scenario_display("Cache Miss Storm"), |
| inputs=[], |
| outputs=[scenario_card, telemetry_plot, impact_plot, timeline_plot] |
| ) |
| |
| return demo |
|
|
| def main(): |
| """Main entry point""" |
| logger.info("=" * 60) |
| logger.info("π ARF OSS v3.3.9 Demo Application") |
| logger.info(f"β
ARF OSS Available: {ARF_OSS_AVAILABLE}") |
| logger.info("=" * 60) |
| |
| demo = create_demo_interface() |
| demo.launch( |
| server_name="0.0.0.0", |
| server_port=7860, |
| share=False |
| ) |
|
|
| if __name__ == "__main__": |
| main() |