How we built it# RadAssist — Explainable AI Radiology Assistant

An AI that reads alongside radiologists — it drafts, highlights, and explains, but the clinician decides. And it's honest about exactly how good it is.

🔗 Try it out

Live demo https://radiology-intervention.razeplaygames.com/
Demo login Username radiologist · Password RadAssist-Demo-2026 (or click "Fill demo credentials" on the sign-in page)
What to do Sign in → Workspace → upload a chest X-ray (or a CT/MRI DICOM series) → review the AI findings → sign & export the report

Use only public / de-identified images — it's a research demo, not for real patient data.


💡 About the project

RadAssist is a full-stack, decision-support workspace for chest X-ray, CT, and MRI. Upload a scan and a deep-learning model flags possible findings and highlights where it looked; the radiologist confirms, edits, or dismisses each one; and the app drafts a complete report — clinical, a plain-English patient summary, and differentials — that a named clinician signs before it can be exported.

Its guiding principle is unusual for a medical-AI demo: the model suggests, it never diagnoses — and it never claims more than it can measure. It provides the accuracy ** It shows a ranking score instead of a fake "probability", it **abstains on images it can't read instead of guessing, it never calls a scan "normal" on its own, and it publishes its real measured accuracy — including where it fails.

📖 The story

It started with an uncomfortable observation: the world has a shortage of radiologists and a surplus of "AI that diagnoses" — tools that confidently label a scan and hope nobody reads the fine print. In medicine, a confident wrong answer is worse than no answer at all.

RadAssist took the opposite bet — an AI that earns trust by being honest. It reads a scan with the clinician, shows its reasoning with Grad-CAM attention maps, admits its uncertainty, and refuses to overrule the human. When it isn't sure, it says so. When it sees an image it wasn't trained on, it abstains. And it puts its own scorecard on the wall — AUROC, calibration error, and the labels it's weak at.

What began as a chest-X-ray demo grew into a real clinical product: a CT/MRI viewer with a full measurement suite and clearly-labelled research AI, structured reporting with mandatory human sign-off, and a production-grade backend — an optional database, two-factor authentication, session management, encrypted secrets, ~300 automated tests, a CI pipeline, and a one-command Docker deploy that's live on its own domain.

RadAssist is a research/education prototype — not FDA-cleared, not a medical device. That honesty isn't a disclaimer bolted on at the end; it is the design. This cannot be used on real Patients


🧰 Tech stack

Frontend

  • [x] React 19 + Vite 8 (SPA, custom lightweight routing)
  • [x] Plain CSS design-token system — light/dark, 4 accent themes, flash-free
  • [x] three.js — interactive 3D "scan volume" hero
  • [x] jsPDF — in-browser PDF report export (nothing stored server-side)
  • [x] qrcode — 2FA enrollment QR
  • [x] Web Speech API — voice dictation for findings

Backend / API

  • [x] Python 3.11 · FastAPI · Uvicorn (ASGI) · Pydantic
  • [x] REST API (~30 endpoints) serving the SPA same-origin

AI / ML

  • [x] PyTorch + TorchXRayVision — DenseNet-121 chest-X-ray ensemble (18 pathologies)
  • [x] pytorch-grad-cam — attention/explainability overlays
  • [x] OpenCV, NumPy, SciPy, scikit-image, pandas — imaging, measurements, classical CT/MRI candidate detection
  • [x] pydicom + Pillow — DICOM parsing, windowing, de-identification
  • [x] Out-of-distribution abstain gate + isotonic calibration + an on-repo validation harness (AUROC / ECE / NPV)
  • [x] Optional LLM report formatter — Gemini / Groq / Ollama, with a deterministic template fallback (the LLM only formats, never invents findings)

Database / persistence

  • [x] SQLModel (SQLAlchemy 2.0) — SQLite → PostgreSQL, versioned with Alembic
  • [x] PHI-safe by design (no pixels or patient identifiers in the DB); off by default (zero-config demo)

Security

  • [x] Stateless HMAC signed-cookie sessions + DB-backed revocation
  • [x] scrypt password hashing · TOTP two-factor auth · 2FA secrets encrypted at rest (Fernet / cryptography)
  • [x] Double-submit CSRF, per-account lockout, rate limiting, CSP/HSTS headers, fail-closed secrets
  • [x] In-memory DICOM de-identification + secondary-capture quarantine

DevOps / quality

  • [x] Docker (multi-stage: builds the SPA, bakes the model weights)
  • [x] GitHub Actions CI (tests + build + dependency audits) · Dependabot
  • [x] pytest — ~294 automated tests · pip-audit / npm audit (0 known vulnerabilities)
  • [x] Hosted on Fly.io + Cloudflare (also deployable to Hugging Face Spaces)

⭐ What makes it different

  • Honest by construction — ranking scores not fake probabilities; abstains rather than guesses; a "not a normal read" safeguard so a no-flag scan is never mistaken for a clean bill of health.
  • Explainable — every finding carries a Grad-CAM attention map, a reliability label, and a plain-language explanation.
  • Measured, not claimed — a live Evidence page shows the model's real performance and its weak spots.
  • Human-in-the-loop, always — AI flags arrive unchecked; nothing is finalized until a clinician signs.
  • Genuinely full-stack — model, API, database, auth/2FA, security, tests, CI, and a live deployment.

⚠️ Honest limitations

Metrics are measured on a public in-distribution benchmark and are optimistic; the chest-X-ray model is reliable only as a high-sensitivity review prompt for a few findings, and CT/MRI AI is unvalidated research. RadAssist is not a diagnostic device and not FDA-cleared — it's a demonstration of how to build medical AI responsibly.


Built With

Share this project:

Updates