churn-predictor / API_GUIDE.md
github-actions
Déploiement automatique depuis GitHub Actions (branche main)
442d016

A newer version of the Gradio SDK is available: 6.11.0

Upgrade

📘 Guide API - Prédicteur de Churn

Version : 1.0.0
Base URL : http://127.0.0.1:8000
Documentation interactive : http://127.0.0.1:8000/docs


🎯 Vue d'ensemble

Cette API FastAPI prédiet le risque de départ d'un employé en fonction de ses données personnelles, professionnelles et de satisfaction. L'API enregistre toutes les prédictions et les appels dans une base PostgreSQL.


🔐 Authentification

Actuellement, aucune authentification n'est requise. À implémenter selon besoin.


📋 Format de réponse standard

Toutes les réponses sont au format JSON.

Réponse de succès (HTTP 200)

{
  "risk_level": "Élevé" | "Faible",
  "churn_probability": 0.75,
  "threshold_applied": 0.5,
  "recommendation": "string"
}

Réponse d'erreur (HTTP 4xx/5xx)

{
  "detail": "Message d'erreur descriptif"
}

🔍 Endpoints détaillés


1. GET /health

Description : Vérifie l'état de l'API, du modèle et de la base de données.

Paramètres : Aucun

Réponse (HTTP 200) :

{
  "status": "OK",
  "model_loaded": true,
  "scaler_loaded": true,
  "threshold_loaded": true,
  "database_connected": true
}

Cas d'erreur (HTTP 500) :

{
  "status": "ERROR",
  "detail": "Modèle non chargé"
}

Exemple cURL :

curl -X GET "http://127.0.0.1:8000/health"

2. POST /predict

Description : Prédit le risque de churn pour un employé individuel.

Content-Type : application/json

Body (EmployeeInput) :

{
  "age": 18,
  "genre": "Masculin",
  "etat_civil": "Celibataire",
  "salaire": 1,
  "distance": 0,
  "departement": "Consulting",
  "domaine_etude": "Entrepreunariat",
  "niveau_hierarchique": 1,
  "poste_freq_deplacement": "Rare",
  "emplois_precedents": 0,
  "experience_totale": 0,
  "annees_entreprise": 0,
  "annees_poste": 0,
  "annees_derniere_promotion": 0,
  "annees_responsable_actuel": 0,
  "heures_semaine": 1,
  "heures_supplementaires": false,
  "employes_supervision": 0,
  "evaluation_precedente": 1,
  "evaluation_actuelle": 1,
  "satisfaction_environnement": 1,
  "satisfaction_travail": 1,
  "satisfaction_equipe": 1,
  "satisfaction_balance": 1,
  "augmentation_salaire": 0,
  "participation_pee": 0,
  "formations_completees": 0
}

Réponse (HTTP 200 - Prédiction réussie) :

{
  "prediction": "Risque Élevé",
  "probabilite_abandon": 97.72,
  "seuil_applique": 59.05,
  "confiance_modele": 97.72,
  "recommandation": "Intervention immédiate recommandée (augmentation, promotion, avantages, télétravail, etc.).",
  "details": {
    "prob_rester": 2.28,
    "prob_partir": 97.72,
    "satisfaction_moyenne": 1,
    "salaire": 1,
    "departement": "Consulting",
    "anciennete_ans": 0
  }
}

Autre réponse possible :

{
  "risk_level": "Élevé",
  "churn_probability": 0.75,
  "threshold_applied": 0.5,
  "recommendation": "Intervention immédiate (entretien RH, augmentation, formation, promotion)"
}

Cas d'erreur (HTTP 422 - Validation) :

{
  "detail": [
    {
      "loc": ["body", "age"],
      "msg": "ensure this value is greater than or equal to 18",
      "type": "value_error.number.not_ge"
    }
  ]
}

Exemple cURL :

