""" Streamlit frontend for Smart Health Monitoring Agent """ import streamlit as st import pandas as pd import plotly.graph_objects as go import plotly.express as px from datetime import datetime import sys import os import numpy as np # Page configuration - MUST be first Streamlit command st.set_page_config( page_title="Smart Health Monitoring Agent", page_icon="🏥", layout="wide", initial_sidebar_state="expanded" ) # Add parent directory to path for imports sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) # Import custom modules with error handling try: from services.analysis_service import HealthAnalysisService from models.health import HealthAnalysis except ImportError as e: st.error(f"❌ Import Error: {e}") st.info("Make sure the 'services' and 'models' folders exist with the required files.") st.stop() # Custom CSS st.markdown(""" """, unsafe_allow_html=True) # Initialize session state if 'analysis' not in st.session_state: st.session_state.analysis = None if 'records_df' not in st.session_state: st.session_state.records_df = None # Helper functions def summarize_heart_rate_zones(df: pd.DataFrame) -> pd.DataFrame: """Compute HR zone distribution for visualization.""" def hr_zone(hr: float) -> str: if hr < 60: return "Resting" elif hr < 90: return "Light" elif hr < 120: return "Moderate" elif hr < 150: return "Intense" else: return "Peak" zones = df["Heart Rate (bpm)"].apply(hr_zone).value_counts().reset_index() zones.columns = ["Zone", "Count"] return zones def recommend_music_bpm(steps: float, hr: float) -> dict: """Lightweight music pacing recommendation.""" if steps > 9000 or hr >= 140: bpm = 150 mood = "High-energy run" elif steps > 6000 or hr >= 120: bpm = 140 mood = "Tempo / steady cardio" elif steps > 4000 or hr >= 100: bpm = 125 mood = "Brisk walk / light jog" else: bpm = 105 mood = "Recovery / focus" return {"bpm": bpm, "mood": mood} def stress_intervention_tip(stress_level: str) -> str: """Return an immediate intervention tip based on stress level.""" if stress_level == "High": return "Start 4-7-8 breathing now. Pause movement and hydrate." elif stress_level == "Moderate": return "Take 3 slow belly breaths and do a 60-second body scan." else: return "Keep up the calm pace. Maintain hydration." # Header st.markdown('

🏥 Smart Health Monitoring Agent

