Spaces:
Running
Running
Commit Β·
8bb06f0
1
Parent(s): 334eff8
Clean up comments, update README
Browse files- app/main.py +7 -7
- app/predictor.py +4 -4
- app/schemas.py +2 -2
- app/ui.py +5 -8
app/main.py
CHANGED
|
@@ -23,7 +23,7 @@ from app.schemas import (
|
|
| 23 |
RegressionOutput,
|
| 24 |
)
|
| 25 |
|
| 26 |
-
#
|
| 27 |
logging.basicConfig(
|
| 28 |
level=logging.INFO,
|
| 29 |
format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
|
|
@@ -31,7 +31,7 @@ logging.basicConfig(
|
|
| 31 |
logger = logging.getLogger(__name__)
|
| 32 |
|
| 33 |
|
| 34 |
-
#
|
| 35 |
@asynccontextmanager
|
| 36 |
async def lifespan(app: FastAPI):
|
| 37 |
logger.info("Starting Immo Predictor API...")
|
|
@@ -40,7 +40,7 @@ async def lifespan(app: FastAPI):
|
|
| 40 |
logger.info("Shutting down Immo Predictor API.")
|
| 41 |
|
| 42 |
|
| 43 |
-
#
|
| 44 |
app = FastAPI(
|
| 45 |
title="Immo Predictor API",
|
| 46 |
description=(
|
|
@@ -60,13 +60,13 @@ app.add_middleware(
|
|
| 60 |
allow_headers=["*"],
|
| 61 |
)
|
| 62 |
|
| 63 |
-
#
|
| 64 |
from app.ui import demo as gradio_demo
|
| 65 |
|
| 66 |
app = gr.mount_gradio_app(app, gradio_demo, path="/ui")
|
| 67 |
|
| 68 |
|
| 69 |
-
#
|
| 70 |
|
| 71 |
|
| 72 |
@app.get("/", tags=["General"], summary="Redirection vers l'interface")
|
|
@@ -113,7 +113,7 @@ def models_info():
|
|
| 113 |
}
|
| 114 |
|
| 115 |
|
| 116 |
-
#
|
| 117 |
|
| 118 |
|
| 119 |
@app.post(
|
|
@@ -148,7 +148,7 @@ def regression_predict(
|
|
| 148 |
raise HTTPException(status_code=500, detail=f"Prediction error: {exc}")
|
| 149 |
|
| 150 |
|
| 151 |
-
#
|
| 152 |
|
| 153 |
|
| 154 |
@app.post(
|
|
|
|
| 23 |
RegressionOutput,
|
| 24 |
)
|
| 25 |
|
| 26 |
+
# Logging
|
| 27 |
logging.basicConfig(
|
| 28 |
level=logging.INFO,
|
| 29 |
format="%(asctime)s | %(levelname)-8s | %(name)s | %(message)s",
|
|
|
|
| 31 |
logger = logging.getLogger(__name__)
|
| 32 |
|
| 33 |
|
| 34 |
+
# Lifespan (load models once at startup)
|
| 35 |
@asynccontextmanager
|
| 36 |
async def lifespan(app: FastAPI):
|
| 37 |
logger.info("Starting Immo Predictor API...")
|
|
|
|
| 40 |
logger.info("Shutting down Immo Predictor API.")
|
| 41 |
|
| 42 |
|
| 43 |
+
# App ββββ
|
| 44 |
app = FastAPI(
|
| 45 |
title="Immo Predictor API",
|
| 46 |
description=(
|
|
|
|
| 60 |
allow_headers=["*"],
|
| 61 |
)
|
| 62 |
|
| 63 |
+
# Mount Gradio UI at /ui
|
| 64 |
from app.ui import demo as gradio_demo
|
| 65 |
|
| 66 |
app = gr.mount_gradio_app(app, gradio_demo, path="/ui")
|
| 67 |
|
| 68 |
|
| 69 |
+
# Routes
|
| 70 |
|
| 71 |
|
| 72 |
@app.get("/", tags=["General"], summary="Redirection vers l'interface")
|
|
|
|
| 113 |
}
|
| 114 |
|
| 115 |
|
| 116 |
+
# Regression
|
| 117 |
|
| 118 |
|
| 119 |
@app.post(
|
|
|
|
| 148 |
raise HTTPException(status_code=500, detail=f"Prediction error: {exc}")
|
| 149 |
|
| 150 |
|
| 151 |
+
# Classification
|
| 152 |
|
| 153 |
|
| 154 |
@app.post(
|
app/predictor.py
CHANGED
|
@@ -12,11 +12,11 @@ import pandas as pd
|
|
| 12 |
|
| 13 |
logger = logging.getLogger(__name__)
|
| 14 |
|
| 15 |
-
#
|
| 16 |
BASE_DIR = Path(__file__).resolve().parent.parent
|
| 17 |
MODEL_PATH = BASE_DIR / "models" / "Mes_models.pkl"
|
| 18 |
|
| 19 |
-
#
|
| 20 |
_store: dict[str, Any] | None = None
|
| 21 |
|
| 22 |
|
|
@@ -40,7 +40,7 @@ def get_store() -> dict[str, Any]:
|
|
| 40 |
return _store
|
| 41 |
|
| 42 |
|
| 43 |
-
#
|
| 44 |
|
| 45 |
# The numerical features expected by the regression pipeline
|
| 46 |
_REG_NUM_FEATURES = [
|
|
@@ -89,7 +89,7 @@ def predict_regression(data: dict, model_name: str = "random_forest") -> float:
|
|
| 89 |
return float(prediction)
|
| 90 |
|
| 91 |
|
| 92 |
-
#
|
| 93 |
|
| 94 |
_CLF_NUM_FEATURES = [
|
| 95 |
"GrLivArea", "TotRmsAbvGrd", "OverallQual", "YearBuilt", "GarageCars",
|
|
|
|
| 12 |
|
| 13 |
logger = logging.getLogger(__name__)
|
| 14 |
|
| 15 |
+
# Paths ββ
|
| 16 |
BASE_DIR = Path(__file__).resolve().parent.parent
|
| 17 |
MODEL_PATH = BASE_DIR / "models" / "Mes_models.pkl"
|
| 18 |
|
| 19 |
+
# Global state (loaded once)
|
| 20 |
_store: dict[str, Any] | None = None
|
| 21 |
|
| 22 |
|
|
|
|
| 40 |
return _store
|
| 41 |
|
| 42 |
|
| 43 |
+
# Regression
|
| 44 |
|
| 45 |
# The numerical features expected by the regression pipeline
|
| 46 |
_REG_NUM_FEATURES = [
|
|
|
|
| 89 |
return float(prediction)
|
| 90 |
|
| 91 |
|
| 92 |
+
# Classification
|
| 93 |
|
| 94 |
_CLF_NUM_FEATURES = [
|
| 95 |
"GrLivArea", "TotRmsAbvGrd", "OverallQual", "YearBuilt", "GarageCars",
|
app/schemas.py
CHANGED
|
@@ -5,7 +5,7 @@ Pydantic schemas for input validation and output formatting.
|
|
| 5 |
from pydantic import BaseModel, Field
|
| 6 |
|
| 7 |
|
| 8 |
-
#
|
| 9 |
|
| 10 |
class RegressionInput(BaseModel):
|
| 11 |
"""Input features for house price prediction (regression)."""
|
|
@@ -59,7 +59,7 @@ class RegressionOutput(BaseModel):
|
|
| 59 |
currency: str = Field(default="USD", description="Currency of the predicted price")
|
| 60 |
|
| 61 |
|
| 62 |
-
#
|
| 63 |
|
| 64 |
class ClassificationInput(BaseModel):
|
| 65 |
"""Input features for building type classification."""
|
|
|
|
| 5 |
from pydantic import BaseModel, Field
|
| 6 |
|
| 7 |
|
| 8 |
+
# Regression
|
| 9 |
|
| 10 |
class RegressionInput(BaseModel):
|
| 11 |
"""Input features for house price prediction (regression)."""
|
|
|
|
| 59 |
currency: str = Field(default="USD", description="Currency of the predicted price")
|
| 60 |
|
| 61 |
|
| 62 |
+
# Classification
|
| 63 |
|
| 64 |
class ClassificationInput(BaseModel):
|
| 65 |
"""Input features for building type classification."""
|
app/ui.py
CHANGED
|
@@ -18,8 +18,7 @@ logger = logging.getLogger(__name__)
|
|
| 18 |
# Ensure models are loaded
|
| 19 |
load_models()
|
| 20 |
|
| 21 |
-
#
|
| 22 |
-
|
| 23 |
NEIGHBORHOODS = [
|
| 24 |
"Blmngtn", "Blueste", "BrDale", "BrkSide", "ClearCr",
|
| 25 |
"CollgCr", "Crawfor", "Edwards", "Gilbert", "IDOTRR",
|
|
@@ -33,7 +32,7 @@ HOUSE_STYLES = [
|
|
| 33 |
"2.5Unf", "SFoyer", "SLvl",
|
| 34 |
]
|
| 35 |
|
| 36 |
-
#
|
| 37 |
|
| 38 |
def create_regression_comparison_chart(data: dict) -> plt.Figure:
|
| 39 |
"""Compare predictions from both regression models."""
|
|
@@ -132,7 +131,7 @@ def create_classification_comparison_chart(data: dict) -> plt.Figure:
|
|
| 132 |
return fig
|
| 133 |
|
| 134 |
|
| 135 |
-
#
|
| 136 |
|
| 137 |
def regression_ui(
|
| 138 |
GrLivArea, TotalBsmtSF, LotArea, BedroomAbvGr, FullBath,
|
|
@@ -168,8 +167,7 @@ def regression_ui(
|
|
| 168 |
return f"Erreur : {str(e)}", None, None
|
| 169 |
|
| 170 |
|
| 171 |
-
#
|
| 172 |
-
|
| 173 |
def classification_ui(
|
| 174 |
GrLivArea, TotRmsAbvGrd, OverallQual, YearBuilt,
|
| 175 |
GarageCars, Neighborhood, HouseStyle, model_name
|
|
@@ -195,8 +193,7 @@ def classification_ui(
|
|
| 195 |
return f"Erreur : {str(e)}", None, None
|
| 196 |
|
| 197 |
|
| 198 |
-
#
|
| 199 |
-
|
| 200 |
CUSTOM_CSS = """
|
| 201 |
.gradio-container > footer {
|
| 202 |
position: fixed !important;
|
|
|
|
| 18 |
# Ensure models are loaded
|
| 19 |
load_models()
|
| 20 |
|
| 21 |
+
# Neighborhood & HouseStyle lists
|
|
|
|
| 22 |
NEIGHBORHOODS = [
|
| 23 |
"Blmngtn", "Blueste", "BrDale", "BrkSide", "ClearCr",
|
| 24 |
"CollgCr", "Crawfor", "Edwards", "Gilbert", "IDOTRR",
|
|
|
|
| 32 |
"2.5Unf", "SFoyer", "SLvl",
|
| 33 |
]
|
| 34 |
|
| 35 |
+
# Chart helpers β
|
| 36 |
|
| 37 |
def create_regression_comparison_chart(data: dict) -> plt.Figure:
|
| 38 |
"""Compare predictions from both regression models."""
|
|
|
|
| 131 |
return fig
|
| 132 |
|
| 133 |
|
| 134 |
+
# Regression Prediction
|
| 135 |
|
| 136 |
def regression_ui(
|
| 137 |
GrLivArea, TotalBsmtSF, LotArea, BedroomAbvGr, FullBath,
|
|
|
|
| 167 |
return f"Erreur : {str(e)}", None, None
|
| 168 |
|
| 169 |
|
| 170 |
+
# Classification Prediction
|
|
|
|
| 171 |
def classification_ui(
|
| 172 |
GrLivArea, TotRmsAbvGrd, OverallQual, YearBuilt,
|
| 173 |
GarageCars, Neighborhood, HouseStyle, model_name
|
|
|
|
| 193 |
return f"Erreur : {str(e)}", None, None
|
| 194 |
|
| 195 |
|
| 196 |
+
# Build Gradio Interface
|
|
|
|
| 197 |
CUSTOM_CSS = """
|
| 198 |
.gradio-container > footer {
|
| 199 |
position: fixed !important;
|