An end-to-end, production-style ML application that predicts car prices. It includes a FastAPI backend (JWT + API key security, Redis caching, Prometheus metrics), a modern React frontend (Vite + TypeScript + Tailwind + Framer Motion), containerization with Docker, and training code to (re)build the model.
Pick one path to run everything locally.
cd /d "D:\CODES\CampusX\FastAPI Capstone Project"
docker compose up --build
- Frontend: http://localhost:5173
- API: http://localhost:8000 (docs at /docs)
- Prometheus: http://localhost:9090
- Grafana: http://localhost:3000
Backend (Windows CMD):
cd /d "D:\CODES\CampusX\FastAPI Capstone Project"
python -m venv .venv
".venv\Scripts\activate"
pip install -r requirements.txt
set REDIS_URL=redis://localhost:6379
uvicorn app.main:app --reload --port 8000
Frontend:
cd /d "D:\CODES\CampusX\FastAPI Capstone Project\frontend"
npm install
npm run dev
- Dev server: http://localhost:5173
- The dev server proxies calls from
/api/*
tohttp://localhost:8000/*
.
- Project Overview
- Features
- Architecture & Structure
- Configuration
- API Reference (Auth + Predict)
- Frontend Highlights
- Monitoring & Observability
- Train or Retrain the Model
- Run with Docker
- Troubleshooting
- Contributing & License
This project showcases how to ship an ML model as a secure, observable web service with a polished user experience:
- High-performance FastAPI backend delivering predictions
- JWT-based auth and API key guard on protected endpoints
- Redis-backed caching (gracefully degrades if Redis is not available in dev)
- Prometheus metrics out-of-the-box
- React frontend with animations, validation, and local history
- Production-ready Docker images and docker-compose orchestration
- Auth: Login to obtain a JWT; send it via a
token
header (simple demo flow). - API Key: Gate prediction requests using
api-key
header. - Prediction: Car price estimates from a trained scikit-learn model.
- Caching: Redis cache for repeated predictions.
- Observability: Prometheus metrics and custom request logging middleware.
- Frontend: Vite + React + TypeScript + Tailwind + Framer Motion + react-hook-form + zod + toast notifications.
- Containers: API, Frontend (Nginx), Redis, Prometheus, Grafana.
High-level data flow:
Browser (React SPA)
β
βΌ
Vite/Nginx proxy βββΆ FastAPI βββΆ Model Service βββΆ model.joblib
β
ββββΆ Redis Cache
Prometheus ββββββββββββββ FastAPI /metrics
Key folders:
app/
β FastAPI appapi/
βroutes_auth.py
(login),routes_predict.py
(predict)core/
βconfig.py
(env),security.py
(JWT),dependencies.py
(headers)services/
βmodel_service.py
(load model, inference, caching)cache/
βredis_cache.py
(safe, optional cache client)middleware/
β request logging
models/
βmodel.joblib
(trained model)training/
βtrain_model.py
,train_utils.py
(retrain pipeline)data/
βcar-details.csv
frontend/
β Vite + React app (multi-page, animated)
Environment variables (defaults in parentheses):
API_KEY
(demo-key) β Required header:api-key
JWT_SECRET_KEY
(secret) β Used for signing JWTsREDIS_URL
(redis://localhost:6379) β Redis connection; app tolerates absence in dev
Ports:
- API: 8000
- Frontend: 5173 (Nginx in Docker, Vite dev server in local dev)
- Redis: 6379
- Prometheus: 9090
- Grafana: 3000
Security notes:
- Auth uses a demo login (
admin
/admin
) returning a JWT inaccess_token
. - Protected endpoints expect two headers:
token
(JWT) andapi-key
. - CORS is set to allow all in dev; restrict origins before production.
OpenAPI docs: http://localhost:8000/docs
POST /login
Request
{ "username": "admin", "password": "admin" }
Success Response
{ "access_token": "<JWT>" }
Failure Response (demo behavior)
{ "error": "Invalid Credentials" }
POST /predict
Headers
token: <JWT>
api-key: demo-key
(or your configured API_KEY)
Body (schema in routes_predict.py
)
{
"company": "Maruti",
"year": 2015,
"owner": "First Owner",
"fuel": "Petrol",
"seller_type": "Individual",
"transmission": "Manual",
"km_driven": 50000,
"mileage_mpg": 18.0,
"engine_cc": 1197,
"max_power_bhp": 82,
"torque_nm": 113,
"seats": 5
}
Response
{ "predicted_price": "350,000.00" }
Example (PowerShell shown for readability; adapt to CMD as needed):
$token = (Invoke-RestMethod -Method Post -Uri http://localhost:8000/login -Body (@{username='admin';password='admin'} | ConvertTo-Json) -ContentType 'application/json').access_token
Invoke-RestMethod -Method Post -Uri http://localhost:8000/predict -Headers @{ token=$token; 'api-key'='demo-key' } -Body (@{
company='Maruti'; year=2015; owner='First Owner'; fuel='Petrol'; seller_type='Individual'; transmission='Manual'; km_driven=50000; mileage_mpg=18; engine_cc=1197; max_power_bhp=82; torque_nm=113; seats=5
} | ConvertTo-Json) -ContentType 'application/json'
- Built with Vite + React + TypeScript
- TailwindCSS for styling, Framer Motion for subtle animations
- React Router multi-page app: Home, Login, Predict, History, About, 404
- Form validation: react-hook-form + zod
- Toast notifications (react-hot-toast)
- Local history persisted in
localStorage
Dev proxy:
- Vite proxies
/api/*
tohttp://localhost:8000/*
during development - In production (Docker), Nginx proxies
/api/*
to theapi
service
Env vars (frontend):
VITE_API_URL
β If set (e.g.,http://localhost:8000/
), Axios calls the API directlyVITE_API_KEY
β If set, used as theapi-key
header (defaults todemo-key
)
- Prometheus scrapes the API at
/metrics
(courtesy ofprometheus-fastapi-instrumentator
) - Grafana can visualize Prometheus metrics (compose includes Grafana)
- Custom logging middleware logs requests and responses for traceability
Prometheus config lives in prometheus.yml
.
- Data:
data/car-details.csv
- Notebook:
notebooks/sample.ipynb
for exploration - Training:
training/train_model.py
producesapp/models/model.joblib
Run training:
cd /d "D:\CODES\CampusX\FastAPI Capstone Project"
".venv\Scripts\activate"
python training\train_model.py
Compose services:
api
β FastAPI app (port 8000)frontend
β Built with Node, served via Nginx (port 5173)redis
β Redis cache (port 6379)prometheus
β Metrics collection (port 9090)grafana
β Dashboards (port 3000)
Start:
cd /d "D:\CODES\CampusX\FastAPI Capstone Project"
docker compose up --build
Stop:
docker compose down
- Proxy error from Vite (
ECONNREFUSED /login
): start the backend (uvicorn ...
) or run via Docker Compose. - 401 Unauthorized: missing/invalid
token
header β login again and include the JWT. - 403 Forbidden: missing/invalid
api-key
header β setapi-key: demo-key
(or your configured value). - Redis errors: optional in dev β the app now runs even if Redis isnβt available.
- CORS issues: CORS is permissive in dev; restrict
allow_origins
inapp/main.py
for production.
- Fork the repo
- Create a branch:
git checkout -b feature/YourFeature
- Commit:
git commit -m "feat: add awesome thing"
- Push:
git push origin feature/YourFeature
- Open a PR
MIT License. See LICENSE file if provided.
Made with β€οΈ by Karan Patel