AayushKuloor's picture
Upload 23 files
3fdedfb verified
Raw
History Blame Contribute Delete
4.29 kB
import pickle
from pathlib import Path
import pandas as pd
import streamlit as st
st.set_page_config(page_title="UrbanNest Rent Predictor", layout="wide")
ARTIFACT_DIR = Path("models")
INFERENCE_BUNDLE_PATH = ARTIFACT_DIR / "inference_bundle.pkl"
UNKNOWN_CATEGORY_TOKEN = "__UNK__"
@st.cache_resource
def load_inference_artifacts():
if not INFERENCE_BUNDLE_PATH.exists():
raise FileNotFoundError(
"Missing models/inference_bundle.pkl. Run train.ipynb first."
)
with open(INFERENCE_BUNDLE_PATH, "rb") as f:
bundle = pickle.load(f)
required_keys = {"model", "label_encoders", "feature_columns", "feature_metadata", "model_metadata"}
missing_keys = required_keys - set(bundle.keys())
if missing_keys:
raise KeyError(f"inference_bundle.pkl is missing keys: {sorted(missing_keys)}")
return (
bundle["model"],
bundle["label_encoders"],
bundle["feature_columns"],
bundle["feature_metadata"],
bundle["model_metadata"],
)
def _build_numeric_input(feature_name, metadata):
dtype = metadata["dtype"]
min_value = metadata["min"]
max_value = metadata["max"]
default_value = metadata["mean"]
if "int" in dtype:
return st.number_input(
label=feature_name,
min_value=int(min_value),
max_value=int(max_value),
value=int(round(default_value)),
step=1,
)
return st.number_input(
label=feature_name,
min_value=float(min_value),
max_value=float(max_value),
value=float(default_value),
step=0.1,
format="%.4f",
)
def main():
st.title("UrbanNest Analytics: Dynamic House Rent Prediction")
st.write("Provide property details below to estimate monthly rent (INR).")
try:
model, label_encoders, feature_columns, feature_metadata, model_metadata = load_inference_artifacts()
except Exception as exc:
st.error(f"Failed to load model artifacts: {exc}")
st.stop()
st.caption(
f"Best training method: {model_metadata['best_method']} | "
f"CV MAE: {model_metadata['best_cv_mae']:.2f} | "
f"Test MAE: {model_metadata['test_mae']:.2f}"
)
user_inputs = {}
left_col, right_col = st.columns(2)
column_index = 0
for feature_name in feature_columns:
target_column = left_col if column_index % 2 == 0 else right_col
with target_column:
if feature_name in label_encoders:
classes = [str(item) for item in label_encoders[feature_name].classes_]
if UNKNOWN_CATEGORY_TOKEN in classes:
display_options = [c for c in classes if c != UNKNOWN_CATEGORY_TOKEN]
display_options.append("Other / Unknown")
user_inputs[feature_name] = st.selectbox(feature_name, options=display_options)
else:
user_inputs[feature_name] = st.selectbox(feature_name, options=classes)
else:
user_inputs[feature_name] = _build_numeric_input(feature_name, feature_metadata[feature_name])
column_index += 1
if st.button("Predict"):
encoded_row = {}
for feature_name in feature_columns:
feature_value = user_inputs[feature_name]
if feature_name in label_encoders:
raw_value = str(feature_value)
if raw_value == "Other / Unknown":
raw_value = UNKNOWN_CATEGORY_TOKEN
encoded_row[feature_name] = int(label_encoders[feature_name].transform([raw_value])[0])
else:
dtype = feature_metadata[feature_name]["dtype"]
if "int" in dtype:
encoded_row[feature_name] = int(feature_value)
else:
encoded_row[feature_name] = float(feature_value)
model_input = pd.DataFrame([encoded_row], columns=feature_columns)
prediction = float(model.predict(model_input)[0])
st.success(f"Predicted Monthly Rent: INR {prediction:,.2f}")
if __name__ == "__main__":
main()