Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import plotly.express as px | |
| import plotly.graph_objects as go | |
| from datetime import datetime, timedelta | |
| import folium | |
| from streamlit_folium import st_folium | |
| import requests | |
| from geopy.distance import geodesic | |
| import time | |
| # Page configuration | |
| st.set_page_config( | |
| page_title="AI City Companion", | |
| page_icon="π", | |
| layout="wide", | |
| initial_sidebar_state="expanded" | |
| ) | |
| # Custom CSS for modern styling | |
| st.markdown(""" | |
| <style> | |
| .main-header { | |
| font-size: 3rem; | |
| font-weight: bold; | |
| text-align: center; | |
| background: linear-gradient(90deg, #667eea 0%, #764ba2 100%); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| margin-bottom: 2rem; | |
| } | |
| .feature-card { | |
| background: white; | |
| padding: 1.5rem; | |
| border-radius: 10px; | |
| box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); | |
| margin: 1rem 0; | |
| border-left: 4px solid #667eea; | |
| } | |
| .emergency-alert { | |
| background: #fee2e2; | |
| border: 1px solid #fecaca; | |
| border-radius: 8px; | |
| padding: 1rem; | |
| margin: 1rem 0; | |
| color: #991b1b; | |
| } | |
| .success-alert { | |
| background: #dcfce7; | |
| border: 1px solid #bbf7d0; | |
| border-radius: 8px; | |
| padding: 1rem; | |
| margin: 1rem 0; | |
| color: #166534; | |
| } | |
| .metric-card { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| color: white; | |
| padding: 1rem; | |
| border-radius: 10px; | |
| text-align: center; | |
| margin: 0.5rem; | |
| } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # Initialize session state | |
| if 'user_location' not in st.session_state: | |
| st.session_state.user_location = [24.8607, 67.0011] # Karachi, Pakistan | |
| if 'user_preferences' not in st.session_state: | |
| st.session_state.user_preferences = {} | |
| if 'search_history' not in st.session_state: | |
| st.session_state.search_history = [] | |
| if 'current_itinerary' not in st.session_state: | |
| st.session_state.current_itinerary = [] | |
| # Mock data for demonstration | |
| def load_mock_data(): | |
| # Healthcare & Emergency | |
| healthcare_data = pd.DataFrame({ | |
| 'name': ['City Hospital', 'Emergency Clinic 24/7', 'Al-Shifa Medical Center', 'Quick Care Pharmacy', 'Blood Bank Center'], | |
| 'category': ['Hospital', 'Clinic', 'Hospital', 'Pharmacy', 'Blood Bank'], | |
| 'lat': [24.8615, 24.8590, 24.8625, 24.8580, 24.8635], | |
| 'lon': [67.0020, 67.0000, 67.0040, 66.9990, 67.0050], | |
| 'rating': [4.5, 4.2, 4.7, 4.0, 4.3], | |
| 'distance': [0.5, 0.8, 0.3, 1.2, 0.7], | |
| 'phone': ['+92-21-111-222', '+92-21-333-444', '+92-21-555-666', '+92-21-777-888', '+92-21-999-000'], | |
| 'open_24h': [True, True, False, False, True] | |
| }) | |
| # Food & Restaurants | |
| food_data = pd.DataFrame({ | |
| 'name': ['Halal Biryani House', 'Vegetarian Delight', 'Quick Bites Cafe', 'Traditional Karahi', 'Fresh Juice Corner'], | |
| 'category': ['Pakistani', 'Vegetarian', 'Fast Food', 'Pakistani', 'Beverages'], | |
| 'lat': [24.8600, 24.8620, 24.8585, 24.8640, 24.8575], | |
| 'lon': [67.0015, 67.0035, 66.9995, 67.0055, 66.9985], | |
| 'rating': [4.6, 4.3, 4.1, 4.8, 4.2], | |
| 'price_range': ['$$', '$', '$', '$$$', '$'], | |
| 'dietary': ['Halal', 'Vegetarian', 'Mixed', 'Halal', 'Vegan'], | |
| 'crowd_level': ['Medium', 'Low', 'High', 'Medium', 'Low'], | |
| 'noise_level': ['Medium', 'Low', 'High', 'Medium', 'Low'] | |
| }) | |
| # Electronics & Repairs | |
| electronics_data = pd.DataFrame({ | |
| 'name': ['TechMart Electronics', 'Mobile Repair Hub', 'Laptop Service Center', 'Gadget World', 'SIM Card Center'], | |
| 'category': ['Electronics Store', 'Repair Shop', 'Repair Shop', 'Electronics Store', 'Telecom'], | |
| 'lat': [24.8610, 24.8595, 24.8630, 24.8570, 24.8645], | |
| 'lon': [67.0025, 67.0005, 67.0045, 66.9980, 67.0060], | |
| 'rating': [4.4, 4.1, 4.5, 4.3, 4.0], | |
| 'services': ['Phones, Laptops, Accessories', 'Phone Repair', 'Laptop Repair', 'All Electronics', 'SIM Cards, Top-up'], | |
| 'price_fair': [True, True, False, True, True] | |
| }) | |
| # Attractions & Places | |
| attractions_data = pd.DataFrame({ | |
| 'name': ['Clifton Beach', 'Quaid Mausoleum', 'Empress Market', 'Karachi Zoo', 'Port Grand'], | |
| 'category': ['Beach', 'Monument', 'Market', 'Zoo', 'Entertainment'], | |
| 'lat': [24.8138, 24.8738, 24.8615, 24.9056, 24.8406], | |
| 'lon': [67.0299, 67.0362, 67.0099, 67.0516, 67.0219], | |
| 'rating': [4.2, 4.7, 4.0, 3.8, 4.1], | |
| 'best_time': ['Evening', 'Morning', 'Morning', 'Morning', 'Evening'], | |
| 'crowd_level': ['High', 'Medium', 'High', 'Medium', 'Medium'], | |
| 'entry_fee': [0, 0, 0, 50, 0] | |
| }) | |
| return healthcare_data, food_data, electronics_data, attractions_data | |
| # Load data | |
| healthcare_df, food_df, electronics_df, attractions_df = load_mock_data() | |
| # Helper functions | |
| def calculate_distance(lat1, lon1, lat2, lon2): | |
| return geodesic((lat1, lon1), (lat2, lon2)).kilometers | |
| def get_recommendations(category, user_prefs=None): | |
| if category == "healthcare": | |
| return healthcare_df.sort_values('rating', ascending=False) | |
| elif category == "food": | |
| df = food_df.copy() | |
| if user_prefs and 'dietary' in user_prefs: | |
| df = df[df['dietary'].str.contains(user_prefs['dietary'], case=False, na=False)] | |
| if user_prefs and 'crowd_preference' in user_prefs: | |
| if user_prefs['crowd_preference'] == 'Low': | |
| df = df[df['crowd_level'] == 'Low'] | |
| return df.sort_values('rating', ascending=False) | |
| elif category == "electronics": | |
| return electronics_df.sort_values('rating', ascending=False) | |
| elif category == "attractions": | |
| return attractions_df.sort_values('rating', ascending=False) | |
| def create_map(data_df, center_lat, center_lon): | |
| m = folium.Map(location=[center_lat, center_lon], zoom_start=13) | |
| # Add user location | |
| folium.Marker( | |
| [center_lat, center_lon], | |
| popup="Your Location", | |
| icon=folium.Icon(color='red', icon='user') | |
| ).add_to(m) | |
| # Add points of interest | |
| colors = {'Hospital': 'green', 'Clinic': 'blue', 'Pharmacy': 'orange', | |
| 'Pakistani': 'red', 'Vegetarian': 'green', 'Fast Food': 'orange', | |
| 'Electronics Store': 'purple', 'Repair Shop': 'darkblue', | |
| 'Beach': 'lightblue', 'Monument': 'gray', 'Market': 'orange'} | |
| for idx, row in data_df.iterrows(): | |
| color = colors.get(row.get('category', 'Unknown'), 'gray') | |
| folium.Marker( | |
| [row['lat'], row['lon']], | |
| popup=f"<b>{row['name']}</b><br>Rating: {row.get('rating', 'N/A')}<br>Category: {row.get('category', 'N/A')}", | |
| icon=folium.Icon(color=color) | |
| ).add_to(m) | |
| return m | |
| # Main App | |
| def main(): | |
| # Header | |
| st.markdown('<h1 class="main-header">π AI City Companion</h1>', unsafe_allow_html=True) | |
| st.markdown('<p style="text-align: center; font-size: 1.2rem; color: #666;">Your Smart Travel Guide for Safe & Smart City Navigation</p>', unsafe_allow_html=True) | |
| # Sidebar for user preferences | |
| with st.sidebar: | |
| st.header("π― Your Preferences") | |
| # Location input | |
| st.subheader("π Current Location") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| user_lat = st.number_input("Latitude", value=24.8607, format="%.4f") | |
| with col2: | |
| user_lon = st.number_input("Longitude", value=67.0011, format="%.4f") | |
| st.session_state.user_location = [user_lat, user_lon] | |
| # Personal preferences | |
| st.subheader("π€ Personal Preferences") | |
| dietary_pref = st.selectbox("Dietary Preference", ["Any", "Halal", "Vegetarian", "Vegan"]) | |
| crowd_pref = st.selectbox("Crowd Preference", ["Any", "Low", "Medium", "High"]) | |
| budget_pref = st.selectbox("Budget Range", ["Any", "$", "$$", "$$$"]) | |
| st.session_state.user_preferences = { | |
| 'dietary': dietary_pref, | |
| 'crowd_preference': crowd_pref, | |
| 'budget': budget_pref | |
| } | |
| # Emergency contacts | |
| st.subheader("π¨ Quick Emergency") | |
| if st.button("π₯ Nearest Hospital", use_container_width=True): | |
| st.session_state.emergency_mode = True | |
| if st.button("π Police Station", use_container_width=True): | |
| st.info("Emergency: 15 (Police)") | |
| if st.button("π Ambulance", use_container_width=True): | |
| st.info("Emergency: 1122 (Rescue)") | |
| # Main content tabs | |
| tab1, tab2, tab3, tab4, tab5 = st.tabs(["πΊοΈ Smart Map", "π AI Search", "π Itinerary Builder", "π City Insights", "βοΈ Settings"]) | |
| with tab1: | |
| st.header("πΊοΈ Smart Contextual City Map") | |
| # Map controls | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| map_category = st.selectbox("Show Category", ["All", "Healthcare", "Food", "Electronics", "Attractions"]) | |
| with col2: | |
| time_filter = st.selectbox("Time Filter", ["Current", "Morning", "Afternoon", "Evening", "Night"]) | |
| with col3: | |
| radius_km = st.slider("Search Radius (km)", 0.5, 10.0, 2.0) | |
| with col4: | |
| show_traffic = st.checkbox("Show Traffic Info") | |
| # Create and display map | |
| if map_category == "All": | |
| all_data = pd.concat([healthcare_df, food_df, electronics_df, attractions_df], ignore_index=True) | |
| elif map_category == "Healthcare": | |
| all_data = healthcare_df | |
| elif map_category == "Food": | |
| all_data = get_recommendations("food", st.session_state.user_preferences) | |
| elif map_category == "Electronics": | |
| all_data = electronics_df | |
| elif map_category == "Attractions": | |
| all_data = attractions_df | |
| # Filter by radius | |
| all_data['distance_calc'] = all_data.apply( | |
| lambda row: calculate_distance(user_lat, user_lon, row['lat'], row['lon']), axis=1 | |
| ) | |
| filtered_data = all_data[all_data['distance_calc'] <= radius_km] | |
| if not filtered_data.empty: | |
| map_obj = create_map(filtered_data, user_lat, user_lon) | |
| st_folium(map_obj, width=700, height=500) | |
| # Show nearby places | |
| st.subheader(f"π Nearby Places ({len(filtered_data)} found)") | |
| for idx, row in filtered_data.head(5).iterrows(): | |
| with st.expander(f"{row['name']} - {row.get('category', 'Unknown')} ({row['distance_calc']:.1f}km)"): | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.write(f"β Rating: {row.get('rating', 'N/A')}") | |
| st.write(f"π Phone: {row.get('phone', 'N/A')}") | |
| with col2: | |
| if 'services' in row: | |
| st.write(f"π§ Services: {row['services']}") | |
| if 'dietary' in row: | |
| st.write(f"π½οΈ Dietary: {row['dietary']}") | |
| else: | |
| st.warning("No places found in the selected radius. Try increasing the search area.") | |
| with tab2: | |
| st.header("π AI-Powered Smart Search") | |
| # Multi-modal search | |
| search_type = st.radio("Search Type", ["Text Query", "Voice Command (Simulated)", "Image Upload (Simulated)"]) | |
| if search_type == "Text Query": | |
| query = st.text_input("Ask me anything about the city:", | |
| placeholder="e.g., 'Find halal biryani that's not crowded' or 'Where can I fix my laptop?'") | |
| if query: | |
| st.session_state.search_history.append({"query": query, "timestamp": datetime.now()}) | |
| # Simple AI simulation | |
| results = [] | |
| query_lower = query.lower() | |
| if any(word in query_lower for word in ['hospital', 'doctor', 'medical', 'emergency']): | |
| results = healthcare_df.head(3).to_dict('records') | |
| st.success("π₯ Found healthcare facilities for you!") | |
| elif any(word in query_lower for word in ['food', 'eat', 'restaurant', 'biryani', 'halal']): | |
| results = get_recommendations("food", st.session_state.user_preferences).head(3).to_dict('records') | |
| st.success("π½οΈ Found great food options!") | |
| elif any(word in query_lower for word in ['laptop', 'phone', 'repair', 'electronics', 'charger']): | |
| results = electronics_df.head(3).to_dict('records') | |
| st.success("π§ Found electronics and repair services!") | |
| elif any(word in query_lower for word in ['visit', 'see', 'attraction', 'tourist']): | |
| results = attractions_df.head(3).to_dict('records') | |
| st.success("π― Found amazing places to visit!") | |
| else: | |
| st.info("π€ I'm learning! Try asking about healthcare, food, electronics, or attractions.") | |
| # Display results | |
| if results: | |
| for result in results: | |
| with st.container(): | |
| st.markdown(f""" | |
| <div class="feature-card"> | |
| <h4>{result['name']}</h4> | |
| <p><strong>Category:</strong> {result.get('category', 'N/A')}</p> | |
| <p><strong>Rating:</strong> β {result.get('rating', 'N/A')}</p> | |
| <p><strong>Distance:</strong> {result.get('distance', calculate_distance(user_lat, user_lon, result['lat'], result['lon'])):.1f} km</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| elif search_type == "Voice Command (Simulated)": | |
| st.info("π€ Voice search simulation - Click to 'speak'") | |
| if st.button("ποΈ Start Voice Search"): | |
| with st.spinner("Listening..."): | |
| time.sleep(2) | |
| st.success("Voice recognized: 'Find nearest pharmacy'") | |
| results = healthcare_df[healthcare_df['category'] == 'Pharmacy'] | |
| for idx, row in results.iterrows(): | |
| st.write(f"π {row['name']} - {row['distance']}km away") | |
| else: # Image Upload | |
| st.info("πΈ Image search simulation") | |
| uploaded_file = st.file_uploader("Upload an image of what you're looking for", type=['jpg', 'jpeg', 'png']) | |
| if uploaded_file: | |
| st.image(uploaded_file, caption="Analyzing image...", width=300) | |
| with st.spinner("AI analyzing image..."): | |
| time.sleep(2) | |
| st.success("π Detected: Broken phone charger") | |
| st.write("Found electronics repair shops nearby:") | |
| repair_shops = electronics_df[electronics_df['category'] == 'Repair Shop'] | |
| for idx, row in repair_shops.iterrows(): | |
| st.write(f"π§ {row['name']} - {row['services']}") | |
| with tab3: | |
| st.header("π Smart Itinerary Builder") | |
| # Itinerary preferences | |
| st.subheader("π― Tell me about your day") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| duration = st.selectbox("Trip Duration", ["Half Day (4 hours)", "Full Day (8 hours)", "Weekend (2 days)"]) | |
| walking_pref = st.selectbox("Walking Preference", ["Minimal walking", "Moderate walking", "Lots of walking"]) | |
| interests = st.multiselect("Interests", ["Food", "Shopping", "Culture", "Nature", "Technology", "Healthcare"]) | |
| with col2: | |
| budget = st.selectbox("Budget Range", ["Budget ($)", "Mid-range ($$)", "Premium ($$$)"]) | |
| group_size = st.number_input("Group Size", min_value=1, max_value=10, value=1) | |
| special_needs = st.multiselect("Special Requirements", ["Wheelchair accessible", "Halal food only", "Quiet places", "Female-friendly"]) | |
| if st.button("π Generate Smart Itinerary", use_container_width=True): | |
| with st.spinner("AI is crafting your perfect day..."): | |
| time.sleep(3) | |
| # Generate sample itinerary | |
| itinerary = [ | |
| {"time": "09:00 AM", "activity": "Breakfast at Halal Biryani House", "duration": "1 hour", "type": "food"}, | |
| {"time": "10:30 AM", "activity": "Visit Quaid Mausoleum", "duration": "1.5 hours", "type": "culture"}, | |
| {"time": "12:30 PM", "activity": "Electronics shopping at TechMart", "duration": "1 hour", "type": "shopping"}, | |
| {"time": "02:00 PM", "activity": "Lunch at Traditional Karahi", "duration": "1 hour", "type": "food"}, | |
| {"time": "04:00 PM", "activity": "Relax at Clifton Beach", "duration": "2 hours", "type": "nature"}, | |
| {"time": "06:30 PM", "activity": "Dinner at Port Grand", "duration": "1.5 hours", "type": "food"} | |
| ] | |
| st.session_state.current_itinerary = itinerary | |
| st.success("β Your personalized itinerary is ready!") | |
| # Display itinerary | |
| for i, item in enumerate(itinerary): | |
| with st.expander(f"{item['time']} - {item['activity']} ({item['duration']})"): | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| st.write(f"β° Duration: {item['duration']}") | |
| with col2: | |
| st.write(f"π·οΈ Type: {item['type'].title()}") | |
| with col3: | |
| if st.button(f"Get Directions", key=f"dir_{i}"): | |
| st.info("πΊοΈ Opening navigation...") | |
| # Itinerary summary | |
| st.subheader("π Itinerary Summary") | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.markdown('<div class="metric-card"><h3>6</h3><p>Total Stops</p></div>', unsafe_allow_html=True) | |
| with col2: | |
| st.markdown('<div class="metric-card"><h3>8.5h</h3><p>Total Duration</p></div>', unsafe_allow_html=True) | |
| with col3: | |
| st.markdown('<div class="metric-card"><h3>5.2km</h3><p>Total Distance</p></div>', unsafe_allow_html=True) | |
| with col4: | |
| st.markdown('<div class="metric-card"><h3>$$</h3><p>Est. Budget</p></div>', unsafe_allow_html=True) | |
| with tab4: | |
| st.header("π City Insights & Analytics") | |
| # Real-time city stats | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.metric("π‘οΈ Temperature", "28Β°C", "2Β°C") | |
| with col2: | |
| st.metric("π¦ Traffic Level", "Medium", "β 15%") | |
| with col3: | |
| st.metric("π₯ Crowd Density", "Low", "β 5%") | |
| with col4: | |
| st.metric("π° Price Index", "Moderate", "β 2%") | |
| # Charts and analytics | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.subheader("π Popular Categories") | |
| category_data = pd.DataFrame({ | |
| 'Category': ['Food', 'Healthcare', 'Electronics', 'Attractions', 'Shopping'], | |
| 'Searches': [45, 23, 18, 32, 28] | |
| }) | |
| fig = px.bar(category_data, x='Category', y='Searches', | |
| title="Most Searched Categories Today") | |
| st.plotly_chart(fig, use_container_width=True) | |
| with col2: | |
| st.subheader("β° Best Times to Visit") | |
| time_data = pd.DataFrame({ | |
| 'Hour': list(range(6, 23)), | |
| 'Crowd_Level': [20, 30, 45, 60, 70, 85, 90, 95, 80, 70, 60, 50, 45, 55, 70, 85, 90] | |
| }) | |
| fig = px.line(time_data, x='Hour', y='Crowd_Level', | |
| title="Crowd Levels Throughout the Day") | |
| st.plotly_chart(fig, use_container_width=True) | |
| # Safety alerts | |
| st.subheader("π‘οΈ Safety & Alerts") | |
| alerts = [ | |
| {"type": "warning", "message": "Heavy traffic on Shahrah-e-Faisal (avoid 5-7 PM)"}, | |
| {"type": "info", "message": "New electronics market opened in Saddar"}, | |
| {"type": "success", "message": "All hospitals report normal capacity"}, | |
| ] | |
| for alert in alerts: | |
| if alert["type"] == "warning": | |
| st.warning(f"β οΈ {alert['message']}") | |
| elif alert["type"] == "info": | |
| st.info(f"βΉοΈ {alert['message']}") | |
| else: | |
| st.success(f"β {alert['message']}") | |
| with tab5: | |
| st.header("βοΈ Settings & Preferences") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.subheader("π Notifications") | |
| st.checkbox("Emergency alerts", value=True) | |
| st.checkbox("Traffic updates", value=True) | |
| st.checkbox("Price alerts", value=False) | |
| st.checkbox("New place recommendations", value=True) | |
| st.subheader("π Language & Region") | |
| language = st.selectbox("Language", ["English", "Urdu", "Arabic"]) | |
| currency = st.selectbox("Currency", ["PKR", "USD", "EUR"]) | |
| with col2: | |
| st.subheader("π Privacy & Safety") | |
| st.checkbox("Share location for better recommendations", value=True) | |
| st.checkbox("Save search history", value=True) | |
| st.checkbox("Anonymous usage analytics", value=False) | |
| st.subheader("π± App Preferences") | |
| theme = st.selectbox("Theme", ["Auto", "Light", "Dark"]) | |
| map_style = st.selectbox("Map Style", ["Standard", "Satellite", "Terrain"]) | |
| # Export data | |
| st.subheader("π€ Export Your Data") | |
| if st.button("Download Search History"): | |
| if st.session_state.search_history: | |
| df = pd.DataFrame(st.session_state.search_history) | |
| st.download_button( | |
| label="π₯ Download CSV", | |
| data=df.to_csv(index=False), | |
| file_name="search_history.csv", | |
| mime="text/csv" | |
| ) | |
| else: | |
| st.info("No search history to export yet!") | |
| if st.button("Download Current Itinerary"): | |
| if st.session_state.current_itinerary: | |
| df = pd.DataFrame(st.session_state.current_itinerary) | |
| st.download_button( | |
| label="π₯ Download Itinerary", | |
| data=df.to_csv(index=False), | |
| file_name="my_itinerary.csv", | |
| mime="text/csv" | |
| ) | |
| else: | |
| st.info("No itinerary created yet!") | |
| # Footer | |
| st.markdown("---") | |
| st.markdown(""" | |
| <div style="text-align: center; color: #666; padding: 2rem;"> | |
| <p>π <strong>AI City Companion</strong> - Your Smart Travel Guide</p> | |
| <p>Built with β€οΈ for safe and smart city navigation | Hackathon MVP 2024</p> | |
| <p>π¨ Emergency: Police (15) | Rescue (1122) | Fire (16)</p> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| if __name__ == "__main__": | |
| main() | |