File size: 10,682 Bytes
319f147
 
357b49d
1d34f62
357b49d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319f147
1d34f62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319f147
 
1d34f62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357b49d
 
1d34f62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357b49d
916772f
 
 
 
 
 
 
 
 
 
 
1d34f62
 
 
 
357b49d
1d34f62
 
357b49d
1d34f62
 
 
 
 
 
 
357b49d
1d34f62
357b49d
1d34f62
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319f147
916772f
 
 
 
319f147
 
 
 
 
 
 
 
 
 
 
 
 
1d34f62
916772f
357b49d
 
1d34f62
916772f
 
 
 
 
1d34f62
916772f
 
1d34f62
357b49d
 
916772f
 
 
 
1d34f62
357b49d
 
916772f
 
 
 
319f147
357b49d
1d34f62
 
319f147
916772f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
319f147
 
916772f
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
import gradio as gr
from huggingface_hub import InferenceClient
import json
from typing import Dict, List, Tuple

# Hotel data
HOTELS = [
    {
        "name": "Azure Haven",
        "pricingPerDay": 250,
        "roomTypes": ["Single Room", "Double Room", "Suite"],
        "description": "Azure Haven is a tranquil getaway offering breathtaking ocean views and luxurious amenities. Ideal for a peaceful escape or a romantic retreat."
    },
    {
        "name": "Golden Sands Resort",
        "pricingPerDay": 300,
        "roomTypes": ["Standard Room", "Deluxe Room", "Family Suite"],
        "description": "Nestled on a pristine beach, Golden Sands Resort is perfect for family vacations and adventure seekers. Enjoy watersports, beachside dining, and more."
    },
    {
        "name": "Mountain Bliss Lodge",
        "pricingPerDay": 220,
        "roomTypes": ["Cabin", "Deluxe Cabin", "Mountain Suite"],
        "description": "Mountain Bliss Lodge offers cozy cabins and stunning mountain views. A perfect destination for nature lovers and outdoor enthusiasts."
    },
    {
        "name": "Urban Oasis Hotel",
        "pricingPerDay": 280,
        "roomTypes": ["Single Room", "Double Room", "Executive Suite"],
        "description": "Located in the heart of the city, Urban Oasis Hotel combines modern luxury with convenient access to top attractions, dining, and entertainment."
    },
    {
        "name": "Lakeside Retreat",
        "pricingPerDay": 270,
        "roomTypes": ["Single Room", "Double Room", "Lakeside Suite"],
        "description": "Lakeside Retreat offers serene lakeside accommodations with a focus on relaxation and rejuvenation. Enjoy spa treatments, boating, and picturesque views."
    }
]

# Cost constants
COST_FACTORS = {
    "local_transport_per_day": {
        "Budget Backpacking": 10,
        "Cultural & Sightseeing": 20,
        "Adventure & Outdoor": 25,
        "Food & Culinary": 20,
        "Relaxation & Wellness": 15,
        "Luxury & High-End": 50,
        "Family-Friendly": 30
    },
    "food_cost_per_day": {
        "Budget Backpacking": 30,
        "Cultural & Sightseeing": 50,
        "Adventure & Outdoor": 45,
        "Food & Culinary": 80,
        "Relaxation & Wellness": 60,
        "Luxury & High-End": 120,
        "Family-Friendly": 70
    },
    "activities_cost_per_day": {
        "Budget Backpacking": 20,
        "Cultural & Sightseeing": 40,
        "Adventure & Outdoor": 60,
        "Food & Culinary": 45,
        "Relaxation & Wellness": 80,
        "Luxury & High-End": 150,
        "Family-Friendly": 70
    }
}

client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")

def calculate_flight_cost(origin: str, destination: str, budget: int) -> float:
    """Estimate flight cost based on budget and journey type."""
    # Basic estimation - can be enhanced with actual flight data API
    if budget < 2000:
        return budget * 0.3  # 30% of budget for budget trips
    elif budget < 5000:
        return budget * 0.35  # 35% for mid-range trips
    else:
        return budget * 0.4  # 40% for luxury trips

def calculate_daily_costs(holiday_type: str) -> Dict[str, float]:
    """Calculate daily costs based on holiday type."""
    return {
        "local_transport": COST_FACTORS["local_transport_per_day"][holiday_type],
        "food": COST_FACTORS["food_cost_per_day"][holiday_type],
        "activities": COST_FACTORS["activities_cost_per_day"][holiday_type]
    }

def get_suitable_hotels(budget_per_day: float, holiday_type: str) -> List[Dict]:
    """Get suitable hotels based on daily budget and holiday type."""
    max_hotel_budget = budget_per_day * 0.4  # 40% of daily budget for accommodation
    
    suitable_hotels = []
    for hotel in HOTELS:
        if hotel["pricingPerDay"] <= max_hotel_budget:
            match_score = 0
            # Score hotels based on type match
            if holiday_type == "Relaxation & Wellness" and ("Haven" in hotel["name"] or "Retreat" in hotel["name"]):
                match_score += 2
            elif holiday_type == "Adventure & Outdoor" and ("Mountain" in hotel["name"] or "Sands" in hotel["name"]):
                match_score += 2
            elif holiday_type == "Cultural & Sightseeing" and "Urban" in hotel["name"]:
                match_score += 2
            elif holiday_type == "Family-Friendly" and "Family" in str(hotel["roomTypes"]):
                match_score += 2
            
            suitable_hotels.append({"hotel": hotel, "match_score": match_score})
    
    # Sort by match score and then price
    sorted_hotels = sorted(suitable_hotels, key=lambda x: (-x["match_score"], x["hotel"]["pricingPerDay"]))
    return [hotel["hotel"] for hotel in sorted_hotels]

