|
from fastapi import FastAPI, HTTPException |
|
from pydantic import BaseModel |
|
import joblib |
|
import pandas as pd |
|
import numpy as np |
|
|
|
app = FastAPI(title="Airbnb Price Prediction in Copenhagen") |
|
|
|
|
|
model_xgb = joblib.load('model_xgb.joblib') |
|
scaler = joblib.load('scaler.joblib') |
|
ohe = joblib.load('ohe.joblib') |
|
|
|
class RoomFeatures(BaseModel): |
|
neighbourhood_cleansed: str |
|
room_type: str |
|
instant_bookable: bool |
|
accommodates: int |
|
bedrooms: int |
|
beds: int |
|
minimum_nights_avg_ntm: int |
|
|
|
@app.post("/predict") |
|
async def predict_price(features: RoomFeatures): |
|
try: |
|
|
|
cat_features = pd.DataFrame({ |
|
'neighbourhood_cleansed': [features.neighbourhood_cleansed], |
|
'room_type': [features.room_type] |
|
}) |
|
cat_encoded = pd.DataFrame( |
|
ohe.transform(cat_features).todense(), |
|
columns=ohe.get_feature_names_out(['neighbourhood_cleansed', 'room_type']) |
|
) |
|
|
|
|
|
num_features = pd.DataFrame({ |
|
'instant_bookable': [int(features.instant_bookable)], |
|
'accommodates': [features.accommodates], |
|
'bedrooms': [features.bedrooms], |
|
'beds': [features.beds], |
|
'minimum_nights_avg_ntm': [features.minimum_nights_avg_ntm] |
|
}) |
|
num_scaled = pd.DataFrame(scaler.transform(num_features), columns=num_features.columns) |
|
|
|
|
|
combined_features = pd.concat([num_scaled, cat_encoded], axis=1) |
|
|
|
|
|
predicted_price = model_xgb.predict(combined_features)[0] |
|
|
|
|
|
lower_range = max(0, round(predicted_price - 350)) |
|
upper_range = round(predicted_price + 350) |
|
|
|
return { |
|
"predicted_price": round(predicted_price), |
|
"suggested_price_range": { |
|
"lower": lower_range, |
|
"upper": upper_range |
|
} |
|
} |
|
except Exception as e: |
|
raise HTTPException(status_code=400, detail=str(e)) |
|
|
|
@app.get("/") |
|
async def root(): |
|
return {"message": "Welcome to the Airbnb Price Prediction API for Copenhagen"} |
|
|
|
if __name__ == "__main__": |
|
import uvicorn |
|
uvicorn.run(app, host="0.0.0.0", port=8000) |