parthsinha commited on
Commit
b00c446
·
verified ·
1 Parent(s): a69571f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +146 -803
app.py CHANGED
@@ -1,870 +1,213 @@
1
  import gradio as gr
2
- import plotly.graph_objects as go
 
3
  from data_processor import DataProcessor
4
- from chatbot_engine import FetiiChatbot
5
  from visualizations import create_visualizations
6
  import config
7
  import utils
8
 
 
 
 
9
  # Global data processors and chatbot
10
  data_processor = DataProcessor()
11
- chatbot = FetiiChatbot(data_processor)
12
 
13
- def chat_response(message, history):
14
- """Handle chat interactions with the Fetii AI chatbot with enhanced responses."""
15
- # Add typing indicator simulation and enhanced response
16
- import time
17
 
18
- # Process the query
19
- response = chatbot.process_query(message)
20
 
21
- # Enhance response with emojis and formatting for better UX
22
- if "peak" in message.lower() or "busy" in message.lower():
23
- response = f"📊 **Peak Hours Analysis**\n\n{response}"
24
- elif "group" in message.lower() or "size" in message.lower():
25
- response = f"👥 **Group Size Insights**\n\n{response}"
26
- elif "location" in message.lower() or "where" in message.lower():
27
- response = f"📍 **Location Analysis**\n\n{response}"
28
- elif "trend" in message.lower() or "pattern" in message.lower():
29
- response = f"📈 **Trend Analysis**\n\n{response}"
30
- else:
31
- response = f"🤖 **Fetii AI Analysis**\n\n{response}"
32
 
33
- return response
34
-
35
- def create_filter_controls():
36
- """Create interactive filter controls for the dashboard."""
37
- with gr.Row():
38
- with gr.Column():
39
- time_filter = gr.Dropdown(
40
- choices=["All Hours", "Morning (6-12)", "Afternoon (12-18)", "Evening (18-24)", "Night (0-6)"],
41
- value="All Hours",
42
- label="🕐 Time Filter"
43
- )
44
- with gr.Column():
45
- group_filter = gr.Dropdown(
46
- choices=["All Groups", "Small (1-4)", "Medium (5-8)", "Large (9-12)", "Extra Large (13+)"],
47
- value="All Groups",
48
- label="👥 Group Size Filter"
49
- )
50
- with gr.Column():
51
- refresh_btn = gr.Button(
52
- "🔄 Refresh Data",
53
- variant="secondary"
54
- )
55
 
56
- return time_filter, group_filter, refresh_btn
57
 
58
- def update_dashboard(time_filter, group_filter):
59
- """Update dashboard based on filter selections."""
60
- # This would filter the data and regenerate visualizations
61
- # For now, return the same visualizations
62
- viz = create_visualizations(data_processor)
63
- return (
64
- viz['hourly_distribution'],
65
- viz['group_size_distribution'],
66
- viz['popular_locations'],
67
- viz['time_heatmap']
68
- )
69
 
70
- def get_insights_html():
71
- """Generate simplified HTML for insights display that works with Gradio."""
72
- insights = data_processor.get_quick_insights()
73
-
74
- html_content = f"""
75
- <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 2rem; border-radius: 16px; color: white; text-align: center; margin-bottom: 2rem;">
76
- <h1 style="margin: 0; font-size: 2.5rem; font-weight: bold;">🚗 Fetii AI Assistant</h1>
77
- <p style="margin: 1rem 0 0 0; font-size: 1.2rem;">Your intelligent companion for Austin rideshare analytics & insights</p>
78
- </div>
79
-
80
- <div style="display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; margin: 2rem 0;">
81
- <div style="background: white; border: 1px solid #e2e8f0; padding: 2rem; border-radius: 12px; text-align: center; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
82
- <div style="font-size: 2rem; margin-bottom: 0.5rem;">📊</div>
83
- <div style="font-size: 2rem; font-weight: bold; color: #1a202c;">{insights['total_trips']:,}</div>
84
- <div style="font-size: 0.9rem; color: #718096; margin-top: 0.5rem;">Total Trips Analyzed</div>
85
- </div>
86
-
87
- <div style="background: white; border: 1px solid #e2e8f0; padding: 2rem; border-radius: 12px; text-align: center; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
88
- <div style="font-size: 2rem; margin-bottom: 0.5rem;">�</div>
89
- <div style="font-size: 2rem; font-weight: bold; color: #1a202c;">{insights['avg_group_size']:.1f}</div>
90
- <div style="font-size: 0.9rem; color: #718096; margin-top: 0.5rem;">Average Group Size</div>
91
- </div>
92
-
93
- <div style="background: white; border: 1px solid #e2e8f0; padding: 2rem; border-radius: 12px; text-align: center; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
94
- <div style="font-size: 2rem; margin-bottom: 0.5rem;">⏰</div>
95
- <div style="font-size: 2rem; font-weight: bold; color: #1a202c;">{utils.format_time(insights['peak_hour'])}</div>
96
- <div style="font-size: 0.9rem; color: #718096; margin-top: 0.5rem;">Peak Hour</div>
97
- </div>
98
-
99
- <div style="background: white; border: 1px solid #e2e8f0; padding: 2rem; border-radius: 12px; text-align: center; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
100
- <div style="font-size: 2rem; margin-bottom: 0.5rem;">🎉</div>
101
- <div style="font-size: 2rem; font-weight: bold; color: #1a202c;">{insights['large_groups_pct']:.1f}%</div>
102
- <div style="font-size: 0.9rem; color: #718096; margin-top: 0.5rem;">Large Groups (6+)</div>
103
- </div>
104
- </div>
105
-
106
- <div class="chart-container" style="margin: 2rem 0;">
107
- <div style="display: flex; align-items: center; justify-content: between; margin-bottom: 1.5rem;">
108
- <h3 style="color: #1a202c; font-size: 1.5rem; font-weight: 700; margin: 0; display: flex; align-items: center; gap: 0.5rem;">
109
- <span style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">🔥</span>
110
- Hottest Pickup Locations
111
- </h3>
112
- <div style="background: rgba(102, 126, 234, 0.1); padding: 0.5rem 1rem; border-radius: 12px;">
113
- <span style="font-size: 0.8rem; color: #667eea; font-weight: 600;">Live Data</span>
114
- </div>
115
- </div>
116
-
117
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1rem;">
118
- """
119
-
120
- top_locations = list(insights['top_pickups'])[:6]
121
- colors = ['#667eea', '#764ba2', '#f093fb', '#f5576c', '#4facfe', '#00f2fe']
122
-
123
- for i, (location, count) in enumerate(top_locations):
124
- color = colors[i % len(colors)]
125
- percentage = (count / insights['total_trips']) * 100
126
 
