ASI-Engineer commited on
Commit
47bae84
·
verified ·
1 Parent(s): c55f566

Upload folder using huggingface_hub

Browse files
Files changed (2) hide show
  1. README.md +225 -35
  2. src/gradio_ui.py +89 -52
README.md CHANGED
@@ -1,49 +1,239 @@
1
- ---
2
- title: Employee Turnover Prediction API
3
- emoji: 👔
4
- colorFrom: blue
5
- colorTo: purple
6
- sdk: docker
7
- pinned: true
8
- license: mit
9
- app_port: 8000
10
- ---
11
 
12
- # Employee Turnover Prediction API 🚀
13
 
14
- API de prédiction du turnover des employés avec XGBoost + SMOTE.
15
 
16
- ## 🎯 Fonctionnalités
17
-
18
- - Prédiction de turnover (0 = reste, 1 = part)
19
- - 📊 Probabilités et niveau de risque (Low/Medium/High)
 
20
  - 🔐 Authentification API Key
21
- - 📝 Logs structurés JSON
22
- - 🛡️ Rate limiting (20 req/min)
23
- - 📚 Documentation OpenAPI/Swagger
24
 
25
- ## 🔗 Endpoints
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
- - **Docs** : `/docs` - Documentation interactive
28
- - **Health** : `/health` - Status de l'API
29
- - **Predict** : `/predict` - Prédiction de turnover
30
 
31
- ## 🚀 Utilisation
32
 
33
  ```bash
34
- # Health check
35
- curl https://asi-engineer-employee-turnover-api.hf.space/health
 
 
 
36
 
37
- # Prédiction
38
- curl -X POST https://asi-engineer-employee-turnover-api.hf.space/predict \
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  -H "Content-Type: application/json" \
40
- -d '{
41
- "satisfaction_employee_environnement": 3,
42
- "satisfaction_employee_nature_travail": 4,
43
- ...
44
- }'
45
  ```
46
 
