openfree commited on
Commit
9b96f4f
ยท
verified ยท
1 Parent(s): 7d68120

Delete app-backup.py

Browse files
Files changed (1) hide show
  1. app-backup.py +0 -1234
app-backup.py DELETED
@@ -1,1234 +0,0 @@
1
- import streamlit as st
2
- import os
3
- import json
4
- from datetime import datetime, timedelta
5
- import base64
6
- import pandas as pd
7
- import pydeck as pdk
8
- from travel import (
9
- destination_research_task, accommodation_task, transportation_task,
10
- activities_task, dining_task, itinerary_task, chatbot_task,
11
- run_task
12
- )
13
-
14
- # st.set_page_config()๋Š” ๋‹ค๋ฅธ Streamlit ํ•จ์ˆ˜๋ณด๋‹ค ๊ฐ€์žฅ ๋จผ์ € ์‹คํ–‰๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
15
- st.set_page_config(
16
- page_title="Your AI Agent for Travelling",
17
- page_icon="โœˆ๏ธ",
18
- layout="wide",
19
- initial_sidebar_state="expanded"
20
- )
21
-
22
- # ------------------------------------------
23
- # ๋‹ค๊ตญ์–ด ์ง€์›์„ ์œ„ํ•œ ๋ฒˆ์—ญ ์‚ฌ์ „ ๋ฐ ํ—ฌํผ ํ•จ์ˆ˜
24
- # ------------------------------------------
25
- translations = {
26
- "en": {
27
- "page_title": "Your AI Agent for Travelling",
28
- "header": "Your AI Agent for Travelling",
29
- "create_itinerary": "Create Your Itinerary",
30
- "trip_details": "Trip Details",
31
- "origin": "Origin",
32
- "destination": "Destination",
33
- "travel_dates": "Travel Dates",
34
- "duration": "Duration (days)",
35
- "preferences": "Preferences",
36
- "additional_preferences": "Additional Preferences",
37
- "interests": "Interests",
38
- "special_requirements": "Special Requirements",
39
- "submit": "๐Ÿš€ Create My Personal Travel Itinerary",
40
- "request_details": "Your Travel Request",
41
- "from": "From",
42
- "when": "When",
43
- "budget": "Budget",
44
- "travel_style": "Travel Style",
45
- "live_agent_outputs": "Live Agent Outputs",
46
- "full_itinerary": "Full Itinerary",
47
- "details": "Details",
48
- "download_share": "Download & Share",
49
- "save_itinerary": "Save Your Itinerary",
50
- "plan_another_trip": "๐Ÿ”„ Plan Another Trip",
51
- "about": "About",
52
- "how_it_works": "How it works",
53
- "travel_agents": "Travel Agents",
54
- "share_itinerary": "Share Your Itinerary",
55
- "save_for_mobile": "Save for Mobile",
56
- "built_with": "Built with โค๏ธ for you",
57
- # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
58
- "itinerary_ready": "Your Travel Itinerary is Ready! ๐ŸŽ‰",
59
- "personalized_experience": "We've created a personalized travel experience just for you. Explore your itinerary below.",
60
- "agent_activity": "Agent Activity",
61
- "error_origin_destination": "Please enter both origin and destination.",
62
- "your_itinerary_file": "Your Itinerary File",
63
- "text_format": "Text format - Can be opened in any text editor"
64
- },
65
- "ko": {
66
- "page_title": "๋‹น์‹ ์˜ ์—ฌํ–‰์„ ์œ„ํ•œ AI ์—์ด์ „ํŠธ",
67
- "header": "๋‹น์‹ ์˜ ์—ฌํ–‰์„ ์œ„ํ•œ AI ์—์ด์ „ํŠธ",
68
- "create_itinerary": "์—ฌํ–‰ ์ผ์ • ์ƒ์„ฑ",
69
- "trip_details": "์—ฌํ–‰ ์„ธ๋ถ€ ์ •๋ณด",
70
- "origin": "์ถœ๋ฐœ์ง€",
71
- "destination": "๋ชฉ์ ์ง€",
72
- "travel_dates": "์—ฌํ–‰ ๋‚ ์งœ",
73
- "duration": "๊ธฐ๊ฐ„ (์ผ์ˆ˜)",
74
- "preferences": "์„ ํ˜ธ์‚ฌํ•ญ",
75
- "additional_preferences": "์ถ”๊ฐ€ ์„ ํ˜ธ์‚ฌํ•ญ",
76
- "interests": "๊ด€์‹ฌ์‚ฌ",
77
- "special_requirements": "ํŠน๋ณ„ ์š”๊ตฌ์‚ฌํ•ญ",
78
- "submit": "๐Ÿš€ ๋‚˜๋งŒ์˜ ์—ฌํ–‰ ์ผ์ • ์ƒ์„ฑ",
79
- "request_details": "์—ฌํ–‰ ์š”์ฒญ ์ •๋ณด",
80
- "from": "์ถœ๋ฐœ์ง€",
81
- "when": "์—ฌํ–‰ ๊ธฐ๊ฐ„",
82
- "budget": "์˜ˆ์‚ฐ",
83
- "travel_style": "์—ฌํ–‰ ์Šคํƒ€์ผ",
84
- "live_agent_outputs": "์‹ค์‹œ๊ฐ„ ์—์ด์ „ํŠธ ๊ฒฐ๊ณผ",
85
- "full_itinerary": "์ „์ฒด ์ผ์ •",
86
- "details": "์„ธ๋ถ€์‚ฌํ•ญ",
87
- "download_share": "๋‹ค์šด๋กœ๋“œ ๋ฐ ๊ณต์œ ",
88
- "save_itinerary": "์ผ์ • ์ €์žฅ",
89
- "plan_another_trip": "๐Ÿ”„ ๋‹ค๋ฅธ ์—ฌํ–‰ ๊ณ„ํš",
90
- "about": "์†Œ๊ฐœ",
91
- "how_it_works": "์ž‘๋™ ๋ฐฉ์‹",
92
- "travel_agents": "์—ฌํ–‰ ์—์ด์ „ํŠธ",
93
- "share_itinerary": "์ผ์ • ๊ณต์œ ",
94
- "save_for_mobile": "๋ชจ๋ฐ”์ผ ์ €์žฅ",
95
- "built_with": "๋‹น์‹ ์„ ์œ„ํ•ด โค๏ธ ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค",
96
- # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
97
- "itinerary_ready": "์—ฌํ–‰ ์ผ์ •์ด ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค! ๐ŸŽ‰",
98
- "personalized_experience": "๋‹น์‹ ๋งŒ์„ ์œ„ํ•œ ๋งž์ถคํ˜• ์—ฌํ–‰ ๊ฒฝํ—˜์ด ๋งŒ๋“ค์–ด์กŒ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜์—์„œ ์ผ์ •์„ ํ™•์ธํ•˜์„ธ์š”.",
99
- "agent_activity": "์—์ด์ „ํŠธ ํ™œ๋™",
100
- "error_origin_destination": "์ถœ๋ฐœ์ง€์™€ ๋ชฉ์ ์ง€๋ฅผ ๋ชจ๋‘ ์ž…๋ ฅํ•˜์„ธ์š”.",
101
- "your_itinerary_file": "๋‹น์‹ ์˜ ์—ฌํ–‰ ์ผ์ • ํŒŒ์ผ",
102
- "text_format": "ํ…์ŠคํŠธ ํ˜•์‹ - ๋ชจ๋“  ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ์—์„œ ์—ด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค."
103
- },
104
- "ja": {
105
- "page_title": "ใ‚ใชใŸใฎๆ—…่กŒใฎใŸใ‚ใฎAIใ‚จใƒผใ‚ธใ‚งใƒณใƒˆ",
106
- "header": "ใ‚ใชใŸใฎๆ—…่กŒใฎใŸใ‚ใฎAIใ‚จใƒผใ‚ธใ‚งใƒณใƒˆ",
107
- "create_itinerary": "ๆ—…่กŒใƒ—ใƒฉใƒณไฝœๆˆ",
108
- "trip_details": "ๆ—…่กŒ่ฉณ็ดฐ",
109
- "origin": "ๅ‡บ็™บๅœฐ",
110
- "destination": "็›ฎ็š„ๅœฐ",
111
- "travel_dates": "ๆ—…่กŒๆ—ฅ็จ‹",
112
- "duration": "ๆœŸ้–“๏ผˆๆ—ฅๆ•ฐ๏ผ‰",
113
- "preferences": "ๅฅฝใฟ",
114
- "additional_preferences": "่ฟฝๅŠ ใฎๅฅฝใฟ",
115
- "interests": "่ˆˆๅ‘ณ",
116
- "special_requirements": "็‰นๅˆฅใช่ฆไปถ",
117
- "submit": "๐Ÿš€ ็งใฎใŸใ‚ใฎๆ—…่กŒใƒ—ใƒฉใƒณไฝœๆˆ",
118
- "request_details": "ๆ—…่กŒใƒชใ‚ฏใ‚จใ‚นใƒˆ",
119
- "from": "ๅ‡บ็™บๅœฐ",
120
- "when": "ๆ—…่กŒๆœŸ้–“",
121
- "budget": "ไบˆ็ฎ—",
122
- "travel_style": "ๆ—…่กŒใ‚นใ‚ฟใ‚คใƒซ",
123
- "live_agent_outputs": "ใƒชใ‚ขใƒซใ‚ฟใ‚คใƒ ใ‚จใƒผใ‚ธใ‚งใƒณใƒˆๅ‡บๅŠ›",
124
- "full_itinerary": "ๅ…จ่กŒ็จ‹",
125
- "details": "่ฉณ็ดฐ",
126
- "download_share": "ใƒ€ใ‚ฆใƒณใƒญใƒผใƒ‰ใจๅ…ฑๆœ‰",
127
- "save_itinerary": "ๆ—…่กŒใƒ—ใƒฉใƒณใ‚’ไฟๅญ˜",
128
- "plan_another_trip": "๐Ÿ”„ ไป–ใฎๆ—…่กŒใ‚’่จˆ็”ป",
129
- "about": "ๆฆ‚่ฆ",
130
- "how_it_works": "ไฝฟใ„ๆ–น",
131
- "travel_agents": "ๆ—…่กŒใ‚จใƒผใ‚ธใ‚งใƒณใƒˆ",
132
- "share_itinerary": "ๆ—…่กŒใƒ—ใƒฉใƒณใ‚’ๅ…ฑๆœ‰",
133
- "save_for_mobile": "ใƒขใƒใ‚คใƒซไฟๅญ˜",
134
- "built_with": "ๆ„›ใ‚’่พผใ‚ใฆไฝœใ‚‰ใ‚Œใพใ—ใŸ",
135
- # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
136
- "itinerary_ready": "ๆ—…่กŒใƒ—ใƒฉใƒณใฎๆบ–ๅ‚™ใŒใงใใพใ—ใŸ๏ผ ๐ŸŽ‰",
137
- "personalized_experience": "ใ‚ใชใŸใฎใŸใ‚ใซใƒ‘ใƒผใ‚ฝใƒŠใƒฉใ‚คใ‚บใ•ใ‚ŒใŸๆ—…่กŒไฝ“้จ“ใ‚’ไฝœๆˆใ—ใพใ—ใŸใ€‚ไธ‹ใฎใƒ—ใƒฉใƒณใ‚’ใ”่ฆงใใ ใ•ใ„ใ€‚",
138
- "agent_activity": "ใ‚จใƒผใ‚ธใ‚งใƒณใƒˆใ‚ขใ‚ฏใƒ†ใ‚ฃใƒ“ใƒ†ใ‚ฃ",
139
- "error_origin_destination": "ๅ‡บ็™บๅœฐใจ็›ฎ็š„ๅœฐใฎไธกๆ–นใ‚’ๅ…ฅๅŠ›ใ—ใฆใใ ใ•ใ„ใ€‚",
140
- "your_itinerary_file": "ใ‚ใชใŸใฎๆ—…่กŒใƒ—ใƒฉใƒณใƒ•ใ‚กใ‚คใƒซ",
141
- "text_format": "ใƒ†ใ‚ญใ‚นใƒˆๅฝขๅผ - ไปปๆ„ใฎใƒ†ใ‚ญใ‚นใƒˆใ‚จใƒ‡ใ‚ฃใ‚ฟใง้–‹ใ‘ใพใ™ใ€‚"
142
- },
143
- "zh": {
144
- "page_title": "ๆ‚จ็š„ๆ—…่กŒ AI ไปฃ็†",
145
- "header": "ๆ‚จ็š„ๆ—…่กŒ AI ไปฃ็†",
146
- "create_itinerary": "ๅˆ›ๅปบๆ‚จ็š„่กŒ็จ‹",
147
- "trip_details": "ๆ—…่กŒ่ฏฆๆƒ…",
148
- "origin": "ๅ‡บๅ‘ๅœฐ",
149
- "destination": "็›ฎ็š„ๅœฐ",
150
- "travel_dates": "ๆ—…่กŒๆ—ฅๆœŸ",
151
- "duration": "ๅคฉๆ•ฐ",
152
- "preferences": "ๅๅฅฝ",
153
- "additional_preferences": "ๅ…ถไป–ๅๅฅฝ",
154
- "interests": "ๅ…ด่ถฃ",
155
- "special_requirements": "็‰นๆฎŠ้œ€ๆฑ‚",
156
- "submit": "๐Ÿš€ ๅˆ›ๅปบๆˆ‘็š„ไธชๆ€งๅŒ–่กŒ็จ‹",
157
- "request_details": "ๆ‚จ็š„ๆ—…่กŒ่ฏทๆฑ‚",
158
- "from": "ๅ‡บๅ‘ๅœฐ",
159
- "when": "ๆ—…่กŒๆ—ถ้—ด",
160
- "budget": "้ข„็ฎ—",
161
- "travel_style": "ๆ—…่กŒ้ฃŽๆ ผ",
162
- "live_agent_outputs": "ๅฎžๆ—ถไปฃ็†่พ“ๅ‡บ",
163
- "full_itinerary": "ๅฎŒๆ•ด่กŒ็จ‹",
164
- "details": "่ฏฆๆƒ…",
165
- "download_share": "ไธ‹่ฝฝไธŽๅˆ†ไบซ",
166
- "save_itinerary": "ไฟๅญ˜่กŒ็จ‹",
167
- "plan_another_trip": "๐Ÿ”„ ่ฎกๅˆ’ๅฆไธ€่ถŸๆ—…่กŒ",
168
- "about": "ๅ…ณไบŽ",
169
- "how_it_works": "ๅทฅไฝœๅŽŸ็†",
170
- "travel_agents": "ๆ—…่กŒไปฃ็†",
171
- "share_itinerary": "ๅˆ†ไบซ่กŒ็จ‹",
172
- "save_for_mobile": "ไฟๅญ˜ๅˆฐๆ‰‹ๆœบ",
173
- "built_with": "็”จโค๏ธไธบๆ‚จๅˆถไฝœ",
174
- # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
175
- "itinerary_ready": "ๆ‚จ็š„ๆ—…่กŒ่กŒ็จ‹ๅทฒๅ‡†ๅค‡ๅฐฑ็ปช๏ผ ๐ŸŽ‰",
176
- "personalized_experience": "ๆˆ‘ไปฌๅทฒไธบๆ‚จๅˆ›ๅปบไบ†ไธชๆ€งๅŒ–็š„ๆ—…่กŒไฝ“้ชŒ๏ผŒ่ฏทๅœจไธ‹ๆ–นๆŸฅ็œ‹ๆ‚จ็š„่กŒ็จ‹ใ€‚",
177
- "agent_activity": "ไปฃ็†ๆดปๅŠจ",
178
- "error_origin_destination": "่ฏท่พ“ๅ…ฅๅ‡บๅ‘ๅœฐๅ’Œ็›ฎ็š„ๅœฐใ€‚",
179
- "your_itinerary_file": "ๆ‚จ็š„่กŒ็จ‹ๆ–‡ไปถ",
180
- "text_format": "ๆ–‡ๆœฌๆ ผๅผ - ๅฏๅœจไปปไฝ•ๆ–‡ๆœฌ็ผ–่พ‘ๅ™จไธญๆ‰“ๅผ€ใ€‚"
181
- },
182
- "es": {
183
- "page_title": " Tu Agente de IA para Viajar",
184
- "header": " Tu Agente de IA para Viajar",
185
- "create_itinerary": "Crea Tu Itinerario",
186
- "trip_details": "Detalles del Viaje",
187
- "origin": "Origen",
188
- "destination": "Destino",
189
- "travel_dates": "Fechas del Viaje",
190
- "duration": "Duraciรณn (dรญas)",
191
- "preferences": "Preferencias",
192
- "additional_preferences": "Preferencias Adicionales",
193
- "interests": "Intereses",
194
- "special_requirements": "Requisitos Especiales",
195
- "submit": "๐Ÿš€ Crea Mi Itinerario Personalizado",
196
- "request_details": "Tu Solicitud de Viaje",
197
- "from": "Desde",
198
- "when": "Cuรกndo",
199
- "budget": "Presupuesto",
200
- "travel_style": "Estilo de Viaje",
201
- "live_agent_outputs": "Salidas en Vivo del Agente",
202
- "full_itinerary": "Itinerario Completo",
203
- "details": "Detalles",
204
- "download_share": "Descargar y Compartir",
205
- "save_itinerary": "Guardar Itinerario",
206
- "plan_another_trip": "๐Ÿ”„ Planear Otro Viaje",
207
- "about": "Acerca de",
208
- "how_it_works": "Cรณmo Funciona",
209
- "travel_agents": "Agentes de Viaje",
210
- "share_itinerary": "Compartir Itinerario",
211
- "save_for_mobile": "Guardar para Mรณvil",
212
- "built_with": "Hecho con โค๏ธ para ti",
213
- # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
214
- "itinerary_ready": "ยกTu itinerario de viaje estรก listo! ๐ŸŽ‰",
215
- "personalized_experience": "Hemos creado una experiencia de viaje personalizada solo para ti. Explora tu itinerario a continuaciรณn.",
216
- "agent_activity": "Actividad del Agente",
217
- "error_origin_destination": "Por favor, ingresa tanto el origen como el destino.",
218
- "your_itinerary_file": "Tu Archivo de Itinerario",
219
- "text_format": "Formato de texto - Se puede abrir en cualquier editor de texto."
220
- },
221
- "fr": {
222
- "page_title": " Votre Agent IA pour Voyager",
223
- "header": " Votre Agent IA pour Voyager",
224
- "create_itinerary": "Crรฉez Votre Itinรฉraire",
225
- "trip_details": "Dรฉtails du Voyage",
226
- "origin": "Origine",
227
- "destination": "Destination",
228
- "travel_dates": "Dates du Voyage",
229
- "duration": "Durรฉe (jours)",
230
- "preferences": "Prรฉfรฉrences",
231
- "additional_preferences": "Prรฉfรฉrences Supplรฉmentaires",
232
- "interests": "Centres d'intรฉrรชt",
233
- "special_requirements": "Exigences Spรฉciales",
234
- "submit": "๐Ÿš€ Crรฉez Mon Itinรฉraire Personnalisรฉ",
235
- "request_details": "Votre Demande de Voyage",
236
- "from": "De",
237
- "when": "Quand",
238
- "budget": "Budget",
239
- "travel_style": "Style de Voyage",
240
- "live_agent_outputs": "Rรฉsultats en Direct de l'Agent",
241
- "full_itinerary": "Itinรฉraire Complet",
242
- "details": "Dรฉtails",
243
- "download_share": "Tรฉlรฉcharger et Partager",
244
- "save_itinerary": "Enregistrer l'Itinรฉraire",
245
- "plan_another_trip": "๐Ÿ”„ Planifier un Autre Voyage",
246
- "about": "ร€ Propos",
247
- "how_it_works": "Fonctionnement",
248
- "travel_agents": "Agents de Voyage",
249
- "share_itinerary": "Partager l'Itinรฉraire",
250
- "save_for_mobile": "Enregistrer pour Mobile",
251
- "built_with": "Conรงu avec โค๏ธ pour vous",
252
- # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
253
- "itinerary_ready": "Votre itinรฉraire de voyage est prรชt ! ๐ŸŽ‰",
254
- "personalized_experience": "Nous avons crรฉรฉ une expรฉrience de voyage personnalisรฉe rien que pour vous. Dรฉcouvrez votre itinรฉraire ci-dessous.",
255
- "agent_activity": "Activitรฉ de l'Agent",
256
- "error_origin_destination": "Veuillez saisir ร  la fois le lieu de dรฉpart et la destination.",
257
- "your_itinerary_file": "Votre Fichier d'Itinรฉraire",
258
- "text_format": "Format texte - Peut รชtre ouvert dans n'importe quel รฉditeur de texte."
259
- },
260
- "de": {
261
- "page_title": "Ihr KI-Reiseassistent",
262
- "header": " Ihr KI-Reiseassistent",
263
- "create_itinerary": "Erstellen Sie Ihre Reiseroute",
264
- "trip_details": "Reisedetails",
265
- "origin": "Abfahrtsort",
266
- "destination": "Zielort",
267
- "travel_dates": "Reisedaten",
268
- "duration": "Dauer (Tage)",
269
- "preferences": "Vorlieben",
270
- "additional_preferences": "Zusรคtzliche Vorlieben",
271
- "interests": "Interessen",
272
- "special_requirements": "Besondere Anforderungen",
273
- "submit": "๐Ÿš€ Erstellen Sie meine personalisierte Reiseroute",
274
- "request_details": "Ihre Reiseanfrage",
275
- "from": "Von",
276
- "when": "Wann",
277
- "budget": "Budget",
278
- "travel_style": "Reisestil",
279
- "live_agent_outputs": "Live Agent Ausgaben",
280
- "full_itinerary": "Komplette Reiseroute",
281
- "details": "Details",
282
- "download_share": "Herunterladen & Teilen",
283
- "save_itinerary": "Reiseroute speichern",
284
- "plan_another_trip": "๐Ÿ”„ Plane eine weitere Reise",
285
- "about": "รœber",
286
- "how_it_works": "Wie es funktioniert",
287
- "travel_agents": "Reiseassistenten",
288
- "share_itinerary": "Reiseroute teilen",
289
- "save_for_mobile": "Fรผr Mobilgerรคte speichern",
290
- "built_with": "Mit โค๏ธ fรผr Sie gebaut",
291
- # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
292
- "itinerary_ready": "Ihre Reiseroute ist fertig! ๐ŸŽ‰",
293
- "personalized_experience": "Wir haben eine personalisierte Reiseerfahrung nur fรผr Sie erstellt. Entdecken Sie Ihre Reiseroute unten.",
294
- "agent_activity": "Agentenaktivitรคt",
295
- "error_origin_destination": "Bitte geben Sie sowohl den Abfahrtsort als auch das Ziel ein.",
296
- "your_itinerary_file": "Ihre Reise-Datei",
297
- "text_format": "Textformat โ€“ Kann in jedem Texteditor geรถffnet werden."
298
- },
299
- "ar": {
300
- "page_title": " ูˆูƒูŠู„ ุงู„ุณูุฑ ุงู„ุฐูƒูŠ ุงู„ุฎุงุต ุจูƒ",
301
- "header": " ูˆูƒูŠู„ ุงู„ุณูุฑ ุงู„ุฐูƒูŠ ุงู„ุฎุงุต ุจูƒ",
302
- "create_itinerary": "ุฅู†ุดุงุก ุฎุท ุณูŠุฑ ุงู„ุฑุญู„ุฉ",
303
- "trip_details": "ุชูุงุตูŠู„ ุงู„ุฑุญู„ุฉ",
304
- "origin": "ุงู„ู…ุบุงุฏุฑุฉ ู…ู†",
305
- "destination": "ุงู„ูˆุฌู‡ุฉ",
306
- "travel_dates": "ุชูˆุงุฑูŠุฎ ุงู„ุณูุฑ",
307
- "duration": "ุงู„ู…ุฏุฉ (ุจุงู„ุฃูŠุงู…)",
308
- "preferences": "ุงู„ุชูุถูŠู„ุงุช",
309
- "additional_preferences": "ุชูุถูŠู„ุงุช ุฅุถุงููŠุฉ",
310
- "interests": "ุงู„ุงู‡ุชู…ุงู…ุงุช",
311
- "special_requirements": "ุงู„ู…ุชุทู„ุจุงุช ุงู„ุฎุงุตุฉ",
312
- "submit": "๐Ÿš€ ุฅู†ุดุงุก ุฎุท ุณูŠุฑ ุงู„ุฑุญู„ุฉ ุงู„ุดุฎุตูŠ",
313
- "request_details": "ุทู„ุจ ุงู„ุณูุฑ ุงู„ุฎุงุต ุจูƒ",
314
- "from": "ู…ู†",
315
- "when": "ู…ุชู‰",
316
- "budget": "ุงู„ู…ูŠุฒุงู†ูŠุฉ",
317
- "travel_style": "ุฃุณู„ูˆุจ ุงู„ุณูุฑ",
318
- "live_agent_outputs": "ู…ุฎุฑุฌุงุช ุงู„ูˆูƒูŠู„ ุงู„ู…ุจุงุดุฑุฉ",
319
- "full_itinerary": "ุฎุท ุณูŠุฑ ุงู„ุฑุญู„ุฉ ุงู„ูƒุงู…ู„",
320
- "details": "ุงู„ุชูุงุตูŠู„",
321
- "download_share": "ุชู†ุฒูŠู„ ูˆู…ุดุงุฑูƒุฉ",
322
- "save_itinerary": "ุญูุธ ุฎุท ุณูŠุฑ ุงู„ุฑุญู„ุฉ",
323
- "plan_another_trip": "๐Ÿ”„ ุฎุทุท ู„ุฑุญู„ุฉ ุฃุฎุฑู‰",
324
- "about": "ุญูˆู„",
325
- "how_it_works": "ูƒูŠู ูŠุนู…ู„",
326
- "travel_agents": "ูˆูƒู„ุงุก ุงู„ุณูุฑ",
327
- "share_itinerary": "ุดุงุฑูƒ ุฎุท ุณูŠุฑ ุงู„ุฑุญู„ุฉ",
328
- "save_for_mobile": "ุญูุธ ู„ู„ู‡ุงุชู ุงู„ู…ุญู…ูˆู„",
329
- "built_with": "ู…ุตู†ูˆุน ุจุญุจ ู…ู† ุฃุฌู„ูƒ",
330
- # ์ถœ๋ ฅ ๊ด€๋ จ ์ถ”๊ฐ€ ํ…์ŠคํŠธ
331
- "itinerary_ready": "ุชู… ุชุฌู‡ูŠุฒ ุฎุท ุณูŠุฑ ุฑุญู„ุชูƒ! ๐ŸŽ‰",
332
- "personalized_experience": "ู„ู‚ุฏ ุฃู†ุดุฃู†ุง ุชุฌุฑุจุฉ ุณูุฑ ู…ุฎุตุตุฉ ู„ูƒ. ุงุณุชุนุฑุถ ุฎุท ุณูŠุฑ ุฑุญู„ุชูƒ ุฃุฏู†ุงู‡.",
333
- "agent_activity": "ู†ุดุงุท ุงู„ูˆูƒูŠู„",
334
- "error_origin_destination": "ูŠุฑุฌู‰ ุฅุฏุฎุงู„ ู†ู‚ุทุฉ ุงู„ุงู†ุทู„ุงู‚ ูˆุงู„ูˆุฌู‡ุฉ.",
335
- "your_itinerary_file": "ู…ู„ู ุฎุท ุณูŠุฑ ุฑุญู„ุชูƒ",
336
- "text_format": "ุชู†ุณูŠู‚ ู†ุตูŠ - ูŠู…ูƒู† ูุชุญู‡ ููŠ ุฃูŠ ู…ุญุฑุฑ ู†ุตูˆุต."
337
- }
338
- }
339
-
340
- def t(key):
341
- lang = st.session_state.get("selected_language", "en")
342
- return translations[lang].get(key, key)
343
-
344
- # ---------------------------
345
- # ์„ธ์…˜ ์ดˆ๊ธฐํ™”
346
- # ---------------------------
347
- if 'selected_language' not in st.session_state:
348
- st.session_state.selected_language = "en" # ๊ธฐ๋ณธ์€ ์˜์–ด
349
-
350
- # ------------------------------------------
351
- # ์‚ฌ์ด๋“œ๋ฐ”์— ์–ธ์–ด ์„ ํƒ ์œ„์ ฏ ์ถ”๊ฐ€
352
- # ------------------------------------------
353
- with st.sidebar:
354
- language = st.selectbox(
355
- "Language / ์–ธ์–ด / ่จ€่ชž / ่ฏญ่จ€ / Idioma / Langue / Sprache / ุงู„ู„ุบุฉ",
356
- ["English", "ํ•œ๊ตญ์–ด", "ๆ—ฅๆœฌ่ชž", "ไธญๆ–‡", "Espaรฑol", "Franรงais", "Deutsch", "ุงู„ุนุฑุจูŠุฉ"]
357
- )
358
- lang_map = {
359
- "English": "en",
360
- "ํ•œ๊ตญ์–ด": "ko",
361
- "ๆ—ฅๆœฌ่ชž": "ja",
362
- "ไธญๆ–‡": "zh",
363
- "Espaรฑol": "es",
364
- "Franรงais": "fr",
365
- "Deutsch": "de",
366
- "ุงู„ุนุฑุจูŠุฉ": "ar"
367
- }
368
- st.session_state.selected_language = lang_map.get(language, "en")
369
-
370
- # ------------------------------------------
371
- # ์ดํ›„ Streamlit UI ์ฝ”๋“œ ์‹œ์ž‘
372
- # ------------------------------------------
373
-
374
- # Modern CSS with refined color scheme and sleek animations
375
- st.markdown("""
376
- <style>
377
- /* Sleek Color Palette */
378
- :root {
379
- --primary: #3a86ff;
380
- --primary-light: #4895ef;
381
- --primary-dark: #2667ff;
382
- --secondary: #4cc9f0;
383
- --accent: #4361ee;
384
- --background: #f8f9fa;
385
- --card-bg: #ffffff;
386
- --text: #212529;
387
- --text-light: #6c757d;
388
- --text-muted: #adb5bd;
389
- --border: #e9ecef;
390
- --success: #2ecc71;
391
- --warning: #f39c12;
392
- --info: #3498db;
393
- }
394
-
395
- /* Refined Animations */
396
- @keyframes smoothFadeIn {
397
- from { opacity: 0; transform: translateY(10px); }
398
- to { opacity: 1; transform: translateY(0); }
399
- }
400
-
401
- @keyframes slideInRight {
402
- from { opacity: 0; transform: translateX(20px); }
403
- to { opacity: 1; transform: translateX(0); }
404
- }
405
-
406
- .animate-in {
407
- animation: smoothFadeIn 0.5s cubic-bezier(0.215, 0.61, 0.355, 1);
408
- }
409
-
410
- .slide-in {
411
- animation: slideInRight 0.5s cubic-bezier(0.215, 0.61, 0.355, 1);
412
- }
413
-
414
- /* Sleek Header Styles */
415
- .main-header {
416
- font-size: 2.5rem;
417
- color: var(--primary-dark);
418
- text-align: center;
419
- margin-bottom: 0.8rem;
420
- font-weight: 700;
421
- letter-spacing: -0.5px;
422
- }
423
-
424
- .sub-header {
425
- font-size: 1.4rem;
426
- color: var(--accent);
427
- font-weight: 600;
428
- margin-top: 1.8rem;
429
- margin-bottom: 0.8rem;
430
- border-bottom: 1px solid var(--border);
431
- padding-bottom: 0.4rem;
432
- }
433
-
434
- /* Sleek Card Styles */
435
- .modern-card {
436
- background-color: var(--card-bg);
437
- border-radius: 10px;
438
- padding: 1.2rem;
439
- margin-bottom: 1.2rem;
440
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
441
- transition: all 0.25s ease;
442
- border: 1px solid var(--border);
443
- }
444
-
445
- .modern-card:hover {
446
- transform: translateY(-3px);
447
- box-shadow: 0 4px 15px rgba(0, 0, 0, 0.08);
448
- }
449
-
450
- /* Refined Form Styles */
451
- .stTextInput > div > div > input,
452
- .stDateInput > div > div > input,
453
- .stTextArea > div > div > textarea {
454
- border-radius: 6px;
455
- border: 1px solid var(--border);
456
- padding: 10px 12px;
457
- font-size: 14px;
458
- transition: all 0.2s ease;
459
- box-shadow: none;
460
- }
461
-
462
- .stTextInput > div > div > input:focus,
463
- .stDateInput > div > div > input:focus,
464
- .stTextArea > div > div > textarea:focus {
465
- border: 1px solid var(--primary);
466
- box-shadow: 0 0 0 1px rgba(58, 134, 255, 0.15);
467
- }
468
-
469
- /* Sleek Button Styles */
470
- .stButton > button {
471
- background-color: var(--primary);
472
- color: white;
473
- font-weight: 500;
474
- padding: 0.5rem 1.2rem;
475
- border-radius: 6px;
476
- border: none;
477
- transition: all 0.2s ease;
478
- font-size: 14px;
479
- letter-spacing: 0.3px;
480
- }
481
-
482
- .stButton > button:hover {
483
- background-color: var(--primary-dark);
484
- transform: translateY(-1px);
485
- box-shadow: 0 3px 8px rgba(58, 134, 255, 0.25);
486
- }
487
-
488
- /* Sleek Tab Styles */
489
- .stTabs [data-baseweb="tab-list"] {
490
- gap: 2px;
491
- background-color: var(--background);
492
- border-radius: 8px;
493
- padding: 2px;
494
- }
495
-
496
- .stTabs [data-baseweb="tab"] {
497
- border-radius: 6px;
498
- padding: 8px 16px;
499
- font-size: 14px;
500
- font-weight: 500;
501
- }
502
-
503
- .stTabs [aria-selected="true"] {
504
- background-color: var(--primary);
505
- color: white !important;
506
- }
507
-
508
- /* Progress Bar Styles */
509
- .stProgress > div > div > div > div {
510
- background-color: var(--primary);
511
- }
512
-
513
- /* Progress Styles */
514
- .progress-container {
515
- margin: 1.2rem 0;
516
- background-color: var(--background);
517
- border-radius: 8px;
518
- padding: 0.8rem;
519
- border: 1px solid var(--border);
520
- }
521
-
522
- .step-complete {
523
- color: #4CAF50;
524
- font-weight: 600;
525
- }
526
-
527
- .step-pending {
528
- color: #9E9E9E;
529
- }
530
-
531
- .step-active {
532
- color: var(--primary);
533
- font-weight: 600;
534
- }
535
-
536
- /* Agent Output */
537
- .agent-output {
538
- background-color: #f8f9fa;
539
- border-left: 5px solid var(--primary);
540
- padding: 1.2rem;
541
- margin: 1rem 0;
542
- border-radius: 10px;
543
- max-height: 400px;
544
- overflow-y: auto;
545
- }
546
-
547
- /* Footer */
548
- .footer {
549
- text-align: center;
550
- margin-top: 3rem;
551
- color: var(--text-light);
552
- font-size: 0.9rem;
553
- padding: 1rem;
554
- border-top: 1px solid #eaeaea;
555
- }
556
-
557
- /* Agent Log */
558
- .agent-log {
559
- background-color: #F5F5F5;
560
- border-left: 3px solid var(--primary);
561
- padding: 0.5rem;
562
- margin-bottom: 0.5rem;
563
- font-family: monospace;
564
- border-radius: 4px;
565
- }
566
-
567
- /* Info and Success Boxes */
568
- .info-box {
569
- background-color: var(--primary-light);
570
- color: white;
571
- padding: 1rem;
572
- border-radius: 0.5rem;
573
- margin-bottom: 1rem;
574
- }
575
-
576
- .success-box {
577
- background-color: #E8F5E9;
578
- padding: 1rem;
579
- border-radius: 0.5rem;
580
- margin-bottom: 1rem;
581
- border-left: 5px solid #4CAF50;
582
- }
583
- </style>
584
- """, unsafe_allow_html=True)
585
-
586
- # Helper function to download HTML file
587
- def get_download_link(text_content, filename):
588
- b64 = base64.b64encode(text_content.encode()).decode()
589
- href = f'<a class="download-link" href="data:text/plain;base64,{b64}" download="{filename}"><i>๐Ÿ“ฅ</i> {t("save_itinerary")}</a>'
590
- return href
591
-
592
- # Updated helper function to display modern progress with a single UI element
593
- def display_modern_progress(current_step, total_steps=6):
594
- if 'progress_steps' not in st.session_state:
595
- st.session_state.progress_steps = {
596
- 0: {'status': 'pending', 'name': t("trip_details")},
597
- 1: {'status': 'pending', 'name': t("about")},
598
- 2: {'status': 'pending', 'name': t("travel_style")},
599
- 3: {'status': 'pending', 'name': t("live_agent_outputs")},
600
- 4: {'status': 'pending', 'name': t("download_share")},
601
- 5: {'status': 'pending', 'name': t("full_itinerary")}
602
- }
603
-
604
- for i in range(total_steps):
605
- if i < current_step:
606
- st.session_state.progress_steps[i]['status'] = 'complete'
607
- elif i == current_step:
608
- st.session_state.progress_steps[i]['status'] = 'active'
609
- else:
610
- st.session_state.progress_steps[i]['status'] = 'pending'
611
-
612
- progress_percentage = (current_step / total_steps) * 100
613
- st.progress(progress_percentage / 100)
614
-
615
- st.markdown("""
616
- <style>
617
- .compact-progress {
618
- background: white;
619
- border-radius: 10px;
620
- padding: 15px;
621
- box-shadow: 0 4px 6px rgba(0,0,0,0.1);
622
- margin-bottom: 20px;
623
- }
624
- .progress-title {
625
- font-size: 16px;
626
- font-weight: bold;
627
- margin-bottom: 15px;
628
- color: #333;
629
- border-bottom: 1px solid #eee;
630
- padding-bottom: 10px;
631
- }
632
- .step-grid {
633
- display: grid;
634
- grid-template-columns: repeat(3, 1fr);
635
- gap: 10px;
636
- }
637
- .step-item {
638
- display: flex;
639
- align-items: center;
640
- padding: 8px 10px;
641
- border-radius: 6px;
642
- background: #f8f9fa;
643
- box-shadow: 0 1px 3px rgba(0,0,0,0.05);
644
- }
645
- .step-item.complete {
646
- border-left: 3px solid #4CAF50;
647
- background: #f1f8e9;
648
- }
649
- .step-item.active {
650
- border-left: 3px solid #2196F3;
651
- background: #e3f2fd;
652
- font-weight: bold;
653
- }
654
- .step-item.pending {
655
- border-left: 3px solid #9e9e9e;
656
- opacity: 0.7;
657
- }
658
- .step-icon {
659
- margin-right: 8px;
660
- font-size: 14px;
661
- }
662
- .step-text {
663
- font-size: 13px;
664
- white-space: nowrap;
665
- overflow: hidden;
666
- text-overflow: ellipsis;
667
- }
668
- </style>
669
- <div class="compact-progress">
670
- """, unsafe_allow_html=True)
671
-
672
- st.markdown('<div class="step-grid">', unsafe_allow_html=True)
673
- for i, step_info in st.session_state.progress_steps.items():
674
- status = step_info['status']
675
- name = step_info['name']
676
- if status == 'complete':
677
- icon = "โœ…"
678
- status_class = "complete"
679
- elif status == 'active':
680
- icon = "๐Ÿ”„"
681
- status_class = "active"
682
- else:
683
- icon = "โญ•"
684
- status_class = "pending"
685
-
686
- st.markdown(f"""
687
- <div class="step-item {status_class}">
688
- <span class="step-icon">{icon}</span>
689
- <span class="step-text">{name}</span>
690
- </div>
691
- """, unsafe_allow_html=True)
692
-
693
- st.markdown('</div></div>', unsafe_allow_html=True)
694
- return progress_percentage
695
-
696
- def update_step_status(step_index, status):
697
- if 'progress_steps' in st.session_state and step_index in st.session_state.progress_steps:
698
- st.session_state.progress_steps[step_index]['status'] = status
699
-
700
- def run_task_with_logs(task, input_text, log_container, output_container, results_key=None):
701
- log_message = f"๐Ÿค– Starting {task.agent.role}..."
702
- st.session_state.log_messages.append(log_message)
703
-
704
- with log_container:
705
- st.markdown("### " + t("agent_activity"))
706
- for msg in st.session_state.log_messages:
707
- st.markdown(msg)
708
-
709
- result = run_task(task, input_text)
710
-
711
- if results_key:
712
- st.session_state.results[results_key] = result
713
-
714
- log_message = f"โœ… {task.agent.role} completed!"
715
- st.session_state.log_messages.append(log_message)
716
-
717
- with log_container:
718
- st.markdown("### " + t("agent_activity"))
719
- for msg in st.session_state.log_messages:
720
- st.markdown(msg)
721
-
722
- with output_container:
723
- st.markdown(f"### {task.agent.role} Output")
724
- st.markdown("<div class='agent-output'>" + result + "</div>", unsafe_allow_html=True)
725
-
726
- return result
727
-
728
- # ------------------------------------------
729
- # Session state ์ดˆ๊ธฐํ™”
730
- # ------------------------------------------
731
- if 'generated_itinerary' not in st.session_state:
732
- st.session_state.generated_itinerary = None
733
- if 'generation_complete' not in st.session_state:
734
- st.session_state.generation_complete = False
735
- if 'current_step' not in st.session_state:
736
- st.session_state.current_step = 0
737
- if 'results' not in st.session_state:
738
- st.session_state.results = {
739
- "destination_info": "",
740
- "accommodation_info": "",
741
- "transportation_info": "",
742
- "activities_info": "",
743
- "dining_info": "",
744
- "itinerary": "",
745
- "final_itinerary": ""
746
- }
747
- if 'log_messages' not in st.session_state:
748
- st.session_state.log_messages = []
749
- if 'current_output' not in st.session_state:
750
- st.session_state.current_output = None
751
- if 'form_submitted' not in st.session_state:
752
- st.session_state.form_submitted = False
753
-
754
- # Modern animated header
755
- st.markdown(f"""
756
- <div class="animate-in" style="text-align: center;">
757
- <div style="margin-bottom: 20px;">
758
- <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));">
759
- </div>
760
- <h1 class="main-header">{t("header")}</h1>
761
- <p style="font-size: 1.2rem; color: #6c757d; margin-bottom: 25px;">
762
- โœจ Create your personalized AI-powered travel itinerary in minutes! โœจ
763
- </p>
764
- </div>
765
- """, unsafe_allow_html=True)
766
-
767
- st.markdown('<hr style="height:3px;border:none;background-color:#f0f0f0;margin-bottom:25px;">', unsafe_allow_html=True)
768
-
769
- with st.sidebar:
770
- st.markdown("""
771
- <div style="text-align: center; padding: 20px 0; margin-bottom: 20px; border-bottom: 1px solid #eaeaea;">
772
- <img src="https://img.icons8.com/fluency/96/travel-card.png" width="80" style="margin-bottom: 15px;">
773
- <h3 style="margin-bottom: 5px; color: #4361ee;">Your AI Agent for Travelling</h3>
774
- <p style="color: #6c757d; font-size: 0.9rem;">AI-Powered Travel Planning</p>
775
- </div>
776
- """, unsafe_allow_html=True)
777
-
778
- st.markdown('<div class="modern-card">', unsafe_allow_html=True)
779
- st.markdown("### ๐ŸŒŸ " + t("about"))
780
- 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!")
781
- st.markdown('</div>', unsafe_allow_html=True)
782
-
783
- st.markdown('<div class="modern-card">', unsafe_allow_html=True)
784
- st.markdown("### ๐Ÿ” " + t("how_it_works"))
785
- st.markdown("""
786
- <ol style="padding-left: 25px;">
787
- <li><b>๐Ÿ–Š๏ธ Enter</b> your travel details</li>
788
- <li><b>๐Ÿง  AI analysis</b> of your preferences</li>
789
- <li><b>๐Ÿ“‹ Generate</b> comprehensive itinerary</li>
790
- <li><b>๐Ÿ“ฅ Download</b> and enjoy your trip!</li>
791
- </ol>
792
- """, unsafe_allow_html=True)
793
- st.markdown('</div>', unsafe_allow_html=True)
794
-
795
- st.markdown('<div class="modern-card">', unsafe_allow_html=True)
796
- st.markdown("### ๐Ÿค– Travel Agents")
797
- agents = [
798
- ("๐Ÿ”ญ Research Specialist", "Finds the best destinations based on your preferences"),
799
- ("๐Ÿจ Accommodation Expert", "Suggests suitable hotels and stays"),
800
- ("๐Ÿš† Transportation Planner", "Plans efficient travel routes"),
801
- ("๐ŸŽฏ Activities Curator", "Recommends activities tailored to your interests"),
802
- ("๐Ÿฝ๏ธ Dining Connoisseur", "Finds the best dining experiences"),
803
- ("๐Ÿ“… Itinerary Creator", "Puts everything together in a daily plan")
804
- ]
805
- for name, desc in agents:
806
- st.markdown("**" + name + "**")
807
- st.markdown("<small>" + desc + "</small>", unsafe_allow_html=True)
808
- st.markdown('</div>', unsafe_allow_html=True)
809
-
810
- if not st.session_state.generation_complete:
811
- st.markdown('<div class="modern-card animate-in">', unsafe_allow_html=True)
812
- st.markdown("<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)
813
-
814
- st.markdown("""
815
- <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>
816
- """, unsafe_allow_html=True)
817
-
818
- with st.form("travel_form"):
819
- col1, col2 = st.columns(2)
820
- with col1:
821
- st.markdown('<p style="font-weight: 500; color: var(--primary); font-size: 14px; margin-bottom: 12px;">Trip Details</p>', unsafe_allow_html=True)
822
- origin = st.text_input(t("origin"), placeholder="e.g., New York, USA")
823
- destination = st.text_input(t("destination"), placeholder="e.g., Paris, France")
824
- st.markdown('<p style="margin-bottom: 5px; font-size: 14px;">Travel Dates</p>', unsafe_allow_html=True)
825
- start_date = st.date_input("Start Date", min_value=datetime.now(), label_visibility="collapsed")
826
- duration = st.slider(t("duration"), min_value=1, max_value=30, value=7)
827
- end_date = start_date + timedelta(days=duration-1)
828
- st.markdown('<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)
829
- with col2:
830
- st.markdown('<p style="font-weight: 500; color: var(--primary); font-size: 14px; margin-bottom: 12px;">Preferences</p>', unsafe_allow_html=True)
831
- travelers = st.number_input("Travelers", min_value=1, max_value=15, value=2)
832
- budget_options = ["Budget", "Moderate", "Luxury"]
833
- budget = st.selectbox("Budget", budget_options, help="Budget: Economy options | Moderate: Mid-range | Luxury: High-end experiences")
834
- travel_style = st.multiselect("๐ŸŒˆ Travel Style", options=["Culture", "Adventure", "Relaxation", "Food & Dining", "Nature", "Shopping", "Nightlife", "Family-friendly"], default=["Culture", "Food & Dining"])
835
- with st.expander("Additional Preferences", expanded=False):
836
- preferences = st.text_area("Interests", placeholder="History museums, local cuisine, hiking, art...")
837
- special_requirements = st.text_area("Special Requirements", placeholder="Dietary restrictions, accessibility needs...")
838
- submit_button = st.form_submit_button(t("submit"))
839
- st.markdown('</div>', unsafe_allow_html=True)
840
-
841
- if submit_button:
842
- if not origin or not destination:
843
- st.error(t("error_origin_destination"))
844
- else:
845
- st.session_state.form_submitted = True
846
- user_input = {
847
- "origin": origin,
848
- "destination": destination,
849
- "duration": str(duration),
850
- "travel_dates": f"{start_date.strftime('%Y-%m-%d')} to {end_date.strftime('%Y-%m-%d')}",
851
- "travelers": str(travelers),
852
- "budget": budget.lower(),
853
- "travel_style": ", ".join(travel_style),
854
- "preferences": preferences,
855
- "special_requirements": special_requirements
856
- }
857
- # ๊ธฐ์กด์˜ ์—ฌํ–‰ ์š”์ฒญ ํ”„๋กฌํ”„ํŠธ
858
- input_context = f"""Travel Request Details:
859
- Origin: {user_input['origin']}
860
- Destination: {user_input['destination']}
861
- Duration: {user_input['duration']} days
862
- Travel Dates: {user_input['travel_dates']}
863
- Travelers: {user_input['travelers']}
864
- Budget Level: {user_input['budget']}
865
- Travel Style: {user_input['travel_style']}
866
- Preferences/Interests: {user_input['preferences']}
867
- Special Requirements: {user_input['special_requirements']}
868
- """
869
- # LLM์— ์ „๋‹ฌํ•  ํ”„๋กฌํ”„ํŠธ์— ์–ธ์–ด ์ง€์‹œ๋ฌธ ์ถ”๊ฐ€
870
- llm_language_instructions = {
871
- "en": "Please output the response in English.",
872
- "ko": "ํ•œ๊ตญ์–ด๋กœ ์ถœ๋ ฅํ•ด ์ฃผ์„ธ์š”.",
873
- "ja": "ๆ—ฅๆœฌ่ชžใงๅ‡บๅŠ›ใ—ใฆใใ ใ•ใ„ใ€‚",
874
- "zh": "่ฏท็”จไธญๆ–‡่พ“ๅ‡บใ€‚",
875
- "es": "Por favor, responda en espaรฑol.",
876
- "fr": "Veuillez rรฉpondre en franรงais.",
877
- "de": "Bitte antworten Sie auf Deutsch.",
878
- "ar": "ูŠุฑุฌู‰ ุงู„ุฑุฏ ุจุงู„ู„ุบุฉ ุงู„ุนุฑุจูŠุฉ."
879
- }
880
- selected_lang = st.session_state.get("selected_language", "en")
881
- language_instruction = llm_language_instructions.get(selected_lang, "Please output the response in English.")
882
- modified_input_context = language_instruction + "\n" + input_context
883
-
884
- st.markdown("""
885
- <div class="sleek-processing-container">
886
- <div class="pulse-container">
887
- <div class="pulse-ring"></div>
888
- <div class="pulse-core"></div>
889
- </div>
890
- </div>
891
- <style>
892
- .sleek-processing-container {
893
- display: flex;
894
- justify-content: center;
895
- align-items: center;
896
- padding: 20px 0;
897
- }
898
- .pulse-container {
899
- position: relative;
900
- width: 50px;
901
- height: 50px;
902
- }
903
- .pulse-core {
904
- position: absolute;
905
- left: 50%;
906
- top: 50%;
907
- transform: translate(-50%, -50%);
908
- width: 12px;
909
- height: 12px;
910
- background-color: #4361ee;
911
- border-radius: 50%;
912
- box-shadow: 0 0 8px rgba(67, 97, 238, 0.6);
913
- }
914
- .pulse-ring {
915
- position: absolute;
916
- left: 0;
917
- top: 0;
918
- width: 100%;
919
- height: 100%;
920
- border: 2px solid #4361ee;
921
- border-radius: 50%;
922
- animation: pulse 1.5s ease-out infinite;
923
- opacity: 0;
924
- }
925
- @keyframes pulse {
926
- 0% { transform: scale(0.1); opacity: 0; }
927
- 50% { opacity: 0.5; }
928
- 100% { transform: scale(1); opacity: 0; }
929
- }
930
- </style>
931
- """, unsafe_allow_html=True)
932
-
933
- st.markdown('<div class="modern-card">', unsafe_allow_html=True)
934
- progress_tab, logs_tab, details_tab = st.tabs(["๐Ÿ“Š Progress", "๐Ÿ”„ Live Activity", "๐Ÿ“‹ " + t("request_details")])
935
- with details_tab:
936
- st.markdown("#### " + t("request_details"))
937
- st.markdown("**" + t("destination") + ":** " + user_input['destination'])
938
- st.markdown("**" + t("from") + ":** " + user_input['origin'])
939
- st.markdown("**" + t("when") + ":** " + user_input['travel_dates'] + " (" + user_input['duration'] + " days)")
940
- st.markdown("**" + t("budget") + ":** " + user_input['budget'].title())
941
- st.markdown("**" + t("travel_style") + ":** " + user_input['travel_style'])
942
- if user_input['preferences']:
943
- st.markdown("**Interests:** " + user_input['preferences'])
944
- if user_input['special_requirements']:
945
- st.markdown("**Special Requirements:** " + user_input['special_requirements'])
946
- with progress_tab:
947
- if 'progress_placeholder' not in st.session_state:
948
- st.session_state.progress_placeholder = st.empty()
949
- with st.session_state.progress_placeholder.container():
950
- display_modern_progress(0)
951
- with logs_tab:
952
- log_container = st.container()
953
- st.session_state.log_messages = []
954
- st.markdown('</div>', unsafe_allow_html=True)
955
- output_container = st.container()
956
- with output_container:
957
- st.markdown('<div class="modern-card">', unsafe_allow_html=True)
958
- st.markdown("### ๐ŸŒŸ " + t("live_agent_outputs"))
959
- st.info("Our AI agents will show their work here as they create your itinerary")
960
- st.markdown('</div>', unsafe_allow_html=True)
961
- st.session_state.current_step = 0
962
-
963
- update_step_status(0, 'active')
964
- with st.session_state.progress_placeholder.container():
965
- display_modern_progress(st.session_state.current_step)
966
- destination_info = run_task_with_logs(
967
- destination_research_task,
968
- modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
969
- log_container,
970
- output_container,
971
- "destination_info"
972
- )
973
- update_step_status(0, 'complete')
974
- st.session_state.current_step = 1
975
- update_step_status(1, 'active')
976
- with st.session_state.progress_placeholder.container():
977
- display_modern_progress(st.session_state.current_step)
978
- accommodation_info = run_task_with_logs(
979
- accommodation_task,
980
- modified_input_context.format(destination=user_input['destination'], budget=user_input['budget'], preferences=user_input['preferences']),
981
- log_container,
982
- output_container,
983
- "accommodation_info"
984
- )
985
- update_step_status(1, 'complete')
986
- st.session_state.current_step = 2
987
- update_step_status(2, 'active')
988
- with st.session_state.progress_placeholder.container():
989
- display_modern_progress(st.session_state.current_step)
990
- transportation_info = run_task_with_logs(
991
- transportation_task,
992
- modified_input_context.format(origin=user_input['origin'], destination=user_input['destination']),
993
- log_container,
994
- output_container,
995
- "transportation_info"
996
- )
997
- update_step_status(2, 'complete')
998
- st.session_state.current_step = 3
999
- update_step_status(3, 'active')
1000
- with st.session_state.progress_placeholder.container():
1001
- display_modern_progress(st.session_state.current_step)
1002
- activities_info = run_task_with_logs(
1003
- activities_task,
1004
- modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
1005
- log_container,
1006
- output_container,
1007
- "activities_info"
1008
- )
1009
- update_step_status(3, 'complete')
1010
- st.session_state.current_step = 4
1011
- update_step_status(4, 'active')
1012
- with st.session_state.progress_placeholder.container():
1013
- display_modern_progress(st.session_state.current_step)
1014
- dining_info = run_task_with_logs(
1015
- dining_task,
1016
- modified_input_context.format(destination=user_input['destination'], preferences=user_input['preferences']),
1017
- log_container,
1018
- output_container,
1019
- "dining_info"
1020
- )
1021
- update_step_status(4, 'complete')
1022
- st.session_state.current_step = 5
1023
- update_step_status(5, 'active')
1024
- with st.session_state.progress_placeholder.container():
1025
- display_modern_progress(st.session_state.current_step)
1026
- combined_info = f"""{input_context}
1027
-
1028
- Destination Information:
1029
- {destination_info}
1030
-
1031
- Accommodation Options:
1032
- {accommodation_info}
1033
-
1034
- Transportation Plan:
1035
- {transportation_info}
1036
-
1037
- Recommended Activities:
1038
- {activities_info}
1039
-
1040
- Dining Recommendations:
1041
- {dining_info}
1042
- """
1043
- itinerary = run_task_with_logs(
1044
- itinerary_task,
1045
- combined_info.format(duration=user_input['duration'], origin=user_input['origin'], destination=user_input['destination']),
1046
- log_container,
1047
- output_container,
1048
- "itinerary"
1049
- )
1050
- update_step_status(5, 'complete')
1051
- st.session_state.current_step = 6
1052
- with st.session_state.progress_placeholder.container():
1053
- display_modern_progress(st.session_state.current_step)
1054
- st.session_state.generated_itinerary = itinerary
1055
- st.session_state.generation_complete = True
1056
- date_str = datetime.now().strftime("%Y-%m-%d")
1057
- st.session_state.filename = f"{user_input['destination'].replace(' ', '_')}_{date_str}_itinerary.txt"
1058
-
1059
- if st.session_state.generation_complete:
1060
- st.markdown("""
1061
- <div class="modern-card animate-in">
1062
- <div style="display: flex; justify-content: center; margin-bottom: 20px;">
1063
- <div class="success-animation">
1064
- <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
1065
- <circle class="checkmark__circle" cx="26" cy="26" r="25" fill="none" />
1066
- <path class="checkmark__check" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8" />
1067
- </svg>
1068
- </div>
1069
- </div>
1070
- <h2 style="text-align: center; color: #4361ee;">""" + t("itinerary_ready") + """</h2>
1071
- <p style="text-align: center; color: #6c757d; margin-bottom: 20px;">""" + t("personalized_experience") + """</p>
1072
- </div>
1073
-
1074
- <style>
1075
- .success-animation {
1076
- width: 100px;
1077
- height: 100px;
1078
- position: relative;
1079
- }
1080
- .checkmark {
1081
- width: 100px;
1082
- height: 100px;
1083
- border-radius: 50%;
1084
- display: block;
1085
- stroke-width: 2;
1086
- stroke: #4361ee;
1087
- stroke-miterlimit: 10;
1088
- box-shadow: 0 0 20px rgba(67, 97, 238, 0.3);
1089
- animation: fill .4s ease-in-out .4s forwards, scale .3s ease-in-out .9s both;
1090
- }
1091
- .checkmark__circle {
1092
- stroke-dasharray: 166;
1093
- stroke-dashoffset: 166;
1094
- stroke-width: 2;
1095
- stroke-miterlimit: 10;
1096
- stroke: #4361ee;
1097
- fill: none;
1098
- animation: stroke 0.6s cubic-bezier(0.65, 0, 0.45, 1) forwards;
1099
- }
1100
- .checkmark__check {
1101
- transform-origin: 50% 50%;
1102
- stroke-dasharray: 48;
1103
- stroke-dashoffset: 48;
1104
- animation: stroke 0.3s cubic-bezier(0.65, 0, 0.45, 1) 0.8s forwards;
1105
- }
1106
- @keyframes stroke {
1107
- 100% { stroke-dashoffset: 0; }
1108
- }
1109
- @keyframes scale {
1110
- 0%, 100% { transform: none; }
1111
- 50% { transform: scale3d(1.1, 1.1, 1); }
1112
- }
1113
- @keyframes fill {
1114
- 100% { box-shadow: 0 0 20px rgba(67, 97, 238, 0.3); }
1115
- }
1116
- </style>
1117
- """, unsafe_allow_html=True)
1118
-
1119
- # ์ถ”๊ฐ€๋œ ํƒญ: ์ „์ฒด ์ผ์ •, ์ƒ์„ธ ์ •๋ณด, ๋‹ค์šด๋กœ๋“œ/๊ณต์œ , ์ง€๋„ ๋ฐ ์‹œ๊ฐํ™”, AI ์ฑ—๋ด‡ ์ธํ„ฐํŽ˜์ด์Šค
1120
- itinerary_tab, details_tab, download_tab, map_tab, chatbot_tab = st.tabs([
1121
- "๐Ÿ—’๏ธ " + t("full_itinerary"),
1122
- "๐Ÿ’ผ " + t("details"),
1123
- "๐Ÿ’พ " + t("download_share"),
1124
- "๐Ÿ—บ๏ธ ์ง€๋„ ๋ฐ ์‹œ๊ฐํ™”",
1125
- "๐Ÿค– ์ฑ—๋ด‡ ์ธํ„ฐํŽ˜์ด์Šค"
1126
- ])
1127
-
1128
- # ์ผ์ • ํƒญ
1129
- with itinerary_tab:
1130
- st.text_area("Your Itinerary", st.session_state.generated_itinerary, height=600)
1131
-
1132
- # ์ƒ์„ธ ์ •๋ณด ํƒญ
1133
- with details_tab:
1134
- agent_tabs = st.tabs(["๐ŸŒŽ Destination", "๐Ÿจ Accommodation", "๐Ÿš— Transportation", "๐ŸŽญ Activities", "๐Ÿฝ๏ธ Dining"])
1135
- with agent_tabs[0]:
1136
- st.markdown("### ๐ŸŒŽ Destination Research")
1137
- st.markdown(st.session_state.results["destination_info"])
1138
- with agent_tabs[1]:
1139
- st.markdown("### ๐Ÿจ Accommodation Options")
1140
- st.markdown(st.session_state.results["accommodation_info"])
1141
- with agent_tabs[2]:
1142
- st.markdown("### ๐Ÿš— Transportation Plan")
1143
- st.markdown(st.session_state.results["transportation_info"])
1144
- with agent_tabs[3]:
1145
- st.markdown("### ๐ŸŽญ Recommended Activities")
1146
- st.markdown(st.session_state.results["activities_info"])
1147
- with agent_tabs[4]:
1148
- st.markdown("### ๐Ÿฝ๏ธ Dining Recommendations")
1149
- st.markdown(st.session_state.results["dining_info"])
1150
-
1151
- # ๋‹ค์šด๋กœ๋“œ ๋ฐ ๊ณต์œ  ํƒญ
1152
- with download_tab:
1153
- col1, col2 = st.columns([2, 1])
1154
- with col1:
1155
- st.markdown("### " + t("save_itinerary"))
1156
- st.markdown("Download your personalized travel plan to access it offline or share with your travel companions.")
1157
- st.markdown("""
1158
- <div style="background-color: #f8f9fa; padding: 15px; border-radius: 10px; margin-top: 20px;">
1159
- <h4 style="margin-top: 0;">""" + t("your_itinerary_file") + """</h4>
1160
- <p style="font-size: 0.9rem; color: #6c757d;">""" + t("text_format") + """</p>
1161
- """, unsafe_allow_html=True)
1162
- st.markdown("<div style='margin: 10px 0;'>" + get_download_link(st.session_state.generated_itinerary, st.session_state.filename) + "</div>", unsafe_allow_html=True)
1163
- st.markdown("</div>", unsafe_allow_html=True)
1164
- st.markdown("### " + t("share_itinerary"))
1165
- st.markdown("*Coming soon: Email your itinerary or share via social media.*")
1166
- with col2:
1167
- st.markdown("### " + t("save_for_mobile"))
1168
- st.markdown("*Coming soon: QR code for easy access on your phone*")
1169
-
1170
- # ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์ง€๋„ ๋ฐ ์‹œ๊ฐํ™” ํƒญ
1171
- with map_tab:
1172
- st.markdown("### ๋ชฉ์ ์ง€ ์ง€๋„")
1173
- # ์˜ˆ์‹œ: ๋ชฉ์ ์ง€ ์ฃผ๋ณ€์˜ ์ฃผ์š” ๋ช…์†Œ ์ขŒํ‘œ ๋ฐ์ดํ„ฐ (์‹ค์ œ API๋‚˜ DB๋ฅผ ํ†ตํ•ด ๋™์ ์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Œ)
1174
- map_data = pd.DataFrame({
1175
- "lat": [48.8584, 48.8606, 48.8529],
1176
- "lon": [2.2945, 2.3376, 2.3500],
1177
- "name": ["Eiffel Tower", "Louvre Museum", "Notre Dame"]
1178
- })
1179
- # ๊ธฐ๋ณธ ์ง€๋„ ์ถœ๋ ฅ (st.map)
1180
- st.map(map_data)
1181
-
1182
- st.markdown("#### Pydeck์„ ํ™œ์šฉํ•œ ์ธํ„ฐ๋ž™ํ‹ฐ๋ธŒ ์ง€๋„ ์˜ˆ์‹œ")
1183
- layer = pdk.Layer(
1184
- "ScatterplotLayer",
1185
- data=map_data,
1186
- get_position='[lon, lat]',
1187
- get_color='[200, 30, 0, 160]',
1188
- get_radius=200,
1189
- )
1190
- view_state = pdk.ViewState(
1191
- latitude=48.8566,
1192
- longitude=2.3522,
1193
- zoom=12,
1194
- pitch=50,
1195
- )
1196
- deck_chart = pdk.Deck(layers=[layer], initial_view_state=view_state)
1197
- st.pydeck_chart(deck_chart)
1198
-
1199
- # AI ์ฑ—๋ด‡ ์ธํ„ฐํŽ˜์ด์Šค ํƒญ (์ œ๋ฏธ๋‚˜์ด ์ ์šฉ)
1200
- with chatbot_tab:
1201
- st.markdown("### AI ์ฑ—๋ด‡ ์ธํ„ฐํŽ˜์ด์Šค")
1202
- # ๋Œ€ํ™” ๊ธฐ๋ก์„ ์„ธ์…˜ ๏ฟฝ๏ฟฝ๏ฟฝํƒœ์— ์ €์žฅ (๋ฉ”์‹œ์ง€, ๋ฐœ์‹ ์ž, ํƒ€์ž„์Šคํƒฌํ”„)
1203
- if "chat_history" not in st.session_state:
1204
- st.session_state.chat_history = []
1205
-
1206
- # ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ฐฝ ๋ฐ ์ „์†ก ๋ฒ„ํŠผ
1207
- user_message = st.text_input("๋ฉ”์‹œ์ง€๋ฅผ ์ž…๋ ฅํ•˜์„ธ์š”:", key="chat_input")
1208
- if st.button("์ „์†ก", key="send_button"):
1209
- if user_message:
1210
- # ์ œ๋ฏธ๋‚˜์ด ๊ธฐ๋ฐ˜ ์ฑ—๋ด‡ ์‘๋‹ต: run_task()๋ฅผ ํ™œ์šฉํ•˜์—ฌ chatbot_task์— ์งˆ์˜
1211
- response = run_task(chatbot_task, user_message)
1212
- st.session_state.chat_history.append({
1213
- "speaker": "์‚ฌ์šฉ์ž",
1214
- "message": user_message,
1215
- "time": datetime.now()
1216
- })
1217
- st.session_state.chat_history.append({
1218
- "speaker": "AI",
1219
- "message": response,
1220
- "time": datetime.now()
1221
- })
1222
-
1223
- # ๋Œ€ํ™” ๊ธฐ๋ก ์ถœ๋ ฅ (ํƒ€์ž„์Šคํƒฌํ”„ ํฌํ•จ, ์Šคํฌ๋กค ๊ฐ€๋Šฅํ•œ ์˜์—ญ)
1224
- st.markdown("<div style='max-height:400px; overflow-y:auto; padding:10px; border:1px solid #eaeaea; border-radius:6px;'>", unsafe_allow_html=True)
1225
- for chat in st.session_state.chat_history:
1226
- time_str = chat["time"].strftime("%H:%M:%S")
1227
- st.markdown(f"**{chat['speaker']}** ({time_str}): {chat['message']}")
1228
- st.markdown("</div>", unsafe_allow_html=True)
1229
-
1230
- st.markdown("""
1231
- <div style="margin-top: 50px; text-align: center; padding: 20px; color: #6c757d; font-size: 0.8rem;">
1232
- <p>""" + t("built_with") + """</p>
1233
- </div>
1234
- """, unsafe_allow_html=True)