127
- html_content += f"""
128
- <div style="background: rgba(255,255,255,0.95); backdrop-filter: blur(20px); padding: 1.5rem; border-radius: 16px; border-left: 4px solid {color}; box-shadow: 0 8px 25px rgba(0,0,0,0.1); transition: all 0.3s ease;">
129
- <div style="display: flex; justify-content: between; align-items: start; margin-bottom: 1rem;">
130
- <div style="flex: 1;">
131
- <div style="font-size: 1.1rem; font-weight: 700; color: #1a202c; margin-bottom: 0.5rem;">
132
- #{i+1} {location[:25]}{'...' if len(location) > 25 else ''}
133
- </div>
134
- <div style="display: flex; align-items: center; gap: 1rem;">
135
- <span style="font-size: 1.5rem; font-weight: 800; color: {color};">{count}</span>
136
- <span style="font-size: 0.9rem; color: #6b7280; font-weight: 500;">trips</span>
137
- </div>
138
- </div>
139
- <div style="background: {color}; color: white; padding: 0.25rem 0.75rem; border-radius: 12px; font-size: 0.8rem; font-weight: 600;">
140
- {percentage:.1f}%
141
- </div>
142
- </div>
143
- <div style="background: rgba(0,0,0,0.05); border-radius: 8px; height: 6px; overflow: hidden;">
144
- <div style="background: linear-gradient(90deg, {color}, {color}aa); height: 100%; width: {min(percentage*2, 100)}%; border-radius: 8px; transition: width 0.5s ease;"></div>
145
- </div>
146
- </div>
147
- """
148
 
149
- html_content += """
150
- </div>
151
- </div>
 
 
 
 
 
 
 
 
 
 
152
 
153
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin: 2rem 0;">
154
- <div style="background: rgba(72, 187, 120, 0.1); padding: 1.5rem; border-radius: 16px; text-align: center; border: 2px solid rgba(72, 187, 120, 0.2);">
155
- <div style="font-size: 2rem; margin-bottom: 0.5rem;">🌟</div>
156
- <div style="font-size: 1.1rem; font-weight: 700; color: #276749;">System Status</div>
157
- <div style="font-size: 0.9rem; color: #48bb78; font-weight: 600; margin-top: 0.5rem;">All Systems Operational</div>
158
- </div>
159
-
160
- <div style="background: rgba(102, 126, 234, 0.1); padding: 1.5rem; border-radius: 16px; text-align: center; border: 2px solid rgba(102, 126, 234, 0.2);">
161
- <div style="font-size: 2rem; margin-bottom: 0.5rem;">⚡</div>
162
- <div style="font-size: 1.1rem; font-weight: 700; color: #4c51bf;">Response Time</div>
163
- <div style="font-size: 0.9rem; color: #667eea; font-weight: 600; margin-top: 0.5rem;">< 200ms Average</div>
164
- </div>
165
-
166
- <div style="background: rgba(237, 137, 54, 0.1); padding: 1.5rem; border-radius: 16px; text-align: center; border: 2px solid rgba(237, 137, 54, 0.2);">
167
- <div style="font-size: 2rem; margin-bottom: 0.5rem;">🔄</div>
168
- <div style="font-size: 1.1rem; font-weight: 700; color: #c05621;">Data Freshness</div>
169
- <div style="font-size: 0.9rem; color: #ed8936; font-weight: 600; margin-top: 0.5rem;">Updated 2min ago</div>
170
- </div>
171
- </div>
172
- """
173
 
174
- return html_content
175
 
176
- def create_interface():
177
  """Create the main Gradio interface."""
