ASI-Engineer commited on
Commit
6e87ea4
·
verified ·
1 Parent(s): 74e4534

Upload folder using huggingface_hub

Browse files
Files changed (4) hide show
  1. README.md +82 -1
  2. api.py +12 -6
  3. app.py +7 -0
  4. src/config.py +11 -1
README.md CHANGED
@@ -178,7 +178,9 @@ OC_P5/
178
  │ └── preprocess.py # Preprocessing dataset
179
  ├── scripts/ # 🔧 Scripts utilitaires
180
  │ ├── create_db.py # Création base PostgreSQL
181
- └── insert_dataset.py # Insertion données
 
 
182
  ├── docs/ # 📚 Documentation (5 fichiers minimaux)
183
  │ ├── architecture.md # 🏗️ Vue d'ensemble architecture + schéma BDD
184
  │ ├── api_documentation.md # 📡 Endpoints REST + exemples cURL/Python
@@ -373,6 +375,83 @@ poetry run pytest tests/ -v
373
 
374
  ---
375
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  ## 🚀 Utilisation
377
 
378
  ### Démarrer l'API Localement
@@ -761,6 +840,8 @@ poetry run pytest tests/ --cov=. --cov-report=html
761
  open htmlcov/index.html
762
  ```
763
 
 
 
764
  ### Métriques
765
 
766
  | Métrique | Valeur | Détail |
 
178
  │ └── preprocess.py # Preprocessing dataset
179
  ├── scripts/ # 🔧 Scripts utilitaires
180
  │ ├── create_db.py # Création base PostgreSQL
181
+ ├── insert_dataset.py # Insertion données (1470 employés)
182
+ │ ├── generate_requirements_hf.sh # Génération requirements.txt pour HF
183
+ │ └── run_local.sh # Lancement local développement
184
  ├── docs/ # 📚 Documentation (5 fichiers minimaux)
185
  │ ├── architecture.md # 🏗️ Vue d'ensemble architecture + schéma BDD
186
  │ ├── api_documentation.md # 📡 Endpoints REST + exemples cURL/Python
 
375
 
376
  ---
377
 
378
+ ## 🔧 Scripts Utilitaires
379
+
380
+ Le dossier `scripts/` contient les scripts essentiels pour la gestion de la base de données et le déploiement. **Minimalisme** : 4 fichiers maximum, code principal dans `src/`, tests dans `tests/`.
381
+
382
+ ### 🗄️ `create_db.py` - Création de la base de données
383
+
384
+ **Rôle** : Crée la base de données PostgreSQL et les tables nécessaires (étape 4 du projet).
385
+
386
+ ```bash
387
+ # Créer les tables (dataset, ml_logs)
388
+ poetry run python scripts/create_db.py
389
+ ```
390
+
391
+ **Tables créées** :
392
+ - `dataset` : Stockage des données d'entraînement (features_json, target)
393
+ - `ml_logs` : Logs des prédictions de l'API (inputs, outputs, timestamps)
394
+
395
+ ### 📊 `insert_dataset.py` - Insertion du dataset
396
+
397
+ **Rôle** : Charge les 3 fichiers CSV (sondage, eval, sirh), les fusionne et insère 1470 employés dans PostgreSQL (étape 4 du projet).
398
+
399
+ ```bash
400
+ # Insérer le dataset complet
401
+ poetry run python scripts/insert_dataset.py
402
+
403
+ # Vérifier l'insertion
404
+ psql -h localhost -U ml_user -d oc_p5_db -c "SELECT COUNT(*) FROM dataset;"
405
+ # Résultat attendu : 1470
406
+ ```
407
+
408
+ **Fonctionnalités** :
409
+ - Fusionne automatiquement les 3 sources de données
410
+ - Nettoie les valeurs manquantes (NaN → None)
411
+ - Commits par batch de 100 pour performance
412
+ - Validation de l'intégrité des données
413
+
414
+ ### 📦 `generate_requirements_hf.sh` - Requirements pour HF Spaces
415
+
416
+ **Rôle** : Génère un fichier `requirements.txt` minimaliste pour déploiement sur Hugging Face Spaces (étape 1 & 2).
417
+
418
+ ```bash
419
+ # Générer requirements.txt optimisé pour HF
420
+ bash scripts/generate_requirements_hf.sh
421
+ ```
422
+
423
+ **Pourquoi nécessaire ?** HF Spaces nécessite des dépendances minimales (pas dev/test). Ce script extrait uniquement les packages essentiels depuis `pyproject.toml`.
424
+
425
+ ### 🚀 `run_local.sh` - Lancement local
426
+
427
+ **Rôle** : Script de démarrage rapide pour développement local.
428
+
429
+ ```bash
430
+ # Lancer l'application en mode développement
431
+ bash scripts/run_local.sh
432
+ ```
433
+
434
+ **Actions effectuées** :
435
+ 1. Installation des dépendances (Poetry)
436
+ 2. Vérification du fichier `.env` (copie `.env.example` si nécessaire)
437
+ 3. Lancement de l'interface Gradio sur http://localhost:7860
438
+
439
+ ### 📝 Organisation des Scripts
440
+
441
+ **Principe de séparation** :
442
+ - **`scripts/`** : Utilitaires BDD et déploiement uniquement (4 fichiers max)
443
+ - **`src/`** : Code applicatif principal (API, modèles, preprocessing)
444
+ - **`tests/`** : Tests unitaires et fonctionnels (séparé pour clarté)
445
+ - **`.github/workflows/`** : CI/CD (GitHub Actions, pas dans scripts/)
446
+
447
+ **Justifications** (liées aux étapes du projet) :
448
+ - ✅ **create_db.py** + **insert_dataset.py** : Étape 4 (script Python pour créer BDD + insérer dataset)
449
+ - ✅ **generate_requirements_hf.sh** : Étape 1 (requirements.txt à la racine) + Étape 2 (CI/CD, environnements)
450
+ - ✅ **run_local.sh** : Développement local (pas obligatoire mais pratique)
451
+ - ✅ **Tests dans `tests/`** : Étape 5 (scripts de tests + rapport couverture)
452
+
453
+ ---
454
+
455
  ## 🚀 Utilisation
456
 
457
  ### Démarrer l'API Localement
 
840
  open htmlcov/index.html
841
  ```
