Sarvamangalak commited on
Commit
2ac0173
Β·
verified Β·
1 Parent(s): e8f7801

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +1181 -0
app.py ADDED
@@ -0,0 +1,1181 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Author: Sarvamangala Kokatanur
2
+
3
+ # ============================================================
4
+
5
+ # SMART TRAFFIC & EV ANALYTICS SYSTEM
6
+
7
+ # WITH AGENTIC AI DYNAMIC ANALYTICS DASHBOARD
8
+
9
+ # ============================================================
10
+
11
+ import gradio as gr
12
+ import torch
13
+ import numpy as np
14
+ import cv2
15
+ import sqlite3
16
+ import pandas as pd
17
+ import matplotlib.pyplot as plt
18
+
19
+ from datetime import datetime, timedelta
20
+ from PIL import Image, ImageDraw
21
+
22
+ from transformers import (
23
+ YolosImageProcessor,
24
+ YolosForObjectDetection
25
+ )
26
+
27
+ # ============================================================
28
+
29
+ # LOAD LICENSE PLATE DETECTION MODEL
30
+
31
+ # ============================================================
32
+
33
+ processor = YolosImageProcessor.from_pretrained(
34
+ "nickmuchi/yolos-small-finetuned-license-plate-detection"
35
+ )
36
+
37
+ model = YolosForObjectDetection.from_pretrained(
38
+ "nickmuchi/yolos-small-finetuned-license-plate-detection"
39
+ )
40
+
41
+ model.eval()
42
+
43
+ # ============================================================
44
+
45
+ # DATABASE
46
+
47
+ # ============================================================
48
+
49
+ conn = sqlite3.connect(
50
+ "vehicles.db",
51
+ check_same_thread=False
52
+ )
53
+
54
+ cursor = conn.cursor()
55
+
56
+ cursor.execute("""
57
+ CREATE TABLE IF NOT EXISTS vehicles(
58
+
59
+ ```
60
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
61
+
62
+ timestamp TEXT,
63
+
64
+ license_plate TEXT,
65
+
66
+ vehicle_status TEXT,
67
+
68
+ discount INTEGER
69
+ ```
70
+
71
+ )
72
+ """)
73
+
74
+ conn.commit()
75
+
76
+ # ============================================================
77
+
78
+ # PLATE COLOR CLASSIFIER
79
+
80
+ # ============================================================
81
+
82
+ def classify_plate_color(plate_img):
83
+
84
+ ```
85
+ img = np.array(plate_img)
86
+
87
+ # Convert RGB to HSV
88
+ hsv = cv2.cvtColor(
89
+ img,
90
+ cv2.COLOR_RGB2HSV
91
+ )
92
+
93
+ h, w = hsv.shape[:2]
94
+
95
+ # Inspect left portion of the plate
96
+ left = hsv[:, :int(w * 0.2)]
97
+
98
+ # Detect green color
99
+ green = cv2.inRange(
100
+ left,
101
+ (35, 40, 40),
102
+ (90, 255, 255)
103
+ )
104
+
105
+ green_ratio = (
106
+ np.count_nonzero(green)
107
+ / green.size
108
+ )
109
+
110
+ # EV classification
111
+ if green_ratio > 0.15:
112
+ return "EV"
113
+
114
+ return "Non-EV"
115
+ ```
116
+
117
+ # ============================================================
118
+
119
+ # DUPLICATE VEHICLE CHECK
120
+
121
+ # ============================================================
122
+
123
+ def is_duplicate_vehicle(plate_number):
124
+
125
+ ```
126
+ cursor.execute("""
127
+ SELECT timestamp
128
+ FROM vehicles
129
+ WHERE license_plate=?
130
+ ORDER BY id DESC
131
+ LIMIT 1
132
+ """, (plate_number,))
133
+
134
+ row = cursor.fetchone()
135
+
136
+ if row is None:
137
+ return False
138
+
139
+ last_time = datetime.strptime(
140
+ row[0],
141
+ "%Y-%m-%d %H:%M:%S"
142
+ )
143
+
144
+ if datetime.now() - last_time < timedelta(minutes=5):
145
+ return True
146
+
147
+ return False
148
+ ```
149
+
150
+ # ============================================================
151
+
152
+ # SAVE VEHICLE TO DATABASE
153
+
154
+ # ============================================================
155
+
156
+ def save_vehicle(plate, status):
157
+
158
+ ```
159
+ if status == "EV":
160
+ discount = 50
161
+ else:
162
+ discount = 0
163
+
164
+ if is_duplicate_vehicle(plate):
165
+ return "Duplicate"
166
+
167
+ current_time = datetime.now().strftime(
168
+ "%Y-%m-%d %H:%M:%S"
169
+ )
170
+
171
+ cursor.execute("""
172
+
173
+ INSERT INTO vehicles(
174
+
175
+ timestamp,
176
+ license_plate,
177
+ vehicle_status,
178
+ discount
179
+
180
+ )
181
+
182
+ VALUES (?, ?, ?, ?)
183
+
184
+ """, (
185
+ current_time,
186
+ plate,
187
+ status,
188
+ discount
189
+ ))
190
+
191
+ conn.commit()
192
+
193
+ return "Saved"
194
+ ```
195
+
196
+ # ============================================================
197
+
198
+ # GET STATIC DASHBOARD
199
+
200
+ # ============================================================
201
+
202
+ def get_dashboard():
203
+
204
+ ```
205
+ df = pd.read_sql(
206
+ "SELECT * FROM vehicles",
207
+ conn
208
+ )
209
+
210
+ fig, axs = plt.subplots(
211
+ 2,
212
+ 2,
213
+ figsize=(10, 7)
214
+ )
215
+
216
+ if df.empty:
217
+
218
+ for ax in axs.flatten():
219
+
220
+ ax.text(
221
+ 0.5,
222
+ 0.5,
223
+ "No Data Available",
224
+ ha="center",
225
+ va="center",
226
+ fontsize=12
227
+ )
228
+
229
+ ax.axis("off")
230
+
231
+ plt.tight_layout()
232
+
233
+ return fig
234
+
235
+ # --------------------------------------------------------
236
+ # EV VS NON-EV
237
+ # --------------------------------------------------------
238
+
239
+ status_counts = (
240
+ df["vehicle_status"]
241
+ .value_counts()
242
+ )
243
+
244
+ axs[0, 0].bar(
245
+ status_counts.index,
246
+ status_counts.values
247
+ )
248
+
249
+ axs[0, 0].set_title(
250
+ "EV vs Non-EV Vehicles"
251
+ )
252
+
253
+ axs[0, 0].set_ylabel(
254
+ "Number of Vehicles"
255
+ )
256
+
257
+
258
+ # --------------------------------------------------------
259
+ # PIE CHART
260
+ # --------------------------------------------------------
261
+
262
+ axs[0, 1].pie(
263
+ status_counts.values,
264
+ labels=status_counts.index,
265
+ autopct="%1.1f%%"
266
+ )
267
+
268
+ axs[0, 1].set_title(
269
+ "Vehicle Distribution"
270
+ )
271
+
272
+
273
+ # --------------------------------------------------------
274
+ # DISCOUNT
275
+ # --------------------------------------------------------
276
+
277
+ total_discount = df["discount"].sum()
278
+
279
+ axs[1, 0].bar(
280
+ ["Total Discount"],
281
+ [total_discount]
282
+ )
283
+
284
+ axs[1, 0].set_title(
285
+ "EV Discount Provided"
286
+ )
287
+
288
+ axs[1, 0].set_ylabel(
289
+ "Amount (β‚Ή)"
290
+ )
291
+
292
+
293
+ # --------------------------------------------------------
294
+ # REPORT
295
+ # --------------------------------------------------------
296
+
297
+ axs[1, 1].axis("off")
298
+
299
+ ev_count = len(
300
+ df[
301
+ df["vehicle_status"] == "EV"
302
+ ]
303
+ )
304
+
305
+ non_ev_count = len(
306
+ df[
307
+ df["vehicle_status"] == "Non-EV"
308
+ ]
309
+ )
310
+
311
+ report = (
312
+ "TRAFFIC ANALYTICS REPORT\n\n"
313
+ f"Total Vehicles: {len(df)}\n\n"
314
+ f"EV Vehicles: {ev_count}\n\n"
315
+ f"Non-EV Vehicles: {non_ev_count}\n\n"
316
+ f"Total Discount: β‚Ή{total_discount}"
317
+ )
318
+
319
+ axs[1, 1].text(
320
+ 0.05,
321
+ 0.95,
322
+ report,
323
+ fontsize=11,
324
+ va="top"
325
+ )
326
+
327
+ plt.tight_layout()
328
+
329
+ plt.close(fig)
330
+
331
+ return fig
332
+ ```
333
+
334
+ # ============================================================
335
+
336
+ # AGENTIC AI DATABASE TOOLS
337
+
338
+ # ============================================================
339
+
340
+ def get_vehicle_dataframe():
341
+
342
+ ```
343
+ df = pd.read_sql(
344
+ "SELECT * FROM vehicles",
345
+ conn
346
+ )
347
+
348
+ return df
349
+ ```
350
+
351
+ def get_total_vehicles():
352
+
353
+ ```
354
+ df = get_vehicle_dataframe()
355
+
356
+ return len(df)
357
+ ```
358
+
359
+ def get_ev_count():
360
+
361
+ ```
362
+ df = get_vehicle_dataframe()
363
+
364
+ return len(
365
+ df[
366
+ df["vehicle_status"] == "EV"
367
+ ]
368
+ )
369
+ ```
370
+
371
+ def get_non_ev_count():
372
+
373
+ ```
374
+ df = get_vehicle_dataframe()
375
+
376
+ return len(
377
+ df[
378
+ df["vehicle_status"] == "Non-EV"
379
+ ]
380
+ )
381
+ ```
382
+
383
+ def get_total_discount():
384
+
385
+ ```
386
+ df = get_vehicle_dataframe()
387
+
388
+ if df.empty:
389
+ return 0
390
+
391
+ return int(df["discount"].sum())
392
+ ```
393
+
394
+ def get_ev_percentage():
395
+
396
+ ```
397
+ total = get_total_vehicles()
398
+
399
+ ev_count = get_ev_count()
400
+
401
+ if total == 0:
402
+ return 0
403
+
404
+ return round(
405
+ (ev_count / total) * 100,
406
+ 2
407
+ )
408
+ ```
409
+
410
+ # ============================================================
411
+
412
+ # DYNAMIC GRAPH GENERATOR
413
+
414
+ # ============================================================
415
+
416
+ def generate_ev_graph():
417
+
418
+ ```
419
+ df = get_vehicle_dataframe()
420
+
421
+ fig, ax = plt.subplots(
422
+ figsize=(8, 5)
423
+ )
424
+
425
+ if df.empty:
426
+
427
+ ax.text(
428
+ 0.5,
429
+ 0.5,
430
+ "No Vehicle Data Available",
431
+ ha="center",
432
+ va="center",
433
+ fontsize=14
434
+ )
435
+
436
+ ax.axis("off")
437
+
438
+ return fig
439
+
440
+ counts = (
441
+ df["vehicle_status"]
442
+ .value_counts()
443
+ )
444
+
445
+ ax.bar(
446
+ counts.index,
447
+ counts.values
448
+ )
449
+
450
+ ax.set_title(
451
+ "EV vs Non-EV Vehicle Analysis"
452
+ )
453
+
454
+ ax.set_xlabel(
455
+ "Vehicle Type"
456
+ )
457
+
458
+ ax.set_ylabel(
459
+ "Number of Vehicles"
460
+ )
461
+
462
+ plt.tight_layout()
463
+
464
+ return fig
465
+ ```
466
+
467
+ def generate_discount_graph():
468
+
469
+ ```
470
+ df = get_vehicle_dataframe()
471
+
472
+ fig, ax = plt.subplots(
473
+ figsize=(8, 5)
474
+ )
475
+
476
+ if df.empty:
477
+
478
+ ax.text(
479
+ 0.5,
480
+ 0.5,
481
+ "No Discount Data Available",
482
+ ha="center",
483
+ va="center"
484
+ )
485
+
486
+ ax.axis("off")
487
+
488
+ return fig
489
+
490
+ discount_by_status = (
491
+ df.groupby("vehicle_status")["discount"]
492
+ .sum()
493
+ )
494
+
495
+ ax.bar(
496
+ discount_by_status.index,
497
+ discount_by_status.values
498
+ )
499
+
500
+ ax.set_title(
501
+ "Discount Analysis"
502
+ )
503
+
504
+ ax.set_xlabel(
505
+ "Vehicle Status"
506
+ )
507
+
508
+ ax.set_ylabel(
509
+ "Total Discount (β‚Ή)"
510
+ )
511
+
512
+ plt.tight_layout()
513
+
514
+ return fig
515
+ ```
516
+
517
+ # ============================================================
518
+
519
+ # AGENTIC AI QUERY ENGINE
520
+
521
+ # ============================================================
522
+
523
+ def traffic_ai_agent(user_query):
524
+
525
+ ```
526
+ if not user_query:
527
+ return (
528
+ "Please ask a question about the traffic data.",
529
+ None
530
+ )
531
+
532
+ query = user_query.lower()
533
+
534
+ total = get_total_vehicles()
535
+ ev_count = get_ev_count()
536
+ non_ev_count = get_non_ev_count()
537
+ discount = get_total_discount()
538
+ ev_percentage = get_ev_percentage()
539
+
540
+
541
+ # --------------------------------------------------------
542
+ # EV COUNT
543
+ # --------------------------------------------------------
544
+
545
+ if (
546
+ "how many ev" in query
547
+ or "number of ev" in query
548
+ or "ev count" in query
549
+ ):
550
+
551
+ response = (
552
+ f"πŸ€– AI Analysis:\n\n"
553
+ f"The system has detected "
554
+ f"{ev_count} EV vehicle(s).\n\n"
555
+ f"Total vehicles analysed: {total}."
556
+ )
557
+
558
+ return response, generate_ev_graph()
559
+
560
+
561
+ # --------------------------------------------------------
562
+ # NON-EV COUNT
563
+ # --------------------------------------------------------
564
+
565
+ elif (
566
+ "non ev" in query
567
+ or "non-ev" in query
568
+ ):
569
+
570
+ response = (
571
+ f"πŸ€– AI Analysis:\n\n"
572
+ f"Non-EV vehicles detected: "
573
+ f"{non_ev_count}.\n\n"
574
+ f"EV vehicles detected: "
575
+ f"{ev_count}."
576
+ )
577
+
578
+ return response, generate_ev_graph()
579
+
580
+
581
+ # --------------------------------------------------------
582
+ # TOTAL VEHICLES
583
+ # --------------------------------------------------------
584
+
585
+ elif (
586
+ "total vehicle" in query
587
+ or "how many vehicle" in query
588
+ or "traffic" in query
589
+ ):
590
+
591
+ response = (
592
+ f"πŸ€– AI Traffic Analysis:\n\n"
593
+ f"Total vehicles detected: "
594
+ f"{total}.\n\n"
595
+ f"EV vehicles: {ev_count}\n"
596
+ f"Non-EV vehicles: {non_ev_count}"
597
+ )
598
+
599
+ return response, generate_ev_graph()
600
+
601
+
602
+ # --------------------------------------------------------
603
+ # EV PERCENTAGE
604
+ # --------------------------------------------------------
605
+
606
+ elif (
607
+ "percentage" in query
608
+ or "percent" in query
609
+ ):
610
+
611
+ response = (
612
+ f"πŸ€– AI Analysis:\n\n"
613
+ f"EV Percentage: "
614
+ f"{ev_percentage}%\n\n"
615
+ f"This means {ev_count} out of "
616
+ f"{total} detected vehicles are EVs."
617
+ )
618
+
619
+ return response, generate_ev_graph()
620
+
621
+
622
+ # --------------------------------------------------------
623
+ # DISCOUNT
624
+ # --------------------------------------------------------
625
+
626
+ elif (
627
+ "discount" in query
628
+ or "incentive" in query
629
+ or "money" in query
630
+ ):
631
+
632
+ response = (
633
+ f"πŸ€– AI Discount Analysis:\n\n"
634
+ f"Total EV discount provided: "
635
+ f"β‚Ή{discount}.\n\n"
636
+ f"Number of EV vehicles: "
637
+ f"{ev_count}."
638
+ )
639
+
640
+ return response, generate_discount_graph()
641
+
642
+
643
+ # --------------------------------------------------------
644
+ # CO2 SAVINGS
645
+ # --------------------------------------------------------
646
+
647
+ elif (
648
+ "co2" in query
649
+ or "carbon" in query
650
+ or "environment" in query
651
+ ):
652
+
653
+ # Example estimation
654
+ co2_savings = ev_count * 2.3
655
+
656
+ response = (
657
+ f"🌱 AI Environmental Analysis:\n\n"
658
+ f"Based on the configured estimation model, "
659
+ f"{ev_count} EV vehicles could contribute to "
660
+ f"approximately {co2_savings:.2f} kg of "
661
+ f"potential COβ‚‚ savings.\n\n"
662
+ f"Note: This value is an estimated project "
663
+ f"metric and can be replaced with a validated "
664
+ f"emission calculation model."
665
+ )
666
+
667
+ return response, generate_ev_graph()
668
+
669
+
670
+ # --------------------------------------------------------
671
+ # SUMMARY
672
+ # --------------------------------------------------------
673
+
674
+ elif (
675
+ "summary" in query
676
+ or "report" in query
677
+ or "overall" in query
678
+ ):
679
+
680
+ response = (
681
+ f"πŸ€– SMART TRAFFIC AI SUMMARY\n\n"
682
+ f"πŸš— Total Vehicles: {total}\n\n"
683
+ f"⚑ EV Vehicles: {ev_count}\n\n"
684
+ f"πŸš™ Non-EV Vehicles: {non_ev_count}\n\n"
685
+ f"πŸ“Š EV Percentage: {ev_percentage}%\n\n"
686
+ f"πŸ’° Total Discount: β‚Ή{discount}"
687
+ )
688
+
689
+ return response, generate_ev_graph()
690
+
691
+
692
+ # --------------------------------------------------------
693
+ # DEFAULT RESPONSE
694
+ # --------------------------------------------------------
695
+
696
+ else:
697
+
698
+ response = (
699
+ "πŸ€– I am your Smart Traffic AI Assistant.\n\n"
700
+ "You can ask questions such as:\n\n"
701
+ "β€’ How many EV vehicles were detected?\n"
702
+ "β€’ How many Non-EV vehicles are there?\n"
703
+ "β€’ What is the total traffic?\n"
704
+ "β€’ What percentage of vehicles are EVs?\n"
705
+ "β€’ What is the total EV discount?\n"
706
+ "β€’ Give me a traffic summary.\n"
707
+ "β€’ Show COβ‚‚ savings."
708
+ )
709
+
710
+ return response, None
711
+ ```
712
+
713
+ # ============================================================
714
+
715
+ # MAIN VEHICLE PROCESSING PIPELINE
716
+
717
+ # ============================================================
718
+
719
+ def process_image(img):
720
+
721
+ ```
722
+ if img is None:
723
+
724
+ return (
725
+ None,
726
+ "Please upload an image.",
727
+ "0",
728
+ "0",
729
+ "β‚Ή0",
730
+ get_dashboard()
731
+ )
732
+
733
+
734
+ image = Image.fromarray(img)
735
+
736
+
737
+ # --------------------------------------------------------
738
+ # MODEL INPUT
739
+ # --------------------------------------------------------
740
+
741
+ inputs = processor(
742
+ images=image,
743
+ return_tensors="pt"
744
+ )
745
+
746
+ with torch.no_grad():
747
+
748
+ outputs = model(**inputs)
749
+
750
+
751
+ target_sizes = torch.tensor([
752
+ [
753
+ image.size[1],
754
+ image.size[0]
755
+ ]
756
+ ])
757
+
758
+
759
+ results = processor.post_process_object_detection(
760
+ outputs,
761
+ threshold=0.3,
762
+ target_sizes=target_sizes
763
+ )[0]
764
+
765
+
766
+ draw = ImageDraw.Draw(image)
767
+
768
+
769
+ ev_count = 0
770
+ non_ev_count = 0
771
+ discount_total = 0
772
+
773
+ output_text = ""
774
+
775
+
776
+ # --------------------------------------------------------
777
+ # NO DETECTION
778
+ # --------------------------------------------------------
779
+
780
+ if len(results["boxes"]) == 0:
781
+
782
+ return (
783
+ image,
784
+ "No license plate detected.",
785
+ "0",
786
+ "0",
787
+ "β‚Ή0",
788
+ get_dashboard()
789
+ )
790
+
791
+
792
+ # --------------------------------------------------------
793
+ # PROCESS DETECTED PLATES
794
+ # --------------------------------------------------------
795
+
796
+ for i, box in enumerate(results["boxes"]):
797
+
798
+ x1, y1, x2, y2 = map(
799
+ int,
800
+ box.tolist()
801
+ )
802
+
803
+
804
+ # Crop plate
805
+ plate = image.crop(
806
+ (x1, y1, x2, y2)
807
+ )
808
+
809
+
810
+ # Classify EV / Non-EV
811
+ status = classify_plate_color(
812
+ plate
813
+ )
814
+
815
+
816
+ # Temporary vehicle ID
817
+ plate_number = (
818
+ f"Vehicle_"
819
+ f"{datetime.now().strftime('%H%M%S%f')}"
820
+ f"_{i}"
821
+ )
822
+
823
+
824
+ saved = save_vehicle(
825
+ plate_number,
826
+ status
827
+ )
828
+
829
+
830
+ if saved == "Duplicate":
831
+ continue
832
+
833
+
834
+ # ----------------------------------------------------
835
+ # EV
836
+ # ----------------------------------------------------
837
+
838
+ if status == "EV":
839
+
840
+ ev_count += 1
841
+
842
+ discount = 50
843
+
844
+ discount_total += discount
845
+
846
+ color = "green"
847
+
848
+ label = (
849
+ f"EV | β‚Ή{discount}"
850
+ )
851
+
852
+
853
+ # ----------------------------------------------------
854
+ # NON-EV
855
+ # ----------------------------------------------------
856
+
857
+ else:
858
+
859
+ non_ev_count += 1
860
+
861
+ discount = 0
862
+
863
+ color = "red"
864
+
865
+ label = "Non-EV"
866
+
867
+
868
+ # Draw bounding box
869
+
870
+ draw.rectangle(
871
+ [x1, y1, x2, y2],
872
+ outline=color,
873
+ width=3
874
+ )
875
+
876
+
877
+ # Draw label
878
+
879
+ draw.text(
880
+ (
881
+ x1,
882
+ max(0, y1 - 25)
883
+ ),
884
+ label,
885
+ fill=color
886
+ )
887
+
888
+
889
+ output_text += (
890
+
891
+ f"Vehicle {i+1}\n"
892
+ f"Plate ID: {plate_number}\n"
893
+ f"Status: {status}\n"
894
+ f"Discount: β‚Ή{discount}\n\n"
895
+
896
+ )
897
+
898
+
899
+ dashboard = get_dashboard()
900
+
901
+
902
+ return (
903
+
904
+ image,
905
+
906
+ output_text,
907
+
908
+ str(ev_count),
909
+
910
+ str(non_ev_count),
911
+
912
+ f"β‚Ή{discount_total}",
913
+
914
+ dashboard
915
+
916
+ )
917
+ ```
918
+
919
+ # ============================================================
920
+
921
+ # GRADIO UI
922
+
923
+ # ============================================================
924
+
925
+ css = """
926
+
927
+ .gradio-container {
928
+ max-width: 98% !important;
929
+ margin: auto;
930
+ }
931
+
932
+ textarea {
933
+ font-size: 15px !important;
934
+ }
935
+
936
+ h1 {
937
+ text-align: center;
938
+ }
939
+
940
+ .block {
941
+ border-radius: 12px;
942
+ }
943
+
944
+ .gr-image {
945
+ min-height: 350px;
946
+ }
947
+
948
+ """
949
+
950
+ with gr.Blocks(css=css) as demo:
951
+
952
+ ```
953
+ # ========================================================
954
+ # TITLE
955
+ # ========================================================
956
+
957
+ gr.Markdown(
958
+ "# 🚦 Smart Traffic & EV Analytics System"
959
+ )
960
+
961
+ gr.Markdown(
962
+ "AI License Plate Detection β€’ EV Classification β€’ "
963
+ "Discount Calculation β€’ Agentic AI Analytics"
964
+ )
965
+
966
+
967
+ # ========================================================
968
+ # TAB 1 - VEHICLE DETECTION
969
+ # ========================================================
970
+
971
+ with gr.Tab("πŸš— Vehicle Detection"):
972
+
973
+
974
+ with gr.Row(equal_height=True):
975
+
976
+
977
+ # INPUT
978
+
979
+ with gr.Column(scale=1):
980
+
981
+ input_img = gr.Image(
982
+ type="numpy",
983
+ label="Input Vehicle Image",
984
+ sources=[
985
+ "upload",
986
+ "webcam"
987
+ ],
988
+ height=350
989
+ )
990
+
991
+
992
+ btn = gr.Button(
993
+ "πŸ” Scan Vehicle",
994
+ variant="primary",
995
+ size="lg"
996
+ )
997
+
998
+
999
+ # OUTPUT IMAGE
1000
+
1001
+ with gr.Column(scale=1):
1002
+
1003
+ output_img = gr.Image(
1004
+ label="Detection Result",
1005
+ height=350
1006
+ )
1007
+
1008
+
1009
+ # SUMMARY
1010
+
1011
+ with gr.Column(scale=1):
1012
+
1013
+ summary_box = gr.Textbox(
1014
+ label="Detection Summary",
1015
+ lines=16
1016
+ )
1017
+
1018
+
1019
+ # ====================================================
1020
+ # STATISTICS
1021
+ # ====================================================
1022
+
1023
+ with gr.Row():
1024
+
1025
+ ev_box = gr.Textbox(
1026
+ label="⚑ EV Vehicles"
1027
+ )
1028
+
1029
+ non_ev_box = gr.Textbox(
1030
+ label="πŸš— Non-EV Vehicles"
1031
+ )
1032
+
1033
+ discount_box = gr.Textbox(
1034
+ label="πŸ’° Total Discount"
1035
+ )
1036
+
1037
+
1038
+ # ====================================================
1039
+ # STATIC DASHBOARD
1040
+ # ====================================================
1041
+
1042
+ gr.Markdown(
1043
+ "## πŸ“Š Traffic Analytics Dashboard"
1044
+ )
1045
+
1046
+ dashboard = gr.Plot(
1047
+ label="Analytics"
1048
+ )
1049
+
1050
+
1051
+ btn.click(
1052
+
1053
+ fn=process_image,
1054
+
1055
+ inputs=input_img,
1056
+
1057
+ outputs=[
1058
+ output_img,
1059
+ summary_box,
1060
+ ev_box,
1061
+ non_ev_box,
1062
+ discount_box,
1063
+ dashboard
1064
+ ]
1065
+
1066
+ )
1067
+
1068
+
1069
+ # ========================================================
1070
+ # TAB 2 - AGENTIC AI DASHBOARD
1071
+ # ========================================================
1072
+
1073
+ with gr.Tab("πŸ€– AI Traffic Assistant"):
1074
+
1075
+
1076
+ gr.Markdown(
1077
+ "## πŸ€– Agentic AI Traffic Analytics Dashboard"
1078
+ )
1079
+
1080
+
1081
+ gr.Markdown(
1082
+ "Ask questions about your traffic and EV database "
1083
+ "using natural language."
1084
+ )
1085
+
1086
+
1087
+ user_query = gr.Textbox(
1088
+
1089
+ label="Ask the AI Assistant",
1090
+
1091
+ placeholder=(
1092
+ "Example: How many EV vehicles were detected?"
1093
+ ),
1094
+
1095
+ lines=2
1096
+
1097
+ )
1098
+
1099
+
1100
+ ask_button = gr.Button(
1101
+
1102
+ "πŸ€– Ask AI",
1103
+
1104
+ variant="primary",
1105
+
1106
+ size="lg"
1107
+
1108
+ )
1109
+
1110
+
1111
+ ai_response = gr.Textbox(
1112
+
1113
+ label="πŸ€– AI Response",
1114
+
1115
+ lines=12
1116
+
1117
+ )
1118
+
1119
+
1120
+ ai_graph = gr.Plot(
1121
+
1122
+ label="πŸ“Š Dynamic AI Generated Graph"
1123
+
1124
+ )
1125
+
1126
+
1127
+ ask_button.click(
1128
+
1129
+ fn=traffic_ai_agent,
1130
+
1131
+ inputs=user_query,
1132
+
1133
+ outputs=[
1134
+ ai_response,
1135
+ ai_graph
1136
+ ]
1137
+
1138
+ )
1139
+
1140
+
1141
+ # ====================================================
1142
+ # SUGGESTED QUESTIONS
1143
+ # ====================================================
1144
+
1145
+ gr.Markdown(
1146
+ """
1147
+ ```
1148
+
1149
+ ### πŸ’‘ Suggested Questions
1150
+
1151
+ β€’ How many EV vehicles were detected?
1152
+
1153
+ β€’ How many Non-EV vehicles are there?
1154
+
1155
+ οΏ½οΏ½οΏ½ What is the total traffic?
1156
+
1157
+ β€’ What percentage of vehicles are EVs?
1158
+
1159
+ β€’ What is the total EV discount?
1160
+
1161
+ β€’ Give me an overall traffic summary.
1162
+
1163
+ β€’ Show the COβ‚‚ savings.
1164
+ """
1165
+ )
1166
+
1167
+ # ============================================================
1168
+
1169
+ # RUN APPLICATION
1170
+
1171
+ # ============================================================
1172
+
1173
+ if **name** == "**main**":
1174
+
1175
+ ```
1176
+ demo.queue()
1177
+
1178
+ demo.launch(
1179
+ ssr_mode=False
1180
+ )
1181
+ ```