File size: 28,958 Bytes
285f5e6
be93ed8
 
5378318
285f5e6
be93ed8
b83209c
7ba4f1e
be93ed8
86a862e
6492bfc
 
285f5e6
6492bfc
86a862e
803333c
86a862e
 
 
b83209c
7ba4f1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86a862e
 
b5fc855
be93ed8
86a862e
 
 
 
 
 
b5fc855
86a862e
be93ed8
86a862e
803333c
86a862e
 
 
 
2620440
86a862e
803333c
 
 
 
 
be93ed8
86a862e
b5fc855
be93ed8
527d7d9
b5fc855
527d7d9
803333c
527d7d9
b5fc855
 
 
527d7d9
 
b5fc855
 
803333c
b5fc855
285f5e6
527d7d9
 
 
 
 
 
 
 
 
285f5e6
527d7d9
b5fc855
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285f5e6
b5fc855
 
 
 
 
 
 
 
285f5e6
b5fc855
 
 
 
 
285f5e6
527d7d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
803333c
527d7d9
 
 
803333c
86a862e
 
b5fc855
86a862e
 
 
 
b5fc855
86a862e
 
b5fc855
86a862e
 
b5fc855
86a862e
 
b5fc855
86a862e
 
b5fc855
86a862e
285f5e6
803333c
 
 
 
 
285f5e6
86a862e
 
803333c
 
 
 
 
 
86a862e
285f5e6
86a862e
803333c
86a862e
285f5e6
86a862e
803333c
b5fc855
803333c
86a862e
b5fc855
803333c
86a862e
 
b5fc855
803333c
b5fc855
7ba4f1e
86a862e
803333c
86a862e
 
803333c
b5fc855
803333c
7ba4f1e
86a862e
803333c
 
 
86a862e
b5fc855
803333c
b5fc855
7ba4f1e
527d7d9
803333c
86a862e
803333c
 
 
86a862e
803333c
86a862e
803333c
 
285f5e6
547cc10
803333c
 
527d7d9
86a862e
527d7d9
 
 
803333c
86a862e
803333c
86a862e
803333c
527d7d9
 
 
 
803333c
527d7d9
 
 
 
 
 
 
 
 
803333c
527d7d9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
803333c
527d7d9
 
 
 
 
 
 
 
 
 
 
 
86a862e
 
803333c
527d7d9
 
 
 
 
 
 
 
 
803333c
527d7d9
7ba4f1e
 
 
 
 
 
527d7d9
7ba4f1e
 
 
 
803333c
 
 
b5fc855
803333c
285f5e6
 
 
527d7d9
803333c
285f5e6
803333c
 
 
 
 
 
527d7d9
 
 
803333c
 
 
 
285f5e6
803333c
 
f5b722a
 
 
 
 
285f5e6
803333c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
527d7d9
803333c
 
 
 
 
527d7d9
803333c
 
 
86a862e
803333c
 
86a862e
803333c
285f5e6
803333c
f5b722a
527d7d9
86a862e
 
803333c
527d7d9
7ba4f1e
 
803333c
527d7d9
 
 
 
 
 
 
 
 
803333c
 
 
 
 
285f5e6
 
 
527d7d9
803333c
 
 
 
 
527d7d9
803333c
 
 
 
 
86a862e
 
 
 
285f5e6
86a862e
 
 
 
 
 
 
803333c
86a862e
803333c
 
 
 
 
 
 
 
 
86a862e
be93ed8
76e6c5c
86a862e
803333c
58bec55
f5b722a
 
86a862e
f5b722a
527d7d9
 
 
 
f5b722a
803333c
 
 
86a862e
 
 
f5b722a
86a862e
f5b722a
b5fc855
803333c
 
86a862e
803333c
86a862e
f5b722a
86a862e
 
 
 
 
 
 
803333c
 
527d7d9
803333c
 
86a862e
803333c
86a862e
 
f5b722a
86a862e
 
803333c
 
 
86a862e
 
285f5e6
803333c
 
86a862e
 
803333c
f5b722a
803333c
 
 
86a862e
 
 
 
285f5e6
86a862e
 
803333c
86a862e
527d7d9
803333c
86a862e
803333c
86a862e
 
 
803333c
86a862e
803333c
 
86a862e
803333c
f5b722a
803333c
 
 
b5fc855
803333c
 
b5fc855
86a862e
 
803333c
 
f5b722a
803333c
 
