AichaFaHugFace commited on
Commit
26c3f0d
·
verified ·
1 Parent(s): 7cd0c21

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +141 -0
app.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ API de prédiction du prix de location - Projet Getaround.
3
+
4
+ Cette API expose un point de terminaison /predict qui renvoie le prix
5
+ de location journalier suggéré pour un véhicule, à partir de ses
6
+ caractéristiques.
7
+ """
8
+
9
+ from pathlib import Path
10
+ from typing import List, Union
11
+
12
+ import joblib
13
+ import pandas as pd
14
+ from fastapi import FastAPI, HTTPException
15
+ from pydantic import BaseModel, Field
16
+
17
+ # ---------------------------------------------------------------------------
18
+ # Configuration de l'application
19
+ # ---------------------------------------------------------------------------
20
+ APP_TITLE = "API Getaround - Prédiction du prix de location"
21
+ APP_DESCRIPTION = (
22
+ "Cette API met à disposition un modèle de Machine Learning entraîné "
23
+ "pour suggérer le prix journalier optimal d'une location de véhicule "
24
+ "sur la plateforme Getaround.\n\n"
25
+ "### Performances du modèle (XGBoost Regressor) :\n"
26
+ "* **Erreur absolue moyenne (MAE) :** 9,18 EUR\n"
27
+ "* **RMSE :** 12,82 EUR\n"
28
+ "* **R² :** 0,846\n"
29
+ )
30
+ APP_VERSION = "1.0.0"
31
+ MODEL_PATH = Path(__file__).resolve().parent / "best_model.joblib"
32
+
33
+ FEATURE_COLUMNS = [
34
+ "model_key", "mileage", "engine_power", "fuel", "paint_color",
35
+ "car_type", "private_parking_available", "has_gps",
36
+ "has_air_conditioning", "automatic_car", "has_getaround_connect",
37
+ "has_speed_regulator", "winter_tires",
38
+ ]
39
+
40
+ BOOL_COLUMNS = [
41
+ "private_parking_available", "has_gps", "has_air_conditioning",
42
+ "automatic_car", "has_getaround_connect", "has_speed_regulator",
43
+ "winter_tires",
44
+ ]
45
+
46
+
47
+ # ---------------------------------------------------------------------------
48
+ # Initialisation
49
+ # ---------------------------------------------------------------------------
50
+ app = FastAPI(
51
+ title=APP_TITLE,
52
+ description=APP_DESCRIPTION,
53
+ version=APP_VERSION,
54
+ )
55
+
56
+ # Chargement du modèle
57
+ try:
58
+ model = joblib.load(MODEL_PATH)
59
+ MODEL_LOADED = True
60
+ except Exception as exc:
61
+ print(f"Erreur de chargement du modèle : {exc}")
62
+ model = None
63
+ MODEL_LOADED = False
64
+
65
+
66
+ # ---------------------------------------------------------------------------
67
+ # Schémas Pydantic
68
+ # ---------------------------------------------------------------------------
69
+ class PredictionInput(BaseModel):
70
+ """Schéma d'entrée pour l'endpoint /predict."""
71
+
72
+ input: List[List[Union[str, int, float, bool]]] = Field(
73
+ ...,
74
+ examples=[[[
75
+ "Citroën", 140411, 100, "diesel", "black", "convertible",
76
+ True, True, False, False, True, True, True,
77
+ ]]],
78
+ )
79
+
80
+
81
+ class PredictionOutput(BaseModel):
82
+ """Schéma de sortie pour l'endpoint /predict."""
83
+
84
+ prediction: List[float]
85
+
86
+
87
+ # ---------------------------------------------------------------------------
88
+ # Endpoints
89
+ # ---------------------------------------------------------------------------
90
+ @app.get("/", tags=["Accueil"])
91
+ async def root():
92
+ """Point d'entrée par défaut."""
93
+ return {
94
+ "message": "API Getaround opérationnelle",
95
+ "version": APP_VERSION,
96
+ "model_loaded": MODEL_LOADED,
97
+ "documentation": "/docs",
98
+ }
99
+
100
+
101
+ @app.get("/health", tags=["Accueil"])
102
+ async def health():
103
+ """Indicateur de santé du service."""
104
+ return {"status": "ok" if MODEL_LOADED else "model_missing"}
105
+
106
+
107
+ @app.post(
108
+ "/predict",
109
+ tags=["Prédiction"],
110
+ response_model=PredictionOutput,
111
+ summary="Prédire le prix de location journalier",
112
+ )
113
+ async def predict(payload: PredictionInput):
114
+ """Renvoie la prédiction du prix de location journalier (EUR/jour)."""
115
+ if not MODEL_LOADED:
116
+ raise HTTPException(
117
+ status_code=503,
118
+ detail="Modèle non chargé sur le serveur.",
119
+ )
120
+ try:
121
+ df_input = pd.DataFrame(payload.input, columns=FEATURE_COLUMNS)
122
+
123
+ # Conversion des types
124
+ for col in BOOL_COLUMNS:
125
+ df_input[col] = df_input[col].astype(int)
126
+ df_input["mileage"] = df_input["mileage"].astype(int)
127
+ df_input["engine_power"] = df_input["engine_power"].astype(int)
128
+
129
+ preds = model.predict(df_input)
130
+ return {"prediction": [round(float(p), 2) for p in preds]}
131
+ except Exception as exc:
132
+ raise HTTPException(
133
+ status_code=400,
134
+ detail=f"Erreur lors de la prédiction : {exc}",
135
+ )
136
+
137
+
138
+ if __name__ == "__main__":
139
+ import uvicorn
140
+
141
+ uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=False)