Planificateur de voyage interactif. Collecte destinations, vols, hébergements et transport, optimise les combinaisons et génère un explorer.html interactif. Déclencher quand l'utilisateur veut planifier un voyage de vacances.
Planifier un voyage en collectant et optimisant toutes les options : destinations,
vols, hébergements et transport. Résultat final : un fichier explorer.html
autonome (sans serveur) pour explorer et comparer les options visuellement.
Demander à l'utilisateur (avec AskUserQuestion ou en posant les questions) :
Vélo :
Ski : (champs spécifiques à définir plus tard)
donnees/ avec les fichiers JSON (voir schémas ci-dessous)params.json (voir schéma ci-dessous)cp ~/.claude/skills/vacances/templates/optimiser.py .
cp ~/.claude/skills/vacances/explorer-template.html \
~/Dropbox/Public/<NomDestination>-<Année>/explorer.html
CRITIQUE : lancer T1, T2, T3 et T4 en parallèle via des subagents.
Chaque tâche est indépendante et peut s'exécuter simultanément pour réduire le temps
de collecte. Utiliser l'Agent tool avec run_in_background: true pour T1, T2, T3, T4,
puis attendre leur complétion avant de passer à l'étape 4.
destinations.jsondonnees/destinations.jsonvols.jsondonnees/vols.jsonprix_nuit_max de params.json)hebergements.jsondonnees/hebergements.jsonmcp__claude-in-chrome__*) ou WebSearchautos.jsondonnees/autos.jsonuv run optimiser.py
params.json si nécessairerapport.md avec les 3 meilleures optionsMettre à jour VOYAGE_CONFIG dans explorer.html :
titre : nom du voyage (ex. "Voyage Japon 2026")emoji : emoji représentatif (ex. "🗾")activite : type de voyage (ex. "Culture & Gastronomie")type : "velo" | "ski" | "tourisme" — contrôle les sections spécifiquesdevise : devise (ex. "CA$")nb_nuits : durée en nuitsnb_personnes : nombre de voyageursaeroport_depart : code IATA de l'aéroport de départInjecter les données JSON dans explorer.html via script Python :
import re, json
from pathlib import Path
html = Path('explorer.html').read_text()
for nom_const, fichier in [
('DESTINATIONS', 'donnees/destinations.json'),
('VOLS_RAW', 'donnees/vols.json'),
('HEBERGEMENTS', 'donnees/hebergements.json'),
('AUTOS', 'donnees/autos.json'),
]:
data = json.loads(Path(fichier).read_text())
json_str = json.dumps(data, ensure_ascii=False)
html = re.sub(
rf'const {nom_const}\s*=\s*\[.*?\];',
f'const {nom_const} = {json_str};',
html, flags=re.DOTALL
)
# IMAGES (objet)
images = json.loads(Path('donnees/images.json').read_text())
html = re.sub(
r'const IMAGES\s*=\s*\{[^;]*\};',
f'const IMAGES = {json.dumps(images, ensure_ascii=False)};',
html
)
Path('explorer.html').write_text(html)
Scraper les images Airbnb (si nécessaire) via scraper_images.py
Ouvrir dans le navigateur pour sélection visuelle par l'utilisateur
{
"nom": "Kyoto",
"region": "Kansai",
"aeroports": ["KIX", "ITM"],
"distance_aeroport_km": { "KIX": 75, "ITM": 40 },
"coords": [35.0116, 135.7681],
"description": "Ancienne capitale impériale, temples et jardins zen.",
"point_fort": "Plus de 1600 temples et sanctuaires, quartiers historiques préservés.",
"activites": ["Temples & sanctuaires", "Gastronomie", "Vélo", "Randonnée"],
"stats": [
{ "icon": "landscape", "valeur": "800 m (mont Hiei)" },
{ "icon": "route", "valeur": "75 km pistes cyclables" }
],
"liens": {
"site officiel": "https://kyoto.travel/en",
"office du tourisme": "https://kyoto.travel/en"
},
"notes": "Très fréquenté en avril (cerisiers) et novembre (érables)."
}
Champs obligatoires : nom, region, aeroports, distance_aeroport_km, coords
Champs optionnels : description, point_fort, activites, stats, liens, notes
velo{
"remontee_nom": "First Gondola",
"remontee_accepte_velos": true,
"remontee_prix_chf": 45,
"remontee_mois_ouverts": [6, 7, 8, 9],
"difficulte_trails": "tous niveaux",
"altitude_village_m": 1034,
"altitude_sommet_m": 2168,
"trails_km": 150,
"gravel_routes": [
{
"nom": "Gravel Eiger Loop",
"distance_km": 45,
"denivele_pos_m": 1100,
"type": "gravel",
"niveau": "intermédiaire",
"description": "Boucle autour de l'Eiger"
}
]
}
niveau accepte : facile | intermédiaire | difficile | expert
{
"aeroport_arrivee": "KIX",
"date_depart": "2026-07-04",
"date_retour": "2026-07-18",
"prix_par_personne": 1400,
"compagnie": "Air Canada",
"duree_heures": 13.5,
"escales": 1,
"heure_depart": "14:00",
"heure_arrivee": "17:30",
"url": "https://www.google.com/flights/..."
}
Champs obligatoires : aeroport_arrivee, date_depart, date_retour, prix_par_personne, compagnie, escales
Champs optionnels : duree_heures, heure_depart, heure_arrivee, url
{
"destination": "Kyoto",
"titre": "Machiya traditionnelle avec jardin",
"airbnb_id": "12345678",
"url": "https://www.airbnb.ca/rooms/12345678",
"prix_nuit_cad": 180,
"note": 4.9,
"nb_avis": 87,
"nb_chambres": 2,
"cuisinette": true,
"reservation_instantanee": true,
"annulation_jours": 30,
"stationnement": false,
"notes": "Vue sur jardin zen, 5 min métro"
}
Champs obligatoires : destination, titre, airbnb_id, url, prix_nuit_cad
Champs optionnels : note, nb_avis, nb_chambres, cuisinette, reservation_instantanee, annulation_jours, stationnement, notes
velo{
"rangement_velos": true,
"distance_remontee_km": 0.5
}
{
"aeroport": "KIX",
"fournisseur": "Europcar",
"categorie": "Compact",
"exemple_vehicule": "Toyota Corolla",
"prix_jour_cad": 75,
"km_illimite": true,
"assurance_incluse": false,
"notes": "Coffre 2 valises",
"url": "https://www.europcar.com/..."
}
Champs obligatoires : aeroport, fournisseur, categorie, prix_jour_cad
Champs optionnels : exemple_vehicule, km_illimite, assurance_incluse, notes, url
velo{
"capacite_velo": 2
}
{
"12345678": "https://a0.muscache.com/im/pictures/...",
"87654321": "https://a0.muscache.com/im/pictures/..."
}
{
"nb_personnes": 2,
"nb_nuits": 14,
"devise": "CA$",
"budget_total": 10000,
"prix_nuit_max": 300,
"poids": {
"cout": 0.5,
"note": 0.3,
"duree_vol": 0.1,
"escales": 0.1
},
"filtres": {
"note_min": 4.0,
"nb_avis_min": 3,
"escales_max": 1
}
}
| Fichier | Description |
|---|---|
~/.claude/skills/vacances/explorer-template.html | Interface interactive autonome |
~/.claude/skills/vacances/templates/optimiser.py | Optimiseur à adapter |
og:image sont optionnelles ; l'interface a un fallback emoji