178
- # Enhanced Custom CSS for Premium UI
179
- custom_css = """
180
- @import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap');
181
-
182
- /* Root Variables for Theme Management */
183
- :root {
184
- --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
185
- --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
186
- --success-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
187
- --warning-gradient: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
188
- --dark-gradient: linear-gradient(135deg, #2c3e50 0%, #34495e 100%);
189
- --light-bg: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
190
- --card-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
191
- --hover-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
192
- --text-primary: #1a202c;
193
- --text-secondary: #4a5568;
194
- --border-color: #e2e8f0;
195
- --success-color: #48bb78;
196
- --warning-color: #ed8936;
197
- --error-color: #f56565;
198
- }
199
-
200
- /* Main Container Styling */
201
- .gradio-container {
202
- font-family: 'Inter', sans-serif !important;
203
- background: var(--light-bg) !important;
204
- min-height: 100vh;
205
- padding: 0 !important;
206
- margin: 0 !important;
207
- }
208
-
209
- /* Header Styling */
210
- .main-header {
211
- background: var(--primary-gradient) !important;
212
- padding: 3rem 2rem !important;
213
- border-radius: 0 0 24px 24px !important;
214
- color: white !important;
215
- text-align: center !important;
216
- margin-bottom: 2rem !important;
217
- box-shadow: var(--card-shadow) !important;
218
- position: relative !important;
219
- overflow: hidden !important;
220
- }
221
-
222
- .main-header::before {
223
- content: '';
224
- position: absolute;
225
- top: 0;
226
- left: 0;
227
- right: 0;
228
- bottom: 0;
229
- background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 20"><defs><radialGradient id="a" cx="50%" cy="50%" r="50%"><stop offset="0%" stop-color="rgba(255,255,255,.1)"/><stop offset="100%" stop-color="rgba(255,255,255,0)"/></radialGradient></defs><rect width="100" height="20" fill="url(%23a)"/></svg>') repeat;
230
- opacity: 0.1;
231
- animation: shimmer 3s ease-in-out infinite;
232
- }
233
-
234
- @keyframes shimmer {
235
- 0%, 100% { transform: translateX(-100%); }
236
- 50% { transform: translateX(100%); }
237
- }
238
-
239
- .main-header h1 {
240
- font-size: 3rem !important;
241
- font-weight: 800 !important;
242
- margin: 0 !important;
243
- letter-spacing: -0.05em !important;
244
- text-shadow: 2px 2px 4px rgba(0,0,0,0.3) !important;
245
- position: relative !important;
246
- z-index: 1 !important;
247
- }
248
-
249
- .main-header p {
250
- font-size: 1.25rem !important;
251
- margin: 1rem 0 0 0 !important;
252
- opacity: 0.95 !important;
253
- font-weight: 400 !important;
254
- letter-spacing: 0.025em !important;
255
- position: relative !important;
256
- z-index: 1 !important;
257
- }
258
-
259
- /* Enhanced Metric Cards */
260
- .metric-card {
261
- background: rgba(255, 255, 255, 0.9) !important;
262
- backdrop-filter: blur(20px) !important;
263
- border: 1px solid rgba(255, 255, 255, 0.2) !important;
264
- padding: 2rem !important;
265
- border-radius: 20px !important;
266
- margin: 1rem 0 !important;
267
- box-shadow: var(--card-shadow) !important;
268
- transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) !important;
269
- position: relative !important;
270
- overflow: hidden !important;
271
- }
272
-
273
- .metric-card::before {
274
- content: '';
275
- position: absolute;
276
- top: 0;
277
- left: 0;
278
- right: 0;
279
- height: 4px;
280
- background: var(--primary-gradient);
281
- transform: scaleX(0);
282
- transition: transform 0.3s ease;
283
- }
284
-
285
- .metric-card:hover {
286
- transform: translateY(-8px) scale(1.02) !important;
287
- box-shadow: var(--hover-shadow) !important;
288
- background: rgba(255, 255, 255, 0.95) !important;
289
- }
290
-
291
- .metric-card:hover::before {
292
- transform: scaleX(1);
293
- }
294
-
295
- .metric-icon {
296
- font-size: 2.5rem !important;
297
- background: var(--primary-gradient) !important;
298
- -webkit-background-clip: text !important;
299
- -webkit-text-fill-color: transparent !important;
300
- background-clip: text !important;
301
- margin-bottom: 1rem !important;
302
- display: block !important;
303
- filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.1)) !important;
304
- }
305
-
306
- .metric-value {
307
- font-size: 2.5rem !important;
308
- font-weight: 800 !important;
309
- margin: 0.5rem 0 !important;
310
- color: var(--text-primary) !important;
311
- line-height: 1.1 !important;
312
- background: var(--primary-gradient) !important;
313
- -webkit-background-clip: text !important;
314
- -webkit-text-fill-color: transparent !important;
315
- background-clip: text !important;
316
- }
317
-
318
- .metric-label {
319
- font-size: 0.9rem !important;
320
- margin: 0 !important;
321
- color: var(--text-secondary) !important;
322
- font-weight: 600 !important;
323
- letter-spacing: 0.05em !important;
324
- text-transform: uppercase !important;
325
- }
326
-
327
- /* Chat Interface Enhancements */
328
- .chat-container {
329
- background: rgba(255, 255, 255, 0.95) !important;
330
- backdrop-filter: blur(20px) !important;
331
- border-radius: 24px !important;
332
- box-shadow: var(--card-shadow) !important;
333
- border: 1px solid rgba(255, 255, 255, 0.2) !important;
334
- overflow: hidden !important;
335
- transition: all 0.3s ease !important;
336
- }
337
-
338
- .chat-container:hover {
339
- box-shadow: var(--hover-shadow) !important;
340
- }
341
-
342
- /* Chart Container Improvements */
343
- .chart-container {
344
- background: rgba(255, 255, 255, 0.95) !important;
345
- backdrop-filter: blur(20px) !important;
346
- border-radius: 20px !important;
347
- padding: 2rem !important;
348
- box-shadow: var(--card-shadow) !important;
349
- margin: 1rem 0 !important;
350
- border: 1px solid rgba(255, 255, 255, 0.2) !important;
351
- transition: all 0.3s ease !important;
352
- position: relative !important;
353
- overflow: hidden !important;
354
- }
355
-
356
- .chart-container::before {
357
- content: '';
358
- position: absolute;
359
- top: 0;
360
- left: 0;
361
- right: 0;
362
- height: 3px;
363
- background: var(--success-gradient);
364
- opacity: 0;
365
- transition: opacity 0.3s ease;
366
- }
367
-
368
- .chart-container:hover {
369
- transform: translateY(-4px) !important;
370
- box-shadow: var(--hover-shadow) !important;
371
- }
372
-
373
- .chart-container:hover::before {
374
- opacity: 1;
375
- }
376
-
377
- /* Tab Styling */
378
- .tab-nav {
379
- background: rgba(255, 255, 255, 0.1) !important;
380
- backdrop-filter: blur(10px) !important;
381
- border-radius: 12px !important;
382
- padding: 4px !important;
383
- margin-bottom: 2rem !important;
384
- }
385
-
386
- .tab-nav button {
387
- background: transparent !important;
388
- border: none !important;
389
- padding: 12px 24px !important;
390
- border-radius: 8px !important;
391
- font-weight: 600 !important;
392
- color: var(--text-secondary) !important;
393
- transition: all 0.3s ease !important;
394
- position: relative !important;
395
- }
396
-
397
- .tab-nav button.selected {
398
- background: white !important;
399
- color: var(--text-primary) !important;
400
- box-shadow: 0 4px 12px rgba(0,0,0,0.1) !important;
401
- }
402
-
403
- /* Button Enhancements */
404
- .gr-button {
405
- background: var(--primary-gradient) !important;
406
- border: none !important;
407
- border-radius: 12px !important;
408
- padding: 12px 24px !important;
409
- font-weight: 600 !important;
410
- color: white !important;
411
- transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) !important;
412
- box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4) !important;
413
- position: relative !important;
414
- overflow: hidden !important;
415
- }
416
-
417
- .gr-button::before {
418
- content: '';
419
- position: absolute;
420
- top: 0;
421
- left: -100%;
422
- width: 100%;
423
- height: 100%;
424
- background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
425
- transition: left 0.5s;
426
- }
427
-
428
- .gr-button:hover {
429
- transform: translateY(-2px) scale(1.05) !important;
430
- box-shadow: 0 8px 25px rgba(102, 126, 234, 0.6) !important;
431
- }
432
-
433
- .gr-button:hover::before {
434
- left: 100%;
435
- }
436
-
437
- /* Input Field Styling */
438
- .gr-textbox, .gr-input {
439
- border: 2px solid var(--border-color) !important;
440
- border-radius: 12px !important;
441
- padding: 12px 16px !important;
442
- font-size: 1rem !important;
443
- transition: all 0.3s ease !important;
444
- background: rgba(255, 255, 255, 0.9) !important;
445
- backdrop-filter: blur(10px) !important;
446
- }
447
 
448
- .gr-textbox:focus, .gr-input:focus {
449
- border-color: #667eea !important;
450
- box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important;
451
- outline: none !important;
452
- }
453
 
454
- /* Accordion Improvements */
455
- .gr-accordion {
456
- border: none !important;
457
- border-radius: 16px !important;
458
- margin-bottom: 1rem !important;
459
- background: rgba(255, 255, 255, 0.9) !important;
460
- backdrop-filter: blur(20px) !important;
461
- box-shadow: var(--card-shadow) !important;
462
- overflow: hidden !important;
463
- }
464
-
465
- .gr-accordion-header {
466
- background: var(--primary-gradient) !important;
467
- color: white !important;
468
- padding: 1rem 1.5rem !important;
469
- font-weight: 600 !important;
470
- border: none !important;
471
- transition: all 0.3s ease !important;
472
- }
473
-
474
- .gr-accordion-header:hover {
475
- background: var(--secondary-gradient) !important;
476
- }
477
-
478
- /* Loading Animation */
479
- @keyframes pulse {
480
- 0%, 100% { opacity: 1; }
481
- 50% { opacity: 0.5; }
482
- }
483
-
484
- .loading {
485
- animation: pulse 2s infinite;
486
- }
487
-
488
- /* Responsive Design */
489
- @media (max-width: 768px) {
490
- .main-header h1 {
491
- font-size: 2rem !important;
492
- }
493
-
494
- .main-header p {
495
- font-size: 1rem !important;
496
- }
497
 
498
- .metric-card {
499
- padding: 1.5rem !important;
500
- }
501
 
502
- .metric-value {
503
- font-size: 2rem !important;
504
- }
505
- }
506
-
507
- /* Scrollbar Styling */
508
- ::-webkit-scrollbar {
509
- width: 8px;
510
- height: 8px;
511
- }
512
-
513
- ::-webkit-scrollbar-track {
514
- background: rgba(0,0,0,0.1);
515
- border-radius: 10px;
516
- }
517
-
518
- ::-webkit-scrollbar-thumb {
519
- background: var(--primary-gradient);
520
- border-radius: 10px;
521
- transition: all 0.3s ease;
522
- }
523
-
524
- ::-webkit-scrollbar-thumb:hover {
525
- background: var(--secondary-gradient);
526
- }
527
-
528
- /* Success/Error States */
529
- .success {
530
- border-left: 4px solid var(--success-color) !important;
531
- background: rgba(72, 187, 120, 0.1) !important;
532
- }
533
-
534
- .warning {
535
- border-left: 4px solid var(--warning-color) !important;
536
- background: rgba(237, 137, 54, 0.1) !important;
537
- }
538
-
539
- .error {
540
- border-left: 4px solid var(--error-color) !important;
541
- background: rgba(245, 101, 101, 0.1) !important;
542
- }
543
- """
544
-
545
- # Get visualizations
546
- viz = create_visualizations(data_processor)
547
-
548
- with gr.Blocks(css=custom_css, title="🚗 Fetii AI Assistant - Austin Rideshare Analytics", theme=gr.themes.Soft()) as demo:
549
- # Header and insights
550
- gr.HTML(get_insights_html())
551
-
552
- # Main content with tabs for better organization
553
- with gr.Tabs() as tabs:
554
- with gr.TabItem("💬 AI Assistant", elem_id="chat-tab"):
555
  with gr.Row():
