import pandas as pd
import numpy as np
import streamlit as st
import pickle as pk
import os
import datetime
# --- Path Handling ---
script_dir = os.path.dirname(os.path.abspath(__file__))
models_dir = os.path.join(script_dir, "Models")
image_dir = os.path.join(script_dir, "Implementation and work done")
# --- Load Models ---
rf_model = pk.load(open(os.path.join(models_dir, 'random_forest_model.pkl'), 'rb'))
xgb_model = pk.load(open(os.path.join(models_dir, 'XGBoost_model.pkl'), 'rb'))
# --- Streamlit App Config ---
st.set_page_config(page_title="Car Price Predictor", layout="centered")
st.title("🚗 Used Car Price Predictor")
st.markdown("<span style='color:#FFD700;'>Estimate the fair market value of your
used car using two ML models.</span>", unsafe_allow_html=True)
# --- Display Car Image ---
image_path = os.path.join(image_dir, "Caryellow.jpeg")
if os.path.exists(image_path):
# Fixed deprecated parameter: use_column_width -> use_container_width
st.image(image_path, use_container_width=True)
else:
st.warning("Car image not found. Please check the file path.")
# Brand Mapping
brand_mapping = {
'Maruti': 1, 'Skoda': 2, 'Honda': 3, 'Hyundai': 4, 'Toyota': 5,
'Ford': 6, 'Renault': 7, 'Mahindra': 8, 'Tata': 9, 'Chevrolet': 10,
'Datsun': 11, 'Jeep': 12, 'Mercedes-Benz': 13, 'Mitsubishi': 14, 'Audi': 15,
'Volkswagen': 16, 'BMW': 17, 'Nissan': 18, 'Lexus': 19, 'Jaguar': 20,
'Land': 21, 'MG': 22, 'Volvo': 23, 'Daewoo': 24, 'Kia': 25, 'Fiat': 26,
'Force': 27, 'Ambassador': 28, 'Ashok': 29, 'Isuzu': 30, 'Opel': 31
}
fuel_mapping = {'Diesel': 1, 'Petrol': 2, 'LPG': 3, 'CNG': 4}
seller_mapping = {'Individual': 1, 'Dealer': 2, 'Trustmark Dealer': 3}
trans_mapping = {'Manual': 1, 'Automatic': 2}
owner_mapping = {
'First Owner': 1, 'Second Owner': 2, 'Third Owner': 3,
'Fourth & Above Owner': 4, 'Test Drive Car': 5
}
# Comprehensive City Adjustment Factors for all India
city_factor = {
# Tier 1 Metros
"Mumbai": 1.08,
"Delhi": 1.07,
"Bangalore": 1.06,
"Hyderabad": 1.05,
"Chennai": 1.05,
"Kolkata": 1.04,
"Pune": 1.04,
"Ahmedabad": 1.03,
# Tier 2 Cities
"Jaipur": 1.02,
"Lucknow": 1.02,
"Chandigarh": 1.03,
"Indore": 1.02,
"Bhopal": 1.01,
"Coimbatore": 1.01,
"Kochi": 1.01,
"Visakhapatnam": 1.01,
"Bhubaneswar": 1.01,
"Guwahati": 1.00,
# Tier 3 Cities
"Nagpur": 1.00,
"Surat": 1.00,
"Vadodara": 1.00,
"Patna": 0.99,
"Ranchi": 0.99,
"Raipur": 0.99,
"Dehradun": 1.00,
"Mysore": 1.00,
"Mangalore": 1.00,
"Thiruvananthapuram": 1.00,
"Tiruchirappalli": 1.00,
"Madurai": 1.00,
"Vijayawada": 1.00,
"Warangal": 1.00,
"Jamshedpur": 0.99,
"Bhilai": 0.99,
# Regional Defaults
"North India": 0.98,
"South India": 0.99,
"East India": 0.97,
"West India": 0.99,
"Central India": 0.97,
"Northeast India": 0.96,
"Other": 1.00
}
# Grouped city options for better UI organization
city_options = [
("Major Metros", [
"Mumbai", "Delhi", "Bangalore", "Hyderabad",
"Chennai", "Kolkata", "Pune", "Ahmedabad"
]),
("Tier 2 Cities", [
"Jaipur", "Lucknow", "Chandigarh", "Indore",
"Bhopal", "Coimbatore", "Kochi", "Visakhapatnam",
"Bhubaneswar", "Guwahati"
]),
("Tier 3 Cities", [
"Nagpur", "Surat", "Vadodara", "Patna",
"Ranchi", "Raipur", "Dehradun", "Mysore",
"Mangalore", "Thiruvananthapuram", "Tiruchirappalli",
"Madurai", "Vijayawada", "Warangal",
"Jamshedpur", "Bhilai"
]),
("Regions", [
"North India", "South India", "East India",
"West India", "Central India", "Northeast India"
]),
("Other", ["Other"])
]
# Flattened list for selectbox
flat_city_options = []
for category, cities in city_options:
if category != "Other": # Don't add category label for "Other"
flat_city_options.append(f"--- {category} ---")
flat_city_options.extend(cities)
# ======================
# Streamlit UI
with st.form("car_form"):
# Add car model name input
car_model_name = st.text_input("Car Model Name", placeholder="e.g., Hyundai
Grand i10 Sportz 1.2 Kappa VTVT")
col1, col2 = st.columns(2)
with col1:
brand = st.selectbox("Select Brand", list(brand_mapping.keys()))
year = st.number_input("Manufacturing Year", min_value=1990,
max_value=2025, value=2015)
km_driven = st.number_input("Kilometers Driven", min_value=0, value=30000,
step=500)
fuel = st.selectbox("Fuel Type", list(fuel_mapping.keys()))
seller_type = st.selectbox("Seller Type", list(seller_mapping.keys()))
transmission = st.selectbox("Transmission", list(trans_mapping.keys()))
# City selection with grouped options
city = st.selectbox("Select City", flat_city_options, index=1) # Default
to Delhi
with col2:
owner = st.selectbox("Ownership Status", list(owner_mapping.keys()))
mileage = st.number_input("Mileage (kmpl)", min_value=0.0, value=18.0,
step=0.5)
engine = st.number_input("Engine Capacity (CC)", min_value=500.0,
value=1200.0, step=50.0)
max_power = st.number_input("Max Power (bhp)", min_value=20.0, value=90.0,
step=1.0)
seats = st.number_input("Number of Seats", min_value=2, max_value=10,
value=5)
submitted = st.form_submit_button("🔍 Predict Final Combined Price")
# --- Predict Button ---
if submitted:
try:
# Skip if city is a separator
if city.startswith("---"):
st.error("Please select a specific city from the list")
st.stop()
# === Preprocessing ===
current_year = datetime.datetime.now().year
age = current_year - year
log_km = np.log1p(km_driven)
# Prepare dataframe with ALL expected features including 'index'
input_data = [
0, # Index value (default)
brand_mapping[brand], # name
fuel_mapping[fuel],
seller_mapping[seller_type],
trans_mapping[transmission],
owner_mapping[owner],
mileage,
engine,
max_power,
seats,
brand_mapping[brand], # brand
age,
log_km
]
columns = ['index', 'name', 'fuel', 'seller_type', 'transmission', 'owner',
'mileage', 'engine', 'max_power', 'seats', 'brand', 'age',
'log_km_driven']
input_df = pd.DataFrame([input_data], columns=columns)
# Predictions from both models
rf_pred = rf_model.predict(input_df)[0]
xgb_pred = xgb_model.predict(input_df)[0]
# Ensemble prediction
final_price = (0.5 * rf_pred) + (0.5 * xgb_pred)
# Reverse log transform
final_price_actual = np.expm1(final_price)
# Apply city adjustment
adjusted_price = final_price_actual * city_factor[city]
# Fair and Good Condition Prices
fair_price = adjusted_price * 0.9
good_price = adjusted_price * 1.05
# Format prices with commas
def format_price(price):
return f"₹ {price:,.0f}"
# Create display name with model variant
display_name = f"{brand} {car_model_name}" if car_model_name else brand
# --- Styled Output ---
st.markdown(f"""
<div style="background-color:#ffffff; padding:20px; border-radius:12px;
border:1px solid #ddd; box-shadow:0px 2px 6px rgba(0,0,0,0.1);">
<h3 style="color:#0A81AB; margin-bottom:5px;">🚘 {display_name}</h3>
<p style="margin:0; color:#555;">
<b>Fuel:</b> {fuel} |
<b>Transmission:</b> {transmission} |
<b>Owner:</b> {owner} <br>
<b>KMs Driven:</b> {km_driven:,} |
<b>Seats:</b> {seats}
</p>
<hr style="margin:10px 0;">
<h4 style="color:#444;">📍 City: {city}</h4>
<div style="margin-top:15px;">
<p style="font-size:18px; color:#444; margin:5px 0;">
<b style="color:#ff6f00;">Fair Condition:</b>
{format_price(fair_price)}
</p>
<p style="font-size:18px; color:#444; margin:5px 0;">
<b style="color:#2e7d32;">Good Condition:</b>
{format_price(good_price)}
</p>
<div style="height:20px; background:linear-gradient(to right,
#2e7d32, #fbbc05, #d32f2f); border-radius:10px; margin-top:10px;"></div>
<p style="font-size:14px; color:#777; text-align:center; margin-
top:5px;">
Price Range Indicator (Lower to Higher)
</p>
</div>
</div>
""", unsafe_allow_html=True)
except Exception as e:
st.error(f"Prediction Failed: {str(e)}")