0–5 min
Real Hook
5–25 min
Core Concept
25–45 min
Live Coding
45–55 min
You Code It
55–60 min
Cheat Sheet
🔥 Real-World Hook (0–5 min)

A model that lives in a Jupyter notebook helps only you. A model behind a FastAPI endpoint can be called by a mobile app in Chennai, a web dashboard in Mumbai, and a batch job in Bengaluru — all at the same time.

Every ML model in production runs behind an API. FastAPI is Python's fastest, with automatic docs, type validation via Pydantic, and async support. Netflix, Uber, and Microsoft use it.

📈 FastAPI Core Concepts (5–25 min)

💡 Why FastAPI over Flask?

Auto docs — Swagger UI at /docs, Redoc at /redoc. Zero config.
Pydantic validation — wrong input type = 422 error with a clear message, not a crash.
Async — handle thousands of concurrent LLM calls without blocking.
Speed — on par with Node.js, 2× faster than Flask for I/O-heavy work.

💻 Live Demo — Sentiment Analysis API (25–45 min)

># main.py — run with: uvicorn main:app --reload
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import LogisticRegression
import pickle, os

app = FastAPI(title="Sentiment API", version="1.0")

# Request / Response schemas (Pydantic validates automatically)
class ReviewRequest(BaseModel):
    text: str
    language: str = "en"

class SentimentResponse(BaseModel):
    sentiment: str         # "positive" | "negative"
    confidence: float
    word_count: int

# Load model at startup (not per request)
vectorizer: TfidfVectorizer = None
model: LogisticRegression   = None

@app.on_event("startup")
async def load_model():
    global vectorizer, model
    if os.path.exists("model.pkl"):
        with open("model.pkl", "rb") as f:
            vectorizer, model = pickle.load(f)
    print("Model loaded")

@app.get("/health")
def health():
    return {"status": "ok", "model_loaded": model is not None}

@app.post("/predict", response_model=SentimentResponse)
async def predict(req: ReviewRequest):
    if not model:
        raise HTTPException(status_code=503, detail="Model not loaded")
    vec = vectorizer.transform([req.text])
    pred  = model.predict(vec)[0]
    proba = model.predict_proba(vec)[0].max()
    return SentimentResponse(
        sentiment  = "positive" if pred == 1 else "negative",
        confidence = round(float(proba), 3),
        word_count = len(req.text.split())
    )

📋 You Code It (45–55 min)

✍ Task

Add a POST /batch endpoint that accepts a list of reviews and returns a list of SentimentResponse. Add a GET /stats endpoint that returns total predictions made (use a module-level counter).

⚡ Day 13 Cheat Sheet

app = FastAPI(title="...")
Create app
@app.post("/path")
POST endpoint
@app.get("/path")
GET endpoint
class X(BaseModel)
Pydantic schema
response_model=MyModel
Type-validate output
HTTPException(status_code=4xx)
Return error responses
@app.on_event("startup")
Run code once at boot
uvicorn main:app --reload
Dev server with hot-reload