AdithyaSNair commited on
Commit
3c70bd5
·
verified ·
1 Parent(s): b467bd7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -138
app.py CHANGED
@@ -3,13 +3,16 @@ from datetime import datetime, timedelta
3
  import base64
4
  import pandas as pd
5
  import pydeck as pdk
 
 
 
 
 
6
  from travel import (
7
  destination_research_task, accommodation_task, transportation_task,
8
  activities_task, dining_task, itinerary_task, chatbot_task,
9
- run_task
10
  )
11
- from geopy.geocoders import Nominatim
12
- from io import BytesIO
13
 
14
  st.set_page_config(
15
  page_title="Your AI Agent for Travelling",
@@ -18,6 +21,44 @@ st.set_page_config(
18
  initial_sidebar_state="expanded"
19
  )
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  st.markdown("""
22
  <style>
23
  :root {
@@ -32,66 +73,14 @@ st.markdown("""
32
  --text-muted: #495057;
33
  --border: #e9ecef;
34
  }
35
- /* Sidebar custom styles */
36
- .sidebar-container {
37
- padding: 20px;
38
- background-color: var(--card-bg);
39
- border-radius: 10px;
40
- margin-bottom: 20px;
41
- box-shadow: 0 2px 10px rgba(0,0,0,0.05);
42
- }
43
- .sidebar-header {
44
- text-align: center;
45
- margin-bottom: 20px;
46
- }
47
- .sidebar-header img {
48
- margin-bottom: 10px;
49
- }
50
- .sidebar-header h3 {
51
- margin-bottom: 5px;
52
- color: var(--accent);
53
- font-size: 1.5rem;
54
- }
55
- .sidebar-section {
56
- margin-bottom: 20px;
57
- }
58
- .sidebar-section h2 {
59
- margin-bottom: 10px;
60
- color: var(--primary-dark);
61
- border-bottom: 1px solid var(--border);
62
- padding-bottom: 5px;
63
- }
64
- .sidebar-section p {
65
- font-size: 14px;
66
- color: var(--text-muted);
67
- }
68
- .sidebar-section ul {
69
- list-style-type: disc;
70
- margin-left: 20px;
71
- color: var(--text);
72
- font-size: 14px;
73
- }
74
- .agent-item {
75
- margin-bottom: 10px;
76
- }
77
- .agent-item strong {
78
- font-size: 18px;
79
- color: var(--primary-dark);
80
- }
81
- .agent-item small {
82
- font-size: 16px;
83
- }
84
  </style>
85
  """, unsafe_allow_html=True)
86
 
87
  def get_download_link(text_content, filename):
88
- """Generate a download link for the itinerary text file."""
89
  b64 = base64.b64encode(text_content.encode()).decode()
90
- href = f'<a class="download-link" href="data:text/plain;base64,{b64}" download="{filename}"><i>📥</i> Save Your Itinerary</a>'
91
- return href
92
 
93
  def display_modern_progress(current_step, total_steps=6):
94
- """Displays a progress bar and step indicators."""
95
  if 'progress_steps' not in st.session_state:
96
  st.session_state.progress_steps = {
97
  0: {'status': 'pending', 'name': "Trip Details"},
@@ -113,7 +102,6 @@ def display_modern_progress(current_step, total_steps=6):
113
  progress_percentage = (current_step / total_steps) * 100
114
  st.progress(progress_percentage / 100)
115
 
116
- # Display step grid
117
  st.markdown("""
118
  <style>
119
  .compact-progress {
@@ -174,7 +162,6 @@ def display_modern_progress(current_step, total_steps=6):
174
  else:
175
  icon = "⭕"
176
  status_class = "pending"
177
-
178
  st.markdown(f"""
179
  <div class="step-item {status_class}">
180
  <span class="step-icon">{icon}</span>
@@ -186,15 +173,12 @@ def display_modern_progress(current_step, total_steps=6):
186
  return progress_percentage
187
 
188
  def update_step_status(step_index, status):
189
- """Update the status (pending, active, complete) for a given step index."""
190
  if 'progress_steps' in st.session_state and step_index in st.session_state.progress_steps:
191
  st.session_state.progress_steps[step_index]['status'] = status
192
 
193
  def run_task_with_logs(task, input_text, log_container, output_container, results_key=None):
194
- """Runs a task with logging in a separate container."""
195
  if 'log_messages' not in st.session_state:
196
  st.session_state.log_messages = []
197
-
198
  log_message = f"🤖 Starting {task.agent.role}..."
199
  st.session_state.log_messages.append(log_message)
200
 
@@ -207,7 +191,6 @@ def run_task_with_logs(task, input_text, log_container, output_container, result
207
 
208
  if results_key:
209
  st.session_state.results[results_key] = result
210
-
211
  log_message = f"✅ {task.agent.role} completed!"
212
  st.session_state.log_messages.append(log_message)
213
 
@@ -219,7 +202,6 @@ def run_task_with_logs(task, input_text, log_container, output_container, result
219
  with output_container:
220
  st.markdown(f"### {task.agent.role} Output")
221
  st.markdown("<div class='agent-output'>" + result + "</div>", unsafe_allow_html=True)
222
-
223
  return result
224
 
225
  if 'generated_itinerary' not in st.session_state:
@@ -258,56 +240,14 @@ st.markdown(f"""
258
  </div>
259
  """, unsafe_allow_html=True)
260
 
261
-
262
  st.markdown('<hr style="height:3px;border:none;background-color:#f0f0f0;margin-bottom:25px;">', unsafe_allow_html=True)
263
 
264
- with st.sidebar:
265
- st.image("image.png", width=250)
266
- st.markdown("""
267
- <h3>Namude Yatra: The beginning of your dream journey</h3>
268
- <p style="font-size: 14px; color: var(--text-muted);">AI-Powered Agentic Travel Planning</p>
269
- """, unsafe_allow_html=True)
270
-
271
-
272
- st.markdown('<div class="sidebar-section">', unsafe_allow_html=True)
273
- st.markdown("<h2>About</h2>", unsafe_allow_html=True)
274
- st.markdown("<p>This tool creates a personalized travel itinerary based on your preferences. Fill in the form on the main page and let our expert travel agents plan your perfect trip!</p>", unsafe_allow_html=True)
275
- st.markdown('</div>', unsafe_allow_html=True)
276
-
277
- st.markdown('<div class="sidebar-section">', unsafe_allow_html=True)
278
- st.markdown("<h2>How It Works</h2>", unsafe_allow_html=True)
279
- st.markdown("""
280
- <ul>
281
- <li><b>Enter:</b> Your travel details</li>
282
- <li><b>Analyze:</b> Preferences by AI</li>
283
- <li><b>Generate:</b> Your comprehensive itinerary</li>
284
- <li><b>Download:</b> Save and share your itinerary</li>
285
- </ul>
286
- """, unsafe_allow_html=True)
287
- st.markdown('</div>', unsafe_allow_html=True)
288
-
289
- st.markdown('<div class="sidebar-section">', unsafe_allow_html=True)
290
- st.markdown("<h2>Travel Agents</h2>", unsafe_allow_html=True)
291
- agents = [
292
- ("🔭 Research Specialist", "Finds the best destinations based on your preferences."),
293
- ("🏨 Accommodation Expert", "Suggests suitable hotels and stays."),
294
- ("🚆 Transportation Planner", "Plans efficient travel routes."),
295
- ("🎯 Activities Curator", "Recommends activities tailored to your interests."),
296
- ("🍽️ Dining Connoisseur", "Finds the best dining experiences."),
297
- ("📅 Itinerary Creator", "Puts everything together in a daily plan.")
298
- ]
299
- for name, desc in agents:
300
- st.markdown(f'<div class="agent-item"><strong>{name}</strong><br><small>{desc}</small></div>', unsafe_allow_html=True)
301
- st.markdown('</div>', unsafe_allow_html=True)
302
-
303
  if not st.session_state.generation_complete:
304
  st.markdown('<div class="modern-card animate-in">', unsafe_allow_html=True)
305
- st.markdown("<h3 style='font-weight: 600; color: var(--primary-dark); display: flex; align-items: center; gap: 10px;'><span style='font-size: 20px;'>✈️</span> Create Your Itinerary</h3>", unsafe_allow_html=True)
306
-
307
  st.markdown("""
308
- <p style="color: var(--text-muted); margin-bottom: 16px; font-size: 14px;">Complete the form below for a personalized travel plan.</p>
309
  """, unsafe_allow_html=True)
310
-
311
  with st.form("travel_form"):
312
  col1, col2 = st.columns(2)
313
  with col1:
@@ -318,7 +258,7 @@ if not st.session_state.generation_complete:
318
  start_date = st.date_input("Start Date", min_value=datetime.now(), label_visibility="collapsed")
319
  duration = st.slider("Duration (days)", min_value=1, max_value=30, value=7)
320
  end_date = start_date + timedelta(days=duration-1)
321
- st.markdown(f'<p style="font-size: 13px; color: var(--text-muted);">{start_date.strftime("%b %d")} - {end_date.strftime("%b %d, %Y")}</p>', unsafe_allow_html=True)
322
  with col2:
323
  st.markdown('<p style="font-weight: 500; color: var(--primary); font-size: 14px;">Preferences</p>', unsafe_allow_html=True)
324
  travelers = st.number_input("Travelers", min_value=1, max_value=15, value=2)
@@ -348,8 +288,7 @@ if not st.session_state.generation_complete:
348
  "preferences": preferences,
349
  "special_requirements": special_requirements
350
  }
351
-
352
- st.session_state.user_input = user_input
353
  input_context = f"""Travel Request Details:
354
  Origin: {user_input['origin']}
355
  Destination: {user_input['destination']}
@@ -362,13 +301,13 @@ Preferences/Interests: {user_input['preferences']}
362
  Special Requirements: {user_input['special_requirements']}
363
  """
364
  modified_input_context = "Please output the response in English.\n" + input_context
365
-
366
  # Processing Animation
367
  st.markdown("""
368
- <div class="sleek-processing-container" style="text-align:center; padding:20px 0;">
369
- <div class="pulse-container" style="position:relative; width:50px; height:50px;">
370
- <div class="pulse-ring" style="position:absolute; width:100%; height:100%; border:2px solid #4361ee; border-radius:50%; animation:pulse 1.5s ease-out infinite;"></div>
371
- <div class="pulse-core" style="position:absolute; left:50%; top:50%; transform:translate(-50%, -50%); width:12px; height:12px; background-color:#4361ee; border-radius:50%; box-shadow:0 0 8px rgba(67,97,238,0.6);"></div>
372
  </div>
373
  </div>
374
  <style>
@@ -379,7 +318,7 @@ Special Requirements: {user_input['special_requirements']}
379
  }
380
  </style>
381
  """, unsafe_allow_html=True)
382
-
383
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
384
  progress_tab, logs_tab, details_tab = st.tabs(["📊 Progress", "🔄 Live Activity", "📋 Your Travel Request"])
385
  with details_tab:
@@ -403,7 +342,6 @@ Special Requirements: {user_input['special_requirements']}
403
  st.session_state.log_messages = []
404
  st.markdown('</div>', unsafe_allow_html=True)
405
 
406
- # Output container for the Agents
407
  output_container = st.container()
408
  with output_container:
409
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
@@ -411,7 +349,6 @@ Special Requirements: {user_input['special_requirements']}
411
  st.info("Our AI agents will show their work here as they create your itinerary")
412
  st.markdown('</div>', unsafe_allow_html=True)
413
 
414
- # Steps
415
  st.session_state.current_step = 0
416
 
417
  # Step 1: Destination Research
@@ -419,7 +356,7 @@ Special Requirements: {user_input['special_requirements']}
419
  with st.session_state.progress_placeholder.container():
420
  display_modern_progress(st.session_state.current_step)
421
  destination_info = run_task_with_logs(
422
- destination_research_task,
423
  modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
424
  log_container,
425
  output_container,
@@ -433,7 +370,7 @@ Special Requirements: {user_input['special_requirements']}
433
  with st.session_state.progress_placeholder.container():
434
  display_modern_progress(st.session_state.current_step)
435
  accommodation_info = run_task_with_logs(
436
- accommodation_task,
437
  modified_input_context.format(destination=user_input['destination'], budget=user_input['budget'], preferences=user_input['preferences']),
438
  log_container,
439
  output_container,
@@ -447,7 +384,7 @@ Special Requirements: {user_input['special_requirements']}
447
  with st.session_state.progress_placeholder.container():
448
  display_modern_progress(st.session_state.current_step)
449
  transportation_info = run_task_with_logs(
450
- transportation_task,
451
  modified_input_context.format(origin=user_input['origin'], destination=user_input['destination']),
452
  log_container,
453
  output_container,
@@ -461,7 +398,7 @@ Special Requirements: {user_input['special_requirements']}
461
  with st.session_state.progress_placeholder.container():
462
  display_modern_progress(st.session_state.current_step)
463
  activities_info = run_task_with_logs(
464
- activities_task,
465
  modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
466
  log_container,
467
  output_container,
@@ -475,7 +412,7 @@ Special Requirements: {user_input['special_requirements']}
475
  with st.session_state.progress_placeholder.container():
476
  display_modern_progress(st.session_state.current_step)
477
  dining_info = run_task_with_logs(
478
- dining_task,
479
  modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
480
  log_container,
481
  output_container,
@@ -506,7 +443,7 @@ Dining Recommendations:
506
  {dining_info}
507
  """
508
  itinerary = run_task_with_logs(
509
- itinerary_task,
510
  combined_info.format(duration=user_input['duration'], origin=user_input['origin'], destination=user_input['destination']),
511
  log_container,
512
  output_container,
@@ -517,14 +454,13 @@ Dining Recommendations:
517
  with st.session_state.progress_placeholder.container():
518
  display_modern_progress(st.session_state.current_step)
519
 
520
- # Store the final itinerary
521
  st.session_state.generated_itinerary = itinerary
522
  st.session_state.generation_complete = True
523
  date_str = datetime.now().strftime("%Y-%m-%d")
524
  st.session_state.filename = f"{user_input['destination'].replace(' ', '_')}_{date_str}_itinerary.txt"
525
 
 
526
  if st.session_state.generation_complete:
527
- # Success Animation
528
  st.markdown("""
529
  <div class="modern-card animate-in">
530
  <div style="display: flex; justify-content: center; margin-bottom: 20px;">
@@ -538,7 +474,6 @@ if st.session_state.generation_complete:
538
  <h2 style="text-align: center; color: var(--primary-dark);">Your Travel Itinerary is Ready! 🎉</h2>
539
  <p style="text-align: center; color: var(--text-muted); margin-bottom: 20px;">We've created a personalized travel experience just for you. Explore your itinerary below.</p>
540
  </div>
541
-
542
  <style>
543
  .success-animation {
544
  width: 100px;
@@ -584,7 +519,6 @@ if st.session_state.generation_complete:
584
  </style>
585
  """, unsafe_allow_html=True)
586
 
587
- # Tabs
588
  itinerary_tab, details_tab, download_tab, map_tab, chatbot_tab = st.tabs([
589
  "🗒️ Full Itinerary",
590
  "💼 Details",
@@ -614,7 +548,6 @@ if st.session_state.generation_complete:
614
  st.markdown("### 🍽️ Dining Recommendations")
615
  st.markdown(st.session_state.results["dining_info"])
616
 
617
- # Download & Share Tab (No QR code)
618
  with download_tab:
619
  col1, col2 = st.columns([2, 1])
620
  with col1:
@@ -624,25 +557,20 @@ if st.session_state.generation_complete:
624
  <div style="background-color: var(--background); padding: 15px; border-radius: 10px; margin-top: 20px;">
625
  <h4>Your Itinerary File</h4>
626
  <p style="font-size: 0.9rem; color: var(--text-muted);">Text format - Can be opened in any text editor</p>
 
627
  """, unsafe_allow_html=True)
628
-
629
- # Download link
630
  st.markdown(
631
  "<div style='margin: 10px 0;'>"
632
  + get_download_link(st.session_state.generated_itinerary, st.session_state.filename)
633
  + "</div>",
634
  unsafe_allow_html=True
635
  )
636
- st.markdown("</div>", unsafe_allow_html=True)
637
-
638
  st.markdown("### Share Your Itinerary")
639
  st.markdown("*Coming soon: Additional sharing features (email, phone, etc.)*")
640
-
641
  with col2:
642
  st.markdown("### Save for Mobile")
643
  st.markdown("*Coming soon: Additional mobile features such as a dedicated app or push notifications*")
644
 
645
- # Map & Visualization Tab
646
  with map_tab:
647
  st.markdown("### Destination Map")
648
  dest = st.session_state.get("destination", "Paris")
@@ -664,7 +592,6 @@ if st.session_state.generation_complete:
664
  "name": [dest]
665
  })
666
  st.map(map_data)
667
-
668
  st.markdown("#### Interactive Map with Pydeck")
669
  layer = pdk.Layer(
670
  "ScatterplotLayer",
@@ -682,7 +609,6 @@ if st.session_state.generation_complete:
682
  deck_chart = pdk.Deck(layers=[layer], initial_view_state=view_state)
683
  st.pydeck_chart(deck_chart)
684
 
685
- # Chatbot Interface
686
  with chatbot_tab:
687
  st.markdown("### AI Chatbot Interface")
688
  if "chat_history" not in st.session_state:
@@ -707,7 +633,6 @@ if st.session_state.generation_complete:
707
  st.markdown(f"**{chat['speaker']}** ({time_str}): {chat['message']}")
708
  st.markdown("</div>", unsafe_allow_html=True)
709
 
710
- # Footer
711
  st.markdown("""
712
  <div style="margin-top: 50px; text-align: center; padding: 20px; color: var(--text-muted); font-size: 0.8rem;">
713
  <p>Built with ❤️ for you</p>
 
3
  import base64
4
  import pandas as pd
5
  import pydeck as pdk
6
+ from geopy.geocoders import Nominatim
7
+ import qrcode
8
+ from io import BytesIO
9
+
10
+ # Import functions and tasks from travel.py
11
  from travel import (
12
  destination_research_task, accommodation_task, transportation_task,
13
  activities_task, dining_task, itinerary_task, chatbot_task,
14
+ run_task, update_llm
15
  )
 
 
16
 
17
  st.set_page_config(
18
  page_title="Your AI Agent for Travelling",
 
21
  initial_sidebar_state="expanded"
22
  )
23
 
24
+ with st.sidebar:
25
+ st.image("image.png", width=250)
26
+ st.markdown("""
27
+ <h3>Namude Yatra: The beginning of your dream journey</h3>
28
+ <p style="font-size: 14px; color: var(--text-muted);">AI-Powered Agentic Travel Planning</p>
29
+ """, unsafe_allow_html=True)
30
+
31
+ # API Key Input (update dynamically)
32
+ api_key = st.text_input("Enter your GEMINI API Key", type="password")
33
+ if api_key:
34
+ update_llm(api_key)
35
+ st.success("API Key updated!")
36
+
37
+ st.markdown("""
38
+ <div class="sidebar-section">
39
+ <h2>About</h2>
40
+ <p>This tool creates a personalized travel itinerary based on your preferences. Fill in the form on the main page and let our expert travel agents plan your perfect trip!</p>
41
+ </div>
42
+ <div class="sidebar-section">
43
+ <h2>How It Works</h2>
44
+ <ul>
45
+ <li><b>Enter:</b> Your travel details</li>
46
+ <li><b>Analyze:</b> Preferences by AI</li>
47
+ <li><b>Generate:</b> Your comprehensive itinerary</li>
48
+ <li><b>Download:</b> Save and share your itinerary</li>
49
+ </ul>
50
+ </div>
51
+ <div class="sidebar-section">
52
+ <h2>Travel Agents</h2>
53
+ <div class="agent-item"><strong>🔭 Research Specialist</strong><br><small>Finds the best destinations based on your preferences.</small></div>
54
+ <div class="agent-item"><strong>🏨 Accommodation Expert</strong><br><small>Suggests suitable hotels and stays.</small></div>
55
+ <div class="agent-item"><strong>🚆 Transportation Planner</strong><br><small>Plans efficient travel routes.</small></div>
56
+ <div class="agent-item"><strong>🎯 Activities Curator</strong><br><small>Recommends activities tailored to your interests.</small></div>
57
+ <div class="agent-item"><strong>🍽️ Dining Connoisseur</strong><br><small>Finds the best dining experiences.</small></div>
58
+ <div class="agent-item"><strong>📅 Itinerary Creator</strong><br><small>Puts everything together in a daily plan.</small></div>
59
+ </div>
60
+ """, unsafe_allow_html=True)
61
+
62
  st.markdown("""
63
  <style>
64
  :root {
 
73
  --text-muted: #495057;
74
  --border: #e9ecef;
75
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  </style>
77
  """, unsafe_allow_html=True)
78
 
79
  def get_download_link(text_content, filename):
 
80
  b64 = base64.b64encode(text_content.encode()).decode()
81
+ return f'<a class="download-link" href="data:text/plain;base64,{b64}" download="{filename}"><i>📥</i> Save Your Itinerary</a>'
 
82
 
83
  def display_modern_progress(current_step, total_steps=6):
 
84
  if 'progress_steps' not in st.session_state:
85
  st.session_state.progress_steps = {
86
  0: {'status': 'pending', 'name': "Trip Details"},
 
102
  progress_percentage = (current_step / total_steps) * 100
103
  st.progress(progress_percentage / 100)
104
 
 
105
  st.markdown("""
106
  <style>
107
  .compact-progress {
 
162
  else:
163
  icon = "⭕"
164
  status_class = "pending"
 
165
  st.markdown(f"""
166
  <div class="step-item {status_class}">
167
  <span class="step-icon">{icon}</span>
 
173
  return progress_percentage
174
 
175
  def update_step_status(step_index, status):
 
176
  if 'progress_steps' in st.session_state and step_index in st.session_state.progress_steps:
177
  st.session_state.progress_steps[step_index]['status'] = status
178
 
179
  def run_task_with_logs(task, input_text, log_container, output_container, results_key=None):
 
180
  if 'log_messages' not in st.session_state:
181
  st.session_state.log_messages = []
 
182
  log_message = f"🤖 Starting {task.agent.role}..."
183
  st.session_state.log_messages.append(log_message)
184
 
 
191
 
192
  if results_key:
193
  st.session_state.results[results_key] = result
 
194
  log_message = f"✅ {task.agent.role} completed!"
195
  st.session_state.log_messages.append(log_message)
196
 
 
202
  with output_container:
203
  st.markdown(f"### {task.agent.role} Output")
204
  st.markdown("<div class='agent-output'>" + result + "</div>", unsafe_allow_html=True)
 
205
  return result
206
 
207
  if 'generated_itinerary' not in st.session_state:
 
240
  </div>
241
  """, unsafe_allow_html=True)
242
 
 
243
  st.markdown('<hr style="height:3px;border:none;background-color:#f0f0f0;margin-bottom:25px;">', unsafe_allow_html=True)
244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  if not st.session_state.generation_complete:
246
  st.markdown('<div class="modern-card animate-in">', unsafe_allow_html=True)
247
+ st.markdown("<h3 style='font-weight: 600; color: var(--primary-dark); text-align: center;'>✈️ Create Your Itinerary</h3>", unsafe_allow_html=True)
 
248
  st.markdown("""
249
+ <p style="text-align: center; color: var(--text-muted); font-size: 14px;">Complete the form below for a personalized travel plan.</p>
250
  """, unsafe_allow_html=True)
 
251
  with st.form("travel_form"):
252
  col1, col2 = st.columns(2)
253
  with col1:
 
258
  start_date = st.date_input("Start Date", min_value=datetime.now(), label_visibility="collapsed")
259
  duration = st.slider("Duration (days)", min_value=1, max_value=30, value=7)
260
  end_date = start_date + timedelta(days=duration-1)
261
+ st.markdown(f'<p style="font-size: 13px; color: var(--text-muted); text-align: center;">{start_date.strftime("%b %d")} - {end_date.strftime("%b %d, %Y")}</p>', unsafe_allow_html=True)
262
  with col2:
263
  st.markdown('<p style="font-weight: 500; color: var(--primary); font-size: 14px;">Preferences</p>', unsafe_allow_html=True)
264
  travelers = st.number_input("Travelers", min_value=1, max_value=15, value=2)
 
288
  "preferences": preferences,
289
  "special_requirements": special_requirements
290
  }
291
+ st.session_state.user_input = user_input
 
292
  input_context = f"""Travel Request Details:
293
  Origin: {user_input['origin']}
294
  Destination: {user_input['destination']}
 
301
  Special Requirements: {user_input['special_requirements']}
302
  """
303
  modified_input_context = "Please output the response in English.\n" + input_context
304
+
305
  # Processing Animation
306
  st.markdown("""
307
+ <div style="text-align: center; padding:20px 0;">
308
+ <div style="position:relative; width:50px; height:50px;">
309
+ <div style="position:absolute; width:100%; height:100%; border:2px solid #4361ee; border-radius:50%; animation:pulse 1.5s ease-out infinite;"></div>
310
+ <div style="position:absolute; left:50%; top:50%; transform:translate(-50%, -50%); width:12px; height:12px; background-color:#4361ee; border-radius:50%; box-shadow:0 0 8px rgba(67,97,238,0.6);"></div>
311
  </div>
312
  </div>
313
  <style>
 
318
  }
319
  </style>
320
  """, unsafe_allow_html=True)
321
+
322
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
323
  progress_tab, logs_tab, details_tab = st.tabs(["📊 Progress", "🔄 Live Activity", "📋 Your Travel Request"])
324
  with details_tab:
 
342
  st.session_state.log_messages = []
343
  st.markdown('</div>', unsafe_allow_html=True)
344
 
 
345
  output_container = st.container()
346
  with output_container:
347
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
 
349
  st.info("Our AI agents will show their work here as they create your itinerary")
350
  st.markdown('</div>', unsafe_allow_html=True)
351
 
 
352
  st.session_state.current_step = 0
353
 
354
  # Step 1: Destination Research
 
356
  with st.session_state.progress_placeholder.container():
357
  display_modern_progress(st.session_state.current_step)
358
  destination_info = run_task_with_logs(
359
+ destination_research_task,
360
  modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
361
  log_container,
362
  output_container,
 
370
  with st.session_state.progress_placeholder.container():
371
  display_modern_progress(st.session_state.current_step)
372
  accommodation_info = run_task_with_logs(
373
+ accommodation_task,
374
  modified_input_context.format(destination=user_input['destination'], budget=user_input['budget'], preferences=user_input['preferences']),
375
  log_container,
376
  output_container,
 
384
  with st.session_state.progress_placeholder.container():
385
  display_modern_progress(st.session_state.current_step)
386
  transportation_info = run_task_with_logs(
387
+ transportation_task,
388
  modified_input_context.format(origin=user_input['origin'], destination=user_input['destination']),
389
  log_container,
390
  output_container,
 
398
  with st.session_state.progress_placeholder.container():
399
  display_modern_progress(st.session_state.current_step)
400
  activities_info = run_task_with_logs(
401
+ activities_task,
402
  modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
403
  log_container,
404
  output_container,
 
412
  with st.session_state.progress_placeholder.container():
413
  display_modern_progress(st.session_state.current_step)
414
  dining_info = run_task_with_logs(
415
+ dining_task,
416
  modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
417
  log_container,
418
  output_container,
 
443
  {dining_info}
444
  """
445
  itinerary = run_task_with_logs(
446
+ itinerary_task,
447
  combined_info.format(duration=user_input['duration'], origin=user_input['origin'], destination=user_input['destination']),
448
  log_container,
449
  output_container,
 
454
  with st.session_state.progress_placeholder.container():
455
  display_modern_progress(st.session_state.current_step)
456
 
 
457
  st.session_state.generated_itinerary = itinerary
458
  st.session_state.generation_complete = True
459
  date_str = datetime.now().strftime("%Y-%m-%d")
460
  st.session_state.filename = f"{user_input['destination'].replace(' ', '_')}_{date_str}_itinerary.txt"
461
 
462
+
463
  if st.session_state.generation_complete:
 
464
  st.markdown("""
465
  <div class="modern-card animate-in">
466
  <div style="display: flex; justify-content: center; margin-bottom: 20px;">
 
474
  <h2 style="text-align: center; color: var(--primary-dark);">Your Travel Itinerary is Ready! 🎉</h2>
475
  <p style="text-align: center; color: var(--text-muted); margin-bottom: 20px;">We've created a personalized travel experience just for you. Explore your itinerary below.</p>
476
  </div>
 
477
  <style>
478
  .success-animation {
479
  width: 100px;
 
519
  </style>
520
  """, unsafe_allow_html=True)
521
 
 
522
  itinerary_tab, details_tab, download_tab, map_tab, chatbot_tab = st.tabs([
523
  "🗒️ Full Itinerary",
524
  "💼 Details",
 
548
  st.markdown("### 🍽️ Dining Recommendations")
549
  st.markdown(st.session_state.results["dining_info"])
550
 
 
551
  with download_tab:
552
  col1, col2 = st.columns([2, 1])
553
  with col1:
 
557
  <div style="background-color: var(--background); padding: 15px; border-radius: 10px; margin-top: 20px;">
558
  <h4>Your Itinerary File</h4>
559
  <p style="font-size: 0.9rem; color: var(--text-muted);">Text format - Can be opened in any text editor</p>
560
+ </div>
561
  """, unsafe_allow_html=True)
 
 
562
  st.markdown(
563
  "<div style='margin: 10px 0;'>"
564
  + get_download_link(st.session_state.generated_itinerary, st.session_state.filename)
565
  + "</div>",
566
  unsafe_allow_html=True
567
  )
 
 
568
  st.markdown("### Share Your Itinerary")
569
  st.markdown("*Coming soon: Additional sharing features (email, phone, etc.)*")
 
570
  with col2:
571
  st.markdown("### Save for Mobile")
572
  st.markdown("*Coming soon: Additional mobile features such as a dedicated app or push notifications*")
573
 
 
574
  with map_tab:
575
  st.markdown("### Destination Map")
576
  dest = st.session_state.get("destination", "Paris")
 
592
  "name": [dest]
593
  })
594
  st.map(map_data)
 
595
  st.markdown("#### Interactive Map with Pydeck")
596
  layer = pdk.Layer(
597
  "ScatterplotLayer",
 
609
  deck_chart = pdk.Deck(layers=[layer], initial_view_state=view_state)
610
  st.pydeck_chart(deck_chart)
611
 
 
612
  with chatbot_tab:
613
  st.markdown("### AI Chatbot Interface")
614
  if "chat_history" not in st.session_state:
 
633
  st.markdown(f"**{chat['speaker']}** ({time_str}): {chat['message']}")
634
  st.markdown("</div>", unsafe_allow_html=True)
635
 
 
636
  st.markdown("""
637
  <div style="margin-top: 50px; text-align: center; padding: 20px; color: var(--text-muted); font-size: 0.8rem;">
638
  <p>Built with ❤️ for you</p>