MrTravelX commited on
Commit
a3b693b
·
verified ·
1 Parent(s): 11d9c22

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +475 -0
app.py ADDED
@@ -0,0 +1,475 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import os
3
+ import json
4
+ from datetime import datetime, timedelta
5
+ import base64
6
+ from travel import (
7
+ destination_research_task, accommodation_task, transportation_task,
8
+ activities_task, dining_task, itinerary_task, final_report_task,
9
+ run_task
10
+ )
11
+
12
+ # Set page configuration
13
+ st.set_page_config(
14
+ page_title="BlockX Travel Itinerary Generator",
15
+ page_icon="✈️",
16
+ layout="wide",
17
+ initial_sidebar_state="expanded"
18
+ )
19
+
20
+ # Custom CSS for better styling
21
+ st.markdown("""
22
+ <style>
23
+ .main-header {
24
+ font-size: 2.5rem;
25
+ color: #1E88E5;
26
+ text-align: center;
27
+ margin-bottom: 1rem;
28
+ }
29
+ .sub-header {
30
+ font-size: 1.5rem;
31
+ color: #0D47A1;
32
+ margin-top: 2rem;
33
+ margin-bottom: 1rem;
34
+ }
35
+ .info-box {
36
+ background-color: #E3F2FD;
37
+ padding: 1rem;
38
+ border-radius: 0.5rem;
39
+ margin-bottom: 1rem;
40
+ }
41
+ .success-box {
42
+ background-color: #E8F5E9;
43
+ padding: 1rem;
44
+ border-radius: 0.5rem;
45
+ margin-bottom: 1rem;
46
+ border-left: 5px solid #4CAF50;
47
+ }
48
+ .progress-container {
49
+ margin: 1rem 0;
50
+ }
51
+ .step-complete {
52
+ color: #4CAF50;
53
+ font-weight: bold;
54
+ }
55
+ .step-pending {
56
+ color: #9E9E9E;
57
+ }
58
+ .step-active {
59
+ color: #1E88E5;
60
+ font-weight: bold;
61
+ }
62
+ .agent-log {
63
+ background-color: #F5F5F5;
64
+ border-left: 3px solid #1E88E5;
65
+ padding: 0.5rem;
66
+ margin-bottom: 0.5rem;
67
+ font-family: monospace;
68
+ }
69
+ .agent-output {
70
+ background-color: #E8F5E9;
71
+ border-left: 5px solid #4CAF50;
72
+ padding: 1rem;
73
+ margin: 1rem 0;
74
+ border-radius: 0.5rem;
75
+ max-height: 400px;
76
+ overflow-y: auto;
77
+ }
78
+ .footer {
79
+ text-align: center;
80
+ margin-top: 3rem;
81
+ color: #757575;
82
+ font-size: 0.8rem;
83
+ }
84
+ .stButton button {
85
+ background-color: #1E88E5;
86
+ color: white;
87
+ font-weight: bold;
88
+ }
89
+ </style>
90
+ """, unsafe_allow_html=True)
91
+
92
+ # Helper function to download HTML file
93
+ def get_download_link(html_content, filename):
94
+ b64 = base64.b64encode(html_content.encode()).decode()
95
+ href = f'<a href="data:text/html;base64,{b64}" download="{filename}">Download Itinerary as HTML</a>'
96
+ return href
97
+
98
+ # Helper function to display progress
99
+ def display_progress(current_step, total_steps=7):
100
+ progress_html = '<div class="progress-container">'
101
+ steps = [
102
+ "Destination Research",
103
+ "Accommodation",
104
+ "Transportation",
105
+ "Activities",
106
+ "Dining",
107
+ "Itinerary Creation",
108
+ "Final Report"
109
+ ]
110
+
111
+ for i, step in enumerate(steps):
112
+ if i < current_step:
113
+ progress_html += f'<p class="step-complete">✓ {step} - Complete</p>'
114
+ elif i == current_step:
115
+ progress_html += f'<p class="step-active">⟳ {step} - In Progress...</p>'
116
+ else:
117
+ progress_html += f'<p class="step-pending">○ {step} - Pending</p>'
118
+
119
+ progress_html += '</div>'
120
+ return progress_html
121
+
122
+ # Custom run_task function that updates the UI with logs and shows live agent outputs
123
+ def run_task_with_logs(task, input_text, log_container, output_container, results_key=None):
124
+ # Add log message
125
+ log_message = f"🤖 Starting {task.agent.role}..."
126
+ st.session_state.log_messages.append(log_message)
127
+
128
+ # Update the log container
129
+ with log_container:
130
+ st.markdown("### Agent Activity")
131
+ for msg in st.session_state.log_messages:
132
+ st.markdown(msg)
133
+
134
+ # Run the actual task
135
+ result = run_task(task, input_text)
136
+
137
+ # Store result if needed
138
+ if results_key:
139
+ st.session_state.results[results_key] = result
140
+
141
+ # Add completion log message
142
+ log_message = f"✅ {task.agent.role} completed!"
143
+ st.session_state.log_messages.append(log_message)
144
+
145
+ # Update the log container again
146
+ with log_container:
147
+ st.markdown("### Agent Activity")
148
+ for msg in st.session_state.log_messages:
149
+ st.markdown(msg)
150
+
151
+ # Display the agent's output in the output container
152
+ with output_container:
153
+ st.markdown(f"### {task.agent.role} Output")
154
+ st.markdown("""<div class='agent-output'>""" + result + """</div>""", unsafe_allow_html=True)
155
+
156
+ return result
157
+
158
+ # Initialize session state
159
+ if 'generated_itinerary' not in st.session_state:
160
+ st.session_state.generated_itinerary = None
161
+ if 'generation_complete' not in st.session_state:
162
+ st.session_state.generation_complete = False
163
+ if 'current_step' not in st.session_state:
164
+ st.session_state.current_step = 0
165
+ if 'results' not in st.session_state:
166
+ st.session_state.results = {
167
+ "destination_info": "",
168
+ "accommodation_info": "",
169
+ "transportation_info": "",
170
+ "activities_info": "",
171
+ "dining_info": "",
172
+ "itinerary": "",
173
+ "final_itinerary": ""
174
+ }
175
+ if 'log_messages' not in st.session_state:
176
+ st.session_state.log_messages = []
177
+ if 'current_output' not in st.session_state:
178
+ st.session_state.current_output = None
179
+
180
+ # Header
181
+ st.markdown('<h1 class="main-header">BlockX Travel Itinerary Generator</h1>', unsafe_allow_html=True)
182
+ st.markdown('<p style="text-align: center;">Create your personalized AI-powered travel itinerary in minutes!</p>', unsafe_allow_html=True)
183
+
184
+ # Sidebar with information
185
+ with st.sidebar:
186
+ st.image("https://img.icons8.com/fluency/96/travel-card.png", width=80)
187
+ st.markdown("### About")
188
+ st.info(
189
+ "This AI-powered tool creates a personalized travel itinerary based on your preferences. "
190
+ "Fill in the form and let our specialized travel agents plan your perfect trip!"
191
+ )
192
+
193
+ st.markdown("### How it works")
194
+ st.markdown(
195
+ "1. Enter your travel details\n"
196
+ "2. Our AI agents analyze your preferences\n"
197
+ "3. Receive a comprehensive itinerary\n"
198
+ "4. Download and enjoy your trip!"
199
+ )
200
+
201
+ st.markdown("### Travel Agents")
202
+ st.markdown(
203
+ "- 🔍 Destination Research Agent\n"
204
+ "- 🏨 Accommodation Agent\n"
205
+ "- 🚗 Transportation Agent\n"
206
+ "- 🎭 Activities & Attractions Agent\n"
207
+ "- 🍽️ Dining & Culinary Agent\n"
208
+ "- 📅 Itinerary Integration Agent\n"
209
+ "- 📄 Final Report Generation Agent"
210
+ )
211
+
212
+ # Input Form
213
+ if not st.session_state.generation_complete:
214
+ st.markdown('<h2 class="sub-header">Enter Your Travel Details</h2>', unsafe_allow_html=True)
215
+
216
+ col1, col2 = st.columns(2)
217
+
218
+ with col1:
219
+ origin = st.text_input("Origin City/Country", placeholder="e.g., New York, USA")
220
+ destination = st.text_input("Destination City/Country", placeholder="e.g., Paris, France")
221
+ duration = st.number_input("Trip Duration (days)", min_value=1, max_value=30, value=7)
222
+
223
+ with col2:
224
+ budget_options = ["Budget", "Moderate", "Luxury"]
225
+ budget = st.selectbox("Budget Level", budget_options)
226
+ preferences = st.text_area("Travel Preferences & Interests",
227
+ placeholder="e.g., museums, hiking, food, shopping, beaches, history, nightlife, family-friendly")
228
+ special_requirements = st.text_area("Special Requirements",
229
+ placeholder="e.g., dietary restrictions, accessibility needs, etc.")
230
+
231
+ # Generate button
232
+ if st.button("Generate My Travel Itinerary"):
233
+ if not origin or not destination:
234
+ st.error("Please enter both origin and destination.")
235
+ else:
236
+ user_input = {
237
+ "origin": origin,
238
+ "destination": destination,
239
+ "duration": str(duration),
240
+ "budget": budget.lower(),
241
+ "preferences": preferences,
242
+ "special_requirements": special_requirements
243
+ }
244
+
245
+ # Format the user input for tasks
246
+ input_context = f"""Travel Request Details:
247
+ Origin: {user_input['origin']}
248
+ Destination: {user_input['destination']}
249
+ Duration: {user_input['duration']} days
250
+ Budget Level: {user_input['budget']}
251
+ Preferences/Interests: {user_input['preferences']}
252
+ Special Requirements: {user_input['special_requirements']}
253
+ """
254
+
255
+ # Create containers for progress, logs, and live output
256
+ col1, col2 = st.columns([1, 2])
257
+
258
+ with col1:
259
+ progress_placeholder = st.empty()
260
+ progress_placeholder.markdown(display_progress(0), unsafe_allow_html=True)
261
+ log_container = st.container()
262
+ st.session_state.log_messages = []
263
+
264
+ with col2:
265
+ output_container = st.container()
266
+ with output_container:
267
+ st.markdown("### Live Agent Outputs")
268
+ st.info("Agent outputs will appear here as they are generated")
269
+
270
+ # Step 1: Destination Research
271
+ st.session_state.current_step = 0
272
+ progress_placeholder.markdown(display_progress(st.session_state.current_step), unsafe_allow_html=True)
273
+
274
+ destination_info = run_task_with_logs(
275
+ destination_research_task,
276
+ input_context.format(
277
+ destination=user_input['destination'],
278
+ preferences=user_input['preferences']
279
+ ),
280
+ log_container,
281
+ output_container,
282
+ "destination_info"
283
+ )
284
+
285
+ st.session_state.current_step = 1
286
+ progress_placeholder.markdown(display_progress(st.session_state.current_step), unsafe_allow_html=True)
287
+
288
+ # Step 2: Accommodation Recommendations
289
+ accommodation_info = run_task_with_logs(
290
+ accommodation_task,
291
+ input_context.format(
292
+ destination=user_input['destination'],
293
+ budget=user_input['budget'],
294
+ preferences=user_input['preferences']
295
+ ),
296
+ log_container,
297
+ output_container,
298
+ "accommodation_info"
299
+ )
300
+
301
+ st.session_state.current_step = 2
302
+ progress_placeholder.markdown(display_progress(st.session_state.current_step), unsafe_allow_html=True)
303
+
304
+ # Step 3: Transportation Planning
305
+ transportation_info = run_task_with_logs(
306
+ transportation_task,
307
+ input_context.format(
308
+ origin=user_input['origin'],
309
+ destination=user_input['destination']
310
+ ),
311
+ log_container,
312
+ output_container,
313
+ "transportation_info"
314
+ )
315
+
316
+ st.session_state.current_step = 3
317
+ progress_placeholder.markdown(display_progress(st.session_state.current_step), unsafe_allow_html=True)
318
+
319
+ # Step 4: Activities & Attractions
320
+ activities_info = run_task_with_logs(
321
+ activities_task,
322
+ input_context.format(
323
+ destination=user_input['destination'],
324
+ preferences=user_input['preferences']
325
+ ),
326
+ log_container,
327
+ output_container,
328
+ "activities_info"
329
+ )
330
+
331
+ st.session_state.current_step = 4
332
+ progress_placeholder.markdown(display_progress(st.session_state.current_step), unsafe_allow_html=True)
333
+
334
+ # Step 5: Dining Recommendations
335
+ dining_info = run_task_with_logs(
336
+ dining_task,
337
+ input_context.format(
338
+ destination=user_input['destination'],
339
+ preferences=user_input['preferences']
340
+ ),
341
+ log_container,
342
+ output_container,
343
+ "dining_info"
344
+ )
345
+
346
+ st.session_state.current_step = 5
347
+ progress_placeholder.markdown(display_progress(st.session_state.current_step), unsafe_allow_html=True)
348
+
349
+ # Step 6: Create Day-by-Day Itinerary
350
+ combined_info = f"""{input_context}
351
+
352
+ Destination Information:
353
+ {destination_info}
354
+
355
+ Accommodation Options:
356
+ {accommodation_info}
357
+
358
+ Transportation Plan:
359
+ {transportation_info}
360
+
361
+ Recommended Activities:
362
+ {activities_info}
363
+
364
+ Dining Recommendations:
365
+ {dining_info}
366
+ """
367
+
368
+ itinerary = run_task_with_logs(
369
+ itinerary_task,
370
+ combined_info.format(
371
+ duration=user_input['duration'],
372
+ origin=user_input['origin'],
373
+ destination=user_input['destination']
374
+ ),
375
+ log_container,
376
+ output_container,
377
+ "itinerary"
378
+ )
379
+
380
+ st.session_state.current_step = 6
381
+ progress_placeholder.markdown(display_progress(st.session_state.current_step), unsafe_allow_html=True)
382
+
383
+ # Step 7: Generate Final Report
384
+ final_context = f"""{combined_info}
385
+
386
+ Day-by-Day Itinerary:
387
+ {itinerary}
388
+ """
389
+
390
+ final_itinerary = run_task_with_logs(
391
+ final_report_task,
392
+ final_context.format(
393
+ duration=user_input['duration'],
394
+ origin=user_input['origin'],
395
+ destination=user_input['destination']
396
+ ),
397
+ log_container,
398
+ output_container,
399
+ "final_itinerary"
400
+ )
401
+
402
+ # Save the generated itinerary to session state
403
+ st.session_state.generated_itinerary = final_itinerary
404
+ st.session_state.generation_complete = True
405
+
406
+ # Create a filename based on the destination and date
407
+ date_str = datetime.now().strftime("%Y-%m-%d")
408
+ st.session_state.filename = f"{user_input['destination'].replace(' ', '_')}_{date_str}_itinerary.html"
409
+
410
+ # No need to rerun, we'll update the UI directly
411
+
412
+ # Display results if generation is complete
413
+ if st.session_state.generation_complete:
414
+ st.markdown('<h2 class="sub-header">Your Travel Itinerary is Ready! 🎉</h2>', unsafe_allow_html=True)
415
+
416
+ # Display download link
417
+ st.markdown(
418
+ get_download_link(st.session_state.generated_itinerary, st.session_state.filename),
419
+ unsafe_allow_html=True
420
+ )
421
+
422
+ # Option to view the itinerary directly
423
+ with st.expander("Preview Your Itinerary", expanded=True):
424
+ st.components.v1.html(st.session_state.generated_itinerary, height=600, scrolling=True)
425
+
426
+ # Option to view individual agent outputs
427
+ with st.expander("View Detailed Agent Outputs"):
428
+ agent_tabs = st.tabs([
429
+ "Destination", "Accommodation", "Transportation",
430
+ "Activities", "Dining", "Day-by-Day"
431
+ ])
432
+
433
+ with agent_tabs[0]:
434
+ st.markdown("### Destination Research")
435
+ st.markdown(st.session_state.results["destination_info"])
436
+
437
+ with agent_tabs[1]:
438
+ st.markdown("### Accommodation Options")
439
+ st.markdown(st.session_state.results["accommodation_info"])
440
+
441
+ with agent_tabs[2]:
442
+ st.markdown("### Transportation Plan")
443
+ st.markdown(st.session_state.results["transportation_info"])
444
+
445
+ with agent_tabs[3]:
446
+ st.markdown("### Recommended Activities")
447
+ st.markdown(st.session_state.results["activities_info"])
448
+
449
+ with agent_tabs[4]:
450
+ st.markdown("### Dining Recommendations")
451
+ st.markdown(st.session_state.results["dining_info"])
452
+
453
+ with agent_tabs[5]:
454
+ st.markdown("### Day-by-Day Itinerary")
455
+ st.markdown(st.session_state.results["itinerary"])
456
+
457
+ # Option to start over
458
+ if st.button("Create Another Itinerary"):
459
+ # Reset session state
460
+ st.session_state.generated_itinerary = None
461
+ st.session_state.generation_complete = False
462
+ st.session_state.current_step = 0
463
+ st.session_state.results = {
464
+ "destination_info": "",
465
+ "accommodation_info": "",
466
+ "transportation_info": "",
467
+ "activities_info": "",
468
+ "dining_info": "",
469
+ "itinerary": "",
470
+ "final_itinerary": ""
471
+ }
472
+ st.rerun()
473
+
474
+ # Footer
475
+ st.markdown('<div class="footer">BlockX Travel Itinerary Generator © 2025</div>', unsafe_allow_html=True)