import os import json import joblib import pandas as pd from fastapi import FastAPI from fastapi.responses import HTMLResponse from pydantic import BaseModel, ConfigDict # ========================================================= # Paths # ========================================================= BASE_DIR = os.path.dirname(os.path.abspath(__file__)) PIPELINE_PATH = os.path.join(BASE_DIR, "pipeline.pkl") FEATURES_PATH = os.path.join(BASE_DIR, "feature_names.json") METRICS_PATH = os.path.join(BASE_DIR, "model_metrics.json") # ========================================================= # Load artefacts # ========================================================= pipeline = joblib.load(PIPELINE_PATH) with open(FEATURES_PATH, "r", encoding="utf-8") as f: feature_names = json.load(f) if os.path.exists(METRICS_PATH): with open(METRICS_PATH, "r", encoding="utf-8") as f: model_metrics = json.load(f) else: model_metrics = {} # ========================================================= # FastAPI app # ========================================================= app = FastAPI( title="GetAround Pricing API", description="Predicts the optimal rental price per day for a car", version="1.0.0", docs_url=None, redoc_url=None ) # ========================================================= # Input schema # ========================================================= class PredictInput(BaseModel): input: list[list] model_config = ConfigDict( json_schema_extra={ "example": { "input": [[ "Citroën", 50000, 120, "diesel", "black", "sedan", 1, 1, 1, 0, 1, 1, 0 ]] } } ) # ========================================================= # Helpers # ========================================================= def metric_value(name: str, digits: int = 2) -> str: value = model_metrics.get(name) if value is None: return "N/A" try: return f"{float(value):.{digits}f}" except Exception: return "N/A" def get_model_name() -> str: try: return pipeline.named_steps["model"].__class__.__name__ except Exception: return "Unknown" # ========================================================= # Routes # ========================================================= @app.get("/", response_class=HTMLResponse) def root(): return """
API is running.
📄 Go to Documentation """ @app.post("/predict") def predict(data: PredictInput): X = pd.DataFrame(data.input, columns=feature_names) predictions = pipeline.predict(X) return {"prediction": [round(float(p), 2) for p in predictions]} @app.get("/docs", response_class=HTMLResponse) def documentation(): algo_name = get_model_name() rmse = metric_value("RMSE") mae = metric_value("MAE") r2 = metric_value("R²", 3) cv_rmse = metric_value("CV_RMSE_mean") cv_std = metric_value("CV_RMSE_std") feature_rows = "".join([ f"Predict the optimal rental price per day for a car
Returns a predicted rental price per day based on the car's characteristics.
| # | Feature |
|---|
{{
"input": [[
"Citroën",
50000,
120,
"diesel",
"black",
"sedan",
1,
1,
1,
0,
1,
1,
0
]]
}}
{{
"prediction": [124.52]
}}
Health check endpoint.
Custom API documentation page.
| Property | Value |
|---|---|
| Algorithm | {algo_name} |
| Target | rental_price_per_day (€) |
| RMSE | {rmse} |
| MAE | {mae} |
| R² | {r2} |
| CV RMSE | {cv_rmse} |
| CV RMSE std | {cv_std} |
| Number of features | {len(feature_names)} |