Abs6187's picture
Updated New Version with Chat fix
cc4ec11 verified
import pandas as pd
import pydeck as pdk
import streamlit as st
from geopy.geocoders import Nominatim
# Optional imports handled inside functions or try-except blocks
# Try to import google.generativeai
try:
import google.generativeai as genai
GENAI_AVAILABLE = True
except ImportError:
GENAI_AVAILABLE = False
def get_coordinates(destination):
"""
Get latitude and longitude for a destination with error handling.
Args:
destination (str): Name of the destination.
Returns:
tuple: (latitude, longitude) or (28.6139, 77.2090) if not found (Delhi default).
"""
try:
geolocator = Nominatim(user_agent="travel_app")
location = geolocator.geocode(destination)
if location:
return location.latitude, location.longitude
else:
return 28.6139, 77.2090
except Exception as e:
print(f"Geocoding error: {e}")
return 28.6139, 77.2090
def find_nearby_attractions(destination, search_term, radius=5000, mongodb_uri=None, gemini_api_key=None):
"""
Find attractions near the specified destination using MongoDB vector search.
"""
if not mongodb_uri or not gemini_api_key:
return None
if not GENAI_AVAILABLE:
return None
try:
from pymongo import MongoClient
from bson import ObjectId
# Connect to MongoDB
client = MongoClient(mongodb_uri)
db_name = 'travel_india'
collection = client[db_name]['attractions']
# Get coordinates for the destination
lat, lon = get_coordinates(destination)
# Create the geo query
coordinates = [lon, lat]
# Create a new search ID for this query
search_id = ObjectId()
# Set up pipeline for geospatial pre-filtering
geo_pipeline = [
{
"$geoNear": {
"near": {"type": "Point", "coordinates": coordinates},
"distanceField": "distance",
"maxDistance": radius,
"spherical": True
}
},
{
"$addFields": {
"searchId": search_id
}
}
]
# Execute the pre-filtering
collection.aggregate(geo_pipeline)
# Configure Gemini and generate embeddings
genai.configure(api_key=gemini_api_key)
# Generative embedding using Gemini
embedding_result = genai.embed_content(
model="models/text-embedding-004",
content=search_term,
task_type="retrieval_query"
)
search_embedding = embedding_result['embedding']
# Vector search
vector_query = {
"$vectorSearch": {
"index": "vector_index",
"queryVector": search_embedding,
"path": "embedding",
"numCandidates": 10,
"limit": 5,
"filter": {"searchId": search_id}
}
}
results = list(collection.aggregate([vector_query]))
return {
"results": results,
"count": len(results),
"destination": destination,
"coordinates": coordinates
}
except Exception as e:
st.warning(f"Error using MongoDB search: {str(e)}")
return None
def render_map(destination, lat, lon, attractions_data=None):
"""
Render a PyDeck map with the destination and optionally nearby attractions.
Args:
destination (str): Name of the destination.
lat (float): Latitude.
lon (float): Longitude.
attractions_data (list): List of attraction dictionaries from MongoDB results.
"""
# Base destination data
map_data = [{
'lat': lat,
'lon': lon,
'name': destination,
'description': "Your destination",
'color': [255, 103, 31, 200], # Saffron
'radius': 1000
}]
if attractions_data:
for att in attractions_data:
map_data.append({
'lat': att["location"]["coordinates"][1],
'lon': att["location"]["coordinates"][0],
'name': att.get("name", "Attraction"),
'description': att.get("description", ""),
'color': [4, 106, 56, 200], # Green
'radius': 500
})
df = pd.DataFrame(map_data)
view_state = pdk.ViewState(latitude=lat, longitude=lon, zoom=11, pitch=50)
text_layer = pdk.Layer(
'TextLayer',
data=df,
get_position='[lon, lat]',
get_text='name',
get_size=16,
get_color=[0, 0, 0, 200],
get_angle=0,
get_text_anchor='"middle"',
get_alignment_baseline='"bottom"',
)
scatter_layer = pdk.Layer(
'ScatterplotLayer',
data=df,
get_position='[lon, lat]',
get_color='color',
get_radius='radius',
pickable=True,
)
st.pydeck_chart(pdk.Deck(
map_style=None,
initial_view_state=view_state,
layers=[scatter_layer, text_layer],
tooltip={"text": "{name}\n{description}"}
))
def extract_locations_from_itinerary(itinerary_text, gemini_api_key):
"""
Use Gemini to extract structured location data from the itinerary text.
"""
if not GENAI_AVAILABLE or not gemini_api_key:
return []
try:
genai.configure(api_key=gemini_api_key)
model = genai.GenerativeModel('gemini-2.5-flash')
prompt = f"""
Extract all specific locations (cities, tourist attractions, hotels, restaurants) mentioned in this travel itinerary.
Return a JSON list of objects. Each object must have:
- "name": Name of the place
- "latitude": Approximate latitude (float)
- "longitude": Approximate longitude (float)
- "day": Day number (integer, if mentioned, else 1)
- "description": Brief context from text (e.g., "Day 1 activity")
Itinerary:
{itinerary_text[:10000]}
Return ONLY valid JSON.
"""
response = model.generate_content(prompt)
text = response.text
# Clean markdown code blocks if present
if "```json" in text:
text = text.split("```json")[1].split("```")[0]
elif "```" in text:
text = text.split("```")[1].split("```")[0]
import json
locations = json.loads(text)
return locations
except Exception as e:
st.warning(f"Could not extract locations: {e}")
return []
def render_itinerary_map(locations):
"""
Render a map showing the itinerary route.
"""
if not locations:
st.warning("No locations found to visualize.")
return
df = pd.DataFrame(locations)
# Calculate center
lat = df['latitude'].mean()
lon = df['longitude'].mean()
view_state = pdk.ViewState(latitude=lat, longitude=lon, zoom=10, pitch=50)
# Scatter layer for points
scatter_layer = pdk.Layer(
'ScatterplotLayer',
data=df,
get_position='[longitude, latitude]',
get_color=[255, 0, 0, 200],
get_radius=800,
pickable=True,
)
# Text layer for labels
text_layer = pdk.Layer(
'TextLayer',
data=df,
get_position='[longitude, latitude]',
get_text='name',
get_size=16,
get_color=[0, 0, 0, 200],
get_angle=0,
get_text_anchor='"middle"',
get_alignment_baseline='"bottom"',
)
# Path layer to connect points (sorted by day)
path_data = []
if 'day' in df.columns:
df_sorted = df.sort_values('day')
path = df_sorted[['longitude', 'latitude']].values.tolist()
path_data = [{'path': path, 'color': [0, 0, 255, 150]}]
path_layer = pdk.Layer(
'PathLayer',
data=path_data,
pickable=True,
width_scale=20,
width_min_pixels=2,
get_path='path',
get_color='color',
get_width=5
)
st.pydeck_chart(pdk.Deck(
map_style=None,
initial_view_state=view_state,
layers=[path_layer, scatter_layer, text_layer],
tooltip={"text": "Day {day}: {name}\n{description}"}
))