556
  with gr.Column(scale=3):
557
- gr.HTML("""
558
- <div style="text-align: center; margin: 2rem 0;">
559
- <h2 style="color: #1a202c; font-weight: 700; margin-bottom: 1rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
560
- <span style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">🤖</span>
561
- Chat with Fetii AI
562
- </h2>
563
- <p style="color: #4a5568; font-size: 1.1rem; margin-bottom: 2rem;">Ask me anything about Austin rideshare patterns and trends</p>
564
- </div>
565
- """)
566
-
567
- # Enhanced example questions with categories
568
- gr.HTML("""
569
- <div style="margin: 2rem 0;">
570
- <h3 style="color: #2d3748; font-weight: 600; margin-bottom: 1.5rem; text-align: center; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
571
- <span style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">💡</span>
572
- Quick Start Questions
573
- </h3>
574
- </div>
575
- """)
576
 
577
- # Get example questions from config
578
- base_questions = config.CHATBOT_CONFIG['example_questions']
579
-
580
- # Categorized example questions
581
- example_categories = {
582
- "📊 Popular Questions": [
583
- "What are the peak hours for rideshare in Austin?",
584
- "Which locations have the most pickups?",
585
- "What's the average group size?"
586
- ],
587
- "📈 Trend Analysis": [
588
- "Show me daily volume trends",
589
- "How do group sizes vary by time?",
590
- "What are the busiest days of the week?"
591
- ],
592
- "🎯 Advanced Insights": [
593
- base_questions[0] if len(base_questions) > 0 else "How many groups went to The Aquarium on 6th last month?",
594
- base_questions[1] if len(base_questions) > 1 else "What are the top drop-off spots for large groups on Saturday nights?",
595
- base_questions[2] if len(base_questions) > 2 else "When do groups of 6+ riders typically ride downtown?"
596
- ]
597
- }
598
 
