import streamlit as st
from datetime import datetime
from typing import Optional, Dict, Any
import os
from ..agent import HealthcareAgent
from ..models.state import TaskType, PriorityLevel
from ..utils.logger import setup_logger
logger = setup_logger(__name__)
class HealthcareUI:
def __init__(self):
"""Initialize the Healthcare Operations Management UI"""
try:
# Set up Streamlit page configuration
st.set_page_config(
page_title="Healthcare Operations Assistant",
page_icon="🏥",
layout="wide",
initial_sidebar_state="expanded",
menu_items={
'About': "Healthcare Operations Management AI Assistant",
'Report a bug': "https://github.com/yourusername/repo/issues",
'Get Help': "https://your-docs-url"
}
)
# Apply custom theme
self.setup_theme()
# Initialize the agent
self.agent = HealthcareAgent(os.getenv("OPENAI_API_KEY"))
# Initialize session state variables only if not already set
if 'initialized' not in st.session_state:
st.session_state.initialized = True
st.session_state.messages = []
st.session_state.thread_id = datetime.now().strftime("%Y%m%d-%H%M%S")
st.session_state.current_department = "All Departments"
st.session_state.metrics_history = []
st.session_state.system_status = True
except Exception as e:
logger.error(f"Error initializing UI: {str(e)}")
st.error("Failed to initialize the application. Please refresh the page.")
def setup_theme(self):
"""Configure the UI theme and styling"""
st.markdown("""
""", unsafe_allow_html=True)
def render_header(self):
"""Render the application header"""
try:
header_container = st.container()
with header_container:
col1, col2, col3 = st.columns([1, 4, 1])
with col1:
st.markdown("# 🏥")
with col2:
st.title("Healthcare Operations Assistant")
st.markdown("*Your AI-powered healthcare operations management solution* 🤖")
with col3:
# System status indicator
status = "🟢 Online" if st.session_state.system_status else "🔴 Offline"
st.markdown(f"### {status}")
except Exception as e:
logger.error(f"Error rendering header: {str(e)}")
st.error("Error loading header section")
def render_metrics(self, metrics: Optional[Dict[str, Any]] = None):
"""Render the metrics dashboard"""
try:
if not metrics:
metrics = {
"patient_flow": {"occupied_beds": 75, "total_beds": 100},
"quality": {"patient_satisfaction": 8.5},
"staffing": {"available_staff": {"doctors": 20, "nurses": 50}},
"resources": {"resource_utilization": 0.75}
}
st.markdown("### 📊 Key Metrics Dashboard")
metrics_container = st.container()
with metrics_container:
# First row - Key metrics
col1, col2, col3, col4 = st.columns(4)
with col1:
occupancy = (metrics['patient_flow']['occupied_beds'] /
metrics['patient_flow']['total_beds'] * 100)
st.metric(
"Bed Occupancy 🛏️",
f"{occupancy:.1f}%",
"Normal 🟢" if occupancy < 85 else "High 🟡"
)
with col2:
satisfaction = metrics['quality']['patient_satisfaction']
st.metric(
"Patient Satisfaction 😊",
f"{satisfaction}/10",
"↗ +0.5" if satisfaction > 8 else "↘ -0.3"
)
with col3:
total_staff = sum(metrics['staffing']['available_staff'].values())
st.metric(
"Available Staff 👥",
total_staff,
"Optimal 🟢" if total_staff > 80 else "Low 🔴"
)
with col4:
utilization = metrics['resources']['resource_utilization'] * 100
st.metric(
"Resource Utilization 📦",
f"{utilization:.1f}%",
"↘ -2%"
)
# Add metrics to history
st.session_state.metrics_history.append({
'timestamp': datetime.now(),
'metrics': metrics
})
except Exception as e:
logger.error(f"Error rendering metrics: {str(e)}")
st.error("Error loading metrics dashboard")
def render_chat(self):
"""Render the chat interface"""
try:
st.markdown("### 💬 Chat Interface")
chat_container = st.container()
with chat_container:
# Display chat messages
for message in st.session_state.messages:
role = message["role"]
content = message["content"]
timestamp = message.get("timestamp", datetime.now())
with st.chat_message(role, avatar="🤖" if role == "assistant" else "👤"):
st.markdown(content)
st.caption(f":clock2: {timestamp.strftime('%H:%M')}")
# Chat input
if prompt := st.chat_input("How can I assist you with healthcare operations today?"):
# Add user message
current_time = datetime.now()
st.session_state.messages.append({
"role": "user",
"content": prompt,
"timestamp": current_time
})
# Display user message
with st.chat_message("user", avatar="👤"):
st.markdown(prompt)
st.caption(f":clock2: {current_time.strftime('%H:%M')}")
# Display assistant response
with st.chat_message("assistant", avatar="🤖"):
with st.spinner("Processing your request... 🔄"):
try:
# Generate response based on query type
response = self._get_department_response(prompt)
# Display structured response
st.markdown("### 🔍 Key Insights")
st.markdown(response["insights"])
st.markdown("### 📋 Actionable Recommendations")
st.markdown(response["recommendations"])
st.markdown("### ⚡ Priority Actions")
st.markdown(response["priority_actions"])
st.markdown("### ⏰ Implementation Timeline")
st.markdown(response["timeline"])
# Update metrics if available
if "metrics" in response:
self.render_metrics(response["metrics"])
# Add to chat history
st.session_state.messages.append({
"role": "assistant",
"content": response["full_response"],
"timestamp": datetime.now()
})
except Exception as e:
st.error(f"Error processing request: {str(e)} ❌")
logger.error(f"Error in chat processing: {str(e)}")
except Exception as e:
logger.error(f"Error rendering chat interface: {str(e)}")
st.error("Error loading chat interface")
def _get_department_response(self, query: str) -> Dict[str, Any]:
"""Generate response based on query type"""
query = query.lower()
# Waiting times response
if "waiting" in query or "wait time" in query:
return {
"insights": """
📊 Current Department Wait Times:
- ER: 45 minutes (⚠️ Above target)
- ICU: 5 minutes (✅ Within target)
- General Ward: 25 minutes (✅ Within target)
- Surgery: 30 minutes (⚡ Approaching target)
- Pediatrics: 20 minutes (✅ Within target)
""",
"recommendations": """
1. 👥 Deploy additional triage nurses to ER
2. 🔄 Optimize patient handoff procedures
3. 📱 Implement real-time wait time updates
4. 🏥 Activate overflow protocols where needed
""",
"priority_actions": """
Immediate Actions Required:
- 🚨 Redirect non-emergency cases from ER
- 👨⚕️ Increase ER staffing for next 2 hours
- 📢 Update waiting patients every 15 minutes
""",
"timeline": """
Implementation Schedule:
- 🕐 0-1 hour: Staff reallocation
- 🕒 1-2 hours: Process optimization
- 🕓 2-4 hours: Situation reassessment
- 🕔 4+ hours: Long-term monitoring
""",
"metrics": {
"patient_flow": {
"occupied_beds": 85,
"total_beds": 100,
"waiting_patients": 18,
"average_wait_time": 35.0
},
"quality": {"patient_satisfaction": 7.8},
"staffing": {"available_staff": {"doctors": 22, "nurses": 55}},
"resources": {"resource_utilization": 0.82}
},
"full_response": "Based on current data, we're seeing elevated wait times in the ER department. Immediate actions have been recommended to address this situation."
}
# Bed occupancy response
elif "bed" in query or "occupancy" in query:
return {
"insights": """
🛏️ Current Bed Occupancy Status:
- Overall Occupancy: 85%
- Critical Care: 90% (⚠️ Near capacity)
- General Wards: 82% (✅ Optimal)
- Available Emergency Beds: 5
""",
"recommendations": """
1. 🔄 Review discharge plans
2. 🏥 Prepare overflow areas
3. 📋 Optimize bed turnover
4. 👥 Adjust staff allocation
""",
"priority_actions": """
Critical Actions:
- 🚨 Expedite planned discharges
- 🏥 Activate surge capacity plan
- 📊 Hourly capacity monitoring
""",
"timeline": """
Action Timeline:
- 🕐 Immediate: Discharge reviews
- 🕑 2 hours: Capacity reassessment
- 🕒 4 hours: Staff reallocation
- 🕓 8 hours: Full situation review
""",
"metrics": {
"patient_flow": {
"occupied_beds": 90,
"total_beds": 100,
"waiting_patients": 12,
"average_wait_time": 30.0
},
"quality": {"patient_satisfaction": 8.0},
"staffing": {"available_staff": {"doctors": 25, "nurses": 58}},
"resources": {"resource_utilization": 0.88}
},
"full_response": "Current bed occupancy is at 85% with critical care areas approaching capacity. Immediate actions are being taken to optimize bed utilization."
}
# Default response for other queries
else:
return {
"insights": """
Please specify your request:
- 🏥 Department specific information
- ⏰ Wait time inquiries
- 🛏️ Bed capacity status
- 👥 Staffing information
- 📊 Resource utilization
""",
"recommendations": "To better assist you, please provide more specific details about what you'd like to know.",
"priority_actions": "No immediate actions required. Awaiting specific inquiry.",
"timeline": "Timeline will be generated based on specific requests.",
"full_response": "I'm here to help! Please specify what information you need about healthcare operations."
}
def render_sidebar(self):
"""Render the sidebar with controls and filters"""
try:
with st.sidebar:
# Add custom CSS for consistent button styling
st.markdown("""
""", unsafe_allow_html=True)
st.markdown("### ⚙️ Settings")
# Department filter
if "department_filter" not in st.session_state:
st.session_state.department_filter = "All Departments"
st.selectbox(
"Select Department",
["All Departments", "ER", "ICU", "General Ward", "Surgery", "Pediatrics"],
key="department_filter"
)
# Priority filter
if "priority_filter" not in st.session_state:
st.session_state.priority_filter = "Medium"
st.select_slider(
"Priority Level",
options=["Low", "Medium", "High", "Urgent", "Critical"],
key="priority_filter"
)
# Time range
if "time_range_filter" not in st.session_state:
st.session_state.time_range_filter = 8
st.slider(
"Time Range (hours)",
min_value=1,
max_value=24,
key="time_range_filter"
)
# Quick actions with consistent styling
st.markdown("### ⚡ Quick Actions")
# Create two columns for buttons
col1, col2 = st.columns(2)
with col1:
if st.button("📊 Report"):
st.info("Generating comprehensive report...")
with col2:
if st.button("🔄 Refresh"):
st.success("Data refreshed successfully!")
# Emergency Mode
st.markdown("### 🚨 Emergency Mode")
if "emergency_mode" not in st.session_state:
st.session_state.emergency_mode = False
st.toggle(
"Activate Emergency Protocol",
key="emergency_mode",
help="Enable emergency mode for critical situations"
)
if st.session_state.emergency_mode:
st.warning("Emergency Mode Active!")
# Help section
st.markdown("### ❓ Help")
with st.expander("Usage Guide"):
st.markdown("""
- 💬 Use the chat to ask questions
- 📊 Monitor real-time metrics
- ⚙️ Adjust filters as needed
- 📋 Generate reports for analysis
- 🚨 Toggle emergency mode for critical situations
""")
# Footer
st.markdown("---")
st.caption(
f"*Last updated: {datetime.now().strftime('%H:%M:%S')}*"
)
except Exception as e:
logger.error(f"Error rendering sidebar: {str(e)}")
st.error("Error loading sidebar")
def run(self):
"""Run the Streamlit application"""
try:
# Main application container
main_container = st.container()
with main_container:
# Render components
self.render_header()
self.render_sidebar()
# Main content area
content_container = st.container()
with content_container:
self.render_metrics()
st.markdown("
", unsafe_allow_html=True) # Spacing
self.render_chat()
except Exception as e:
logger.error(f"Error running application: {str(e)}")
st.error(f"Application error: {str(e)} ❌")