def calculate_total_costs(
    origin: str,
    destination: str,
    budget: int,
    num_days: int,
    holiday_type: str,
    selected_hotel: Dict
) -> Dict[str, float]:
    """Calculate detailed cost breakdown."""
    flight_cost = calculate_flight_cost(origin, destination, budget)
    daily_costs = calculate_daily_costs(holiday_type)
    
    accommodation_cost = selected_hotel["pricingPerDay"] * num_days
    local_transport_cost = daily_costs["local_transport"] * num_days
    food_cost = daily_costs["food"] * num_days
    activities_cost = daily_costs["activities"] * num_days
    
    total_cost = (
        flight_cost +
        accommodation_cost +
        local_transport_cost +
        food_cost +
        activities_cost
    )
    
    return {
        "flight": flight_cost,
        "accommodation": accommodation_cost,
        "local_transport": local_transport_cost,
        "food": food_cost,
        "activities": activities_cost,
        "total": total_cost,
        "per_day": total_cost / num_days
    }

def format_cost_breakdown(costs: Dict[str, float]) -> str:
    """Format cost breakdown for display."""
    return f"""Cost Breakdown:
- Flight: ${costs['flight']:,.2f}
- Accommodation: ${costs['accommodation']:,.2f}
- Local Transportation: ${costs['local_transport']:,.2f}
- Food & Dining: ${costs['food']:,.2f}
- Activities & Entertainment: ${costs['activities']:,.2f}

Total Cost: ${costs['total']:,.2f}
Average Daily Cost: ${costs['per_day']:,.2f}"""

def generate_itinerary(
    destination: str,
    origin: str,
    budget: int,
    num_days: int,
    holiday_type: str,
    system_message: str,
    max_tokens: int,
    temperature: float,
    top_p: float,
) -> str:
    # Calculate initial costs and get hotel recommendations
    recommended_hotels = get_suitable_hotels(budget/num_days, holiday_type)
    if not recommended_hotels:
        return "Error: No suitable hotels found for your budget. Please increase your budget or reduce the number of days."
    
    selected_hotel = recommended_hotels[0]
    costs = calculate_total_costs(origin, destination, budget, num_days, holiday_type, selected_hotel)
    
    if costs["total"] > budget:
        return f"""Warning: The estimated total cost (${costs['total']:,.2f}) exceeds your budget (${budget:,.2f}).
Please consider:
1. Increasing your budget
2. Reducing the number of days
3. Choosing a more budget-friendly holiday type
4. Selecting different destinations

{format_cost_breakdown(costs)}"""
    
    # Construct prompt with accurate cost information
    prompt = f"""Create a detailed {num_days}-day travel itinerary for a trip:
From: {origin}
To: {destination}
Budget Breakdown: {format_cost_breakdown(costs)}
Holiday Type: {holiday_type}

Recommended Accommodation:
{selected_hotel['name']} (${selected_hotel['pricingPerDay']}/night)
{selected_hotel['description']}

Please provide:
1. Day-by-day itinerary with specific activities and timing
2. Daily budget allocation matching the cost breakdown above
3. Specific local transportation recommendations
4. Restaurant suggestions within the food budget (${costs['food']/num_days:.2f}/day)
5. Activity recommendations within the activities budget (${costs['activities']/num_days:.2f}/day)

Format as a clear day-by-day breakdown with budgets for each activity."""

    messages = [
        {"role": "system", "content": system_message},
        {"role": "user", "content": prompt}
    ]

    response = ""
    for message in client.chat_completion(
        messages,
        max_tokens=max_tokens,
        stream=True,
        temperature=temperature,
        top_p=top_p,
    ):
        token = message.choices[0].delta.content
        response += token
        yield response

# [Previous Gradio interface code remains the same, just update the button click handler to use the new generate_itinerary function]
# Create the Gradio interface
with gr.Blocks(theme=gr.themes.Soft()) as demo:
    gr.Markdown("# 🌎 AI Travel Itinerary Generator ✈️")
    gr.Markdown("Enter your travel details for a customized itinerary with accurate cost calculations!")
    
    with gr.Row():
        with gr.Column():
            origin = gr.Textbox(label="Starting Location", placeholder="e.g., New York, USA")
            destination = gr.Textbox(label="Destination", placeholder="e.g., Paris, France")
            budget = gr.Slider(minimum=1000, maximum=15000, value=3000, step=100, label="Total Budget (USD)")
            num_days = gr.Slider(minimum=1, maximum=14, value=3, step=1, label="Number of Days")
            holiday_type = gr.Dropdown(
                choices=list(COST_FACTORS["local_transport_per_day"].keys()),
                label="Type of Holiday",
                value="Cultural & Sightseeing"
            )
    
    with gr.Accordion("Advanced Settings", open=False):
        system_message = gr.Textbox(
            value="You are an experienced travel planner. Provide detailed itineraries that strictly adhere to the given budget constraints and cost breakdown.",
            label="System Message",
            lines=3
        )
        max_tokens = gr.Slider(minimum=1, maximum=2048, value=1024, step=1, label="Max Tokens")
        temperature = gr.Slider(minimum=0.1, maximum=1.0, value=0.7, step=0.1, label="Temperature")
        top_p = gr.Slider(minimum=0.1, maximum=1.0, value=0.95, step=0.05, label="Top-p")

    with gr.Row():
        generate_button = gr.Button("Generate Itinerary", variant="primary")
        output = gr.Textbox(label="Your Custom Itinerary", lines=20, show_copy_button=True)

    generate_button.click(
        fn=generate_itinerary,
        inputs=[
            destination,
            origin,
            budget,
            num_days,
            holiday_type,
            system_message,
            max_tokens,
            temperature,
            top_p,
        ],
        outputs=output,
    )

if __name__ == "__main__":
    demo.launch()