47
- ## 📚 Documentation complète
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
- Voir [GitHub Repository](https://github.com/chaton59/OC_P5) pour la documentation complète.
 
 
1
+ # 🚀 Employee Turnover Prediction API - v2.1.0
 
 
 
 
 
 
 
 
 
2
 
3
+ ## 📊 Vue d'ensemble
4
 
5
+ API REST de prédiction du turnover des employés basée sur un modèle XGBoost avec SMOTE.
6
 
7
+ **✨ Nouveautés v2.1.0** :
8
+ - 📝 Logging structuré JSON
9
+ - 🛡️ Rate limiting (20 req/min par IP)
10
+ - Gestion d'erreurs améliorée
11
+ - 📊 Monitoring des performances
12
  - 🔐 Authentification API Key
 
 
 
13
 
14
+ ## 🏗️ Architecture
15
+
16
+ ```
17
+ OC_P5/
18
+ ├── app.py # Point d'entrée FastAPI
19
+ ├── src/
20
+ │ ├── auth.py # Authentification API Key
21
+ │ ├── config.py # Configuration centralisée
22
+ │ ├── logger.py # Logging structuré (NOUVEAU)
23
+ │ ├── models.py # Chargement modèle HF Hub
24
+ │ ├── preprocessing.py # Pipeline preprocessing
25
+ │ ├── rate_limit.py # Rate limiting (NOUVEAU)
26
+ │ └── schemas.py # Validation Pydantic
27
+ ├── tests/ # Suite pytest (33 tests, 88% couverture)
28
+ ├── logs/ # Logs JSON (NOUVEAU)
29
+ │ ├── api.log # Tous les logs
30
+ │ └── error.log # Erreurs uniquement
31
+ ├── docs/ # Documentation
32
+ ├── ml_model/ # Scripts training
33
+ └── data/ # Données sources
34
+ ```
35
+
36
+ ## 🚀 Installation
37
+
38
+ ### Prérequis
39
+ - Python 3.12+
40
+ - Poetry 1.7+
41
+ - Git
42
+
43
+ ### Setup rapide
44
+
45
+ ```bash
46
+ # 1. Cloner le repo
47
+ git clone https://github.com/chaton59/OC_P5.git
48
+ cd OC_P5
49
+
50
+ # 2. Installer les dépendances
51
+ poetry install
52
+
53
+ # 3. Configurer l'environnement
54
+ cp .env.example .env
55
+ # Éditer .env avec vos valeurs
56
+
57
+ # 4. Lancer l'API
58
+ poetry run uvicorn app:app --reload
59
 
60
+ # 5. Accéder à la documentation
61
+ # http://localhost:8000/docs
62
+ ```
63
 
64
+ ## 📝 Configuration (.env)
65
 
66
  ```bash
67
+ # Mode développement (désactive auth + active logs détaillés)
68
+ DEBUG=true
69
+
70
+ # API Key (requis en production)
71
+ API_KEY=your-secret-key-here
72
 
73
+ # Logging (DEBUG, INFO, WARNING, ERROR, CRITICAL)
74
+ LOG_LEVEL=INFO
75
+
76
+ # HuggingFace Model
77
+ HF_MODEL_REPO=ASI-Engineer/employee-turnover-model
78
+ MODEL_FILENAME=model/model.pkl
79
+ ```
80
+
81
+ ## 🔒 Authentification
82
+
83
+ ### Mode DEBUG (développement)
84
+ ```bash
85
+ # L'API Key n'est PAS requise
86
+ curl http://localhost:8000/predict -H "Content-Type: application/json" -d '{...}'
87
+ ```
88
+
89
+ ### Mode PRODUCTION
90
+ ```bash
91
+ # L'API Key est REQUISE
92
+ curl http://localhost:8000/predict \
93
+ -H "X-API-Key: your-secret-key" \
94
  -H "Content-Type: application/json" \
95
+ -d '{...}'
 
 
 
 
96
  ```
97
 
98
+ ## 📡 Endpoints
99
+
100
+ ### 🏥 Health Check
101
+ ```bash
102
+ GET /health
103
+
104
+ # Réponse
105
+ {
106
+ "status": "healthy",
107
+ "model_loaded": true,
108
+ "model_type": "Pipeline",
109
+ "version": "2.1.0"
110
+ }
111
+ ```
112
+
113
+ ### 🔮 Prédiction
114
+ ```bash
115
+ POST /predict
116
+ Content-Type: application/json
117
+ X-API-Key: your-key (en production)
118
+
119
+ # Exemple payload (voir docs/API_GUIDE.md pour tous les champs)
120
+ {
121
+ "satisfaction_employee_environnement": 3,
122
+ "satisfaction_employee_nature_travail": 4,
123
+ "satisfaction_employee_equipe": 5,
124
+ "satisfaction_employee_equilibre_pro_perso": 3,
125
+ "note_evaluation_actuelle": 85,
126
+ "annees_depuis_la_derniere_promotion": 2,
127
+ "nombre_formations_realisees": 3,
128
+ ...
129
+ }
130
+
131
+ # Réponse
132
+ {
133
+ "prediction": 0, # 0 = reste, 1 = part
134
+ "probability_0": 0.85, # Probabilité de rester
135
+ "probability_1": 0.15, # Probabilité de partir
136
+ "risk_level": "Low" # Low, Medium, High
137
+ }
138
+ ```
139
+
140
+ ## 📊 Logging
141
+
142
+ ### Logs structurés JSON
143
+
144
+ **Fichiers** :
145
+ - `logs/api.log` : Tous les logs
146
+ - `logs/error.log` : Erreurs uniquement
147
+
148
+ **Format** :
149
+ ```json
150
+ {
151
+ "timestamp": "2025-12-26T10:30:45",
152
+ "level": "INFO",
153
+ "logger": "employee_turnover_api",
154
+ "message": "Request POST /predict",
155
+ "method": "POST",
156
+ "path": "/predict",
157
+ "status_code": 200,
158
+ "duration_ms": 23.45,
159
+ "client_host": "127.0.0.1"
160
+ }
161
+ ```
162
+
163
+ ## 🛡️ Rate Limiting
164
+
165
+ **Configuration** :
166
+ - **Développement** : Désactivé (DEBUG=true)
167
+ - **Production** : 20 requêtes/minute par IP ou API Key
168
+
169
+ **En cas de dépassement** :
170
+ ```json
171
+ {
172
+ "error": "Rate limit exceeded",
173
+ "message": "20 per 1 minute"
174
+ }
175
+ ```
176
+
177
+ ## ✅ Tests
178
+
179
+ ```bash
180
+ # Tous les tests
181
+ poetry run pytest tests/ -v
182
+
183
+ # Avec couverture
184
+ poetry run pytest tests/ --cov --cov-report=html
185
+
186
+ # Voir rapport HTML
187
+ open htmlcov/index.html
188
+ ```
189
+
190
+ **Résultats** :
191
+ - ✅ 33 tests passés
192
+ - 📊 88% de couverture globale
193
+
194
+ ## 🚀 Déploiement
195
+
196
+ ### Variables d'environnement requises
197
+ ```bash
198
+ DEBUG=false
199
+ API_KEY=<votre-clé-sécurisée>
200
+ LOG_LEVEL=INFO
201
+ ```
202
+
203
+ ### HuggingFace Spaces
204
+ Prêt pour déploiement avec `app.py` et `requirements.txt`
205
+
206
+ ## 📚 Documentation
207
+
208
+ - **API Interactive** : http://localhost:8000/docs
209
+ - **ReDoc** : http://localhost:8000/redoc
210
+ - **Guide complet** : [docs/API_GUIDE.md](docs/API_GUIDE.md)
211
+ - **Standards** : [docs/standards.md](docs/standards.md)
212
+ - **Couverture tests** : [docs/TEST_COVERAGE.md](docs/TEST_COVERAGE.md)
213
+
214
+ ## 📦 Dépendances principales
215
+
216
+ - **FastAPI** 0.115.14 : Framework web
217
+ - **Pydantic** 2.12.5 : Validation données
218
+ - **XGBoost** 2.1.3 : Modèle ML
219
+ - **SlowAPI** 0.1.9 : Rate limiting
220
+ - **python-json-logger** 4.0.0 : Logs structurés
221
+ - **pytest** 9.0.2 : Tests
222
+
223
+ ## 🔄 Changelog
224
+
225
+ ### v2.1.0 (26 décembre 2025)
226
+ - ✨ Système de logging structuré JSON
227
+ - 🛡️ Rate limiting avec SlowAPI
228
+ - ⚡ Amélioration gestion d'erreurs
229
+ - 📊 Monitoring des performances
230
+
231
+ ### v2.0.0 (26 décembre 2025)
232
+ - ✅ Suite de tests complète (33 tests)
233
+ - 🔐 Authentification API Key
234
+ - 📊 88% de couverture de code
235
+
236
+ ## 👥 Auteurs
237
 
238
+ - **Projet** : OpenClassrooms P5
239
+ - **Repo** : [github.com/chaton59/OC_P5](https://github.com/chaton59/OC_P5)
src/gradio_ui.py CHANGED
@@ -7,11 +7,23 @@ Cette interface permet de:
7
  - Visualiser la documentation de l'API
8
  - Comprendre les champs requis
9
  """
 
 
10
  import gradio as gr
 
 
 
11
 
12
- from src.models import load_model, get_model_info
13
- from src.preprocessing import preprocess_for_prediction
14
- from src.schemas import EmployeeInput
 
 
 
 
 
 
 
15
 
16
 
17
  def predict_turnover(
@@ -49,68 +61,93 @@ def predict_turnover(
49
  annees_dans_l_entreprise: int,
50
  annees_dans_le_poste_actuel: int,
51
  ) -> str:
52
- """Effectue une prédiction de turnover."""
53
  try:
54
- # Créer l'objet EmployeeInput
55
- employee = EmployeeInput(
56
- nombre_participation_pee=nombre_participation_pee,
57
- nb_formations_suivies=nb_formations_suivies,
58
- nombre_employee_sous_responsabilite=nombre_employee_sous_responsabilite,
59
- distance_domicile_travail=distance_domicile_travail,
60
- niveau_education=niveau_education,
61
- domaine_etude=domaine_etude,
62
- ayant_enfants=ayant_enfants,
63
- frequence_deplacement=frequence_deplacement,
64
- annees_depuis_la_derniere_promotion=annees_depuis_la_derniere_promotion,
65
- annes_sous_responsable_actuel=annes_sous_responsable_actuel,
66
- satisfaction_employee_environnement=satisfaction_employee_environnement,
67
- note_evaluation_precedente=note_evaluation_precedente,
68
- niveau_hierarchique_poste=niveau_hierarchique_poste,
69
- satisfaction_employee_nature_travail=satisfaction_employee_nature_travail,
70
- satisfaction_employee_equipe=satisfaction_employee_equipe,
71
- satisfaction_employee_equilibre_pro_perso=satisfaction_employee_equilibre_pro_perso,
72
- note_evaluation_actuelle=note_evaluation_actuelle,
73
- heure_supplementaires=heure_supplementaires,
74
- augementation_salaire_precedente=augementation_salaire_precedente,
75
- age=age,
76
- genre=genre,
77
- revenu_mensuel=revenu_mensuel,
78
- statut_marital=statut_marital,
79
- departement=departement,
80
- poste=poste,
81
- nombre_experiences_precedentes=nombre_experiences_precedentes,
82
- nombre_heures_travailless=nombre_heures_travailless,
83
- annee_experience_totale=annee_experience_totale,
84
- annees_dans_l_entreprise=annees_dans_l_entreprise,
85
- annees_dans_le_poste_actuel=annees_dans_le_poste_actuel,
86
- )
87
-
88
- # Préprocessing
89
- features = preprocess_for_prediction(employee)
90
-
91
- # Prédiction
92
- model = load_model()
93
- prediction = model.predict(features)[0]
94
- proba = model.predict_proba(features)[0]
95
-
96
- # Résultat
97
- risk_level = "🔴 RISQUE ÉLEVÉ" if prediction == 1 else "🟢 RISQUE FAIBLE"
98
- confidence = max(proba) * 100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99
 
100
  result = f"""
101
- ## {risk_level}
102
 
103
  ### Résultat de la prédiction
104
  - **Prédiction**: {"Départ probable" if prediction == 1 else "Maintien probable"}
105
  - **Confiance**: {confidence:.1f}%
106
- - **Probabilité de départ**: {proba[1] * 100:.1f}%
107
- - **Probabilité de maintien**: {proba[0] * 100:.1f}%
108
 
109
  ### Interprétation
110
  {"⚠️ Cet employé présente des facteurs de risque de départ. Il est recommandé d'engager un dialogue pour comprendre ses attentes." if prediction == 1 else "✅ Cet employé semble stable. Continuez à maintenir un environnement de travail positif."}
111
  """
112
  return result
113
 
 
 
 
 
114
  except Exception as e:
115
  return f"❌ **Erreur**: {str(e)}"
116
 
 
7
  - Visualiser la documentation de l'API
8
  - Comprendre les champs requis
9
  """
10
+ import os
11
+
12
  import gradio as gr
13
+ import httpx
14
+
15
+ from src.models import get_model_info
16
 
17
+
18
+ # URL de base pour les appels API (localhost en dev, relatif en prod)
19
+ def get_api_base_url() -> str:
20
+ """Retourne l'URL de base de l'API."""
21
+ # En production sur HF Spaces, utiliser le même host
22
+ space_host = os.getenv("SPACE_HOST")
23
+ if space_host:
24
+ return f"https://{space_host}"
25
+ # En local
26
+ return "http://localhost:8000"
27
 
28
 
29
  def predict_turnover(
 
61
  annees_dans_l_entreprise: int,
62
  annees_dans_le_poste_actuel: int,
63
  ) -> str:
64
+ """Effectue une prédiction de turnover via l'API REST."""
65
  try:
66
+ # Construire le payload pour l'API
67
+ payload = {
68
+ "nombre_participation_pee": int(nombre_participation_pee),
69
+ "nb_formations_suivies": int(nb_formations_suivies),
70
+ "nombre_employee_sous_responsabilite": int(
71
+ nombre_employee_sous_responsabilite
72
+ ),
73
+ "distance_domicile_travail": int(distance_domicile_travail),
74
+ "niveau_education": int(niveau_education),
75
+ "domaine_etude": domaine_etude,
76
+ "ayant_enfants": ayant_enfants,
77
+ "frequence_deplacement": frequence_deplacement,
78
+ "annees_depuis_la_derniere_promotion": int(
79
+ annees_depuis_la_derniere_promotion
80
+ ),
81
+ "annes_sous_responsable_actuel": int(annes_sous_responsable_actuel),
82
+ "satisfaction_employee_environnement": int(
83
+ satisfaction_employee_environnement
84
+ ),
85
+ "note_evaluation_precedente": int(note_evaluation_precedente),
86
+ "niveau_hierarchique_poste": int(niveau_hierarchique_poste),
87
+ "satisfaction_employee_nature_travail": int(
88
+ satisfaction_employee_nature_travail
89
+ ),
90
+ "satisfaction_employee_equipe": int(satisfaction_employee_equipe),
91
+ "satisfaction_employee_equilibre_pro_perso": int(
92
+ satisfaction_employee_equilibre_pro_perso
93
+ ),
94
+ "note_evaluation_actuelle": int(note_evaluation_actuelle),
95
+ "heure_supplementaires": heure_supplementaires,
96
+ "augementation_salaire_precedente": float(augementation_salaire_precedente),
97
+ "age": int(age),
98
+ "genre": genre,
99
+ "revenu_mensuel": float(revenu_mensuel),
100
+ "statut_marital": statut_marital,
101
+ "departement": departement,
102
+ "poste": poste,
103
+ "nombre_experiences_precedentes": int(nombre_experiences_precedentes),
104
+ "nombre_heures_travailless": int(nombre_heures_travailless),
105
+ "annee_experience_totale": int(annee_experience_totale),
106
+ "annees_dans_l_entreprise": int(annees_dans_l_entreprise),
107
+ "annees_dans_le_poste_actuel": int(annees_dans_le_poste_actuel),
108
+ }
109
+
110
+ # Appeler l'API REST
111
+ api_url = get_api_base_url()
112
+ with httpx.Client(timeout=30.0) as client:
113
+ response = client.post(f"{api_url}/predict", json=payload)
114
+ response.raise_for_status()
115
+ data = response.json()
116
+
117
+ # Formater le résultat
118
+ prediction = data["prediction"]
119
+ prob_1 = data["probability_1"]
120
+ prob_0 = data["probability_0"]
121
+ risk_level = data["risk_level"]
122
+
123
+ # Affichage
124
+ if risk_level == "High":
125
+ risk_emoji = "🔴 RISQUE ÉLEVÉ"
126
+ elif risk_level == "Medium":
127
+ risk_emoji = "🟠 RISQUE MOYEN"
128
+ else:
129
+ risk_emoji = "🟢 RISQUE FAIBLE"
130
+
131
+ confidence = max(prob_0, prob_1) * 100
132
 
133
  result = f"""
134
+ ## {risk_emoji}
135
 
136
  ### Résultat de la prédiction
137
  - **Prédiction**: {"Départ probable" if prediction == 1 else "Maintien probable"}
138
  - **Confiance**: {confidence:.1f}%
139
+ - **Probabilité de départ**: {prob_1 * 100:.1f}%
140
+ - **Probabilité de maintien**: {prob_0 * 100:.1f}%
141
 
142
  ### Interprétation
143
  {"⚠️ Cet employé présente des facteurs de risque de départ. Il est recommandé d'engager un dialogue pour comprendre ses attentes." if prediction == 1 else "✅ Cet employé semble stable. Continuez à maintenir un environnement de travail positif."}
144
  """
145
  return result
146
 
147
+ except httpx.HTTPStatusError as e:
148
+ return f"❌ **Erreur API**: {e.response.status_code} - {e.response.text}"
149
+ except httpx.RequestError as e:
150
+ return f"❌ **Erreur de connexion**: {str(e)}"
151
  except Exception as e:
152
  return f"❌ **Erreur**: {str(e)}"
153