Update app.py
Browse files
app.py
CHANGED
@@ -1,488 +1,71 @@
|
|
1 |
-
#
|
2 |
# This agent helps travelers with destination information, local time, weather forecasts,
|
3 |
-
# currency conversion, language translation, and
|
4 |
|
5 |
-
from smolagents import CodeAgent, HfApiModel, load_tool
|
6 |
import datetime
|
7 |
-
import requests
|
8 |
-
import pytz
|
9 |
import yaml
|
10 |
-
import random
|
11 |
-
import json
|
12 |
import os
|
|
|
|
|
13 |
from tools.final_answer import FinalAnswerTool
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
from Gradio_UI import GradioUI
|
15 |
|
16 |
-
# Load the image generation tool once, outside the function
|
17 |
-
image_generation_tool = load_tool("agents-course/text-to-image", trust_remote_code=True)
|
18 |
-
|
19 |
-
# ==================== ORIGINAL TOOLS (ENHANCED) ====================
|
20 |
-
|
21 |
-
@tool
|
22 |
-
def generate_destination_preview(destination: str) -> str:
|
23 |
-
"""Generates a vibrant, artistic preview image of a travel destination.
|
24 |
-
|
25 |
-
Args:
|
26 |
-
destination: The travel destination to visualize (e.g., 'Paris', 'Tokyo', 'Bali').
|
27 |
-
|
28 |
-
Returns:
|
29 |
-
A link to the generated destination preview image.
|
30 |
-
"""
|
31 |
-
# List of visual styles for variety
|
32 |
-
styles = [
|
33 |
-
"sunrise golden hour",
|
34 |
-
"blue hour twilight",
|
35 |
-
"vibrant daytime",
|
36 |
-
"dramatic sunset",
|
37 |
-
"night lights"
|
38 |
-
]
|
39 |
-
|
40 |
-
# Select a random style for variety
|
41 |
-
style = random.choice(styles)
|
42 |
-
|
43 |
-
# Construct a detailed prompt for the AI model
|
44 |
-
prompt = f"A beautiful travel photograph of {destination}, {style}, photorealistic, high-resolution, travel photography, highly detailed landmark view"
|
45 |
-
|
46 |
-
# Use the pre-loaded image generation tool
|
47 |
-
try:
|
48 |
-
image_url = image_generation_tool(prompt)
|
49 |
-
return f"Here's a preview of {destination}: {image_url}"
|
50 |
-
except Exception as e:
|
51 |
-
return f"Error generating image of {destination}: {str(e)}"
|
52 |
-
|
53 |
-
|
54 |
-
@tool
|
55 |
-
def get_local_time(destination: str) -> str:
|
56 |
-
"""Get the current local time at a travel destination.
|
57 |
-
|
58 |
-
Args:
|
59 |
-
destination: A city or location name (e.g., 'Paris', 'Tokyo', 'New York').
|
60 |
-
|
61 |
-
Returns:
|
62 |
-
The current local time at the specified destination.
|
63 |
-
"""
|
64 |
-
# Map of common tourist destinations to their timezones
|
65 |
-
destination_timezones = {
|
66 |
-
"london": "Europe/London",
|
67 |
-
"paris": "Europe/Paris",
|
68 |
-
"rome": "Europe/Rome",
|
69 |
-
"madrid": "Europe/Madrid",
|
70 |
-
"berlin": "Europe/Berlin",
|
71 |
-
"amsterdam": "Europe/Amsterdam",
|
72 |
-
"athens": "Europe/Athens",
|
73 |
-
"istanbul": "Europe/Istanbul",
|
74 |
-
"dubai": "Asia/Dubai",
|
75 |
-
"new delhi": "Asia/Kolkata",
|
76 |
-
"mumbai": "Asia/Kolkata",
|
77 |
-
"bangkok": "Asia/Bangkok",
|
78 |
-
"singapore": "Asia/Singapore",
|
79 |
-
"tokyo": "Asia/Tokyo",
|
80 |
-
"seoul": "Asia/Seoul",
|
81 |
-
"beijing": "Asia/Shanghai",
|
82 |
-
"shanghai": "Asia/Shanghai",
|
83 |
-
"hong kong": "Asia/Hong_Kong",
|
84 |
-
"sydney": "Australia/Sydney",
|
85 |
-
"melbourne": "Australia/Melbourne",
|
86 |
-
"auckland": "Pacific/Auckland",
|
87 |
-
"fiji": "Pacific/Fiji",
|
88 |
-
"honolulu": "Pacific/Honolulu",
|
89 |
-
"anchorage": "America/Anchorage",
|
90 |
-
"los angeles": "America/Los_Angeles",
|
91 |
-
"san francisco": "America/Los_Angeles",
|
92 |
-
"las vegas": "America/Los_Angeles",
|
93 |
-
"denver": "America/Denver",
|
94 |
-
"chicago": "America/Chicago",
|
95 |
-
"houston": "America/Chicago",
|
96 |
-
"new york": "America/New_York",
|
97 |
-
"miami": "America/New_York",
|
98 |
-
"toronto": "America/Toronto",
|
99 |
-
"mexico city": "America/Mexico_City",
|
100 |
-
"rio de janeiro": "America/Sao_Paulo",
|
101 |
-
"sao paulo": "America/Sao_Paulo",
|
102 |
-
"buenos aires": "America/Argentina/Buenos_Aires",
|
103 |
-
"cairo": "Africa/Cairo",
|
104 |
-
"cape town": "Africa/Johannesburg",
|
105 |
-
"johannesburg": "Africa/Johannesburg",
|
106 |
-
"nairobi": "Africa/Nairobi"
|
107 |
-
}
|
108 |
-
|
109 |
-
try:
|
110 |
-
# Normalize the destination name
|
111 |
-
normalized_dest = destination.lower().strip()
|
112 |
-
|
113 |
-
# Find the closest matching timezone
|
114 |
-
timezone = None
|
115 |
-
for city, tz in destination_timezones.items():
|
116 |
-
if city in normalized_dest or normalized_dest in city:
|
117 |
-
timezone = tz
|
118 |
-
break
|
119 |
-
|
120 |
-
if not timezone:
|
121 |
-
return f"I don't have timezone information for {destination}. Please try a major city nearby."
|
122 |
-
|
123 |
-
# Get current time in that timezone
|
124 |
-
tz = pytz.timezone(timezone)
|
125 |
-
local_time = datetime.datetime.now(tz)
|
126 |
-
|
127 |
-
# Format the result
|
128 |
-
formatted_time = local_time.strftime("%I:%M %p on %A, %B %d, %Y")
|
129 |
-
time_diff = local_time.utcoffset().total_seconds() / 3600
|
130 |
-
sign = "+" if time_diff >= 0 else ""
|
131 |
-
|
132 |
-
return f"The current local time in {destination} is {formatted_time} (UTC{sign}{int(time_diff)})"
|
133 |
-
|
134 |
-
except Exception as e:
|
135 |
-
return f"Error getting local time for {destination}: {str(e)}"
|
136 |
-
|
137 |
-
# ==================== NEW TRAVEL-SPECIFIC TOOLS ====================
|
138 |
-
|
139 |
-
@tool
|
140 |
-
def get_weather_forecast(destination: str, days: int = 3) -> str:
|
141 |
-
"""Get the weather forecast for a travel destination.
|
142 |
-
|
143 |
-
Args:
|
144 |
-
destination: City or location name
|
145 |
-
days: Number of days to forecast (default: 3)
|
146 |
-
|
147 |
-
Returns:
|
148 |
-
Weather forecast information for trip planning
|
149 |
-
"""
|
150 |
-
try:
|
151 |
-
# In a production environment, you would use a real API key
|
152 |
-
API_KEY = os.environ.get("WEATHER_API_KEY", "demo_key")
|
153 |
-
|
154 |
-
# For demo purposes, we'll generate simulated weather data
|
155 |
-
# In a real implementation, you would call an actual weather API
|
156 |
-
weather_conditions = ["Sunny", "Partly Cloudy", "Cloudy", "Light Rain", "Heavy Rain", "Thunderstorms", "Windy", "Foggy", "Snow", "Clear"]
|
157 |
-
|
158 |
-
# Create a deterministic but seemingly random forecast based on destination name
|
159 |
-
seed = sum(ord(c) for c in destination)
|
160 |
-
random.seed(seed)
|
161 |
-
|
162 |
-
# Generate forecast data
|
163 |
-
forecast_text = f"🌦️ Weather forecast for {destination}:\n\n"
|
164 |
-
|
165 |
-
today = datetime.datetime.now()
|
166 |
-
for i in range(days):
|
167 |
-
day = today + datetime.timedelta(days=i)
|
168 |
-
day_name = day.strftime("%A")
|
169 |
-
date = day.strftime("%b %d")
|
170 |
-
|
171 |
-
# "Random" but deterministic weather for the demo
|
172 |
-
condition = weather_conditions[random.randint(0, len(weather_conditions)-1)]
|
173 |
-
temp_high = random.randint(15, 35) # Celsius
|
174 |
-
temp_low = temp_high - random.randint(5, 15)
|
175 |
-
precipitation = random.randint(0, 100) if "Rain" in condition or "Snow" in condition or "Thunder" in condition else 0
|
176 |
-
|
177 |
-
forecast_text += f"• {day_name}, {date}: {condition}, {temp_low}°C to {temp_high}°C"
|
178 |
-
if precipitation > 0:
|
179 |
-
forecast_text += f", {precipitation}% chance of precipitation"
|
180 |
-
forecast_text += "\n"
|
181 |
-
|
182 |
-
# Add packing recommendations based on conditions
|
183 |
-
coldest = min([forecast_text.count("Snow"), forecast_text.count("0°C")])
|
184 |
-
rainiest = forecast_text.count("Rain") + forecast_text.count("Thunder")
|
185 |
-
|
186 |
-
forecast_text += "\n🧳 Packing tips: "
|
187 |
-
if coldest > 0:
|
188 |
-
forecast_text += "Bring warm layers and a heavy jacket. "
|
189 |
-
elif "5°C" in forecast_text or "6°C" in forecast_text or "7°C" in forecast_text:
|
190 |
-
forecast_text += "Pack a warm jacket and layers. "
|
191 |
-
|
192 |
-
if rainiest > 0:
|
193 |
-
forecast_text += "Don't forget an umbrella and waterproof footwear. "
|
194 |
-
|
195 |
-
if "Sunny" in forecast_text and "30°C" in forecast_text:
|
196 |
-
forecast_text += "Bring sunscreen, sunglasses, and light clothing. "
|
197 |
-
|
198 |
-
return forecast_text
|
199 |
-
|
200 |
-
except Exception as e:
|
201 |
-
return f"Error retrieving weather data for {destination}: {str(e)}"
|
202 |
-
|
203 |
-
|
204 |
-
@tool
|
205 |
-
def convert_currency(amount: float, from_currency: str, to_currency: str) -> str:
|
206 |
-
"""Convert an amount between currencies for travel budgeting.
|
207 |
-
|
208 |
-
Args:
|
209 |
-
amount: The amount to convert
|
210 |
-
from_currency: Source currency code (e.g., USD, EUR)
|
211 |
-
to_currency: Target currency code (e.g., JPY, GBP)
|
212 |
-
|
213 |
-
Returns:
|
214 |
-
Converted amount and exchange rate information
|
215 |
-
"""
|
216 |
-
try:
|
217 |
-
# In a production environment, you would use a real API key
|
218 |
-
# For demo purposes, we'll use fixed exchange rates
|
219 |
-
# In a real implementation, you would call an actual currency API
|
220 |
-
|
221 |
-
# Common exchange rates (as of early 2025, for demo purposes)
|
222 |
-
exchange_rates = {
|
223 |
-
"USD": {"EUR": 0.92, "GBP": 0.79, "JPY": 149.50, "CAD": 1.35, "AUD": 1.52, "CNY": 7.20, "INR": 83.20, "MXN": 17.05},
|
224 |
-
"EUR": {"USD": 1.09, "GBP": 0.86, "JPY": 163.00, "CAD": 1.47, "AUD": 1.66, "CNY": 7.85, "INR": 90.70, "MXN": 18.60},
|
225 |
-
"GBP": {"USD": 1.27, "EUR": 1.16, "JPY": 189.30, "CAD": 1.71, "AUD": 1.92, "CNY": 9.10, "INR": 105.30, "MXN": 21.60},
|
226 |
-
"JPY": {"USD": 0.0067, "EUR": 0.0061, "GBP": 0.0053, "CAD": 0.0090, "AUD": 0.0102, "CNY": 0.0482, "INR": 0.5565, "MXN": 0.1141},
|
227 |
-
"CAD": {"USD": 0.74, "EUR": 0.68, "GBP": 0.58, "JPY": 110.70, "AUD": 1.13, "CNY": 5.33, "INR": 61.60, "MXN": 12.60},
|
228 |
-
"AUD": {"USD": 0.66, "EUR": 0.60, "GBP": 0.52, "JPY": 98.40, "CAD": 0.89, "CNY": 4.73, "INR": 54.70, "MXN": 11.20},
|
229 |
-
"CNY": {"USD": 0.14, "EUR": 0.13, "GBP": 0.11, "JPY": 20.80, "CAD": 0.19, "AUD": 0.21, "INR": 11.60, "MXN": 2.37},
|
230 |
-
"INR": {"USD": 0.012, "EUR": 0.011, "GBP": 0.0095, "JPY": 1.80, "CAD": 0.016, "AUD": 0.018, "CNY": 0.086, "MXN": 0.205},
|
231 |
-
"MXN": {"USD": 0.059, "EUR": 0.054, "GBP": 0.046, "JPY": 8.77, "CAD": 0.079, "AUD": 0.089, "CNY": 0.422, "INR": 4.88}
|
232 |
-
}
|
233 |
-
|
234 |
-
# Normalize currency codes
|
235 |
-
from_currency = from_currency.upper().strip()
|
236 |
-
to_currency = to_currency.upper().strip()
|
237 |
-
|
238 |
-
# Validate currencies
|
239 |
-
if from_currency not in exchange_rates:
|
240 |
-
return f"Sorry, I don't have exchange rate data for {from_currency}."
|
241 |
-
|
242 |
-
if to_currency not in exchange_rates[from_currency] and to_currency != from_currency:
|
243 |
-
return f"Sorry, I don't have exchange rate data from {from_currency} to {to_currency}."
|
244 |
-
|
245 |
-
# If same currency, return original amount
|
246 |
-
if from_currency == to_currency:
|
247 |
-
return f"{amount} {from_currency} = {amount} {to_currency}"
|
248 |
-
|
249 |
-
# Get exchange rate and calculate conversion
|
250 |
-
rate = exchange_rates[from_currency][to_currency]
|
251 |
-
converted_amount = amount * rate
|
252 |
-
|
253 |
-
# Format the result
|
254 |
-
return f"💱 {amount:,.2f} {from_currency} = {converted_amount:,.2f} {to_currency}\n\nExchange rate: 1 {from_currency} = {rate} {to_currency}\n\n(Note: Actual rates may vary. For planning purposes only.)"
|
255 |
-
|
256 |
-
except Exception as e:
|
257 |
-
return f"Error converting currency: {str(e)}"
|
258 |
-
|
259 |
-
|
260 |
-
@tool
|
261 |
-
def translate_phrase(text: str, language: str) -> str:
|
262 |
-
"""Translate common travel phrases to a local language.
|
263 |
-
|
264 |
-
Args:
|
265 |
-
text: Text to translate (e.g., "Hello", "Thank you", "Where is the bathroom?")
|
266 |
-
language: Target language (e.g., 'Spanish', 'Japanese', 'French')
|
267 |
-
|
268 |
-
Returns:
|
269 |
-
Translated text with pronunciation guide
|
270 |
-
"""
|
271 |
-
try:
|
272 |
-
# Common travel phrases in various languages
|
273 |
-
# In a production environment, you would use a real translation API
|
274 |
-
language = language.lower().strip()
|
275 |
-
text_lower = text.lower().strip()
|
276 |
-
|
277 |
-
phrase_translations = {
|
278 |
-
"hello": {
|
279 |
-
"spanish": {"text": "Hola", "pronunciation": "oh-lah"},
|
280 |
-
"french": {"text": "Bonjour", "pronunciation": "bohn-zhoor"},
|
281 |
-
"italian": {"text": "Ciao", "pronunciation": "chow"},
|
282 |
-
"german": {"text": "Hallo", "pronunciation": "hah-loh"},
|
283 |
-
"japanese": {"text": "こんにちは (Konnichiwa)", "pronunciation": "kohn-nee-chee-wah"},
|
284 |
-
"mandarin": {"text": "你好 (Nǐ hǎo)", "pronunciation": "nee how"},
|
285 |
-
"arabic": {"text": "مرحبا (Marhaba)", "pronunciation": "mar-ha-ba"},
|
286 |
-
"russian": {"text": "Здравствуйте (Zdravstvuyte)", "pronunciation": "zdrah-stvooy-tye"},
|
287 |
-
"portuguese": {"text": "Olá", "pronunciation": "oh-lah"},
|
288 |
-
"thai": {"text": "สวัสดี (Sawatdee)", "pronunciation": "sa-wat-dee"}
|
289 |
-
},
|
290 |
-
"thank you": {
|
291 |
-
"spanish": {"text": "Gracias", "pronunciation": "grah-see-ahs"},
|
292 |
-
"french": {"text": "Merci", "pronunciation": "mair-see"},
|
293 |
-
"italian": {"text": "Grazie", "pronunciation": "graht-see-eh"},
|
294 |
-
"german": {"text": "Danke", "pronunciation": "dahn-kuh"},
|
295 |
-
"japanese": {"text": "ありがとう (Arigatou)", "pronunciation": "ah-ree-gah-toh"},
|
296 |
-
"mandarin": {"text": "谢谢 (Xièxiè)", "pronunciation": "shyeh-shyeh"},
|
297 |
-
"arabic": {"text": "شكرا (Shukran)", "pronunciation": "shoo-kran"},
|
298 |
-
"russian": {"text": "Спасибо (Spasibo)", "pronunciation": "spah-see-boh"},
|
299 |
-
"portuguese": {"text": "Obrigado/a", "pronunciation": "oh-bree-gah-doo/dah"},
|
300 |
-
"thai": {"text": "ขอบคุณ (Khop khun)", "pronunciation": "kop-koon"}
|
301 |
-
},
|
302 |
-
"excuse me": {
|
303 |
-
"spanish": {"text": "Disculpe", "pronunciation": "dees-kool-peh"},
|
304 |
-
"french": {"text": "Excusez-moi", "pronunciation": "ex-koo-zay mwah"},
|
305 |
-
"italian": {"text": "Scusi", "pronunciation": "skoo-zee"},
|
306 |
-
"german": {"text": "Entschuldigung", "pronunciation": "ent-shool-di-goong"},
|
307 |
-
"japanese": {"text": "すみません (Sumimasen)", "pronunciation": "soo-mee-mah-sen"},
|
308 |
-
"mandarin": {"text": "对不起 (Duìbùqǐ)", "pronunciation": "dway-boo-chee"},
|
309 |
-
"arabic": {"text": "عفوا (Afwan)", "pronunciation": "af-wan"},
|
310 |
-
"russian": {"text": "Извините (Izvinite)", "pronunciation": "eez-vee-nee-tye"},
|
311 |
-
"portuguese": {"text": "Com licença", "pronunciation": "com lee-sen-sah"},
|
312 |
-
"thai": {"text": "ขอโทษ (Kho thot)", "pronunciation": "kor-toht"}
|
313 |
-
},
|
314 |
-
"where is the bathroom": {
|
315 |
-
"spanish": {"text": "¿Dónde está el baño?", "pronunciation": "don-deh es-tah el ban-yo"},
|
316 |
-
"french": {"text": "Où sont les toilettes?", "pronunciation": "oo son lay twa-let"},
|
317 |
-
"italian": {"text": "Dov'è il bagno?", "pronunciation": "doh-veh eel ban-yo"},
|
318 |
-
"german": {"text": "Wo ist die Toilette?", "pronunciation": "vo ist dee twa-let-te"},
|
319 |
-
"japanese": {"text": "トイレはどこですか (Toire wa doko desu ka)", "pronunciation": "toy-reh wah doh-koh des-kah"},
|
320 |
-
"mandarin": {"text": "厕所在哪里 (Cèsuǒ zài nǎlǐ)", "pronunciation": "tsuh-swor dzeye nah-lee"},
|
321 |
-
"arabic": {"text": "أين الحمام (Ayna al-hammam)", "pronunciation": "eye-nah al-ham-mam"},
|
322 |
-
"russian": {"text": "Где туалет (Gde tualet)", "pronunciation": "g-dyeh too-ah-lyet"},
|
323 |
-
"portuguese": {"text": "Onde fica o banheiro?", "pronunciation": "on-jee fee-ka oo ban-yay-roo"},
|
324 |
-
"thai": {"text": "ห้องน้ำอยู่ที่ไหน (Hong nam yu tee nai)", "pronunciation": "hong nam yoo tee nai"}
|
325 |
-
},
|
326 |
-
"how much": {
|
327 |
-
"spanish": {"text": "¿Cuánto cuesta?", "pronunciation": "kwan-toh kwes-tah"},
|
328 |
-
"french": {"text": "Combien ça coûte?", "pronunciation": "kom-bee-en sa koot"},
|
329 |
-
"italian": {"text": "Quanto costa?", "pronunciation": "kwan-toh kos-tah"},
|
330 |
-
"german": {"text": "Wie viel kostet das?", "pronunciation": "vee feel kos-tet das"},
|
331 |
-
"japanese": {"text": "いくらですか (Ikura desu ka)", "pronunciation": "ee-koo-rah des-kah"},
|
332 |
-
"mandarin": {"text": "多少钱 (Duōshǎo qián)", "pronunciation": "dwor-shaow chyen"},
|
333 |
-
"arabic": {"text": "كم الثمن (Kam althaman)", "pronunciation": "kam al-tha-man"},
|
334 |
-
"russian": {"text": "Сколько это стоит (Skol'ko eto stoit)", "pronunciation": "skol-ka eh-ta stoh-eet"},
|
335 |
-
"portuguese": {"text": "Quanto custa?", "pronunciation": "kwan-too koos-tah"},
|
336 |
-
"thai": {"text": "ราคาเท่าไหร่ (Raka tao rai)", "pronunciation": "ra-ka tao-rai"}
|
337 |
-
}
|
338 |
-
}
|
339 |
-
|
340 |
-
# Find the phrase key that most closely matches the input text
|
341 |
-
matched_phrase = None
|
342 |
-
for phrase in phrase_translations:
|
343 |
-
if phrase in text_lower or text_lower in phrase:
|
344 |
-
matched_phrase = phrase
|
345 |
-
break
|
346 |
-
|
347 |
-
if not matched_phrase:
|
348 |
-
return f"I don't have a translation for '{text}'. Try common travel phrases like 'hello', 'thank you', 'excuse me', etc."
|
349 |
-
|
350 |
-
# Find the language that most closely matches the input language
|
351 |
-
matched_language = None
|
352 |
-
for lang in phrase_translations[matched_phrase]:
|
353 |
-
if lang in language or language in lang:
|
354 |
-
matched_language = lang
|
355 |
-
break
|
356 |
-
|
357 |
-
if not matched_language:
|
358 |
-
return f"I don't have translations for {language}. Try languages like Spanish, French, Italian, German, Japanese, etc."
|
359 |
-
|
360 |
-
# Get the translation
|
361 |
-
translation = phrase_translations[matched_phrase][matched_language]
|
362 |
-
|
363 |
-
return f"🗣️ '{text}' in {matched_language.capitalize()}:\n\n{translation['text']}\n\nPronunciation: {translation['pronunciation']}"
|
364 |
-
|
365 |
-
except Exception as e:
|
366 |
-
return f"Error translating text: {str(e)}"
|
367 |
-
|
368 |
-
|
369 |
-
@tool
|
370 |
-
def get_visa_requirements(nationality: str, destination: str) -> str:
|
371 |
-
"""Check visa requirements for traveling to a destination.
|
372 |
-
|
373 |
-
Args:
|
374 |
-
nationality: Traveler's passport country (e.g., 'US', 'UK', 'Canada')
|
375 |
-
destination: Country to visit (e.g., 'Japan', 'France', 'Brazil')
|
376 |
-
|
377 |
-
Returns:
|
378 |
-
Visa requirement information
|
379 |
-
"""
|
380 |
-
try:
|
381 |
-
# Normalize inputs
|
382 |
-
nationality = nationality.lower().strip()
|
383 |
-
destination = destination.lower().strip()
|
384 |
-
|
385 |
-
# Map of common country names to their normalized forms
|
386 |
-
country_mapping = {
|
387 |
-
"us": "united states", "usa": "united states", "united states of america": "united states",
|
388 |
-
"uk": "united kingdom", "britain": "united kingdom", "great britain": "united kingdom",
|
389 |
-
"uae": "united arab emirates",
|
390 |
-
# Add more mappings as needed
|
391 |
-
}
|
392 |
-
|
393 |
-
# Apply mappings if available
|
394 |
-
nationality = country_mapping.get(nationality, nationality)
|
395 |
-
destination = country_mapping.get(destination, destination)
|
396 |
-
|
397 |
-
# Skip if same country (generally no visa needed for citizens)
|
398 |
-
if nationality == destination:
|
399 |
-
return f"As a citizen of {nationality.title()}, you generally don't need a visa to visit your own country."
|
400 |
-
|
401 |
-
# Sample visa requirement data
|
402 |
-
# In a production environment, this would be a comprehensive database or API call
|
403 |
-
visa_data = {
|
404 |
-
"united states": {
|
405 |
-
"european union": "No visa required for stays up to 90 days",
|
406 |
-
"united kingdom": "No visa required for stays up to 6 months",
|
407 |
-
"japan": "No visa required for stays up to 90 days",
|
408 |
-
"australia": "Electronic Travel Authority (ETA) required",
|
409 |
-
"china": "Visa required, must apply in advance",
|
410 |
-
"india": "e-Visa available, apply online before travel",
|
411 |
-
"brazil": "No visa required for stays up to 90 days",
|
412 |
-
"mexico": "No visa required for stays up to 180 days",
|
413 |
-
"south africa": "No visa required for stays up to 90 days",
|
414 |
-
"thailand": "No visa required for stays up to 30 days"
|
415 |
-
},
|
416 |
-
"united kingdom": {
|
417 |
-
"european union": "No visa required for stays up to 90 days",
|
418 |
-
"united states": "ESTA required for entry",
|
419 |
-
"japan": "No visa required for stays up to 90 days",
|
420 |
-
"australia": "eVisitor visa required",
|
421 |
-
"china": "Visa required, must apply in advance",
|
422 |
-
"india": "e-Visa available, apply online before travel",
|
423 |
-
"brazil": "No visa required for stays up to 90 days",
|
424 |
-
"mexico": "No visa required for stays up to 180 days",
|
425 |
-
"south africa": "No visa required for stays up to 90 days",
|
426 |
-
"thailand": "No visa required for stays up to 30 days"
|
427 |
-
},
|
428 |
-
# Add more countries as needed
|
429 |
-
}
|
430 |
-
|
431 |
-
# Check if we have data for this nationality
|
432 |
-
if nationality not in visa_data:
|
433 |
-
return f"I don't have specific visa information for citizens of {nationality.title()}. Please check with the embassy of {destination.title()} for accurate visa requirements."
|
434 |
-
|
435 |
-
# Check if we have data for this destination
|
436 |
-
if destination not in visa_data[nationality]:
|
437 |
-
return f"I don't have specific visa information for {nationality.title()} citizens traveling to {destination.title()}. Please check with the embassy of {destination.title()} for accurate visa requirements."
|
438 |
-
|
439 |
-
# Get the visa requirements
|
440 |
-
requirements = visa_data[nationality][destination]
|
441 |
-
|
442 |
-
return f"🛂 Visa requirements for {nationality.title()} citizens traveling to {destination.title()}:\n\n{requirements}\n\n(Note: Visa requirements may change. Always verify with the official embassy or consulate before travel.)"
|
443 |
-
|
444 |
-
except Exception as e:
|
445 |
-
return f"Error retrieving visa information: {str(e)}"
|
446 |
-
|
447 |
# ==================== AGENT SETUP ====================
|
448 |
|
|
|
449 |
final_answer = FinalAnswerTool()
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
|
454 |
-
|
455 |
-
|
456 |
-
|
457 |
-
|
458 |
-
|
|
|
459 |
model = HfApiModel(
|
460 |
max_tokens=2096,
|
461 |
-
temperature=0.
|
462 |
model_id='https://pflgm2locj2t89co.us-east-1.aws.endpoints.huggingface.cloud', # Use the AWS endpoint
|
463 |
custom_role_conversions=None,
|
464 |
)
|
465 |
|
466 |
-
|
467 |
# Load prompts
|
468 |
-
|
469 |
-
|
|
|
|
|
|
|
|
|
|
|
470 |
|
471 |
# Add travel companion specific instructions to the prompt templates
|
472 |
travel_agent_prompt = """
|
473 |
-
You are
|
474 |
Your goal is to provide helpful, accurate information about destinations, local customs, and practical travel advice.
|
475 |
|
476 |
You have access to these capabilities:
|
477 |
-
1.
|
478 |
-
2.
|
479 |
-
3. Provide
|
480 |
-
4.
|
481 |
-
5.
|
482 |
-
6.
|
|
|
|
|
483 |
|
484 |
When users ask about a destination, try to provide comprehensive information by combining multiple tools.
|
485 |
-
For example, if someone asks about Tokyo, consider providing the local time, weather, and a
|
486 |
|
487 |
Always be enthusiastic about travel while remaining practical and informative.
|
488 |
Suggest off-the-beaten-path experiences when appropriate, but prioritize the specific information requested.
|
@@ -499,22 +82,40 @@ agent = CodeAgent(
|
|
499 |
model=model,
|
500 |
tools=[
|
501 |
final_answer,
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
|
|
|
|
508 |
],
|
509 |
max_steps=8, # Increased to allow for more tool usage in a single query
|
510 |
verbosity_level=1,
|
511 |
grammar=None,
|
512 |
planning_interval=None,
|
513 |
-
name="
|
514 |
description="Your AI travel companion",
|
515 |
-
prompt_templates=prompt_templates
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
516 |
)
|
517 |
|
518 |
# Launch the UI
|
519 |
-
|
520 |
-
|
|
|
|
|
|
1 |
+
# Journi - Your AI Travel Companion
|
2 |
# This agent helps travelers with destination information, local time, weather forecasts,
|
3 |
+
# currency conversion, language translation, and destination previews.
|
4 |
|
5 |
+
from smolagents import CodeAgent, HfApiModel, load_tool
|
6 |
import datetime
|
|
|
|
|
7 |
import yaml
|
|
|
|
|
8 |
import os
|
9 |
+
|
10 |
+
# Import all the tool classes from their respective files
|
11 |
from tools.final_answer import FinalAnswerTool
|
12 |
+
from tools.web_search import DuckDuckGoSearchTool
|
13 |
+
from tools.visit_webpage import VisitWebpageTool
|
14 |
+
from tools.generate_destination_preview import GenerateDestinationPreviewTool
|
15 |
+
from tools.get_local_time import GetLocalTimeTool
|
16 |
+
from tools.get_weather_forecast import GetWeatherForecastTool
|
17 |
+
from tools.convert_currency import ConvertCurrencyTool
|
18 |
+
from tools.translate_phrase import TranslatePhraseTool
|
19 |
+
from tools.get_visa_requirements import GetVisaRequirementsTool
|
20 |
from Gradio_UI import GradioUI
|
21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
# ==================== AGENT SETUP ====================
|
23 |
|
24 |
+
# Initialize all tool instances
|
25 |
final_answer = FinalAnswerTool()
|
26 |
+
web_search = DuckDuckGoSearchTool(max_results=5) # Limit results for better readability
|
27 |
+
visit_webpage = VisitWebpageTool()
|
28 |
+
generate_destination_preview = GenerateDestinationPreviewTool()
|
29 |
+
get_local_time = GetLocalTimeTool()
|
30 |
+
get_weather_forecast = GetWeatherForecastTool()
|
31 |
+
convert_currency = ConvertCurrencyTool()
|
32 |
+
translate_phrase = TranslatePhraseTool()
|
33 |
+
get_visa_requirements = GetVisaRequirementsTool()
|
34 |
+
|
35 |
+
# Model initialization
|
36 |
model = HfApiModel(
|
37 |
max_tokens=2096,
|
38 |
+
temperature=0.5, # Balanced between creativity and accuracy
|
39 |
model_id='https://pflgm2locj2t89co.us-east-1.aws.endpoints.huggingface.cloud', # Use the AWS endpoint
|
40 |
custom_role_conversions=None,
|
41 |
)
|
42 |
|
|
|
43 |
# Load prompts
|
44 |
+
try:
|
45 |
+
with open("prompts.yaml", 'r') as stream:
|
46 |
+
prompt_templates = yaml.safe_load(stream)
|
47 |
+
except FileNotFoundError:
|
48 |
+
# Create a basic template if file doesn't exist
|
49 |
+
prompt_templates = {}
|
50 |
+
print("Warning: prompts.yaml not found. Using default prompt templates.")
|
51 |
|
52 |
# Add travel companion specific instructions to the prompt templates
|
53 |
travel_agent_prompt = """
|
54 |
+
You are Journi, an AI travel companion designed to help travelers plan and navigate their journeys.
|
55 |
Your goal is to provide helpful, accurate information about destinations, local customs, and practical travel advice.
|
56 |
|
57 |
You have access to these capabilities:
|
58 |
+
1. Search for travel information online
|
59 |
+
2. Visit webpages to get detailed information
|
60 |
+
3. Provide vivid descriptions of travel destinations
|
61 |
+
4. Check local time at travel destinations
|
62 |
+
5. Provide weather forecasts for trip planning
|
63 |
+
6. Convert currencies for travel budgeting
|
64 |
+
7. Translate common travel phrases
|
65 |
+
8. Check visa requirements
|
66 |
|
67 |
When users ask about a destination, try to provide comprehensive information by combining multiple tools.
|
68 |
+
For example, if someone asks about Tokyo, consider providing the local time, weather, and a descriptive preview.
|
69 |
|
70 |
Always be enthusiastic about travel while remaining practical and informative.
|
71 |
Suggest off-the-beaten-path experiences when appropriate, but prioritize the specific information requested.
|
|
|
82 |
model=model,
|
83 |
tools=[
|
84 |
final_answer,
|
85 |
+
web_search,
|
86 |
+
visit_webpage,
|
87 |
+
generate_destination_preview,
|
88 |
+
get_local_time,
|
89 |
+
get_weather_forecast,
|
90 |
+
convert_currency,
|
91 |
+
translate_phrase,
|
92 |
+
get_visa_requirements,
|
93 |
],
|
94 |
max_steps=8, # Increased to allow for more tool usage in a single query
|
95 |
verbosity_level=1,
|
96 |
grammar=None,
|
97 |
planning_interval=None,
|
98 |
+
name="Journi",
|
99 |
description="Your AI travel companion",
|
100 |
+
prompt_templates=prompt_templates,
|
101 |
+
authorized_imports=[
|
102 |
+
"unicodedata",
|
103 |
+
"stat",
|
104 |
+
"datetime",
|
105 |
+
"random",
|
106 |
+
"pandas",
|
107 |
+
"itertools",
|
108 |
+
"math",
|
109 |
+
"statistics",
|
110 |
+
"queue",
|
111 |
+
"time",
|
112 |
+
"collections",
|
113 |
+
"re"
|
114 |
+
]
|
115 |
)
|
116 |
|
117 |
# Launch the UI
|
118 |
+
if __name__ == "__main__":
|
119 |
+
print("✈️ Launching Journi - Your AI Travel Companion")
|
120 |
+
print("Ask me about any destination, local time, weather, currency conversion, or travel phrases!")
|
121 |
+
GradioUI(agent).launch()
|