842
 
843
+ Pour le détail de l'organisation et des catégories de tests, voir `tests/README.md`.
844
+
845
  ### Métriques
846
 
847
  | Métrique | Valeur | Détail |
api.py CHANGED
@@ -7,7 +7,7 @@ Cette API expose le modèle de prédiction de départ des employés avec :
7
  - Preprocessing automatique
8
  - Health check pour monitoring
9
  - Documentation OpenAPI/Swagger automatique
10
- - Interface Gradio pour utilisation interactive
11
  - Endpoint batch pour traitement de fichiers CSV
12
  """
13
  import io
@@ -15,7 +15,6 @@ import time
15
  from contextlib import asynccontextmanager
16
  from typing import Any, Callable
17
 
18
- import gradio as gr
19
  import pandas as pd
20
  from fastapi import Depends, FastAPI, File, HTTPException, Request, Response, UploadFile
21
  from fastapi.middleware.cors import CORSMiddleware
@@ -24,7 +23,6 @@ from slowapi.errors import RateLimitExceeded
24
 
25
  from src.auth import verify_api_key
26
  from src.config import get_settings
27
- from src.gradio_ui import create_gradio_interface
28
  from src.logger import log_model_load, log_request, logger
29
  from src.models import get_model_info, load_model
30
  from src.preprocessing import (
@@ -44,6 +42,7 @@ from src.schemas import (
44
  # Charger la configuration
45
  settings = get_settings()
46
  API_VERSION = settings.API_VERSION
 
47
 
48
 
49
  def conditional_rate_limit(
@@ -450,9 +449,16 @@ async def predict_batch(
450
  )
451
 
452
 
453
- # Monter l'interface Gradio sur / (racine pour HuggingFace Spaces)
454
- gradio_app = create_gradio_interface()
455
- app = gr.mount_gradio_app(app, gradio_app, path="/")
 
 
 
 
 
 
 
456
 
457
 
458
  if __name__ == "__main__":
 
7
  - Preprocessing automatique
8
  - Health check pour monitoring
9
  - Documentation OpenAPI/Swagger automatique
10
+ - Interface Gradio optionnelle pour utilisation interactive
11
  - Endpoint batch pour traitement de fichiers CSV
12
  """
