Hugo Bui commited on
Commit
7b51008
·
unverified ·
1 Parent(s): b50765b

translate tools to english

Browse files
tools/__pycache__/country_info_tool.cpython-310.pyc ADDED
Binary file (23.7 kB). View file
 
tools/country_info_tool.py CHANGED
@@ -10,10 +10,10 @@ import anthropic
10
 
11
  class CountryInfoTool(Tool):
12
  name = "country_info"
13
- description = "Récupère des informations contextuelles importantes sur un pays en temps réel : sécurité, événements actuels, fêtes nationales, climat politique, conseils de voyage."
14
  inputs = {
15
- 'country': {'type': 'string', 'description': 'Le nom du pays en français ou en anglais (ex: "France", "États-Unis", "Japon")'},
16
- 'info_type': {'type': 'string', 'description': 'Type d\'information recherchée: "all", "security", "events", "holidays", "travel", "politics"', 'nullable': True}
17
  }
18
  output_type = "string"
19
 
@@ -22,7 +22,7 @@ class CountryInfoTool(Tool):
22
  load_dotenv()
23
 
24
  # Initialiser le client Claude (Anthropic)
25
- self.claude_client = anthropic.Anthropic(api_key=os.getenv('ANTHROPIC_API_KEY'))
26
 
27
  # Mapping étendu des pays français vers anglais pour les APIs