599
- for category, questions in example_categories.items():
600
- gr.HTML(f"""
601
- <div style="background: rgba(255,255,255,0.7); backdrop-filter: blur(10px); border-radius: 12px; padding: 1rem; margin: 1rem 0; border-left: 4px solid #667eea;">
602
- <h4 style="color: #1a202c; font-weight: 600; margin: 0 0 0.5rem 0; font-size: 0.95rem;">{category}</h4>
603
- </div>
604
- """)
605
-
606
- with gr.Row():
607
- for question in questions:
608
- gr.Button(
609
- question,
610
- size="sm",
611
- variant="secondary",
612
- scale=1
613
- )
614
 
615
- # Enhanced chat interface
616
  chatbot_interface = gr.ChatInterface(
617
  fn=chat_response,
618
- textbox=gr.Textbox(
619
- placeholder="💭 Ask me about Austin rideshare patterns...",
620
- scale=7,
621
- container=False
622
- ),
623
  title="",
624
  description="",
625
  examples=[
626
- "What are the peak hours for rideshare in Austin?",
627
- "Which locations have the most pickups?",
628
- "What's the average group size?",
629
- "Show me daily volume trends"
630
  ],
631
- cache_examples=False
 
632
  )
633
-
634
- with gr.Column(scale=1):
635
- gr.HTML("""
636
- <div style="background: rgba(255,255,255,0.95); backdrop-filter: blur(20px); border-radius: 20px; padding: 2rem; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1); margin-bottom: 1rem;">
637
- <h3 style="color: #1a202c; font-size: 1.3rem; font-weight: 700; margin: 0 0 1.5rem 0; text-align: center; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
638
- <span style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">📊</span>
639
- Quick Insights
640
- </h3>
641
- <div style="space-y: 1rem;">
642
- <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 1rem; border-radius: 12px; margin-bottom: 1rem;">
643
- <div style="font-size: 0.9rem; opacity: 0.9; margin-bottom: 0.5rem;">🚗 Most Active Route</div>
644
- <div style="font-size: 1.1rem; font-weight: 700;">Downtown ↔ Airport</div>
645
- </div>
646
- <div style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; padding: 1rem; border-radius: 12px; margin-bottom: 1rem;">
647
- <div style="font-size: 0.9rem; opacity: 0.9; margin-bottom: 0.5rem;">⏰ Rush Hour Peak</div>
648
- <div style="font-size: 1.1rem; font-weight: 700;">5:00 PM - 7:00 PM</div>
649
- </div>
650
- <div style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); color: white; padding: 1rem; border-radius: 12px;">
651
- <div style="font-size: 0.9rem; opacity: 0.9; margin-bottom: 0.5rem;">📈 Trend Status</div>
652
- <div style="font-size: 1.1rem; font-weight: 700;">Growing +15%</div>
653
- </div>
654
- </div>
655
- </div>
656
- """)
657
-
658
- with gr.TabItem("📊 Analytics Dashboard", elem_id="analytics-tab"):
659
- gr.HTML("""
660
- <div style="text-align: center; margin: 2rem 0;">
661
- <h2 style="color: #1a202c; font-weight: 700; margin-bottom: 1rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
662
- <span style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">📊</span>
663
- Interactive Analytics Dashboard
664
- </h2>
665
- <p style="color: #4a5568; font-size: 1.1rem;">Explore detailed visualizations and trends with interactive filters</p>
666
- </div>
667
- """)
668
-
669
- # Interactive filter controls
670
- time_filter, group_filter, refresh_btn = create_filter_controls()
671
-
672
- # Charts with state management
673
- with gr.Row():
674
- with gr.Column(scale=1):
675
- with gr.Accordion("⏰ Peak Hours Analysis", open=True):
676
- hourly_plot = gr.Plot(value=viz['hourly_distribution'])
677
 
678
- with gr.Accordion("👥 Group Size Distribution", open=True):
679
- group_plot = gr.Plot(value=viz['group_size_distribution'])
 
 
 
680
 
681
  with gr.Column(scale=1):
682
- with gr.Accordion("📍 Popular Locations", open=True):
683
- location_plot = gr.Plot(value=viz['popular_locations'])
 
684
 
685
- with gr.Accordion("🗓️ Time Heatmap", open=False):
686
- heatmap_plot = gr.Plot(value=viz['time_heatmap'])
687
-
688
- # Connect filters to update function
689
- def on_filter_change(time_val, group_val):
690
- return update_dashboard(time_val, group_val)
691
-
692
- time_filter.change(
693
- fn=on_filter_change,
694
- inputs=[time_filter, group_filter],
695
- outputs=[hourly_plot, group_plot, location_plot, heatmap_plot]
696
- )
697
-
698
- group_filter.change(
699
- fn=on_filter_change,
700
- inputs=[time_filter, group_filter],
701
- outputs=[hourly_plot, group_plot, location_plot, heatmap_plot]
702
- )
703
 
704
- refresh_btn.click(
705
- fn=on_filter_change,
706
- inputs=[time_filter, group_filter],
707
- outputs=[hourly_plot, group_plot, location_plot, heatmap_plot]
708
- )
709
 
710
  with gr.Row():
711
  with gr.Column():
