This repository contains an end-to-end MLOps example for predicting flight arrival delays. It shows how data is ingested from Azure Blob Storage, feature-engineered, trained and logged to MLflow, packaged and served via a Flask API that performs inference using the latest model and preprocessor artifacts stored in blob storage.
requirements.txt
01-notebook/
training_delays.py # Feature engineering + training + MLflow logging
flight_delay.ipynb
new.csv # example / sample dataset
flasc_model/
train.py # (empty placeholder in this repo)
flask_API/
app.py # Flask app exposing /predict
predict.py # Inference helpers: loads latest model & preprocessor from blob, runs predictions
Dockerfile
mlruns/ # MLflow tracking artifact directory (if used locally)
models/ # Saved models (optional / local)
README.md
Note: Some files live in the 01-notebook folder and include the primary training and preprocessing pipeline (script form is present as training_delays.py). The predict.py in flask_API downloads the latest model/preprocessor from Azure Blob Storage and runs inference on an input CSV blob.
ASCII architecture summary:
- Data source: Azure Blob (container
rawflightsdata) - Training:
01-notebook/training_delays.pyreadsnew.csv(or reads from blob) and trains a BalancedRandomForestClassifier. It logs models + preprocessors to MLflow and (optionally) uploads pickled artifacts to a blob container namedmodels/preprocessors. - Serving:
flask_API/app.pyexposes a POST/predictendpoint which accepts a JSON payload withblob_name. The API callspredict.pywhich:- downloads the input CSV from
rawflightsdatacontainer, - finds the latest
delay_model_<version>.pklandpreprocessor_<version>.pklin their respective blob containers, - applies preprocessing and model predict,
- uploads
predictions_<blob_name>topredicted-flight-datacontainer and returns results in the API response.
- downloads the input CSV from
Set these before running training or the API:
AZURE_STORAGE_CONNECTION_STRING— connection string for an Azure Storage account used to store data, models and artifacts.AZURE_STORAGE_ACCOUNT— storage account name (used for artifact URIs in some scripts).MLFLOW_TRACKING_URI— MLflow tracking server URI (e.g.,http://localhost:5001or an external server).MLFLOW_EXPERIMENT_NAME— name for MLflow experiment (script appends_RFfor the random forest experiment).
Optional but useful:
MLFLOW_TRACKING_USERNAME/MLFLOW_TRACKING_PASSWORDif the MLflow server requires auth.
Primary dependencies are in requirements.txt and include (non-exhaustive):
- Flask
- pandas
- numpy
- scikit-learn
- joblib
- imbalanced-learn
- mlflow
- azure-storage-blob
- holidays
Install locally (recommended inside a virtualenv):
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtIf you add new runtime dependencies, add them to requirements.txt so Docker builds are consistent.
The training/feature engineering pipeline is in 01-notebook/training_delays.py. That file performs:
- loading the CSV training data (either local
new.csvor downloaded from blob storage), - feature engineering (date/time cyclic features, route/airline historical rates, holiday indicator, etc.),
- building a
ColumnTransformerpreprocessor, - training a BalancedRandomForestClassifier,
- logging parameters/metrics and saving the
preprocessorandmodelinto MLflow (and setting artifact tags),
To run training (locally):
# ensure env vars are set: AZURE_STORAGE_CONNECTION_STRING, MLFLOW_TRACKING_URI, MLFLOW_EXPERIMENT_NAME
python 01-notebook/training_delays.pyNotes:
- The training script will call MLflow APIs to record metrics and log models. Ensure
MLFLOW_TRACKING_URIis reachable. - The training script names models as
delay_model_<version>.pkl(the inference code expects that naming pattern). Confirm the naming used by your training script.
Start the Flask API (from flask_API folder):
cd flask_API
# Ensure AZURE_STORAGE_CONNECTION_STRING is set (and MLFLOW vars if needed)
python app.pyDefault: the app listens on port 5000 (Dockerfile exposes 5000 as well).
Endpoint:
- POST /predict
- JSON body:
{ "blob_name": "inputfile.csv" } - Example response: { "status": "success", "message": "Predicion Executed", "blob": "inputfile.csv", "results": [ { row1 }, { row2 }, ... ] }
- JSON body:
Sample curl (from any machine that can reach the API):
curl -X POST http://localhost:5000/predict \
-H "Content-Type: application/json" \
-d '{"blob_name": "sample_input.csv"}'What the API does under the hood (see flask_API/predict.py):
- downloads the CSV from the input container (name:
rawflightsdata), - loads latest model and preprocessor from blob containers
modelsandpreprocessors, - applies preprocessing and model prediction,
- writes
predictions_<blob_name>to containerpredicted-flight-dataand returns the predictions.
The inference code finds the latest model/preprocessor by matching a filename pattern like delay_model_<version>.pkl and preprocessor_<version>.pkl and selecting the highest version number. This implies:
- When saving artifacts from training, use a semantic version suffix (e.g.
delay_model_1.1.pkl). - Keep a consistent naming scheme so the inference function can pick the latest automatically.
If you prefer explicit model pinning, modify predict.py to read a specific artifact name from env or request.
The training script uses MLflow for experiment tracking. Common usage patterns:
- Run an MLflow server locally:
mlflow server --backend-store-uri sqlite:///mlflow.db --default-artifact-root ./mlruns --host 0.0.0.0 --port 5001 - Set
MLFLOW_TRACKING_URIto your server:export MLFLOW_TRACKING_URI=http://localhost:5001 - The training script will call
mlflow.sklearn.log_model(preprocessor, name="preprocessor")andmlflow.sklearn.log_model(brf, name="model").
If you'd like to use Azure Blob as the artifact store, configure MLflow's artifact location accordingly (the training code attempts to create an experiment with a wasbs:// artifact location if AZURE_STORAGE_ACCOUNT is set).
Build (from flask_API dir or modify path in Dockerfile):
cd flask_API
docker build -t flight-delay-api:latest .
# run container (pass env vars and map port)
docker run -e AZURE_STORAGE_CONNECTION_STRING="$AZURE_STORAGE_CONNECTION_STRING" -p 5000:5000 flight-delay-api:latestTips:
- For local development, prefer running
python app.pyinside a venv — faster iteration. - When running in production, supply a process manager (gunicorn) and proper logging, and set
--workersaccording to CPU.
- "Import X could not be resolved" — ensure dependencies are installed in the Python environment that VS Code or your runtime uses. Use
pip install -r requirements.txtand confirmpython -m pip listshows packages. - Azure auth / access errors — check
AZURE_STORAGE_CONNECTION_STRINGand ensure the target containers (rawflightsdata,models,preprocessors,predicted-flight-data) exist and the connection string has RW permissions. - MLflow connection issues — confirm
MLFLOW_TRACKING_URIis reachable from the machine running training and that the artifact store is writable. - Model not found — ensure training uploads or saves model artifacts with names matching the inference pattern
delay_model_<version>.pkl.
- Unit test the inference flow locally by placing a small CSV in Azure blob
rawflightsdataand call the API with that blob name. - Use
mlflowUI to inspect runs and confirm model + preprocessor were logged. - Use local storage emulators (Azurite) if you prefer to not use an Azure subscription during dev.
- Add CI workflow to run linting and tests.
- Add a small test harness that runs
predict.pywith a local CSV to verify preprocessing and model output. - Improve model pinning or add an environment-toggle for sticking to a specific model version in production.
- Add a
Makefileor tiny CLI script to standardize common tasks (train, serve, docker-build, mlflow-run).
- Fork the repository
- Create a branch:
git checkout -b feat/your-feature - Add tests and documentation updates
- Create a pull request
This project includes a MIT license file in the repository