curl -X POST "http://127.0.0.1:8000/predict" \
  -H "Content-Type: application/json" \
  -d '{
  "age": 18,
  "genre": "Masculin",
  "etat_civil": "Celibataire",
  "salaire": 1200,
  "distance": 0,
  "departement": "Consulting",
  "domaine_etude": "Entrepreunariat",
  "niveau_hierarchique": 1,
  "poste_freq_deplacement": "Rare",
  "emplois_precedents": 0,
  "experience_totale": 0,
  "annees_entreprise": 0,
  "annees_poste": 0,
  "annees_derniere_promotion": 0,
  "annees_responsable_actuel": 0,
  "heures_semaine": 1,
  "heures_supplementaires": false,
  "employes_supervision": 0,
  "evaluation_precedente": 1,
  "evaluation_actuelle": 1,
  "satisfaction_environnement": 1,
  "satisfaction_travail": 1,
  "satisfaction_equipe": 1,
  "satisfaction_balance": 1,
  "augmentation_salaire": 0,
  "participation_pee": 0,
  "formations_completees": 0
}'

Exemple Python (requests) :

import requests

url = "http://127.0.0.1:8000/predict"
data = {
    "age": 18,
  "genre": "Masculin",
  "etat_civil": "Celibataire",
  "salaire": 1200,
  "distance": 0,
  "departement": "Consulting",
  "domaine_etude": "Entrepreunariat",
  "niveau_hierarchique": 1,
  "poste_freq_deplacement": "Rare",
  "emplois_precedents": 0,
  "experience_totale": 0,
  "annees_entreprise": 0,
  "annees_poste": 0,
  "annees_derniere_promotion": 0,
  "annees_responsable_actuel": 0,
  "heures_semaine": 1,
  "heures_supplementaires": false,
  "employes_supervision": 0,
  "evaluation_precedente": 1,
  "evaluation_actuelle": 1,
  "satisfaction_environnement": 1,
  "satisfaction_travail": 1,
  "satisfaction_equipe": 1,
  "satisfaction_balance": 1,
  "augmentation_salaire": 0,
  "participation_pee": 0,
  "formations_completees": 0
}

response = requests.post(url, json=data)
print(response.json())

3. POST /test-prediction

Description : Teste rapidement l'API avec un employé fictif par défaut.

Paramètres : Aucun
Body : Aucun

Réponse (HTTP 200) :

{
  "risk_level": "Faible",
  "churn_probability": 0.22,
  "threshold_applied": 0.5,
  "recommendation": "Maintenir la relation positive, surveiller satisfactions"
}

Cas d'erreur (HTTP 500) :

{
  "detail": "Erreur lors de la prédiction de test"
}

Exemple cURL :

curl -X POST "http://127.0.0.1:8000/test-prediction"

Exemple Python :

import requests

response = requests.post("http://127.0.0.1:8000/test-prediction")
print(response.json())

4. POST /predict-bulk

Description : Prédit le risque pour une liste d'employés et retourne des statistiques globales.

Content-Type : application/json

Body (BulkPredictionRequest) :