86a862e
 
285f5e6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
import os
import json
import requests
from datetime import datetime, timedelta
from functools import lru_cache
import gradio as gr
import openai
import random

# -------------------- CONFIGURATION --------------------
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OPENWEATHER_API_KEY = os.getenv("OPENWEATHER_API_KEY", "")
SERP_API_KEY = os.getenv("SERPAPI_API_KEY", "")

if not OPENAI_API_KEY:
    print("⚠️ OPENAI_API_KEY not set. AI itinerary generation will fall back to manual mode.")
    client = None
else:
    client = openai.OpenAI(api_key=OPENAI_API_KEY)

# Image cache to avoid repeated API calls
IMAGE_CACHE = {}

# -------------------- IMAGE FUNCTION --------------------
def get_destination_image(city: str) -> str:
    """Fetch a real image of the destination using SerpAPI."""
    cache_key = city.lower()
    
    if cache_key in IMAGE_CACHE:
        return IMAGE_CACHE[cache_key]
    
    if SERP_API_KEY:
        try:
            params = {
                "q": f"{city} city landmark beautiful view",
                "api_key": SERP_API_KEY,
                "engine": "google",
                "tbm": "isch",
                "num": 1
            }
            response = requests.get("https://serpapi.com/search", params=params, timeout=10)
            data = response.json()
            
            images = data.get("images_results", [])
            if images and len(images) > 0:
                img_url = images[0].get("original", images[0].get("thumbnail"))
                if img_url:
                    IMAGE_CACHE[cache_key] = img_url
                    return img_url
        except Exception as e:
            print(f"Image fetch error: {e}")
    
    return None

# -------------------- WEATHER FUNCTION --------------------
def get_weather(city: str) -> dict:
    """Fetch real-time weather data for any city."""
    if not OPENWEATHER_API_KEY:
        return {
            "city": city,
            "temperature": 22,
            "condition": "sunny",
            "humidity": 60,
            "wind_speed": 10,
            "note": "Add OpenWeather API key for real data"
        }
    try:
        url = "https://api.openweathermap.org/data/2.5/weather"
        params = {'q': city, 'appid': OPENWEATHER_API_KEY, 'units': 'metric'}
        response = requests.get(url, params=params, timeout=10)
        data = response.json()
        if response.status_code != 200:
            return {"error": f"Weather API error: {data.get('message', 'unknown')}"}
        return {
            "city": city,
            "temperature": data['main']['temp'],
            "condition": data['weather'][0]['description'],
            "humidity": data['main']['humidity'],
            "wind_speed": data['wind']['speed'],
            "precipitation": data.get('rain', {}).get('1h', 0)
        }
    except Exception as e:
        return {"error": f"Weather error: {str(e)}"}