712
- with gr.Accordion("📈 Daily Volume Trends", open=False):
713
- gr.Plot(value=viz['daily_volume'])
714
-
715
- with gr.Column():
716
- with gr.Accordion("🆚 Pickup vs Dropoff", open=False):
717
- gr.Plot(value=viz['location_comparison'])
718
-
719
- with gr.TabItem("� Comprehensive Dashboard", elem_id="comprehensive-tab"):
720
- gr.HTML("""
721
- <div style="text-align: center; margin: 2rem 0;">
722
- <h2 style="color: #1a202c; font-weight: 700; margin-bottom: 1rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
723
- <span style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">📈</span>
724
- Comprehensive Analytics Dashboard
725
- </h2>
726
- <p style="color: #4a5568; font-size: 1.1rem;">Complete overview of all analytics and insights</p>
727
- </div>
728
- """)
729
-
730
- # All charts in a comprehensive view
731
- with gr.Row():
732
- with gr.Column(scale=1):
733
- with gr.Accordion("⏰ Hourly Distribution", open=True):
734
- gr.Plot(value=viz['hourly_distribution'])
735
 
736
- with gr.Accordion("🗓️ Daily Volume Trends", open=True):
737
- gr.Plot(value=viz['daily_volume'])
738
-
739
- with gr.Accordion("🎯 Peak Patterns Analysis", open=False):
740
- gr.Plot(value=viz['peak_patterns'])
741
 
742
- with gr.Column(scale=1):
743
- with gr.Accordion("👥 Group Size Distribution", open=True):
744
- gr.Plot(value=viz['group_size_distribution'])
745
-
746
- with gr.Accordion("📍 Popular Locations", open=True):
747
- gr.Plot(value=viz['popular_locations'])
748
-
749
- with gr.Accordion("🆚 Location Comparison", open=False):
750
- gr.Plot(value=viz['location_comparison'])
751
-
752
- with gr.Column(scale=1):
753
- with gr.Accordion("🔥 Time Heatmap", open=True):
754
- gr.Plot(value=viz['time_heatmap'])
755
-
756
- with gr.Accordion("📏 Distance Analysis", open=False):
757
- gr.Plot(value=viz['trip_distance_analysis'])
758
 
759
- # Add summary metrics
760
- gr.HTML("""
761
- <div style="background: rgba(255,255,255,0.95); backdrop-filter: blur(20px); border-radius: 16px; padding: 1.5rem; margin-top: 1rem; box-shadow: 0 10px 25px rgba(0,0,0,0.1);">
762
- <h4 style="color: #1a202c; font-weight: 700; margin: 0 0 1rem 0; text-align: center;">📊 Quick Stats</h4>
763
- <div style="display: grid; gap: 0.5rem;">
764
- <div style="display: flex; justify-content: between; align-items: center; padding: 0.5rem; background: rgba(102, 126, 234, 0.1); border-radius: 8px;">
765
- <span style="font-size: 0.9rem; color: #4a5568;">Efficiency Score</span>
766
- <span style="font-weight: 700; color: #667eea;">87%</span>
767
- </div>
768
- <div style="display: flex; justify-content: between; align-items: center; padding: 0.5rem; background: rgba(72, 187, 120, 0.1); border-radius: 8px;">
769
- <span style="font-size: 0.9rem; color: #4a5568;">Satisfaction</span>
770
- <span style="font-weight: 700; color: #48bb78;">94%</span>
771
- </div>
772
- <div style="display: flex; justify-content: between; align-items: center; padding: 0.5rem; background: rgba(237, 137, 54, 0.1); border-radius: 8px;">
773
- <span style="font-size: 0.9rem; color: #4a5568;">Growth Rate</span>
774
- <span style="font-weight: 700; color: #ed8936;">+15%</span>
775
- </div>
776
- </div>
777
- </div>
778
- """)
779
 
780
- with gr.TabItem("�🔬 Advanced Analytics", elem_id="advanced-tab"):
781
- gr.HTML("""
782
- <div style="text-align: center; margin: 2rem 0;">
783
- <h2 style="color: #1a202c; font-weight: 700; margin-bottom: 1rem; display: flex; align-items: center; justify-content: center; gap: 0.5rem;">
784
- <span style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">🔬</span>
785
- Advanced Analytics & Insights
786
- </h2>
787
- <p style="color: #4a5568; font-size: 1.1rem;">Deep dive into complex patterns and correlations</p>
788
- </div>
789
- """)
790
 
791
  with gr.Row():
792
  with gr.Column():
793
- with gr.Accordion("🎯 Peak Patterns by Group Size", open=True):
794
- gr.Plot(value=viz['peak_patterns'])
795
-
796
- with gr.Column():
797
- with gr.Accordion("📏 Distance Analysis", open=True):
798
- gr.Plot(value=viz['trip_distance_analysis'])
799
-
800
- with gr.Row():
801
- with gr.Column():
802
- with gr.Accordion("📈 Daily Volume Trends", open=False):
803
- gr.Plot(value=viz['daily_volume'])
804
 
805
  with gr.Column():
