Yiwennnn's picture
Update app.py
3188e47 verified
import pandas as pd
import joblib
import gradio as gr
import json
import requests
MODEL_PATH = "risk_model.joblib"
ZAPIER_WEBHOOK_URL = "https://hooks.zapier.com/hooks/catch/27083565/uvtxiub/"
DISCLAIMER = (
"Educational demo only. This tool does not provide diagnosis, "
"prescriptions, or treatment plans. If symptoms are severe or urgent, seek emergency care."
)
RED_FLAGS = [
"chest pain",
"chest tightness",
"severe shortness of breath",
"fainting",
"loss of consciousness",
"stroke"
]
risk_model = joblib.load(MODEL_PATH)
def send_urgent_alert(symptom_text, risk_score):
try:
requests.post(ZAPIER_WEBHOOK_URL, json={
"triage_level": "urgent",
"symptom": symptom_text,
"risk_score": risk_score,
"message": "URGENT triage case detected by HealthBridge AI"
}, timeout=5)
except Exception:
pass
def assess(sexvar, educa, genhlth, menthlth, stress, sleep_hours, sleep_quality, duration_days, adherence_prob, symptom_text):
text_lower = str(symptom_text).lower()
red_flag_hit = any(flag in text_lower for flag in RED_FLAGS)
input_df = pd.DataFrame([{
"user_id": 0,
"SEXVAR": sexvar,
"EDUCA": educa,
"GENHLTH": genhlth,
"MENTHLTH": menthlth,
"stress_score_0_10": stress,
"sleep_hours": sleep_hours,
"sleep_quality_0_10": sleep_quality,
"symptom_duration_days": duration_days,
"adherence_prob": adherence_prob,
"symptom_text": symptom_text,
"triage_label": "medium"
}])
risk_score = float(risk_model.predict_proba(input_df)[0][1])
if red_flag_hit:
triage_level = "urgent"
elif risk_score >= 0.7:
triage_level = "high"
elif risk_score >= 0.4:
triage_level = "medium"
else:
triage_level = "low"
if triage_level == "urgent":
send_urgent_alert(symptom_text, round(risk_score, 3))
if triage_level == "urgent":
next_steps = [
"๐Ÿšจ Seek emergency care immediately or call emergency services.",
"Do not drive yourself โ€” ask someone nearby to help.",
"Do not wait to see if symptoms improve."
]
elif triage_level == "high":
next_steps = [
"Contact a healthcare provider as soon as possible.",
"Monitor symptoms closely and note any changes.",
"Seek emergency care if symptoms worsen rapidly."
]
elif triage_level == "medium":
next_steps = [
"Schedule an appointment with your doctor within the next few days.",
"Rest and monitor your symptoms.",
"Seek urgent care if symptoms escalate."
]
else:
next_steps = [
"Monitor symptoms and maintain healthy routines.",
"Seek professional care if symptoms persist beyond a week.",
"Stay hydrated and rest as needed."
]
LEVEL_COLORS = {
"urgent": "#FF2D2D",
"high": "#FF8C00",
"medium": "#F5C518",
"low": "#2ECC71"
}
LEVEL_BG = {
"urgent": "#FFF0F0",
"high": "#FFF5E6",
"medium": "#FFFBEA",
"low": "#F0FFF6"
}
LEVEL_ICONS = {
"urgent": "๐Ÿšจ",
"high": "โš ๏ธ",
"medium": "๐Ÿ”ถ",
"low": "โœ…"
}
color = LEVEL_COLORS[triage_level]
bg = LEVEL_BG[triage_level]
icon = LEVEL_ICONS[triage_level]
risk_pct = int(risk_score * 100)
bar_color = color
steps_html = "".join(f"<li style='margin-bottom:6px'>{s}</li>" for s in next_steps)
alert_banner = ""
if triage_level == "urgent":
alert_banner = f"""
<div style='background:#FF2D2D;color:white;padding:14px 18px;border-radius:8px;
font-weight:700;font-size:15px;letter-spacing:0.5px;margin-bottom:16px;
animation: pulse 1.5s infinite;'>
๐Ÿšจ URGENT โ€” An automated alert email has been sent.
</div>
"""
html = f"""
<style>
@import url('https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=DM+Mono:wght@400;500&display=swap');
.hb-card * {{ font-family: 'DM Sans', sans-serif; box-sizing: border-box; }}
@keyframes pulse {{
0%, 100% {{ opacity: 1; }}
50% {{ opacity: 0.75; }}
}}
@keyframes fadeIn {{
from {{ opacity: 0; transform: translateY(8px); }}
to {{ opacity: 1; transform: translateY(0); }}
}}
.hb-card {{ animation: fadeIn 0.4s ease; }}
</style>
<div class='hb-card' style='background:{bg};border:2px solid {color};border-radius:12px;
padding:24px;max-width:600px;'>
{alert_banner}
<!-- Triage Level Badge -->
<div style='display:flex;align-items:center;gap:12px;margin-bottom:20px;'>
<span style='font-size:32px;'>{icon}</span>
<div>
<div style='font-size:11px;font-weight:600;color:#888;letter-spacing:1.5px;
text-transform:uppercase;'>Triage Level</div>
<div style='font-size:28px;font-weight:700;color:{color};line-height:1.1;'>
{triage_level.upper()}
</div>
</div>
</div>
<!-- Risk Score Bar -->
<div style='margin-bottom:20px;'>
<div style='display:flex;justify-content:space-between;margin-bottom:6px;'>
<span style='font-size:12px;font-weight:600;color:#555;text-transform:uppercase;
letter-spacing:1px;'>Risk Score</span>
<span style='font-size:14px;font-weight:700;color:{color};
font-family:"DM Mono",monospace;'>{risk_pct}%</span>
</div>
<div style='background:#E8E8E8;border-radius:99px;height:10px;overflow:hidden;'>
<div style='background:{bar_color};width:{risk_pct}%;height:100%;
border-radius:99px;transition:width 0.6s ease;'></div>
</div>
</div>
<!-- Red Flag -->
<div style='display:flex;align-items:center;gap:8px;margin-bottom:20px;
padding:10px 14px;background:white;border-radius:8px;
border:1px solid #E0E0E0;'>
<span style='font-size:16px;'>{"๐Ÿšฉ" if red_flag_hit else "โœ”๏ธ"}</span>
<span style='font-size:13px;font-weight:600;color:{"#FF2D2D" if red_flag_hit else "#2ECC71"};'>
Red Flag: {"DETECTED" if red_flag_hit else "None detected"}
</span>
</div>
<!-- Next Steps -->
<div style='margin-bottom:20px;'>
<div style='font-size:12px;font-weight:600;color:#555;letter-spacing:1px;
text-transform:uppercase;margin-bottom:10px;'>Recommended Next Steps</div>
<ul style='margin:0;padding-left:20px;color:#333;font-size:14px;line-height:1.6;'>
{steps_html}
</ul>
</div>
<!-- Disclaimer -->
<div style='font-size:11px;color:#999;border-top:1px solid #E0E0E0;
padding-top:12px;line-height:1.5;'>
โš ๏ธ {DISCLAIMER}
</div>
</div>
"""
return html
demo = gr.Interface(
fn=assess,
inputs=[
gr.Dropdown([1, 2], value=1, label="Sex (BRFSS-coded)"),
gr.Slider(1, 6, value=4, step=1, label="Education level"),
gr.Slider(1, 5, value=3, step=1, label="General health"),
gr.Slider(0, 30, value=5, step=1, label="Mental health bad days"),
gr.Slider(0, 10, value=5, step=0.1, label="Stress score"),
gr.Slider(3, 10, value=7, step=0.1, label="Sleep hours"),
gr.Slider(0, 10, value=7, step=0.1, label="Sleep quality"),
gr.Slider(1, 30, value=5, step=1, label="Symptom duration (days)"),
gr.Slider(0.05, 0.95, value=0.65, step=0.01, label="Adherence probability"),
gr.Textbox(lines=4, placeholder="e.g. chest pain for 2 days, high stress, poor sleep", label="Symptom description")
],
outputs=gr.HTML(label="Triage Result"),
title="HealthBridge AI โ€” Non-diagnostic Triage Demo",
description="Educational demo only. Not a substitute for professional medical advice.",
theme=gr.themes.Soft()
)
demo.launch()