AI-assisted myocardial perfusion imaging (MPI) analysis and clinical decision-support platform.
Warning
CardioScan AI is an academic proof of concept. It has not been clinically validated, is not a medical device, and must not replace diagnosis or independent clinical judgment by a qualified healthcare professional.
CardioScan AI is a full-stack Final Year Project developed to explore automated analysis of paired stress and rest MPI scans. It combines a clinical dashboard with a separate TensorFlow inference service, vessel-aware risk stratification, Groq-powered clinical report generation, and persistent scan history.
The research pipeline compares three transfer-learning backbones:
- VGG16
- ResNet50V2 (displayed as
ResNet50in the application) - DenseNet121
Each model is designed to process a six-channel representation created by concatenating RGB stress and rest images. Their outputs are averaged to produce an ensemble result with coronary-territory probabilities for LAD, LCX, and RCA.
- Paired stress/rest MPI image upload
- Three-model inference and ensemble prediction
- LAD, LCX, and RCA territory probability estimates
- Four risk tiers: Low, Medium, High, and Critical
- Patient information form with age and BMI handling
- AI-generated clinical-style reports powered by Groq and Llama 3.3 70B
- Automatic rule-based report fallback if Groq is unavailable
- Individual model confidence visualizations
- Persistent scan and report history with Supabase
- Local browser fallback when cloud persistence is unavailable
- Email/password demo accounts and optional Google OAuth
- Printable results for browser-based PDF export
- Responsive dark clinical dashboard
- Hugging Face Spaces-compatible FastAPI service
flowchart TD
A["Stress and rest MPI scans"] --> B["Next.js dashboard"]
B --> C["Next.js prediction API"]
C --> D["FastAPI inference service"]
D --> E["VGG16"]
D --> F["ResNet50V2"]
D --> G["DenseNet121"]
E --> H["Ensemble and risk tiers"]
F --> H
G --> H
H --> I["Groq Llama 3.3 report generation"]
I --> L["Rule-based fallback"]
C --> J["Supabase history"]
I --> J
J --> K["Results dashboard"]
- The user enters patient information and uploads stress and rest images.
/api/predictvalidates the request and forwards both images to the configured Python service.- FastAPI resizes each image to
224 x 224, converts it to RGB, concatenates the pair into a six-channel tensor, and applies ImageNet normalization. - VGG16, ResNet50V2, and DenseNet121 run independently.
- Successful outputs are averaged and mapped to risk tiers.
/api/analyzesends the patient context and quantitative model outputs to Groq'sllama-3.3-70b-versatilemodel.- Groq returns a structured MPI report containing protocol, stress impression, imaging findings, clinical impression, and key findings.
- If Groq is unavailable or returns an empty response, the application automatically generates a deterministic rule-based report.
- Predictions and reports are saved to Supabase when configured.
| Layer | Technologies |
|---|---|
| Frontend | Next.js 15, React 19, TypeScript, Tailwind CSS 4 |
| Web API | Next.js Route Handlers, Groq SDK |
| Inference API | Python, FastAPI, Uvicorn |
| Machine learning | TensorFlow/Keras, NumPy, Pillow |
| Model hosting | Hugging Face Spaces (Docker) |
| Database | Supabase PostgreSQL |
| Authentication | Browser-based demo auth, optional Google OAuth |
| Report generation | Groq API, Llama 3.3 70B Versatile, rule-based fallback |
| Icons | Lucide React |
.
├── app/
│ ├── api/ # Prediction, reporting, persistence, and migration routes
│ ├── context/ # Client authentication state
│ ├── dashboard/ # Upload, patient form, history, and status UI
│ ├── login/ # Login page
│ ├── results/ # Analysis and report view
│ ├── signup/ # Registration page
│ ├── globals.css # Global design system
│ ├── layout.tsx # Root layout and metadata
│ └── page.tsx # Landing page
├── hf_space/
│ ├── app.py # FastAPI model loading and inference
│ ├── Dockerfile # Hugging Face container
│ └── requirements.txt # Inference dependencies
├── lib/supabase.ts # Browser and server Supabase clients
├── public/ # Static assets
├── huggingface_deployment_guide.md
├── next.config.mjs
├── package.json
└── tsconfig.json
- Node.js 18.18+ (Node.js 20 LTS recommended)
- npm
- A Supabase project for cloud persistence (optional for UI testing)
- A running inference API for real model predictions
- A Google OAuth client ID if Google sign-in is required
git clone https://github.com/mahadbaig2/fyp-web-depolyement.git
cd fyp-web-depolyement
npm installCreate .env.local in the repository root:
# Supabase persistence
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
# Optional Google OAuth
NEXT_PUBLIC_GOOGLE_CLIENT_ID=your-google-client-id
# TensorFlow inference service
PYTHON_BACKEND_URL=https://your-space-name.hf.space
# AI-generated clinical reports
GROQ_API_KEY=your-groq-api-keyNever commit .env.local or expose SUPABASE_SERVICE_ROLE_KEY to client-side code.
GROQ_API_KEY is used only by the server-side /api/analyze route. Create a key from the Groq Console. If the key is missing, invalid, rate-limited, or the API request fails, the application falls back to its rule-based report generator.
The routes expect scans, reports, and profiles tables. At minimum, preserve these fields:
| Table | Fields used by the application |
|---|---|
scans |
id, filename, predictions (jsonb), user_email, user_id, model_source, patient_info (jsonb), created_at |
reports |
id, scan_id, user_email, user_id, content, created_at |
profiles |
email, name, avatar_url, provider |
Apply appropriate constraints, indexes, Row Level Security policies, and server-side authorization before production use. The current server routes use the service-role client and should be treated as research-prototype code.
npm run devOpen http://localhost:3000.
For a production build:
npm run build
npm startThe hf_space/ directory contains a Docker-ready FastAPI service for Hugging Face Spaces.
The service currently looks for:
VGG16_20260508_200536.keras
ResNet50_20260502_141714.keras
DenseNet121_20260502_151212.keras
Either place them in hf_space/models/ or upload them to a Hugging Face model repository and set MODEL_REPO_ID in the Space settings. Use Git LFS or a dedicated model repository for large artifacts.
cd hf_space
python -m venv .venvActivate the environment:
# macOS/Linux
source .venv/bin/activate
# Windows PowerShell
.venv\Scripts\Activate.ps1Then install and launch:
pip install -r requirements.txt
uvicorn app:app --host 0.0.0.0 --port 7860 --reloadSet PYTHON_BACKEND_URL=http://localhost:7860 in .env.local.
curl http://localhost:7860/healthExpected response:
{
"status": "ok",
"models_loaded": ["VGG16", "ResNet50", "DenseNet121"]
}If models_loaded is empty, no real neural-network inference is available.
curl -X POST http://localhost:7860/predict \
-F "stress_file=@stress.png" \
-F "rest_file=@rest.png"See huggingface_deployment_guide.md for more deployment notes.
| Method | Route | Description |
|---|---|---|
POST |
/api/predict |
Validates uploads, calls inference, and saves a scan |
POST |
/api/analyze |
Generates a Groq report, falls back to a rule-based report, and stores it |
GET |
/api/scans?email=... |
Retrieves a user's scan history |
GET |
/api/results?id=... |
Retrieves a scan and related report |
POST |
/api/migrate |
Migrates browser history to Supabase |
POST |
/api/profile |
Upserts profile information |
GET |
/api/test-db |
Checks database access during development |
| Method | Route | Description |
|---|---|---|
GET |
/health |
Reports service health and loaded models |
POST |
/predict |
Runs single-image or paired-image inference |
{
"VGG16": {
"probability": 0.41,
"prediction": "Normal",
"risk_level": "Medium",
"confidence": 18.0,
"vessels": { "LAD": 0.38, "LCX": 0.44, "RCA": 0.41 }
},
"ResNet50": {},
"DenseNet121": {},
"ensemble": {
"probability": 0.47,
"prediction": "Normal",
"risk_level": "Medium",
"confidence": 6.0,
"vessels": { "LAD": 0.45, "LCX": 0.49, "RCA": 0.47 }
}
}| Probability | Risk tier |
|---|---|
< 0.25 |
Low |
0.25 - < 0.50 |
Medium |
0.50 - < 0.70 |
High |
>= 0.70 |
Critical |
The /api/analyze endpoint uses the ensemble verdict, vessel probabilities, individual model outputs, filename, and patient information to prompt Groq.
| Setting | Value |
|---|---|
| Model | llama-3.3-70b-versatile |
| Temperature | 0.3 |
| Maximum output tokens | 1800 |
| Fallback | Built-in rule-based generator |
The generated report follows these fixed sections:
NUCLEAR IMAGING PROTOCOLSTRESS PROTOCOLSTRESS IMPRESSIONIMAGING FINDINGSIMPRESSIONKEY CLINICAL FINDINGS
The endpoint returns the report and its source:
{
"report": "## NUCLEAR IMAGING PROTOCOL\n...",
"source": "groq"
}If Groq fails, source is rule-based. The fallback keeps the analysis workflow available, but it is less context-sensitive than the LLM-generated report.
The broader FYP explored:
- Transfer learning with VGG16, ResNet50V2, and DenseNet121
- Six-channel paired stress/rest input
- Attention pooling
- Focal loss with label smoothing
- Class-aware oversampling and paired augmentation
- MixUp augmentation
- Two-stage fine-tuning
- Model comparison and ensemble inference
- A PRISMA-guided systematic review of 47 studies (2015-2025)
The reported experimental dataset included 724 original paired samples and augmentation to 2,000 paired samples, split into 1,400 training, 300 validation, and 300 test samples.
- Model weights are not included in this repository.
- Without
PYTHON_BACKEND_URL,/api/predictreturns randomized heuristic/demo predictions, not model results. - The Python service also uses a heuristic fallback if no model loads; always inspect
/health. - Groq-generated text can contain unsupported or hallucinated clinical statements. Every report requires review by a qualified clinician.
- The prompt includes patient information and scan-derived results. Do not send identifiable patient data to Groq without authorization, appropriate agreements, and regulatory review.
- The UI accepts DICOM and NPY extensions, but the FastAPI preprocessing uses Pillow and does not implement native DICOM or NPY decoding.
- Local email/password authentication stores demo credentials in browser storage and is not production-grade.
- Email-based history filtering is not a substitute for server-verified authorization.
- The research used a limited, single-source dataset with synthetic augmentation and no multi-center external validation.
- Grad-CAM, SHAP, and LIME are not implemented in the current application.
- Performance figures across the report/UI are not fully consistent; metrics must be revalidated from original evaluation artifacts before publication or clinical claims.
npm run lint
npm run buildBefore deployment, also verify that all three models appear in /health, test paired and single-image inference, validate database flows, and test OAuth origins.
MPI scans and patient information are sensitive health data. Before using real patient data:
- Replace browser-based authentication with a secure identity provider.
- Enforce authorization and Row Level Security.
- Protect or remove
/api/test-db. - Restrict inference API CORS.
- Add upload limits, MIME validation, malware scanning, rate limiting, and audit logs.
- Encrypt data in transit and at rest.
- Define retention and deletion policies.
- Obtain applicable institutional, ethical, privacy, and regulatory approval.
- Never send identifiable scans to third-party services without explicit authorization.
- Minimize or de-identify patient information before sending report-generation requests to Groq.
- Train and validate on larger multi-center clinical datasets
- Add native DICOM ingestion and metadata handling
- Implement Grad-CAM and clinically interpretable explanations
- Calibrate vessel-level probabilities and risk thresholds
- Add Supabase Auth and role-based access control
- Add model/version tracking and inference audit trails
- Evaluate Vision Transformers and hybrid CNN-transformer architectures
- Conduct prospective validation with nuclear cardiology experts
- Add automated tests and CI/CD for both services
| Name | Student ID | |
|---|---|---|
| Mirza Mahad Baig | 65332 | mahadmirza681@gmail.com |
| Emaan Khan | 65254 | khaneman218@gmail.com |
| Muhammad Danial Shariq | 65312 | umaimamahmood28@gmail.com |
| Umm e Umaima | 64960 | danialshariq88@gmail.com |
Supervised by Mr. Amanullah Khan at the College of Computing & Information Sciences, KIET, Karachi, Pakistan.
No license file is currently included. Unless a license is added, default copyright applies and others do not automatically have permission to reuse, modify, or redistribute the code.
@misc{cardioscanai2026,
title = {CardioScan AI: AI-Powered Myocardial Perfusion Imaging Scan Analyzer},
author = {Baig, Mirza Mahad and Khan, Emaan and Shariq, Muhammad Danial and Umaima, Umm e},
year = {2026},
note = {Bachelor of Science in Computer Science Final Year Project, KIET}
}Built as a Bachelor of Science in Computer Science Final Year Project at KIET.