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()