806
- with gr.Accordion("🆚 Pickup vs Dropoff Analysis", open=False):
807
- gr.Plot(value=viz['location_comparison'])
808
-
809
- # Advanced metrics section
810
- gr.HTML("""
811
- <div style="background: rgba(255,255,255,0.95); backdrop-filter: blur(20px); border-radius: 20px; padding: 2rem; margin: 2rem 0; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);">
812
- <h3 style="color: #1a202c; font-size: 1.4rem; font-weight: 700; margin: 0 0 2rem 0; text-align: center;">🧠 AI-Powered Insights</h3>
813
- <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem;">
814
- <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 1.5rem; border-radius: 16px; text-align: center;">
815
- <div style="font-size: 2rem; margin-bottom: 1rem;">🎯</div>
816
- <div style="font-size: 1.1rem; font-weight: 700; margin-bottom: 0.5rem;">Demand Prediction</div>
817
- <div style="font-size: 0.9rem; opacity: 0.9;">Next peak: 6:30 PM</div>
818
- </div>
819
- <div style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); color: white; padding: 1.5rem; border-radius: 16px; text-align: center;">
820
- <div style="font-size: 2rem; margin-bottom: 1rem;">💡</div>
821
- <div style="font-size: 1.1rem; font-weight: 700; margin-bottom: 0.5rem;">Route Optimization</div>
822
- <div style="font-size: 0.9rem; opacity: 0.9;">12% efficiency gain possible</div>
823
- </div>
824
- <div style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); color: white; padding: 1.5rem; border-radius: 16px; text-align: center;">
825
- <div style="font-size: 2rem; margin-bottom: 1rem;">📊</div>
826
- <div style="font-size: 1.1rem; font-weight: 700; margin-bottom: 0.5rem;">Market Analysis</div>
827
- <div style="font-size: 0.9rem; opacity: 0.9;">Growth opportunity detected</div>
828
- </div>
829
- </div>
830
- </div>
831
- """)
832
 
833
- # Enhanced Footer
834
- gr.HTML("""
835
- <div style="background: rgba(255,255,255,0.95); backdrop-filter: blur(20px); border-radius: 20px; padding: 3rem 2rem; margin-top: 3rem; box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1); text-align: center; border: 1px solid rgba(255,255,255,0.2);">
836
- <div style="display: flex; align-items: center; justify-content: center; gap: 1rem; margin-bottom: 2rem;">
837
- <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-size: 2rem;">🚗</div>
838
- <h3 style="color: #1a202c; font-weight: 800; margin: 0; font-size: 1.8rem; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;">Fetii AI</h3>
839
- <div style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text; font-size: 2rem;">✨</div>
840
- </div>
841
- <p style="color: #4a5568; font-size: 1.1rem; margin: 1rem 0; font-weight: 500;">Built with ❤️ using Gradio • Real Austin Data • Advanced AI Analytics</p>
842
- <div style="display: flex; justify-content: center; gap: 1rem; margin-top: 2rem; flex-wrap: wrap;">
843
- <div style="background: rgba(102, 126, 234, 0.1); padding: 0.5rem 1rem; border-radius: 20px;">
844
- <span style="color: #667eea; font-weight: 600; font-size: 0.9rem;">🔄 Real-time Updates</span>
845
- </div>
846
- <div style="background: rgba(72, 187, 120, 0.1); padding: 0.5rem 1rem; border-radius: 20px;">
847
- <span style="color: #48bb78; font-weight: 600; font-size: 0.9rem;">⚡ Lightning Fast</span>
848
- </div>
849
- <div style="background: rgba(237, 137, 54, 0.1); padding: 0.5rem 1rem; border-radius: 20px;">
850
- <span style="color: #ed8936; font-weight: 600; font-size: 0.9rem;">🛡️ Secure & Private</span>
851
- </div>
852
- </div>
853
- </div>
854
- """)
855
 
856
  return demo
857
 
858
  def main():
859
  """Launch the Gradio application."""
860
- demo = create_interface()
861
  demo.launch(
862
  server_name="127.0.0.1",
863
  server_port=7860,
864
- share=False,
865
  show_api=False,
866
- show_error=True,
867
- quiet=False,
868
  inbrowser=True
869
  )
870
 
 
1
  import gradio as gr
2
+ import os
3
+ from dotenv import load_dotenv
4
  from data_processor import DataProcessor
5
+ from chatbot_engine import EnhancedFetiiChatbot
6
  from visualizations import create_visualizations
7
  import config
8
  import utils
9
 
10
+ # Load environment variables
11
+ load_dotenv()
12
+
13
  # Global data processors and chatbot
14
  data_processor = DataProcessor()
15
+ chatbot = None
16
 
17
+ def initialize_chatbot(api_key=None, use_ai=True):
18
+ """Initialize or update the chatbot with new configuration."""
19
+ global chatbot
 
20
 
21
+ if api_key:
22
+ os.environ['GEMINI_API_KEY'] = api_key
23
 
24
+ gemini_api_key = api_key or os.getenv('GEMINI_API_KEY')
 
 
 
 
 
 
 
 
 
 
25
 
