Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import joblib, json, pandas as pd, time | |
| from datetime import datetime | |
| from io import BytesIO | |
| from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer | |
| from reportlab.lib.styles import getSampleStyleSheet | |
| from reportlab.lib.pagesizes import letter | |
| st.set_page_config(page_title="Stroke Risk Predictor", page_icon="icon2.png", layout="centered") | |
| # ---------- SESSION ---------- | |
| if "show_reset" not in st.session_state: | |
| st.session_state.show_reset = False | |
| # ---------- STYLE ---------- | |
| st.markdown(""" | |
| <style> | |
| body { background: linear-gradient(135deg,#0f172a,#020617); } | |
| .card { | |
| background:#0b1220; | |
| border-radius:18px; | |
| padding:20px 22px; | |
| box-shadow:0 16px 28px rgba(0,0,0,.45); | |
| margin-bottom:14px; | |
| color:#e5ecff; | |
| } | |
| /* Primary (Check Risk) */ | |
| .stButton>button { | |
| width:100%; | |
| border-radius:12px; | |
| background:linear-gradient(135deg,#3b82f6,#06b6d4); | |
| color:#ffffff; | |
| padding:12px 16px; | |
| font-weight:700; | |
| border:0; | |
| box-shadow:0 10px 22px rgba(59,130,246,.25); | |
| transition:.2s ease-in-out; | |
| } | |
| .stButton>button:hover { | |
| transform:translateY(-2px); | |
| box-shadow:0 14px 28px rgba(59,130,246,.35); | |
| } | |
| /* Better secondary button (Reset) */ | |
| .reset-btn button{ | |
| width:100%; | |
| border-radius:14px; | |
| background:#111827 !important; | |
| color:#e5e7eb !important; | |
| border:1px solid #2a2f3a !important; | |
| padding:12px 16px; | |
| font-weight:600; | |
| box-shadow:0 6px 16px rgba(0,0,0,.25); | |
| } | |
| .reset-btn button:hover{ | |
| background:#1f2937 !important; | |
| border-color:#3b4251 !important; | |
| } | |
| .result-box { | |
| background:#020617; | |
| border-radius:20px; | |
| padding:22px; | |
| border:1px solid #1f2937; | |
| text-align:center; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # ---------- HEADER ---------- | |
| st.markdown(""" | |
| <div class="card"> | |
| <h3 style="text-align:center;">🧠 Stroke Risk Predictor</h3> | |
| <p style="text-align:center;color:#9ca3af;">This tool estimates possible stroke risk — not a diagnosis.</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # ---------- MODEL ---------- | |
| model = joblib.load("stroke_model.pkl") | |
| thr = json.load(open("threshold.json"))["threshold"] | |
| MODEL_COLUMNS = [ | |
| "gender","age","hypertension","heart_disease", | |
| "ever_married","work_type","Residence_type", | |
| "avg_glucose_level","bmi","smoking_status" | |
| ] | |
| def predict(data): | |
| df = pd.DataFrame([data])[MODEL_COLUMNS] | |
| prob = model.predict_proba(df)[0][1] | |
| return prob, int(prob >= thr) | |
| # =============================== | |
| # INPUTS | |
| # =============================== | |
| st.markdown('<div class="card">', unsafe_allow_html=True) | |
| st.subheader("🧑 Personal Details") | |
| gender = st.selectbox("Gender", ["Male","Female","Other"]) | |
| age = st.slider("Age", 1, 100, 45) | |
| ever_married = st.checkbox("Married") | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| st.markdown('<div class="card">', unsafe_allow_html=True) | |
| st.subheader("🩺 Health Info") | |
| hypertension = st.checkbox("Hypertension") | |
| heart_disease = st.checkbox("Heart Disease") | |
| avg_glucose = st.slider("Average Glucose", 40.0, 300.0, 100.0) | |
| bmi = st.slider("BMI", 10.0, 60.0, 24.0) | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| st.markdown('<div class="card">', unsafe_allow_html=True) | |
| st.subheader("🏡 Lifestyle") | |
| work_type = st.radio("Work", ["Private","Self-employed","Govt_job","child","Never_worked"], horizontal=True) | |
| res_type = st.radio("Residence", ["Urban","Rural"], horizontal=True) | |
| smoking = st.radio("Smoking", ["never smoked","formerly smoked","smokes","Unknown"], horizontal=True) | |
| colA, colB = st.columns(2) | |
| with colA: | |
| predict_btn = st.button("✨ Check Risk") | |
| # show reset as soon as prediction is attempted | |
| if predict_btn: | |
| st.session_state.show_reset = True | |
| with colB: | |
| reset_btn = None | |
| if st.session_state.show_reset: | |
| st.markdown('<div class="reset-btn">', unsafe_allow_html=True) | |
| reset_btn = st.button(" Reset ", key="reset", help="Clear all inputs") | |
| st.markdown('</div>', unsafe_allow_html=True) | |
| # ---------- RESET ---------- | |
| if reset_btn: | |
| st.session_state.clear() | |
| st.rerun() | |
| # ---------- CONVERT ---------- | |
| ever_married = "Yes" if ever_married else "No" | |
| hypertension = 1 if hypertension else 0 | |
| heart_disease = 1 if heart_disease else 0 | |
| # =============================== | |
| # RESULT | |
| # =============================== | |
| if predict_btn: | |
| data = { | |
| "gender": gender, | |
| "age": age, | |
| "hypertension": hypertension, | |
| "heart_disease": heart_disease, | |
| "ever_married": ever_married, | |
| "work_type": work_type, | |
| "Residence_type": res_type, | |
| "avg_glucose_level": avg_glucose, | |
| "bmi": bmi, | |
| "smoking_status": smoking | |
| } | |
| prob, pred = predict(data) | |
| percent = round(prob * 100, 1) | |
| with st.spinner("Analyzing…"): | |
| time.sleep(0.8) | |
| st.divider() | |
| st.markdown('<div class="card"><h4>📝 Summary</h4></div>', unsafe_allow_html=True) | |
| c1, c2 = st.columns(2) | |
| with c1: | |
| st.write(f"**Gender:** {gender}") | |
| st.write(f"**Age:** {age}") | |
| st.write(f"**Married:** {ever_married}") | |
| st.write(f"**Residence:** {res_type}") | |
| with c2: | |
| st.write(f"**Hypertension:** {hypertension}") | |
| st.write(f"**Heart Disease:** {heart_disease}") | |
| st.write(f"**Glucose:** {avg_glucose}") | |
| st.write(f"**BMI:** {bmi}") | |
| st.markdown(f""" | |
| <div class="result-box"> | |
| <h4>Estimated Risk</h4> | |
| <h1>{percent}%</h1> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| bar = st.progress(0) | |
| for i in range(int(percent)): | |
| time.sleep(0.01) | |
| bar.progress(i + 1) | |
| # ---------- SMART SUGGESTIONS ---------- | |
| reasons, tips = [], [] | |
| if avg_glucose > 125: reasons.append("High glucose increases stroke risk"); tips.append("Reduce sugar and walk daily.") | |
| if bmi >= 30: reasons.append("High BMI strains the heart"); tips.append("Aim gradual weight loss.") | |
| if hypertension: reasons.append("Blood pressure increases stroke risk"); tips.append("Reduce salt — monitor BP.") | |
| if heart_disease: reasons.append("Heart disease increases clot risk"); tips.append("Follow cardiac treatment regularly.") | |
| if smoking == "smokes": reasons.append("Smoking damages blood vessels"); tips.append("Quitting sharply reduces risk.") | |
| if not reasons: reasons.append("Fewer major risk factors detected"); tips.append("Maintain activity, diet, and checkups.") | |
| st.markdown('<div class="card"><h4>🧪 Why this score?</h4></div>', unsafe_allow_html=True) | |
| for r in reasons: | |
| st.write("🔎 " + r) | |
| st.markdown('<div class="card"><h4>💡 Suggestions</h4></div>', unsafe_allow_html=True) | |
| for t in tips: | |
| st.write("✅ " + t) | |
| if pred: | |
| st.warning("⚠️ Higher risk — please consult a medical professional.") | |
| else: | |
| st.success("💚 Lower risk — keep following healthy habits.") | |
| # ---------- PDF ---------- | |
| def create_pdf(): | |
| buffer = BytesIO() | |
| styles = getSampleStyleSheet() | |
| doc = SimpleDocTemplate(buffer, pagesize=letter) | |
| content = [ | |
| Paragraph("<b>Stroke Risk Report</b>", styles["Title"]), | |
| Spacer(1, 10), | |
| Paragraph(f"Risk: {percent}%", styles["Normal"]), | |
| Paragraph(f"Gender: {gender}", styles["Normal"]), | |
| Paragraph(f"Age: {age}", styles["Normal"]), | |
| Paragraph(f"Glucose: {avg_glucose}", styles["Normal"]), | |
| Paragraph(f"BMI: {bmi}", styles["Normal"]), | |
| Spacer(1, 10), | |
| Paragraph("<b>Recommendations:</b>", styles["Heading2"]), | |
| ] | |
| for t in tips: | |
| content.append(Paragraph("• " + t, styles["Normal"])) | |
| doc.build(content) | |
| buffer.seek(0) | |
| return buffer | |
| st.download_button( | |
| "📄 Download Report (PDF)", | |
| create_pdf(), | |
| file_name="stroke_report.pdf", | |
| mime="application/pdf" | |
| ) | |