import gradio as gr import plotly.graph_objects as go from data_processor import DataProcessor from chatbot_engine import FetiiChatbot from visualizations import create_visualizations import config import utils # Global data processors and chatbot data_processor = DataProcessor() chatbot = FetiiChatbot(data_processor) def chat_response(message, history): """Handle chat interactions with the Fetii AI chatbot with enhanced responses.""" # Add typing indicator simulation and enhanced response import time # Process the query response = chatbot.process_query(message) # Enhance response with emojis and formatting for better UX if "peak" in message.lower() or "busy" in message.lower(): response = f"📊 **Peak Hours Analysis**\n\n{response}" elif "group" in message.lower() or "size" in message.lower(): response = f"👥 **Group Size Insights**\n\n{response}" elif "location" in message.lower() or "where" in message.lower(): response = f"📍 **Location Analysis**\n\n{response}" elif "trend" in message.lower() or "pattern" in message.lower(): response = f"📈 **Trend Analysis**\n\n{response}" else: response = f"🤖 **Fetii AI Analysis**\n\n{response}" return response def create_filter_controls(): """Create interactive filter controls for the dashboard.""" with gr.Row(): with gr.Column(): time_filter = gr.Dropdown( choices=["All Hours", "Morning (6-12)", "Afternoon (12-18)", "Evening (18-24)", "Night (0-6)"], value="All Hours", label="🕐 Time Filter" ) with gr.Column(): group_filter = gr.Dropdown( choices=["All Groups", "Small (1-4)", "Medium (5-8)", "Large (9-12)", "Extra Large (13+)"], value="All Groups", label="👥 Group Size Filter" ) with gr.Column(): refresh_btn = gr.Button( "🔄 Refresh Data", variant="secondary" ) return time_filter, group_filter, refresh_btn def update_dashboard(time_filter, group_filter): """Update dashboard based on filter selections.""" # This would filter the data and regenerate visualizations # For now, return the same visualizations viz = create_visualizations(data_processor) return ( viz['hourly_distribution'], viz['group_size_distribution'], viz['popular_locations'], viz['time_heatmap'] ) def get_insights_html(): """Generate simplified HTML for insights display that works with Gradio.""" insights = data_processor.get_quick_insights() html_content = f"""

🚗 Fetii AI Assistant

Your intelligent companion for Austin rideshare analytics & insights

📊
{insights['total_trips']:,}
Total Trips Analyzed
{insights['avg_group_size']:.1f}
Average Group Size
{utils.format_time(insights['peak_hour'])}
Peak Hour
🎉
{insights['large_groups_pct']:.1f}%
Large Groups (6+)

🔥 Hottest Pickup Locations