{
  "employes": [
    {
      "age": 18,
      "genre": "Masculin",
      "etat_civil": "Celibataire",
      "salaire": 1200,
      "distance": 0,
      "departement": "Consulting",
      "domaine_etude": "Entrepreunariat",
      "niveau_hierarchique": 1,
      "poste_freq_deplacement": "Rare",
      "emplois_precedents": 0,
      "experience_totale": 0,
      "annees_entreprise": 0,
      "annees_poste": 0,
      "annees_derniere_promotion": 0,
      "annees_responsable_actuel": 0,
      "heures_semaine": 1,
      "heures_supplementaires": false,
      "employes_supervision": 0,
      "evaluation_precedente": 1,
      "evaluation_actuelle": 1,
      "satisfaction_environnement": 1,
      "satisfaction_travail": 1,
      "satisfaction_equipe": 1,
      "satisfaction_balance": 1,
      "augmentation_salaire": 0,
      "participation_pee": 0,
      "formations_completees": 0
    },
    {
      {
      "age": 45,
      "genre": "Masculin",
      "etat_civil": "Celibataire",
      "salaire": 3000,
      "distance": 0,
      "departement": "Consulting",
      "domaine_etude": "Entrepreunariat",
      "niveau_hierarchique": 1,
      "poste_freq_deplacement": "Rare",
      "emplois_precedents": 0,
      "experience_totale": 0,
      "annees_entreprise": 0,
      "annees_poste": 0,
      "annees_derniere_promotion": 0,
      "annees_responsable_actuel": 0,
      "heures_semaine": 1,
      "heures_supplementaires": true,
      "employes_supervision": 0,
      "evaluation_precedente": 1,
      "evaluation_actuelle": 1,
      "satisfaction_environnement": 3,
      "satisfaction_travail": 3,
      "satisfaction_equipe": 3,
      "satisfaction_balance": 3,
      "augmentation_salaire": 0,
      "participation_pee": 1,
      "formations_completees": 2
    }
  ]
}

Réponse (HTTP 200) :

{
  "predictions": [
    {
      "risk_level": "Faible",
      "churn_probability": 0.15,
      "threshold_applied": 0.5,
      "recommendation": "Maintenir la relation positive, surveiller satisfactions"
    },
    {
      "risk_level": "Élevé",
      "churn_probability": 0.78,
      "threshold_applied": 0.5,
      "recommendation": "Intervention immédiate (entretien RH, augmentation, formation, promotion)"
    }
  ],
  "statistics": {
    "total_processed": 2,
    "high_risk_count": 1,
    "low_risk_count": 1,
    "high_risk_percentage": 50.0
  }
}

Cas d'erreur (HTTP 422) :

{
  "detail": "Au moins 1 employé est requis"
}

Exemple cURL :

curl -X POST "http://127.0.0.1:8000/predict-bulk" \
  -H "Content-Type: application/json" \
  -d '{
  "employes": [
    {
      "age": 18,
      "genre": "Masculin",
      "etat_civil": "Celibataire",
      "salaire": 1200,
      "distance": 0,
      "departement": "Consulting",
      "domaine_etude": "Entrepreunariat",
      "niveau_hierarchique": 1,
      "poste_freq_deplacement": "Rare",
      "emplois_precedents": 0,
      "experience_totale": 0,
      "annees_entreprise": 0,
      "annees_poste": 0,
      "annees_derniere_promotion": 0,
      "annees_responsable_actuel": 0,
      "heures_semaine": 1,
      "heures_supplementaires": false,
      "employes_supervision": 0,
      "evaluation_precedente": 1,
      "evaluation_actuelle": 1,
      "satisfaction_environnement": 1,
      "satisfaction_travail": 1,
      "satisfaction_equipe": 1,
      "satisfaction_balance": 1,
      "augmentation_salaire": 0,
      "participation_pee": 0,
      "formations_completees": 0
    },
    {
      "age": 45,
      "genre": "Masculin",
      "etat_civil": "Celibataire",
      "salaire": 3000,
      "distance": 0,
      "departement": "Consulting",
      "domaine_etude": "Entrepreunariat",
      "niveau_hierarchique": 1,
      "poste_freq_deplacement": "Rare",
      "emplois_precedents": 0,
      "experience_totale": 0,
      "annees_entreprise": 0,
      "annees_poste": 0,
      "annees_derniere_promotion": 0,
      "annees_responsable_actuel": 0,
      "heures_semaine": 1,
      "heures_supplementaires": true,
      "employes_supervision": 0,
      "evaluation_precedente": 1,
      "evaluation_actuelle": 1,
      "satisfaction_environnement": 3,
      "satisfaction_travail": 3,
      "satisfaction_equipe": 3,
      "satisfaction_balance": 3,
      "augmentation_salaire": 0,
      "participation_pee": 1,
      "formations_completees": 2
    }
  ]
}'

