Create app.py
Browse files
app.py
CHANGED
|
@@ -40,6 +40,7 @@ from models import (
|
|
| 40 |
)
|
| 41 |
from claude_adapter import get_claude_adapter
|
| 42 |
from healing_policies import PolicyEngine, DEFAULT_HEALING_POLICIES
|
|
|
|
| 43 |
|
| 44 |
# === Logging Configuration ===
|
| 45 |
logging.basicConfig(
|
|
@@ -1544,6 +1545,39 @@ class EnhancedReliabilityEngine:
|
|
| 1544 |
logger.error(f"Failed to enhance with Claude: {e}")
|
| 1545 |
# Continue without enhancement
|
| 1546 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1547 |
return result
|
| 1548 |
|
| 1549 |
async def enhance_with_claude(
|
|
@@ -1631,6 +1665,9 @@ Focus on clarity, accuracy, and decisive recommendations."""
|
|
| 1631 |
# === Initialize Engine (with dependency injection) ===
|
| 1632 |
enhanced_engine = EnhancedReliabilityEngine()
|
| 1633 |
|
|
|
|
|
|
|
|
|
|
| 1634 |
|
| 1635 |
# === Rate Limiting ===
|
| 1636 |
class RateLimiter:
|
|
@@ -1725,6 +1762,15 @@ def create_enhanced_ui():
|
|
| 1725 |
lines=6
|
| 1726 |
)
|
| 1727 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1728 |
with gr.Accordion("π€ Agent Specialists Analysis", open=False):
|
| 1729 |
gr.Markdown("""
|
| 1730 |
**Specialized AI Agents:**
|
|
@@ -1814,7 +1860,7 @@ def create_enhanced_ui():
|
|
| 1814 |
allowed, rate_msg = rate_limiter.is_allowed()
|
| 1815 |
if not allowed:
|
| 1816 |
logger.warning(f"Rate limit exceeded")
|
| 1817 |
-
return rate_msg, {}, {}, "*Rate limit exceeded*", gr.Dataframe(value=[])
|
| 1818 |
|
| 1819 |
# Type conversion
|
| 1820 |
try:
|
|
@@ -1826,7 +1872,7 @@ def create_enhanced_ui():
|
|
| 1826 |
except (ValueError, TypeError) as e:
|
| 1827 |
error_msg = f"β Invalid input types: {str(e)}"
|
| 1828 |
logger.warning(error_msg)
|
| 1829 |
-
return error_msg, {}, {}, "*Invalid input type*", gr.Dataframe(value=[])
|
| 1830 |
|
| 1831 |
# Input validation
|
| 1832 |
is_valid, error_msg = validate_inputs(
|
|
@@ -1834,7 +1880,7 @@ def create_enhanced_ui():
|
|
| 1834 |
)
|
| 1835 |
if not is_valid:
|
| 1836 |
logger.warning(f"Invalid input: {error_msg}")
|
| 1837 |
-
return error_msg, {}, {}, "*Validation failed*", gr.Dataframe(value=[])
|
| 1838 |
|
| 1839 |
# FIXED: Direct async call - no event loop creation needed
|
| 1840 |
result = await enhanced_engine.process_event_enhanced(
|
|
@@ -1843,7 +1889,7 @@ def create_enhanced_ui():
|
|
| 1843 |
|
| 1844 |
# Handle errors
|
| 1845 |
if 'error' in result:
|
| 1846 |
-
return f"β {result['error']}", {}, {}, "*Error occurred*", gr.Dataframe(value=[])
|
| 1847 |
|
| 1848 |
# Build table data (THREAD-SAFE)
|
| 1849 |
table_data = []
|
|
@@ -1905,6 +1951,14 @@ def create_enhanced_ui():
|
|
| 1905 |
*Model: {claude_synthesis.get('source', 'claude-opus-4')}*
|
| 1906 |
"""
|
| 1907 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1908 |
return (
|
| 1909 |
output_msg,
|
| 1910 |
agent_insights_data,
|
|
@@ -1914,19 +1968,20 @@ def create_enhanced_ui():
|
|
| 1914 |
headers=["Timestamp", "Component", "Latency", "Error Rate", "Throughput", "Severity", "Analysis"],
|
| 1915 |
value=table_data,
|
| 1916 |
wrap=True
|
| 1917 |
-
)
|
|
|
|
| 1918 |
)
|
| 1919 |
|
| 1920 |
except Exception as e:
|
| 1921 |
error_msg = f"β Error processing event: {str(e)}"
|
| 1922 |
logger.error(error_msg, exc_info=True)
|
| 1923 |
-
return error_msg, {}, {}, "*Processing error*", gr.Dataframe(value=[])
|
| 1924 |
|
| 1925 |
# FIXED: Use async handler directly
|
| 1926 |
submit_btn.click(
|
| 1927 |
fn=submit_event_enhanced_async,
|
| 1928 |
inputs=[component, latency, error_rate, throughput, cpu_util, memory_util],
|
| 1929 |
-
outputs=[output_text, agent_insights, predictive_insights, claude_output, events_table]
|
| 1930 |
)
|
| 1931 |
|
| 1932 |
return demo
|
|
|
|
| 40 |
)
|
| 41 |
from claude_adapter import get_claude_adapter
|
| 42 |
from healing_policies import PolicyEngine, DEFAULT_HEALING_POLICIES
|
| 43 |
+
from voice_narrator import VoiceHandler
|
| 44 |
|
| 45 |
# === Logging Configuration ===
|
| 46 |
logging.basicConfig(
|
|
|
|
| 1545 |
logger.error(f"Failed to enhance with Claude: {e}")
|
| 1546 |
# Continue without enhancement
|
| 1547 |
|
| 1548 |
+
# === Generate voice alert for anomalies ===
|
| 1549 |
+
if is_anomaly and voice_handler:
|
| 1550 |
+
try:
|
| 1551 |
+
# Extract diagnosis and action from results
|
| 1552 |
+
diagnosis = "System anomaly detected"
|
| 1553 |
+
action = "INVESTIGATE"
|
| 1554 |
+
|
| 1555 |
+
if agent_analysis and 'recommended_actions' in agent_analysis:
|
| 1556 |
+
actions = agent_analysis['recommended_actions']
|
| 1557 |
+
if actions:
|
| 1558 |
+
diagnosis = actions[0][:100] # First recommendation, truncated
|
| 1559 |
+
|
| 1560 |
+
if healing_actions:
|
| 1561 |
+
action = healing_actions[0].value if healing_actions else "INVESTIGATE"
|
| 1562 |
+
|
| 1563 |
+
# Generate voice alert
|
| 1564 |
+
logger.info(f"Generating voice alert for {component}")
|
| 1565 |
+
audio_file = voice_handler.speak_alert(
|
| 1566 |
+
diagnosis=diagnosis,
|
| 1567 |
+
action=action,
|
| 1568 |
+
output_filename=f"alert_{component}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.mp3"
|
| 1569 |
+
)
|
| 1570 |
+
|
| 1571 |
+
if audio_file:
|
| 1572 |
+
result['audio_file'] = audio_file
|
| 1573 |
+
logger.info(f"β
Voice alert generated: {audio_file}")
|
| 1574 |
+
else:
|
| 1575 |
+
logger.warning("Voice generation returned no file")
|
| 1576 |
+
|
| 1577 |
+
except Exception as e:
|
| 1578 |
+
logger.error(f"Voice generation failed (non-critical): {e}", exc_info=True)
|
| 1579 |
+
# === End voice integration ===
|
| 1580 |
+
|
| 1581 |
return result
|
| 1582 |
|
| 1583 |
async def enhance_with_claude(
|
|
|
|
| 1665 |
# === Initialize Engine (with dependency injection) ===
|
| 1666 |
enhanced_engine = EnhancedReliabilityEngine()
|
| 1667 |
|
| 1668 |
+
# === Initialize Voice Handler ===
|
| 1669 |
+
voice_handler = VoiceHandler()
|
| 1670 |
+
logger.info("Voice handler initialized")
|
| 1671 |
|
| 1672 |
# === Rate Limiting ===
|
| 1673 |
class RateLimiter:
|
|
|
|
| 1762 |
lines=6
|
| 1763 |
)
|
| 1764 |
|
| 1765 |
+
# === ADD AUDIO PLAYER ===
|
| 1766 |
+
audio_output = gr.Audio(
|
| 1767 |
+
label="π Voice Alert",
|
| 1768 |
+
type="filepath",
|
| 1769 |
+
visible=False,
|
| 1770 |
+
autoplay=True
|
| 1771 |
+
)
|
| 1772 |
+
# === END AUDIO PLAYER ===
|
| 1773 |
+
|
| 1774 |
with gr.Accordion("π€ Agent Specialists Analysis", open=False):
|
| 1775 |
gr.Markdown("""
|
| 1776 |
**Specialized AI Agents:**
|
|
|
|
| 1860 |
allowed, rate_msg = rate_limiter.is_allowed()
|
| 1861 |
if not allowed:
|
| 1862 |
logger.warning(f"Rate limit exceeded")
|
| 1863 |
+
return rate_msg, {}, {}, "*Rate limit exceeded*", gr.Dataframe(value=[]), gr.Audio(visible=False)
|
| 1864 |
|
| 1865 |
# Type conversion
|
| 1866 |
try:
|
|
|
|
| 1872 |
except (ValueError, TypeError) as e:
|
| 1873 |
error_msg = f"β Invalid input types: {str(e)}"
|
| 1874 |
logger.warning(error_msg)
|
| 1875 |
+
return error_msg, {}, {}, "*Invalid input type*", gr.Dataframe(value=[]), gr.Audio(visible=False)
|
| 1876 |
|
| 1877 |
# Input validation
|
| 1878 |
is_valid, error_msg = validate_inputs(
|
|
|
|
| 1880 |
)
|
| 1881 |
if not is_valid:
|
| 1882 |
logger.warning(f"Invalid input: {error_msg}")
|
| 1883 |
+
return error_msg, {}, {}, "*Validation failed*", gr.Dataframe(value=[]), gr.Audio(visible=False)
|
| 1884 |
|
| 1885 |
# FIXED: Direct async call - no event loop creation needed
|
| 1886 |
result = await enhanced_engine.process_event_enhanced(
|
|
|
|
| 1889 |
|
| 1890 |
# Handle errors
|
| 1891 |
if 'error' in result:
|
| 1892 |
+
return f"β {result['error']}", {}, {}, "*Error occurred*", gr.Dataframe(value=[]), gr.Audio(visible=False)
|
| 1893 |
|
| 1894 |
# Build table data (THREAD-SAFE)
|
| 1895 |
table_data = []
|
|
|
|
| 1951 |
*Model: {claude_synthesis.get('source', 'claude-opus-4')}*
|
| 1952 |
"""
|
| 1953 |
|
| 1954 |
+
# === Extract audio file if present ===
|
| 1955 |
+
audio_file = result.get('audio_file', None)
|
| 1956 |
+
audio_visible = audio_file is not None
|
| 1957 |
+
|
| 1958 |
+
if audio_file:
|
| 1959 |
+
logger.info(f"Audio alert available: {audio_file}")
|
| 1960 |
+
# === End audio extraction ===
|
| 1961 |
+
|
| 1962 |
return (
|
| 1963 |
output_msg,
|
| 1964 |
agent_insights_data,
|
|
|
|
| 1968 |
headers=["Timestamp", "Component", "Latency", "Error Rate", "Throughput", "Severity", "Analysis"],
|
| 1969 |
value=table_data,
|
| 1970 |
wrap=True
|
| 1971 |
+
),
|
| 1972 |
+
gr.Audio(value=audio_file, visible=audio_visible)
|
| 1973 |
)
|
| 1974 |
|
| 1975 |
except Exception as e:
|
| 1976 |
error_msg = f"β Error processing event: {str(e)}"
|
| 1977 |
logger.error(error_msg, exc_info=True)
|
| 1978 |
+
return error_msg, {}, {}, "*Processing error*", gr.Dataframe(value=[]), gr.Audio(visible=False)
|
| 1979 |
|
| 1980 |
# FIXED: Use async handler directly
|
| 1981 |
submit_btn.click(
|
| 1982 |
fn=submit_event_enhanced_async,
|
| 1983 |
inputs=[component, latency, error_rate, throughput, cpu_util, memory_util],
|
| 1984 |
+
outputs=[output_text, agent_insights, predictive_insights, claude_output, events_table, audio_output]
|
| 1985 |
)
|
| 1986 |
|
| 1987 |
return demo
|