openfree commited on
Commit
14d4eaf
ยท
verified ยท
1 Parent(s): ffbc6a2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +97 -179
app.py CHANGED
@@ -10,9 +10,9 @@ from travel import (
10
  run_task
11
  )
12
 
13
- # st.set_page_config()๋Š” ๋‹ค๋ฅธ Streamlit ํ•จ์ˆ˜ ํ˜ธ์ถœ๋ณด๋‹ค ๊ฐ€์žฅ ๋จผ์ € ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
14
  st.set_page_config(
15
- page_title="Globetrotter AI: Your AI Agent for Travelling", # ๊ธฐ๋ณธ๊ฐ’์€ ์˜์–ด
16
  page_icon="โœˆ๏ธ",
17
  layout="wide",
18
  initial_sidebar_state="expanded"
@@ -52,7 +52,14 @@ translations = {
52
  "travel_agents": "Travel Agents",
53
  "share_itinerary": "Share Your Itinerary",
54
  "save_for_mobile": "Save for Mobile",
55
- "built_with": "Built with โค๏ธ for you"
 
 
 
 
 
 
 
56
  },
57
  "ko": {
58
  "page_title": "Globetrotter AI: ๋‹น์‹ ์˜ ์—ฌํ–‰์„ ์œ„ํ•œ AI ์—์ด์ „ํŠธ",
@@ -84,7 +91,14 @@ translations = {
84
  "travel_agents": "์—ฌํ–‰ ์—์ด์ „ํŠธ",
85
  "share_itinerary": "์ผ์ • ๊ณต์œ ",
86
  "save_for_mobile": "๋ชจ๋ฐ”์ผ ์ €์žฅ",
87
- "built_with": "๋‹น์‹ ์„ ์œ„ํ•ด โค๏ธ ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค"
 
 
 
 
 
 
 
88
  },
89
  "ja": {
90
  "page_title": "Globetrotter AI: ใ‚ใชใŸใฎๆ—…่กŒใฎใŸใ‚ใฎAIใ‚จใƒผใ‚ธใ‚งใƒณใƒˆ",
@@ -116,7 +130,14 @@ translations = {
116
  "travel_agents": "ๆ—…่กŒใ‚จใƒผใ‚ธใ‚งใƒณใƒˆ",
117
  "share_itinerary": "ๆ—…่กŒใƒ—ใƒฉใƒณใ‚’ๅ…ฑๆœ‰",
118
  "save_for_mobile": "ใƒขใƒใ‚คใƒซไฟๅญ˜",
119
- "built_with": "ๆ„›ใ‚’่พผใ‚ใฆไฝœใ‚‰ใ‚Œใพใ—ใŸ"
 
 
 
 
 
 
 
120
  },
121
  "zh": {
122
  "page_title": "Globetrotter AI๏ผšๆ‚จ็š„ๆ—…่กŒ AI ไปฃ็†",
@@ -148,7 +169,14 @@ translations = {
148
  "travel_agents": "ๆ—…่กŒไปฃ็†",
149
  "share_itinerary": "ๅˆ†ไบซ่กŒ็จ‹",
150
  "save_for_mobile": "ไฟๅญ˜ๅˆฐๆ‰‹ๆœบ",
151
- "built_with": "็”จโค๏ธไธบๆ‚จๅˆถไฝœ"
 
 
 
 
 
 
 
152
  },
153
  "es": {
154
  "page_title": "Globetrotter AI: Tu Agente de IA para Viajar",
@@ -180,7 +208,14 @@ translations = {
180
  "travel_agents": "Agentes de Viaje",
181
  "share_itinerary": "Compartir Itinerario",
182
  "save_for_mobile": "Guardar para Mรณvil",
183
- "built_with": "Hecho con โค๏ธ para ti"
 
 
 
 
 
 
 
184
  },
185
  "fr": {
186
  "page_title": "Globetrotter AI : Votre Agent IA pour Voyager",
@@ -212,7 +247,14 @@ translations = {
212
  "travel_agents": "Agents de Voyage",
213
  "share_itinerary": "Partager l'Itinรฉraire",
214
  "save_for_mobile": "Enregistrer pour Mobile",
215
- "built_with": "Conรงu avec โค๏ธ pour vous"
 
 
 
 
 
 
 
216
  },
217
  "de": {
218
  "page_title": "Globetrotter AI: Ihr KI-Reiseassistent",
@@ -244,7 +286,14 @@ translations = {
244
  "travel_agents": "Reiseassistenten",
245
  "share_itinerary": "Reiseroute teilen",
246
  "save_for_mobile": "Fรผr Mobilgerรคte speichern",
247
- "built_with": "Mit โค๏ธ fรผr Sie gebaut"
 
 
 
 
 
 
 
248
  },
249
  "ar": {
250
  "page_title": "Globetrotter AI: ูˆูƒูŠู„ ุงู„ุณูุฑ ุงู„ุฐูƒูŠ ุงู„ุฎุงุต ุจูƒ",
@@ -276,7 +325,14 @@ translations = {
276
  "travel_agents": "ูˆูƒู„ุงุก ุงู„ุณูุฑ",
277
  "share_itinerary": "ุดุงุฑูƒ ุฎุท ุณูŠุฑ ุงู„ุฑุญู„ุฉ",
278
  "save_for_mobile": "ุญูุธ ู„ู„ู‡ุงุชู ุงู„ู…ุญู…ูˆู„",
279
- "built_with": "ู…ุตู†ูˆุน ุจุญุจ ู…ู† ุฃุฌู„ูƒ"
 
 
 
 
 
 
 
280
  }
281
  }
282
 
@@ -544,7 +600,6 @@ def display_modern_progress(current_step, total_steps=6):
544
  5: {'status': 'pending', 'name': t("full_itinerary")}
545
  }
546
 
547
- # Update the current step status
548
  for i in range(total_steps):
549
  if i < current_step:
550
  st.session_state.progress_steps[i]['status'] = 'complete'
@@ -553,13 +608,9 @@ def display_modern_progress(current_step, total_steps=6):
553
  else:
554
  st.session_state.progress_steps[i]['status'] = 'pending'
555
 
556
- # Calculate overall progress percentage
557
  progress_percentage = (current_step / total_steps) * 100
558
-
559
- # Show overall progress bar
560
  st.progress(progress_percentage / 100)
561
 
562
- # Create a modern, compact, inline progress tracker
563
  st.markdown('''
564
  <style>
565
  .compact-progress {
@@ -617,14 +668,10 @@ def display_modern_progress(current_step, total_steps=6):
617
  <div class="compact-progress">
618
  ''', unsafe_allow_html=True)
619
 
620
- # Create grid layout
621
  st.markdown('<div class="step-grid">', unsafe_allow_html=True)
622
-
623
- # Display each step in a compact grid
624
  for i, step_info in st.session_state.progress_steps.items():
625
  status = step_info['status']
626
  name = step_info['name']
627
-
628
  if status == 'complete':
629
  icon = "โœ…"
630
  status_class = "complete"
@@ -643,44 +690,34 @@ def display_modern_progress(current_step, total_steps=6):
643
  ''', unsafe_allow_html=True)
644
 
645
  st.markdown('</div></div>', unsafe_allow_html=True)
646
-
647
  return progress_percentage
648
 
649
- # Function to update the status of a specific step
650
  def update_step_status(step_index, status):
651
  if 'progress_steps' in st.session_state and step_index in st.session_state.progress_steps:
652
  st.session_state.progress_steps[step_index]['status'] = status
653
 
654
- # Custom run_task function that updates the UI with logs and shows live agent outputs
655
  def run_task_with_logs(task, input_text, log_container, output_container, results_key=None):
656
- # Add log message
657
  log_message = f"๐Ÿค– Starting {task.agent.role}..."
658
  st.session_state.log_messages.append(log_message)
659
 
660
- # Update the log container
661
  with log_container:
662
- st.markdown("### Agent Activity")
663
  for msg in st.session_state.log_messages:
664
  st.markdown(msg)
665
 
666
- # Run the actual task
667
  result = run_task(task, input_text)
668
 
669
- # Store result if needed
670
  if results_key:
671
  st.session_state.results[results_key] = result
672
 
673
- # Add completion log message
674
  log_message = f"โœ… {task.agent.role} completed!"
675
  st.session_state.log_messages.append(log_message)
676
 
677
- # Update the log container again
678
  with log_container:
679
- st.markdown("### Agent Activity")
680
  for msg in st.session_state.log_messages:
681
  st.markdown(msg)
682
 
683
- # Display the agent's output in the output container
684
  with output_container:
685
  st.markdown(f"### {task.agent.role} Output")
686
  st.markdown("""<div class='agent-output'>""" + result + """</div>""", unsafe_allow_html=True)
@@ -717,8 +754,7 @@ if 'form_submitted' not in st.session_state:
717
  st.markdown(f'''
718
  <div class="animate-in" style="text-align: center;">
719
  <div style="margin-bottom: 20px;">
720
- <img src="https://img.icons8.com/fluency/96/travel-card.png" width="90"
721
- style="filter: drop-shadow(0 4px 8px rgba(0,0,0,0.1));">
722
  </div>
723
  <h1 class="main-header">{t("header")}</h1>
724
  <p style="font-size: 1.2rem; color: #6c757d; margin-bottom: 25px;">
@@ -727,32 +763,22 @@ st.markdown(f'''
727
  </div>
728
  ''', unsafe_allow_html=True)
729
 
730
- # Add a nice separator
731
  st.markdown('<hr style="height:3px;border:none;background-color:#f0f0f0;margin-bottom:25px;">', unsafe_allow_html=True)
732
 
733
- # Enhanced sidebar with modern design
734
  with st.sidebar:
735
- # Add a profile/brand area at the top
736
  st.markdown('''
737
- <div style="text-align: center; padding: 20px 0; margin-bottom: 20px;
738
- border-bottom: 1px solid #eaeaea;">
739
- <img src="https://img.icons8.com/fluency/96/travel-card.png" width="80"
740
- style="margin-bottom: 15px;">
741
  <h3 style="margin-bottom: 5px; color: #4361ee;">Globetrotter AI: Your AI Agent for Travelling</h3>
742
  <p style="color: #6c757d; font-size: 0.9rem;">AI-Powered Travel Planning</p>
743
  </div>
744
  ''', unsafe_allow_html=True)
745
 
746
- # About section with modern container
747
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
748
  st.markdown(f"### ๐ŸŒŸ {t('about')}")
749
- st.info(
750
- "This AI-powered tool creates a personalized travel itinerary based on your preferences. "
751
- "Fill in the form and let our specialized travel agents plan your perfect trip!"
752
- )
753
  st.markdown('</div>', unsafe_allow_html=True)
754
 
755
- # How it works with steps and icons
756
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
757
  st.markdown(f"### ๐Ÿ” {t('how_it_works')}")
758
  st.markdown("""
@@ -765,7 +791,6 @@ with st.sidebar:
765
  """, unsafe_allow_html=True)
766
  st.markdown('</div>', unsafe_allow_html=True)
767
 
768
- # Travel Agents section with icons
769
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
770
  st.markdown("### ๐Ÿค– Travel Agents")
771
  agents = [
@@ -776,67 +801,45 @@ with st.sidebar:
776
  ("๐Ÿฝ๏ธ Dining Connoisseur", "Finds the best dining experiences"),
777
  ("๐Ÿ“… Itinerary Creator", "Puts everything together in a daily plan")
778
  ]
779
-
780
  for name, desc in agents:
781
  st.markdown(f"**{name}**")
782
  st.markdown(f"<small>{desc}</small>", unsafe_allow_html=True)
783
  st.markdown('</div>', unsafe_allow_html=True)
784
 
785
- # Main content area
786
  if not st.session_state.generation_complete:
787
- # Sleek form with minimal design
788
  st.markdown('<div class="modern-card animate-in">', unsafe_allow_html=True)
789
  st.markdown(f"<h3 style='font-weight: 600; color: var(--primary-dark); display: flex; align-items: center; gap: 10px;'><span style='font-size: 20px;'>โœˆ๏ธ</span> {t('create_itinerary')}</h3>", unsafe_allow_html=True)
790
 
791
- # Minimalist description
792
  st.markdown("""
793
  <p style="color: var(--text-light); margin-bottom: 16px; font-size: 14px; font-weight: 400;">Complete the form below for a personalized travel plan.</p>
794
  """, unsafe_allow_html=True)
795
 
796
- # Form with improved layout and visual cues
797
  with st.form("travel_form"):
798
  col1, col2 = st.columns(2)
799
-
800
  with col1:
801
  st.markdown('<p style="font-weight: 500; color: var(--primary); font-size: 14px; margin-bottom: 12px;">Trip Details</p>', unsafe_allow_html=True)
802
  origin = st.text_input(t("origin"), placeholder="e.g., New York, USA")
803
  destination = st.text_input(t("destination"), placeholder="e.g., Paris, France")
804
-
805
- # Minimalist date picker
806
  st.markdown('<p style="margin-bottom: 5px; font-size: 14px;">Travel Dates</p>', unsafe_allow_html=True)
807
  start_date = st.date_input("Start Date", min_value=datetime.now(), label_visibility="collapsed")
808
  duration = st.slider(t("duration"), min_value=1, max_value=30, value=7)
809
  end_date = start_date + timedelta(days=duration-1)
810
  st.markdown(f'<p style="font-size: 13px; color: var(--text-muted); margin-top: 5px;">{start_date.strftime("%b %d")} - {end_date.strftime("%b %d, %Y")}</p>', unsafe_allow_html=True)
811
-
812
  with col2:
813
  st.markdown('<p style="font-weight: 500; color: var(--primary); font-size: 14px; margin-bottom: 12px;">Preferences</p>', unsafe_allow_html=True)
814
  travelers = st.number_input("Travelers", min_value=1, max_value=15, value=2)
815
  budget_options = ["Budget", "Moderate", "Luxury"]
816
- budget = st.selectbox("Budget", budget_options,
817
- help="Budget: Economy options | Moderate: Mid-range | Luxury: High-end experiences")
818
-
819
- # Travel style with visual selection
820
- travel_style = st.multiselect("๐ŸŒˆ Travel Style",
821
- options=["Culture", "Adventure", "Relaxation", "Food & Dining",
822
- "Nature", "Shopping", "Nightlife", "Family-friendly"],
823
- default=["Culture", "Food & Dining"])
824
-
825
- # Simplified expander for additional preferences
826
  with st.expander("Additional Preferences", expanded=False):
827
  preferences = st.text_area("Interests", placeholder="History museums, local cuisine, hiking, art...")
828
- special_requirements = st.text_area("Special Requirements",
829
- placeholder="Dietary restrictions, accessibility needs...")
830
-
831
- # Submit button
832
  submit_button = st.form_submit_button(t("submit"))
833
-
834
  st.markdown('</div>', unsafe_allow_html=True)
835
 
836
- # Process form submission
837
  if submit_button:
838
  if not origin or not destination:
839
- st.error("Please enter both origin and destination.")
840
  else:
841
  st.session_state.form_submitted = True
842
  user_input = {
@@ -850,8 +853,6 @@ if not st.session_state.generation_complete:
850
  "preferences": preferences,
851
  "special_requirements": special_requirements
852
  }
853
-
854
- # Format the user input for tasks
855
  input_context = f"""Travel Request Details:
856
  Origin: {user_input['origin']}
857
  Destination: {user_input['destination']}
@@ -863,8 +864,6 @@ Travel Style: {user_input['travel_style']}
863
  Preferences/Interests: {user_input['preferences']}
864
  Special Requirements: {user_input['special_requirements']}
865
  """
866
-
867
- # Display processing animation
868
  st.markdown("""
869
  <div class="sleek-processing-container">
870
  <div class="pulse-container">
@@ -872,7 +871,6 @@ Special Requirements: {user_input['special_requirements']}
872
  <div class="pulse-core"></div>
873
  </div>
874
  </div>
875
-
876
  <style>
877
  .sleek-processing-container {
878
  display: flex;
@@ -908,25 +906,15 @@ Special Requirements: {user_input['special_requirements']}
908
  opacity: 0;
909
  }
910
  @keyframes pulse {
911
- 0% {
912
- transform: scale(0.1);
913
- opacity: 0;
914
- }
915
- 50% {
916
- opacity: 0.5;
917
- }
918
- 100% {
919
- transform: scale(1);
920
- opacity: 0;
921
- }
922
  }
923
  </style>
924
  """, unsafe_allow_html=True)
925
 
926
- # Create containers for progress, logs, and live output
927
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
928
- progress_tab, logs_tab, details_tab = st.tabs(["๐Ÿ“Š Progress", "๐Ÿ”„ Live Activity", "๐Ÿ“‹ Request Details"])
929
-
930
  with details_tab:
931
  st.markdown("#### " + t("request_details"))
932
  st.markdown(f"**{t('destination')}:** {user_input['destination']}")
@@ -938,17 +926,14 @@ Special Requirements: {user_input['special_requirements']}
938
  st.markdown(f"**Interests:** {user_input['preferences']}")
939
  if user_input['special_requirements']:
940
  st.markdown(f"**Special Requirements:** {user_input['special_requirements']}")
941
-
942
  with progress_tab:
943
  if 'progress_placeholder' not in st.session_state:
944
  st.session_state.progress_placeholder = st.empty()
945
  with st.session_state.progress_placeholder.container():
946
  display_modern_progress(0)
947
-
948
  with logs_tab:
949
  log_container = st.container()
950
  st.session_state.log_messages = []
951
-
952
  st.markdown('</div>', unsafe_allow_html=True)
953
  output_container = st.container()
954
  with output_container:
@@ -956,105 +941,71 @@ Special Requirements: {user_input['special_requirements']}
956
  st.markdown("### ๐ŸŒŸ " + t("live_agent_outputs"))
957
  st.info("Our AI agents will show their work here as they create your itinerary")
958
  st.markdown('</div>', unsafe_allow_html=True)
959
-
960
  st.session_state.current_step = 0
961
 
962
- # Step 1: Destination Research
963
  update_step_status(0, 'active')
964
  with st.session_state.progress_placeholder.container():
965
  display_modern_progress(st.session_state.current_step)
966
-
967
  destination_info = run_task_with_logs(
968
  destination_research_task,
969
- input_context.format(
970
- destination=user_input['destination'],
971
- preferences=user_input['preferences']
972
- ),
973
  log_container,
974
  output_container,
975
  "destination_info"
976
  )
977
-
978
  update_step_status(0, 'complete')
979
  st.session_state.current_step = 1
980
  update_step_status(1, 'active')
981
  with st.session_state.progress_placeholder.container():
982
  display_modern_progress(st.session_state.current_step)
983
-
984
- # Step 2: Accommodation Recommendations
985
  accommodation_info = run_task_with_logs(
986
  accommodation_task,
987
- input_context.format(
988
- destination=user_input['destination'],
989
- budget=user_input['budget'],
990
- preferences=user_input['preferences']
991
- ),
992
  log_container,
993
  output_container,
994
  "accommodation_info"
995
  )
996
-
997
  update_step_status(1, 'complete')
998
  st.session_state.current_step = 2
999
  update_step_status(2, 'active')
1000
  with st.session_state.progress_placeholder.container():
1001
  display_modern_progress(st.session_state.current_step)
1002
-
1003
- # Step 3: Transportation Planning
1004
  transportation_info = run_task_with_logs(
1005
  transportation_task,
1006
- input_context.format(
1007
- origin=user_input['origin'],
1008
- destination=user_input['destination']
1009
- ),
1010
  log_container,
1011
  output_container,
1012
  "transportation_info"
1013
  )
1014
-
1015
  update_step_status(2, 'complete')
1016
  st.session_state.current_step = 3
1017
  update_step_status(3, 'active')
1018
  with st.session_state.progress_placeholder.container():
1019
  display_modern_progress(st.session_state.current_step)
1020
-
1021
- # Step 4: Activities & Attractions
1022
  activities_info = run_task_with_logs(
1023
  activities_task,
1024
- input_context.format(
1025
- destination=user_input['destination'],
1026
- preferences=user_input['preferences']
1027
- ),
1028
  log_container,
1029
  output_container,
1030
  "activities_info"
1031
  )
1032
-
1033
  update_step_status(3, 'complete')
1034
  st.session_state.current_step = 4
1035
  update_step_status(4, 'active')
1036
  with st.session_state.progress_placeholder.container():
1037
  display_modern_progress(st.session_state.current_step)
1038
-
1039
- # Step 5: Dining Recommendations
1040
  dining_info = run_task_with_logs(
1041
  dining_task,
1042
- input_context.format(
1043
- destination=user_input['destination'],
1044
- preferences=user_input['preferences']
1045
- ),
1046
  log_container,
1047
  output_container,
1048
  "dining_info"
1049
  )
1050
-
1051
  update_step_status(4, 'complete')
1052
  st.session_state.current_step = 5
1053
  update_step_status(5, 'active')
1054
  with st.session_state.progress_placeholder.container():
1055
  display_modern_progress(st.session_state.current_step)
1056
-
1057
- # Step 6: Create Day-by-Day Itinerary
1058
  combined_info = f"""{input_context}
1059
 
1060
  Destination Information:
@@ -1072,33 +1023,24 @@ Recommended Activities:
1072
  Dining Recommendations:
1073
  {dining_info}
1074
  """
1075
-
1076
  itinerary = run_task_with_logs(
1077
  itinerary_task,
1078
- combined_info.format(
1079
- duration=user_input['duration'],
1080
- origin=user_input['origin'],
1081
- destination=user_input['destination']
1082
- ),
1083
  log_container,
1084
  output_container,
1085
  "itinerary"
1086
  )
1087
-
1088
  update_step_status(5, 'complete')
1089
  st.session_state.current_step = 6
1090
  with st.session_state.progress_placeholder.container():
1091
  display_modern_progress(st.session_state.current_step)
1092
-
1093
  st.session_state.generated_itinerary = itinerary
1094
  st.session_state.generation_complete = True
1095
-
1096
  date_str = datetime.now().strftime("%Y-%m-%d")
1097
  st.session_state.filename = f"{user_input['destination'].replace(' ', '_')}_{date_str}_itinerary.txt"
1098
 
1099
- # Display results if generation is complete
1100
  if st.session_state.generation_complete:
1101
- st.markdown("""
1102
  <div class="modern-card animate-in">
1103
  <div style="display: flex; justify-content: center; margin-bottom: 20px;">
1104
  <div class="success-animation">
@@ -1108,8 +1050,8 @@ if st.session_state.generation_complete:
1108
  </svg>
1109
  </div>
1110
  </div>
1111
- <h2 style="text-align: center; color: #4361ee;">Your Travel Itinerary is Ready! ๐ŸŽ‰</h2>
1112
- <p style="text-align: center; color: #6c757d; margin-bottom: 20px;">We've created a personalized travel experience just for you. Explore your itinerary below.</p>
1113
  </div>
1114
 
1115
  <style>
@@ -1145,22 +1087,14 @@ if st.session_state.generation_complete:
1145
  animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards;
1146
  }
1147
  @keyframes stroke {
1148
- 100% {
1149
- stroke-dashoffset: 0;
1150
- }
1151
  }
1152
  @keyframes scale {
1153
- 0%, 100% {
1154
- transform: none;
1155
- }
1156
- 50% {
1157
- transform: scale3d(1.1, 1.1, 1);
1158
- }
1159
  }
1160
  @keyframes fill {
1161
- 100% {
1162
- box-shadow: 0 0 20px rgba(67, 97, 238, 0.3);
1163
- }
1164
  }
1165
  </style>
1166
  """, unsafe_allow_html=True)
@@ -1170,56 +1104,40 @@ if st.session_state.generation_complete:
1170
 
1171
  with itinerary_tab:
1172
  st.text_area("Your Itinerary", st.session_state.generated_itinerary, height=600)
1173
-
1174
  with details_tab:
1175
- agent_tabs = st.tabs([
1176
- "๐ŸŒŽ Destination", "๐Ÿจ Accommodation", "๐Ÿš— Transportation",
1177
- "๐ŸŽญ Activities", "๐Ÿฝ๏ธ Dining"
1178
- ])
1179
-
1180
  with agent_tabs[0]:
1181
  st.markdown("### ๐ŸŒŽ Destination Research")
1182
  st.markdown(st.session_state.results["destination_info"])
1183
-
1184
  with agent_tabs[1]:
1185
  st.markdown("### ๐Ÿจ Accommodation Options")
1186
  st.markdown(st.session_state.results["accommodation_info"])
1187
-
1188
  with agent_tabs[2]:
1189
  st.markdown("### ๐Ÿš— Transportation Plan")
1190
  st.markdown(st.session_state.results["transportation_info"])
1191
-
1192
  with agent_tabs[3]:
1193
  st.markdown("### ๐ŸŽญ Recommended Activities")
1194
  st.markdown(st.session_state.results["activities_info"])
1195
-
1196
  with agent_tabs[4]:
1197
  st.markdown("### ๐Ÿฝ๏ธ Dining Recommendations")
1198
  st.markdown(st.session_state.results["dining_info"])
1199
-
1200
  with download_tab:
1201
  col1, col2 = st.columns([2, 1])
1202
-
1203
  with col1:
1204
  st.markdown("### " + t("save_itinerary"))
1205
  st.markdown("Download your personalized travel plan to access it offline or share with your travel companions.")
1206
  st.markdown("""
1207
  <div style="background-color: #f8f9fa; padding: 15px; border-radius: 10px; margin-top: 20px;">
1208
- <h4 style="margin-top: 0;">Your Itinerary File</h4>
1209
- <p style="font-size: 0.9rem; color: #6c757d;">Text format - Can be opened in any text editor</p>
1210
  """, unsafe_allow_html=True)
1211
- st.markdown(
1212
- f"""<div style="margin: 10px 0;">{ get_download_link(st.session_state.generated_itinerary, st.session_state.filename) }</div>""",
1213
- unsafe_allow_html=True
1214
- )
1215
  st.markdown("</div>", unsafe_allow_html=True)
1216
  st.markdown("### " + t("share_itinerary"))
1217
  st.markdown("*Coming soon: Email your itinerary or share via social media.*")
1218
-
1219
  with col2:
1220
  st.markdown("### " + t("save_for_mobile"))
1221
  st.markdown("*Coming soon: QR code for easy access on your phone*")
1222
-
1223
  st.markdown('</div>', unsafe_allow_html=True)
1224
 
1225
  if st.button(t("plan_another_trip"), key="reset_button"):
 
10
  run_task
11
  )
12
 
13
+ # st.set_page_config()๋Š” ๋‹ค๋ฅธ Streamlit ํ•จ์ˆ˜๋ณด๋‹ค ๊ฐ€์žฅ ๋จผ์ € ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
14
  st.set_page_config(
15
+ page_title="Globetrotter AI: Your AI Agent for Travelling",
16
  page_icon="โœˆ๏ธ",
17
  layout="wide",
18
  initial_sidebar_state="expanded"
 
52
  "travel_agents": "Travel Agents",
53
  "share_itinerary": "Share Your Itinerary",
54
  "save_for_mobile": "Save for Mobile",
55
+ "built_with": "Built with โค๏ธ for you",
56
+ # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
57
+ "itinerary_ready": "Your Travel Itinerary is Ready! ๐ŸŽ‰",
58
+ "personalized_experience": "We've created a personalized travel experience just for you. Explore your itinerary below.",
59
+ "agent_activity": "Agent Activity",
60
+ "error_origin_destination": "Please enter both origin and destination.",
61
+ "your_itinerary_file": "Your Itinerary File",
62
+ "text_format": "Text format - Can be opened in any text editor"
63
  },
64
  "ko": {
65
  "page_title": "Globetrotter AI: ๋‹น์‹ ์˜ ์—ฌํ–‰์„ ์œ„ํ•œ AI ์—์ด์ „ํŠธ",
 
91
  "travel_agents": "์—ฌํ–‰ ์—์ด์ „ํŠธ",
92
  "share_itinerary": "์ผ์ • ๊ณต์œ ",
93
  "save_for_mobile": "๋ชจ๋ฐ”์ผ ์ €์žฅ",
94
+ "built_with": "๋‹น์‹ ์„ ์œ„ํ•ด โค๏ธ ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค",
95
+ # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
96
+ "itinerary_ready": "์—ฌํ–‰ ์ผ์ •์ด ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค! ๐ŸŽ‰",
97
+ "personalized_experience": "๋‹น์‹ ๋งŒ์„ ์œ„ํ•œ ๋งž์ถคํ˜• ์—ฌํ–‰ ๊ฒฝํ—˜์ด ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ์ผ์ •์„ ํ™•์ธํ•˜์„ธ์š”.",
98
+ "agent_activity": "์—์ด์ „ํŠธ ํ™œ๋™",
99
+ "error_origin_destination": "์ถœ๋ฐœ์ง€์™€ ๋ชฉ์ ์ง€๋ฅผ ๋ชจ๋‘ ์ž…๋ ฅํ•˜์„ธ์š”.",
100
+ "your_itinerary_file": "๋‹น์‹ ์˜ ์—ฌํ–‰ ์ผ์ • ํŒŒ์ผ",
101
+ "text_format": "ํ…์ŠคํŠธ ํ˜•์‹ - ๋ชจ๋“  ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ์—์„œ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."
102
  },
103
  "ja": {
104
  "page_title": "Globetrotter AI: ใ‚ใชใŸใฎๆ—…่กŒใฎใŸใ‚ใฎAIใ‚จใƒผใ‚ธใ‚งใƒณใƒˆ",
 
130
  "travel_agents": "ๆ—…่กŒใ‚จใƒผใ‚ธใ‚งใƒณใƒˆ",
131
  "share_itinerary": "ๆ—…่กŒใƒ—ใƒฉใƒณใ‚’ๅ…ฑๆœ‰",
132
  "save_for_mobile": "ใƒขใƒใ‚คใƒซไฟๅญ˜",
133
+ "built_with": "ๆ„›ใ‚’่พผใ‚ใฆไฝœใ‚‰ใ‚Œใพใ—ใŸ",
134
+ # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
135
+ "itinerary_ready": "ๆ—…่กŒใƒ—ใƒฉใƒณใฎๆบ–ๅ‚™ใŒใงใใพใ—ใŸ๏ผ ๐ŸŽ‰",
136
+ "personalized_experience": "ใ‚ใชใŸใฎใŸใ‚ใซใƒ‘ใƒผใ‚ฝใƒŠใƒฉใ‚คใ‚บใ•ใ‚ŒใŸๆ—…่กŒไฝ“้จ“ใ‚’ไฝœๆˆใ—ใพใ—ใŸใ€‚ไธ‹ใฎใƒ—ใƒฉใƒณใ‚’ใ”่ฆงใใ ใ•ใ„ใ€‚",
137
+ "agent_activity": "ใ‚จใƒผใ‚ธใ‚งใƒณใƒˆใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ“ใƒ†ใ‚ฃ",
138
+ "error_origin_destination": "ๅ‡บ็™บๅœฐใจ็›ฎ็š„ๅœฐใฎไธกๆ–นใ‚’ๅ…ฅๅŠ›ใ—ใฆใใ ใ•ใ„ใ€‚",
139
+ "your_itinerary_file": "ใ‚ใชใŸใฎๆ—…่กŒใƒ—ใƒฉใƒณใƒ•ใ‚กใ‚คใƒซ",
140
+ "text_format": "ใƒ†ใ‚ญใ‚นใƒˆๅฝขๅผ - ไปปๆ„ใฎใƒ†ใ‚ญใ‚นใƒˆใ‚จใƒ‡ใ‚ฃใ‚ฟใง้–‹ใ‘ใพใ™ใ€‚"
141
  },
142
  "zh": {
143
  "page_title": "Globetrotter AI๏ผšๆ‚จ็š„ๆ—…่กŒ AI ไปฃ็†",
 
169
  "travel_agents": "ๆ—…่กŒไปฃ็†",
170
  "share_itinerary": "ๅˆ†ไบซ่กŒ็จ‹",
171
  "save_for_mobile": "ไฟๅญ˜ๅˆฐๆ‰‹ๆœบ",
172
+ "built_with": "็”จโค๏ธไธบๆ‚จๅˆถไฝœ",
173
+ # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
174
+ "itinerary_ready": "ๆ‚จ็š„ๆ—…่กŒ่กŒ็จ‹ๅทฒๅ‡†ๅค‡ๅฐฑ็ปช๏ผ ๐ŸŽ‰",
175
+ "personalized_experience": "ๆˆ‘ไปฌๅทฒไธบๆ‚จๅˆ›ๅปบไบ†ไธชๆ€งๅŒ–็š„ๆ—…่กŒไฝ“้ชŒ๏ผŒ่ฏทๅœจไธ‹ๆ–นๆŸฅ็œ‹ๆ‚จ็š„่กŒ็จ‹ใ€‚",
176
+ "agent_activity": "ไปฃ็†ๆดปๅŠจ",
177
+ "error_origin_destination": "่ฏท่พ“ๅ…ฅๅ‡บๅ‘ๅœฐๅ’Œ็›ฎ็š„ๅœฐใ€‚",
178
+ "your_itinerary_file": "ๆ‚จ็š„่กŒ็จ‹ๆ–‡ไปถ",
179
+ "text_format": "ๆ–‡ๆœฌๆ ผๅผ - ๅฏๅœจไปปไฝ•ๆ–‡ๆœฌ็ผ–่พ‘ๅ™จไธญๆ‰“ๅผ€ใ€‚"
180
  },
181
  "es": {
182
  "page_title": "Globetrotter AI: Tu Agente de IA para Viajar",
 
208
  "travel_agents": "Agentes de Viaje",
209
  "share_itinerary": "Compartir Itinerario",
210
  "save_for_mobile": "Guardar para Mรณvil",
211
+ "built_with": "Hecho con โค๏ธ para ti",
212
+ # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
213
+ "itinerary_ready": "ยกTu itinerario de viaje estรก listo! ๐ŸŽ‰",
214
+ "personalized_experience": "Hemos creado una experiencia de viaje personalizada solo para ti. Explora tu itinerario a continuaciรณn.",
215
+ "agent_activity": "Actividad del Agente",
216
+ "error_origin_destination": "Por favor, ingresa tanto el origen como el destino.",
217
+ "your_itinerary_file": "Tu Archivo de Itinerario",
218
+ "text_format": "Formato de texto - Se puede abrir en cualquier editor de texto."
219
  },
220
  "fr": {
221
  "page_title": "Globetrotter AI : Votre Agent IA pour Voyager",
 
247
  "travel_agents": "Agents de Voyage",
248
  "share_itinerary": "Partager l'Itinรฉraire",
249
  "save_for_mobile": "Enregistrer pour Mobile",
250
+ "built_with": "Conรงu avec โค๏ธ pour vous",
251
+ # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
252
+ "itinerary_ready": "Votre itinรฉraire de voyage est prรชt ! ๐ŸŽ‰",
253
+ "personalized_experience": "Nous avons crรฉรฉ une expรฉrience de voyage personnalisรฉe rien que pour vous. Dรฉcouvrez votre itinรฉraire ci-dessous.",
254
+ "agent_activity": "Activitรฉ de l'Agent",
255
+ "error_origin_destination": "Veuillez saisir ร  la fois le lieu de dรฉpart et la destination.",
256
+ "your_itinerary_file": "Votre Fichier d'Itinรฉraire",
257
+ "text_format": "Format texte - Peut รชtre ouvert dans n'importe quel รฉditeur de texte."
258
  },
259
  "de": {
260
  "page_title": "Globetrotter AI: Ihr KI-Reiseassistent",
 
286
  "travel_agents": "Reiseassistenten",
287
  "share_itinerary": "Reiseroute teilen",
288
  "save_for_mobile": "Fรผr Mobilgerรคte speichern",
289
+ "built_with": "Mit โค๏ธ fรผr Sie gebaut",
290
+ # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
291
+ "itinerary_ready": "Ihre Reiseroute ist fertig! ๐ŸŽ‰",
292
+ "personalized_experience": "Wir haben eine personalisierte Reiseerfahrung nur fรผr Sie erstellt. Entdecken Sie Ihre Reiseroute unten.",
293
+ "agent_activity": "Agentenaktivitรคt",
294
+ "error_origin_destination": "Bitte geben Sie sowohl den Abfahrtsort als auch das Ziel ein.",
295
+ "your_itinerary_file": "Ihre Reise-Datei",
296
+ "text_format": "Textformat โ€“ Kann in jedem Texteditor geรถffnet werden."
297
  },
298
  "ar": {
299
  "page_title": "Globetrotter AI: ูˆูƒูŠู„ ุงู„ุณูุฑ ุงู„ุฐูƒูŠ ุงู„ุฎุงุต ุจูƒ",
 
325
  "travel_agents": "ูˆูƒู„ุงุก ุงู„ุณูุฑ",
326
  "share_itinerary": "ุดุงุฑูƒ ุฎุท ุณูŠุฑ ุงู„ุฑุญู„ุฉ",
327
  "save_for_mobile": "ุญูุธ ู„ู„ู‡ุงุชู ุงู„ู…ุญู…ูˆู„",
328
+ "built_with": "ู…ุตู†ูˆุน ุจุญุจ ู…ู† ุฃุฌู„ูƒ",
329
+ # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
330
+ "itinerary_ready": "ุชู… ุชุฌู‡ูŠุฒ ุฎุท ุณูŠุฑ ุฑุญู„ุชูƒ! ๐ŸŽ‰",
331
+ "personalized_experience": "ู„ู‚ุฏ ุฃู†ุดุฃู†ุง ุชุฌุฑุจุฉ ุณูุฑ ู…ุฎุตุตุฉ ู„ูƒ. ุงุณุชุนุฑุถ ุฎุท ุณูŠุฑ ุฑุญู„ุชูƒ ุฃุฏู†ุงู‡.",
332
+ "agent_activity": "ู†ุดุงุท ุงู„ูˆูƒูŠู„",
333
+ "error_origin_destination": "ูŠุฑุฌู‰ ุฅุฏุฎุงู„ ู†ู‚ุทุฉ ุงู„ุงู†ุทู„ุงู‚ ูˆุงู„ูˆุฌู‡ุฉ.",
334
+ "your_itinerary_file": "ู…ู„ู ุฎุท ุณูŠุฑ ุฑุญู„ุชูƒ",
335
+ "text_format": "ุชู†ุณูŠู‚ ู†ุตูŠ - ูŠู…ูƒู† ูุชุญู‡ ููŠ ุฃูŠ ู…ุญุฑุฑ ู†ุตูˆุต."
336
  }
337
  }
338
 
 
600
  5: {'status': 'pending', 'name': t("full_itinerary")}
601
  }
602
 
 
603
  for i in range(total_steps):
604
  if i < current_step:
605
  st.session_state.progress_steps[i]['status'] = 'complete'
 
608
  else:
609
  st.session_state.progress_steps[i]['status'] = 'pending'
610
 
 
611
  progress_percentage = (current_step / total_steps) * 100
 
 
612
  st.progress(progress_percentage / 100)
613
 
 
614
  st.markdown('''
615
  <style>
616
  .compact-progress {
 
668
  <div class="compact-progress">
669
  ''', unsafe_allow_html=True)
670
 
 
671
  st.markdown('<div class="step-grid">', unsafe_allow_html=True)
 
 
672
  for i, step_info in st.session_state.progress_steps.items():
673
  status = step_info['status']
674
  name = step_info['name']
 
675
  if status == 'complete':
676
  icon = "โœ…"
677
  status_class = "complete"
 
690
  ''', unsafe_allow_html=True)
691
 
692
  st.markdown('</div></div>', unsafe_allow_html=True)
 
693
  return progress_percentage
694
 
 
695
  def update_step_status(step_index, status):
696
  if 'progress_steps' in st.session_state and step_index in st.session_state.progress_steps:
697
  st.session_state.progress_steps[step_index]['status'] = status
698
 
 
699
  def run_task_with_logs(task, input_text, log_container, output_container, results_key=None):
 
700
  log_message = f"๐Ÿค– Starting {task.agent.role}..."
701
  st.session_state.log_messages.append(log_message)
702
 
 
703
  with log_container:
704
+ st.markdown("### " + t("agent_activity"))
705
  for msg in st.session_state.log_messages:
706
  st.markdown(msg)
707
 
 
708
  result = run_task(task, input_text)
709
 
 
710
  if results_key:
711
  st.session_state.results[results_key] = result
712
 
 
713
  log_message = f"โœ… {task.agent.role} completed!"
714
  st.session_state.log_messages.append(log_message)
715
 
 
716
  with log_container:
717
+ st.markdown("### " + t("agent_activity"))
718
  for msg in st.session_state.log_messages:
719
  st.markdown(msg)
720
 
 
721
  with output_container:
722
  st.markdown(f"### {task.agent.role} Output")
723
  st.markdown("""<div class='agent-output'>""" + result + """</div>""", unsafe_allow_html=True)
 
754
  st.markdown(f'''
755
  <div class="animate-in" style="text-align: center;">
756
  <div style="margin-bottom: 20px;">
757
+ <img src="https://img.icons8.com/fluency/96/travel-card.png" width="90" style="filter: drop-shadow(0 4px 8px rgba(0,0,0,0.1));">
 
758
  </div>
759
  <h1 class="main-header">{t("header")}</h1>
760
  <p style="font-size: 1.2rem; color: #6c757d; margin-bottom: 25px;">
 
763
  </div>
764
  ''', unsafe_allow_html=True)
765
 
 
766
  st.markdown('<hr style="height:3px;border:none;background-color:#f0f0f0;margin-bottom:25px;">', unsafe_allow_html=True)
767
 
 
768
  with st.sidebar:
 
769
  st.markdown('''
770
+ <div style="text-align: center; padding: 20px 0; margin-bottom: 20px; border-bottom: 1px solid #eaeaea;">
771
+ <img src="https://img.icons8.com/fluency/96/travel-card.png" width="80" style="margin-bottom: 15px;">
 
 
772
  <h3 style="margin-bottom: 5px; color: #4361ee;">Globetrotter AI: Your AI Agent for Travelling</h3>
773
  <p style="color: #6c757d; font-size: 0.9rem;">AI-Powered Travel Planning</p>
774
  </div>
775
  ''', unsafe_allow_html=True)
776
 
 
777
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
778
  st.markdown(f"### ๐ŸŒŸ {t('about')}")
779
+ st.info("This AI-powered tool creates a personalized travel itinerary based on your preferences. Fill in the form and let our specialized travel agents plan your perfect trip!")
 
 
 
780
  st.markdown('</div>', unsafe_allow_html=True)
781
 
 
782
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
783
  st.markdown(f"### ๐Ÿ” {t('how_it_works')}")
784
  st.markdown("""
 
791
  """, unsafe_allow_html=True)
792
  st.markdown('</div>', unsafe_allow_html=True)
793
 
 
794
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
795
  st.markdown("### ๐Ÿค– Travel Agents")
796
  agents = [
 
801
  ("๐Ÿฝ๏ธ Dining Connoisseur", "Finds the best dining experiences"),
802
  ("๐Ÿ“… Itinerary Creator", "Puts everything together in a daily plan")
803
  ]
 
804
  for name, desc in agents:
805
  st.markdown(f"**{name}**")
806
  st.markdown(f"<small>{desc}</small>", unsafe_allow_html=True)
807
  st.markdown('</div>', unsafe_allow_html=True)
808
 
 
809
  if not st.session_state.generation_complete:
 
810
  st.markdown('<div class="modern-card animate-in">', unsafe_allow_html=True)
811
  st.markdown(f"<h3 style='font-weight: 600; color: var(--primary-dark); display: flex; align-items: center; gap: 10px;'><span style='font-size: 20px;'>โœˆ๏ธ</span> {t('create_itinerary')}</h3>", unsafe_allow_html=True)
812
 
 
813
  st.markdown("""
814
  <p style="color: var(--text-light); margin-bottom: 16px; font-size: 14px; font-weight: 400;">Complete the form below for a personalized travel plan.</p>
815
  """, unsafe_allow_html=True)
816
 
 
817
  with st.form("travel_form"):
818
  col1, col2 = st.columns(2)
 
819
  with col1:
820
  st.markdown('<p style="font-weight: 500; color: var(--primary); font-size: 14px; margin-bottom: 12px;">Trip Details</p>', unsafe_allow_html=True)
821
  origin = st.text_input(t("origin"), placeholder="e.g., New York, USA")
822
  destination = st.text_input(t("destination"), placeholder="e.g., Paris, France")
 
 
823
  st.markdown('<p style="margin-bottom: 5px; font-size: 14px;">Travel Dates</p>', unsafe_allow_html=True)
824
  start_date = st.date_input("Start Date", min_value=datetime.now(), label_visibility="collapsed")
825
  duration = st.slider(t("duration"), min_value=1, max_value=30, value=7)
826
  end_date = start_date + timedelta(days=duration-1)
827
  st.markdown(f'<p style="font-size: 13px; color: var(--text-muted); margin-top: 5px;">{start_date.strftime("%b %d")} - {end_date.strftime("%b %d, %Y")}</p>', unsafe_allow_html=True)
 
828
  with col2:
829
  st.markdown('<p style="font-weight: 500; color: var(--primary); font-size: 14px; margin-bottom: 12px;">Preferences</p>', unsafe_allow_html=True)
830
  travelers = st.number_input("Travelers", min_value=1, max_value=15, value=2)
831
  budget_options = ["Budget", "Moderate", "Luxury"]
832
+ budget = st.selectbox("Budget", budget_options, help="Budget: Economy options | Moderate: Mid-range | Luxury: High-end experiences")
833
+ travel_style = st.multiselect("๐ŸŒˆ Travel Style", options=["Culture", "Adventure", "Relaxation", "Food & Dining", "Nature", "Shopping", "Nightlife", "Family-friendly"], default=["Culture", "Food & Dining"])
 
 
 
 
 
 
 
 
834
  with st.expander("Additional Preferences", expanded=False):
835
  preferences = st.text_area("Interests", placeholder="History museums, local cuisine, hiking, art...")
836
+ special_requirements = st.text_area("Special Requirements", placeholder="Dietary restrictions, accessibility needs...")
 
 
 
837
  submit_button = st.form_submit_button(t("submit"))
 
838
  st.markdown('</div>', unsafe_allow_html=True)
839
 
 
840
  if submit_button:
841
  if not origin or not destination:
842
+ st.error(t("error_origin_destination"))
843
  else:
844
  st.session_state.form_submitted = True
845
  user_input = {
 
853
  "preferences": preferences,
854
  "special_requirements": special_requirements
855
  }
 
 
856
  input_context = f"""Travel Request Details:
857
  Origin: {user_input['origin']}
858
  Destination: {user_input['destination']}
 
864
  Preferences/Interests: {user_input['preferences']}
865
  Special Requirements: {user_input['special_requirements']}
866
  """
 
 
867
  st.markdown("""
868
  <div class="sleek-processing-container">
869
  <div class="pulse-container">
 
871
  <div class="pulse-core"></div>
872
  </div>
873
  </div>
 
874
  <style>
875
  .sleek-processing-container {
876
  display: flex;
 
906
  opacity: 0;
907
  }
908
  @keyframes pulse {
909
+ 0% { transform: scale(0.1); opacity: 0; }
910
+ 50% { opacity: 0.5; }
911
+ 100% { transform: scale(1); opacity: 0; }
 
 
 
 
 
 
 
 
912
  }
913
  </style>
914
  """, unsafe_allow_html=True)
915
 
 
916
  st.markdown('<div class="modern-card">', unsafe_allow_html=True)
917
+ progress_tab, logs_tab, details_tab = st.tabs(["๐Ÿ“Š Progress", "๐Ÿ”„ Live Activity", "๐Ÿ“‹ " + t("request_details")])
 
918
  with details_tab:
919
  st.markdown("#### " + t("request_details"))
920
  st.markdown(f"**{t('destination')}:** {user_input['destination']}")
 
926
  st.markdown(f"**Interests:** {user_input['preferences']}")
927
  if user_input['special_requirements']:
928
  st.markdown(f"**Special Requirements:** {user_input['special_requirements']}")
 
929
  with progress_tab:
930
  if 'progress_placeholder' not in st.session_state:
931
  st.session_state.progress_placeholder = st.empty()
932
  with st.session_state.progress_placeholder.container():
933
  display_modern_progress(0)
 
934
  with logs_tab:
935
  log_container = st.container()
936
  st.session_state.log_messages = []
 
937
  st.markdown('</div>', unsafe_allow_html=True)
938
  output_container = st.container()
939
  with output_container:
 
941
  st.markdown("### ๐ŸŒŸ " + t("live_agent_outputs"))
942
  st.info("Our AI agents will show their work here as they create your itinerary")
943
  st.markdown('</div>', unsafe_allow_html=True)
 
944
  st.session_state.current_step = 0
945
 
 
946
  update_step_status(0, 'active')
947
  with st.session_state.progress_placeholder.container():
948
  display_modern_progress(st.session_state.current_step)
 
949
  destination_info = run_task_with_logs(
950
  destination_research_task,
951
+ input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
 
 
 
952
  log_container,
953
  output_container,
954
  "destination_info"
955
  )
 
956
  update_step_status(0, 'complete')
957
  st.session_state.current_step = 1
958
  update_step_status(1, 'active')
959
  with st.session_state.progress_placeholder.container():
960
  display_modern_progress(st.session_state.current_step)
 
 
961
  accommodation_info = run_task_with_logs(
962
  accommodation_task,
963
+ input_context.format(destination=user_input['destination'], budget=user_input['budget'], preferences=user_input['preferences']),
 
 
 
 
964
  log_container,
965
  output_container,
966
  "accommodation_info"
967
  )
 
968
  update_step_status(1, 'complete')
969
  st.session_state.current_step = 2
970
  update_step_status(2, 'active')
971
  with st.session_state.progress_placeholder.container():
972
  display_modern_progress(st.session_state.current_step)
 
 
973
  transportation_info = run_task_with_logs(
974
  transportation_task,
975
+ input_context.format(origin=user_input['origin'], destination=user_input['destination']),
 
 
 
976
  log_container,
977
  output_container,
978
  "transportation_info"
979
  )
 
980
  update_step_status(2, 'complete')
981
  st.session_state.current_step = 3
982
  update_step_status(3, 'active')
983
  with st.session_state.progress_placeholder.container():
984
  display_modern_progress(st.session_state.current_step)
 
 
985
  activities_info = run_task_with_logs(
986
  activities_task,
987
+ input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
 
 
 
988
  log_container,
989
  output_container,
990
  "activities_info"
991
  )
 
992
  update_step_status(3, 'complete')
993
  st.session_state.current_step = 4
994
  update_step_status(4, 'active')
995
  with st.session_state.progress_placeholder.container():
996
  display_modern_progress(st.session_state.current_step)
 
 
997
  dining_info = run_task_with_logs(
998
  dining_task,
999
+ input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
 
 
 
1000
  log_container,
1001
  output_container,
1002
  "dining_info"
1003
  )
 
1004
  update_step_status(4, 'complete')
1005
  st.session_state.current_step = 5
1006
  update_step_status(5, 'active')
1007
  with st.session_state.progress_placeholder.container():
1008
  display_modern_progress(st.session_state.current_step)
 
 
1009
  combined_info = f"""{input_context}
1010
 
1011
  Destination Information:
 
1023
  Dining Recommendations:
1024
  {dining_info}
1025
  """
 
1026
  itinerary = run_task_with_logs(
1027
  itinerary_task,
1028
+ combined_info.format(duration=user_input['duration'], origin=user_input['origin'], destination=user_input['destination']),
 
 
 
 
1029
  log_container,
1030
  output_container,
1031
  "itinerary"
1032
  )
 
1033
  update_step_status(5, 'complete')
1034
  st.session_state.current_step = 6
1035
  with st.session_state.progress_placeholder.container():
1036
  display_modern_progress(st.session_state.current_step)
 
1037
  st.session_state.generated_itinerary = itinerary
1038
  st.session_state.generation_complete = True
 
1039
  date_str = datetime.now().strftime("%Y-%m-%d")
1040
  st.session_state.filename = f"{user_input['destination'].replace(' ', '_')}_{date_str}_itinerary.txt"
1041
 
 
1042
  if st.session_state.generation_complete:
1043
+ st.markdown(f"""
1044
  <div class="modern-card animate-in">
1045
  <div style="display: flex; justify-content: center; margin-bottom: 20px;">
1046
  <div class="success-animation">
 
1050
  </svg>
1051
  </div>
1052
  </div>
1053
+ <h2 style="text-align: center; color: #4361ee;">{t("itinerary_ready")}</h2>
1054
+ <p style="text-align: center; color: #6c757d; margin-bottom: 20px;">{t("personalized_experience")}</p>
1055
  </div>
1056
 
1057
  <style>
 
1087
  animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards;
1088
  }
1089
  @keyframes stroke {
1090
+ 100% { stroke-dashoffset: 0; }
 
 
1091
  }
1092
  @keyframes scale {
1093
+ 0%, 100% { transform: none; }
1094
+ 50% { transform: scale3d(1.1, 1.1, 1); }
 
 
 
 
1095
  }
1096
  @keyframes fill {
1097
+ 100% { box-shadow: 0 0 20px rgba(67, 97, 238, 0.3); }
 
 
1098
  }
1099
  </style>
1100
  """, unsafe_allow_html=True)
 
1104
 
1105
  with itinerary_tab:
1106
  st.text_area("Your Itinerary", st.session_state.generated_itinerary, height=600)
 
1107
  with details_tab:
1108
+ agent_tabs = st.tabs(["๐ŸŒŽ Destination", "๐Ÿจ Accommodation", "๐Ÿš— Transportation", "๐ŸŽญ Activities", "๐Ÿฝ๏ธ Dining"])
 
 
 
 
1109
  with agent_tabs[0]:
1110
  st.markdown("### ๐ŸŒŽ Destination Research")
1111
  st.markdown(st.session_state.results["destination_info"])
 
1112
  with agent_tabs[1]:
1113
  st.markdown("### ๐Ÿจ Accommodation Options")
1114
  st.markdown(st.session_state.results["accommodation_info"])
 
1115
  with agent_tabs[2]:
1116
  st.markdown("### ๐Ÿš— Transportation Plan")
1117
  st.markdown(st.session_state.results["transportation_info"])
 
1118
  with agent_tabs[3]:
1119
  st.markdown("### ๐ŸŽญ Recommended Activities")
1120
  st.markdown(st.session_state.results["activities_info"])
 
1121
  with agent_tabs[4]:
1122
  st.markdown("### ๐Ÿฝ๏ธ Dining Recommendations")
1123
  st.markdown(st.session_state.results["dining_info"])
 
1124
  with download_tab:
1125
  col1, col2 = st.columns([2, 1])
 
1126
  with col1:
1127
  st.markdown("### " + t("save_itinerary"))
1128
  st.markdown("Download your personalized travel plan to access it offline or share with your travel companions.")
1129
  st.markdown("""
1130
  <div style="background-color: #f8f9fa; padding: 15px; border-radius: 10px; margin-top: 20px;">
1131
+ <h4 style="margin-top: 0;">""" + t("your_itinerary_file") + """</h4>
1132
+ <p style="font-size: 0.9rem; color: #6c757d;">""" + t("text_format") + """</p>
1133
  """, unsafe_allow_html=True)
1134
+ st.markdown(f"""<div style="margin: 10px 0;">{ get_download_link(st.session_state.generated_itinerary, st.session_state.filename) }</div>""", unsafe_allow_html=True)
 
 
 
1135
  st.markdown("</div>", unsafe_allow_html=True)
1136
  st.markdown("### " + t("share_itinerary"))
1137
  st.markdown("*Coming soon: Email your itinerary or share via social media.*")
 
1138
  with col2:
1139
  st.markdown("### " + t("save_for_mobile"))
1140
  st.markdown("*Coming soon: QR code for easy access on your phone*")
 
1141
  st.markdown('</div>', unsafe_allow_html=True)
1142
 
1143
  if st.button(t("plan_another_trip"), key="reset_button"):