Skip to content

Commit 59069b9

Browse files
authored
Create RentPredictor.py
1 parent c2e6b01 commit 59069b9

1 file changed

Lines changed: 194 additions & 0 deletions

File tree

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
"""
2+
RentPredictor v1.0 - Smart Housing Intelligence Tool
3+
ML-powered house rent estimation with modern UI
4+
"""
5+
6+
import os, sys, threading
7+
import tkinter as tk
8+
from tkinter import messagebox
9+
10+
import numpy as np
11+
import joblib
12+
13+
import ttkbootstrap as tb
14+
from ttkbootstrap.constants import *
15+
16+
# ---------------------- UTIL ----------------------
17+
def resource_path(file_name):
18+
base_path = getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__)))
19+
return os.path.join(base_path, file_name)
20+
21+
22+
# ---------------------- ML WORKER ----------------------
23+
class PredictionWorker:
24+
def __init__(self, model, features, callback):
25+
self.model = model
26+
self.features = features
27+
self.callback = callback
28+
29+
def run(self):
30+
try:
31+
prediction = self.model.predict([self.features])[0]
32+
self.callback(round(prediction, 2))
33+
except Exception as e:
34+
self.callback(None, str(e))
35+
36+
37+
# ---------------------- MAIN APP ----------------------
38+
class RentPredictorApp:
39+
APP_NAME = "RentPredictor"
40+
APP_VERSION = "1.0"
41+
42+
def __init__(self):
43+
self.root = tb.Window(themename="darkly")
44+
self.root.title(f"{self.APP_NAME} v{self.APP_VERSION}")
45+
self.root.minsize(900, 520)
46+
47+
try:
48+
self.root.iconbitmap(resource_path("logo.ico"))
49+
except:
50+
pass
51+
52+
self.model = self._load_model()
53+
self._build_ui()
54+
55+
# ---------------------- LOAD MODEL ----------------------
56+
def _load_model(self):
57+
try:
58+
return joblib.load(resource_path("rent_model.pkl"))
59+
except:
60+
# fallback dummy model
61+
class DummyModel:
62+
def predict(self, X):
63+
size, bhk, bath, city = X[0]
64+
return [size * 25 + bhk * 1500 + bath * 1000 + city * 2000]
65+
return DummyModel()
66+
67+
# ---------------------- UI ----------------------
68+
def _build_ui(self):
69+
main = tb.Frame(self.root, padding=15)
70+
main.pack(fill=BOTH, expand=True)
71+
72+
tb.Label(
73+
main,
74+
text="🏠 RentPredictor - Smart Rent Estimation",
75+
font=("Segoe UI", 22, "bold")
76+
).pack(pady=(0, 5))
77+
78+
tb.Label(
79+
main,
80+
text="AI-powered house rent prediction engine",
81+
font=("Segoe UI", 10, "italic"),
82+
foreground="#9ca3af"
83+
).pack(pady=(0, 25))
84+
85+
form = tb.Labelframe(main, text="Property Details", padding=15)
86+
form.pack(fill=X, pady=(0, 20))
87+
88+
# Inputs
89+
self.size_var = tk.DoubleVar()
90+
self.bhk_var = tk.IntVar()
91+
self.bath_var = tk.IntVar()
92+
self.city_var = tk.IntVar()
93+
94+
self._add_field(form, "House Size (sq ft)", self.size_var, 0)
95+
self._add_field(form, "BHK", self.bhk_var, 1)
96+
self._add_field(form, "Bathrooms", self.bath_var, 2)
97+
98+
tb.Label(form, text="City Category").grid(row=3, column=0, sticky=W, pady=5)
99+
self.city_combo = tb.Combobox(
100+
form,
101+
values=["Small City", "Metro City"],
102+
state="readonly"
103+
)
104+
self.city_combo.current(0)
105+
self.city_combo.grid(row=3, column=1, sticky=EW, pady=5)
106+
107+
# Actions
108+
actions = tb.Frame(main)
109+
actions.pack(fill=X, pady=(0, 15))
110+
111+
self.predict_btn = tb.Button(
112+
actions,
113+
text="🔮 Predict Rent",
114+
bootstyle=SUCCESS,
115+
command=self.predict
116+
)
117+
self.predict_btn.pack(side=LEFT, padx=5)
118+
119+
tb.Button(
120+
actions,
121+
text="ℹ️ About",
122+
bootstyle=INFO,
123+
command=self.show_about
124+
).pack(side=LEFT, padx=5)
125+
126+
# Result
127+
self.result_label = tb.Label(
128+
main,
129+
text="Estimated Monthly Rent: —",
130+
font=("Segoe UI", 18, "bold"),
131+
foreground="#22c55e"
132+
)
133+
self.result_label.pack(pady=20)
134+
135+
def _add_field(self, parent, label, var, row):
136+
tb.Label(parent, text=label).grid(row=row, column=0, sticky=W, pady=5)
137+
tb.Entry(parent, textvariable=var).grid(row=row, column=1, sticky=EW, pady=5)
138+
parent.columnconfigure(1, weight=1)
139+
140+
# ---------------------- ACTIONS ----------------------
141+
def predict(self):
142+
try:
143+
size = self.size_var.get()
144+
bhk = self.bhk_var.get()
145+
bath = self.bath_var.get()
146+
city = 1 if self.city_combo.get() == "Metro City" else 0
147+
148+
if size <= 0 or bhk <= 0 or bath <= 0:
149+
raise ValueError
150+
151+
except:
152+
messagebox.showerror("Invalid Input", "Please enter valid numeric values")
153+
return
154+
155+
self.result_label.config(text="Estimating rent…")
156+
157+
worker = PredictionWorker(
158+
self.model,
159+
[size, bhk, bath, city],
160+
self.show_result
161+
)
162+
163+
threading.Thread(target=worker.run, daemon=True).start()
164+
165+
def show_result(self, rent, error=None):
166+
if error:
167+
messagebox.showerror("Prediction Error", error)
168+
self.result_label.config(text="Estimated Monthly Rent: —")
169+
else:
170+
self.result_label.config(
171+
text=f"Estimated Monthly Rent: ₹ {rent:,}"
172+
)
173+
174+
# ---------------------- ABOUT ----------------------
175+
def show_about(self):
176+
messagebox.showinfo(
177+
f"About {self.APP_NAME}",
178+
f"{self.APP_NAME} v{self.APP_VERSION}\n\n"
179+
"• Machine Learning powered rent estimation\n"
180+
"• Clean enterprise-grade UI\n"
181+
"• Threaded predictions (no UI freeze)\n"
182+
"• Supports trained ML models\n\n"
183+
"🏢 Built by Mate Technologies"
184+
)
185+
186+
# ---------------------- RUN ----------------------
187+
def run(self):
188+
self.root.mainloop()
189+
190+
191+
# ---------------------- START ----------------------
192+
if __name__ == "__main__":
193+
app = RentPredictorApp()
194+
app.run()

0 commit comments

Comments
 (0)