Live Data
""" top_locations = list(insights['top_pickups'])[:6] colors = ['#667eea', '#764ba2', '#f093fb', '#f5576c', '#4facfe', '#00f2fe'] for i, (location, count) in enumerate(top_locations): color = colors[i % len(colors)] percentage = (count / insights['total_trips']) * 100 html_content += f"""
#{i+1} {location[:25]}{'...' if len(location) > 25 else ''}
{count} trips
{percentage:.1f}%
""" html_content += """
🌟
System Status
All Systems Operational
Response Time
< 200ms Average
🔄
Data Freshness
Updated 2min ago
""" return html_content def create_interface(): """Create the main Gradio interface.""" # Enhanced Custom CSS for Premium UI custom_css = """ @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'); /* Root Variables for Theme Management */ :root { --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%); --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); --success-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%); --warning-gradient: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%); --dark-gradient: linear-gradient(135deg, #2c3e50 0%, #34495e 100%); --light-bg: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%); --card-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); --hover-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); --text-primary: #1a202c; --text-secondary: #4a5568; --border-color: #e2e8f0; --success-color: #48bb78; --warning-color: #ed8936; --error-color: #f56565; } /* Main Container Styling */ .gradio-container { font-family: 'Inter', sans-serif !important; background: var(--light-bg) !important; min-height: 100vh; padding: 0 !important; margin: 0 !important; } /* Header Styling */ .main-header { background: var(--primary-gradient) !important; padding: 3rem 2rem !important; border-radius: 0 0 24px 24px !important; color: white !important; text-align: center !important; margin-bottom: 2rem !important; box-shadow: var(--card-shadow) !important; position: relative !important; overflow: hidden !important; } .main-header::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: url('data:image/svg+xml,') repeat; opacity: 0.1; animation: shimmer 3s ease-in-out infinite; } @keyframes shimmer { 0%, 100% { transform: translateX(-100%); } 50% { transform: translateX(100%); } } .main-header h1 { font-size: 3rem !important; font-weight: 800 !important; margin: 0 !important; letter-spacing: -0.05em !important; text-shadow: 2px 2px 4px rgba(0,0,0,0.3) !important; position: relative !important; z-index: 1 !important; } .main-header p { font-size: 1.25rem !important; margin: 1rem 0 0 0 !important; opacity: 0.95 !important; font-weight: 400 !important; letter-spacing: 0.025em !important; position: relative !important; z-index: 1 !important; } /* Enhanced Metric Cards */ .metric-card { background: rgba(255, 255, 255, 0.9) !important; backdrop-filter: blur(20px) !important; border: 1px solid rgba(255, 255, 255, 0.2) !important; padding: 2rem !important; border-radius: 20px !important; margin: 1rem 0 !important; box-shadow: var(--card-shadow) !important; transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) !important; position: relative !important; overflow: hidden !important; } .metric-card::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 4px; background: var(--primary-gradient); transform: scaleX(0); transition: transform 0.3s ease; } .metric-card:hover { transform: translateY(-8px) scale(1.02) !important; box-shadow: var(--hover-shadow) !important; background: rgba(255, 255, 255, 0.95) !important; } .metric-card:hover::before { transform: scaleX(1); } .metric-icon { font-size: 2.5rem !important; background: var(--primary-gradient) !important; -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important; background-clip: text !important; margin-bottom: 1rem !important; display: block !important; filter: drop-shadow(2px 2px 4px rgba(0,0,0,0.1)) !important; } .metric-value { font-size: 2.5rem !important; font-weight: 800 !important; margin: 0.5rem 0 !important; color: var(--text-primary) !important; line-height: 1.1 !important; background: var(--primary-gradient) !important; -webkit-background-clip: text !important; -webkit-text-fill-color: transparent !important; background-clip: text !important; } .metric-label { font-size: 0.9rem !important; margin: 0 !important; color: var(--text-secondary) !important; font-weight: 600 !important; letter-spacing: 0.05em !important; text-transform: uppercase !important; } /* Chat Interface Enhancements */ .chat-container { background: rgba(255, 255, 255, 0.95) !important; backdrop-filter: blur(20px) !important; border-radius: 24px !important; box-shadow: var(--card-shadow) !important; border: 1px solid rgba(255, 255, 255, 0.2) !important; overflow: hidden !important; transition: all 0.3s ease !important; } .chat-container:hover { box-shadow: var(--hover-shadow) !important; } /* Chart Container Improvements */ .chart-container { background: rgba(255, 255, 255, 0.95) !important; backdrop-filter: blur(20px) !important; border-radius: 20px !important; padding: 2rem !important; box-shadow: var(--card-shadow) !important; margin: 1rem 0 !important; border: 1px solid rgba(255, 255, 255, 0.2) !important; transition: all 0.3s ease !important; position: relative !important; overflow: hidden !important; } .chart-container::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--success-gradient); opacity: 0; transition: opacity 0.3s ease; } .chart-container:hover { transform: translateY(-4px) !important; box-shadow: var(--hover-shadow) !important; } .chart-container:hover::before { opacity: 1; } /* Tab Styling */ .tab-nav { background: rgba(255, 255, 255, 0.1) !important; backdrop-filter: blur(10px) !important; border-radius: 12px !important; padding: 4px !important; margin-bottom: 2rem !important; } .tab-nav button { background: transparent !important; border: none !important; padding: 12px 24px !important; border-radius: 8px !important; font-weight: 600 !important; color: var(--text-secondary) !important; transition: all 0.3s ease !important; position: relative !important; } .tab-nav button.selected { background: white !important; color: var(--text-primary) !important; box-shadow: 0 4px 12px rgba(0,0,0,0.1) !important; } /* Button Enhancements */ .gr-button { background: var(--primary-gradient) !important; border: none !important; border-radius: 12px !important; padding: 12px 24px !important; font-weight: 600 !important; color: white !important; transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) !important; box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4) !important; position: relative !important; overflow: hidden !important; } .gr-button::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); transition: left 0.5s; } .gr-button:hover { transform: translateY(-2px) scale(1.05) !important; box-shadow: 0 8px 25px rgba(102, 126, 234, 0.6) !important; } .gr-button:hover::before { left: 100%; } /* Input Field Styling */ .gr-textbox, .gr-input { border: 2px solid var(--border-color) !important; border-radius: 12px !important; padding: 12px 16px !important; font-size: 1rem !important; transition: all 0.3s ease !important; background: rgba(255, 255, 255, 0.9) !important; backdrop-filter: blur(10px) !important; } .gr-textbox:focus, .gr-input:focus { border-color: #667eea !important; box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1) !important; outline: none !important; } /* Accordion Improvements */ .gr-accordion { border: none !important; border-radius: 16px !important; margin-bottom: 1rem !important; background: rgba(255, 255, 255, 0.9) !important; backdrop-filter: blur(20px) !important; box-shadow: var(--card-shadow) !important; overflow: hidden !important; } .gr-accordion-header { background: var(--primary-gradient) !important; color: white !important; padding: 1rem 1.5rem !important; font-weight: 600 !important; border: none !important; transition: all 0.3s ease !important; } .gr-accordion-header:hover { background: var(--secondary-gradient) !important; } /* Loading Animation */ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.5; } } .loading { animation: pulse 2s infinite; } /* Responsive Design */ @media (max-width: 768px) { .main-header h1 { font-size: 2rem !important; } .main-header p { font-size: 1rem !important; } .metric-card { padding: 1.5rem !important; } .metric-value { font-size: 2rem !important; } } /* Scrollbar Styling */ ::-webkit-scrollbar { width: 8px; height: 8px; } ::-webkit-scrollbar-track { background: rgba(0,0,0,0.1); border-radius: 10px; } ::-webkit-scrollbar-thumb { background: var(--primary-gradient); border-radius: 10px; transition: all 0.3s ease; } ::-webkit-scrollbar-thumb:hover { background: var(--secondary-gradient); } /* Success/Error States */ .success { border-left: 4px solid var(--success-color) !important; background: rgba(72, 187, 120, 0.1) !important; } .warning { border-left: 4px solid var(--warning-color) !important; background: rgba(237, 137, 54, 0.1) !important; } .error { border-left: 4px solid var(--error-color) !important; background: rgba(245, 101, 101, 0.1) !important; } """ # Get visualizations viz = create_visualizations(data_processor) with gr.Blocks(css=custom_css, title="🚗 Fetii AI Assistant - Austin Rideshare Analytics", theme=gr.themes.Soft()) as demo: # Header and insights gr.HTML(get_insights_html()) # Main content with tabs for better organization with gr.Tabs() as tabs: with gr.TabItem("💬 AI Assistant", elem_id="chat-tab"): with gr.Row(): with gr.Column(scale=3): gr.HTML("""

