ModelKiln's picture
Upload 3 files
8293c58 verified
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"<div style='text-align:center; font-size:1.8rem; margin:1rem 0;'>"
f"{EMOJI[pred_label]} <strong>{pred_label} Workload</strong>"
f"</div>"
f"<div style='text-align:center; color:#555; font-size:1.1rem;'>"
f"Confidence: <strong>{confidence * 100:.1f}%</strong>"
f"</div>"
)
# --- practical tips ---
tips = []
day_length = day_end_hour - day_start_hour
if meetings_count >= 8 or total_meeting_hours >= 6:
tips.append(
"Consider blocking <strong>meeting-free focus time</strong> (e.g. 2–3h) and moving "
"non-essential meetings to another day."
)
if context_switches >= 12:
tips.append(
"Try to <strong>batch similar tasks or meetings</strong> together to reduce context switching."
)
if deep_work_blocks == 0:
tips.append(
"Add at least <strong>one deep work block (60–90 minutes)</strong> for focused work without notifications."
)
if break_minutes < 30 and day_length >= 8:
tips.append(
"Increase <strong>break time</strong> slightly – even short 5–10 minute breaks every few hours reduce fatigue."
)
if day_length > 9:
tips.append(
"Your workday is long – consider <strong>moving low-priority tasks</strong> 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 = "<ul style='padding-left:1.2rem; line-height:1.6;'>"
for tip in tips:
tips_html += f"<li>{tip}</li>"
tips_html += "</ul>"
explanation = (
"<h3 style='margin-top:1.5rem;'>💡 Personalized Suggestions</h3>"
+ tips_html +
"<h3 style='margin-top:1.5rem;'>🧠 How the Model Works</h3>"
"<p style='color:#555;'>This AI estimates your perceived workload using:</p>"
"<ul style='padding-left:1.2rem; color:#555;'>"
"<li>Number and duration of meetings</li>"
"<li>Frequency of task/meeting switches (context switches)</li>"
"<li>Presence of uninterrupted deep work blocks</li>"
"<li>Total break time during the day</li>"
"<li>Overall workday length</li>"
"</ul>"
)
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(
"""
<div id="app-header">
<h1>🗓️ Calendar Workload Estimator</h1>
<p>Estimate your daily cognitive load based on meetings, focus time, and recovery.</p>
</div>
""",
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()