# -------------------- REAL ATTRACTIONS FUNCTION --------------------
def get_real_attractions(city: str) -> list:
    """Get real attractions using OpenAI first for better quality."""
    
    # Try OpenAI first for accurate attraction names and activities
    if client:
        try:
            prompt = f"""List the top 6 REAL tourist attractions in {city}. For each attraction, provide:
- Name (actual famous attraction name)
- A brief description including specific ACTIVITIES you can do there (use action words like: swimming, hiking, skating, climbing, boating, cycling, shopping, dining, photography, sightseeing, museum visiting, etc.)
- Typical entry fee in USD (use numbers, 0 if free)
- Approximate visit duration in hours

Return ONLY a valid JSON array with keys: name, description, entry_fee, duration_hours.

Example for Paris:
[
  {{
    "name": "Eiffel Tower",
    "description": "Climb to the top for panoramic views, dine at the restaurant, and enjoy photography at sunset.",
    "entry_fee": 25,
    "duration_hours": 2.5
  }}
]

Important: Use REAL attractions specific to {city}. Make descriptions include ACTION WORDS like hiking, swimming, exploring, climbing."""
            
            response = client.chat.completions.create(
                model="gpt-3.5-turbo",
                messages=[{"role": "user", "content": prompt}],
                temperature=0.7,
                max_tokens=1000
            )
            content = response.choices[0].message.content
            
            # Clean response
            content = content.strip()
            if content.startswith('```json'):
                content = content[7:]
            if content.startswith('```'):
                content = content[3:]
            if content.endswith('```'):
                content = content[:-3]
            
            attractions = json.loads(content)
            if isinstance(attractions, dict) and "attractions" in attractions:
                attractions = attractions["attractions"]
            elif not isinstance(attractions, list):
                attractions = [attractions]
            
            result = []
            for a in attractions[:6]:
                fee = a.get("entry_fee", 0)
                if isinstance(fee, (int, float)):
                    if fee == 0:
                        fee_display = "Free"
                    else:
                        fee_display = f"${fee}"
                else:
                    fee_display = str(fee)
                
                result.append({
                    "name": a.get("name", "Unknown"),
                    "description": a.get("description", f"A must-visit attraction in {city}"),
                    "entry_fee": fee_display,
                    "duration_hours": a.get("duration_hours", 2)
                })
            
            if result:
                return result
                
        except Exception as e:
            print(f"OpenAI attractions error: {e}")
    
    # Fallback to SerpAPI
    if SERP_API_KEY:
        try:
            params = {
                "q": f"top tourist attractions in {city}",
                "api_key": SERP_API_KEY,
                "engine": "google",
                "num": 6
            }
            response = requests.get("https://serpapi.com/search", params=params, timeout=10)
            data = response.json()
            
            attractions = []
            for result in data.get("organic_results", [])[:6]:
                title = result.get("title", "")
                if "wikipedia" not in title.lower() and "tripadvisor" not in title.lower():
                    name = title.split(" - ")[0].split(" | ")[0].split(":")[0].strip()
                    if len(name) > 5 and len(name) < 100:
                        attractions.append({
                            "name": name,
                            "description": result.get("snippet", f"Explore this popular attraction in {city}"),
                            "entry_fee": "Check website",
                            "duration_hours": 2
                        })
            
            if attractions and len(attractions) >= 3:
                return attractions[:6]
        except Exception as e:
            print(f"SerpAPI error: {e}")
    
    # Ultimate fallback
    return [
        {"name": f"Historic {city} City Center", "description": f"Explore the historic heart of {city} with walking tours, shopping, and photography.", "entry_fee": "Free", "duration_hours": 2},
        {"name": f"{city} Cultural Museum", "description": f"Discover art and history through guided tours and interactive exhibits.", "entry_fee": "$10", "duration_hours": 2},
        {"name": f"{city} Central Park", "description": f"Enjoy hiking, picnicking, and outdoor activities in this beautiful green space.", "entry_fee": "Free", "duration_hours": 1.5}
    ]

# -------------------- BUDGET CALCULATION --------------------
def calculate_budget(num_days: int, budget_amount: float = None) -> dict:
    """Calculate budget based on days and user input."""
    if budget_amount:
        daily_budget = budget_amount / num_days
        if daily_budget < 100:
            level = "Budget"
            daily_rates = {"accommodation": 50, "food": 35, "transport": 15, "activities": 10}
        elif daily_budget < 200:
            level = "Moderate"
            daily_rates = {"accommodation": 100, "food": 60, "transport": 25, "activities": 20}
        elif daily_budget < 400:
            level = "Comfortable"
            daily_rates = {"accommodation": 180, "food": 100, "transport": 35, "activities": 35}
        else:
            level = "Luxury"
            daily_rates = {"accommodation": 300, "food": 150, "transport": 50, "activities": 60}
    else:
        level = "Moderate"
        daily_rates = {"accommodation": 100, "food": 60, "transport": 25, "activities": 20}
    
    accommodation = daily_rates["accommodation"] * num_days
    food = daily_rates["food"] * num_days
    transport = daily_rates["transport"] * num_days
    activities = daily_rates["activities"] * num_days
    total = accommodation + food + transport + activities
    
    return {
        "level": level,
        "accommodation": accommodation,
        "food": food,
        "transport": transport,
        "activities": activities,
        "total": total,
        "daily": daily_rates
    }

# -------------------- ITINERARY GENERATION --------------------
def generate_itinerary(destination: str, start_date: str, num_days: int, 
                       budget_amount: float, budget_currency: str, departure_city: str = ""):
    """Main itinerary generation function."""
    try:
        if not destination:
            return "❌ Please enter a destination city."
        
        if num_days < 1 or num_days > 14:
            return "❌ Number of days must be between 1 and 14."
        
        weather = get_weather(destination)
        if "error" in weather:
            return f"❌ Weather error: {weather['error']}"
        
        attractions = get_real_attractions(destination)
        destination_image = get_destination_image(destination)
        budget_data = calculate_budget(num_days, budget_amount)
        
        start = datetime.strptime(start_date, "%Y-%m-%d")
        end = start + timedelta(days=int(num_days) - 1)
        
        html = generate_html_itinerary(
            destination, weather, attractions, budget_data, 
            num_days, start, end, budget_amount, departure_city, destination_image
        )
        
        return html
        
    except Exception as e:
        return f"❌ An unexpected error occurred: {str(e)}"