🤖 Chat with Fetii AI

Ask me anything about Austin rideshare patterns and trends

""") # Enhanced example questions with categories gr.HTML("""

💡 Quick Start Questions

""") # Get example questions from config base_questions = config.CHATBOT_CONFIG['example_questions'] # Categorized example questions example_categories = { "📊 Popular Questions": [ "What are the peak hours for rideshare in Austin?", "Which locations have the most pickups?", "What's the average group size?" ], "📈 Trend Analysis": [ "Show me daily volume trends", "How do group sizes vary by time?", "What are the busiest days of the week?" ], "🎯 Advanced Insights": [ base_questions[0] if len(base_questions) > 0 else "How many groups went to The Aquarium on 6th last month?", base_questions[1] if len(base_questions) > 1 else "What are the top drop-off spots for large groups on Saturday nights?", base_questions[2] if len(base_questions) > 2 else "When do groups of 6+ riders typically ride downtown?" ] } for category, questions in example_categories.items(): gr.HTML(f"""

{category}

""") with gr.Row(): for question in questions: gr.Button( question, size="sm", variant="secondary", scale=1 ) # Enhanced chat interface chatbot_interface = gr.ChatInterface( fn=chat_response, textbox=gr.Textbox( placeholder="💭 Ask me about Austin rideshare patterns...", scale=7, container=False ), title="", description="", examples=[ "What are the peak hours for rideshare in Austin?", "Which locations have the most pickups?", "What's the average group size?", "Show me daily volume trends" ], cache_examples=False ) with gr.Column(scale=1): gr.HTML("""

📊 Quick Insights

🚗 Most Active Route
Downtown ↔ Airport
⏰ Rush Hour Peak
5:00 PM - 7:00 PM
📈 Trend Status
Growing +15%
""") with gr.TabItem("📊 Analytics Dashboard", elem_id="analytics-tab"): gr.HTML("""

📊 Interactive Analytics Dashboard

Explore detailed visualizations and trends with interactive filters