13
  import io
 
15
  from contextlib import asynccontextmanager
16
  from typing import Any, Callable
17
 
 
18
  import pandas as pd
19
  from fastapi import Depends, FastAPI, File, HTTPException, Request, Response, UploadFile
20
  from fastapi.middleware.cors import CORSMiddleware
 
23
 
24
  from src.auth import verify_api_key
25
  from src.config import get_settings
 
26
  from src.logger import log_model_load, log_request, logger
27
  from src.models import get_model_info, load_model
28
  from src.preprocessing import (
 
42
  # Charger la configuration
43
  settings = get_settings()
44
  API_VERSION = settings.API_VERSION
45
+ GRADIO_ENABLED = settings.GRADIO_ENABLED
46
 
47
 
48
  def conditional_rate_limit(
 
449
  )
450
 
451
 
452
+ if GRADIO_ENABLED:
453
+ # Importer Gradio uniquement si l'UI est activée pour éviter une dépendance inutile en prod API-only
454
+ import gradio as gr
455
+
456
+ from src.gradio_ui import create_gradio_interface
457
+
458
+ gradio_app = create_gradio_interface()
459
+ app = gr.mount_gradio_app(app, gradio_app, path="/")
460
+ else:
461
+ logger.info("Gradio UI désactivée (GRADIO_ENABLED=False)")
462
 
463
 
464
  if __name__ == "__main__":
app.py CHANGED
@@ -20,8 +20,15 @@ logger = logging.getLogger(__name__)
20
  # Ajouter le répertoire src au path
21
  sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
22
 
 
 
23
  if __name__ == "__main__":
24
  try:
 
 
 
 
 
25
  logger.info("🚀 Démarrage de l'application Gradio...")
26
  from src.gradio_ui import launch_standalone
27
 
 
20
  # Ajouter le répertoire src au path
21
  sys.path.insert(0, os.path.join(os.path.dirname(__file__), "src"))
22
 
23
+ from src.config import get_settings # noqa: E402
24
+
25
  if __name__ == "__main__":
26
  try:
27
+ settings = get_settings()
28
+ if not settings.GRADIO_ENABLED:
29
+ logger.info("Gradio désactivée (GRADIO_ENABLED=False) - arrêt.")
30
+ sys.exit(0)
31
+
32
  logger.info("🚀 Démarrage de l'application Gradio...")
33
  from src.gradio_ui import launch_standalone
34
 
src/config.py CHANGED
@@ -14,6 +14,15 @@ from dotenv import load_dotenv
14
  load_dotenv()
15
 
16
 
 
 
 
 
 
 
 
 
 
17
  class Settings:
18
  """
19
  Configuration de l'application.
@@ -37,8 +46,9 @@ class Settings:
37
  MODEL_FILENAME: str = os.getenv("MODEL_FILENAME", "model/model.pkl")
38
 
39
  # ===== ENVIRONNEMENT =====
40
- DEBUG: bool = os.getenv("DEBUG", "False").lower() == "true"
41
  LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
 
42
 
43
  # ===== BASE DE DONNÉES =====
44
  DATABASE_URL: str = os.getenv(
 
14
  load_dotenv()
15
 
16
 
17
+ def _str_to_bool(value: str, default: bool = False) -> bool:
18
+ """Convertit une chaîne d'environnement en booléen robuste."""
19
+
20
+ if value is None:
21
+ return default
22
+
23
+ return value.lower() in {"1", "true", "yes", "y", "on"}
24
+
25
+
26
  class Settings:
27
  """
28
  Configuration de l'application.
 
46
  MODEL_FILENAME: str = os.getenv("MODEL_FILENAME", "model/model.pkl")
47
 
48
  # ===== ENVIRONNEMENT =====
49
+ DEBUG: bool = _str_to_bool(os.getenv("DEBUG", "False"))
50
  LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO")
51
+ GRADIO_ENABLED: bool = _str_to_bool(os.getenv("GRADIO_ENABLED", "True"), True)
52
 
53
  # ===== BASE DE DONNÉES =====
54
  DATABASE_URL: str = os.getenv(