def generate_html_itinerary(destination, weather, attractions, budget_data, 
                           num_days, start_date, end_date, budget_amount, departure_city, destination_image):
    """Create beautiful HTML itinerary with max 3 attractions per day."""
    
    weather_temp = f"{weather['temperature']:.1f}Β°C" if isinstance(weather['temperature'], (int, float)) else str(weather['temperature'])
    weather_condition = weather['condition'].capitalize()
    
    # Budget warning
    budget_warning = ""
    if budget_amount and budget_data['total'] > budget_amount:
        budget_warning = f"""
        <div style="background: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; border-radius: 8px; margin: 15px 0;">
            <strong>⚠️ Budget Alert:</strong> Estimated costs (${budget_data['total']:.0f}) exceed your budget (${budget_amount:.0f}). 
            Consider reducing days or choosing budget-friendly options.
        </div>
        """
    
    # Daily itinerary - MAX 3 ATTRACTIONS PER DAY
    daily_html = ""
    # Distribute attractions: max 3 per day
    attractions_per_day = min(3, len(attractions))
    total_attractions = min(len(attractions), attractions_per_day * num_days)
    
    for day in range(1, num_days + 1):
        current_date = start_date + timedelta(days=day-1)
        date_str = current_date.strftime("%A, %B %d")
        
        # Get attractions for this day (max 3 different attractions)
        start_idx = (day-1) * attractions_per_day
        end_idx = min(day * attractions_per_day, total_attractions)
        day_attractions = attractions[start_idx:end_idx] if start_idx < len(attractions) else []
        
        # If no more unique attractions, use activities based on weather
        if not day_attractions:
            weather_lower = weather_condition.lower()
            if "rain" in weather_lower:
                activities = ["Visit indoor museums", "Enjoy shopping malls", "Try local cooking classes"]
            elif "sun" in weather_lower or "clear" in weather_lower:
                activities = ["Outdoor hiking", "Parks and gardens", "City walking tours"]
            else:
                activities = ["Cultural experiences", "Local food tasting", "Art gallery visits"]
            
            day_attractions = [
                {"name": activities[0], "description": f"Enjoy {activities[0].lower()} in {destination}", "entry_fee": "Varies", "duration_hours": 2},
                {"name": activities[1], "description": f"Experience {activities[1].lower()} in {destination}", "entry_fee": "Varies", "duration_hours": 2},
                {"name": activities[2], "description": f"Explore {activities[2].lower()} in {destination}", "entry_fee": "Varies", "duration_hours": 2}
            ][:attractions_per_day]
        
        daily_html += f"""
        <div style="background: white; border-radius: 12px; margin-bottom: 20px; overflow: hidden; box-shadow: 0 2px 8px rgba(0,0,0,0.05);">
            <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 12px 20px; color: white;">
                <h3 style="margin: 0; font-size: 1.2em;">Day {day} Β· {date_str}</h3>
            </div>
            <div style="padding: 20px;">
        """
        
        for i, attr in enumerate(day_attractions, 1):
            daily_html += f"""
                <div style="margin-bottom: 15px; padding: 12px; background: #f8f9fa; border-radius: 8px;">
                    <div style="display: flex; align-items: center; gap: 10px;">
                        <div style="background: #667eea; color: white; width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold;">
                            {i}
                        </div>
                        <div style="flex: 1;">
                            <strong style="font-size: 1em;">🎯 {attr['name']}</strong><br>
                            <span style="font-size: 0.85em; color: #666;">{attr['description']}</span>
                            <div style="font-size: 0.75em; color: #888; margin-top: 5px;">
                                ⏱️ {attr['duration_hours']} hrs | 🎟️ {attr['entry_fee']}
                            </div>
                        </div>
                    </div>
                </div>
            """
        
        daily_html += f"""
                <div style="margin-top: 15px; padding-top: 15px; border-top: 1px solid #e0e0e0;">
                    <div><span style="font-size: 1.1em;">🍽️</span> <strong>Lunch:</strong> Try authentic local cuisine at a nearby restaurant</div>
                    <div style="margin-top: 8px;"><span style="font-size: 1.1em;">πŸŒ™</span> <strong>Evening:</strong> Explore local markets, enjoy cultural shows, or relax at a cafe</div>
                </div>
            </div>
        </div>
        """
    
    # Destination Image Section
    image_html = ""
    if destination_image:
        image_html = f"""
        <div style="background: white; padding: 20px; border-radius: 12px; margin: 20px 0; box-shadow: 0 2px 10px rgba(0,0,0,0.05); text-align: center;">
            <h2 style="margin: 0 0 15px 0; color: #667eea;">πŸ“Έ A Glimpse of {destination}</h2>
            <div style="border-radius: 12px; overflow: hidden; box-shadow: 0 4px 15px rgba(0,0,0,0.1);">
                <img src="{destination_image}" style="width: 100%; max-height: 400px; object-fit: cover;" alt="{destination}">
            </div>
        </div>
        """
    
    # Budget breakdown
    budget_html = f"""
    <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 20px; border-radius: 12px; color: white; margin: 20px 0;">
        <h3 style="margin: 0 0 15px 0;">πŸ’° Budget Breakdown ({budget_data['level']} Travel Style)</h3>
        <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 15px;">
            <div><strong>🏨 Accommodation</strong><br>${budget_data['accommodation']:.0f}<br><small>(${budget_data['daily']['accommodation']}/day)</small></div>
            <div><strong>🍽️ Food & Dining</strong><br>${budget_data['food']:.0f}<br><small>(${budget_data['daily']['food']}/day)</small></div>
            <div><strong>πŸš— Local Transport</strong><br>${budget_data['transport']:.0f}<br><small>(${budget_data['daily']['transport']}/day)</small></div>
            <div><strong>🎟️ Activities</strong><br>${budget_data['activities']:.0f}<br><small>(${budget_data['daily']['activities']}/day)</small></div>
            <div style="border-top: 2px solid rgba(255,255,255,0.3); padding-top: 10px; grid-column: 1/-1;">
                <strong>πŸ’° Total Estimated Cost</strong><br><span style="font-size: 1.2em;">${budget_data['total']:.0f}</span>
                {f" (Your budget: ${budget_amount:.0f})" if budget_amount else ""}
            </div>
        </div>
    </div>
    """
    
    # Currency conversion link
    currency_link = f"""
    <a href="https://www.xe.com/currencyconverter/" target="_blank" style="color: #667eea; text-decoration: none; margin-left: 15px;">πŸ’± Currency Converter</a>
    """
    
    # Complete HTML
    full_html = f"""
    <div style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 100%;">
        <!-- Hero Section -->
        <div style="background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 40px; border-radius: 20px; color: white; margin-bottom: 30px; text-align: center;">
            <h1 style="margin: 0; font-size: 2.5em;">πŸ€– Agentic AI Travel Planner</h1>
            <p style="margin: 10px 0 0; opacity: 0.9; font-size: 1.1em;">
                Intelligent Itinerary Generation β€’ Real-time Data β€’ Smart Recommendations
            </p>
            <h2 style="margin: 20px 0 0; font-size: 1.8em;">🌍 {destination}</h2>
            <p style="margin: 10px 0 0; opacity: 0.9;">
                {num_days} Days of Adventure β€’ {start_date.strftime('%B %d')} - {end_date.strftime('%B %d, %Y')}
            </p>
            {f"<p style='margin: 5px 0 0; opacity: 0.8;'>✈️ From: {departure_city}</p>" if departure_city else ""}
        </div>
        
        <!-- Quick Stats -->
        <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px;">
            <div style="background: #f8f9fa; padding: 15px; border-radius: 12px; text-align: center;">
                <div style="font-size: 2em;">🌀️</div>
                <strong>{weather_temp}</strong><br>
                <small>{weather_condition}</small>
            </div>
            <div style="background: #f8f9fa; padding: 15px; border-radius: 12px; text-align: center;">
                <div style="font-size: 2em;">πŸ“…</div>
                <strong>{num_days} Days</strong><br>
                <small>Full Itinerary</small>
            </div>
            <div style="background: #f8f9fa; padding: 15px; border-radius: 12px; text-align: center;">
                <div style="font-size: 2em;">🎯</div>
                <strong>{min(len(attractions), num_days * 3)}+ Activities</strong><br>
                <small>To Explore</small>
            </div>
            <div style="background: #f8f9fa; padding: 15px; border-radius: 12px; text-align: center;">
                <div style="font-size: 2em;">πŸ’°</div>
                <strong>${budget_data['total']:.0f}</strong><br>
                <small>Estimated Total</small>
            </div>
        </div>
        
        {budget_warning}
        
        <!-- Budget Section -->
        {budget_html}
        
        <!-- Daily Itinerary -->
        <div style="background: white; padding: 20px; border-radius: 12px; margin: 20px 0; box-shadow: 0 2px 10px rgba(0,0,0,0.05);">
            <h2 style="margin: 0 0 15px 0; color: #667eea;">πŸ“… AI-Generated {num_days}-Day Itinerary</h2>
            <div style="font-size: 0.85em; color: #888; margin-bottom: 15px;">πŸ€– Planner Agent β€’ Optimized Schedule β€’ Max 3 Activities Per Day</div>
            {daily_html}
        </div>
        
        <!-- Destination Image -->
        {image_html}
        
        <!-- Travel Tips -->
        <div style="background: #f0f4ff; padding: 20px; border-radius: 12px; margin: 20px 0;">
            <h3 style="margin: 0 0 15px 0; color: #667eea;">πŸ’‘ Smart Travel Tips</h3>
            <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px;">
                <div>🎫 <strong>Book in Advance</strong><br>Save time and money</div>
                <div>πŸš‡ <strong>Public Transport</strong><br>Get day passes for savings</div>
                <div>πŸ“± <strong>Offline Maps</strong><br>Download before you go</div>
                <div>πŸ’΅ <strong>Local Currency</strong><br>Carry cash for markets</div>
            </div>
        </div>
        
        <!-- Booking Links -->
        <div style="text-align: center; padding: 20px; margin-top: 20px; background: #f8f9fa; border-radius: 12px;">
            <h3 style="margin: 0 0 15px 0;">Ready to Book Your Trip?</h3>
            <p>
                πŸ›οΈ <a href="https://www.booking.com/searchresults.html?ss={destination.replace(' ', '+')}" target="_blank" style="color: #667eea;">Search Hotels</a> | 
                ✈️ <a href="https://www.skyscanner.net/" target="_blank" style="color: #667eea;">Search Flights</a> | 
                🎟️ <a href="https://www.tripadvisor.com/Search?q={destination}" target="_blank" style="color: #667eea;">Read Reviews</a>
                {currency_link}
            </p>
        </div>
        
        <!-- Footer -->
        <div style="text-align: center; padding: 20px; margin-top: 20px; font-size: 0.85em; color: #666;">
            <p>πŸ€– Agentic AI System β€’ Powered by OpenAI, OpenWeather & SerpAPI</p>
        </div>
    </div>
    """
    
    return full_html

