A full-stack web application that helps doctors manage patients and screen retinal fundus images for Diabetic Retinopathy (DR) using a two-stage deep-learning pipeline. Uploaded retina images are first validated by a MobileNetV2 classifier, then graded by a fine-tuned ConvNeXt model into five severity levels — with Grad-CAM heatmaps for visual explainability.
- Features
- Tech Stack
- Project Structure
- Prerequisites
- Getting Started
- Environment Variables
- API Reference
- ML Pipeline
- Scripts
- Doctor Authentication — Register / login with JWT-based token auth.
- Patient Management — Create, view, update, and delete patient records.
- Retinal Scan Upload — Upload left/right fundus images per patient.
- Two-Stage DR Inference — Retina validation → DR severity classification (Negative, Mild, Moderate, Severe, Proliferative).
- Grad-CAM Visualizations — Heatmap and overlay images highlighting regions the model focused on.
- Scan Reports — Detailed per-scan report page with image lightbox (zoom/pan).
- Responsive UI — Modern React + Tailwind CSS interface with code-split lazy loading.
- Zero-Config Database — SQLite by default; optionally switch to PostgreSQL.
| Layer | Technology |
|---|---|
| Frontend | React 19, React Router 7, Vite 7, Tailwind CSS 3, Axios, Lucide |
| Backend | FastAPI, SQLAlchemy 2, Pydantic 2, Uvicorn, python-jose |
| ML / AI | TensorFlow / Keras, ConvNeXt (DR), MobileNetV2 (retina filter) |
| Database | SQLite (default) / PostgreSQL |
project/
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI application factory
│ │ ├── database.py # SQLAlchemy engine & session
│ │ ├── settings.py # Pydantic-settings configuration
│ │ ├── security.py # JWT auth & password hashing
│ │ ├── ml/
│ │ │ └── model.py # Two-stage DR inference pipeline
│ │ ├── models/ # SQLAlchemy ORM models
│ │ ├── routes/ # API route handlers
│ │ └── schemas/ # Pydantic request/response schemas
│ ├── uploads/ # Uploaded scan images (auto-created)
│ ├── requirements.txt # Core Python dependencies
│ └── requirements-ml.txt # Optional ML dependencies (TensorFlow)
├── frontend/
│ ├── src/
│ │ ├── App.jsx # Routes & protected layout
│ │ ├── api/api.js # Axios API client
│ │ ├── components/ # Shared UI components
│ │ └── pages/ # Dashboard, Patients, ScanReport, etc.
│ ├── package.json
│ └── vite.config.js
├── models/ # Keras model weights
│ ├── best_model_finetuned.keras
│ └── retina_classifier.keras
├── scripts/
│ ├── dev.sh # Start both servers in background
│ └── stop.sh # Kill both servers
└── README.md
- Python 3.10+ (3.12 recommended)
- Node.js 18+ and npm
- (Optional) TensorFlow-compatible Python build for ML inference
A convenience script starts both the backend and frontend in the background:
# 1. Create the backend virtual environment (first time only)
cd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
pip install -r requirements-ml.txt # optional, for scan inference
deactivate
cd ..
# 2. Install frontend dependencies (first time only)
cd frontend && npm install && cd ..
# 3. Launch both servers
bash scripts/dev.shThe script prints the URLs when ready:
| Service | URL |
|---|---|
| Frontend | http://127.0.0.1:5173 |
| Backend | http://127.0.0.1:8000 |
| API Docs | http://127.0.0.1:8000/docs (Swagger UI) |
| Health | http://127.0.0.1:8000/health |
To stop both servers:
bash scripts/stop.shcd backend
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# Start the API server
uvicorn app.main:app --reload --host 127.0.0.1 --port 8000cd frontend
npm install
npm run devOpen http://127.0.0.1:5173 in your browser.
The backend reads configuration from backend/.env (optional). Defaults work out of the box with SQLite.
| Variable | Default | Description |
|---|---|---|
DATABASE_URL |
sqlite:///medical_dashboard.db |
Database connection string |
JWT_SECRET_KEY |
change-me |
Secret used to sign JWT tokens |
JWT_ALGORITHM |
HS256 |
JWT signing algorithm |
ACCESS_TOKEN_EXPIRE_MINUTES |
1440 (24 h) |
Token expiry duration in minutes |
CORS_ORIGINS |
http://localhost:5173,... |
Comma-separated allowed origins |
UPLOADS_DIR |
uploads |
Directory for uploaded scan images |
The frontend reads VITE_API_URL from frontend/.env (defaults to http://127.0.0.1:8000).
⚠️ Production note: Always changeJWT_SECRET_KEYto a strong random value.
All endpoints except /auth/* and /health require a Bearer token (Authorization: Bearer <token>).
| Method | Endpoint | Description |
|---|---|---|
| POST | /auth/register |
Register a new doctor |
| POST | /auth/login |
Login (returns JWT token) |
| Method | Endpoint | Description |
|---|---|---|
| GET | /patients |
List all patients |
| POST | /patients |
Create a patient |
| GET | /patients/{id} |
Get patient details + scans |
| PUT | /patients/{id} |
Update a patient |
| DELETE | /patients/{id} |
Delete a patient |
| Method | Endpoint | Description |
|---|---|---|
| POST | /scans/upload |
Upload & classify a retinal scan |
| POST | /scans/upload-bilateral |
Upload left + right eye images |
| GET | /scans/{scan_id} |
Get scan details |
| GET | /scans/patient/{patient_id} |
List scans for a patient |
Full interactive docs are available at http://127.0.0.1:8000/docs when the backend is running.
The inference pipeline lives in backend/app/ml/model.py and uses two Keras models:
-
Retina Classifier (
retina_classifier.keras) — A MobileNetV2-based binary classifier that rejects non-retina images. -
DR Grading Model (
best_model_finetuned.keras) — A fine-tuned ConvNeXt model that classifies retinal images into five DR severity levels:Class Label 0 Negative 1 Mild 2 Moderate 3 Severe 4 Proliferative
Preprocessing includes black-border cropping and Ben Graham preprocessing (local contrast normalization).
Grad-CAM heatmaps are generated over the last convolutional block to provide visual explanations for each prediction.
If TensorFlow or model files are not installed, the API gracefully returns HTTP 503 for scan endpoints while all other features remain fully functional.
cd backend
source .venv/bin/activate
pip install -r requirements-ml.txtModel weight files should be placed in the models/ directory at the project root.
| Script | Description |
|---|---|
scripts/dev.sh |
Starts backend (Uvicorn) and frontend (Vite) in background |
scripts/stop.sh |
Kills processes on ports 8000 and 5173 |
Set BACKEND_RELOAD=1 before running dev.sh to enable Uvicorn auto-reload:
BACKEND_RELOAD=1 bash scripts/dev.shThis project is for educational / research purposes. LICENSE According to the license terms, any redistribution (including compiled or modified versions), you must retain the original copyright notice and the full license text. Copyright © 2026 Rohith Gowda R. All rights reserved.