26
+ chatbot = EnhancedFetiiChatbot(
27
+ data_processor,
28
+ use_ai=use_ai and bool(gemini_api_key),
29
+ gemini_api_key=gemini_api_key
30
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
 
32
+ return chatbot
33
 
34
+ def get_ai_status():
35
+ """Get current AI status for display."""
36
+ if chatbot and hasattr(chatbot, 'ai_available') and chatbot.ai_available:
37
+ return "✅ Gemini AI Active"
38
+ else:
39
+ return "⚠️ Pattern-based Mode"
 
 
 
 
 
40
 
41
+ def chat_response(message, history):
42
+ """Handle chat interactions with the Fetii AI chatbot."""
43
+ if not chatbot:
44
+ initialize_chatbot()
45
+
46
+ try:
47
+ response = chatbot.process_query(message)
48
+ return response
49
+ except Exception as e:
50
+ return f"I encountered an error processing your request. Please try asking about Austin rideshare data patterns, locations, or statistics."
51
+
52
+ def update_configuration(api_key, use_ai_enabled):
53
+ """Update chatbot configuration and return status."""
54
+ try:
55
+ initialize_chatbot(api_key, use_ai_enabled)
56
+ status = get_ai_status()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
 
58
+ if api_key and use_ai_enabled:
59
+ if chatbot.ai_available:
60
+ return f" Configuration updated successfully! {status}", status
61
+ else:
62
+ return f" Failed to connect to Gemini AI. Check your API key. {get_ai_status()}", get_ai_status()
63
+ else:
64
+ return f"⚠️ Using pattern-based responses. {status}", status
65
+
66
+ except Exception as e:
67
+ return f" Configuration error: {str(e)}", "❌ Configuration Error"
68
+
69
+ def get_quick_stats():
70
+ """Get formatted quick statistics."""
71
+ insights = data_processor.get_quick_insights()
 
 
 
 
 
 
 
72
 
73
+ stats_text = f"""
74
+ **Quick Stats:**
75
+ - Total Trips: {insights['total_trips']:,}
76
+ - Average Group Size: {insights['avg_group_size']:.1f}
77
+ - Peak Hour: {utils.format_time(insights['peak_hour'])}
78
+ - Large Groups (6+): {insights['large_groups_pct']:.1f}%
79
+ """
80
+ return stats_text
81
+
82
+ def get_top_locations():
83
+ """Get formatted top locations."""
84
+ insights = data_processor.get_quick_insights()
85
+ top_locations = list(insights['top_pickups'])[:5]
86
 
87
+ locations_text = "**Top Pickup Locations:**\n"
88
+ for i, (location, count) in enumerate(top_locations, 1):
89
+ locations_text += f"{i}. {location} - {count} trips\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ return locations_text
92
 
93
+ def create_main_interface():
94
  """Create the main Gradio interface."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
+ # Initialize chatbot on startup
97
+ initialize_chatbot()
 
 
 
98
 
99
+ with gr.Blocks(title="Fetii AI Assistant - Austin Rideshare Analytics", theme=gr.themes.Soft()) as demo:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
+ # Header
102
+ gr.Markdown("# Fetii AI Assistant")
103
+ gr.Markdown("Your intelligent companion for Austin rideshare analytics & insights")
104
 
105
+ # Main content with tabs
106
+ with gr.Tabs():
107
+
108
+ # Chat Tab
109
+ with gr.TabItem("AI Assistant"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  with gr.Row():
111
  with gr.Column(scale=3):
112
+ # Example questions
113
+ gr.Markdown("### Quick Start Questions:")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
+ with gr.Row():
116
+ q1_btn = gr.Button("What are the peak hours?", size="sm")
117
+ q2_btn = gr.Button("Tell me about West Campus", size="sm")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
 
119
+ with gr.Row():
120
+ q3_btn = gr.Button("Show busiest locations", size="sm")
121
+ q4_btn = gr.Button("How many large groups?", size="sm")
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
+ # Main chat interface
124
  chatbot_interface = gr.ChatInterface(
125
  fn=chat_response,
126
+ textbox=gr.Textbox(placeholder="Ask me about Austin rideshare patterns...", scale=7),
 
 
 
 
127
  title="",
128
  description="",
129
  examples=[
130
+ "Hello, how are you?",
131
+ "What are the peak hours?",
132
+ "Tell me about popular pickup locations",
133
+ "How do group sizes vary?"
134
  ],
135
+ cache_examples=False,
136
+ type="messages"
137
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
 
139
+ # Button functions
140
+ q1_btn.click(lambda: "What are the peak hours for rideshare?", outputs=chatbot_interface.textbox)
141
+ q2_btn.click(lambda: "Tell me about West Campus pickups", outputs=chatbot_interface.textbox)
142
+ q3_btn.click(lambda: "Show me the busiest locations", outputs=chatbot_interface.textbox)
143
+ q4_btn.click(lambda: "How many large groups ride?", outputs=chatbot_interface.textbox)
144
 
145
  with gr.Column(scale=1):
146
+ # Quick Stats
147
+ gr.Markdown("### Quick Stats")
148
+ stats_display = gr.Markdown(get_quick_stats())
149
 
150
+ # Top Locations
151
+ gr.Markdown("### Top Pickup Spots")
152
+ locations_display = gr.Markdown(get_top_locations())
153
+
154
+ # Analytics Dashboard Tab
155
+ with gr.TabItem("Analytics Dashboard"):
156
+ gr.Markdown("## Interactive Analytics Dashboard")
157
+ gr.Markdown("Explore detailed visualizations and trends")
 
 
 
 
 
 
 
 
 
 
158
 
159
+ # Get visualizations
160
+ viz = create_visualizations(data_processor)
 
 
 
161
 
162
  with gr.Row():
163
  with gr.Column():
164
+ gr.Markdown("### Peak Hours Analysis")
165
+ gr.Plot(value=viz['hourly_distribution'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
 
167
+ gr.Markdown("### Group Size Distribution")
168
+ gr.Plot(value=viz['group_size_distribution'])
 
 
 
169
 
170
+ with gr.Column():
171
+ gr.Markdown("### Popular Locations")
172
+ gr.Plot(value=viz['popular_locations'])
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
+ gr.Markdown("### Time Heatmap")
175
+ gr.Plot(value=viz['time_heatmap'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
 
177
+ # Advanced Analytics Tab
178
+ with gr.TabItem("Advanced Analytics"):
179
+ gr.Markdown("## Advanced Analytics & Insights")
180
+ gr.Markdown("Deep dive into complex patterns")
 
 
 
 
 
 
181
 
182
  with gr.Row():
183
  with gr.Column():
184
+ gr.Markdown("### Daily Volume Trends")
185
+ gr.Plot(value=viz['daily_volume'])
186
+
187
+ gr.Markdown("### Peak Patterns by Group")
188
+ gr.Plot(value=viz['peak_patterns'])
 
 
 
 
 
 
189
 
190
  with gr.Column():
191
+ gr.Markdown("### Distance Analysis")
192
+ gr.Plot(value=viz['trip_distance_analysis'])
193
+
194
+ gr.Markdown("### Location Comparison")
195
+ gr.Plot(value=viz['location_comparison'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
+ # Footer
198
+ gr.Markdown("---")
199
+ gr.Markdown("**Powered by Fetii AI** Enhanced with AI Real Austin Data Advanced Analytics")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
 
201
  return demo
202
 
203
  def main():
204
  """Launch the Gradio application."""
205
+ demo = create_main_interface()
206
  demo.launch(
207
  server_name="127.0.0.1",
208
  server_port=7860,
209
+ share=True,
210
  show_api=False,
 
 
211
  inbrowser=True
212
  )
213