import joblib import numpy as np import gradio as gr # Lataa malli model = joblib.load("workload_model.joblib") CLASS_NAMES = {0: "Low", 1: "Medium", 2: "High"} EMOJI = {"Low": "🟢", "Medium": "🟠", "High": "🔴"} # Esimerkkipäivät dropdownille EXAMPLE_PRESETS = { "Balanced day": [3, 2.5, 4, 2, 45, 9, 16], "Overloaded day": [9, 7.5, 15, 0, 10, 9, 18], "Focused day": [2, 1.5, 2, 3, 60, 8, 15], } def predict_workload( meetings_count, total_meeting_hours, context_switches, deep_work_blocks, break_minutes, day_start_hour, day_end_hour, ): X = np.array([[ meetings_count, total_meeting_hours, context_switches, deep_work_blocks, break_minutes, day_start_hour, day_end_hour, ]]) probs = model.predict_proba(X)[0] pred_class = int(np.argmax(probs)) pred_label = CLASS_NAMES[pred_class] confidence = float(probs[pred_class]) probs_dict = {name: float(probs[i]) for i, name in CLASS_NAMES.items()} headline = ( f"
" f"{EMOJI[pred_label]} {pred_label} Workload" f"
" f"
" f"Confidence: {confidence * 100:.1f}%" f"
" ) # --- practical tips --- tips = [] day_length = day_end_hour - day_start_hour if meetings_count >= 8 or total_meeting_hours >= 6: tips.append( "Consider blocking meeting-free focus time (e.g. 2–3h) and moving " "non-essential meetings to another day." ) if context_switches >= 12: tips.append( "Try to batch similar tasks or meetings together to reduce context switching." ) if deep_work_blocks == 0: tips.append( "Add at least one deep work block (60–90 minutes) for focused work without notifications." ) if break_minutes < 30 and day_length >= 8: tips.append( "Increase break time slightly – even short 5–10 minute breaks every few hours reduce fatigue." ) if day_length > 9: tips.append( "Your workday is long – consider moving low-priority tasks to another day or finishing earlier." ) if not tips: tips.append( "Your setup looks balanced! To stay sustainable, consider scheduling regular deep work and micro-breaks." ) tips_html = "" explanation = ( "

💡 Personalized Suggestions

" + tips_html + "

🧠 How the Model Works

" "

This AI estimates your perceived workload using:

" "" ) return headline, probs_dict, explanation def load_example(example_name): """Täyttää sliderit valitun esimerkin arvoilla.""" if example_name in EXAMPLE_PRESETS: return EXAMPLE_PRESETS[example_name] return [4, 3, 6, 1, 30, 9, 17] # Teema theme = gr.themes.Soft( primary_hue=gr.themes.colors.orange, secondary_hue=gr.themes.colors.rose, neutral_hue=gr.themes.colors.slate, radius_size=gr.themes.sizes.radius_md, ).set( button_primary_background_fill="*primary_500", button_primary_background_fill_hover="*primary_600", block_title_text_weight="600", ) # CSS css = """ #app-container { max-width: 1200px; margin: 0 auto; padding: 0 1.5rem; } #app-header { text-align: center; margin-bottom: 2rem; } #app-header h1 { font-weight: 700; font-size: 2.2rem; color: #222; margin-bottom: 0.4rem; } #app-header p { font-size: 1.1rem; color: #666; max-width: 650px; margin: 0 auto; line-height: 1.5; } .gr-button-primary { font-weight: 600; padding: 0.6rem 1.4rem; font-size: 1.05rem; } @media (max-width: 768px) { #app-header h1 { font-size: 1.8rem; } #app-header p { font-size: 1rem; } .gr-button-primary { width: 100%; padding: 0.7rem; } } """ with gr.Blocks(theme=theme, css=css, title="🗓️ Workload Estimator") as demo: with gr.Column(elem_id="app-container"): gr.Markdown( """

🗓️ Calendar Workload Estimator

Estimate your daily cognitive load based on meetings, focus time, and recovery.

""", elem_id="header" ) with gr.Tab("📊 Estimate Your Day"): with gr.Row(equal_height=False): # VASEN SARake: dropdown + sliderit + nappi with gr.Column(scale=2): example_dropdown = gr.Dropdown( label="💡 Load example schedule", choices=list(EXAMPLE_PRESETS.keys()), value=None, interactive=True, ) gr.Markdown("### 🗓️ Workday Structure") meetings_count = gr.Slider(0, 12, value=4, step=1, label="Meetings (count)") total_meeting_hours = gr.Slider(0, 9, value=3, step=0.5, label="Total meeting hours") context_switches = gr.Slider(0, 20, value=6, step=1, label="Context switches") gr.Markdown("### 🧘 Focus & Recovery") deep_work_blocks = gr.Slider(0, 4, value=1, step=1, label="Deep work blocks (≥60 min)") break_minutes = gr.Slider(0, 120, value=30, step=5, label="Total break minutes") gr.Markdown("### ⏰ Workday Timing") day_start_hour = gr.Slider(6, 11, value=9, step=1, label="Start hour (24h)") day_end_hour = gr.Slider(14, 21, value=17, step=1, label="End hour (24h)") btn = gr.Button("🔍 Analyze Workload", variant="primary") # OIKEA sarake: tulos with gr.Column(scale=1): gr.Markdown("### 📈 Result") headline_out = gr.HTML() probs_out = gr.Label(label="Workload Probabilities") explanation_out = gr.HTML() # Kun valitaan esimerkki → täytetään sliderit example_dropdown.change( load_example, inputs=example_dropdown, outputs=[ meetings_count, total_meeting_hours, context_switches, deep_work_blocks, break_minutes, day_start_hour, day_end_hour, ], ) # Varsinainen ennustekutsu btn.click( predict_workload, inputs=[ meetings_count, total_meeting_hours, context_switches, deep_work_blocks, break_minutes, day_start_hour, day_end_hour, ], outputs=[headline_out, probs_out, explanation_out], ) with gr.Tab("ℹ️ About"): gr.Markdown(""" ### About This Tool This demo shows how **calendar metadata** can be used to estimate cognitive workload — helping you reflect on sustainability, focus, and recovery. - **Synthetic data only**: No real user data was used. - **Model**: Trained `RandomForestClassifier` (scikit-learn). - **Output**: 3-class workload (`Low`, `Medium`, `High`). - **Goal**: Spark reflection, not replace judgment. Use this to **simulate "what-if" scenarios**: _"What if I cancel two meetings?"_ or _"What if I add a 90-min focus block?"_ Built with **Python**, **scikit-learn** and **Gradio**, deployed on **Hugging Face Spaces**. """) if __name__ == "__main__": demo.launch()