', unsafe_allow_html=True) st.markdown("---") # Sidebar with st.sidebar: st.header("📤 Upload Health Data") st.markdown("Upload a CSV file containing your health metrics.") uploaded_file = st.file_uploader( "Choose a CSV file", type=['csv'], help="CSV should contain: Date, Steps, Heart Rate, Calories, Sleep Duration" ) if uploaded_file is not None: try: with st.spinner("Analyzing your health data..."): service = HealthAnalysisService() uploaded_file.seek(0) file_content = uploaded_file.read() analysis = service.analyze_csv_file(file_content=file_content) st.session_state.analysis = analysis # Create DataFrame for display records_data = [] for record in analysis.records: stress = analysis.stress_levels[record.date] sleep = analysis.sleep_qualities[record.date] records_data.append({ 'Date': record.date, 'Steps': record.steps, 'Heart Rate (bpm)': record.heart_rate, 'Calories': record.calories, 'Sleep (hours)': record.sleep_duration, 'Stress Level': stress.level, 'Stress Score': f"{stress.score:.2f}", 'Sleep Quality': sleep.rating, 'Sleep Score': sleep.score }) st.session_state.records_df = pd.DataFrame(records_data) st.success("✅ Data analyzed successfully!") st.balloons() except Exception as e: st.error(f"❌ Error: {str(e)}") st.session_state.analysis = None st.session_state.records_df = None # Main content if st.session_state.analysis is None: # Landing page st.markdown(""" ### Welcome to Smart Health Monitoring Agent This AI-powered tool analyzes your smartwatch/fitness data and provides: - **Stress Level Predictions** - Based on heart rate, activity, and sleep patterns - **Sleep Quality Analysis** - Comprehensive sleep assessment - **Health Risk Alerts** - Intelligent alerts for potential health issues - **Trend Analysis** - Visual insights into your health patterns #### How to use: 1. Upload a CSV file with your health data using the sidebar 2. Required columns: Date, Steps, Heart Rate, Calories, Sleep Duration 3. View your personalized health dashboard #### Sample CSV Format: ```csv Date,Steps,Heart Rate,Calories,Sleep Duration 2024-12-01,8500,72,2100,7.5 2024-12-02,10200,68,2300,8.0 ``` """) # Show sample data preview st.markdown("### 📊 Sample Data Preview") sample_data = pd.DataFrame({ 'Date': ['2024-12-01', '2024-12-02', '2024-12-03'], 'Steps': [8500, 10200, 6800], 'Heart Rate': [72, 68, 78], 'Calories': [2100, 2300, 1950], 'Sleep Duration': [7.5, 8.0, 6.5] }) st.dataframe(sample_data, width="stretch") else: analysis = st.session_state.analysis records_df = st.session_state.records_df latest_record = analysis.records[-1] latest_stress = analysis.stress_levels[latest_record.date] hr_zones_df = summarize_heart_rate_zones(records_df) music_rec = recommend_music_bpm(latest_record.steps, latest_record.heart_rate) # Key Metrics Cards st.header("📊 Key Metrics") col1, col2, col3, col4, col5 = st.columns(5) with col1: st.metric( "Average Steps", f"{analysis.metrics.average_steps:,.0f}", delta=f"{analysis.metrics.average_steps - 10000:,.0f}" if analysis.metrics.average_steps < 10000 else None ) with col2: st.metric( "Avg Heart Rate", f"{analysis.metrics.average_heart_rate:.1f} bpm", delta=f"{analysis.metrics.average_heart_rate - 70:.1f}" if analysis.metrics.average_heart_rate > 70 else None ) with col3: st.metric( "Avg Calories", f"{analysis.metrics.average_calories:,.0f}", ) with col4: st.metric( "Avg Sleep", f"{analysis.metrics.average_sleep:.1f} hrs", delta=f"{analysis.metrics.average_sleep - 8:.1f}" if analysis.metrics.average_sleep < 8 else None ) with col5: # Health Score Gauge health_score = analysis.health_score color = "#28a745" if health_score >= 75 else "#ffc107" if health_score >= 50 else "#dc3545" fig_gauge = go.Figure(go.Indicator( mode="gauge+number", value=health_score, domain={'x': [0, 1], 'y': [0, 1]}, title={'text': "Health Score"}, gauge={ 'axis': {'range': [None, 100]}, 'bar': {'color': color}, 'steps': [ {'range': [0, 50], 'color': "lightgray"}, {'range': [50, 75], 'color': "gray"} ], 'threshold': { 'line': {'color': "red", 'width': 4}, 'thickness': 0.75, 'value': 90 } } )) fig_gauge.update_layout(height=200, margin=dict(l=0, r=0, t=0, b=0)) st.plotly_chart(fig_gauge, width="stretch") st.markdown("---") # Smart Features st.header("🚀 Smart Boosters") col1, col2, col3 = st.columns(3) with col1: st.subheader("🎶 Workout Music Optimizer") st.write(f"Current vibe: **{music_rec['mood']}**") st.write(f"Recommended BPM: **{music_rec['bpm']}**") st.caption("Tip: Match your stride to the beat for smoother pacing.") st.progress(min(music_rec["bpm"] / 180, 1.0)) with col2: st.subheader("🧘 Real-time Stress Intervention") st.write(f"Latest HR: **{latest_record.heart_rate:.0f} bpm**") st.write(f"Stress: **{latest_stress.level} ({latest_stress.score:.2f})**") st.info(stress_intervention_tip(latest_stress.level)) with col3: st.subheader("🩺 Doctor Report Highlights") st.write("Top talking points:") bullets = [ f"- Avg HR: {analysis.metrics.average_heart_rate:.1f} bpm", f"- Sleep: {analysis.metrics.average_sleep:.1f} hrs/night", f"- Steps: {analysis.metrics.average_steps:,.0f} /day" ] st.markdown("\n".join(bullets)) st.caption("Download full CSV for detailed review.") st.markdown("---") # Future Self Motivation st.header("🌟 Design Your Future Self") target = { "steps": 10000, "sleep": 8.0, "hr": 68.0, "stress": 0.25 } col_fs1, col_fs2 = st.columns(2) with col_fs1: st.subheader("\"Future You\" (90 days)") st.write("Identity-based goals set by your future self:") st.markdown( f"- Daily steps: **{target['steps']:,}**\n" f"- Sleep: **{target['sleep']} hrs/night**\n" f"- Resting HR target: **{target['hr']:.0f} bpm**\n" f"- Stress score target: **{target['stress']:.2f}** (Low)\n" ) encouragement = [ 'Future You says: "Keep compounding the small wins."', "Today's recovery is tomorrow's performance.", "You're 1% closer every consistent day." ] st.success(encouragement[len(analysis.records) % len(encouragement)]) with col_fs2: st.subheader("Progress Toward Future You") steps_progress = min(analysis.metrics.average_steps / target["steps"], 1.0) st.markdown("**Steps**") st.progress(steps_progress, text=f"{analysis.metrics.average_steps:,.0f} / {target['steps']:,}") sleep_progress = min(analysis.metrics.average_sleep / target["sleep"], 1.0) st.markdown("**Sleep**") st.progress(sleep_progress, text=f"{analysis.metrics.average_sleep:.1f} / {target['sleep']:.1f} hrs") hr_progress = min(target["hr"] / max(analysis.metrics.average_heart_rate, 1), 1.0) st.markdown("**Resting Heart Rate**") st.progress(hr_progress, text=f"{analysis.metrics.average_heart_rate:.1f} → {target['hr']:.1f} bpm") stress_avg = np.mean([s.score for s in analysis.stress_levels.values()]) stress_progress = min(target["stress"] / max(stress_avg, 0.01), 1.0) st.markdown("**Stress Score**") st.progress(stress_progress, text=f"{stress_avg:.2f} → {target['stress']:.2f}") st.markdown("---") # Alerts Section if analysis.alerts: st.header("⚠️ Health Alerts") for alert in analysis.alerts: alert_class = f"alert-{alert.type}" st.markdown(f"""
{alert.title}
{alert.message}
💡 Recommendation: {alert.recommendation}
""", unsafe_allow_html=True) st.markdown("---") # Charts Section st.header("📈 Health Trends") chart_data = records_df.copy() chart_data['Date'] = pd.to_datetime(chart_data['Date']) chart_data = chart_data.sort_values('Date') col1, col2 = st.columns(2) with col1: fig_steps = px.line( chart_data, x='Date', y='Steps', title='Daily Steps Trend', markers=True ) fig_steps.update_layout(height=300) st.plotly_chart(fig_steps, width="stretch") with col2: fig_hr = px.line( chart_data, x='Date', y='Heart Rate (bpm)', title='Heart Rate Trend', markers=True, color_discrete_sequence=['red'] ) fig_hr.update_layout(height=300) st.plotly_chart(fig_hr, width="stretch") col1, col2 = st.columns(2) with col1: fig_calories = px.bar( chart_data, x='Date', y='Calories', title='Daily Calorie Burn', color='Calories', color_continuous_scale='Blues' ) fig_calories.update_layout(height=300) st.plotly_chart(fig_calories, width="stretch") with col2: fig_sleep = px.bar( chart_data, x='Date', y='Sleep (hours)', title='Sleep Duration', color='Sleep (hours)', color_continuous_scale='Purples' ) fig_sleep.update_layout(height=300) st.plotly_chart(fig_sleep, width="stretch") st.subheader("📊 Deeper Insights") col_a, col_b = st.columns(2) with col_a: fig_zone = px.pie( hr_zones_df, values="Count", names="Zone", title="Heart Rate Zone Distribution", color_discrete_sequence=px.colors.sequential.Blues ) fig_zone.update_layout(height=340) st.plotly_chart(fig_zone, width="stretch") with col_b: fig_corr = px.scatter( chart_data, x="Steps", y="Calories", color="Sleep (hours)", size="Heart Rate (bpm)", title="Steps vs Calories (bubble sized by HR, colored by Sleep)", color_continuous_scale="Viridis" ) fig_corr.update_layout(height=340) st.plotly_chart(fig_corr, width="stretch") st.markdown("---") # AI Insights Panel st.header("🤖 AI Insights") col1, col2 = st.columns(2) with col1: st.subheader("Stress Level Predictions") for record in analysis.records[-7:]: stress = analysis.stress_levels[record.date] stress_class = f"stress-{stress.level.lower()}" st.markdown(f"**{record.date}**") st.markdown(f'{stress.level} (Score: {stress.score:.2f}, Confidence: {stress.confidence*100:.0f}%)', unsafe_allow_html=True) st.progress(stress.score, text=f"{stress.score*100:.0f}%") with col2: st.subheader("Sleep Quality Analysis") for record in analysis.records[-7:]: sleep = analysis.sleep_qualities[record.date] sleep_color = "#28a745" if sleep.rating == "Excellent" else "#17a2b8" if sleep.rating == "Good" else "#ffc107" if sleep.rating == "Fair" else "#dc3545" st.markdown(f"**{record.date}**") st.markdown(f'{sleep.rating} (Score: {sleep.score:.0f}/100)', unsafe_allow_html=True) st.progress(sleep.score / 100, text=f"{sleep.score:.0f}%") st.markdown("---") # Historical Trends st.header("📅 Historical Analysis") service = HealthAnalysisService() weekly_comparison = service.get_weekly_comparison(analysis.records) best_worst = service.get_best_worst_days(analysis.records) if weekly_comparison and weekly_comparison.get('changes'): st.subheader("Week-over-Week Comparison") changes = weekly_comparison['changes'] col1, col2, col3, col4 = st.columns(4) with col1: delta = changes.get('avg_steps', 0) st.metric("Steps Change", f"{delta:+.1f}%") with col2: delta = changes.get('avg_hr', 0) st.metric("Heart Rate Change", f"{delta:+.1f}%") with col3: delta = changes.get('avg_sleep', 0) st.metric("Sleep Change", f"{delta:+.1f}%") with col4: delta = changes.get('avg_calories', 0) st.metric("Calories Change", f"{delta:+.1f}%") if best_worst: col1, col2 = st.columns(2) with col1: if best_worst.get('best'): st.subheader("🏆 Best Day") best = best_worst['best'] st.write(f"**Date:** {best['date']}") st.write(f"**Health Score:** {best['score']:.1f}") st.write(f"Steps: {best['record'].steps:,.0f} | HR: {best['record'].heart_rate:.0f} bpm | Sleep: {best['record'].sleep_duration:.1f} hrs") with col2: if best_worst.get('worst'): st.subheader("⚠️ Needs Improvement") worst = best_worst['worst'] st.write(f"**Date:** {worst['date']}") st.write(f"**Health Score:** {worst['score']:.1f}") st.write(f"Steps: {worst['record'].steps:,.0f} | HR: {worst['record'].heart_rate:.0f} bpm | Sleep: {worst['record'].sleep_duration:.1f} hrs") st.markdown("---") # Data Table st.header("📋 Detailed Data") st.dataframe(records_df, width="stretch", height=400) # Download button csv = records_df.to_csv(index=False) st.download_button( label="📥 Download Analysis as CSV", data=csv, file_name=f"health_analysis_{datetime.now().strftime('%Y%m%d')}.csv", mime="text/csv" )