Dans ce projet, je suis dans le rôle d´un freelance en ML en mission pour Futurisys. Mon but est de déployer un modèle de ML de prédiction de départ d´employer.
Pour cela je pars de mon projet précédent (4) où je dispose de mon notebook contenant mon modèle entrainé.
L´objectif est de rendre le modèle utilisable en production tout en respectant les meilleurs pratiques de l´ingénierie logicielle. À la fin du projet, je dois avoir un POC fonctionnel.
Méthodologie
1 - Organisation du dépôt GIT
Structure de base:
/projet5
|-- /notebook # mes notebooks du projet 4
|-- /src # le code source de l´API, du modèle.
|-- /tests # les tests unitaires et fonctionnels
|-- /scripts # les script SQL, scripts de déploiements
|-- /docs # la documentation, schémas
|-- requirements.txt # dépendances générée à partir de pyproject.toml (pour compatibilité Docker)
|-- pyproject.toml # dépendances principales + metadonnées solveur UV
|-- main.py # main
|-- README.md # README
|-- .gitignore # Exclusion des fichiers inutiles
Branches:
main : code stable, prêt pour la production.
dev : Intégration des fonctinnalités testées.
features/* : une branche par fonctionnalité.
Le but est de travailler sur une nouvelle fonctionnalité dans feature/ma-fonctionnalite.
Quand la fonctionnalité est testée, je merge dans dev.
Je merge dev dans main quand je suis prêt pour la production
J´ai ensuite placer le ficheir "model.joblib" dans /src.
Mais ce model ne contient pas les deux étapes nécessaires à sont foncitonnement à savoir l´encodage des variables catégorielles et la standardisation des variables numériques. J´ai donc aussi extrait la pipeline complète de mon notebook et l´ai stocker dans /src. (evaluation_pipeline.joblib).
Avoir la pipeline complète va m´éviter de devoir recode l´encodage et la standardisation.
Je crée ensuite un script python qui charge ma pipeline (pipeline_loader.py). Dans ce script, je crée aussi une fonction qui permet de prédire avec le modèle. Dans cette fonction je dois ajouter le code pour vérifier que les données d´entrée sont au bon format (celui attendu par la pipeline).
[ ] Ajouter le code pour vérifier le bon format des données d´entrée dans la fonction predict de pipeline_loarder.py
3 - Développer l´API avec FastAPI et CI
Je commencer par créer ma branche dev.
Ajout de "fastapi" dans les dépendances avec uv add fastapi.
Création de l´app fastAPI dans main.py.
Ajout de "uvicorn" pour implementer le web server.
Pour lancer l´app, uvicorn main:app. Cela lancer le serveur sur http://127.0.0.1/8000.
Pour tester le fonctionnement de mon API, j´ai créé 2 endpoints:
get("/") qui renvoie un simple Hello World
get("/predict") qui renvoie la prédiction du premier élément lorsque j´envoie la totalité des data nettoyées (Dataframe extrait de mon projet précédent).
Cela me permet de valider le fonctionnement de mon serveur et celui de ma pipeline(OneHot + standardisation + modèle).
La base fonctionne. Maintenant je dois définir quelles sont les fonctionnalité que je souhaite avoir pour mon API.
Avant de commencer le développement de l´API, je dois mettre en place ma board pour la planification.
Dans le dépôt gitlab, j´ai créé mes labels, ma board. Je commence très simple avec une seule board: 'Development', contenant 2 colonnes 'To Do' et 'Doing', et seulement un 'type' de carte 'user story'. Cela me permet de commencer rapidement et facilement. Ceci étant la première fois que j´utilise cette méthodes et ce projet étant solo, je ne veux pas trop alourdir la méthodes de projet.
Cela ne m´empèche pas de la faire évoluer au fur et à mesure du projet en ajoutant des labels comme 'Epic' ou 'Evil User Story'.
Maintenant que j´ai créé la structure pour accueillir les User Stories, je peux commencer à en créer.
CREATION DE USER STORIES
Avec quelques User Stories de créées, je peux commencer le développement.
Les fonctionnalités de mon API dépendent de ma base de données. Je dois donc définir sa structure.
- Base de données
Les données d´entrée sont sous forme de 3 fichiers CSV fourni par les RH.
Afin de respecter la structure des CSV, je vais créer 3 tables avec les champs des CSV. J´ajouter les clés étrangères pour relier les tables.
Je crée aussi une table prediction pour stocker les prédictions.
Je rédige donc un script init_db.sql qui crée les tables.
Je créer une branche pour le développement de ma première feature: l´API FastAPI
Sur ma branche feature, je commence donc le développement en partant de mes User Story.
Ajout de ruff dans la pipeline CI et en pre-commit
Le but est ici d´ajouter le linter et formater ruff dans la pipeline CI mais aussi dans le pre-commit.
Je commence donc par ajouter ruff avec la commande:
uv add --dev ruff--dev car ruff ne sert pas en production.
Lancer les tests en local:
uv run uvicorn src.main:app --reload
export PYTHONPATH="${PYTHONPATH}:$(pwd)"
uv run pytest tests/ --cov=src --cov-report=term-missing
Se connecter à la base de donnée en local:
sudo -u postgres psql
Ajouter les droits à user1:
GRANT ALL PRIVILEGES ON DATABASE futurisys TO user1;
\c futurisys
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO user1;
Lancer l´app en local:
uv run uvicorn src.main:app --reload
AAAAAAA
CREATE USER user1 WITH PASSWORD 'password1' CREATEDB;
Changer le mode d´authentification ident => md5 dans pg_hba.conf (pour tourver le chemin: sudo find / -name pg_hba.conf 2>/dev/null
)
Puis sudo find / -name pg_hba.conf 2>/dev/null
Ensuite je peux lancer le script de création de la base et des tables:
uv run scripts/create_db.py
Ensutie je peux lancer le script d´import des CSV pour peupler la DB:
uv run scripts/import_data.py