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() | |