SharmilNK commited on
Commit
239f1a7
·
1 Parent(s): 6c46b62

Initial commit of Streamlit app for VIN decoder

Browse files
Files changed (1) hide show
  1. streamlit_app.py +191 -0
streamlit_app.py ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ VIN Decoder Streamlit App
3
+
4
+ This app allows users to input a Vehicle Identification Number (VIN) and fetch vehicle
5
+ information (year, make, model). The data is retrieved from the NHTSA (National Highway Traffic Safety
6
+ Administration) VIN decoding API via the helper module `nhtsa_api_call.py`.
7
+ Useful for car dealerships who need quick VIN lookups.
8
+
9
+ Usage:
10
+ streamlit run streamlit_vin_decoder.py
11
+
12
+ Author: Sharmil Nanjappa
13
+ Date: August 25, 2025
14
+ """
15
+
16
+ import streamlit as st # Import the Streamlit library for creating the web app
17
+ import nhtsa_api_call # Import the API call function from external file
18
+ import os
19
+ import re
20
+ import pandas as pd
21
+ import matplotlib.pyplot as plt
22
+ from collections import Counter
23
+
24
+ BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # Gets the current directory
25
+ logo_img_file = os.path.join(BASE_DIR, "logo_image.png")
26
+ car_img_file = os.path.join(BASE_DIR, "car_image.png")
27
+
28
+ # Check if the 'make_history' key is already in Streamlit's session state
29
+ if "make_history" not in st.session_state:
30
+ # If not, initialize it as an empty list to store searched vehicle makes
31
+ st.session_state.make_history = []
32
+
33
+ # Define a function to track the vehicle make each time a VIN is decoded
34
+ def track_make(make):
35
+ """
36
+ Store the searched make in session state for pie chart stats.
37
+ """
38
+ # Proceed only if a valid make value is provided
39
+ if make:
40
+ # Capitalize and append the make to the session history list
41
+ st.session_state.make_history.append(make.title())
42
+ # Optional: Display the current list of searched makes in the sidebar for debugging
43
+ #st.sidebar.write("Debug – History:", st.session_state.make_history)
44
+
45
+
46
+ def show_top_3_makes():
47
+ """
48
+ Display a pie chart of the top 3 most searched vehicle makes.
49
+
50
+ if not st.session_state.make_history:
51
+ st.warning("No vehicle makes have been searched yet.")
52
+ return
53
+ """
54
+ counts = Counter(st.session_state.make_history)
55
+ top_3 = counts.most_common(3) # A tuple to hold values: (make_name, count)
56
+
57
+
58
+ labels = [item[0].upper() for item in top_3] # Label for the vehicle make, displayed in upper case for each slice of the pie chart
59
+ sizes = [item[1] for item in top_3] # Count of each make in the Top3. Used to determine how large each slice of the pie chart is.
60
+ colors = ['#4682B4', '#1E3F66', '#0B1F3A'] # Blue, dark blue, night blue : colors of pie chart slices
61
+ with st.container():
62
+
63
+ st.markdown("""
64
+ <div style="
65
+ max-width: 700px;
66
+ margin: 0 auto;
67
+ padding: 12px 24px;
68
+ border: 1px solid #ccc;
69
+ border-radius: 10px;
70
+ background-color: #f9f9f9;
71
+ text-align: center;
72
+ font-size: 16px;
73
+ font-weight: 500;
74
+ ">
75
+ Pie chart displaying the Top 3 Vehicles<br>
76
+ searched based on their Make
77
+ </div>
78
+ """, unsafe_allow_html=True)
79
+
80
+ fig, ax = plt.subplots(figsize=(3,3), dpi=150)
81
+
82
+ # Draw pie chart with borders and percentage labels
83
+ wedges, texts, autotexts = ax.pie(
84
+ sizes,
85
+ labels=labels,
86
+ colors=colors,
87
+ autopct='%1.1f%%',
88
+ startangle=90, # autopct shows % and startangle starts the first slice from the top
89
+ wedgeprops={'edgecolor': 'white', 'linewidth': 1}
90
+ )
91
+
92
+ ax.axis('equal') # Forces the chart to be a perfect circle
93
+
94
+ # Style text and labels
95
+ for text in texts: #The labels of each pie slice
96
+ text.set_fontsize(5)
97
+ text.set_color('#000') # text color: Black
98
+ text.set_fontweight('semibold')
99
+
100
+ for autotext in autotexts: #The percentages shown on each slice
101
+ autotext.set_fontsize(5)
102
+ autotext.set_color('#fff') # text color: White
103
+
104
+ st.pyplot(fig)
105
+ st.markdown("</div>", unsafe_allow_html=True)
106
+
107
+ def get_vin(vin):
108
+ """
109
+ Decodes the VIN and displays model,make, model year.
110
+ Validates VIN format and displays vehicle details or error message.
111
+ """
112
+ status_area = st.empty()
113
+ col1, col2 = st.columns([1, 1])
114
+
115
+ if len(vin) != 17:
116
+ status_area.error(f"VIN must be exactly 17 characters long.")
117
+ return
118
+ elif not re.match(r'^[A-HJ-NPR-Z0-9]{17}$', vin):
119
+ status_area.error(f"VIN must be alpha-numeric and cannot include letters I, O, Q.")
120
+ return
121
+ else:
122
+ status_area.info("Decoding VIN...")
123
+
124
+ try:
125
+ year, make, model = nhtsa_api_call.get_vehicle_info(vin)
126
+
127
+ if not all([year, make, model]) or any([v is None for v in [year, make, model]]):
128
+ status_area.warning(f"Incomplete vehicle data returned. Please verify the VIN and try again.")
129
+ else:
130
+ status_area.success("VIN decoded successfully!")
131
+
132
+ track_make(make)
133
+ with col1:
134
+ st.image(car_img_file, use_container_width=True)
135
+
136
+ with col2:
137
+ st.write(f"Below are the vehicle details :")
138
+ st.write("🔍 Vehicle Information")
139
+ st.write(f"**Make:** {make}")
140
+ st.write(f"**Model:** {model}")
141
+ st.write(f"**Model Year:** {year}")
142
+
143
+ except Exception as e:
144
+ status_area.error(f"An error occurred while decoding the VIN: {e}")
145
+
146
+ def main():
147
+ """
148
+ Sets Streamlitcomponents for the page layout, handles user input, and calls get_vin function.
149
+ """
150
+
151
+ col1, col2 = st.columns([1, 2])
152
+ with col1:
153
+ st.image(logo_img_file, width=180)
154
+ with col2:
155
+ st.markdown("""
156
+ <div style='text-align: left; margin-top: 30px;'>
157
+ <h1 style='font-size: 38px;'>Vehicle VIN Decoder</h1>
158
+ </div>
159
+ """, unsafe_allow_html=True)
160
+ st.write("*" * 50)
161
+
162
+ st.markdown("<h5 style='text-align: center;'>Welcome to the Car Dealership VIN Lookup!</h5>", unsafe_allow_html=True)
163
+
164
+
165
+ with st.expander("ℹ️ About this app"):
166
+ 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.")
167
+
168
+
169
+
170
+ st.markdown("Enter a **17-character VIN** below to decode the vehicle info.")
171
+
172
+ vin = st.text_input("Enter VIN:", max_chars=17).strip().upper()
173
+ if st.button("Decode VIN", use_container_width=True):
174
+ if vin:
175
+ get_vin(vin)
176
+ else:
177
+ st.error(f"❌ Please enter a VIN before fetching the vehicle information.")
178
+
179
+ # Show top 3 searched makes
180
+ st.markdown("---")
181
+ if st.button("Top 3 Makes Searched", use_container_width=True):
182
+ show_top_3_makes()
183
+
184
+ st.markdown("___")
185
+ st.markdown("<p style='text-align: center; font-size: 14px;'>© 2025 Car Dealership VIN Lookup", unsafe_allow_html=True) #Footer for the webpage
186
+
187
+
188
+
189
+
190
+ if __name__ == "__main__":
191
+ main()