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("""
""", 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
@st.cache_data
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"{row['name']}
Rating: {row.get('rating', 'N/A')}
Category: {row.get('category', 'N/A')}",
icon=folium.Icon(color=color)
).add_to(m)
return m
# Main App
def main():
# Header
st.markdown('
Your Smart Travel Guide for Safe & Smart City Navigation
', 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"""Category: {result.get('category', 'N/A')}
Rating: β {result.get('rating', 'N/A')}
Distance: {result.get('distance', calculate_distance(user_lat, user_lon, result['lat'], result['lon'])):.1f} km
Total Stops
Total Duration
Total Distance
Est. Budget
π AI City Companion - Your Smart Travel Guide
Built with β€οΈ for safe and smart city navigation | Hackathon MVP 2024
π¨ Emergency: Police (15) | Rescue (1122) | Fire (16)