| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import json |
| import zipfile |
| import shutil |
| import tempfile |
| import numpy as np |
| import torch |
| import torch.nn as nn |
| import gradio as gr |
| from huggingface_hub import hf_hub_download |
| from pathlib import Path |
|
|
| |
| MODEL_REPO = "your-hf-username/stress-level-classifier-mlp" |
|
|
| FEATURE_COLS = [ |
| "anxiety_level", "self_esteem", "mental_health_history", "depression", |
| "headache", "blood_pressure", "sleep_quality", "breathing_problem", |
| "noise_level", "living_conditions", "safety", "basic_needs", |
| "academic_performance", "study_load", "teacher_student_relationship", |
| "future_career_concerns", "social_support", "peer_pressure", |
| "extracurricular_activities", "bullying", |
| ] |
|
|
| FEATURE_RANGES = { |
| "anxiety_level": (0, 21), |
| "self_esteem": (0, 30), |
| "mental_health_history": (0, 1), |
| "depression": (0, 27), |
| "headache": (0, 5), |
| "blood_pressure": (1, 3), |
| "sleep_quality": (1, 5), |
| "breathing_problem": (1, 5), |
| "noise_level": (0, 5), |
| "living_conditions": (1, 5), |
| "safety": (1, 5), |
| "basic_needs": (1, 5), |
| "academic_performance": (1, 5), |
| "study_load": (1, 5), |
| "teacher_student_relationship":(1, 5), |
| "future_career_concerns": (1, 5), |
| "social_support": (1, 5), |
| "peer_pressure": (1, 5), |
| "extracurricular_activities": (0, 5), |
| "bullying": (1, 5), |
| } |
|
|
| STRESS_EMOJIS = {"low": "π’", "medium": "π‘", "high": "π΄"} |
| STRESS_LABELS = ["low", "medium", "high"] |
| ID2LABEL = {"0": "low", "1": "medium", "2": "high"} |
|
|
| |
| class StressMLP(nn.Module): |
| def __init__(self, input_dim, num_classes, dropout=0.3): |
| super().__init__() |
| self.net = nn.Sequential( |
| nn.Linear(input_dim, 256), nn.BatchNorm1d(256), nn.ReLU(), nn.Dropout(dropout), |
| nn.Linear(256, 128), nn.BatchNorm1d(128), nn.ReLU(), nn.Dropout(dropout), |
| nn.Linear(128, 64), nn.BatchNorm1d(64), nn.ReLU(), nn.Dropout(dropout / 2), |
| nn.Linear(64, num_classes), |
| ) |
|
|
| def forward(self, x): |
| return self.net(x) |
|
|
| |
| print(f"Loading model from {MODEL_REPO} β¦") |
|
|
| cfg_path = hf_hub_download(MODEL_REPO, "config.json") |
| scaler_path = hf_hub_download(MODEL_REPO, "scaler.json") |
| weights_path = hf_hub_download(MODEL_REPO, "model_weights.pt") |
|
|
| with open(cfg_path) as f: cfg = json.load(f) |
| with open(scaler_path) as f: scaler = json.load(f) |
|
|
| MEAN = np.array(scaler["mean"], dtype=np.float32) |
| SCALE = np.array(scaler["scale"], dtype=np.float32) |
|
|
| model = StressMLP(cfg["input_dim"], cfg["num_classes"], cfg["dropout"]) |
| model.load_state_dict(torch.load(weights_path, map_location="cpu")) |
| model.eval() |
| print("Model loaded β
") |
|
|
| |
| DOWNLOAD_ZIP = Path("/tmp/stress_model_package.zip") |
|
|
| def build_download_zip(): |
| """Package the cached HF model files into a single zip for users.""" |
| if DOWNLOAD_ZIP.exists(): |
| return |
| files_to_zip = { |
| "model_weights.pt": weights_path, |
| "config.json": cfg_path, |
| "scaler.json": scaler_path, |
| } |
| with zipfile.ZipFile(DOWNLOAD_ZIP, "w", zipfile.ZIP_DEFLATED) as zf: |
| for arcname, src in files_to_zip.items(): |
| zf.write(src, arcname=arcname) |
| print(f"Download zip ready: {DOWNLOAD_ZIP}") |
|
|
| build_download_zip() |
|
|
| |
| def predict(*feature_values): |
| arr = np.array(feature_values, dtype=np.float32).reshape(1, -1) |
| arr = (arr - MEAN) / SCALE |
|
|
| with torch.no_grad(): |
| logits = model(torch.tensor(arr)) |
| probs = torch.softmax(logits, dim=-1).squeeze().numpy() |
|
|
| pred_id = int(probs.argmax()) |
| pred_label = STRESS_LABELS[pred_id] |
| emoji = STRESS_EMOJIS[pred_label] |
| confidence = probs[pred_id] * 100 |
|
|
| result = f"## {emoji} Stress Level: **{pred_label.upper()}**\n" |
| result += f"Confidence: **{confidence:.1f}%**" |
|
|
| scores = { |
| f"{STRESS_EMOJIS[lbl]} {lbl.capitalize()}": float(probs[i]) * 100 |
| for i, lbl in enumerate(STRESS_LABELS) |
| } |
| return result, scores |
|
|
| def get_download(): |
| return str(DOWNLOAD_ZIP) |
|
|
| |
| def make_label(col): |
| return col.replace("_", " ").title() |
|
|
| sliders = [ |
| gr.Slider( |
| minimum=lo, maximum=hi, value=(lo + hi) // 2, step=1, |
| label=make_label(col), |
| ) |
| for col, (lo, hi) in FEATURE_RANGES.items() |
| ] |
|
|
| |
| with gr.Blocks( |
| theme=gr.themes.Soft(), |
| title="Stress Level Classifier", |
| css=""" |
| .result-md { font-size: 1.35rem; padding: 14px 18px; |
| border-radius: 10px; background: var(--block-background-fill); } |
| .dl-btn { margin-top: 8px; } |
| footer { display: none !important; } |
| """, |
| ) as demo: |
|
|
| gr.Markdown( |
| """ |
| # π§ Student Stress Level Classifier |
| Predicts stress level (**Low / Medium / High**) from 20 psychosocial & |
| physiological indicators using a fine-tuned MLP. |
| """ |
| ) |
|
|
| with gr.Row(): |
| |
| with gr.Column(scale=3): |
| gr.Markdown("### π Input Features") |
|
|
| with gr.Accordion("𧬠Psychological Factors", open=True): |
| s_anxiety = sliders[0] |
| s_esteem = sliders[1] |
| s_mh_hist = sliders[2] |
| s_depress = sliders[3] |
|
|
| with gr.Accordion("π©Ί Physical Indicators", open=False): |
| s_headache = sliders[4] |
| s_bp = sliders[5] |
| s_sleep = sliders[6] |
| s_breath = sliders[7] |
|
|
| with gr.Accordion("π Environmental Factors", open=False): |
| s_noise = sliders[8] |
| s_living = sliders[9] |
| s_safety = sliders[10] |
| s_basic = sliders[11] |
|
|
| with gr.Accordion("π Academic Factors", open=False): |
| s_acad = sliders[12] |
| s_study = sliders[13] |
| s_teacher = sliders[14] |
| s_career = sliders[15] |
|
|
| with gr.Accordion("π₯ Social Factors", open=False): |
| s_social = sliders[16] |
| s_peer = sliders[17] |
| s_extra = sliders[18] |
| s_bully = sliders[19] |
|
|
| predict_btn = gr.Button("π Predict Stress Level", variant="primary", size="lg") |
|
|
| |
| with gr.Column(scale=2): |
| gr.Markdown("### π Results") |
| result_md = gr.Markdown( |
| value="*Adjust sliders and click Predict.*", |
| elem_classes=["result-md"], |
| ) |
| scores_out = gr.Label( |
| label="Confidence per Class (%)", |
| num_top_classes=3, |
| ) |
|
|
| gr.Markdown("---") |
| gr.Markdown("### π₯ Download Model") |
| gr.Markdown( |
| "Download all model files (weights, config, scaler) as a single ZIP." |
| ) |
| download_btn = gr.DownloadButton( |
| label="β¬οΈ Download stress_model_package.zip", |
| value=get_download, |
| variant="secondary", |
| elem_classes=["dl-btn"], |
| ) |
| gr.Markdown( |
| f"Or browse individual files on the " |
| f"[HuggingFace model page π€](https://huggingface.co/{MODEL_REPO})." |
| ) |
|
|
| |
| gr.Markdown("---") |
| gr.Examples( |
| examples=[ |
| |
| |
| |
| [4, 26, 0, 6, 1, 2, 4, 1, 1, 4, 4, 4, 5, 1, 4, 1, 3, 2, 2, 1], |
| [13, 22, 1, 12, 3, 1, 2, 4, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 2, 2], |
| [20, 3, 1, 22, 5, 3, 1, 5, 3, 1, 1, 1, 1, 5, 2, 5, 1, 5, 4, 5], |
| ], |
| inputs=sliders, |
| label="Quick examples (Low / Medium / High stress)", |
| ) |
|
|
| gr.Markdown( |
| """ |
| --- |
| **Features:** 20 psychosocial & physiological indicators Β· |
| **Model:** PyTorch MLP fine-tuned for 10 epochs Β· |
| **Classes:** π’ Low Β· π‘ Medium Β· π΄ High |
| """ |
| ) |
|
|
| predict_btn.click( |
| fn=predict, |
| inputs=sliders, |
| outputs=[result_md, scores_out], |
| ) |
|
|
| if __name__ == "__main__": |
| demo.launch() |
|
|