Spaces:
Sleeping
Sleeping
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() | |