File size: 8,030 Bytes
5e43d07 bb93b26 5e43d07 bb93b26 5e43d07 bb93b26 5e43d07 bb93b26 5e43d07 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
"""
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 the Streamlit library for creating the web app
import nhtsa_api_call # Import the API call function from external file
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__)) # Gets the current directory
logo_img_file = os.path.join(BASE_DIR, "logo_image.png")
car_img_file = os.path.join(BASE_DIR, "car_image.png")
TOP3 = 3 # Define top N makes to display
# Check if the 'make_history' key is already in Streamlit's session state
if "make_history" not in st.session_state:
# If not, initialize it as an empty list to store searched vehicle makes
st.session_state.make_history = []
# Define a function to track the vehicle make each time a VIN is decoded
def track_make(make):
"""
Store the searched make in session state for pie chart stats.
"""
# Proceed only if a valid make value is provided
if make:
# Capitalize and append the make to the session history list
st.session_state.make_history.append(make.title())
# Optional: Display the current list of searched makes in the sidebar for debugging
#st.sidebar.write("Debug – History:", st.session_state.make_history)
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
# Count how many times each make was searched
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.")
# Get the top N (3 or fewer)
top_n = counts.most_common(min(len(counts), TOP3))
labels = [item[0].upper() for item in top_n] # Label for the vehicle make, displayed in upper case for each slice of the pie chart
sizes = [item[1] for item in top_n] # Count of each make in the Top3. Used to determine how large each slice of the pie chart is.
colors = ['#4682B4', '#1E3F66', '#0B1F3A'][:len(labels)] #[colors of pie chart slices][match slice count]
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)
# Draw pie chart with borders and percentage labels
wedges, texts, autotexts = ax.pie(
sizes,
labels=labels,
colors=colors,
autopct='%1.1f%%',
startangle=90, # autopct shows % and startangle starts the first slice from the top
wedgeprops={'edgecolor': 'white', 'linewidth': 1}
)
ax.axis('equal') # Forces the chart to be a perfect circle
# Style text and labels
for text in texts: #The labels of each pie slice
text.set_fontsize(5)
text.set_color('#000') # text color: Black
text.set_fontweight('semibold')
for autotext in autotexts: #The percentages shown on each slice
autotext.set_fontsize(5)
autotext.set_color('#fff') # text color: White
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.")
# Show top 3 searched makes
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) #Footer for the webpage
if __name__ == "__main__":
main()
|