""") # Interactive filter controls time_filter, group_filter, refresh_btn = create_filter_controls() # Charts with state management with gr.Row(): with gr.Column(scale=1): with gr.Accordion("⏰ Peak Hours Analysis", open=True): hourly_plot = gr.Plot(value=viz['hourly_distribution']) with gr.Accordion("👥 Group Size Distribution", open=True): group_plot = gr.Plot(value=viz['group_size_distribution']) with gr.Column(scale=1): with gr.Accordion("📍 Popular Locations", open=True): location_plot = gr.Plot(value=viz['popular_locations']) with gr.Accordion("🗓️ Time Heatmap", open=False): heatmap_plot = gr.Plot(value=viz['time_heatmap']) # Connect filters to update function def on_filter_change(time_val, group_val): return update_dashboard(time_val, group_val) time_filter.change( fn=on_filter_change, inputs=[time_filter, group_filter], outputs=[hourly_plot, group_plot, location_plot, heatmap_plot] ) group_filter.change( fn=on_filter_change, inputs=[time_filter, group_filter], outputs=[hourly_plot, group_plot, location_plot, heatmap_plot] ) refresh_btn.click( fn=on_filter_change, inputs=[time_filter, group_filter], outputs=[hourly_plot, group_plot, location_plot, heatmap_plot] ) with gr.Row(): with gr.Column(): with gr.Accordion("📈 Daily Volume Trends", open=False): gr.Plot(value=viz['daily_volume']) with gr.Column(): with gr.Accordion("🆚 Pickup vs Dropoff", open=False): gr.Plot(value=viz['location_comparison']) with gr.TabItem("� Comprehensive Dashboard", elem_id="comprehensive-tab"): gr.HTML("""

📈 Comprehensive Analytics Dashboard

Complete overview of all analytics and insights

""") # All charts in a comprehensive view with gr.Row(): with gr.Column(scale=1): with gr.Accordion("⏰ Hourly Distribution", open=True): gr.Plot(value=viz['hourly_distribution']) with gr.Accordion("🗓️ Daily Volume Trends", open=True): gr.Plot(value=viz['daily_volume']) with gr.Accordion("🎯 Peak Patterns Analysis", open=False): gr.Plot(value=viz['peak_patterns']) with gr.Column(scale=1): with gr.Accordion("👥 Group Size Distribution", open=True): gr.Plot(value=viz['group_size_distribution']) with gr.Accordion("📍 Popular Locations", open=True): gr.Plot(value=viz['popular_locations']) with gr.Accordion("🆚 Location Comparison", open=False): gr.Plot(value=viz['location_comparison']) with gr.Column(scale=1): with gr.Accordion("🔥 Time Heatmap", open=True): gr.Plot(value=viz['time_heatmap']) with gr.Accordion("📏 Distance Analysis", open=False): gr.Plot(value=viz['trip_distance_analysis']) # Add summary metrics gr.HTML("""

📊 Quick Stats

Efficiency Score 87%
Satisfaction 94%
Growth Rate +15%
""") with gr.TabItem("�🔬 Advanced Analytics", elem_id="advanced-tab"): gr.HTML("""

🔬 Advanced Analytics & Insights

Deep dive into complex patterns and correlations

""") with gr.Row(): with gr.Column(): with gr.Accordion("🎯 Peak Patterns by Group Size", open=True): gr.Plot(value=viz['peak_patterns']) with gr.Column(): with gr.Accordion("📏 Distance Analysis", open=True): gr.Plot(value=viz['trip_distance_analysis']) with gr.Row(): with gr.Column(): with gr.Accordion("📈 Daily Volume Trends", open=False): gr.Plot(value=viz['daily_volume']) with gr.Column(): with gr.Accordion("🆚 Pickup vs Dropoff Analysis", open=False): gr.Plot(value=viz['location_comparison']) # Advanced metrics section gr.HTML("""

🧠 AI-Powered Insights

🎯
Demand Prediction
Next peak: 6:30 PM
💡
Route Optimization
12% efficiency gain possible
📊
Market Analysis
Growth opportunity detected
""") # Enhanced Footer gr.HTML("""
🚗

Fetii AI

Built with ❤️ using Gradio • Real Austin Data • Advanced AI Analytics

🔄 Real-time Updates
⚡ Lightning Fast
🛡️ Secure & Private
""") return demo def main(): """Launch the Gradio application.""" demo = create_interface() demo.launch( server_name="127.0.0.1", server_port=7860, share=False, show_api=False, show_error=True, quiet=False, inbrowser=True ) if __name__ == "__main__": main()