import streamlit as st
from datetime import datetime, timedelta
import base64
import pandas as pd
import pydeck as pdk
from travel import (
destination_research_task, accommodation_task, transportation_task,
activities_task, dining_task, itinerary_task, chatbot_task,
run_task
)
from geopy.geocoders import Nominatim
from io import BytesIO
st.set_page_config(
page_title="Your AI Agent for Travelling",
page_icon="βοΈ",
layout="wide",
initial_sidebar_state="expanded"
)
# ------------------------------------------------------
# CSS Styles for the App
# ------------------------------------------------------
st.markdown("""
""", unsafe_allow_html=True)
# ------------------------------------------------------
# Helper Functions
# ------------------------------------------------------
def get_download_link(text_content, filename):
"""Generate a download link for the itinerary text file."""
b64 = base64.b64encode(text_content.encode()).decode()
href = f'π₯ Save Your Itinerary'
return href
def display_modern_progress(current_step, total_steps=6):
"""Displays a progress bar and step indicators."""
if 'progress_steps' not in st.session_state:
st.session_state.progress_steps = {
0: {'status': 'pending', 'name': "Trip Details"},
1: {'status': 'pending', 'name': "About"},
2: {'status': 'pending', 'name': "Travel Style"},
3: {'status': 'pending', 'name': "Live Agent Outputs"},
4: {'status': 'pending', 'name': "Download & Share"},
5: {'status': 'pending', 'name': "Full Itinerary"}
}
for i in range(total_steps):
if i < current_step:
st.session_state.progress_steps[i]['status'] = 'complete'
elif i == current_step:
st.session_state.progress_steps[i]['status'] = 'active'
else:
st.session_state.progress_steps[i]['status'] = 'pending'
progress_percentage = (current_step / total_steps) * 100
st.progress(progress_percentage / 100)
# Display step grid
st.markdown("""
""", unsafe_allow_html=True)
for i, step_info in st.session_state.progress_steps.items():
status = step_info['status']
name = step_info['name']
if status == 'complete':
icon = "β
"
status_class = "complete"
elif status == 'active':
icon = "π"
status_class = "active"
else:
icon = "β"
status_class = "pending"
st.markdown(f"""
{icon}
{name}
""", unsafe_allow_html=True)
st.markdown('
', unsafe_allow_html=True)
return progress_percentage
def update_step_status(step_index, status):
"""Update the status (pending, active, complete) for a given step index."""
if 'progress_steps' in st.session_state and step_index in st.session_state.progress_steps:
st.session_state.progress_steps[step_index]['status'] = status
def run_task_with_logs(task, input_text, log_container, output_container, results_key=None):
"""Runs a task with logging in a separate container."""
if 'log_messages' not in st.session_state:
st.session_state.log_messages = []
log_message = f"π€ Starting {task.agent.role}..."
st.session_state.log_messages.append(log_message)
with log_container:
st.markdown("### Agent Activity")
for msg in st.session_state.log_messages:
st.markdown(msg)
result = run_task(task, input_text)
if results_key:
st.session_state.results[results_key] = result
log_message = f"β
{task.agent.role} completed!"
st.session_state.log_messages.append(log_message)
with log_container:
st.markdown("### Agent Activity")
for msg in st.session_state.log_messages:
st.markdown(msg)
with output_container:
st.markdown(f"### {task.agent.role} Output")
st.markdown("" + result + "
", unsafe_allow_html=True)
return result
# ------------------------------------------------------
# Session State Initialization
# ------------------------------------------------------
if 'generated_itinerary' not in st.session_state:
st.session_state.generated_itinerary = None
if 'generation_complete' not in st.session_state:
st.session_state.generation_complete = False
if 'current_step' not in st.session_state:
st.session_state.current_step = 0
if 'results' not in st.session_state:
st.session_state.results = {
"destination_info": "",
"accommodation_info": "",
"transportation_info": "",
"activities_info": "",
"dining_info": "",
"itinerary": "",
"final_itinerary": ""
}
if 'log_messages' not in st.session_state:
st.session_state.log_messages = []
if 'current_output' not in st.session_state:
st.session_state.current_output = None
if 'form_submitted' not in st.session_state:
st.session_state.form_submitted = False
col1, col2, col3 = st.columns([1,2,1])
with col2:
st.image("assets/image.png", width=350)
st.markdown(f"""
Your AI Agent for Travelling
β¨ Create your personalized AI-powered travel itinerary in minutes! β¨
""", unsafe_allow_html=True)
st.markdown('
', unsafe_allow_html=True)
with st.sidebar:
st.image("assets/image.png", width=250)
st.markdown("""
Namude Yatra: The beginning of your dream journey
AI-Powered Agentic Travel Planning
""", unsafe_allow_html=True)
st.markdown('', unsafe_allow_html=True)
st.markdown('', unsafe_allow_html=True)
st.markdown('', unsafe_allow_html=True)
# ------------------------------------------------------
# Main Form
# ------------------------------------------------------
if not st.session_state.generation_complete:
st.markdown('', unsafe_allow_html=True)
st.markdown("
βοΈ Create Your Itinerary
", unsafe_allow_html=True)
st.markdown("""
Complete the form below for a personalized travel plan.
""", unsafe_allow_html=True)
with st.form("travel_form"):
col1, col2 = st.columns(2)
with col1:
st.markdown('
Trip Details
', unsafe_allow_html=True)
origin = st.text_input("Origin", placeholder="e.g., New York, USA")
destination = st.text_input("Destination", placeholder="e.g., Paris, France")
st.markdown('
Travel Dates
', unsafe_allow_html=True)
start_date = st.date_input("Start Date", min_value=datetime.now(), label_visibility="collapsed")
duration = st.slider("Duration (days)", min_value=1, max_value=30, value=7)
end_date = start_date + timedelta(days=duration-1)
st.markdown(f'
{start_date.strftime("%b %d")} - {end_date.strftime("%b %d, %Y")}
', unsafe_allow_html=True)
with col2:
st.markdown('
Preferences
', unsafe_allow_html=True)
travelers = st.number_input("Travelers", min_value=1, max_value=15, value=2)
budget_options = ["Budget", "Moderate", "Luxury"]
budget = st.selectbox("Budget", budget_options, help="Budget: Economy options | Moderate: Mid-range | Luxury: High-end experiences")
travel_style = st.multiselect("Travel Style", options=["Culture", "Adventure", "Relaxation", "Food & Dining", "Nature", "Shopping", "Nightlife", "Family-friendly"], default=["Culture", "Food & Dining"])
with st.expander("Additional Preferences"):
preferences = st.text_area("Interests", placeholder="History museums, local cuisine, hiking, art...")
special_requirements = st.text_area("Special Requirements", placeholder="Dietary restrictions, accessibility needs...")
submit_button = st.form_submit_button("π Create My Personal Travel Itinerary")
st.markdown('
', unsafe_allow_html=True)
if submit_button:
if not origin or not destination:
st.error("Please enter both origin and destination.")
else:
st.session_state.form_submitted = True
st.session_state.destination = destination
user_input = {
"origin": origin,
"destination": destination,
"duration": str(duration),
"travel_dates": f"{start_date.strftime('%Y-%m-%d')} to {end_date.strftime('%Y-%m-%d')}",
"travelers": str(travelers),
"budget": budget.lower(),
"travel_style": ", ".join(travel_style),
"preferences": preferences,
"special_requirements": special_requirements
}
st.session_state.user_input = user_input
input_context = f"""Travel Request Details:
Origin: {user_input['origin']}
Destination: {user_input['destination']}
Duration: {user_input['duration']} days
Travel Dates: {user_input['travel_dates']}
Travelers: {user_input['travelers']}
Budget Level: {user_input['budget']}
Travel Style: {user_input['travel_style']}
Preferences/Interests: {user_input['preferences']}
Special Requirements: {user_input['special_requirements']}
"""
modified_input_context = "Please output the response in English.\n" + input_context
# Processing Animation
st.markdown("""
""", unsafe_allow_html=True)
st.markdown('', unsafe_allow_html=True)
progress_tab, logs_tab, details_tab = st.tabs(["π Progress", "π Live Activity", "π Your Travel Request"])
with details_tab:
st.markdown("#### Your Travel Request")
st.markdown("**Destination:** " + user_input['destination'])
st.markdown("**From:** " + user_input['origin'])
st.markdown("**When:** " + user_input['travel_dates'] + " (" + user_input['duration'] + " days)")
st.markdown("**Budget:** " + user_input['budget'].title())
st.markdown("**Travel Style:** " + user_input['travel_style'])
if user_input['preferences']:
st.markdown("**Interests:** " + user_input['preferences'])
if user_input['special_requirements']:
st.markdown("**Special Requirements:** " + user_input['special_requirements'])
with progress_tab:
if 'progress_placeholder' not in st.session_state:
st.session_state.progress_placeholder = st.empty()
with st.session_state.progress_placeholder.container():
display_modern_progress(st.session_state.current_step)
with logs_tab:
log_container = st.container()
st.session_state.log_messages = []
st.markdown('
', unsafe_allow_html=True)
# Output container for the Agents
output_container = st.container()
with output_container:
st.markdown('', unsafe_allow_html=True)
st.markdown("### Live Agent Outputs")
st.info("Our AI agents will show their work here as they create your itinerary")
st.markdown('
', unsafe_allow_html=True)
# Steps
st.session_state.current_step = 0
# Step 1: Destination Research
update_step_status(0, 'active')
with st.session_state.progress_placeholder.container():
display_modern_progress(st.session_state.current_step)
destination_info = run_task_with_logs(
destination_research_task,
modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
log_container,
output_container,
"destination_info"
)
update_step_status(0, 'complete')
st.session_state.current_step = 1
# Step 2: Accommodation
update_step_status(1, 'active')
with st.session_state.progress_placeholder.container():
display_modern_progress(st.session_state.current_step)
accommodation_info = run_task_with_logs(
accommodation_task,
modified_input_context.format(destination=user_input['destination'], budget=user_input['budget'], preferences=user_input['preferences']),
log_container,
output_container,
"accommodation_info"
)
update_step_status(1, 'complete')
st.session_state.current_step = 2
# Step 3: Transportation
update_step_status(2, 'active')
with st.session_state.progress_placeholder.container():
display_modern_progress(st.session_state.current_step)
transportation_info = run_task_with_logs(
transportation_task,
modified_input_context.format(origin=user_input['origin'], destination=user_input['destination']),
log_container,
output_container,
"transportation_info"
)
update_step_status(2, 'complete')
st.session_state.current_step = 3
# Step 4: Activities
update_step_status(3, 'active')
with st.session_state.progress_placeholder.container():
display_modern_progress(st.session_state.current_step)
activities_info = run_task_with_logs(
activities_task,
modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
log_container,
output_container,
"activities_info"
)
update_step_status(3, 'complete')
st.session_state.current_step = 4
# Step 5: Dining
update_step_status(4, 'active')
with st.session_state.progress_placeholder.container():
display_modern_progress(st.session_state.current_step)
dining_info = run_task_with_logs(
dining_task,
modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
log_container,
output_container,
"dining_info"
)
update_step_status(4, 'complete')
st.session_state.current_step = 5
# Step 6: Final Itinerary
update_step_status(5, 'active')
with st.session_state.progress_placeholder.container():
display_modern_progress(st.session_state.current_step)
combined_info = f"""{input_context}
Destination Information:
{destination_info}
Accommodation Options:
{accommodation_info}
Transportation Plan:
{transportation_info}
Recommended Activities:
{activities_info}
Dining Recommendations:
{dining_info}
"""
itinerary = run_task_with_logs(
itinerary_task,
combined_info.format(duration=user_input['duration'], origin=user_input['origin'], destination=user_input['destination']),
log_container,
output_container,
"itinerary"
)
update_step_status(5, 'complete')
st.session_state.current_step = 6
with st.session_state.progress_placeholder.container():
display_modern_progress(st.session_state.current_step)
# Store the final itinerary
st.session_state.generated_itinerary = itinerary
st.session_state.generation_complete = True
date_str = datetime.now().strftime("%Y-%m-%d")
st.session_state.filename = f"{user_input['destination'].replace(' ', '_')}_{date_str}_itinerary.txt"
# ------------------------------------------------------
# Display after Itinerary Generation
# ------------------------------------------------------
if st.session_state.generation_complete:
# Success Animation
st.markdown("""
Your Travel Itinerary is Ready! π
We've created a personalized travel experience just for you. Explore your itinerary below.
""", unsafe_allow_html=True)
# Tabs
itinerary_tab, details_tab, download_tab, map_tab, chatbot_tab = st.tabs([
"ποΈ Full Itinerary",
"πΌ Details",
"πΎ Download & Share",
"πΊοΈ Map & Visualization",
"π€ Chatbot Interface"
])
# Full Itinerary
with itinerary_tab:
st.text_area("Your Itinerary", st.session_state.generated_itinerary, height=600)
# Details (Destination, Accommodation, etc.)
with details_tab:
agent_tabs = st.tabs(["π Destination", "π¨ Accommodation", "π Transportation", "π Activities", "π½οΈ Dining"])
with agent_tabs[0]:
st.markdown("### π Destination Research")
st.markdown(st.session_state.results["destination_info"])
with agent_tabs[1]:
st.markdown("### π¨ Accommodation Options")
st.markdown(st.session_state.results["accommodation_info"])
with agent_tabs[2]:
st.markdown("### π Transportation Plan")
st.markdown(st.session_state.results["transportation_info"])
with agent_tabs[3]:
st.markdown("### π Recommended Activities")
st.markdown(st.session_state.results["activities_info"])
with agent_tabs[4]:
st.markdown("### π½οΈ Dining Recommendations")
st.markdown(st.session_state.results["dining_info"])
# Download & Share Tab (No QR code)
with download_tab:
col1, col2 = st.columns([2, 1])
with col1:
st.markdown("### Save Your Itinerary")
st.markdown("Download your personalized travel plan to access it offline or share with your travel companions.")
st.markdown("""
Your Itinerary File
Text format - Can be opened in any text editor
""", unsafe_allow_html=True)
# Download link
st.markdown(
"
"
+ get_download_link(st.session_state.generated_itinerary, st.session_state.filename)
+ "
",
unsafe_allow_html=True
)
st.markdown("
", unsafe_allow_html=True)
st.markdown("### Share Your Itinerary")
st.markdown("*Coming soon: Additional sharing features (email, phone, etc.)*")
with col2:
st.markdown("### Save for Mobile")
st.markdown("*Coming soon: Additional mobile features such as a dedicated app or push notifications*")
# Map & Visualization Tab
with map_tab:
st.markdown("### Destination Map")
dest = st.session_state.get("destination", "Paris")
try:
geolocator = Nominatim(user_agent="travel_app")
location = geolocator.geocode(dest)
if location:
lat, lon = location.latitude, location.longitude
else:
st.error("The destination could not be found. Using default coordinates.")
lat, lon = 48.8566, 2.3522
except Exception as e:
st.error("Geocoding error: " + str(e))
lat, lon = 48.8566, 2.3522
map_data = pd.DataFrame({
"lat": [lat],
"lon": [lon],
"name": [dest]
})
st.map(map_data)
st.markdown("#### Interactive Map with Pydeck")
layer = pdk.Layer(
"ScatterplotLayer",
data=map_data,
get_position='[lon, lat]',
get_color='[200, 30, 0, 160]',
get_radius=200,
)
view_state = pdk.ViewState(
latitude=lat,
longitude=lon,
zoom=12,
pitch=50,
)
deck_chart = pdk.Deck(layers=[layer], initial_view_state=view_state)
st.pydeck_chart(deck_chart)
# Chatbot Interface
with chatbot_tab:
st.markdown("### AI Chatbot Interface")
if "chat_history" not in st.session_state:
st.session_state.chat_history = []
user_message = st.text_input("Enter your message:", key="chat_input")
if st.button("Send", key="send_button"):
if user_message:
response = run_task(chatbot_task, user_message)
st.session_state.chat_history.append({
"speaker": "User",
"message": user_message,
"time": datetime.now()
})
st.session_state.chat_history.append({
"speaker": "AI",
"message": response,
"time": datetime.now()
})
st.markdown("", unsafe_allow_html=True)
for chat in st.session_state.chat_history:
time_str = chat["time"].strftime("%H:%M:%S")
st.markdown(f"**{chat['speaker']}** ({time_str}): {chat['message']}")
st.markdown("
", unsafe_allow_html=True)
# Footer
st.markdown("""
Built with β€οΈ for you
""", unsafe_allow_html=True)