Spaces:
Sleeping
Sleeping
File size: 6,404 Bytes
10c3735 5cc9fa6 41c36a3 35969a2 75dfb95 45ba6f5 75dfb95 e288985 75dfb95 10c3735 9136785 e288985 4c91f84 e288985 9136785 83f0f75 b5bf2af 83f0f75 b5bf2af 83f0f75 b5bf2af 83f0f75 b5bf2af 83f0f75 b5bf2af 83f0f75 5f8477f 83f0f75 e288985 b5bf2af e288985 b5bf2af 83f0f75 b5bf2af 83f0f75 b5bf2af 83f0f75 e288985 c8447c0 e288985 83f0f75 35969a2 83f0f75 46bb294 83f0f75 10c3735 c8447c0 4c91f84 c8447c0 41c36a3 a0bc8db 5889de4 dd44a35 5cc9fa6 b40bba3 35969a2 10c3735 35969a2 41c36a3 e288985 b40bba3 35969a2 b40bba3 41c36a3 b40bba3 41c36a3 b40bba3 41c36a3 e288985 5cc9fa6 18c9ca8 e288985 5cc9fa6 e288985 18c9ca8 5cc9fa6 e288985 18c9ca8 17940dc e288985 5cc9fa6 e288985 5cc9fa6 e288985 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | from fastapi import FastAPI
from fastapi import HTTPException
from pydantic import BaseModel
import mlflow.pyfunc
import pandas as pd
import config
import logging
import os
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# 1) URL du Space HF qui héberge MLflow (tracking server)
MLFLOW_TRACKING_URI = os.getenv("MLFLOW_TRACKING_URI", "https://pradelf-getaround-mlflow.hf.space")
MODEL_URI = os.getenv("MODEL_URI", "models:/getaround-price-prediction-model@certification")
BOOL_COLS = [
"private_parking_available",
"has_gps",
"has_air_conditioning",
"automatic_car",
"has_getaround_connect",
"has_speed_regulator",
"winter_tires",
]
description = """
Bienvenue sur l'API de Getaround pour prédire le prix journalier de location d'une voiture en fonction de son année d'expérience!
## Point de terminaison d'introduction
Pour tester le fonctionnement de l'API, vous pouvez utiliser le point de terminaison d'introduction suivant:
* `/`: **GET** retourne la version de l'API et un message de bienvenue.
## Point de terminaison de ligne de vie
Cette web fonction permet de vérifier que le serveur de l'API est opérationnel et de surveiller son statut.
* `/health`: **GET** retourne juste OK pour valider que le serveur de l'API est en cours d'exécution sans problèmes.
## Machine Learning : Point de terminaison du prix de location
Cette terminaison de l'API permet de prédire le prix journalier de location d'une voiture en fonction de ses caractéristiques..
* `/predict` accepte une requête POST avec un JSON contenant un objet JSON donnant les caractéristiques d'une voiture
et retourne une prédiction du prix journalier de location de celle-ci.
La documentation est ci-dessous 👇 pour chaque point de terminaison (endpoints).
"""
tags_metadata = [
{
"name": "Point de terminaison d'introduction",
"description": "Terminaison simple de présentation de l'API et de sa version pour vérifier que tout fonctionne correctement.",
},
{
"name": "Point de terminaison de ligne de vie",
"description": "Point de terminaison de ligne de vie pour surveiller le statut du serveur de l'API. Retourne 'ok' si le serveur fonctionne sans problèmes.",
},
{
"name": "Point de terminaison du prix de location",
"description": "Point de terminaison permettant de prédire le prix journalier de location d'une voiture en fonction de ses caractéristiques.",
},
{
"name": "Machine Learning",
"description": "Point de terminaison de prediction du prix de location journalier d'un véhicule en fonction de ses caractéristiques.",
},
]
model= None
app = FastAPI(
title="Getaround API pour le prix journalier de location d'une voiture.",
description=description,
version=config.__version__,
contact={
"name": "Francis Pradel",
"url": "https://promotion.francispradel.fr",
},
openapi_tags=tags_metadata,
swagger_ui_parameters={"syntaxHighlight": {"theme": "obsidian"}},
)
@app.on_event("startup")
def load_model_on_startup():
global model
try:
logger.info(f"Chargement du modèle depuis {MLFLOW_TRACKING_URI}")
logger.info(f"Model : {MODEL_URI}")
mlflow.set_tracking_uri(MLFLOW_TRACKING_URI) # ou via env MLFLOW_TRACKING_URI
model = mlflow.pyfunc.load_model(MODEL_URI)
logger.info("Modèle chargé avec succès")
except Exception:
logger.exception("Impossible de charger le modèle au démarrage")
model = None
class RentalFeatures(BaseModel):
model_key: str
mileage: int
engine_power: int
fuel: str
paint_color: str
car_type: str
private_parking_available: bool
has_gps: bool
has_air_conditioning: bool
automatic_car: bool
has_getaround_connect: bool
has_speed_regulator: bool
winter_tires: bool
@app.get("/", tags=["Introduction Endpoints"])
def greet_json():
"""
Bonjour
"""
return {"Hello": "World!", "version": config.__version__}
@app.get("/health")
def health():
"""
Health line to monitor the server status of the API. Returns "ok" if the server is running without issues.
"""
return {"status": "ok"}
@app.post("/predict", tags=["Machine Learning"])
async def predict(predictionFeatures: RentalFeatures):
"""
Prediction of car daily rental cost for a given properties of a car !
"""
# Read data
# pf = [
# predictionFeatures.model_key or "Peugeot",
# predictionFeatures.mileage or 0,
# predictionFeatures.engine_power or 0,
# predictionFeatures.fuel or "petrol",
# predictionFeatures.car_type or "sedan",
# predictionFeatures.private_parking_available or 1,
# predictionFeatures.has_gps or 0,
# predictionFeatures.has_air_conditioning or 0,
# predictionFeatures.automatic_car or 0,
# predictionFeatures.has_getaround_connect or 0,
# predictionFeatures.has_speed_regulator or 0,
# predictionFeatures.winter_tires or 0,
# ]
try:
payload = predictionFeatures.model_dump()
car_characteristic = pd.DataFrame([payload])
#car_caracteristic = pd.DataFrame({"Car": pf})
# Log model from mlflow
BOOL_COLS = [
"private_parking_available",
"has_gps",
"has_air_conditioning",
"automatic_car",
"has_getaround_connect",
"has_speed_regulator",
"winter_tires",
]
# Conversion explicite des colonnes booléennes
for col in BOOL_COLS:
car_characteristic[col] = car_characteristic[col].astype(bool)
logger.info("Payload reçu: %s", payload)
logger.info("dtypes:\n%s", car_characteristic.dtypes)
# Prediction from previously loaded model as a PyFuncModel.
prediction = model.predict(car_characteristic)
logger.info(f"Output : {prediction}")
# Format response
response = {
"prediction": float(prediction[0]),
"detail": "Prédiction du tarif journalier (nul si aucun modèle : model.pkl).",
}
return response
except Exception as e:
logger.exception("Erreur dans /predict")
raise HTTPException(status_code=500, detail=str(e))
|