Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/characat0/mlops-fundamentals-homework/llms.txt

Use this file to discover all available pages before exploring further.

The FastAPI application exposes two endpoints on port 8000. The /health endpoint provides a simple liveness signal for load balancers and CI pipelines, while the /predict endpoint accepts the full set of Spotify audio features and returns a genre classification with a model confidence score. All request bodies are validated by Pydantic before inference runs — malformed or incomplete payloads are rejected automatically with HTTP 422.

SpotifyFeatures Request Schema

Every POST /predict call must include a JSON body that matches the SpotifyFeatures Pydantic model. All 12 fields are required; omitting any field or passing the wrong type returns HTTP 422.
Student TODO: The SpotifyFeatures class in app/main.py is currently a stub (pass). Students must add the 12 fields below with the correct types before the validation and the test_predict_endpoint_invalid_payload test will work correctly.
# TODO: Students must implement this class body in app/main.py
class SpotifyFeatures(BaseModel):
    danceability: float
    energy: float
    key: int
    loudness: float
    mode: int
    speechiness: float
    acousticness: float
    instrumentalness: float
    liveness: float
    valence: float
    tempo: float
    duration_ms: int
danceability
float
required
How suitable a track is for dancing. Range: 0.0–1.0.
energy
float
required
Perceptual measure of intensity and activity. Range: 0.0–1.0.
key
int
required
The key the track is in, mapped to standard Pitch Class notation (e.g. 0 = C, 1 = C♯/D♭). Range: 0–11.
loudness
float
required
Overall loudness of a track in decibels (dB). Typical range: −60.0–0.0.
mode
int
required
Modality of the track. 1 = major, 0 = minor.
speechiness
float
required
Presence of spoken words in a track. Range: 0.0–1.0. Values above 0.66 indicate tracks made entirely of spoken words.
acousticness
float
required
Confidence measure of whether the track is acoustic. Range: 0.0–1.0.
instrumentalness
float
required
Predicts whether a track contains no vocals. Range: 0.0–1.0. Values above 0.5 represent instrumental tracks.
liveness
float
required
Detects the presence of an audience in the recording. Range: 0.0–1.0. Values above 0.8 indicate a live performance.
valence
float
required
Musical positiveness conveyed by a track. Range: 0.0–1.0. High valence sounds more positive (happy, cheerful); low valence sounds more negative (sad, angry).
tempo
float
required
Overall estimated tempo of the track in beats per minute (BPM).
duration_ms
int
required
Duration of the track in milliseconds.

GET /health

A lightweight liveness probe. Use this endpoint to verify the API process is up before sending prediction traffic.
Student TODO: The GET /health route is not yet implemented in app/main.py. Students must add the endpoint decorated with @app.get("/health") that returns {"status": "healthy"} with HTTP 200.
PropertyValue
MethodGET
Path/health
AuthNone
Response{"status": "healthy"}
StatusHTTP 200
curl http://localhost:8000/health
# {"status": "healthy"}

POST /predict

Accepts a full SpotifyFeatures payload, runs inference using the baked-in @champion model via predict_genre(), and returns the predicted genre and confidence score.
PropertyValue
MethodPOST
Path/predict
Content-Typeapplication/json
Request bodySpotifyFeatures (all 12 fields required)
Response modelPredictionResponse
Success statusHTTP 200

Request Example

curl -X POST http://localhost:8000/predict \
  -H 'Content-Type: application/json' \
  -d '{
    "danceability": 0.7,
    "energy": 0.8,
    "key": 5,
    "loudness": -5.0,
    "mode": 1,
    "speechiness": 0.05,
    "acousticness": 0.1,
    "instrumentalness": 0.0,
    "liveness": 0.2,
    "valence": 0.6,
    "tempo": 120.0,
    "duration_ms": 240000
  }'

Response Example

{"genre": "Pop", "confidence": 0.85}

PredictionResponse Fields

PredictionResponse is defined in app/main.py as a complete Pydantic model (no student changes needed):
class PredictionResponse(BaseModel):
    genre: str
    confidence: float = 0.0
genre
string
Predicted genre name returned by the model (e.g. “Pop”, “Rock”, “Electronic”).
confidence
float
Model confidence score for the prediction (0.0–1.0), defaulting to 0.0. When fully implemented, this is the max value from model.predict_proba().

Request Logging Middleware

Every POST /predict request is intercepted by an HTTP middleware that appends a JSON line to logs/api_requests.jsonl before forwarding the request to the endpoint. The logs/ directory is created automatically if it does not exist.
Student TODO: The log_requests middleware in app/main.py is currently a skeleton that calls call_next immediately without logging. Students must implement the body-reading, JSON-parsing, timestamp-stamping, and JSONL-appending steps described in the inline comments.
Each line is a self-contained JSON object containing all 12 audio feature fields plus a timestamp field in ISO 8601 format:
{"danceability": 0.7, "energy": 0.8, "key": 5, "loudness": -5.0, "mode": 1, "speechiness": 0.05, "acousticness": 0.1, "instrumentalness": 0.0, "liveness": 0.2, "valence": 0.6, "tempo": 120.0, "duration_ms": 240000, "timestamp": "2024-01-15T10:23:45.123456"}
The logs/api_requests.jsonl file is the data source for the drift monitoring pipeline when running in online mode. Each prediction appended here is consumed by the monitoring component to detect distribution shift between live traffic and the training baseline.
The middleware reconstructs the request body after reading it so the /predict endpoint can still parse it correctly — a necessary step because HTTP request bodies are single-use streams.

Error Handling

Status CodeCondition
200 OKPrediction completed successfully. Response body contains genre and confidence.
422 Unprocessable EntityValidation error — one or more required fields are missing, have the wrong type, or the body is not valid JSON. Response body contains Pydantic’s detailed validation error.
500 Internal Server ErrorPrediction failed due to a model or runtime error. The exception is logged server-side; the response body contains {"detail": "Prediction failed"}.

Running Tests

The test suite lives in model_serving/tests/ and uses pytest with FastAPI’s built-in TestClient:
pytest model_serving/tests/
The suite contains three tests:
TestWhat It Covers
test_health_checkCalls GET /health and asserts HTTP 200 with body {"status": "healthy"}.
test_predict_endpoint_valid_payloadPosts a complete 12-field payload to POST /predict, asserts HTTP 200, and verifies both genre and confidence keys are present in the response.
test_predict_endpoint_invalid_payloadPosts a payload with only danceability (11 required fields missing), asserts HTTP 422 to confirm Pydantic validation is active.

Build docs developers (and LLMs) love