28
  self.country_mapping = {
@@ -104,7 +104,7 @@ class CountryInfoTool(Tool):
104
  country_normalized = self._normalize_country_name(country)
105
 
106
  if not country_normalized:
107
- return f"❌ Pays non reconnu: '{country}'. Essayez avec le nom complet (ex: 'France', 'États-Unis', 'Royaume-Uni')"
108
 
109
  # Collecter les informations selon le type demandé
110
  info_sections = []
@@ -135,11 +135,11 @@ class CountryInfoTool(Tool):
135
  info_sections.append(politics_info)
136
 
137
  if not info_sections:
138
- return f"❌ Aucune information disponible pour {country_normalized} actuellement."
139
 
140
  # Assembler le rapport final
141
- result = f"🌍 **Informations contextuelles pour {country_normalized}**\n"
142
- result += f"*Mise à jour: {datetime.now().strftime('%d/%m/%Y %H:%M')}*\n\n"
143
  result += "\n\n".join(info_sections)
144
 
145
  # Ajouter une recommandation finale intelligente si Claude est disponible et qu'on demande toutes les infos
@@ -151,7 +151,7 @@ class CountryInfoTool(Tool):
151
  return result
152
 
153
  except Exception as e:
154
- return f"❌ Erreur lors de la récupération des informations: {str(e)}"
155
 
156
  def _normalize_country_name(self, country: str) -> Optional[str]:
157
  """Normalise le nom du pays"""
@@ -265,15 +265,15 @@ class CountryInfoTool(Tool):
265
  # Analyser les résultats pour déterminer le niveau de sécurité
266
  security_level, description, recommendation = self._analyze_security_data(country, unique_news, risk_level)
267
 
268
- result = f"🛡️ **Sécurité et Conseils de Voyage**\n"
269
- result += f"{security_level} **Niveau déterminé par analyse en temps réel**\n"
270
  result += f"📋 {description}\n"
271
- result += f"🎯 **Recommandation: {recommendation}**"
272
 
273
  return result
274
 
275
  except Exception as e:
276
- return f"🛡️ **Sécurité**: Erreur lors de la récupération - {str(e)}"
277
 
278
  def _check_known_risk_countries(self, country: str) -> str:
279
  """Vérifie si le pays est dans la liste des pays à risque connus"""
@@ -382,8 +382,8 @@ class CountryInfoTool(Tool):
382
  try:
383
  if not self.claude_client:
384
  return ("⚪",
385
- "Claude non disponible",
386
- "❓ Clé API Anthropic requise pour l'analyse de sécurité")
387
 
388
  # Préparer le contenu des actualités pour l'analyse
389
  news_content = ""
@@ -397,16 +397,16 @@ class CountryInfoTool(Tool):
397
  if not news_content.strip():
398
  if risk_level == "HIGH_RISK":
399
  return ("🔴",
400
- f"Pays à très haut risque - conflit actif ou guerre",
401
- "🚫 CHANGEZ DE DESTINATION - Zone de conflit active")
402
  elif risk_level == "MODERATE_RISK":
403
  return ("🟡",
404
- f"Pays à risque modéré - instabilité politique",
405
- "⚠️ Voyage possible avec précautions renforcées")
406
  else:
407
  return ("🟢",
408
- f"Aucune actualité de sécurité récente trouvée",
409
- "✅ Destination considérée comme sûre")
410
 
411
  # Utiliser Claude pour analyser
412
  analysis = self._llm_security_analysis(country, news_content, risk_level)
@@ -415,11 +415,11 @@ class CountryInfoTool(Tool):
415
  return analysis
416
  else:
417
  return ("⚪",
418
- "Erreur d'analyse Claude",
419
- "❓ Impossible d'analyser la sécurité actuellement")
420
 
421
  except Exception:
422
- return ("⚪", "Analyse impossible", "❓ Consultez les sources officielles")
423
 
424
  def _llm_security_analysis(self, country: str, news_content: str, risk_level: str = "UNKNOWN") -> Optional[tuple]:
425
  """Utilise Claude pour analyser la sécurité du pays"""
@@ -427,38 +427,38 @@ class CountryInfoTool(Tool):
427
  if not self.claude_client:
428
  return None
429
 
430
- prompt = f"""Analysez les actualités récentes suivantes concernant {country} et déterminez le niveau de sécurité pour un voyageur :
431
 
432
- NIVEAU DE RISQUE CONNU : {risk_level}
433
- - HIGH_RISK = Pays en guerre active ou conflit majeur
434
- - MODERATE_RISK = Pays avec instabilité politique significative
435
- - TENSION = Pays avec tensions géopolitiques
436
- - UNKNOWN = Pas de classification spéciale
437
 
438
- ACTUALITÉS RÉCENTES :
439
  {news_content}
440
 
441
- INSTRUCTIONS CRITIQUES :
442
- 1. Si NIVEAU DE RISQUE = HIGH_RISK, vous DEVEZ recommander CHANGEZ_DE_DESTINATION sauf preuve claire d'amélioration
443
- 2. Pour l'Ukraine, Palestine, Afghanistan, Syrie, Yémen : TOUJOURS ROUGE/CHANGEZ_DE_DESTINATION
444
- 3. Analysez le niveau de risque pour un touriste/voyageur civil
445
- 4. Soyez TRÈS STRICT - la sécurité des voyageurs est prioritaire
446
 
447
- Répondez UNIQUEMENT au format JSON suivant :
448
 
449
  {{
450
- "niveau": "ROUGE|JAUNE|VERT",
451
- "description": "Description courte de la situation (max 100 caractères)",
452
- "recommandation": "CHANGEZ_DE_DESTINATION|PRECAUTIONS_RENFORCEES|DESTINATION_SURE",
453
- "justification": "Explication de votre décision (max 200 caractères)"
454
  }}
455
 
456
- Critères STRICTS :
457
- - ROUGE/CHANGEZ_DE_DESTINATION : guerre active, conflit armé, terrorisme actif, coup d'état, violence généralisée, zones de combat
458
- - JAUNE/PRECAUTIONS_RENFORCEES : manifestations violentes, criminalité très élevée, instabilité politique, tensions ethniques
459
- - VERT/DESTINATION_SURE : pas de risques majeurs pour les civils
460
 
461
- PRIORITÉ ABSOLUE : Protéger les voyageurs - en cas de doute, choisissez le niveau de sécurité le plus strict."""
462
 
463
  response = self.claude_client.messages.create(
464
  model="claude-3-opus-20240229",
@@ -474,21 +474,21 @@ PRIORITÉ ABSOLUE : Protéger les voyageurs - en cas de doute, choisissez le niv
474
  # Parser la réponse JSON
475
  try:
476
  result = json.loads(result_text)
477
- niveau = result.get('niveau', 'VERT')
478
- description = result.get('description', 'Analyse effectuée')
479
- recommandation = result.get('recommandation', 'DESTINATION_SURE')
480
  justification = result.get('justification', '')
481
 
482
  # Convertir en format attendu
483
- if niveau == 'ROUGE':
484
  emoji = "🔴"
485
- advice = "🚫 CHANGEZ DE DESTINATION - " + justification
486
- elif niveau == 'JAUNE':
487
  emoji = "🟡"
488
- advice = "⚠️ Voyage possible avec précautions renforcées - " + justification
489
  else:
490
  emoji = "🟢"
491
- advice = "✅ Destination considérée comme sûre - " + justification
492
 
493
  return (emoji, description, advice)
494
 
@@ -501,24 +501,24 @@ PRIORITÉ ABSOLUE : Protéger les voyageurs - en cas de doute, choisissez le niv
501
 
502
 
503
  def _get_current_events_info(self, country: str) -> str:
504
- """Récupère les événements actuels via recherche web"""
505
  try:
506
- # Rechercher les événements récents
507
  events_keywords = f"{country} current events news today recent"
508
  events_data = self._search_current_events(events_keywords)
509
 
510
  if not events_data:
511
- return f"📅 **Événements**: Aucun événement majeur détecté pour {country}"
512
 
513
- result = f"📅 **Événements et Contexte Actuel**\n"
514
  for i, event in enumerate(events_data[:5], 1):
515
- title = event.get('title', 'Événement non spécifié')
516
  result += f"• {title}\n"
517
 
518
  return result.rstrip()
519
 
520
  except Exception:
521
- return "📅 **Événements**: Erreur lors de la récupération"
522
 
523
  def _search_current_events(self, keywords: str) -> list:
524
  """Recherche d'événements actuels"""
@@ -547,29 +547,29 @@ PRIORITÉ ABSOLUE : Protéger les voyageurs - en cas de doute, choisissez le niv
547
  return []
548
 
549
  def _get_holidays_info(self, country: str) -> str:
550
- """Récupère les fêtes nationales via API"""
551
  try:
552
  country_code = self.country_codes.get(country, '')
553
 
554
- # Si pas de code dans notre mapping, essayer de le récupérer via API
555
  if not country_code:
556
  country_code = self._get_country_code_from_api(country)
557
 
558
  if not country_code:
559
- return f"🎉 **Fêtes**: Code pays non trouvé pour {country}"
560
 
561
- # Utiliser l'API Calendarific ou similaire
562
  holidays_data = self._fetch_holidays_api(country_code)
563
 
564
  if not holidays_data:
565
- return f"🎉 **Fêtes**: Informations non disponibles pour {country}"
566
 
567
  current_month = datetime.now().month
568
  current_year = datetime.now().year
569
 
570
- result = f"🎉 **Fêtes et Événements Saisonniers**\n"
571
 
572
- # Filtrer les fêtes du mois actuel et des prochains mois
573
  upcoming_holidays = []
574
  for holiday in holidays_data:
575
  try:
@@ -580,18 +580,18 @@ PRIORITÉ ABSOLUE : Protéger les voyageurs - en cas de doute, choisissez le niv
580
  continue
581
 
582
  if upcoming_holidays:
583
- result += f"**Prochaines fêtes:**\n"
584
  for holiday in upcoming_holidays[:5]:
585
- name = holiday.get('name', 'Fête inconnue')
586
  date = holiday.get('date', '')
587
  result += f"• {name} ({date})\n"
588
  else:
589
- result += f"**Aucune fête majeure prévue dans les prochains mois**\n"
590
 
591
  return result.rstrip()
592
 
593
  except Exception:
594
- return "🎉 **Fêtes**: Erreur lors de la récupération"
595
 
596
  def _fetch_holidays_api(self, country_code: str) -> list:
597
  """Récupère les fêtes via API publique"""
@@ -610,9 +610,9 @@ PRIORITÉ ABSOLUE : Protéger les voyageurs - en cas de doute, choisissez le niv
610
  return []
611
 
612
  def _get_travel_info(self, country: str) -> str:
613
- """Récupère les informations de voyage via API REST Countries"""
614
  try:
615
- # Utiliser l'API REST Countries
616
  url = f"https://restcountries.com/v3.1/name/{country}"
617
  response = requests.get(url, timeout=10)
618
 
@@ -621,40 +621,40 @@ PRIORITÉ ABSOLUE : Protéger les voyageurs - en cas de doute, choisissez le niv
621
  if data:
622
  country_data = data[0]
623
 
624
- # Extraire les informations
625
  currencies = country_data.get('currencies', {})
626
  languages = country_data.get('languages', {})
627
- region = country_data.get('region', 'Inconnu')
628
 
629
- currency_name = list(currencies.keys())[0] if currencies else 'Inconnue'
630
- language_list = list(languages.values()) if languages else ['Inconnue']
631
 
632
- result = f"✈️ **Informations Pratiques de Voyage**\n"
633
- result += f"💰 Monnaie: {currency_name}\n"
634
- result += f"🗣️ Langues: {', '.join(language_list[:3])}\n"
635
- result += f"🌍 Région: {region}\n"
636
- result += f"📋 Vérifiez les exigences visa sur le site officiel du pays"
637
 
638
  return result
639
 
640
- return f"✈️ **Voyage**: Informations non disponibles pour {country}"
641
 
642
  except Exception:
643
- return "✈️ **Voyage**: Erreur lors de la récupération"
644
 
645
  def _get_political_info(self, country: str) -> str:
646
- """Récupère le contexte politique via recherche d'actualités"""
647
  try:
648
- # Rechercher des actualités politiques récentes
649
  political_keywords = f"{country} politics government election democracy"
650
  political_data = self._search_political_news(political_keywords)
651
 
652
  if not political_data:
653
- return f"🏛️ **Politique**: Situation stable pour {country}"
654
 
655
- result = f"🏛️ **Contexte Politique**\n"
656
 
657
- # Analyser les actualités politiques
658
  for article in political_data[:3]:
659
  title = article.get('title', '')
660
  if title:
@@ -663,7 +663,7 @@ PRIORITÉ ABSOLUE : Protéger les voyageurs - en cas de doute, choisissez le niv
663
  return result.rstrip()
664
 
665
  except Exception:
666
- return "🏛️ **Politique**: Erreur lors de la récupération"
667
 
668
  def _search_political_news(self, keywords: str) -> list:
669
  """Recherche d'actualités politiques"""
@@ -691,34 +691,34 @@ PRIORITÉ ABSOLUE : Protéger les voyageurs - en cas de doute, choisissez le niv
691
  return []
692
 
693
  def _get_llm_final_recommendation(self, country: str, full_report: str) -> Optional[str]:
694
- """Utilise Claude pour générer une recommandation finale intelligente"""
695
  try:
696
  if not self.claude_client:
697
  return None
698
 
699
- prompt = f"""Analysez ce rapport complet sur {country} et donnez une recommandation finale concise pour un voyageur français :
700
 
701
- RAPPORT COMPLET :
702
  {full_report}
703
 
704
- Votre tâche :
705
- 1. Synthétisez les informations les plus importantes
706
- 2. Donnez une recommandation claire et actionnable
707
- 3. Répondez en français, maximum 200 mots
708
- 4. Utilisez un ton professionnel mais accessible
709
- 5. Si des risques existent, soyez explicite sur les précautions
710
 
711
- Format de réponse souhaité :
712
- 🎯 **RECOMMANDATION FINALE**
713
- [Votre analyse synthétique et recommandation]
714
 
715
- Si la destination est dangereuse, utilisez clairement "CHANGEZ DE DESTINATION" dans votre réponse."""
716
 
717
  response = self.claude_client.messages.create(
718
  model="claude-3-opus-20240229",
719
  max_tokens=250,
720
  temperature=0.2,
721
- system="Vous êtes un conseiller en voyage expert. Donnez des recommandations claires et pratiques.",
722
  messages=[
723
  {"role": "user", "content": prompt}
724
  ]
 
10
 
11
  class CountryInfoTool(Tool):
12
  name = "country_info"
13
+ description = "Retrieves important contextual information about a country in real-time: security, current events, national holidays, political climate, travel advice."
14
  inputs = {
15
+ 'country': {'type': 'string', 'description': 'Country name in French or English (e.g., "France", "United States", "Japan")'},
16
+ 'info_type': {'type': 'string', 'description': 'Type of information requested: "all", "security", "events", "holidays", "travel", "politics"', 'nullable': True}
17
  }
18
  output_type = "string"
19
 
 
22
  load_dotenv()
23
 
24
  # Initialiser le client Claude (Anthropic)
25
+ self.claude_client = anthropic.Anthropic(api_key=os.getenv('ANTROPIC_KEY'))
26
 
27
  # Mapping étendu des pays français vers anglais pour les APIs
28
  self.country_mapping = {
 
104
  country_normalized = self._normalize_country_name(country)
105
 
106
  if not country_normalized:
107
+ return f"❌ Country not recognized: '{country}'. Try with the full name (e.g., 'France', 'United States', 'United Kingdom')"
108
 
109
  # Collecter les informations selon le type demandé
110
  info_sections = []
 
135
  info_sections.append(politics_info)
136
 
137
  if not info_sections:
138
+ return f"❌ No information available for {country_normalized} currently."
139
 
140
  # Assembler le rapport final
141
+ result = f"🌍 **Contextual Information for {country_normalized}**\n"
142
+ result += f"*Updated: {datetime.now().strftime('%m/%d/%Y %H:%M')}*\n\n"
143
  result += "\n\n".join(info_sections)
144
 
145
  # Ajouter une recommandation finale intelligente si Claude est disponible et qu'on demande toutes les infos
 
151
  return result
152
 
153
  except Exception as e:
154
+ return f"❌ Error retrieving information: {str(e)}"
155
 
156
  def _normalize_country_name(self, country: str) -> Optional[str]:
157
  """Normalise le nom du pays"""
 
265
  # Analyser les résultats pour déterminer le niveau de sécurité
266
  security_level, description, recommendation = self._analyze_security_data(country, unique_news, risk_level)
267
 
268
+ result = f"🛡️ **Security and Travel Advice**\n"
269
+ result += f"{security_level} **Level determined by real-time analysis**\n"
270
  result += f"📋 {description}\n"
271
+ result += f"🎯 **Recommendation: {recommendation}**"
272
 
273
  return result
274
 
275
  except Exception as e:
276
+ return f"🛡️ **Security**: Error during retrieval - {str(e)}"
277
 
278
  def _check_known_risk_countries(self, country: str) -> str:
279
  """Vérifie si le pays est dans la liste des pays à risque connus"""
 
382
  try:
383
  if not self.claude_client:
384
  return ("⚪",
385
+ "Claude not available",
386
+ "❓ Anthropic API key required for security analysis")
387
 
388
  # Préparer le contenu des actualités pour l'analyse
389
  news_content = ""
 
397
  if not news_content.strip():
398
  if risk_level == "HIGH_RISK":
399
  return ("🔴",
400
+ f"Very high risk country - active conflict or war",
401
+ "🚫 CHANGE DESTINATION - Active conflict zone")
402
  elif risk_level == "MODERATE_RISK":
403
  return ("🟡",
404
+ f"Moderate risk country - political instability",
405
+ "⚠️ Travel possible with enhanced precautions")
406
  else:
407
  return ("🟢",
408
+ f"No recent security news found",
409
+ "✅ Destination considered safe")
410
 
411
  # Utiliser Claude pour analyser
412
  analysis = self._llm_security_analysis(country, news_content, risk_level)
 
415
  return analysis
416
  else:
417
  return ("⚪",
418
+ "Claude analysis error",
419
+ "❓ Unable to analyze security currently")
420
 
421
  except Exception:
422
+ return ("⚪", "Analysis impossible", "❓ Consult official sources")
423
 
424
  def _llm_security_analysis(self, country: str, news_content: str, risk_level: str = "UNKNOWN") -> Optional[tuple]:
425
  """Utilise Claude pour analyser la sécurité du pays"""
 
427
  if not self.claude_client:
428
  return None
429
 
430
+ prompt = f"""Analyze the following recent news about {country} and determine the security level for a traveler:
431
 
432
+ KNOWN RISK LEVEL: {risk_level}
433
+ - HIGH_RISK = Country in active war or major conflict
434
+ - MODERATE_RISK = Country with significant political instability
435
+ - TENSION = Country with geopolitical tensions
436
+ - UNKNOWN = No special classification
437
 
438
+ RECENT NEWS:
439
  {news_content}
440
 
441
+ CRITICAL INSTRUCTIONS:
442
+ 1. If RISK LEVEL = HIGH_RISK, you MUST recommend CHANGE_DESTINATION unless clear evidence of improvement
443
+ 2. For Ukraine, Palestine, Afghanistan, Syria, Yemen: ALWAYS RED/CHANGE_DESTINATION
444
+ 3. Analyze risk level for a civilian tourist/traveler
445
+ 4. Be VERY STRICT - traveler safety is priority
446
 
447
+ Respond ONLY in the following JSON format:
448
 
449
  {{
450
+ "level": "RED|YELLOW|GREEN",
451
+ "description": "Short situation description (max 100 characters)",
452
+ "recommendation": "CHANGE_DESTINATION|ENHANCED_PRECAUTIONS|SAFE_DESTINATION",
453
+ "justification": "Explanation of your decision (max 200 characters)"
454
  }}
455
 
456
+ STRICT Criteria:
457
+ - RED/CHANGE_DESTINATION: active war, armed conflict, active terrorism, coup, widespread violence, combat zones
458
+ - YELLOW/ENHANCED_PRECAUTIONS: violent protests, very high crime, political instability, ethnic tensions
459
+ - GREEN/SAFE_DESTINATION: no major risks for civilians
460
 
461
+ ABSOLUTE PRIORITY: Protect travelers - when in doubt, choose the strictest security level."""
462
 
463
  response = self.claude_client.messages.create(
464
  model="claude-3-opus-20240229",
 
474
  # Parser la réponse JSON
475
  try:
476
  result = json.loads(result_text)
477
+ level = result.get('level', 'GREEN')
478
+ description = result.get('description', 'Analysis completed')
479
+ recommendation = result.get('recommendation', 'SAFE_DESTINATION')
480
  justification = result.get('justification', '')
481
 
482
  # Convertir en format attendu
483
+ if level == 'RED':
484
  emoji = "🔴"
485
+ advice = "🚫 CHANGE DESTINATION - " + justification
486
+ elif level == 'YELLOW':
487
  emoji = "🟡"
488
+ advice = "⚠️ Travel possible with enhanced precautions - " + justification
489
  else:
490
  emoji = "🟢"
491
+ advice = "✅ Destination considered safe - " + justification
492
 
493
  return (emoji, description, advice)
494
 
 
501
 
502
 
503
  def _get_current_events_info(self, country: str) -> str:
504
+ """Retrieves current events via web search"""
505
  try:
506
+ # Search for recent events
507
  events_keywords = f"{country} current events news today recent"
508
  events_data = self._search_current_events(events_keywords)
509
 
510
  if not events_data:
511
+ return f"📅 **Events**: No major events detected for {country}"
512
 
513
+ result = f"📅 **Current Events and Context**\n"
514
  for i, event in enumerate(events_data[:5], 1):
515
+ title = event.get('title', 'Event not specified')
516
  result += f"• {title}\n"
517
 
518
  return result.rstrip()
519
 
520
  except Exception:
521
+ return "📅 **Events**: Error during retrieval"
522
 
523
  def _search_current_events(self, keywords: str) -> list:
524
  """Recherche d'événements actuels"""
 
547
  return []
548
 
549
  def _get_holidays_info(self, country: str) -> str:
550
+ """Retrieves national holidays via API"""
551
  try:
552
  country_code = self.country_codes.get(country, '')
553
 
554
+ # If no code in our mapping, try to get it via API
555
  if not country_code:
556
  country_code = self._get_country_code_from_api(country)
557
 
558
  if not country_code:
559
+ return f"🎉 **Holidays**: Country code not found for {country}"
560
 
561
+ # Use Calendarific API or similar
562
  holidays_data = self._fetch_holidays_api(country_code)
563
 
564
  if not holidays_data:
565
+ return f"🎉 **Holidays**: Information not available for {country}"
566
 
567
  current_month = datetime.now().month
568
  current_year = datetime.now().year
569
 
570
+ result = f"🎉 **Holidays and Seasonal Events**\n"
571
 
572
+ # Filter holidays from current month and upcoming months
573
  upcoming_holidays = []
574
  for holiday in holidays_data:
575
  try:
 
580
  continue
581
 
582
  if upcoming_holidays:
583
+ result += f"**Upcoming holidays:**\n"
584
  for holiday in upcoming_holidays[:5]:
585
+ name = holiday.get('name', 'Unknown holiday')
586
  date = holiday.get('date', '')
587
  result += f"• {name} ({date})\n"
588
  else:
589
+ result += f"**No major holidays scheduled in the coming months**\n"
590
 
591
  return result.rstrip()
592
 
593
  except Exception:
594
+ return "🎉 **Holidays**: Error during retrieval"
595
 
596
  def _fetch_holidays_api(self, country_code: str) -> list:
597
  """Récupère les fêtes via API publique"""
 
610
  return []
611
 
612
  def _get_travel_info(self, country: str) -> str:
613
+ """Retrieves travel information via REST Countries API"""
614
  try:
615
+ # Use REST Countries API
616
  url = f"https://restcountries.com/v3.1/name/{country}"
617
  response = requests.get(url, timeout=10)
618
 
 
621
  if data:
622
  country_data = data[0]
623
 
624
+ # Extract information
625
  currencies = country_data.get('currencies', {})
626
  languages = country_data.get('languages', {})
627
+ region = country_data.get('region', 'Unknown')
628
 
629
+ currency_name = list(currencies.keys())[0] if currencies else 'Unknown'
630
+ language_list = list(languages.values()) if languages else ['Unknown']
631
 
632
+ result = f"✈️ **Practical Travel Information**\n"
633
+ result += f"💰 Currency: {currency_name}\n"
634
+ result += f"🗣️ Languages: {', '.join(language_list[:3])}\n"
635
+ result += f"🌍 Region: {region}\n"
636
+ result += f"📋 Check visa requirements on the country's official website"
637
 
638
  return result
639
 
640
+ return f"✈️ **Travel**: Information not available for {country}"
641
 
642
  except Exception:
643
+ return "✈️ **Travel**: Error during retrieval"
644
 
645
  def _get_political_info(self, country: str) -> str:
646
+ """Retrieves political context via news search"""
647
  try:
648
+ # Search for recent political news
649
  political_keywords = f"{country} politics government election democracy"
650
  political_data = self._search_political_news(political_keywords)
651
 
652
  if not political_data:
653
+ return f"🏛️ **Politics**: Stable situation for {country}"
654
 
655
+ result = f"🏛️ **Political Context**\n"
656
 
657
+ # Analyze political news
658
  for article in political_data[:3]:
659
  title = article.get('title', '')
660
  if title:
 
663
  return result.rstrip()
664
 
665
  except Exception:
666
+ return "🏛️ **Politics**: Error during retrieval"
667
 
668
  def _search_political_news(self, keywords: str) -> list:
669
  """Recherche d'actualités politiques"""
 
691
  return []
692
 
693
  def _get_llm_final_recommendation(self, country: str, full_report: str) -> Optional[str]:
694
+ """Uses Claude to generate an intelligent final recommendation"""
695
  try:
696
  if not self.claude_client:
697
  return None
698
 
699
+ prompt = f"""Analyze this complete report about {country} and provide a concise final recommendation for a traveler:
700
 
701
+ COMPLETE REPORT:
702
  {full_report}
703
 
704
+ Your task:
705
+ 1. Synthesize the most important information
706
+ 2. Give a clear and actionable recommendation
707
+ 3. Respond in English, maximum 200 words
708
+ 4. Use a professional but accessible tone
709
+ 5. If risks exist, be explicit about precautions
710
 
711
+ Desired response format:
712
+ 🎯 **FINAL RECOMMENDATION**
713
+ [Your synthetic analysis and recommendation]
714
 
715
+ If the destination is dangerous, clearly use "CHANGE DESTINATION" in your response."""
716
 
717
  response = self.claude_client.messages.create(
718
  model="claude-3-opus-20240229",
719
  max_tokens=250,
720
  temperature=0.2,
721
+ system="You are an expert travel advisor. Provide clear and practical recommendations.",
722
  messages=[
723
  {"role": "user", "content": prompt}
724
  ]
tools/weather_tool.py CHANGED
@@ -29,7 +29,7 @@ class WeatherTool(Tool):
29
 
30
  # Initialiser le client Claude pour les recommandations intelligentes
31
  try:
32
- self.claude_client = anthropic.Anthropic(api_key=os.getenv('ANTHROPIC_API_KEY'))
33
  except:
34
  self.claude_client = None
35
 
 
29
 
30
  # Initialiser le client Claude pour les recommandations intelligentes
31
  try:
32
+ self.claude_client = anthropic.Anthropic(api_key=os.getenv('ANTROPIC_KEY'))
33
  except:
34
  self.claude_client = None
35