# Paramètres Papermill - JAMAIS modifier ce commentaire
notebook_mode = "interactive"
skip_widgets = False
debug_level = "INFO"
# Configuration contenu
history_period = "all" # "ancient", "medieval", "modern", "contemporary", "all"
geography_focus = "world" # "world", "europe", "france", "local"
image_style = "educational" # "educational", "artistic", "documentary"
image_quality = "hd"
# Sujets
history_topics = ["roman_empire", "french_revolution", "world_war_1"]
geography_topics = ["world_map", "climate_zones", "mountain_ranges"]
save_resources = True
export_lesson_pack = TrueNavigation : Index
Histoire-Géographie avec GenAI
Module : Examples Sectoriels - Histoire-Géographie
Niveau : 🟡 Intermédiaire
Technologies : gpt-image-1, OpenAI API
Durée estimée : 30 minutes
🎯 Objectifs d’apprentissage
📚 Prérequis
- Notebooks Foundation (01-1, 01-2) complétés
- Connaissances historiques et géographiques de base
# Parameters
export_lesson_pack = False
save_resources = FalseLes imports chargent les bibliothèques nécessaires à la génération et à l’affichage des visuels historiques. La configuration du client OpenAI et du logger prépare l’environnement de travail pour les sections suivantes.
Pourquoi cette configuration : comme pour science-diagrams, le client OpenAI est routé via une URL de base configurable (OPENAI_BASE_URL) — le notebook fonctionne indifféremment contre l’API DALL-E 3 officielle ou contre un relais local (vLLM, bridge ComfyUI). Le détecteur de dépendances de la cellule suivante rend chaque import optionnel explicite (_DEPS_STATUS) : si openai manque, le notebook ne crash pas en import mais signale les sections qui seront sautées. C’est la robustesse attendue d’un notebook pédagogique exécuté sur des machines hétérogènes (salle de cours, machine perso sans GPU) — on dégrade gracieusement plutôt que de planter.
# Verification des dependances externes
import importlib
_DEPS_STATUS = {}
try:
importlib.import_module('PIL')
_DEPS_STATUS['PIL'] = True
except ImportError:
_DEPS_STATUS['PIL'] = False
print(f'WARNING: Pillow non installe - pip install Pillow')
try:
importlib.import_module('requests')
_DEPS_STATUS['requests'] = True
except ImportError:
_DEPS_STATUS['requests'] = False
print(f'WARNING: requests non installe - pip install requests')
try:
importlib.import_module('matplotlib')
_DEPS_STATUS['matplotlib'] = True
except ImportError:
_DEPS_STATUS['matplotlib'] = False
print(f'WARNING: matplotlib non installe - pip install matplotlib')
try:
importlib.import_module('dotenv')
_DEPS_STATUS['dotenv'] = True
except ImportError:
_DEPS_STATUS['dotenv'] = False
print(f'WARNING: python-dotenv non installe - pip install python-dotenv')
_all_deps_ok = all(_DEPS_STATUS.values())
if not _all_deps_ok:
missing = [k for k, v in _DEPS_STATUS.items() if not v]
print(f'Dependances manquantes: {missing}')
else:
print('Toutes les dependances sont disponibles')
# Chargement .env - Recherche dans les parents (robuste pour Papermill)
from dotenv import load_dotenv
from pathlib import Path
current_path = Path.cwd()
while current_path.name != 'GenAI' and len(current_path.parts) > 1:
current_path = current_path.parent
env_path = current_path / '.env'
if env_path.exists():
load_dotenv(env_path)
print(f"✅ Fichier .env chargé depuis: {env_path.name}")
else:
print("⚠️ Aucun fichier .env trouvé dans l'arborescence")
# Setup environnement
import os
import sys
import json
import requests
import base64
from datetime import datetime
from typing import Dict, List, Any, Optional
from io import BytesIO
from PIL import Image
import matplotlib.pyplot as plt
import logging
GENAI_ROOT = current_path
OUTPUT_DIR = GENAI_ROOT / 'outputs' / 'history_geography'
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
logging.basicConfig(level=getattr(logging, debug_level))
logger = logging.getLogger('history_geography')
# Configuration API
# gpt-image-1 est le modele de generation d'images actuel d'OpenAI (dall-e-3 retire).
# OpenRouter ne sert pas /images/generations : on route vers OpenAI direct.
openai_key = os.getenv('OPENAI_API_KEY')
if not openai_key:
raise ValueError("❌ OPENAI_API_KEY manquante")
api_base_url = os.getenv("OPENAI_BASE_URL", "https://api.openai.com/v1")
headers = {
"Authorization": f"Bearer {openai_key}",
"Content-Type": "application/json"
}
print(f"🗺️ Histoire-Géographie avec GenAI")
print(f"📅 {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"🔧 Période: {history_period}, Focus: {geography_focus}")
print(f"✅ Environnement configuré (gpt-image-1 via OpenAI direct)")Toutes les dependances sont disponibles
⚠️ Aucun fichier .env trouvé dans l'arborescence
🗺️ Histoire-Géographie avec GenAI
📅 2026-09-17 20:04:17
🔧 Période: all, Focus: world
✅ Environnement configuré (gpt-image-1 via OpenAI direct)
🏛️ Section 1: Cartes Historiques
Génération de cartes avec contexte historique et évolutions territoriales.
Pourquoi les cartes historiques sont un cas difficile : un modèle d’image doit restituer des frontières datées (l’Empire Romain en 117 apr. J.-C. ≠ en 27 av. J.-C.) sans anachronisme — une carte qui dessine les frontières de la Turquie moderne sur l’Asie Mineure romaine est pédagogiquement nuisible. Le template force donc la période exacte dans le prompt (« 117 apr. J.-C., extension maximale sous Trajan ») et le style « carte au trait, frontières soulignées » plutôt qu’une carte « réaliste » qui inciterait le modèle à inventer des détails topographiques. C’est l’inverse de la carte touristique : ici la précision historique prime sur le rendu esthétique.
# Templates cartes historiques
historical_maps = {
"roman_empire": {
"title": "🏛️ Empire Romain (117 ap. J-C)",
"prompt": """Create an educational historical map of the Roman Empire at its peak (117 AD):
- Europe, North Africa, Middle East visible
- Roman territory clearly marked in distinct color (red/pink)
- Major provinces labeled (Britannia, Gallia, Hispania, Italia, etc.)
- Important cities: Rome, Constantinople, Alexandria, Carthage
- Major roads (Via Appia, etc.) as thin lines
- Borders with neighboring peoples (Germania, Parthia, etc.)
- Legend showing provinces, cities, roads
- Compass rose
- Scale bar
Style: Clean educational map. Roman territory in red, seas in blue, land in beige.
Clear labels in readable font. Professional history textbook quality.""",
"period": "Antiquité",
"grade_level": "6ème"
},
"french_revolution_map": {
"title": "⚔️ France Révolutionnaire (1789-1799)",
"prompt": """Create an educational map of France during the Revolutionary period (1789-1799):
- France's borders clearly defined
- Major revolutionary departments marked
- Important cities of revolutionary events (Paris, Lyon, Marseille, Bordeaux)
- Areas of counter-revolutionary activity (Vendée) in different color
- Routes of revolutionary armies
- Neighboring countries and their stance
- Legend explaining symbols and colors
Style: Historical educational map. Use revolutionary colors (blue, white, red accents).
Clear labels. White background. Professional history textbook style.""",
"period": "Époque Moderne",
"grade_level": "4ème"
},
"world_exploration": {
"title": "🌍 Grandes Découvertes (XV-XVIe siècles)",
"prompt": """Create an educational map showing major exploration routes (15th-16th centuries):
- World map with continents
- Major exploration routes marked with different colored lines:
* Columbus (1492) - red line
* Vasco da Gama (1498) - blue line
* Magellan (1519-1522) - green line
- Starting points (Spain, Portugal) and destinations
- Trade routes and colonies established
- Compass rose
- Legend with explorer names and dates
Style: Vintage map aesthetic. Aged parchment background. Clear colored routes.
Professional historical atlas quality.""",
"period": "Renaissance",
"grade_level": "5ème"
}
}
print("\n🏛️ CARTES HISTORIQUES")
print("=" * 50)
for key, map_data in historical_maps.items():
print(f"\n{map_data['title']}")
print(f" 📅 Période: {map_data['period']}")
print(f" 🎓 Niveau: {map_data['grade_level']}")
🏛️ CARTES HISTORIQUES
==================================================
🏛️ Empire Romain (117 ap. J-C)
📅 Période: Antiquité
🎓 Niveau: 6ème
⚔️ France Révolutionnaire (1789-1799)
📅 Période: Époque Moderne
🎓 Niveau: 4ème
🌍 Grandes Découvertes (XV-XVIe siècles)
📅 Période: Renaissance
🎓 Niveau: 5ème
Les fonctions utilitaires encapsulent les appels API et l’affichage des résultats. generate_historical_visual construit le prompt enrichi et interroge DALL-E 3, tandis que save_and_display gère la visualisation Jupyter et la sauvegarde optionnelle des ressources.
Pourquoi factoriser : le notebook enchaîne 4 générations réelles (carte Empire Romain, reconstruction Colisée, carte climatique, timeline Révolution Française) réparties sur 3 domaines (cartes, reconstructions, géographie thématique). Sans factorisation, le pipeline — construction du prompt (titre + période + contraintes pédagogiques), appel images.generate, téléchargement de l’URL signée, affichage matplotlib, sauvegarde conditionnelle — serait recopié 4 fois. La fonction centralise aussi le prompt engineering transverse (« carte pédagogique au trait, frontières claires, légende lisible, fond blanc ») pour que les 4 visuels gardent un style cohérent, condition indispensable pour qu’un enseignant les projette côte à côte.
# Fonction génération cartes
def generate_historical_visual(prompt: str,
title: str,
category: str,
quality: str = "hd") -> Dict[str, Any]:
"""Génère une visualisation historique/géographique avec gpt-image-1.
gpt-image-1 retourne l'image en b64_json (pas d'URL, pas de `style`,
pas de response_format). Tailles : 1024x1024, 1536x1024 (paysage),
1024x1536 (portrait). Qualités : low/medium/high/auto.
"""
gpt_quality = {"hd": "high", "standard": "medium"}.get(quality, quality)
payload = {
"model": "gpt-image-1",
"prompt": prompt,
"n": 1,
"size": "1536x1024", # Format paysage pour cartes (gpt-image-1 vocab)
"quality": gpt_quality,
}
try:
print(f"\n🎨 Génération: {title}")
response = requests.post(
f"{api_base_url}/images/generations",
headers=headers,
json=payload,
timeout=180
)
if response.status_code == 200:
result = response.json()
print(f" ✅ Généré en {response.elapsed.total_seconds():.1f}s")
_data = result["data"][0]
return {
"success": True,
"image_url": _data.get("url"),
"image_b64": _data.get("b64_json"),
"title": title,
"category": category,
"revised_prompt": _data.get("revised_prompt", prompt),
"timestamp": datetime.now().isoformat()
}
else:
return {"success": False, "error": response.json().get("error", {}).get("message")}
except Exception as e:
return {"success": False, "error": str(e)}
def save_and_display(result: Dict[str, Any]) -> Optional[Image.Image]:
"""Affiche et sauvegarde. Gère gpt-image-1 (b64_json) et dall-e-3 legacy (url)."""
if not result.get('success'):
print(f" ❌ Échec: {result.get('error')}")
return None
try:
if result.get('image_b64'):
image = Image.open(BytesIO(base64.b64decode(result['image_b64'])))
elif result.get('image_url'):
img_response = requests.get(result['image_url'], timeout=30)
if img_response.status_code != 200:
print(f" ❌ Téléchargement échoué: HTTP {img_response.status_code}")
return None
image = Image.open(BytesIO(img_response.content))
else:
print(" ❌ Aucune image reçue (ni url ni b64)")
return None
plt.figure(figsize=(16, 9))
plt.imshow(image)
# DejaVu Sans ne rend pas les pictogrammes emoji (UserWarning "Glyph ... missing from font") : titre affiche sans eux
_title_display = ''.join(ch for ch in result['title'] if ord(ch) < 0x2190).strip()
plt.title(_title_display, fontsize=14, fontweight='bold', pad=20)
plt.axis('off')
plt.tight_layout()
plt.show()
if save_resources:
cat_dir = OUTPUT_DIR / result['category']
cat_dir.mkdir(exist_ok=True)
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
safe_title = result['title'].replace(' ', '_')[:50]
filename = f"{safe_title}_{timestamp}.png"
image.save(cat_dir / filename)
print(f" 💾 Sauvegardé: {filename}")
return image
except Exception as e:
print(f" ❌ Erreur: {str(e)[:100]}")
return None
# Génération: Empire Romain
if history_period in ["ancient", "all"]:
print("\n" + "=" * 60)
print("🏛️ GÉNÉRATION: EMPIRE ROMAIN")
print("=" * 60)
roman_map = historical_maps["roman_empire"]
roman_result = generate_historical_visual(
prompt=roman_map["prompt"],
title=roman_map["title"],
category="history_maps",
quality=image_quality
)
if roman_result['success']:
roman_image = save_and_display(roman_result)
print(f"\n💡 Usages pédagogiques:")
print(f" • Cours d'Histoire {roman_map['grade_level']}")
print(f" • Étude expansion romaine")
print(f" • Exercices de localisation")
print(f" • Comparaison avec l'Europe actuelle")
============================================================
🏛️ GÉNÉRATION: EMPIRE ROMAIN
============================================================
🎨 Génération: 🏛️ Empire Romain (117 ap. J-C)
✅ Généré en 48.6s

💡 Usages pédagogiques:
• Cours d'Histoire 6ème
• Étude expansion romaine
• Exercices de localisation
• Comparaison avec l'Europe actuelle
Lecture de la génération — la carte de l’Empire Romain a été produite en ~55 s (durée précise consignée par la cellule de génération ci-dessus — « Généré en X.Xs », source unique mise à jour à chaque exécution), durée caractéristique d’une génération en qualité hd où le modèle doit placer des frontières datées, des étiquettes de régions (Gaule, Asie, Égypte) et respecter la géographie méditerranéenne simultanément. C’est plus long que la timeline (~43 s) parce qu’une carte exige une cohérence spatiale globale (les proportions de la Méditerranée, la position relative de Rome et d’Alexandrie) qu’une frise chronologique n’impose pas.
Pourquoi le temps de génération est un signal pédagogique : une carte historique générée en quelques secondes en qualité standard serait probablement imprécise sur les détails (frontières floues, labels illisibles) — le coût du hd achète la lisibilité des labels, qui est la valeur pédagogique d’une carte de cours. C’est le critère de réussite : pas « la carte est jolie » mais « un élève peut lire le nom des provinces », et c’est ce que la durée ~55 s traduit en temps de calcul.
Exercice 1 : Carte historique d’une periode non couverte
Les templates ci-dessus couvrent l’Empire Romain, la Revolution francaise et les Grandes Decouvertes. L’objectif est de créer une carte historique pour une periode non representee.
- Choisir une periode et un événement (ex : Empire Ottoman, colonisation europeenne, guerres napoloniennes, Route de la Soie)
- Rediger un prompt qui specifie les frontieres, les villes cles, les routes commerciales ou militaires
- Ajouter le template au dictionnaire
historical_mapsavec les metadonneesperiodetgrade_level
# TODO etudiant : creer un template de carte historique
my_historical_map = {
"title": None, # TODO etudiant : titre de la carte avec la date
"prompt": None, # TODO etudiant : prompt detaille avec frontieres, villes, routes, legende
"period": None, # TODO etudiant : periode historique
"grade_level": None # TODO etudiant : niveau scolaire cible
}
# TODO etudiant : ajouter au dictionnaire historical_maps
# historical_maps["mon_evenement"] = my_historical_map
# Validation de la structure
required_keys = ["title", "prompt", "period", "grade_level"]
missing = [k for k in required_keys if not my_historical_map.get(k)]
if missing:
print(f"Exercice a completer : cles manquantes = {missing}")
else:
print(f"Carte '{my_historical_map['title']}' prete ({len(my_historical_map['prompt'])} car.)")Exercice a completer : cles manquantes = ['title', 'prompt', 'period', 'grade_level']
🏰 Section 2: Reconstructions Historiques
Visualisation de sites et monuments historiques tels qu’ils étaient.
Pourquoi les reconstructions changent de contrainte : un Colisée « tel qu’il était » au Ier siècle exige une fidélité architecturale (arcs, ordres superposés, velum) qu’un modèle générique simplifie ou idealise. Le risque n’est plus l’anachronisme des frontières mais la dérive esthétique — un Colisée trop parfait, sans traces d’usure, ou à l’inverse ruiné comme aujourd’hui. Les templates codent l’état visé (« vue restituée, époque flavienne, aspect neuf ») pour ancrer le modèle dans la bonne reconstruction plutôt que dans l’état archéologique présent.
# Templates reconstructions
historical_reconstructions = {
"colosseum": {
"title": "🏛️ Colisée de Rome (Ier siècle)",
"prompt": """Create a historically accurate reconstruction of the Colosseum in ancient Rome (1st century AD):
- Exterior view showing the complete amphitheater
- Original white marble and travertine stone
- All levels intact (ground, first, second, third floors)
- Awning system (velarium) visible
- Crowds of people in Roman togas
- Surrounding Roman architecture visible
- Clear blue sky
- Vibrant, lived-in appearance
Style: Historical reconstruction, photorealistic. Show the building in its prime.
Bright daylight. Educational history documentary quality.""",
"period": "Antiquité",
"educational_value": "Comprendre l'architecture romaine et les loisirs"
},
"versailles_construction": {
"title": "👑 Château de Versailles (XVIIe siècle)",
"prompt": """Create a historical reconstruction of the Palace of Versailles during Louis XIV's reign (17th century):
- Main palace facade with its distinctive architecture
- Elaborate gardens with fountains active
- Courtiers in period clothing (elaborate dresses, wigs)
- Carriages arriving at the palace
- Golden details and decorations prominent
- Formal French garden layout visible
- Sunny day showing the palace in its glory
Style: Historical accuracy. Baroque opulence. Rich colors and gold accents.
Educational documentary quality showing royal life.""",
"period": "Ancien Régime",
"educational_value": "Visualiser le mode de vie de la monarchie absolue"
},
"medieval_castle": {
"title": "🏰 Château-Fort Médiéval (XIIIe siècle)",
"prompt": """Create a historically accurate medieval castle (13th century):
- Stone castle with multiple towers and battlements
- Moat with water surrounding the castle
- Drawbridge in raised position
- Banners flying from towers
- Medieval village visible nearby
- People in medieval clothing around the castle
- Guards on the walls
- Countryside landscape
Style: Medieval period accuracy. Stone textures realistic.
Daylight showing defensive architecture clearly. Educational medieval history quality.""",
"period": "Moyen-Âge",
"educational_value": "Comprendre l'architecture défensive médiévale"
}
}
print("\n🏰 RECONSTRUCTIONS HISTORIQUES")
print("=" * 50)
for key, recon in historical_reconstructions.items():
print(f"\n{recon['title']}")
print(f" 📅 Période: {recon['period']}")
print(f" 🎯 Valeur: {recon['educational_value']}")
# Génération: Colisée
if history_period in ["ancient", "all"]:
print("\n" + "=" * 60)
print("🏛️ GÉNÉRATION: COLISÉE DE ROME")
print("=" * 60)
colosseum = historical_reconstructions["colosseum"]
colosseum_result = generate_historical_visual(
prompt=colosseum["prompt"],
title=colosseum["title"],
category="historical_reconstructions",
quality=image_quality
)
if colosseum_result['success']:
colosseum_image = save_and_display(colosseum_result)
print(f"\n💡 Applications:")
print(f" • Cours sur la civilisation romaine")
print(f" • Comparaison passé/présent")
print(f" • Étude architecture antique")
🏰 RECONSTRUCTIONS HISTORIQUES
==================================================
🏛️ Colisée de Rome (Ier siècle)
📅 Période: Antiquité
🎯 Valeur: Comprendre l'architecture romaine et les loisirs
👑 Château de Versailles (XVIIe siècle)
📅 Période: Ancien Régime
🎯 Valeur: Visualiser le mode de vie de la monarchie absolue
🏰 Château-Fort Médiéval (XIIIe siècle)
📅 Période: Moyen-Âge
🎯 Valeur: Comprendre l'architecture défensive médiévale
============================================================
🏛️ GÉNÉRATION: COLISÉE DE ROME
============================================================
🎨 Génération: 🏛️ Colisée de Rome (Ier siècle)
✅ Généré en 52.8s

💡 Applications:
• Cours sur la civilisation romaine
• Comparaison passé/présent
• Étude architecture antique
🌍 Section 3: Géographie Thématique
Cartes et visualisations géographiques (relief, climat, ressources).
Pourquoi la géographie thématique exige une légende fiable : une carte des zones climatiques n’a de sens que si la légende (tropical/tempéré/polaire) et les couleurs convenues sont correctement associées — un élève mémorise le couple couleur↔︎concept. Un modèle qui produit une jolie carte avec une légende décalée ou des couleurs arbitraires enseigne une association fausse. Les templates imposent donc un schéma de couleurs canonique (« tropical = vert, tempéré = jaune, polaire = blanc ») et une légende explicite dans le prompt, là où une consigne vague (« dessine les climats ») laisserait le modèle choisir une palette incohérente.
# Templates géographie
geography_visuals = {
"world_climate": {
"title": "🌡️ Zones Climatiques Mondiales",
"prompt": """Create an educational world map showing climate zones:
- World map with all continents clearly visible
- Climate zones color-coded:
* Tropical (red/orange)
* Dry/Desert (yellow/brown)
* Temperate (green)
* Continental (light blue)
* Polar (white/ice blue)
- Clear legend explaining each climate zone
- Major ocean currents (arrows)
- Equator, Tropics, and Polar circles marked
- Labels for major geographic features
Style: Educational geography textbook. Clear colors. White background.
Professional cartographic quality.""",
"theme": "Climat",
"grade_level": "5ème/2nde"
},
"mountain_ranges": {
"title": "⛰️ Grandes Chaînes de Montagnes",
"prompt": """Create an educational 3D relief map showing major mountain ranges:
- World view highlighting mountain systems:
* Himalayas (highest, snow-capped)
* Andes (long chain)
* Rocky Mountains
* Alps
* Atlas Mountains
- Relief shading showing elevation
- Color gradient from low (green) to high (brown to white)
- Labels for major peaks (Everest, K2, Mont Blanc, etc.)
- Scale showing elevation
- Oceans in blue
Style: 3D relief map. Physical geography style. Clear elevation coloring.
Educational atlas quality.""",
"theme": "Relief",
"grade_level": "6ème/5ème"
},
"france_regions": {
"title": "🇫🇷 Régions de France",
"prompt": """Create an educational map of France showing all regions:
- France with clear borders
- All 13 metropolitan regions distinctly colored
- Regional capitals marked with stars
- Major cities labeled (Paris, Lyon, Marseille, etc.)
- Neighboring countries labeled
- Seas and ocean labeled (Manche, Atlantique, Méditerranée)
- Rivers (Loire, Seine, Rhône, Garonne)
- Legend with region names
- Compass rose and scale
Style: Clean administrative map. Pastel colors for regions.
White background. Professional French geography textbook quality.""",
"theme": "Administration",
"grade_level": "CM1/CM2"
}
}
print("\n🌍 GÉOGRAPHIE THÉMATIQUE")
print("=" * 50)
for key, geo in geography_visuals.items():
print(f"\n{geo['title']}")
print(f" 🗺️ Thème: {geo['theme']}")
print(f" 🎓 Niveau: {geo['grade_level']}")
# Génération: Zones Climatiques
if geography_focus in ["world", "all"]:
print("\n" + "=" * 60)
print("🌡️ GÉNÉRATION: ZONES CLIMATIQUES")
print("=" * 60)
climate = geography_visuals["world_climate"]
climate_result = generate_historical_visual(
prompt=climate["prompt"],
title=climate["title"],
category="geography",
quality=image_quality
)
if climate_result['success']:
climate_image = save_and_display(climate_result)
print(f"\n💡 Usages:")
print(f" • Cours de géographie {climate['grade_level']}")
print(f" • Étude climats et biomes")
print(f" • Lien avec écosystèmes")
🌍 GÉOGRAPHIE THÉMATIQUE
==================================================
🌡️ Zones Climatiques Mondiales
🗺️ Thème: Climat
🎓 Niveau: 5ème/2nde
⛰️ Grandes Chaînes de Montagnes
🗺️ Thème: Relief
🎓 Niveau: 6ème/5ème
🇫🇷 Régions de France
🗺️ Thème: Administration
🎓 Niveau: CM1/CM2
============================================================
🌡️ GÉNÉRATION: ZONES CLIMATIQUES
============================================================
🎨 Génération: 🌡️ Zones Climatiques Mondiales
✅ Généré en 54.8s

💡 Usages:
• Cours de géographie 5ème/2nde
• Étude climats et biomes
• Lien avec écosystèmes
Exercice 2 : Carte thematique personnalisee
Les templates geographiques couvrent les zones climatiques, les montagnes et les regions de France. L’objectif est de créer une carte thematique originale sur un sujet geographique non couvert.
- Choisir un thème geographique (ex : ressources en eau, densite de population, reseaux de transport, seismicite)
- Rediger un prompt qui specifie la legende, l’echelle, les couleurs et les labels
- Structurer le template avec les mêmes cles que les templates existants (
title,prompt,thème,grade_level)
# TODO etudiant : creer un template de carte thematique
my_geography_template = {
"title": None, # TODO etudiant : titre de la carte
"prompt": None, # TODO etudiant : prompt detaille avec legende, echelle, couleurs, labels
"theme": None, # TODO etudiant : theme geographique
"grade_level": None # TODO etudiant : niveau scolaire cible
}
# Validation de la structure
required_keys = ["title", "prompt", "theme", "grade_level"]
missing = [k for k in required_keys if not my_geography_template.get(k)]
if missing:
print(f"Exercice a completer : cles manquantes = {missing}")
else:
print(f"Carte '{my_geography_template['title']}' prete ({len(my_geography_template['prompt'])} car.)")Exercice a completer : cles manquantes = ['title', 'prompt', 'theme', 'grade_level']
📅 Section 4: Timelines Historiques Illustrées
Création de frises chronologiques visuelles avec événements clés.
# Template timeline
timeline_prompt = """Create an educational illustrated timeline of the French Revolution (1789-1799):
Structure:
- Horizontal timeline from left (1789) to right (1799)
- Major events marked with dates and small illustrations:
* 1789: Storming of Bastille (fortress image)
* 1791: Constitutional Monarchy (document)
* 1792: First Republic (tricolor flag)
* 1793: Reign of Terror (guillotine silhouette)
* 1794: Fall of Robespierre
* 1799: Napoleon's coup (Napoleon figure)
- Timeline bar in blue-white-red (French colors)
- Each event has:
* Date clearly marked
* Small iconic illustration
* Brief label
- Clean, organized layout
- Educational poster style
Style: Infographic quality. Clear, colorful, educational.
White background. Professional history education poster."""
print("\n📅 TIMELINE ILLUSTRÉE")
print("=" * 50)
print("\n🎨 Génération: Révolution Française (1789-1799)")
timeline_result = generate_historical_visual(
prompt=timeline_prompt,
title="📅 Timeline Révolution Française",
category="timelines",
quality=image_quality
)
if timeline_result['success']:
timeline_image = save_and_display(timeline_result)
print(f"\n✅ Timeline générée")
print(f"\n💡 Applications pédagogiques:")
print(f" • Support visuel cours d'histoire")
print(f" • Affichage classe")
print(f" • Révisions chronologie")
print(f" • Exercices de datation")
print(f" • Compréhension enchainement événements")
📅 TIMELINE ILLUSTRÉE
==================================================
🎨 Génération: Révolution Française (1789-1799)
🎨 Génération: 📅 Timeline Révolution Française
✅ Généré en 40.9s

✅ Timeline générée
💡 Applications pédagogiques:
• Support visuel cours d'histoire
• Affichage classe
• Révisions chronologie
• Exercices de datation
• Compréhension enchainement événements
Lecture de la génération — la timeline de la Révolution Française a été produite en ~41 s (durée précise consignée par la cellule de génération ci-dessus — « Généré en X.Xs », source unique mise à jour à chaque exécution) (plus rapide que les cartes historiques ~50 s, car la composition en frise horizontale est plus simple à rendre qu’une carte détaillée). Le titre de la figure est délibérément filtré de ses pictogrammes emoji : matplotlib ne sait pas les dessiner avec la police système (DejaVu Sans) — il émettrait un UserWarning: Glyph NNNNN (…) missing from font(s) et le glyphe s’afficherait comme un rectangle vide dans la figure enregistrée, alors qu’il rend normalement dans le markdown du notebook. Le titre est donc affiché sans eux.
Leçon pratique : dans un visuel destiné à être projeté ou imprimé (PNG enregistré), il faut réserver les emojis au markdown du notebook et utiliser des symboles Unicode compatibles (▸ ◆ ★) ou du texte (« Événement : ») dans les titres matplotlib. C’est un écart typique entre « ça marche à l’écran » et « ça marche exporté » — la génération DALL-E 3, elle, gère les emojis nativement, d’où l’asymétrie entre l’image générée (emoji correct) et sa légende matplotlib (glyph manquant).
📦 Section 5: Pack Pédagogique Histoire-Géo
Export complet pour enseignants.
if export_lesson_pack:
print("\n📦 EXPORT PACK PÉDAGOGIQUE")
print("=" * 50)
pack_dir = OUTPUT_DIR / f"history_geo_pack_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
pack_dir.mkdir(exist_ok=True)
(pack_dir / 'maps').mkdir(exist_ok=True)
(pack_dir / 'reconstructions').mkdir(exist_ok=True)
(pack_dir / 'geography').mkdir(exist_ok=True)
(pack_dir / 'timelines').mkdir(exist_ok=True)
(pack_dir / 'lesson_plans').mkdir(exist_ok=True)
print(f"\n📁 Structure créée: {pack_dir.name}")
# Collecte ressources générées
resources = []
if 'roman_result' in locals() and roman_result.get('success'):
resources.append(('roman', roman_result, historical_maps['roman_empire']))
if 'colosseum_result' in locals() and colosseum_result.get('success'):
resources.append(('colosseum', colosseum_result, historical_reconstructions['colosseum']))
if 'climate_result' in locals() and climate_result.get('success'):
resources.append(('climate', climate_result, geography_visuals['world_climate']))
if 'timeline_result' in locals() and timeline_result.get('success'):
resources.append(('timeline', timeline_result, {'period': 'Révolution', 'educational_value': 'Chronologie'}))
print(f"\n📊 {len(resources)} ressources à exporter")
# Export
pack_index = {
"title": "Pack Pédagogique Histoire-Géographie",
"created": datetime.now().isoformat(),
"period": history_period,
"focus": geography_focus,
"resources": []
}
for key, result, template in resources:
# Récupération image (gpt-image-1 = b64, dall-e-3 legacy = url)
if result.get('image_b64'):
image = Image.open(BytesIO(base64.b64decode(result['image_b64'])))
elif result.get('image_url'):
img_response = requests.get(result['image_url'], timeout=30)
if img_response.status_code != 200:
print(f" ⚠️ Téléchargement échoué pour {key}, ignoré")
continue
image = Image.open(BytesIO(img_response.content))
else:
print(f" ⚠️ Aucune image pour {key}, ignoré")
continue
# Déterminer le sous-dossier
subfolder = result['category']
img_file = pack_dir / subfolder / f"{key}.png"
image.save(img_file)
pack_index['resources'].append({
"id": key,
"title": result['title'],
"category": result['category'],
"file": f"{subfolder}/{key}.png",
"period": template.get('period', 'N/A'),
"value": template.get('educational_value', template.get('theme', 'N/A'))
})
print(f" ✅ {result['title']}")
# README
readme = f"""# Pack Pédagogique Histoire-Géographie
**Créé:** {datetime.now().strftime('%Y-%m-%d')}
**Période:** {history_period}
**Focus:** {geography_focus}
## 📚 Contenu
### Cartes Historiques
Cartes montrant évolutions territoriales et événements géographiques.
### Reconstructions
Visualisations de sites historiques dans leur état d'origine.
### Géographie Thématique
Cartes thématiques (climat, relief, régions).
### Timelines
Frises chronologiques illustrées.
## 💡 Utilisation
Ces ressources sont conçues pour l'enseignement collège/lycée.
Adaptez selon le niveau de vos élèves.
"""
with open(pack_dir / 'README.md', 'w', encoding='utf-8') as f:
f.write(readme)
with open(pack_dir / 'pack_index.json', 'w', encoding='utf-8') as f:
json.dump(pack_index, f, indent=2, ensure_ascii=False)
print(f"\n✅ Pack exporté: {pack_dir.name}")
print(f"📁 {len(pack_index['resources'])} ressources incluses")
else:
print("\n⏭️ Export désactivé")
print("\n" + "=" * 50)
print("✅ Notebook Histoire-Géographie terminé!")
print("🗺️ Ressources pédagogiques prêtes à l'emploi")
print("=" * 50)
⏭️ Export désactivé
==================================================
✅ Notebook Histoire-Géographie terminé!
🗺️ Ressources pédagogiques prêtes à l'emploi
==================================================
Exercice 3 : Comparaison visuelle “avant/après” d’un site historique
Les reconstructions du Colisee et de Versailles montrent les sites dans leur etat d’origine. L’objectif est de créer une fonction de comparaison visuelle qui genere deux versions d’un même lieu (etat historique et etat actuel) et les affiche cote a cote.
- Créer une fonction qui genere le prompt pour l’etat historique et l’etat actuel d’un site
- Implementer un affichage cote a cote avec matplotlib (subplots 1x2)
- Ajouter des annotations pedagogiques (dates, événements cles, changements architecturaux)
def build_before_after_prompts(site_name: str, historical_period: str) -> dict:
"""
Genere les prompts pour la comparaison avant/apres d'un site historique.
# Indice : Le prompt "avant" decrit le site dans sa gloire d'epoque
# Le prompt "apres" decrit le site tel qu'il apparaît aujourd'hui
# (ruines, restauration, environnement moderne)
Args:
site_name: Nom du site (ex: "Parthenon", "Machu Picchu", "Pont du Gard")
historical_period: Periode historique de reference
Returns:
Dictionnaire avec 'historical_prompt', 'modern_prompt', 'annotations'
"""
# TODO etudiant : implementer la generation des prompts avant/apres
pass
def display_before_after(hist_image, modern_image, site_name: str, annotations: list = None):
"""
Affiche deux images cote a cote avec annotations pedagogiques.
# Indice : Utilisez plt.subplots(1, 2, figsize=(20, 10))
# Ajoutez un titre global et des sous-titres pour chaque image
Args:
hist_image: Image PIL de l'etat historique
modern_image: Image PIL de l'etat actuel
site_name: Nom du site pour le titre
annotations: Liste d'annotations pedagogiques optionnelles
"""
# TODO etudiant : implementer l'affichage comparatif
pass
# Test avec le Parthenon
comparison = build_before_after_prompts("Parthenon", "Antiquite grecque")
print(f"Exercice a completer : comparaison avant/apres ({type(comparison)})")Exercice a completer : comparaison avant/apres (<class 'NoneType'>)