← Portfolio Home
Machine Learning Nov 2025 → Rebuilt July 2026 ⚡ 41 diseases · SHAP-explained

Disease Prediction System

A Streamlit prototype rebuilt into a real client-server product — FastAPI backend serving a Random Forest + ExtraTrees ensemble across 41 diseases and 133 symptoms, with SHAP explainability and one-click PDF reports, fronted by a custom dark medical-tech UI.

PythonFastAPIscikit-learnSHAPReportLabDockerVercel

The Problem

The original project was a single Streamlit script — a 949-line app.py holding the model, the UI, and the PDF logic in one process. It worked locally, but Streamlit's architecture needs a persistent server with an open WebSocket, which meant it couldn't be shared as a fast, portfolio-embeddable link the way a real product could.

Architecture & Approach

Split it into a proper client-server app: a FastAPI backend (/api/meta, /api/predict, /api/report, /health) serving the same Random Forest + ExtraTrees ensemble, and a hand-built dark medical-tech frontend — searchable symptom picker, animated confidence bars, SHAP explainability chart, PDF download — deployed separately. Backend on Render (where scikit-learn, SHAP, and matplotlib can run persistently), frontend on Vercel for fast static delivery. All 41 diseases' info and the ReportLab PDF generation were ported over verbatim and re-verified against the real model rather than retyped from memory.

Engineering Challenges & Solutions

  • Confirming the model's true input contract — the 63MB model.joblib was trained on 133 symptom columns matching data/symptoms.json, not the unrelated 40-item list sitting elsewhere in the repo, which would have silently produced wrong predictions if used
  • Pinning scikit-learn to the exact training version (1.7.2) after finding a fresh install would grab 1.8.0 and throw unpickling warnings that could silently change behavior
  • Wiring CORS correctly across two separately-hosted origins — the frontend's config.js has to point at the exact Render URL, and Render's FRONTEND_ORIGIN env var has to match the Vercel URL exactly, or every request fails silently as a generic 'fetch' error
  • Render's free-tier cold start: the backend spins down after ~15 minutes idle and has to reload a 63MB model on the next request, so a keep-warm health-check ping was added to avoid a dead-looking demo

Outcome & Results

A fully split, independently-deployed ML product — FastAPI + Docker on Render, static frontend on Vercel — with the original ensemble's predictions, SHAP-driven explainability, and full PDF report export all preserved and verified end-to-end against the real model.

Lessons Learned

A model is only as portfolio-ready as its deployment story. The prediction logic barely changed in this rebuild — what changed was giving it a real API contract, and that's what turned a script only I could run locally into a link anyone can open.

Arman Ahemad Khan

Built by Arman Ahemad Khan

Application Security & Full-Stack Developer based in Bhubaneswar, Odisha, India. Final-year B.Tech CSE at Silicon University (CGPA 9.15, graduating May 2027).