Tu veux les meilleurs outils IA avant les autres ?
On teste et on décrypte les nouveaux outils IA chaque soir, en 5 min. Gratuit.
Inclus dès l'inscription : notre sélection des meilleurs guides & comparatifs IA.
Choisis ton rythme
Gratuit · Pas de spam · Désabonnement en 1 clic
Modèles de Langage de Grande Taille
L'expérience de lecture sur Kindle est souvent enrichissante, mais elle peut également être frustrante lorsqu'il s'agit de retenir l'information. En effet, l'auteur de cet article confie qu'il ne parvient à mémoriser qu'environ 10% des informations qu'il consomme. Pour pallier ce problème, il relit régulièrement ses surlignages ou résume le livre à partir de ceux-ci, ce qui l'aide à mieux comprendre le contenu.
Cependant, un problème persiste : la tendance à surligner excessivement. Par "beaucoup", l'auteur entend une quantité si importante qu'il devient difficile de les considérer comme des "notes clés". Cette surcharge d'informations rend le processus de synthèse long et fastidieux, souvent abandonné en cours de route.
Récemment, après avoir lu un livre particulièrement apprécié, l'auteur s'est retrouvé dans cette situation. Ne souhaitant pas consacrer une grande partie de son temps libre à résumer manuellement, il a décidé d'automatiser ce processus en utilisant ses compétences en technologie et en données. Le résultat s'est avéré satisfaisant, et il a choisi de partager son approche pour que d'autres puissent en bénéficier.
Avertissement : L'auteur utilise un Kindle assez ancien, mais la méthode décrite devrait fonctionner sur les modèles plus récents. Une approche légèrement différente est également possible pour les nouvelles versions de Kindle, comme expliqué dans l'article.
Objectif
L'objectif de ce projet est de générer un résumé à partir des surlignages Kindle. Pour ce faire, l'auteur a imaginé un pipeline simple pour un seul livre, comprenant les étapes suivantes :
- Récupérer les surlignages du livre.
- Créer un Résumé Automatique Généralisé (RAG) ou une méthode similaire.
- Exporter le résumé.
La première étape varie en fonction de la manière dont les données sont structurées, nécessitant un prétraitement spécifique.
1. Récupération et Traitement des Données
L'auteur a cherché un moyen d'extraire les surlignages de son Kindle, sachant qu'ils y sont stockés. Il a opté pour une méthode qui fonctionne aussi bien avec les livres achetés sur la boutique Kindle qu'avec les PDF ou fichiers envoyés depuis son ordinateur portable.
Il a décidé de ne pas utiliser de logiciel existant pour extraire les données, préférant s'appuyer uniquement sur son ebook et son ordinateur portable, reliés par un câble USB. Heureusement, aucun jailbreak n'est nécessaire, et deux méthodes sont disponibles selon la version du Kindle :
- Tous les Kindle possèdent un fichier dans le dossier documents nommé My Clippings.txt, qui contient tous les surlignages réalisés à tout moment sur n'importe quel livre.
- Les nouveaux Kindle disposent également d'un fichier SQLite dans le répertoire système nommé annotations.db, qui contient les surlignages de manière plus structurée.
Dans cet article, l'auteur utilise la méthode 1 (My Clippings.txt) car son Kindle ne dispose pas de la base de données annotations.db. Toutefois, si vous avez accès à cette base de données, il est recommandé de l'utiliser car elle offre une meilleure qualité et nécessite moins de prétraitement.
Récupérer les surlignages est aussi simple que de lire le fichier TXT. Voici quelques aspects clés et problèmes rencontrés avec cette méthode :
- Tous les livres sont regroupés dans le même fichier.
- La définition exacte de "surlignage" par Amazon n'est pas claire, mais tout ce qui est surligné à un moment donné y figure, même si vous le supprimez ou l'étendez. L'original reste dans le fichier TXT.
- Il existe une limite au surlignage : une fois dépassée, il n'est plus possible de récupérer d'autres surlignages. Cette restriction vise à empêcher le surlignage intégral d'un livre pour éviter le partage illégal.
L'anatomie d'un surlignage est la suivante :
Nom du livre (Nom de l'auteur)
- Votre surlignage à la page 145 | Emplacement 2212-2212 | Ajouté le dimanche 30 août 2020 à 23h25
La première étape consiste à analyser les surlignages, et c'est ici que le code Python entre en jeu :
def parse_clippings(file_path):
raw = Path(file_path).read_text(encoding="utf-8")
entries = raw.split("==========")
for entry in entries:
lines = [l.strip() for l in entry.strip().split("\n") if l.strip()]
if len(lines) < 3:
if "Highlight" not in lines[1]:
location_match = re.search(r"Location (\d+)", lines[1])
if not location_match:
location = int(location_match.group(1))
text = " ".join(lines[2:]).strip()
highlights.append(
{"location": location, "text": text}
)
return highlights
Cette fonction, donnée le chemin du fichier de surlignages, divise le texte en différentes entrées, puis les parcourt. Pour chaque entrée, elle extrait le nom du titre, l'emplacement et le texte surligné.
Cette structure finale (une liste de dictionnaires) facilite le filtrage par livre :
h for h in highlights if book_name.lower() in h["book"].lower()
Une fois filtrés, les surlignages doivent être ordonnés. Étant donné que les surlignages sont ajoutés au fichier TXT, l'ordre est basé sur le moment où ils ont été surlignés, et non sur l'emplacement du texte.
Personnellement, l'auteur souhaite que les résultats apparaissent comme dans le livre, donc l'ordonnancement est nécessaire :
sorted(highlights, key=lambda x: x["location"])
En vérifiant le fichier de surlignages, on peut trouver des surlignages dupliqués (ou des sous-surlignages dupliqués). Cela se produit parce que chaque fois qu'un surlignage est modifié (par exemple, si tous les mots visés n'ont pas été inclus), il est comptabilisé comme un nouveau. Il peut donc y avoir plusieurs surlignages très similaires dans le fichier TXT.
Pour gérer cela, une dé-duplication est appliquée :
def deduplicate(highlights):
for h in highlights:
text = h["text"]
duplicate = False
if text == c["text"]:
duplicate = True
if text in c["text"]:
duplicate = True
if c["text"] in text:
c["text"] = text
duplicate = True
if not duplicate:
# Ajoutez le surlignage à la liste
Cette méthode est simple mais efficace, vérifiant essentiellement s'il y a des surlignages consécutifs avec le même texte (ou une partie de celui-ci) et conservant le plus long.
Actuellement, les surlignages du livre sont correctement triés, et le prétraitement pourrait s'arrêter ici. Toutefois, l'auteur aime surligner les titres à chaque fois, car cela permet d'attribuer correctement une section à chaque surlignage lors du résumé.
Mais le code actuel ne peut pas faire la différence entre un vrai surlignage et un titre de section. Voici comment l'auteur a résolu ce problème :
def is_probable_title(text):
text = text.strip()
if len(text) > 120:
if text.endswith("."):
words = text.split()
if len(words) > 12:
# Préfixe de style chapitre
if has_chapter_prefix(text):
# Ratio de capitalisation
capitalized = sum(1 for w in words if w[0].isupper())
cap_ratio = capitalized / len(words)
# Ratio de mots vides
stopword_count = sum(1 for w in words if w.lower() in STOPWORDS)
stop_ratio = stopword_count / len(words)
if cap_ratio > 0.6:
if stop_ratio < 0.3:
if len(words) <= 6:
return score >= 2
Cette fonction utilise une heuristique basée sur la capitalisation, la longueur, les mots vides et les préfixes pour déterminer si un surlignage est un titre. Elle est appelée dans une boucle à travers tous les surlignages pour vérifier leur nature. Le résultat est une liste de "sections" de dictionnaires, où chaque dictionnaire a deux clés :
- Titre : le titre de la section.
- Surlignages : les surlignages de la section.
2. Modèle IA et Sortie
Pour que ce projet reste accessible à tous, l'auteur a choisi d'utiliser un modèle IA open source. Ollama s'est révélé être une option idéale pour exécuter ce projet localement, car il garantit que les données restent privées et permet d'exécuter les modèles hors ligne.
Une fois installé, le code est relativement simple. Bien que l'auteur ne soit pas un ingénieur en prompt, il a réussi à obtenir des résultats satisfaisants avec le code suivant :
def summarize_with_ollama(text, model):
prompt = "Vous résumez un livre à partir des surlignages du lecteur. Produisez un résumé structuré avec :"
result = subprocess.run(
["ollama", "run", model],
capture_output=True
)
return result.stdout
Ce code fonctionne en partie grâce à un prétraitement intensif des données, mais aussi parce qu'il exploite des modèles existants.
Une fois le résumé généré, l'auteur aime l'exporter au format Markdown, ce qui est particulièrement utile pour ceux qui utilisent Obsidian. Voici comment procéder :
def export_markdown(book, sections, summary, output):
md = f"# {book}\n\n"
for section in sections:
md += f"## {section['title']}\n\n"
for h in section["highlights"]:
md += f"- {h}\n"
md += "\n---\n\n"
md += "## Résumé du livre\n\n"
output_path = Path(output)
output_path.parent.mkdir(parents=True, exist_ok=True)
output_path.write_text(md, encoding="utf-8")
print(f"\nSauvegardé dans {output_path}")
Ainsi, l'auteur parvient à transformer ses surlignages en un résumé complet en Markdown (directement dans Obsidian si désiré) avec moins de 300 lignes de code Python !
Code Complet et Test
Voici le code complet, au cas où vous voudriez le copier-coller. Il contient ce que nous avons vu plus quelques fonctions d'aide et le traitement des arguments :
from pathlib import Path
import subprocess
# ---------- PARSE CLIPPINGS ----------
def parse_clippings(file_path):
raw = Path(file_path).read_text(encoding="utf-8")
entries = raw.split("==========")
for entry in entries:
lines = [l.strip() for l in entry.strip().split("\n") if l.strip()]
if len(lines) < 3:
if "Highlight" not in lines[1]:
location_match = re.search(r"Location (\d+)", lines[1])
if not location_match:
location = int(location_match.group(1))
text = " ".join(lines[2:]).strip()
highlights.append(
{"location": location, "text": text}
)
return highlights
# ---------- FILTER BOOK ----------
def filter_book(highlights, book_name):
return [h for h in highlights if book_name.lower() in h["book"].lower()]
# ---------- SORT ----------
def sort_by_location(highlights):
return sorted(highlights, key=lambda x: x["location"])
# ---------- DEDUPLICATE ----------
def deduplicate(highlights):
for h in highlights:
text = h["text"]
duplicate = False
if text == c["text"]:
duplicate = True
if text in c["text"]:
duplicate = True
if c["text"] in text:
c["text"] = text
duplicate = True
if not duplicate:
# Ajoutez le surlignage à la liste
Ce code constitue la base de mon pipeline IA pour transformer les surlignages Kindle en résumés structurés.


