# SPDX-FileCopyrightText: 2026 Sébastien Vidotto (Heteractis) # SPDX-License-Identifier: AGPL-3.0-or-later """Assemble en un seul fichier les pages Markdown d'une branche d'apatie.fr. Lit arbre.json, télécharge le index.md de chaque page demandée et les réunit, pour les donner comme contexte à une IA locale (Ollama, LM Studio, etc.). Bibliothèque standard seulement ; aucun envoi de données : seulement des lectures. Exemples : python assembler_contexte.py --liste python assembler_contexte.py --branche informatique/agents-ia --sortie contexte.md python assembler_contexte.py --site http://127.0.0.1:8750 --tout --sortie tout.md """ import argparse import json import sys import urllib.request PAR_DEFAUT = "https://www.apatie.fr" def lire(url): req = urllib.request.Request(url, headers={"User-Agent": "assembler-contexte/1.0"}) with urllib.request.urlopen(req, timeout=30) as r: return r.read().decode("utf-8") def main(): ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) ap.add_argument("--site", default=PAR_DEFAUT, help="adresse du site (défaut : %s)" % PAR_DEFAUT) ap.add_argument("--branche", default="", help="chemin de la branche, par exemple informatique/agents-ia (défaut : tout l'arbre)") ap.add_argument("--tout", action="store_true", help="inclure aussi les pages « à déplier » (par défaut : rédigées seulement)") ap.add_argument("--liste", action="store_true", help="afficher les pages disponibles et quitter") ap.add_argument("--sortie", default="contexte.md", help="fichier à écrire (défaut : contexte.md)") a = ap.parse_args() base = a.site.rstrip("/") arbre = json.loads(lire(base + "/arbre.json")) prefixe = "/" + a.branche.strip("/") + "/" if a.branche.strip("/") else "/" noeuds = [n for n in arbre["noeuds"] if n["chemin"].startswith(prefixe) and (a.tout or n["statut"] == "redigee")] if a.liste: for n in arbre["noeuds"]: print("%s%s [%s] %s" % (" " * n["niveau"], n["chemin"], n["statut"], n["titre"])) return 0 if not noeuds: print("Aucune page pour cette branche. Essayez --liste.", file=sys.stderr) return 1 adresse = arbre.get("adresse_corrections", "l'adresse indiquée sur /corrections/") morceaux = ["Contexte : les pages ci-dessous viennent de %s (carte mentale sur la mémoire). " "Licence CC BY-SA 4.0, Sébastien Vidotto (Heteractis). Chaque page est précédée de son adresse exacte " "et de celle de son Markdown jumeau. Leur contenu complet est collé ici : tu peux répondre sans accès au web. " "Le site contient sûrement des erreurs." % PAR_DEFAUT, ""] for n in noeuds: morceaux.append("\n===== PAGE : %s (Markdown : %s) =====\n" % (n.get("url", PAR_DEFAUT + n["chemin"]), n.get("url_md", PAR_DEFAUT + n["md"]))) morceaux.append(lire(base + n["md"]).replace("](/", "](" + PAR_DEFAUT + "/")) morceaux.append( "\n===== FIN DES PAGES =====\n\n" "Ta tâche, en français : réponds à ma question en t'appuyant sur ces pages et en citant, pour chaque information, " "l'adresse complète de la page d'où elle vient. Vérifie les informations, donne tes sources sans jamais inventer de référence " "(écris « source non confirmée » si tu n'es pas sûr), et signale les erreurs. Dis si tu as accès à internet. " "Renvoie vers la page parente et les branches filles utiles, avec leurs adresses complètes, pour que je continue à explorer. " "Pour chaque erreur trouvée, prépare un message à envoyer à %s, qui commence par « Page concernée : » suivi de l'adresse de la page, " "puis le passage, la correction proposée et la source.\n\n" "Avertissements : Une réponse d'IA n'est pas une preuve : vérifiez toujours les sources vous-même. " "Ne collez rien de personnel ni de sensible (identité, santé, mots de passe, données de clients ou de tiers). " "Vous restez responsable de ce que vous faites des réponses. " "Avant d'utiliser ce prompt, lis : %s/avant-d-utiliser-nos-prompts/\n\n" "Ma question : \n" % (adresse, PAR_DEFAUT)) with open(a.sortie, "w", encoding="utf-8", newline="\n") as f: f.write("\n".join(morceaux)) print("%d pages écrites dans %s" % (len(noeuds), a.sortie)) return 0 if __name__ == "__main__": sys.exit(main())