Les entreprises produisent chaque semaine une quantité impressionnante de documents : rapports d’activité, études de marché, comptes rendus de réunion, audits techniques, bilans financiers, analyses concurrentielles. Ces documents peuvent faire des dizaines ou des centaines de pages. Personne ne les lit en entier. Et pourtant, ils contiennent souvent des informations critiques qui influencent des décisions importantes.
La résumé automatique change la donne. En quelques secondes, un modèle de langage peut extraire l’essentiel d’un document long, identifier les décisions importantes, les chiffres clés et les points d’action, et présenter tout cela dans un format lisible et exploitable.
Mais résumer automatiquement un long rapport sans perdre les informations clés est un défi technique non trivial. Ce tutoriel vous guide à travers une méthode fiable : le résumé hiérarchique avec validation des passages critiques.
Comprendre les défis du résumé de documents longs
La résumé automatique souffre d’un problème fondamental : les modèles de langage ont une fenêtre de contexte limitée. Si votre rapport fait 50 pages, vous ne pouvez pas le fournir entièrement à GPT-4 ou à un modèle local en une seule fois.
Le problème de la fenêtre de contexte
La plupart des modèles acceptent entre 8 000 et 128 000 tokens. Un rapport de 100 pages fait environ 30 000 mots, soit 40 000 tokens. Même les modèles avec de grandes fenêtrès ont tendance à « oublier » les informations du début quand le document est très long.
Le problème de la perte d’information
Un résumé naïf génère souvent un texte fluide mais superficiel. Les détails importants, les chiffres précis, les noms propres et les décisions actées sont souvent les premiers à disparaître. C’est acceptable pour un article de blog, pas pour un rapport d’audit ou une étude de marché.
La solution : le résumé hiérarchique
L’approche la plus fiable consiste à :
- Découper le rapport en sections
- Résumer chaque section indépendamment
- Extraire les points critiques (chiffres, décisions, actions)
- Consolider les résumés en un résumé final
- Vérifier la cohérence et la complétude
💡 Conseil : ne résumez jamais directement un document de plus de 20 pages en un seul prompt. Le modèle produit un résumé « lisse » qui semble complet mais qui omet systématiquement les détails techniques importants.
Préparer l’environnement et extraire le texte
Installation des dépendances
pip install pymupdf requests tiktoken
Extraction du texte par sections
import fitz # PyMuPDF
import re
def extract_sections_from_pdf(pdf_path: str) -> list[dict]:
"""Extrait le texte du PDF organisé par sections/chapitres."""
doc = fitz.open(pdf_path)
sections = []
current_section = {"title": "Introduction", "content": "", "pages": []}
for page_num, page in enumerate(doc):
text = page.get_text("text", sort=True)
# Détecter les titres de section (heuristique simple)
lines = text.split('\n')
for line in lines:
line = line.strip()
if not line:
continue
# Heuristique : ligne courte en majuscules = titre potentiel
if (len(line) < 80 and
(line.isupper() or line.startswith(('CHAPITRE', 'SECTION', '1.', '2.', '3.', 'PARTIE')))):
if current_section["content"].strip():
sections.append(current_section.copy())
current_section = {"title": line, "content": "", "pages": [page_num + 1]}
else:
current_section["content"] += line + " "
if page_num + 1 not in current_section["pages"]:
current_section["pages"].append(page_num + 1)
if current_section["content"].strip():
sections.append(current_section)
return sections
# Utilisation
sections = extract_sections_from_pdf("rapport_annuel.pdf")
for s in sections:
print(f"Section: {s['title']} | {len(s['content'])} chars | Pages: {s['pages']}")
Résumer chaque section indépendamment
Module de résumé par section
import requests
def summarize_section(section: dict, model="gemma3") -> dict:
"""Résume une section en préservant les informations clés."""
prompt = f"""Tu es un expert en analyse de documents professionnels.
Résume la section suivante en respectant ces règles STRICTES :
1. Conserve TOUS les chiffres, pourcentages et statistiques mentionnés
2. Liste les décisions et recommandations de manière explicite
3. Identifie les actions à entreprendre et leurs responsables si mentionnés
4. Mentionne tous les noms propres importants (personnes, entreprises, projets)
5. Le résumé doit faire entre 150 et 300 mots maximum
6. Utilise des puces pour les points importants
Section : {section['title']}
Contenu :
{section['content'][:4000]} # Limiter à ~1000 tokens par section
Résumé structuré :"""
response = requests.post(
"http://localhost:11434/api/chat",
json={
"model": model,
"messages": [{"rôle": "user", "content": prompt}],
"stream": False
},
timeout=120
)
summary = response.json()["message"]["content"]
return {
"title": section["title"],
"pages": section["pages"],
"summary": summary,
"original_length": len(section["content"])
}
# Résumer toutes les sections
summaries = []
for i, section in enumerate(sections):
print(f"Résumé section {i+1}/{len(sections)}: {section['title'][:50]}")
summary = summarize_section(section)
summaries.append(summary)
print(f"✅ {len(summaries)} sections résumées")
Gérer les sections très longues avec découpage récursif
def chunk_text(text: str, max_chars: int = 4000, overlap: int = 200) -> list[str]:
"""Découpe un texte long en morceaux avec chevauchement."""
chunks = []
start = 0
while start < len(text):
end = start + max_chars
chunk = text[start:end]
# Couper à la fin d'une phrase si possible
last_period = chunk.rfind('.')
if last_period > max_chars * 0.7:
chunk = chunk[:last_period + 1]
end = start + last_period + 1
chunks.append(chunk.strip())
start = end - overlap
return chunks
def summarize_long_section(section: dict, model="gemma3") -> dict:
"""Résume une section très longue avec découpage récursif."""
content = section["content"]
if len(content) <= 4000:
return summarize_section(section)
# Découper en chunks
chunks = chunk_text(content, max_chars=3500, overlap=150)
# Résumer chaque chunk
chunk_summaries = []
for chunk in chunks:
temp_section = {**section, "content": chunk}
result = summarize_section(temp_section)
chunk_summaries.append(result["summary"])
# Consolider les résumés des chunks
combined = "\n\n".join(chunk_summaries)
consolidation_section = {**section, "content": combined}
final = summarize_section(consolidation_section)
return {**final, "chunks_processed": len(chunks)}
💡 Conseil : pour les sections très techniques (tableaux financiers, données chiffrées denses), utilisez un prompt spécialisé qui demande explicitement d'extraire tous les chiffres sous forme structurée avant de résumer. Cela évite la perte des données quantitatives.
Consolider en un résumé exécutif final
Générer le résumé exécutif
def generate_executive_summary(summaries: list[dict], model="gemma3") -> str:
"""Génère un résumé exécutif complet à partir des résumés de sections."""
# Construire le contexte consolidé
context_parts = []
for s in summaries:
pages_str = f"Pages {s['pages'][0]}-{s['pages'][-1]}" if len(s['pages']) > 1 else f"Page {s['pages'][0]}"
context_parts.append(f"## {s['title']} ({pages_str})\n{s['summary']}")
consolidated = "\n\n".join(context_parts)
prompt = f"""Tu es un analyste senior chargé de rédiger un résumé exécutif professionnel.
À partir des résumés de sections ci-dessous, rédige un résumé exécutif complet comprenant :
1. **Synthèse générale** (3-5 phrases, vision d'ensemble)
2. **Points clés et chiffres importants** (liste structurée)
3. **Décisions et recommandations principales** (liste numérotée)
4. **Actions à entreprendre** (tableau : quoi | qui | quand si mentionné)
5. **Points de vigilance** (risques ou points critiques)
Le résumé exécutif doit faire entre 400 et 600 mots.
Garde un ton professionnel et factuel.
N'ajoute aucune information non présente dans les résumés fournis.
Résumés des sections :
{consolidated}
Résumé exécutif :"""
response = requests.post(
"http://localhost:11434/api/chat",
json={
"model": model,
"messages": [{"rôle": "user", "content": prompt}],
"stream": False
},
timeout=120
)
return response.json()["message"]["content"]
executive_summary = generate_executive_summary(summaries)
print(executive_summary)
Extraire et valider les informations critiques
Un résumé fluide peut cacher des omissions importantes. La validation est une étape clé.
Extraction automatique des informations critiques
def extract_critical_info(full_text: str, model="gemma3") -> dict:
"""Extrait les informations critiques qui ne doivent pas être perdues."""
prompt = f"""Analyse ce texte et extrais UNIQUEMENT les informations suivantes, sous forme structurée :
- Tous les chiffres et statistiques (avec leur contexte)
- Toutes les dates et échéances mentionnées
- Tous les noms de personnes et leurs rôles
- Toutes les décisions formelles prises
- Tous les montants financiers
- Toutes les actions assignées avec responsable
Réponds en JSON strict :
{{
"chiffres": ["stat1", "stat2"],
"dates": ["date1", "date2"],
"personnes": ["nom1 - rôle", "nom2 - rôle"],
"décisions": ["decision1", "decision2"],
"montants": ["montant1 - contexte"],
"actions": ["action1 - responsable", "action2 - responsable"]
}}
Texte à analyser :
{full_text[:8000]}"""
response = requests.post(
"http://localhost:11434/api/chat",
json={
"model": model,
"messages": [{"rôle": "user", "content": prompt}],
"stream": False
},
timeout=120
)
import json, re
text = response.json()["message"]["content"]
# Extraire le JSON
json_match = re.search(r'\{.*\}', text, re.DOTALL)
if json_match:
try:
return json.loads(json_match.group())
except:
pass
return {"raw": text}
# Valider que le résumé contient les infos critiques
critical_info = extract_critical_info(full_text)
print("Informations critiques extraites:", critical_info)
Vérification de cohérence
def validate_summary_completeness(summary: str, critical_info: dict) -> dict:
"""Vérifie que le résumé mentionne les informations critiques."""
issues = []
for chiffré in critical_info.get("chiffres", []):
# Extraire juste le nombre
numbers = re.findall(r'\d+[.,]?\d*%?', chiffré)
for num in numbers[:1]: # Vérifier le premier nombre de chaque stat
if num not in summary:
issues.append(f"Chiffre manquant dans le résumé : {chiffré}")
for décision in critical_info.get("décisions", []):
# Vérifier qu'un mot-clé de la décision est dans le résumé
keywords = [w for w in décision.split() if len(w) > 5][:3]
if keywords and not any(kw.lower() in summary.lower() for kw in keywords):
issues.append(f"Décision potentiellement absente : {décision[:80]}")
return {
"is_complete": len(issues) == 0,
"missing_items": issues,
"completeness_score": max(0, 1 - len(issues) / max(1, len(critical_info.get("chiffres", [])) + len(critical_info.get("décisions", []))))
}
validation = validate_summary_completeness(executive_summary, critical_info)
print(f"Complétude: {validation['completeness_score']:.0%}")
if validation['missing_items']:
print("Points manquants:", validation['missing_items'])
Automatiser et créer des rapports formatés
Script complet d'automatisation
def summarize_report(pdf_path: str, output_path: str = None) -> dict:
"""Pipeline complet : PDF → résumé exécutif validé."""
print(f"📄 Traitement de : {pdf_path}")
# 1. Extraction
sections = extract_sections_from_pdf(pdf_path)
full_text = " ".join([s["content"] for s in sections])
print(f" {len(sections)} sections extraites")
# 2. Résumé par sections
summaries = []
for i, section in enumerate(sections):
summary = summarize_long_section(section)
summaries.append(summary)
print(f" ✓ Section {i+1}/{len(sections)} résumée")
# 3. Résumé exécutif
executive = generate_executive_summary(summaries)
# 4. Extraction des infos critiques
critical = extract_critical_info(full_text)
# 5. Validation
validation = validate_summary_completeness(executive, critical)
result = {
"document": pdf_path,
"sections_count": len(sections),
"executive_summary": executive,
"section_summaries": summaries,
"critical_info": critical,
"validation": validation
}
# 6. Export
if output_path:
import json
with open(output_path, 'w', encoding='utf-8') as f:
json.dump(result, f, ensure_ascii=False, indent=2)
print(f" ✅ Rapport sauvegardé : {output_path}")
return result
# Utilisation
result = summarize_report("rapport_annuel_2025.pdf", "resume_rapport_annuel.json")
print("\n=== RÉSUMÉ EXÉCUTIF ===")
print(result["executive_summary"])
💡 Conseil : planifiez une étape de relecture humaine pour tous les résumés de documents à fort impact (audits, rapports financiers, études réglementaires). La validation automatique détecte les omissions évidentes, mais un œil humain reste indispensable pour juger de la pertinence et de la nuance.
Conclusion
Résumer automatiquement de longs rapports sans perdre les informations clés est un défi solvable avec la bonne architecture. Le résumé hiérarchique — sections → consolidation → résumé exécutif — combiné à l'extraction et à la validation des informations critiques, donne des résultats fiables et professionnels.
Cette approche est adaptée à tous les contextes : rapports d'audit, études de marché, bilans financiers, documentations techniques ou comptes rendus de réunion. Elle peut fonctionner entièrement en local avec Ollama, garantissant la confidentialité des données sensibles.
La clé du succès reste la validation : un résumé IA non contrôlé peut être fluide mais lacunaire. Un processus de validation, même léger, transforme un outil expérimental en solution professionnelle fiable.
Vous voulez maîtriser l'automatisation des processus documentaires avec l'IA ? Retrouvez nos tutoriels complets sur ITSkillsCenter.io pour développer des compétences concrètes et directement applicables.
Resumer un rapport long sans perdre l essentiel — la discipline qui fait la difference
Resumer un rapport de 50 pages en 1 page de synthese n est pas une tache d ecriture. C est une tache d extraction et de hierarchisation. La difficulte n est pas de raccourcir — c est de garder les bons 2 pour cent et de retirer les 98 pour cent de detail. Les LLM modernes (Claude, GPT-4, Gemini) excellent dans cette tache quand on leur donne le bon brief.
La methode qui produit un resume utilisable et fiable comporte trois etapes : (1) clarifier la question a laquelle le resume doit repondre, (2) instructer le LLM avec un cadre structure, (3) verifier les chiffres et citations contre le source.
Le prompt structure qui marche
Un prompt qui produit un resume de qualite suit cette trame : Voici un rapport de N pages sur le sujet X. Mon objectif est d en extraire ce qu un decideur a 10 minutes a investir doit absolument savoir pour prendre une decision. Produis : (1) 3 phrases de synthese executive, (2) les 5 chiffres cles avec source, (3) les 3 implications pour notre activite, (4) les 2 points de vigilance ou zones d incertitude. Ne fais aucune extrapolation au-dela du rapport. Si une information manque, dis-le explicitement.
Trois principes derriere ce prompt. La question explicite oriente l extraction : un meme rapport produit des resumes differents selon qu on veut decider un investissement ou comprendre un risque reglementaire. Le format structure en sections numerotees force le LLM a ne pas diluer dans un texte continu. La contrainte anti-hallucination finale (ne fais aucune extrapolation) reduit drastiquement les inventions.
Pour les rapports trop longs pour la fenetre de contexte
Claude Pro accepte 200 000 tokens (environ 500 pages). ChatGPT Plus accepte 128 000 tokens. Au-dela, le pattern map-reduce est necessaire. (1) Decouper le document en sections de 50-100 pages. (2) Resumer chaque section avec le meme prompt. (3) Combiner les resumes en un meta-resume final. Cette technique fonctionne pour des rapports de 1000+ pages mais demande 5-10 minutes de processing au lieu de 2 minutes pour un rapport qui rentre directement.
Outils dedies : LlamaIndex et LangChain offrent des chaines map-reduce pretes a l emploi. Pour des usages reguliers, automatiser via un script Python de 50 lignes qui prend un PDF et produit le resume final. Cout typique : 0,50 a 5 USD par rapport selon longueur.
Verifier le resultat avant utilisation
La discipline qui distingue un resume utilisable d un piege : verifier chaque chiffre cite et chaque citation contre le document source. Les LLM hallucinent occasionnellement sur les chiffres, surtout sur les totaux, pourcentages, et evolutions. Verification typique : 3-5 minutes par resume, qui evitent les erreurs en reunion.
La pratique professionnelle : demander au LLM de citer la page source pour chaque affirmation chiffree. Cela facilite la verification croisee et alerte si l LLM ne peut pas pointer une page (signal probable d hallucination).
Cas d usage concrets
Rapports analystes financiers. Rapport Goldman Sachs de 80 pages sur un secteur → synthese de 1 page avec les 3 thematiques majeures et les chiffres cles. Permet de digerer 5 rapports concurrents par semaine au lieu d un seul.
Etudes de marche. Etude PwC ou McKinsey de 150 pages → resume oriente sur une question metier precise (Quel est le potentiel de croissance du marche X en zone Y a horizon 2028 ?). Les details non pertinents sont filtres, les implications sont mises en evidence.
Rapports administratifs et reglementaires. Rapport ANSSI sur les menaces 2025 ou rapport NIS2 → synthese des points qui touchent l organisation, des obligations qui s appliquent, et des actions a anticiper.
Comptes rendus de reunions longues. Transcription Otter de 3 heures de reunion → resume avec decisions, actions, points reportes. Le LLM extrait la structure que la transcription brute n a pas.
Documents juridiques. Contrat de 30 pages → synthese des clauses defavorables, des engagements, des conditions de sortie. Toujours faire valider par un juriste avant signature, mais le pre-traitement IA accelere la revue de 70-80 pour cent.
FAQ
Le resume IA peut-il remplacer la lecture complete d un rapport critique ?
Non. Pour les decisions importantes, le resume IA est un acceleurateur, pas un substitut. Il identifie les sections a lire en profondeur. Comme un sommaire augmente, pas comme une dispense de lecture.
Quelle taille de resume produire ?
Regle empirique : 1-2 pour cent du document source. Un rapport de 100 pages → 1-2 pages de resume. En dessous, on perd des nuances importantes. Au-dessus, on dilue ce qui doit etre garde.
Comment garder confidentielles les donnees du rapport ?
Utiliser exclusivement Claude Pro/Team ou ChatGPT Enterprise pour les documents confidentiels. Pour les documents tres sensibles, un modele open-source local (Ollama avec Llama 3.1 70B) ne fait pas sortir les donnees du reseau interne.
Comment automatiser pour les rapports recurrents ?
Un script Python qui : (1) telecharge le PDF via API ou inbox dediee, (2) extrait le texte avec PyPDF2 ou pdfplumber, (3) appelle l API Claude/OpenAI avec le prompt structure, (4) publie le resume dans Slack ou par email. 100-200 lignes de code, deployable en quelques heures.
References
- Anthropic Claude — claude.ai
- LlamaIndex (map-reduce) — llamaindex.ai
- LangChain — langchain.com
- pdfplumber (extraction texte PDF) — github.com/jsvine/pdfplumber
- Anthropic prompt engineering — docs.anthropic.com/prompt-engineering