siyah1 commited on
Commit
f766339
Β·
verified Β·
1 Parent(s): 665a228

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +684 -0
app.py ADDED
@@ -0,0 +1,684 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ from typing import Union, List, Dict, Optional
4
+ from groq import Groq
5
+ import os
6
+ from duckduckgo_search import DDGS
7
+ import json
8
+ from datetime import datetime, timedelta
9
+ import time
10
+
11
+ # Set page configuration with fullscreen layout and custom theme
12
+ st.set_page_config(
13
+ page_title="SmolAgent Travel Planner",
14
+ layout="wide",
15
+ initial_sidebar_state="collapsed",
16
+ page_icon="✈️"
17
+ )
18
+
19
+ # Enhanced CSS for a beautiful travel-themed styling
20
+ st.markdown("""
21
+ <style>
22
+ /* Base styles */
23
+ html, body, .stApp, .main {
24
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
25
+ color: #ffffff !important;
26
+ }
27
+
28
+ /* Typography */
29
+ h1, h2, h3, h4, h5, h6 {
30
+ color: #ffffff !important;
31
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif !important;
32
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
33
+ }
34
+
35
+ /* Cards and containers */
36
+ .card {
37
+ background: rgba(255, 255, 255, 0.1) !important;
38
+ backdrop-filter: blur(10px) !important;
39
+ border: 1px solid rgba(255, 255, 255, 0.2) !important;
40
+ border-radius: 15px !important;
41
+ box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37) !important;
42
+ padding: 2rem !important;
43
+ margin-bottom: 2rem !important;
44
+ }
45
+
46
+ /* Agent status cards */
47
+ .agent-card {
48
+ background: rgba(255, 255, 255, 0.15) !important;
49
+ border: 1px solid rgba(255, 255, 255, 0.3) !important;
50
+ border-radius: 12px !important;
51
+ padding: 1.5rem !important;
52
+ margin: 1rem 0 !important;
53
+ backdrop-filter: blur(5px) !important;
54
+ }
55
+
56
+ /* Input fields */
57
+ .stTextInput input, .stTextArea textarea, .stSelectbox div[data-baseweb="select"] {
58
+ background: rgba(255, 255, 255, 0.2) !important;
59
+ color: #ffffff !important;
60
+ border: 1px solid rgba(255, 255, 255, 0.3) !important;
61
+ border-radius: 8px !important;
62
+ }
63
+
64
+ .stTextInput input::placeholder, .stTextArea textarea::placeholder {
65
+ color: rgba(255, 255, 255, 0.7) !important;
66
+ }
67
+
68
+ /* Buttons */
69
+ .stButton > button {
70
+ background: linear-gradient(45deg, #ff6b6b, #ff8e8e) !important;
71
+ color: #ffffff !important;
72
+ border: none !important;
73
+ border-radius: 25px !important;
74
+ font-weight: bold !important;
75
+ padding: 0.75rem 2rem !important;
76
+ transition: all 0.3s ease !important;
77
+ box-shadow: 0 4px 15px rgba(255, 107, 107, 0.4) !important;
78
+ }
79
+
80
+ .stButton > button:hover {
81
+ transform: translateY(-2px) !important;
82
+ box-shadow: 0 8px 25px rgba(255, 107, 107, 0.6) !important;
83
+ }
84
+
85
+ /* Progress indicators */
86
+ .agent-status {
87
+ display: flex;
88
+ align-items: center;
89
+ gap: 10px;
90
+ padding: 10px;
91
+ border-radius: 8px;
92
+ margin: 5px 0;
93
+ background: rgba(255, 255, 255, 0.1);
94
+ backdrop-filter: blur(5px);
95
+ }
96
+
97
+ .status-working {
98
+ border-left: 4px solid #4CAF50;
99
+ }
100
+
101
+ .status-complete {
102
+ border-left: 4px solid #2196F3;
103
+ }
104
+
105
+ .status-error {
106
+ border-left: 4px solid #F44336;
107
+ }
108
+
109
+ /* Spinning animation */
110
+ .spinner {
111
+ border: 2px solid rgba(255, 255, 255, 0.3);
112
+ border-radius: 50%;
113
+ border-top: 2px solid #ffffff;
114
+ width: 20px;
115
+ height: 20px;
116
+ animation: spin 1s linear infinite;
117
+ }
118
+
119
+ @keyframes spin {
120
+ 0% { transform: rotate(0deg); }
121
+ 100% { transform: rotate(360deg); }
122
+ }
123
+
124
+ /* Results styling */
125
+ .travel-result {
126
+ background: rgba(255, 255, 255, 0.05) !important;
127
+ border-left: 4px solid #4CAF50 !important;
128
+ border-radius: 8px !important;
129
+ padding: 1.5rem !important;
130
+ margin: 1rem 0 !important;
131
+ }
132
+
133
+ /* Tabs */
134
+ .stTabs [aria-selected="true"] {
135
+ background: rgba(255, 255, 255, 0.2) !important;
136
+ color: #ffffff !important;
137
+ border-bottom: 2px solid #ff6b6b !important;
138
+ }
139
+
140
+ /* Logo styling */
141
+ .logo-text {
142
+ font-size: 3rem !important;
143
+ background: linear-gradient(45deg, #FFD700, #FFA500) !important;
144
+ -webkit-background-clip: text !important;
145
+ -webkit-text-fill-color: transparent !important;
146
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3) !important;
147
+ }
148
+
149
+ /* Success indicators */
150
+ .success-badge {
151
+ background: linear-gradient(45deg, #4CAF50, #66BB6A) !important;
152
+ color: white !important;
153
+ padding: 0.5rem 1rem !important;
154
+ border-radius: 20px !important;
155
+ font-size: 0.9rem !important;
156
+ }
157
+ </style>
158
+ """, unsafe_allow_html=True)
159
+
160
+
161
+ class SmolAgent:
162
+ """
163
+ Base agent class implementing the smol agent architecture.
164
+ Each agent has a specific role and can collaborate with others.
165
+ """
166
+ def __init__(self, name: str, role: str, llm_client, search_tool):
167
+ self.name = name
168
+ self.role = role
169
+ self.llm = llm_client
170
+ self.search = search_tool
171
+ self.status = "idle"
172
+ self.last_result = None
173
+
174
+ def set_status(self, status: str, message: str = ""):
175
+ self.status = status
176
+ self.status_message = message
177
+
178
+ def execute_task(self, task_prompt: str, search_query: str = None) -> str:
179
+ """Execute a task with optional web search"""
180
+ try:
181
+ self.set_status("working", f"Processing {self.role.lower()} task...")
182
+
183
+ # Perform search if needed
184
+ search_results = ""
185
+ if search_query:
186
+ self.set_status("working", "Searching for relevant information...")
187
+ search_results = self.search(search_query)
188
+
189
+ # Create enhanced prompt with search results
190
+ enhanced_prompt = f"""
191
+ Role: {self.role}
192
+ Task: {task_prompt}
193
+
194
+ {f"Search Results: {search_results}" if search_results else ""}
195
+
196
+ Please provide a detailed response based on your role as {self.role}.
197
+ """
198
+
199
+ # Get response from LLM
200
+ self.set_status("working", "Generating response...")
201
+ result = self.llm(enhanced_prompt)
202
+
203
+ self.last_result = result
204
+ self.set_status("complete", "Task completed successfully")
205
+ return result
206
+
207
+ except Exception as e:
208
+ self.set_status("error", f"Error: {str(e)}")
209
+ return f"Error in {self.name}: {str(e)}"
210
+
211
+
212
+ class TravelSearchTool:
213
+ """Enhanced search tool specifically designed for travel planning"""
214
+ def __init__(self):
215
+ self.ddgs = DDGS()
216
+
217
+ def __call__(self, query: str, search_type: str = "general", max_results: int = 5) -> str:
218
+ try:
219
+ # Customize search based on type
220
+ if search_type == "flights":
221
+ query = f"best flight deals {query} 2024 booking sites"
222
+ elif search_type == "hotels":
223
+ query = f"best hotels accommodation {query} reviews booking"
224
+ elif search_type == "activities":
225
+ query = f"top attractions activities things to do {query} tourist guide"
226
+ elif search_type == "restaurants":
227
+ query = f"best restaurants food dining {query} local cuisine"
228
+ elif search_type == "weather":
229
+ query = f"weather forecast climate {query} best time to visit"
230
+
231
+ # Perform search
232
+ search_results = list(self.ddgs.text(
233
+ query,
234
+ max_results=max_results,
235
+ region='wt-wt',
236
+ safesearch='on'
237
+ ))
238
+
239
+ if not search_results:
240
+ return "No relevant information found. Please try a different search."
241
+
242
+ # Format results
243
+ formatted_results = []
244
+ for idx, result in enumerate(search_results, 1):
245
+ title = result.get('title', 'No title')
246
+ snippet = result.get('body', 'No description')
247
+ url = result.get('href', 'No URL')
248
+
249
+ formatted_results.append(
250
+ f"{idx}. {title}\n"
251
+ f" Description: {snippet}\n"
252
+ f" Source: {url}\n"
253
+ )
254
+
255
+ return "\n".join(formatted_results)
256
+
257
+ except Exception as e:
258
+ return f"Search error: {str(e)}"
259
+
260
+
261
+ class GroqLLM:
262
+ """Enhanced LLM client with travel-specific optimizations"""
263
+ def __init__(self, model_name="llama-3.1-70b-versatile"):
264
+ self.client = Groq(api_key=os.environ.get("GROQ_API_KEY"))
265
+ self.model_name = model_name
266
+
267
+ def __call__(self, prompt: Union[str, dict, List[Dict]]) -> str:
268
+ try:
269
+ completion = self.client.chat.completions.create(
270
+ model=self.model_name,
271
+ messages=[{
272
+ "role": "user",
273
+ "content": str(prompt)
274
+ }],
275
+ temperature=0.7,
276
+ max_tokens=2048,
277
+ stream=False
278
+ )
279
+
280
+ return completion.choices[0].message.content if completion.choices else "No response generated"
281
+
282
+ except Exception as e:
283
+ return f"LLM Error: {str(e)}"
284
+
285
+
286
+ class TravelPlannerSystem:
287
+ """Main orchestrator for the travel planning system"""
288
+ def __init__(self):
289
+ self.llm = GroqLLM()
290
+ self.search_tool = TravelSearchTool()
291
+ self.agents = self._initialize_agents()
292
+
293
+ def _initialize_agents(self) -> Dict[str, SmolAgent]:
294
+ """Initialize specialized travel agents"""
295
+ return {
296
+ "destination_expert": SmolAgent(
297
+ "Destination Expert",
298
+ "Travel destination researcher and recommender",
299
+ self.llm, self.search_tool
300
+ ),
301
+ "itinerary_planner": SmolAgent(
302
+ "Itinerary Planner",
303
+ "Trip itinerary creator and scheduler",
304
+ self.llm, self.search_tool
305
+ ),
306
+ "accommodation_specialist": SmolAgent(
307
+ "Accommodation Specialist",
308
+ "Hotel and lodging finder and recommender",
309
+ self.llm, self.search_tool
310
+ ),
311
+ "activity_curator": SmolAgent(
312
+ "Activity Curator",
313
+ "Tourist attraction and activity recommender",
314
+ self.llm, self.search_tool
315
+ ),
316
+ "budget_advisor": SmolAgent(
317
+ "Budget Advisor",
318
+ "Travel cost estimator and budget optimizer",
319
+ self.llm, self.search_tool
320
+ )
321
+ }
322
+
323
+ def create_travel_plan(self, destination: str, duration: str, budget: str,
324
+ travel_style: str, interests: str) -> Dict[str, str]:
325
+ """Create a comprehensive travel plan using multiple agents"""
326
+
327
+ # Prepare base context for all agents
328
+ base_context = f"""
329
+ Destination: {destination}
330
+ Duration: {duration}
331
+ Budget: {budget}
332
+ Travel Style: {travel_style}
333
+ Interests: {interests}
334
+ """
335
+
336
+ results = {}
337
+
338
+ # Agent 1: Destination Research
339
+ dest_task = f"""
340
+ Research {destination} as a travel destination. Include:
341
+ - Best time to visit and current weather
342
+ - Cultural highlights and local customs
343
+ - Transportation options
344
+ - Safety and travel requirements
345
+ - Local currency and tipping customs
346
+
347
+ Context: {base_context}
348
+ """
349
+ results["destination_info"] = self.agents["destination_expert"].execute_task(
350
+ dest_task, f"{destination} travel guide weather best time visit"
351
+ )
352
+
353
+ # Agent 2: Accommodation Research
354
+ accommodation_task = f"""
355
+ Find accommodation options for {destination}. Consider:
356
+ - Hotels, hostels, and alternative lodging based on budget: {budget}
357
+ - Location preferences for {travel_style} travelers
358
+ - Amenities and reviews
359
+ - Booking tips and best deals
360
+
361
+ Context: {base_context}
362
+ """
363
+ results["accommodation"] = self.agents["accommodation_specialist"].execute_task(
364
+ accommodation_task, f"{destination} hotels accommodation {budget} {travel_style}"
365
+ )
366
+
367
+ # Agent 3: Activities and Attractions
368
+ activity_task = f"""
369
+ Curate activities and attractions for {destination} based on interests: {interests}
370
+ Include:
371
+ - Must-see attractions and hidden gems
372
+ - Activities matching {travel_style} style
373
+ - Local experiences and cultural activities
374
+ - Restaurant and dining recommendations
375
+
376
+ Context: {base_context}
377
+ """
378
+ results["activities"] = self.agents["activity_curator"].execute_task(
379
+ activity_task, f"{destination} attractions activities {interests} restaurants"
380
+ )
381
+
382
+ # Agent 4: Itinerary Planning
383
+ itinerary_task = f"""
384
+ Create a detailed {duration} itinerary for {destination}. Include:
385
+ - Day-by-day schedule optimized for {travel_style} travelers
386
+ - Time management and logistics
387
+ - Mix of planned activities and free time
388
+ - Transportation between locations
389
+
390
+ Use information about accommodations and activities to create a cohesive plan.
391
+ Context: {base_context}
392
+ """
393
+ results["itinerary"] = self.agents["itinerary_planner"].execute_task(
394
+ itinerary_task, f"{destination} {duration} itinerary travel schedule"
395
+ )
396
+
397
+ # Agent 5: Budget Planning
398
+ budget_task = f"""
399
+ Create a detailed budget breakdown for the {destination} trip:
400
+ - Accommodation costs based on research
401
+ - Transportation (flights, local transport)
402
+ - Food and dining expenses
403
+ - Activities and attraction fees
404
+ - Miscellaneous expenses and emergency fund
405
+ - Money-saving tips and deals
406
+
407
+ Context: {base_context}
408
+ """
409
+ results["budget_breakdown"] = self.agents["budget_advisor"].execute_task(
410
+ budget_task, f"{destination} travel costs budget {duration} {budget}"
411
+ )
412
+
413
+ return results
414
+
415
+
416
+ def display_agent_status(agents: Dict[str, SmolAgent]):
417
+ """Display the status of all agents"""
418
+ st.markdown("### πŸ€– Agent Status Dashboard")
419
+
420
+ cols = st.columns(len(agents))
421
+ for idx, (name, agent) in enumerate(agents.items()):
422
+ with cols[idx]:
423
+ status_class = f"status-{agent.status}" if hasattr(agent, 'status') else "status-idle"
424
+ status_message = getattr(agent, 'status_message', 'Ready')
425
+
426
+ if agent.status == "working":
427
+ icon = '<div class="spinner"></div>'
428
+ elif agent.status == "complete":
429
+ icon = 'βœ…'
430
+ elif agent.status == "error":
431
+ icon = '❌'
432
+ else:
433
+ icon = '⏸️'
434
+
435
+ st.markdown(f"""
436
+ <div class="agent-status {status_class}">
437
+ {icon} <strong>{agent.name}</strong><br>
438
+ <small>{status_message}</small>
439
+ </div>
440
+ """, unsafe_allow_html=True)
441
+
442
+
443
+ # Main Application Interface
444
+ st.markdown("""
445
+ <div class="card" style="text-align: center; padding: 3rem;">
446
+ <h1 class="logo-text">✈️ SmolAgent Travel Planner</h1>
447
+ <p style="font-size: 1.2rem; opacity: 0.9; margin-top: 1rem;">
448
+ AI-powered travel planning with specialized agents working together to create your perfect trip
449
+ </p>
450
+ </div>
451
+ """, unsafe_allow_html=True)
452
+
453
+ # Initialize the system
454
+ try:
455
+ if 'travel_system' not in st.session_state:
456
+ st.session_state.travel_system = TravelPlannerSystem()
457
+
458
+ travel_system = st.session_state.travel_system
459
+
460
+ # Input Section
461
+ st.markdown('<div class="card">', unsafe_allow_html=True)
462
+ st.markdown("## 🌍 Plan Your Perfect Trip")
463
+
464
+ col1, col2 = st.columns(2)
465
+
466
+ with col1:
467
+ destination = st.text_input(
468
+ "🎯 Where do you want to go?",
469
+ placeholder="e.g., Tokyo, Japan or Paris, France",
470
+ help="Enter your dream destination"
471
+ )
472
+
473
+ duration = st.selectbox(
474
+ "πŸ“… Trip Duration",
475
+ ["3 days", "1 week", "2 weeks", "1 month", "Custom"],
476
+ help="How long will you be traveling?"
477
+ )
478
+
479
+ if duration == "Custom":
480
+ duration = st.text_input("Specify custom duration:", placeholder="e.g., 10 days")
481
+
482
+ with col2:
483
+ budget = st.selectbox(
484
+ "πŸ’° Budget Range",
485
+ ["Budget ($50-100/day)", "Mid-range ($100-250/day)", "Luxury ($250+/day)", "No specific budget"],
486
+ help="What's your daily budget range?"
487
+ )
488
+
489
+ travel_style = st.selectbox(
490
+ "πŸŽ’ Travel Style",
491
+ ["Adventure & Outdoor", "Cultural & Historical", "Relaxation & Spa", "Nightlife & Entertainment",
492
+ "Food & Culinary", "Family-Friendly", "Business Travel", "Solo Traveler", "Romantic Getaway"],
493
+ help="What kind of traveler are you?"
494
+ )
495
+
496
+ interests = st.text_area(
497
+ "🎨 Interests & Preferences",
498
+ placeholder="Tell us about your interests: art, food, history, adventure, shopping, nightlife, nature, etc.",
499
+ help="The more specific you are, the better recommendations we can provide!"
500
+ )
501
+
502
+ st.markdown('</div>', unsafe_allow_html=True)
503
+
504
+ # Planning Button
505
+ col1, col2, col3 = st.columns([1, 2, 1])
506
+ with col2:
507
+ plan_trip = st.button("πŸš€ CREATE MY TRAVEL PLAN", type="primary")
508
+
509
+ # Results Section
510
+ if plan_trip and destination:
511
+ with st.spinner(""):
512
+ # Display agent status dashboard
513
+ display_agent_status(travel_system.agents)
514
+
515
+ # Create the travel plan
516
+ st.markdown("### πŸ”„ Agents Working Together...")
517
+
518
+ # Progress tracking
519
+ progress_bar = st.progress(0)
520
+ status_placeholder = st.empty()
521
+
522
+ results = {}
523
+ total_agents = len(travel_system.agents)
524
+
525
+ # Update progress as each agent completes
526
+ for i, (agent_name, agent) in enumerate(travel_system.agents.items()):
527
+ progress = (i + 1) / total_agents
528
+ progress_bar.progress(progress)
529
+ status_placeholder.text(f"Agent {i+1}/{total_agents}: {agent.name} working...")
530
+ time.sleep(0.5) # Brief delay for visual effect
531
+
532
+ # Execute the travel planning
533
+ results = travel_system.create_travel_plan(
534
+ destination, duration, budget, travel_style, interests
535
+ )
536
+
537
+ progress_bar.progress(1.0)
538
+ status_placeholder.text("βœ… All agents completed successfully!")
539
+
540
+ # Display Results in Tabs
541
+ st.markdown(f'<div class="card"><h2>🎯 Your {destination} Travel Plan</h2></div>', unsafe_allow_html=True)
542
+
543
+ tab1, tab2, tab3, tab4, tab5 = st.tabs([
544
+ "🌍 Destination Info", "🏨 Accommodation", "🎭 Activities",
545
+ "πŸ“‹ Itinerary", "πŸ’° Budget"
546
+ ])
547
+
548
+ with tab1:
549
+ st.markdown('<div class="travel-result">', unsafe_allow_html=True)
550
+ st.markdown(results.get("destination_info", "Information not available"))
551
+ st.markdown('</div>', unsafe_allow_html=True)
552
+
553
+ with tab2:
554
+ st.markdown('<div class="travel-result">', unsafe_allow_html=True)
555
+ st.markdown(results.get("accommodation", "Information not available"))
556
+ st.markdown('</div>', unsafe_allow_html=True)
557
+
558
+ with tab3:
559
+ st.markdown('<div class="travel-result">', unsafe_allow_html=True)
560
+ st.markdown(results.get("activities", "Information not available"))
561
+ st.markdown('</div>', unsafe_allow_html=True)
562
+
563
+ with tab4:
564
+ st.markdown('<div class="travel-result">', unsafe_allow_html=True)
565
+ st.markdown(results.get("itinerary", "Information not available"))
566
+ st.markdown('</div>', unsafe_allow_html=True)
567
+
568
+ with tab5:
569
+ st.markdown('<div class="travel-result">', unsafe_allow_html=True)
570
+ st.markdown(results.get("budget_breakdown", "Information not available"))
571
+ st.markdown('</div>', unsafe_allow_html=True)
572
+
573
+ # Final agent status
574
+ st.markdown("### βœ… Mission Complete!")
575
+ display_agent_status(travel_system.agents)
576
+
577
+ elif plan_trip:
578
+ st.warning("🚨 Please enter a destination to start planning your trip!")
579
+
580
+ # Tips and Examples Section
581
+ if not plan_trip or not destination:
582
+ st.markdown('<div class="card">', unsafe_allow_html=True)
583
+ st.markdown("## πŸ’‘ How It Works")
584
+
585
+ col1, col2, col3 = st.columns(3)
586
+
587
+ with col1:
588
+ st.markdown("""
589
+ ### πŸ” Research Phase
590
+ Our **Destination Expert** searches for:
591
+ - Current weather & best times to visit
592
+ - Local customs & cultural insights
593
+ - Safety requirements & travel tips
594
+ - Transportation options
595
+ """)
596
+
597
+ with col2:
598
+ st.markdown("""
599
+ ### 🏨 Planning Phase
600
+ Our specialists find:
601
+ - **Accommodation** matching your budget
602
+ - **Activities** based on your interests
603
+ - **Restaurants** & local dining spots
604
+ - Hidden gems & local experiences
605
+ """)
606
+
607
+ with col3:
608
+ st.markdown("""
609
+ ### πŸ“‹ Organization Phase
610
+ Our planners create:
611
+ - **Day-by-day itinerary** optimized for you
612
+ - **Budget breakdown** with cost estimates
613
+ - **Logistics** and travel coordination
614
+ - **Money-saving tips** and deals
615
+ """)
616
+
617
+ st.markdown('</div>', unsafe_allow_html=True)
618
+
619
+ # Example destinations
620
+ st.markdown('<div class="card">', unsafe_allow_html=True)
621
+ st.markdown("## 🌟 Popular Destinations")
622
+
623
+ example_cols = st.columns(4)
624
+
625
+ examples = [
626
+ ("πŸ—Ύ Tokyo, Japan", "tokyo japan"),
627
+ ("πŸ₯– Paris, France", "paris france"),
628
+ ("πŸ›οΈ Rome, Italy", "rome italy"),
629
+ ("🏝️ Bali, Indonesia", "bali indonesia")
630
+ ]
631
+
632
+ for i, (display_name, destination_value) in enumerate(examples):
633
+ with example_cols[i]:
634
+ if st.button(display_name, key=f"example_{i}"):
635
+ st.session_state.destination_input = destination_value
636
+ st.rerun()
637
+
638
+ st.markdown('</div>', unsafe_allow_html=True)
639
+
640
+ except Exception as e:
641
+ st.error(f"""
642
+ <div style="display: flex; align-items: center; gap: 12px;">
643
+ <span>❌ Application Error: {str(e)}</span>
644
+ </div>
645
+ """, unsafe_allow_html=True)
646
+
647
+ st.markdown("""
648
+ <div class="card">
649
+ <h3>πŸ”§ Troubleshooting</h3>
650
+ <ul>
651
+ <li>Ensure your GROQ_API_KEY is set in environment variables</li>
652
+ <li>Check your internet connection for web searches</li>
653
+ <li>Try refreshing the page or restarting the application</li>
654
+ </ul>
655
+ </div>
656
+ """, unsafe_allow_html=True)
657
+
658
+ # Sidebar controls
659
+ with st.sidebar:
660
+ st.markdown("### πŸ› οΈ System Controls")
661
+
662
+ if st.button("πŸ”„ Reset Application"):
663
+ for key in list(st.session_state.keys()):
664
+ if key.startswith('travel_'):
665
+ del st.session_state[key]
666
+ st.rerun()
667
+
668
+ st.markdown("### πŸ“Š Agent Performance")
669
+ if 'travel_system' in st.session_state:
670
+ for name, agent in st.session_state.travel_system.agents.items():
671
+ status = getattr(agent, 'status', 'idle')
672
+ st.metric(agent.name, status.title())
673
+
674
+ st.markdown("### πŸ’¬ Feedback")
675
+ feedback = st.text_area("Share your experience:", placeholder="How was your travel plan?")
676
+ if st.button("Submit Feedback"):
677
+ st.success("Thank you for your feedback!")
678
+
679
+ # Footer
680
+ st.markdown("""
681
+ <div style="text-align: center; padding: 2rem; opacity: 0.8;">
682
+ <p>SmolAgent Travel Planner v2.0 | Powered by AI Collaboration</p>
683
+ </div>
684
+ """, unsafe_allow_html=True)