# -------------------- GRADIO INTERFACE --------------------
css = """
.gradio-container {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    max-width: 1200px;
    margin: 0 auto;
}
.gr-button-primary {
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
    border: none !important;
    font-weight: bold !important;
    padding: 12px 30px !important;
    font-size: 1.1em !important;
    transition: transform 0.2s !important;
}
.gr-button-primary:hover {
    transform: translateY(-2px) !important;
}
input, select, textarea {
    border-radius: 8px !important;
    border: 1px solid #e0e0e0 !important;
}
"""

with gr.Blocks(css=css, title="πŸ€– TRAVEL  WITH ME ") as demo:
    gr.HTML("""
    <div style="text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding: 40px; border-radius: 20px; margin-bottom: 30px;">
        <h1 style="color: white; margin: 0; font-size: 2.5em;">πŸ€– TRAVEL WITH ME</h1>
        <p style="color: white; margin: 10px 0 0; opacity: 0.95; font-size: 1.1em;">
            Multi-Agent System β€’ Intelligent Itinerary Generation β€’ Real-time Data Processing
        </p>
        <div style="margin-top: 15px;">
            <span style="background: rgba(255,255,255,0.2); padding: 5px 12px; border-radius: 20px; font-size: 0.85em; margin: 0 5px;">🧠 Weather Agent</span>
            <span style="background: rgba(255,255,255,0.2); padding: 5px 12px; border-radius: 20px; font-size: 0.85em; margin: 0 5px;">πŸ” Scout Agent</span>
            <span style="background: rgba(255,255,255,0.2); padding: 5px 12px; border-radius: 20px; font-size: 0.85em; margin: 0 5px;">πŸ’° Budget Agent</span>
            <span style="background: rgba(255,255,255,0.2); padding: 5px 12px; border-radius: 20px; font-size: 0.85em; margin: 0 5px;">πŸ“… Planner Agent</span>
        </div>
    </div>
    """)
    
    with gr.Row(equal_height=True):
        with gr.Column(scale=2):
            with gr.Group():
                gr.Markdown("### 🎯 Destination Input")
                destination = gr.Textbox(
                    label="Enter City",
                    placeholder="e.g., Paris, Tokyo, Nairobi, New York, Rome...",
                    lines=1,
                    show_label=False
                )
            
            with gr.Group():
                gr.Markdown("### πŸ“… Travel Details")
                with gr.Row():
                    start_date = gr.Textbox(
                        label="Start Date",
                        value=datetime.now().strftime("%Y-%m-%d"),
                        placeholder="YYYY-MM-DD"
                    )
                    num_days = gr.Slider(
                        label="Duration (Days)",
                        minimum=1,
                        maximum=7,
                        value=3,
                        step=1
                    )
        
        with gr.Column(scale=1):
            with gr.Group():
                gr.Markdown("### πŸ’° Budget Optimization")
                with gr.Row():
                    budget_amount = gr.Number(
                        label="Total Budget (Optional)",
                        placeholder="Enter amount",
                        value=None
                    )
                    budget_currency = gr.Dropdown(
                        ["USD", "EUR", "GBP", "JPY", "CAD", "AUD"],
                        label="Currency",
                        value="USD"
                    )
                gr.HTML("""
                <div style="background: #e8f0fe; padding: 10px; border-radius: 8px; margin-top: 10px;">
                    <small>πŸ’‘ <strong>Budget Agent:</strong> Automatically optimizes recommendations based on your budget!</small>
                </div>
                """)
            
            with gr.Group():
                gr.Markdown("### ✈️ Departure Info")
                departure_city = gr.Textbox(
                    label="Departure City (Optional)",
                    placeholder="e.g., New York, London",
                    lines=1
                )
    
    with gr.Row():
        generate_btn = gr.Button("✈️ Plan My Trip", variant="primary", size="lg")
    
    output = gr.HTML()
    
    generate_btn.click(
        fn=generate_itinerary,
        inputs=[destination, start_date, num_days, budget_amount, budget_currency, departure_city],
        outputs=output
    )
    
    # Examples section
    gr.HTML("""
    <div style="text-align: center; padding: 20px; margin-top: 20px; border-top: 1px solid #eee;">
        <h3>🌟 Try These Destinations</h3>
        <div style="display: flex; gap: 10px; justify-content: center; flex-wrap: wrap;">
            <button onclick="document.querySelector('#destination input').value='Paris';" style="background: #f0f4ff; border: none; padding: 8px 16px; border-radius: 20px; cursor: pointer;">πŸ—Ό Paris</button>
            <button onclick="document.querySelector('#destination input').value='Tokyo';" style="background: #f0f4ff; border: none; padding: 8px 16px; border-radius: 20px; cursor: pointer;">πŸ—Ύ Tokyo</button>
            <button onclick="document.querySelector('#destination input').value='Nairobi';" style="background: #f0f4ff; border: none; padding: 8px 16px; border-radius: 20px; cursor: pointer;">πŸ¦’ Nairobi</button>
            <button onclick="document.querySelector('#destination input').value='New York';" style="background: #f0f4ff; border: none; padding: 8px 16px; border-radius: 20px; cursor: pointer;">πŸ—½ New York</button>
            <button onclick="document.querySelector('#destination input').value='Rome';" style="background: #f0f4ff; border: none; padding: 8px 16px; border-radius: 20px; cursor: pointer;">πŸ›οΈ Rome</button>
            <button onclick="document.querySelector('#destination input').value='Bangkok';" style="background: #f0f4ff; border: none; padding: 8px 16px; border-radius: 20px; cursor: pointer;">🍜 Bangkok</button>
        </div>
    </div>
    
    <div style="text-align: center; padding: 20px; margin-top: 20px; border-top: 1px solid #eee; color: #666;">
        <small>πŸ€– Multi-Agent AI System β€’ Weather Agent | Scout Agent | Budget Agent | Planner Agent β€’ Working in Harmony ✨</small>
    </div>
    """)

if __name__ == "__main__":
    demo.launch(share=False, server_name="0.0.0.0")