|
|
""" |
|
|
VIN Decoder Streamlit App |
|
|
|
|
|
This app allows users to input a Vehicle Identification Number (VIN) and fetch vehicle |
|
|
information (year, make, model). The data is retrieved from the NHTSA (National Highway Traffic Safety |
|
|
Administration) VIN decoding API via the helper module `nhtsa_api_call.py`. |
|
|
Useful for car dealerships who need quick VIN lookups. |
|
|
|
|
|
Usage: |
|
|
streamlit run streamlit_vin_decoder.py |
|
|
|
|
|
Author: Sharmil Nanjappa |
|
|
Date: August 25, 2025 |
|
|
""" |
|
|
|
|
|
import streamlit as st |
|
|
import nhtsa_api_call |
|
|
import os |
|
|
import re |
|
|
import pandas as pd |
|
|
import matplotlib.pyplot as plt |
|
|
from collections import Counter |
|
|
|
|
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) |
|
|
logo_img_file = os.path.join(BASE_DIR, "logo_image.png") |
|
|
car_img_file = os.path.join(BASE_DIR, "car_image.png") |
|
|
TOP3 = 3 |
|
|
|
|
|
|
|
|
if "make_history" not in st.session_state: |
|
|
|
|
|
st.session_state.make_history = [] |
|
|
|
|
|
|
|
|
def track_make(make): |
|
|
""" |
|
|
Store the searched make in session state for pie chart stats. |
|
|
""" |
|
|
|
|
|
if make: |
|
|
|
|
|
st.session_state.make_history.append(make.title()) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def show_top_3_makes(): |
|
|
""" |
|
|
Display a pie chart of the top 3 most searched vehicle makes. |
|
|
|
|
|
if not st.session_state.make_history: |
|
|
st.warning("No vehicle makes have been searched yet.") |
|
|
return |
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
if not st.session_state.make_history: |
|
|
st.warning("No vehicle makes have been searched yet.") |
|
|
return |
|
|
|
|
|
|
|
|
counts = Counter(st.session_state.make_history) |
|
|
|
|
|
if len(counts) < TOP3: |
|
|
st.warning(f"Not enough data to display Top 3. Showing Top {len(counts)} instead.") |
|
|
|
|
|
|
|
|
top_n = counts.most_common(min(len(counts), TOP3)) |
|
|
|
|
|
labels = [item[0].upper() for item in top_n] |
|
|
sizes = [item[1] for item in top_n] |
|
|
colors = ['#4682B4', '#1E3F66', '#0B1F3A'][:len(labels)] |
|
|
with st.container(): |
|
|
|
|
|
st.markdown(""" |
|
|
<div style=" |
|
|
max-width: 700px; |
|
|
margin: 0 auto; |
|
|
padding: 12px 24px; |
|
|
border: 1px solid #ccc; |
|
|
border-radius: 10px; |
|
|
background-color: #f9f9f9; |
|
|
text-align: center; |
|
|
font-size: 16px; |
|
|
font-weight: 500; |
|
|
"> |
|
|
Pie chart displaying the Top 3 Vehicles<br> |
|
|
searched based on their Make |
|
|
</div> |
|
|
""", unsafe_allow_html=True) |
|
|
|
|
|
fig, ax = plt.subplots(figsize=(3,3), dpi=150) |
|
|
|
|
|
|
|
|
wedges, texts, autotexts = ax.pie( |
|
|
sizes, |
|
|
labels=labels, |
|
|
colors=colors, |
|
|
autopct='%1.1f%%', |
|
|
startangle=90, |
|
|
wedgeprops={'edgecolor': 'white', 'linewidth': 1} |
|
|
) |
|
|
|
|
|
ax.axis('equal') |
|
|
|
|
|
|
|
|
for text in texts: |
|
|
text.set_fontsize(5) |
|
|
text.set_color('#000') |
|
|
text.set_fontweight('semibold') |
|
|
|
|
|
for autotext in autotexts: |
|
|
autotext.set_fontsize(5) |
|
|
autotext.set_color('#fff') |
|
|
|
|
|
st.pyplot(fig) |
|
|
st.markdown("</div>", unsafe_allow_html=True) |
|
|
|
|
|
def get_vin(vin): |
|
|
""" |
|
|
Decodes the VIN and displays model,make, model year. |
|
|
Validates VIN format and displays vehicle details or error message. |
|
|
""" |
|
|
status_area = st.empty() |
|
|
col1, col2 = st.columns([1, 1]) |
|
|
|
|
|
if len(vin) != 17: |
|
|
status_area.error(f"VIN must be exactly 17 characters long.") |
|
|
return |
|
|
elif not re.match(r'^[A-HJ-NPR-Z0-9]{17}$', vin): |
|
|
status_area.error(f"VIN must be alpha-numeric and cannot include letters I, O, Q.") |
|
|
return |
|
|
else: |
|
|
status_area.info("Decoding VIN...") |
|
|
|
|
|
try: |
|
|
year, make, model = nhtsa_api_call.get_vehicle_info(vin) |
|
|
|
|
|
if not all([year, make, model]) or any([v is None for v in [year, make, model]]): |
|
|
status_area.warning(f"Incomplete vehicle data returned. Please verify the VIN and try again.") |
|
|
else: |
|
|
status_area.success("VIN decoded successfully!") |
|
|
|
|
|
track_make(make) |
|
|
with col1: |
|
|
st.image(car_img_file, use_container_width=True) |
|
|
|
|
|
with col2: |
|
|
st.write(f"Below are the vehicle details :") |
|
|
st.write("🔍 Vehicle Information") |
|
|
st.write(f"**Make:** {make}") |
|
|
st.write(f"**Model:** {model}") |
|
|
st.write(f"**Model Year:** {year}") |
|
|
|
|
|
except Exception as e: |
|
|
status_area.error(f"An error occurred while decoding the VIN: {e}") |
|
|
|
|
|
def main(): |
|
|
""" |
|
|
Sets Streamlitcomponents for the page layout, handles user input, and calls get_vin function. |
|
|
""" |
|
|
|
|
|
col1, col2 = st.columns([1, 2]) |
|
|
with col1: |
|
|
st.image(logo_img_file, width=180) |
|
|
with col2: |
|
|
st.markdown(""" |
|
|
<div style='text-align: left; margin-top: 30px;'> |
|
|
<h1 style='font-size: 38px;'>Vehicle VIN Decoder</h1> |
|
|
</div> |
|
|
""", unsafe_allow_html=True) |
|
|
st.write("*" * 50) |
|
|
|
|
|
st.markdown("<h5 style='text-align: center;'>Welcome to the Car Dealership VIN Lookup!</h5>", unsafe_allow_html=True) |
|
|
|
|
|
|
|
|
with st.expander("ℹ️ About this app"): |
|
|
st.write("This app is designed to help car dealerships and automotive professionals effortlessly decode Vehicle Identification Numbers (VINs) to retrieve key vehicle details such as model,make and model year. By simply entering a 17-character VIN, users can access verified vehicle information. The data is fetched in real-time from the National Highway Traffic Safety Administration (NHTSA). Whether you're validating trade-ins, checking vehicle specs, or streamlining inventory intake, this tool delivers quick and reliable insights.") |
|
|
|
|
|
|
|
|
|
|
|
st.markdown("Enter a **17-character VIN** below to decode the vehicle info.") |
|
|
|
|
|
vin = st.text_input("Enter VIN:", max_chars=17).strip().upper() |
|
|
if st.button("Decode VIN", use_container_width=True): |
|
|
if vin: |
|
|
get_vin(vin) |
|
|
else: |
|
|
st.error(f"❌ Please enter a VIN before fetching the vehicle information.") |
|
|
|
|
|
|
|
|
st.markdown("---") |
|
|
if st.button("Top 3 Makes Searched", use_container_width=True): |
|
|
show_top_3_makes() |
|
|
|
|
|
st.markdown("___") |
|
|
st.markdown("<p style='text-align: center; font-size: 14px;'>© 2025 Car Dealership VIN Lookup", unsafe_allow_html=True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
main() |
|
|
|