property_model / app.py
vishwak1's picture
Update app.py
d29abcc verified
import gradio as gr
import pandas as pd
import numpy as np
import joblib
import os
from datetime import datetime
import plotly.graph_objects as go
import warnings
warnings.filterwarnings('ignore')
# Try to import the PropertyValuePredictor class
try:
from train_model import PropertyValuePredictor
print("โœ… Successfully imported PropertyValuePredictor from train_model")
except ImportError as e:
print(f"โŒ Import error: {e}")
# Fallback: create a simple predictor class
class PropertyValuePredictor:
def __init__(self):
self.model = None
self.scaler = None
self.feature_columns = None
self.label_encoders = {}
def load_model(self, model_path):
try:
if os.path.exists(model_path):
model_data = joblib.load(model_path)
self.model = model_data['model']
self.scaler = model_data['scaler']
self.feature_columns = model_data['feature_columns']
self.label_encoders = model_data.get('label_encoders', {})
print(f"โœ… Model loaded from {model_path}")
return True
else:
print(f"โŒ Model file {model_path} not found")
return False
except Exception as e:
print(f"โŒ Error loading model: {e}")
return False
def predict_future_value(self, property_data):
if self.model is None:
return {"error": "Model not loaded"}
try:
# Convert to DataFrame
if isinstance(property_data, dict):
df = pd.DataFrame([property_data])
else:
df = property_data.copy()
# Feature engineering
df['property_age'] = 2025 - df['year_built']
df['price_per_sqft'] = df['current_value'] / df['square_feet']
df['value_per_bedroom'] = df['current_value'] / df['bedrooms'].replace(0, 1)
# Encode categorical features
for col, encoder in self.label_encoders.items():
if col.replace('_encoded', '') in df.columns:
original_col = col.replace('_encoded', '')
try:
df[col] = encoder.transform(df[original_col].astype(str))
except:
df[col] = 0
# Select features
if self.feature_columns:
# Ensure all features exist
for col in self.feature_columns:
if col not in df.columns:
df[col] = 0
X = df[self.feature_columns]
else:
# Use available numeric columns
numeric_cols = df.select_dtypes(include=[np.number]).columns
X = df[numeric_cols]
# Scale features
if self.scaler:
X_scaled = self.scaler.transform(X)
else:
X_scaled = X.values
# Predict
predicted_value = self.model.predict(X_scaled)[0]
# Calculate metrics
current_value = df['current_value'].iloc[0]
appreciation = predicted_value - current_value
appreciation_pct = (appreciation / current_value) * 100
return {
'current_value': current_value,
'predicted_future_value': predicted_value,
'predicted_appreciation': appreciation,
'appreciation_percentage': appreciation_pct,
'annual_appreciation_rate': appreciation_pct / 5 }
except Exception as e:
return {"error": f"Prediction error: {str(e)}"}
class PropertyPredictionApp:
def __init__(self):
self.predictor = PropertyValuePredictor()
self.model_loaded = False
self.load_model()
# State mappings
self.states = [
'AL', 'AK', 'AZ', 'AR', 'CA', 'CO', 'CT', 'DE', 'FL', 'GA',
'HI', 'ID', 'IL', 'IN', 'IA', 'KS', 'KY', 'LA', 'ME', 'MD',
'MA', 'MI', 'MN', 'MS', 'MO', 'MT', 'NE', 'NV', 'NH', 'NJ',
'NM', 'NY', 'NC', 'ND', 'OH', 'OK', 'OR', 'PA', 'RI', 'SC',
'SD', 'TN', 'TX', 'UT', 'VT', 'VA', 'WA', 'WV', 'WI', 'WY', 'DC'
]
self.property_types = [
'Single Family Home', 'Townhouse', 'Condo', 'Multi-Family',
'Duplex', 'Ranch', 'Colonial', 'Victorian', 'Modern', 'Split Level' ]
self.school_ratings = [
'Excellent', 'Very Good', 'Good', 'Average', 'Below Average'
]
def load_model(self):
"""Load the trained model with fallback options"""
model_files = [
'simple_property_model.joblib',
'enhanced_property_model.joblib',
'property_value_model.joblib'
]
for model_file in model_files:
if os.path.exists(model_file):
try:
success = self.predictor.load_model(model_file)
if success:
self.model_loaded = True
print(f"โœ… Successfully loaded model from {model_file}")
return
except Exception as e:
print(f"โŒ Failed to load {model_file}: {e}")
continue
print("โŒ No model file found. Using demo mode.")
self.model_loaded = False
def predict_property_value(self, current_value, year_built, state, property_type,
bedrooms, bathrooms, square_feet, lot_size,
school_district_rating, monthly_rent, property_tax,
hoa_monthly):
"""Predict future property value"""
if not self.model_loaded:
# Demo mode - simple calculation
base_appreciation = 0.05 # 5% annual
years = 5
demo_value = current_value * (1 + base_appreciation) ** years
prediction_text = (
f"๐Ÿšจ **Demo Mode** (No model loaded)\n\n"
f"**Current Property Value:** ${current_value:,.2f}\n\n"
f"**Estimated 5-Year Value:** ${demo_value:,.2f}\n\n"
f"**Estimated Appreciation:** ${demo_value - current_value:,.2f} ({((demo_value - current_value) / current_value) * 100:.1f}%)\n\n"
f"**Annual Appreciation Rate:** {((demo_value / current_value) ** (1/5) - 1) * 100:.1f}%\n\n"
f"*Note: This is a demo calculation using 5% annual appreciation. Train and upload a model for accurate predictions.*"
)
chart = self.create_prediction_chart(current_value, None)
return prediction_text, chart
try:
# Prepare property data
property_data = {
'current_value': current_value,
'year_built': year_built,
'state': state,
'property_type': property_type,
'bedrooms': bedrooms,
'bathrooms': bathrooms,
'square_feet': square_feet,
'lot_size': lot_size,
'school_district_rating': school_district_rating,
'monthly_rent_estimate': monthly_rent,
'property_tax_annual': property_tax,
'hoa_monthly': hoa_monthly
}
# Get prediction
result = self.predictor.predict_future_value(property_data)
if "error" in result:
error_text = f"โŒ **Error:** {result['error']}"
chart = self.create_prediction_chart(current_value, None)
return error_text, chart
# Format results
current_val = result['current_value']
future_val = result['predicted_future_value']
appreciation = result['predicted_appreciation']
appreciation_pct = result['appreciation_percentage']
annual_rate = result['annual_appreciation_rate']
prediction_text = (
f"## ๐Ÿ  Property Value Prediction Results\n\n"
f"**Current Property Value:** ${current_val:,.2f}\n\n"
f"**Predicted 5-Year Value:** ${future_val:,.2f}\n\n"
f"**Total Appreciation:** ${appreciation:,.2f}\n\n"
f"**Appreciation Percentage:** {appreciation_pct:.2f}%\n\n"
f"**Annual Appreciation Rate:** {annual_rate:.2f}%\n\n"
f"---\n\n"
f"๐Ÿ“Š **Investment Analysis:**\n"
f"- Monthly appreciation: ${appreciation/60:,.2f}\n"
f"- ROI over 5 years: {appreciation_pct:.1f}%\n"
f"- Estimated monthly rent: ${monthly_rent:,.2f}\n"
f"- Property tax burden: {(property_tax/current_val)*100:.2f}% of value" )
# Create chart with actual prediction
chart = self.create_prediction_chart(current_val, future_val)
return prediction_text, chart
except Exception as e:
error_text = f"โŒ **Prediction Error:** {str(e)}"
chart = self.create_prediction_chart(current_value, None)
return error_text, chart
def create_prediction_chart(self, current_value, predicted_value=None):
"""Create a chart showing actual prediction results"""
years = list(range(0, 6))
if predicted_value is None or not self.model_loaded:
# Demo mode - use 5% annual appreciation
values = [current_value * (1.05 ** year) for year in years]
title = "Demo: Property Value Growth (5% Annual)"
line_color = '#FFA500' # Orange for demo
else:
# Use actual prediction - interpolate between current and predicted
annual_rate = (predicted_value / current_value) ** (1/5) - 1
total_appreciation = ((predicted_value - current_value) / current_value) * 100
values = [current_value * (1 + annual_rate) ** year for year in years]
title = f"AI Prediction: {total_appreciation:.1f}% Total Growth ({annual_rate*100:.1f}% Annual)"
line_color = '#2E86AB' # Blue for real predictions
fig = go.Figure()
fig.add_trace(go.Scatter(
x=years,
y=values,
mode='lines+markers',
name='Property Value',
line=dict(color=line_color, width=3),
marker=dict(size=8)
))
# Add annotations for key points
fig.add_annotation(
x=0, y=values[0],
text=f"Current: ${values[0]:,.0f}",
showarrow=True,
arrowhead=2,
bgcolor="white",
bordercolor=line_color
)
fig.add_annotation(
x=5, y=values[5],
text=f"5-Year: ${values[5]:,.0f}",
showarrow=True,
arrowhead=2,
bgcolor="white",
bordercolor=line_color
)
# Add total appreciation annotation for ML predictions
if predicted_value is not None and self.model_loaded:
total_appreciation = ((predicted_value - current_value) / current_value) * 100
fig.add_annotation(
x=2.5, y=values[2] + (values[5] - values[2]) * 0.3,
text=f"Total Growth: +{total_appreciation:.1f}%",
showarrow=False,
bgcolor="rgba(46, 134, 171, 0.8)",
bordercolor=line_color,
font=dict(color="white", size=14, family="Arial Black")
)
fig.update_layout(
title=title,
xaxis_title="Years from Now",
yaxis_title="Property Value ($)",
template="plotly_white",
height=400,
yaxis=dict(tickformat='$,.0f')
)
return fig
def create_interface(self):
"""Create the Gradio interface"""
with gr.Blocks(title="๐Ÿ  Property Value Predictor", theme=gr.themes.Soft()) as interface:
gr.Markdown("""
# ๐Ÿ  AI Property Value Predictor
Predict your property's value 5 years from now using advanced machine learning!
**How it works:**
1. Enter your property details below
2. Click "Predict Future Value"
3. Get instant AI-powered predictions with detailed analysis
""")
with gr.Row():
with gr.Column(scale=1):
gr.Markdown("### ๐Ÿ“Š Property Details")
current_value = gr.Number(
label="Current Property Value ($)",
value=500000,
minimum=50000,
maximum=10000000,
step=10000
)
year_built = gr.Number(
label="Year Built",
value=2010,
minimum=1800,
maximum=2025,
step=1
)
state = gr.Dropdown(
choices=self.states,
label="State",
value="CA"
)
property_type = gr.Dropdown(
choices=self.property_types,
label="Property Type",
value="Single Family Home"
)
with gr.Column(scale=1):
gr.Markdown("### ๐Ÿก Property Features")
bedrooms = gr.Number(
label="Bedrooms",
value=3,
minimum=1,
maximum=10,
step=1
)
bathrooms = gr.Number(
label="Bathrooms",
value=2.5,
minimum=1,
maximum=10,
step=0.5
)
square_feet = gr.Number(
label="Square Feet",
value=2000,
minimum=300,
maximum=20000,
step=100
)
lot_size = gr.Number(
label="Lot Size (acres)",
value=0.25,
minimum=0.01,
maximum=5.0,
step=0.01
)
with gr.Column(scale=1):
gr.Markdown("### ๐Ÿ’ฐ Financial Details")
school_rating = gr.Dropdown(
choices=self.school_ratings,
label="School District Rating",
value="Good"
)
monthly_rent = gr.Number(
label="Estimated Monthly Rent ($)",
value=2500,
minimum=500,
maximum=20000,
step=100
)
property_tax = gr.Number(
label="Annual Property Tax ($)",
value=6000,
minimum=500,
maximum=100000,
step=500
)
hoa_monthly = gr.Number(
label="Monthly HOA Fee ($)",
value=0,
minimum=0,
maximum=2000,
step=50
)
with gr.Row():
predict_btn = gr.Button(
"๐Ÿ”ฎ Predict Future Value",
variant="primary",
size="lg"
)
with gr.Row():
with gr.Column(scale=2): prediction_output = gr.Markdown(
label="Prediction Results",
value="Enter property details and click 'Predict Future Value' to see AI predictions!"
)
with gr.Column(scale=1):
chart_output = gr.Plot(label="Value Projection Chart")
# Event handlers
predict_btn.click(
fn=self.predict_property_value,
inputs=[
current_value, year_built, state, property_type,
bedrooms, bathrooms, square_feet, lot_size,
school_rating, monthly_rent, property_tax, hoa_monthly
],
outputs=[prediction_output, chart_output]
)
# Update chart when current value changes (demo mode only)
current_value.change(
fn=lambda val: self.create_prediction_chart(val, None),
inputs=current_value,
outputs=chart_output
)
# Set initial chart
interface.load(
fn=lambda: self.create_prediction_chart(500000, None),
outputs=chart_output
)
gr.Markdown("""
---
### ๐Ÿ“ About This Tool
This AI-powered property value predictor uses machine learning to analyze:
- **Property characteristics** (age, size, type, location)
- **Market factors** (school ratings, comparable sales)
- **Financial metrics** (rent potential, taxes, HOA fees)
- **Historical trends** and regional market patterns
**Disclaimer:** Predictions are estimates based on historical data and should not be considered as professional real estate advice.
""")
return interface
def main():
"""Main function to create and launch the app"""
print("๐Ÿš€ Starting Property Value Predictor App...")
app = PropertyPredictionApp()
interface = app.create_interface()
# Launch the interface
interface.launch(
share=True,
server_name="0.0.0.0",
server_port=7860,
show_error=True
)
if __name__ == "__main__":
main()