lcamara/deployMLModel
Déployez un modèle de Machine Learning
Projet 5 du parcours AI Engineer — déploiement en production d'un modèle de Machine Learning pour le client fictif Futurisys.
L'objectif : exposer un modèle ML via une API FastAPI, persister les échanges dans une base PostgreSQL, garantir la qualité avec une suite de tests Pytest, et automatiser le déploiement via un pipeline CI/CD (GitHub Actions + Hugging Face Spaces).
Sommaire
- Démo en ligne
- Prérequis
- Installation
- Structure du projet
- Utilisation
- Tests
- Déploiement
- Architecture
- Conventions
Démo en ligne
- Space Hugging Face : <https://huggingface.co/spaces/lcamara/deployMLModel>
- Documentation interactive (Swagger UI) : <https://lcamara-deploymlmodel.hf.space/docs>
Prérequis
- Python >= 3.10
- PostgreSQL >= 14 (local ou via Docker)
- Git
Installation
# Cloner le dépôt
git clone git@github.com:Formation-AI-Engineer/deployez-un-modele-de-machine-learning.git
cd deployez-un-modele-de-machine-learning
# Créer et activer un environnement virtuel
python3 -m venv .venv
source .venv/bin/activate # Linux/Mac
# .venv\Scripts\activate # Windows
# Installer les dépendances (runtime + dev)
pip install -e ".[dev]"Configuration
Copier le fichier d'exemple et adapter les valeurs :
cp .env.example .envVariables disponibles (chargées via app/config.py avec pydantic-settings) :
.env et .env.* sont gitignorés. Seul .env.example est versionné comme template.
Structure du projet
.
├── app/ # Code de l'API FastAPI
│ ├── routers/ # Endpoints (APIRouter)
│ ├── services/ # Logique métier (prédiction)
│ └── schemas/ # Modèles Pydantic
├── db/ # Scripts base de données, modèles ORM
├── models/ # Modèles ML sérialisés (gitignored, régénérés via train_model.py)
├── data/ # CSV synthétiques du dataset (trackés ; sous-dossiers raw/interim/processed gitignorés)
├── scripts/ # Scripts utilitaires (train_model.py, seed_db.py)
├── tests/
│ ├── unit/ # Tests unitaires
│ └── functional/ # Tests fonctionnels / end-to-end
├── docs/ # Documentation technique
├── .github/workflows/ # Pipeline CI/CD (ci-cd.yml)
├── .env.example # Template des variables d'environnement
├── pyproject.toml # Dépendances et configuration
└── README.mdUtilisation
Entraîner le modèle (prérequis)
Le modèle CatBoost sérialisé (models/catboost_attrition.cbm) n'est pas versionné. Il faut l'entraîner une fois avant de lancer l'API :
python3 scripts/train_model.pyLes 3 CSV nécessaires (extrait_sirh.csv, extrait_eval.csv, extrait_sondage.csv) sont déjà dans data/.
En local (développement)
1. Démarrer PostgreSQL — soit via le service db du docker-compose (option la plus simple) :
docker compose up -d db…soit en utilisant une instance Postgres déjà installée (adapter DATABASE_URL dans .env en conséquence).
2. Lancer l'API :
source .venv/bin/activate
uvicorn app.main:app --reloadLes tables sont créées automatiquement au démarrage (Base.metadata.create_all dans app/main.py). Aucune migration à lancer.
3. (Optionnel) Pré-remplir la base — utile si tu veux interroger le dataset original via SQL ; non requis pour faire des prédictions :
python3 scripts/seed_db.pyAvec Docker Compose (API + PostgreSQL)
# Lancer l'ensemble (API + base de données)
docker compose up --build -d
# Importer le dataset dans la base (une seule fois)
docker compose exec api python scripts/seed_db.py
# Arrêter
docker compose downDocumentation interactive (Swagger UI) :
- Local : <http://localhost:8000/docs>
- Docker / Compose : <http://localhost:7860/docs>
Exemples d'appels API
Les exemples ci-dessous ciblent l'instance locale Docker Compose (port 7860). Adapter le hôte si besoin.
Health check
curl http://localhost:7860/health
# {"status":"ok"}Prédiction à partir de caractéristiques RH (POST /predict)
curl -X POST http://localhost:7860/predict \
-H "Content-Type: application/json" \
-d '{
"age": 35, "genre": "M", "revenu_mensuel": 5000,
"nombre_experiences_precedentes": 3, "annee_experience_totale": 10,
"annees_dans_l_entreprise": 5,
"satisfaction_employee_environnement": 3, "satisfaction_employee_nature_travail": 3,
"satisfaction_employee_equipe": 3, "satisfaction_employee_equilibre_pro_perso": 2,
"note_evaluation_actuelle": 3, "note_evaluation_precedente": 3,
"heure_supplementaires": "Non", "augementation_salaire_precedente": 12.0,
"nombre_participation_pee": 2, "nb_formations_suivies": 3,
"distance_domicile_travail": 10, "niveau_education": 3,
"frequence_deplacement": "Occasionnel", "annees_depuis_la_derniere_promotion": 1,
"statut_marital": "Marié(e)", "departement": "Consulting",
"poste": "Consultant", "domaine_etude": "Data Science"
}'Réponse :
{
"prediction_id": 42,
"prediction": "Non",
"probability": 0.2134,
"risk_level": "faible",
"threshold": 0.5,
"model_version": "1.0.0",
"timestamp": "2026-04-17T10:42:00Z"
}Historique des prédictions
curl "http://localhost:7860/predictions?skip=0&limit=10"
curl http://localhost:7860/predictions/42Tests
51 tests (unitaires + fonctionnels) couvrent la validation Pydantic, le préprocessing, le service de prédiction, l'ORM et l'ensemble des endpoints. Couverture actuelle : 88 % (cible ≥ 80 %).
# Suite complète (SQLite temporaire auto — pas besoin de Postgres)
pytest
# Avec rapport de couverture console
pytest --cov=app --cov-report=term-missing
# Avec rapport HTML → ouvre htmlcov/index.html
pytest --cov=app --cov-report=htmlLes tests sont exécutés automatiquement en CI (job test dans .github/workflows/ci-cd.yml).
Déploiement
L'API est déployée automatiquement sur Hugging Face Spaces (type Docker) via GitHub Actions.
Pipeline CI/CD
Fichier : `.github/workflows/ci-cd.yml`
push/PR → lint (ruff) → test (pytest --cov) → deploy (push vers HF Spaces)Déclencheurs :
pushsurdev→ lint + tests uniquement (feedback rapide)pull_requestversmain→ lint + tests (gate de merge, CI bloquante)pushsurmainou tagv*→ lint + tests + déploiement HF
Secrets requis (GitHub Settings > Secrets and variables > Actions)
Mécanique du déploiement
Le job deploy force-push le contenu du repo Git vers le repo Git du Space Hugging Face. Le Space, configuré en mode Docker, build l'image à partir du Dockerfile à la racine, qui :
- Installe les dépendances Python (
pip install .) - Lance
scripts/train_model.pypour régénérermodels/catboost_attrition.cbm(le.cbmn'est pas versionné) - Expose l'API sur le port
7860(convention HF Spaces)
Base de données en production
L'API en prod pointe vers une instance PostgreSQL managée chez [Neon](https://neon.tech). La connexion est fournie au Space via la variable d'environnement DATABASE_URL configurée dans les secrets du Space (HF Settings → Variables and secrets).
Architecture
Composants
Le client HTTP envoie une requête JSON à l'API FastAPI (servie par Uvicorn). L'API charge le modèle CatBoost une seule fois au démarrage (singleton en mémoire) et utilise SQLAlchemy pour persister chaque prédiction dans PostgreSQL.
Flux d'une requête /predict
- Le client envoie un
POST /predictavec un payload JSON. - Le router (
app/routers/prediction.py) valide le payload via le schéma PydanticPredictionInput. Si les types ou bornes ne sont pas respectés, FastAPI retourne422immédiatement. - Le router appelle le service
predict_and_record(data, db)(app/services/prediction.py). - Le service applique le préprocessing (
app/preprocessing.py), passe les features à CatBoost (predict_proba) et récupère la probabilité. - Le service insère un enregistrement dans la table
predictions(input + output + métadonnées) via SQLAlchemy. - Le router renvoie au client la réponse sérialisée par
PredictionOutput.
Couches : routers/ (HTTP) → services/ (métier + DB) → db/models.py (entités SQLAlchemy). Les schemas/ (Pydantic) définissent le contrat d'API en entrée/sortie, distincts des entités DB.
Le préprocessing (app/preprocessing.py) est partagé entre l'entraînement (scripts/train_model.py) et l'inférence pour garantir que les features sont strictement identiques dans les deux cas.
Stack technique
Conventions
Branches
main: branche stable, protégéedev: branche d'intégrationfeature/<nom>: nouvelles fonctionnalitésfix/<nom>: corrections de bugsdocs/<nom>: documentation uniquement
Commits
Format recommandé : Conventional Commits
<type>(<scope>): <description>
Exemples :
feat(api): add /predict endpoint
fix(db): handle connection timeout
docs(readme): add installation stepsTypes courants : feat, fix, docs, test, refactor, chore, ci.
Versioning
SemVer — tags vMAJOR.MINOR.PATCH. Voir la page Releases pour l'historique des versions.
Auteur
Lamine Camara — formation AI Engineer (OpenClassrooms)
