Download app.py from abhi9716/model: direct link, hf CLI and curl.
- Browser
- Download file 14.6 kB
-
https://huggingface.co/spaces/abhi9716/model/resolve/main/app.py
- Command line
-
hf download hf://spaces/abhi9716/model/app.py
-
curl -L -o app.py https://huggingface.co/spaces/abhi9716/model/resolve/main/app.py
14.6 kB
| import streamlit as st | |
| import pandas as pd | |
| import pickle | |
| import os | |
| import warnings | |
| warnings.filterwarnings("ignore") | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PAGE CONFIG | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| st.set_page_config( | |
| page_title="House Price AI", | |
| page_icon="π ", | |
| layout="centered", | |
| initial_sidebar_state="auto", | |
| ) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CSS LOADER β reads from static/css/style.css | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| def load_css(): | |
| """ | |
| Reads the external stylesheet from static/css/style.css | |
| and injects it into the Streamlit page via st.markdown. | |
| All visual styling lives in that file β app.py stays clean. | |
| """ | |
| css_path = os.path.join("static", "css", "style.css") | |
| if not os.path.exists(css_path): | |
| st.warning("β οΈ style.css not found β place it at static/css/style.css") | |
| return | |
| with open(css_path, "r", encoding="utf-8") as f: | |
| css_content = f.read() | |
| st.markdown(f"<style>{css_content}</style>", unsafe_allow_html=True) | |
| load_css() | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # DATA & MODEL | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| DATA_PATH = "data_updated_ap_kakinada.csv" | |
| MODEL_PATH = "model.pkl" | |
| if not os.path.exists(DATA_PATH): | |
| st.error("β Dataset file not found! Expected: data_updated_ap_kakinada.csv") | |
| st.stop() | |
| if not os.path.exists(MODEL_PATH): | |
| st.error("β Model file not found! Expected: model.pkl") | |
| st.stop() | |
| df = pd.read_csv(DATA_PATH) | |
| with open(MODEL_PATH, "rb") as f: | |
| model = pickle.load(f) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # SESSION STATE | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| if "logged_in" not in st.session_state: | |
| st.session_state.logged_in = False | |
| if "username" not in st.session_state: | |
| st.session_state.username = "" | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # HELPER: render HTML card wrapper | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| def card_open(extra_class=""): | |
| st.markdown(f'<div class="card {extra_class}">', unsafe_allow_html=True) | |
| def card_close(): | |
| st.markdown("</div>", unsafe_allow_html=True) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PAGE: LOGIN | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| def login(): | |
| # Hero header | |
| st.markdown(""" | |
| <div style="text-align:center; padding: 2rem 0 1rem;"> | |
| <div class="badge-live" style="margin-bottom:1rem;">AI-Powered Β· Real-time Estimates</div> | |
| <h1 style="font-size:2.4rem; margin-bottom:.4rem;">Welcome Back</h1> | |
| <p style="color:#64748b; font-size:.95rem;">Sign in to your House Price AI account</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| card_open() | |
| username = st.text_input("Username", placeholder="Enter your username") | |
| password = st.text_input("Password", type="password", placeholder="Enter your password") | |
| if st.button("π Sign In"): | |
| if username and password: | |
| st.session_state.logged_in = True | |
| st.session_state.username = username | |
| st.success("β Login successful! Redirectingβ¦") | |
| st.rerun() | |
| else: | |
| st.error("β Please enter both username and password.") | |
| st.markdown(""" | |
| <p style="text-align:center; margin-top:1.2rem; font-size:.875rem; color:#64748b;"> | |
| Don't have an account? | |
| <span style="color:#38bdf8; font-weight:500; cursor:pointer;"> | |
| Use the sidebar β Signup | |
| </span> | |
| </p> | |
| """, unsafe_allow_html=True) | |
| card_close() | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PAGE: SIGNUP | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| def signup(): | |
| st.markdown(""" | |
| <div style="text-align:center; padding: 2rem 0 1rem;"> | |
| <h1 style="font-size:2.4rem; margin-bottom:.4rem;">Create Account</h1> | |
| <p style="color:#64748b; font-size:.95rem;">Start predicting house prices in seconds</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| card_open() | |
| username = st.text_input("Username", placeholder="Choose a username") | |
| password = st.text_input("Password", type="password", placeholder="Create a strong password") | |
| confirm = st.text_input("Confirm Password", type="password", placeholder="Repeat your password") | |
| if st.button("β¨ Create Account"): | |
| if not username or not password or not confirm: | |
| st.error("β All fields are required.") | |
| elif password != confirm: | |
| st.error("β Passwords do not match.") | |
| elif len(password) < 6: | |
| st.warning("β οΈ Password should be at least 6 characters.") | |
| else: | |
| st.success("β Account created! Please log in.") | |
| st.markdown(""" | |
| <p style="text-align:center; margin-top:1.2rem; font-size:.875rem; color:#64748b;"> | |
| Already have an account? | |
| <span style="color:#a78bfa; font-weight:500; cursor:pointer;"> | |
| Use the sidebar β Login | |
| </span> | |
| </p> | |
| """, unsafe_allow_html=True) | |
| card_close() | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PAGE: DASHBOARD | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| def dashboard(): | |
| # ββ SIDEBAR ββββββββββββββββββββββββββββββ | |
| with st.sidebar: | |
| st.markdown(""" | |
| <div style="text-align:center; padding:.5rem 0 1.2rem;"> | |
| <div style="font-size:2rem;">π </div> | |
| <div style="font-family:'Syne',sans-serif; font-weight:800; | |
| background:linear-gradient(135deg,#00f0ff,#3b82f6); | |
| -webkit-background-clip:text; -webkit-text-fill-color:transparent; | |
| font-size:1.1rem; margin-top:.3rem;"> | |
| House Price AI | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown(f""" | |
| <div style="display:flex; align-items:center; gap:10px; | |
| background:rgba(255,255,255,.04); | |
| border:1px solid rgba(255,255,255,.09); | |
| border-radius:12px; padding:10px 14px; margin-bottom:1.2rem;"> | |
| <div style="width:32px;height:32px;border-radius:50%; | |
| background:linear-gradient(135deg,#00f0ff,#8b5cf6); | |
| display:flex;align-items:center;justify-content:center; | |
| font-weight:700;font-size:14px;color:#fff;flex-shrink:0;"> | |
| {st.session_state.username[:1].upper() if st.session_state.username else "G"} | |
| </div> | |
| <div> | |
| <div style="font-weight:600;font-size:.9rem;color:#e2e8f0;"> | |
| {st.session_state.username or "Guest"} | |
| </div> | |
| <div style="font-size:.75rem;color:#64748b;">Signed in</div> | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.markdown("---") | |
| if st.button("πͺ Sign Out"): | |
| st.session_state.logged_in = False | |
| st.session_state.username = "" | |
| st.rerun() | |
| # ββ HERO βββββββββββββββββββββββββββββββββ | |
| st.markdown(f""" | |
| <div style="padding: 1.5rem 0 1rem;"> | |
| <div class="badge-live" style="margin-bottom:1rem;">AI-Powered Β· Real-time Estimates</div> | |
| <h1 style="font-size:clamp(1.8rem,4vw,2.6rem); line-height:1.15; margin-bottom:.5rem;"> | |
| House Price<br>Predictor | |
| </h1> | |
| <p style="color:#64748b; font-size:.95rem; max-width:480px;"> | |
| Enter city and area details to get an instant AI-powered price estimate for any property. | |
| </p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| # ββ STAT CARDS βββββββββββββββββββββββββββ | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| st.markdown(""" | |
| <div class="metric-card"> | |
| <div style="font-size:1.4rem; margin-bottom:.4rem;">ποΈ</div> | |
| <div class="metric-value">500+</div> | |
| <div class="metric-label">Cities Covered</div> | |
| </div>""", unsafe_allow_html=True) | |
| with col2: | |
| st.markdown(""" | |
| <div class="metric-card"> | |
| <div style="font-size:1.4rem; margin-bottom:.4rem;">π</div> | |
| <div class="metric-value">98.2%</div> | |
| <div class="metric-label">Accuracy Rate</div> | |
| </div>""", unsafe_allow_html=True) | |
| with col3: | |
| st.markdown(""" | |
| <div class="metric-card"> | |
| <div style="font-size:1.4rem; margin-bottom:.4rem;">β‘</div> | |
| <div class="metric-value"><1s</div> | |
| <div class="metric-label">Response Time</div> | |
| </div>""", unsafe_allow_html=True) | |
| st.markdown("<br>", unsafe_allow_html=True) | |
| # ββ PREDICT FORM βββββββββββββββββββββββββ | |
| card_open() | |
| st.markdown(""" | |
| <div style="margin-bottom:1.2rem;"> | |
| <div style="font-family:'Syne',sans-serif; font-weight:700; font-size:1.1rem; | |
| color:#fff; margin-bottom:.3rem;">π Get Price Estimate</div> | |
| <div style="font-size:.85rem; color:#64748b;">Fill in the property details below</div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| cities = sorted(df["city"].unique()) if "city" in df.columns else ["Kakinada"] | |
| city = st.selectbox("City", cities, help="Select the city where the property is located") | |
| sqft = st.number_input( | |
| "Area (sq ft)", | |
| min_value=100.0, | |
| max_value=50000.0, | |
| step=50.0, | |
| help="Enter the total built-up area in square feet", | |
| ) | |
| predict_clicked = st.button("π Predict Price") | |
| card_close() | |
| # ββ RESULT βββββββββββββββββββββββββββββββ | |
| if predict_clicked: | |
| if sqft < 100: | |
| st.error("β Please enter a valid area (minimum 100 sq ft).") | |
| else: | |
| try: | |
| with st.spinner("Calculating estimateβ¦"): | |
| prediction = model.predict([[sqft]])[0] | |
| price = round(prediction, 2) | |
| price_sqft = round(price / sqft, 2) | |
| card_open() | |
| st.markdown(f""" | |
| <div class="price-result"> | |
| <div class="price-label">π° Predicted Market Price</div> | |
| <div class="price-value">βΉ{price:,.2f}</div> | |
| <div class="price-sub">Based on current market trends Β· {city}</div> | |
| </div> | |
| <div style="margin-top:1rem;"> | |
| <div class="breakdown-row"> | |
| <span>π City</span> | |
| <strong>{city}</strong> | |
| </div> | |
| <div class="breakdown-row"> | |
| <span>π Area</span> | |
| <strong>{sqft:,.0f} sq ft</strong> | |
| </div> | |
| <div class="breakdown-row"> | |
| <span>π Price per sq ft</span> | |
| <strong>βΉ{price_sqft:,.2f}</strong> | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| card_close() | |
| except Exception as e: | |
| st.error(f"β Prediction error: {e}") | |
| # ββ DATASET PREVIEW ββββββββββββββββββββββ | |
| st.markdown("<br>", unsafe_allow_html=True) | |
| card_open() | |
| st.markdown(""" | |
| <div style="margin-bottom:1rem;"> | |
| <div style="font-family:'Syne',sans-serif; font-weight:700; font-size:1.1rem; | |
| color:#fff; margin-bottom:.3rem;">π Dataset Preview</div> | |
| <div style="font-size:.85rem; color:#64748b;">Showing first 10 rows of the training data</div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| st.dataframe(df.head(10), use_container_width=True) | |
| card_close() | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| # ROUTING | |
| # ββββββββββββββββββββββββββββββββββββββββββββββ | |
| if st.session_state.logged_in: | |
| dashboard() | |
| else: | |
| with st.sidebar: | |
| st.markdown(""" | |
| <div style="text-align:center; padding:.5rem 0 1rem;"> | |
| <div style="font-size:2rem;">π </div> | |
| <div style="font-family:'Syne',sans-serif; font-weight:800; | |
| background:linear-gradient(135deg,#00f0ff,#3b82f6); | |
| -webkit-background-clip:text; -webkit-text-fill-color:transparent; | |
| font-size:1.1rem; margin-top:.3rem;"> | |
| House Price AI | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| choice = st.selectbox("", ["Login", "Sign Up"], label_visibility="collapsed") | |
| if choice == "Login": | |
| login() | |
| else: | |
| signup() |