ASI-Engineer commited on
Commit
9589a90
·
verified ·
1 Parent(s): ccc7217

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. README.md +225 -35
  2. src/gradio_ui.py +24 -3
  3. src/schemas.py +19 -1
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
@@ -305,7 +305,14 @@ def create_gradio_interface():
305
  1, 5, value=3, step=1, label="Niveau éducation (1-5)"
306
  )
307
  domaine_etude = gr.Dropdown(
308
- ["Infra & Cloud", "Transformation Digitale", "Autre"],
 
 
 
 
 
 
 
309
  value="Infra & Cloud",
310
  label="Domaine d'études",
311
  )
@@ -377,11 +384,25 @@ def create_gradio_interface():
377
  label="Statut marital",
378
  )
379
  departement = gr.Dropdown(
380
- ["Commercial", "Consulting"],
381
  value="Commercial",
382
  label="Département",
383
  )
384
- poste = gr.Textbox(value="Consultant", label="Poste")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
385
  nombre_experiences_precedentes = gr.Slider(
386
  0, 10, value=2, step=1, label="Expériences précédentes"
387
  )
 
305
  1, 5, value=3, step=1, label="Niveau éducation (1-5)"
306
  )
307
  domaine_etude = gr.Dropdown(
308
+ [
309
+ "Infra & Cloud",
310
+ "Transformation Digitale",
311
+ "Marketing",
312
+ "Entrepreunariat",
313
+ "Ressources Humaines",
314
+ "Autre",
315
+ ],
316
  value="Infra & Cloud",
317
  label="Domaine d'études",
318
  )
 
384
  label="Statut marital",
385
  )
386
  departement = gr.Dropdown(
387
+ ["Commercial", "Consulting", "Ressources Humaines"],
388
  value="Commercial",
389
  label="Département",
390
  )
391
+ poste = gr.Dropdown(
392
+ [
393
+ "Cadre Commercial",
394
+ "Assistant de Direction",
395
+ "Consultant",
396
+ "Tech Lead",
397
+ "Manager",
398
+ "Senior Manager",
399
+ "Représentant Commercial",
400
+ "Directeur Technique",
401
+ "Ressources Humaines",
402
+ ],
403
+ value="Consultant",
404
+ label="Poste",
405
+ )
406
  nombre_experiences_precedentes = gr.Slider(
407
  0, 10, value=2, step=1, label="Expériences précédentes"
408
  )
src/schemas.py CHANGED
@@ -32,6 +32,7 @@ class DepartementEnum(str, Enum):
32
 
33
  COMMERCIAL = "Commercial"
34
  CONSULTING = "Consulting"
 
35
 
36
 
37
  class DomaineEtudeEnum(str, Enum):
@@ -39,9 +40,26 @@ class DomaineEtudeEnum(str, Enum):
39
 
40
  INFRA_CLOUD = "Infra & Cloud"
41
  TRANSFORMATION_DIGITALE = "Transformation Digitale"
 
 
 
42
  AUTRE = "Autre"
43
 
44
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  class FrequenceDeplacementEnum(str, Enum):
46
  """Fréquence des déplacements professionnels."""
47
 
@@ -121,7 +139,7 @@ class EmployeeInput(BaseModel):
121
  revenu_mensuel: float = Field(..., ge=1000, description="Revenu mensuel (€)")
122
  statut_marital: StatutMaritalEnum = Field(..., description="Statut marital")
123
  departement: DepartementEnum = Field(..., description="Département")
124
- poste: str = Field(..., min_length=3, description="Intitulé du poste")
125
  nombre_experiences_precedentes: int = Field(
126
  ..., ge=0, description="Nombre d'expériences précédentes"
127
  )
 
32
 
33
  COMMERCIAL = "Commercial"
34
  CONSULTING = "Consulting"
35
+ RESSOURCES_HUMAINES = "Ressources Humaines"
36
 
37
 
38
  class DomaineEtudeEnum(str, Enum):
 
40
 
41
  INFRA_CLOUD = "Infra & Cloud"
42
  TRANSFORMATION_DIGITALE = "Transformation Digitale"
43
+ MARKETING = "Marketing"
44
+ ENTREPREUNARIAT = "Entrepreunariat"
45
+ RESSOURCES_HUMAINES = "Ressources Humaines"
46
  AUTRE = "Autre"
47
 
48
 
49
+ class PosteEnum(str, Enum):
50
+ """Poste de l'employé."""
51
+
52
+ CADRE_COMMERCIAL = "Cadre Commercial"
53
+ ASSISTANT_DIRECTION = "Assistant de Direction"
54
+ CONSULTANT = "Consultant"
55
+ TECH_LEAD = "Tech Lead"
56
+ MANAGER = "Manager"
57
+ SENIOR_MANAGER = "Senior Manager"
58
+ REPRESENTANT_COMMERCIAL = "Représentant Commercial"
59
+ DIRECTEUR_TECHNIQUE = "Directeur Technique"
60
+ RESSOURCES_HUMAINES = "Ressources Humaines"
61
+
62
+
63
  class FrequenceDeplacementEnum(str, Enum):
64
  """Fréquence des déplacements professionnels."""
65
 
 
139
  revenu_mensuel: float = Field(..., ge=1000, description="Revenu mensuel (€)")
140
  statut_marital: StatutMaritalEnum = Field(..., description="Statut marital")
141
  departement: DepartementEnum = Field(..., description="Département")
142
+ poste: PosteEnum = Field(..., description="Intitulé du poste")
143
  nombre_experiences_precedentes: int = Field(
144
  ..., ge=0, description="Nombre d'expériences précédentes"
145
  )