gitwire / app /main.py
zeltrox's picture
updated the deployment code in the backend
82482aa
Raw
History Blame Contribute Delete
3.29 kB
from __future__ import annotations
from pathlib import Path
from typing import Any, Union
import joblib
import pandas as pd
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
MODEL_PATH = Path(__file__).resolve().parent.parent / "xg_bost.pkl"
# LabelEncoder-style mappings (alphabetical order) for categorical features.
CATEGORICAL_MAPPINGS = {
"weather_condition": {
"Clear": 0.0,
"Cloudy": 1.0,
"Fog": 2.0,
"Rain": 3.0,
"Snow": 4.0,
"Windy": 5.0,
},
"traffic_level": {
"High": 0.0,
"Low": 1.0,
"Medium": 2.0,
"Very High": 3.0,
"Very Low": 4.0,
},
"vehicle_type": {
"car": 0.0,
"cycle": 1.0,
"ev": 2.0,
"motorcycle": 3.0,
"scooter": 4.0,
},
"order_type": {
"Buffet": 0.0,
"Drinks": 1.0,
"Meal": 2.0,
"Snack": 3.0,
"Unknown": 4.0,
},
}
model = joblib.load(MODEL_PATH)
FEATURE_ORDER = list(model.feature_names_in_)
class PredictInput(BaseModel):
distance_km: float = Field(..., example=7.93)
weather_condition: Union[str, float, int] = Field(..., example="Windy")
traffic_level: Union[str, float, int] = Field(..., example="Low")
vehicle_type: Union[str, float, int] = Field(..., example="scooter")
temperature_c: float = Field(..., example=23.0)
humidity_pct: float = Field(..., example=55.0)
precipitation_mm: float = Field(..., example=0.0)
preparation_time_min: float = Field(..., example=12.0)
courier_experience_yrs: float = Field(..., example=1.0)
worker_age: float = Field(..., example=29.0)
worker_rating: float = Field(..., example=4.7)
order_type: Union[str, float, int] = Field(..., example="Unknown")
weather_risk: float = Field(..., example=7.0)
traffic_risk: float = Field(..., example=25.0)
def _encode_categorical(feature_name: str, value: Any) -> float:
if isinstance(value, (int, float)) and not isinstance(value, bool):
return float(value)
mapping = CATEGORICAL_MAPPINGS[feature_name]
raw = str(value).strip()
if raw in mapping:
return mapping[raw]
lower_map = {k.lower(): v for k, v in mapping.items()}
if raw.lower() in lower_map:
return lower_map[raw.lower()]
allowed = ", ".join(mapping.keys())
raise HTTPException(
status_code=422,
detail=f"Unknown value '{value}' for '{feature_name}'. Allowed values: {allowed}",
)
def _prepare_features(payload: PredictInput) -> pd.DataFrame:
values = payload.model_dump()
row: dict[str, float] = {}
for feature in FEATURE_ORDER:
value = values[feature]
if feature in CATEGORICAL_MAPPINGS:
row[feature] = _encode_categorical(feature, value)
else:
row[feature] = float(value)
return pd.DataFrame([row], columns=FEATURE_ORDER)
app = FastAPI(title="Gitwire XGBoost Inference API", version="1.0.0")
@app.get("/health")
def health() -> dict[str, str]:
return {"status": "ok"}
@app.post("/predit")
def predit(payload: PredictInput) -> dict[str, float]:
features = _prepare_features(payload)
prediction = float(model.predict(features)[0])
return {"prediction": prediction}