📊 Codes de réponse HTTP

Code Signification Exemple
200 Succès Prédiction réussie
422 Erreur de validation Champ manquant ou invalide
500 Erreur serveur Modèle non chargé, BDD inaccessible

📈 Interprétation des résultats

risk_level

  • "Élevé" : Probabilité de départ > seuil optimal (50%)

    • Action : Intervention immédiate requise (entretien RH, augmentation, formation, promotion)
  • "Faible" : Probabilité de départ ≤ seuil optimal

    • Action : Maintenir la relation positive, surveiller les satisfactions

churn_probability

Probabilité exprimée entre 0.0 (aucun risque) et 1.0 (risque maximal).

threshold_applied

Le seuil utilisé pour la classification (par défaut 0.5). Les prédictions respectent ce seuil.

recommendation

Recommandation d'action basée sur le risque identifié.


🔄 Exemples d'intégration

Python - Prédiction unique

import requests
import json

url = "http://127.0.0.1:8000/predict"

employee = {
    "age": 35,
    "education_level": 3,
    "distance_from_home": 15,
    "experience_count": 2,
    "total_experience": 10,
    "years_in_company": 5,
    "years_in_role": 2,
    "previous_evaluation": 3,
    "current_evaluation": 4,
    "hierarchy_level": 2,
    "subordinates_count": 3,
    "environment_satisfaction": 3,
    "job_satisfaction": 4,
    "team_satisfaction": 3,
    "worklife_balance_satisfaction": 3,
    "monthly_revenue": 3500,
    "last_raise_percentage": 11,
    "overtime": False,
    "stock_option_level": 1,
    "trainings_completed": 2,
    "years_since_promotion": 2,
    "years_with_current_manager": 2
}

response = requests.post(url, json=employee)
result = response.json()

if result["risk_level"] == "Élevé":
    print(f"⚠️ ALERTE : Cet employé a {result['churn_probability']*100:.1f}% de risque de départ")
    print(f"Action : {result['recommendation']}")
else:
    print(f"✅ Employé stable : {result['churn_probability']*100:.1f}% de risque")

Python - Prédictions en masse

import requests
import pandas as pd

url = "http://127.0.0.1:8000/predict-bulk"

# Charger des données depuis CSV
df = pd.read_csv("employees.csv")
employees_list = df.to_dict('records')

payload = {"employees": employees_list}

response = requests.post(url, json=payload)
result = response.json()

# Afficher les statistiques
stats = result["statistics"]
print(f"Total traité : {stats['total_processed']}")
print(f"Risque élevé : {stats['high_risk_count']} ({stats['high_risk_percentage']:.1f}%)")
print(f"Risque faible : {stats['low_risk_count']}")

# Enregistrer les résultats
with open("predictions_result.json", "w") as f:
    json.dump(result, f, indent=2)

⚠️ Gestion des erreurs courantes

Erreur : "age : ensure this value is greater than or equal to 18"

Cause : L'âge est inférieur à 18 ans
Solution : Vérifier que l'âge est entre 18 et 65

Erreur : "Cannot connect to database"

Cause : PostgreSQL n'est pas accessible
Solution : Vérifier que PostgreSQL est lancé et la base existe (churn_predictor_db)

Erreur : "Model not loaded"

Cause : Les fichiers .pkl ne sont pas dans le dossier models/
Solution : Vérifier que lr_model_opt.pkl, scaler.pkl et seuil_opt.pkl existent


📞 Support

Pour des questions ou des rapports de bug :

  • Consulter la documentation interactive : http://127.0.0.1:8000/docs
  • Vérifier les logs : http://127.0.0.1:8000/audit_log (via BDD)
  • Relancer l'API : python main_api.py

Dernière mise à jour : Mars 2026