551 lines
24 KiB
Python
551 lines
24 KiB
Python
#!/usr/bin/env python3
|
|
"""Génère un PDF expliquant l'architecture Honcho + Hermes"""
|
|
|
|
from reportlab.lib.pagesizes import A4
|
|
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
|
from reportlab.lib.units import mm, cm
|
|
from reportlab.lib.colors import HexColor, black, white
|
|
from reportlab.lib.enums import TA_LEFT, TA_CENTER
|
|
from reportlab.platypus import (
|
|
SimpleDocTemplate, Paragraph, Spacer, PageBreak,
|
|
Table, TableStyle, ListFlowable, ListItem, KeepTogether
|
|
)
|
|
from reportlab.platypus.flowables import HRFlowable
|
|
from reportlab.lib import colors
|
|
import os
|
|
|
|
OUTPUT = "/root/workspace/honcho-hermes-architecture.pdf"
|
|
|
|
# Couleurs
|
|
DARK = HexColor("#0f172a")
|
|
ACCENT = HexColor("#3b82f6")
|
|
GREEN = HexColor("#22c55e")
|
|
GRAY = HexColor("#64748b")
|
|
LIGHT = HexColor("#f1f5f9")
|
|
ORANGE = HexColor("#f59e0b")
|
|
|
|
doc = SimpleDocTemplate(
|
|
OUTPUT,
|
|
pagesize=A4,
|
|
topMargin=2*cm,
|
|
bottomMargin=2*cm,
|
|
leftMargin=2.5*cm,
|
|
rightMargin=2.5*cm,
|
|
)
|
|
|
|
styles = getSampleStyleSheet()
|
|
|
|
# Styles personnalisés
|
|
styles.add(ParagraphStyle(
|
|
"CoverTitle", parent=styles["Title"],
|
|
fontSize=28, leading=34, textColor=DARK,
|
|
spaceAfter=6*mm, alignment=TA_CENTER,
|
|
fontName="Helvetica-Bold"
|
|
))
|
|
styles.add(ParagraphStyle(
|
|
"CoverSub", parent=styles["Normal"],
|
|
fontSize=14, leading=18, textColor=GRAY,
|
|
spaceAfter=4*mm, alignment=TA_CENTER,
|
|
fontName="Helvetica"
|
|
))
|
|
styles.add(ParagraphStyle(
|
|
"SectionTitle", parent=styles["Heading1"],
|
|
fontSize=18, leading=22, textColor=DARK,
|
|
spaceBefore=10*mm, spaceAfter=4*mm,
|
|
fontName="Helvetica-Bold"
|
|
))
|
|
styles.add(ParagraphStyle(
|
|
"SubTitle", parent=styles["Heading2"],
|
|
fontSize=14, leading=18, textColor=ACCENT,
|
|
spaceBefore=6*mm, spaceAfter=3*mm,
|
|
fontName="Helvetica-Bold"
|
|
))
|
|
styles.add(ParagraphStyle(
|
|
"Body", parent=styles["Normal"],
|
|
fontSize=10, leading=14, textColor=HexColor("#334155"),
|
|
spaceAfter=3*mm,
|
|
fontName="Helvetica"
|
|
))
|
|
# "Code" style already exists in default stylesheet
|
|
styles.add(ParagraphStyle(
|
|
"MyBullet", parent=styles["Normal"],
|
|
fontSize=10, leading=14, textColor=HexColor("#334155"),
|
|
leftIndent=8*mm, spaceAfter=2*mm,
|
|
fontName="Helvetica"
|
|
))
|
|
styles.add(ParagraphStyle(
|
|
"MySmallNote", parent=styles["Normal"],
|
|
fontSize=8, leading=10, textColor=GRAY,
|
|
spaceAfter=2*mm, fontName="Helvetica-Oblique"
|
|
))
|
|
|
|
story = []
|
|
|
|
# ===== PAGE DE COUVERTURE =====
|
|
story.append(Spacer(1, 4*cm))
|
|
story.append(Paragraph("Honcho + Hermes", styles["CoverTitle"]))
|
|
story.append(Paragraph("Architecture & Déploiement", styles["CoverSub"]))
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(HRFlowable(width="60%", thickness=1, color=ACCENT))
|
|
story.append(Spacer(1, 5*mm))
|
|
story.append(Paragraph("Mémoire persistante cross-session pour Hermes Agent", styles["CoverSub"]))
|
|
story.append(Spacer(1, 2*cm))
|
|
story.append(Paragraph("Laurent Keller — Homelab 2026", styles["MySmallNote"]))
|
|
story.append(PageBreak())
|
|
|
|
# ===== TABLE DES MATIÈRES =====
|
|
story.append(Paragraph("Table des matières", styles["SectionTitle"]))
|
|
story.append(Spacer(1, 3*mm))
|
|
toc_items = [
|
|
"1. Qu'est-ce que Honcho ?",
|
|
"2. Architecture globale",
|
|
"3. Composants déployés",
|
|
"4. Flux de fonctionnement",
|
|
"5. Configuration Hermes",
|
|
"6. Commandes utiles",
|
|
"7. Schéma réseau",
|
|
"8. Dépannage",
|
|
]
|
|
for item in toc_items:
|
|
story.append(Paragraph(item, styles["MyBullet"]))
|
|
story.append(PageBreak())
|
|
|
|
# ===== 1. QU'EST-CE QUE HONCHO =====
|
|
story.append(Paragraph("1. Qu'est-ce que Honcho ?", styles["SectionTitle"]))
|
|
story.append(HRFlowable(width="100%", thickness=0.5, color=ACCENT))
|
|
story.append(Spacer(1, 3*mm))
|
|
|
|
story.append(Paragraph(
|
|
"Honcho est une infrastructure mémoire open-source (AGPL-3.0) développée par Plastic Labs. "
|
|
"Elle permet aux agents AI de construire une représentation persistante de l'utilisateur "
|
|
"à travers les sessions — contrairement à une mémoire fichier classique qui ne fait que "
|
|
"stocker du texte brut.",
|
|
styles["Body"]
|
|
))
|
|
|
|
story.append(Paragraph("Ce que Honcho apporte à Hermes :", styles["SubTitle"]))
|
|
bullets = [
|
|
"<b>Mémoire cross-session</b> — l'agent se souvient de qui vous êtes entre deux conversations",
|
|
"<b>Représentation utilisateur</b> — Honcho analyse les conversations et extrait des conclusions (préférences, patterns, style de communication)",
|
|
"<b>Dialectic engine</b> — un moteur de raisonnement en arrière-plan qui synthétise la mémoire",
|
|
"<b>Recherche sémantique</b> — retrouver des informations par similarité de sens, pas par mot-clé",
|
|
"<b>Multi-peers</b> — chaque profil Hermes a sa propre identité AI tout en partageant la vue utilisateur",
|
|
]
|
|
for b in bullets:
|
|
story.append(Paragraph(b, styles["MyBullet"]))
|
|
|
|
story.append(Spacer(1, 3*mm))
|
|
story.append(Paragraph("Le cœur du système :", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"1. <b>Store</b> — les conversations sont stockées dans PostgreSQL avec embeddings vectoriels<br/>"
|
|
"2. <b>Reason</b> — le Deriver (worker background) analyse les messages et met à jour la représentation<br/>"
|
|
"3. <b>Query</b> — Hermes interroge Honcho via 5 outils pour récupérer le contexte<br/>"
|
|
"4. <b>Inject</b> — le contexte est injecté dans le system prompt à chaque tour",
|
|
styles["Body"]
|
|
))
|
|
story.append(PageBreak())
|
|
|
|
# ===== 2. ARCHITECTURE GLOBALE =====
|
|
story.append(Paragraph("2. Architecture globale", styles["SectionTitle"]))
|
|
story.append(HRFlowable(width="100%", thickness=0.5, color=ACCENT))
|
|
story.append(Spacer(1, 3*mm))
|
|
|
|
story.append(Paragraph(
|
|
"Le déploiement s'appuie sur 3 VMs du homelab, interconnectées via le réseau 192.168.30.0/24 :",
|
|
styles["Body"]
|
|
))
|
|
|
|
# Tableau des VMs
|
|
vm_data = [
|
|
["VM", "IP", "Rôle", "Services"],
|
|
["Kellerflix\n(VM 101)", "192.168.30.10", "LLM & Embeddings", "Ollama\nnemotron-mini:4b\nnomic-embed-text"],
|
|
["postgres\n(LXC/VM)", "192.168.30.35", "Honcho Server", "Honcho API (:8000)\nHoncho Deriver\nPostgreSQL pgvector (:5434)"],
|
|
["redis\n(LXC/VM)", "192.168.30.36", "Cache", "Redis (:6379)"],
|
|
]
|
|
vm_table = Table(vm_data, colWidths=[3.5*cm, 3*cm, 3*cm, 5.5*cm])
|
|
vm_table.setStyle(TableStyle([
|
|
("BACKGROUND", (0, 0), (-1, 0), DARK),
|
|
("TEXTCOLOR", (0, 0), (-1, 0), white),
|
|
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
|
("FONTSIZE", (0, 0), (-1, -1), 9),
|
|
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
|
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
|
("GRID", (0, 0), (-1, -1), 0.5, GRAY),
|
|
("BACKGROUND", (0, 1), (-1, -1), LIGHT),
|
|
("TOPPADDING", (0, 0), (-1, -1), 6),
|
|
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
|
|
]))
|
|
story.append(vm_table)
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
story.append(Paragraph("Flux des données :", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"Hermes (LXC 112) → Honcho API (192.168.30.35:8000) → PostgreSQL pgvector<br/>"
|
|
"Honcho Deriver → Ollama (192.168.30.10:11434) pour LLM + embeddings<br/>"
|
|
"Honcho API → Redis (192.168.30.36:6379) pour cache",
|
|
styles["Body"]
|
|
))
|
|
story.append(PageBreak())
|
|
|
|
# ===== 3. COMPOSANTS DÉPLOYÉS =====
|
|
story.append(Paragraph("3. Composants déployés", styles["SectionTitle"]))
|
|
story.append(HRFlowable(width="100%", thickness=0.5, color=ACCENT))
|
|
story.append(Spacer(1, 3*mm))
|
|
|
|
# 3.1 Honcho API
|
|
story.append(Paragraph("3.1 Honcho API (FastAPI)", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"Serveur HTTP qui expose l'API REST de Honcho. Point d'entrée pour Hermes et le SDK Python. "
|
|
"Gère les sessions, peers, messages, et la recherche contextuelle.",
|
|
styles["Body"]
|
|
))
|
|
story.append(Paragraph(
|
|
"Port : 8000<br/>"
|
|
"Healthcheck : GET /health → {\"status\":\"ok\"}<br/>"
|
|
"Docker : honcho-api (build local depuis le Dockerfile du repo plastic-labs/honcho)",
|
|
styles["Body"]
|
|
))
|
|
|
|
# 3.2 Honcho Deriver
|
|
story.append(Paragraph("3.2 Honcho Deriver (Worker background)", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"Processus qui tourne en arrière-plan et analyse les messages stockés. "
|
|
"Il utilise le LLM configuré (nemotron-mini:4b) pour :",
|
|
styles["Body"]
|
|
))
|
|
bullets = [
|
|
"Extraire des conclusions sur l'utilisateur (préférences, habitudes)",
|
|
"Générer des résumés de sessions",
|
|
"Mettre à jour la représentation du peer",
|
|
"Alimenter le moteur dialectic pour honcho_reasoning",
|
|
]
|
|
for b in bullets:
|
|
story.append(Paragraph(b, styles["MyBullet"]))
|
|
|
|
# 3.3 PostgreSQL pgvector
|
|
story.append(Paragraph("3.3 PostgreSQL + pgvector", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"Base de données vectorielle. Stocke les messages, sessions, peers, et les embeddings "
|
|
"(vecteurs à 768 dimensions pour nomic-embed-text). L'extension pgvector permet la "
|
|
"recherche par similarité sémantique.",
|
|
styles["Body"]
|
|
))
|
|
story.append(Paragraph(
|
|
"Image : pgvector/pgvector:pg15<br/>"
|
|
"Port interne : 5434 (évite conflit avec le PostgreSQL existant sur 5432)<br/>"
|
|
"Volume : honcho-pgdata (persistant)",
|
|
styles["Body"]
|
|
))
|
|
|
|
# 3.4 Redis
|
|
story.append(Paragraph("3.4 Redis (Cache)", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"Cache pour accélérer les requêtes répétées. Redis existant sur le homelab, "
|
|
"réutilisé sans conteneur dédié dans le stack Honcho.",
|
|
styles["Body"]
|
|
))
|
|
story.append(Paragraph(
|
|
"Hôte : 192.168.30.36:6379<br/>"
|
|
"Pas de mot de passe (réseau interne)",
|
|
styles["Body"]
|
|
))
|
|
|
|
# 3.5 Ollama
|
|
story.append(Paragraph("3.5 Ollama (LLM & Embeddings)", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"Serveur de modèles LLM locaux sur Kellerflix (GTX 1070, 8GB VRAM). "
|
|
"Deux modèles utilisés :",
|
|
styles["Body"]
|
|
))
|
|
bullets = [
|
|
"<b>nemotron-mini:4b</b> (Q4_K_M, 2.7GB) — LLM pour le dialectic engine et le deriver. Supporte le tool calling.",
|
|
"<b>nomic-embed-text</b> (274MB) — modèle d'embeddings pour la recherche vectorielle (768 dimensions).",
|
|
]
|
|
for b in bullets:
|
|
story.append(Paragraph(b, styles["MyBullet"]))
|
|
story.append(PageBreak())
|
|
|
|
# ===== 4. FLUX DE FONCTIONNEMENT =====
|
|
story.append(Paragraph("4. Flux de fonctionnement", styles["SectionTitle"]))
|
|
story.append(HRFlowable(width="100%", thickness=0.5, color=ACCENT))
|
|
story.append(Spacer(1, 3*mm))
|
|
|
|
story.append(Paragraph("4.1 À chaque message utilisateur", styles["SubTitle"]))
|
|
steps = [
|
|
"<b>1.</b> Hermes reçoit le message de l'utilisateur",
|
|
"<b>2.</b> Honcho injecte automatiquement le contexte dans le system prompt (représentation utilisateur + résumé de session + carte AI peer)",
|
|
"<b>3.</b> Hermes traite la requête avec ce contexte",
|
|
"<b>4.</b> La réponse est envoyée à l'utilisateur",
|
|
"<b>5.</b> Le message est stocké dans Honcho (via l'API)",
|
|
"<b>6.</b> Le Deriver analyse le message en arrière-plan et met à jour la représentation",
|
|
]
|
|
for s in steps:
|
|
story.append(Paragraph(s, styles["MyBullet"]))
|
|
|
|
story.append(Paragraph("4.2 Modes de rappel (Recall Modes)", styles["SubTitle"]))
|
|
recall_data = [
|
|
["Mode", "Auto-injection", "Outils mémoire", "Usage"],
|
|
["hybrid\n(default)", "Oui", "Oui (5 outils)", "L'agent décide quand utiliser les outils vs le contexte auto-injecté"],
|
|
["context", "Oui", "Non (cachés)", "Économique en tokens, pas d'appels outils"],
|
|
["tools", "Non", "Oui", "L'agent contrôle tout explicitement"],
|
|
]
|
|
recall_table = Table(recall_data, colWidths=[3*cm, 2.5*cm, 2.5*cm, 6*cm])
|
|
recall_table.setStyle(TableStyle([
|
|
("BACKGROUND", (0, 0), (-1, 0), DARK),
|
|
("TEXTCOLOR", (0, 0), (-1, 0), white),
|
|
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
|
("FONTSIZE", (0, 0), (-1, -1), 9),
|
|
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
|
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
|
("GRID", (0, 0), (-1, -1), 0.5, GRAY),
|
|
("BACKGROUND", (0, 1), (-1, -1), LIGHT),
|
|
("TOPPADDING", (0, 0), (-1, -1), 6),
|
|
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
|
|
]))
|
|
story.append(recall_table)
|
|
story.append(Spacer(1, 3*mm))
|
|
|
|
story.append(Paragraph("4.3 Les 5 outils mémoire", styles["SubTitle"]))
|
|
tools_data = [
|
|
["Outil", "Appel LLM ?", "Coût", "Usage"],
|
|
["honcho_profile", "Non", "minimal", "Lire/mettre à jour la carte du peer (nom, rôle, préférences)"],
|
|
["honcho_search", "Non", "faible", "Recherche sémantique dans l'historique"],
|
|
["honcho_context", "Non", "faible", "Snapshot complet : résumé + représentation + messages récents"],
|
|
["honcho_reasoning", "Oui", "moyen-élevé", "Question synthétisée par le dialectic engine"],
|
|
["honcho_conclude", "Non", "minimal", "Écrire/supprimer une conclusion persistante"],
|
|
]
|
|
tools_table = Table(tools_data, colWidths=[3*cm, 2*cm, 2*cm, 7*cm])
|
|
tools_table.setStyle(TableStyle([
|
|
("BACKGROUND", (0, 0), (-1, 0), DARK),
|
|
("TEXTCOLOR", (0, 0), (-1, 0), white),
|
|
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
|
("FONTSIZE", (0, 0), (-1, -1), 9),
|
|
("ALIGN", (0, 0), (-1, -1), "CENTER"),
|
|
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
|
("GRID", (0, 0), (-1, -1), 0.5, GRAY),
|
|
("BACKGROUND", (0, 1), (-1, -1), LIGHT),
|
|
("TOPPADDING", (0, 0), (-1, -1), 6),
|
|
("BOTTOMPADDING", (0, 0), (-1, -1), 6),
|
|
]))
|
|
story.append(tools_table)
|
|
story.append(PageBreak())
|
|
|
|
# ===== 5. CONFIGURATION HERMES =====
|
|
story.append(Paragraph("5. Configuration Hermes", styles["SectionTitle"]))
|
|
story.append(HRFlowable(width="100%", thickness=0.5, color=ACCENT))
|
|
story.append(Spacer(1, 3*mm))
|
|
|
|
story.append(Paragraph("5.1 Fichier honcho.json", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"Chemin : /root/.hermes/honcho.json",
|
|
styles["Body"]
|
|
))
|
|
story.append(Paragraph(
|
|
"{<br/>"
|
|
" \"baseUrl\": \"http://192.168.30.35:8000\",<br/>"
|
|
" \"peerName\": \"laurent\",<br/>"
|
|
" \"aiPeer\": \"hermes\",<br/>"
|
|
" \"workspace\": \"default\",<br/>"
|
|
" \"recallMode\": \"hybrid\",<br/>"
|
|
" \"writeFrequency\": \"async\",<br/>"
|
|
" \"sessionStrategy\": \"per-directory\",<br/>"
|
|
" \"observation\": {<br/>"
|
|
" \"user\": { \"observeMe\": true, \"observeOthers\": true },<br/>"
|
|
" \"ai\": { \"observeMe\": true, \"observeOthers\": true }<br/>"
|
|
" },<br/>"
|
|
" \"dialecticReasoningLevel\": \"low\",<br/>"
|
|
" \"dialecticDepth\": 1,<br/>"
|
|
" \"contextCadence\": 1,<br/>"
|
|
" \"dialecticCadence\": 2<br/>"
|
|
"}",
|
|
styles["Code"]
|
|
))
|
|
|
|
story.append(Paragraph("5.2 Config Hermes", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"Dans /root/.hermes/config.yaml :",
|
|
styles["Body"]
|
|
))
|
|
story.append(Paragraph(
|
|
"memory:<br/>"
|
|
" provider: honcho",
|
|
styles["Code"]
|
|
))
|
|
|
|
story.append(Paragraph("5.3 Fichier .env Honcho", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"Chemin sur la VM postgres : /root/docker/honcho/.env",
|
|
styles["Body"]
|
|
))
|
|
story.append(Paragraph(
|
|
"LOG_LEVEL=INFO<br/>"
|
|
"AUTH_USE_AUTH=false<br/>"
|
|
"VECTOR_STORE_TYPE=pgvector<br/>"
|
|
"LLM_OPENAI_API_KEY=ollama<br/>"
|
|
"DERIVER_MODEL_CONFIG__TRANSPORT=openai<br/>"
|
|
"DERIVER_MODEL_CONFIG__MODEL=nemotron-mini:4b<br/>"
|
|
"DERIVER_MODEL_CONFIG__OVERRIDES__BASE_URL=http://192.168.30.10:11434/v1<br/>"
|
|
"DERIVER_MODEL_CONFIG__OVERRIDES__API_KEY_ENV=ollama<br/>"
|
|
"EMBEDDING_MODEL_CONFIG__TRANSPORT=openai<br/>"
|
|
"EMBEDDING_MODEL_CONFIG__MODEL=nomic-embed-text<br/>"
|
|
"EMBEDDING_MODEL_CONFIG__OVERRIDES__BASE_URL=http://192.168.30.10:11434/v1<br/>"
|
|
"EMBEDDING_MODEL_CONFIG__OVERRIDES__API_KEY_ENV=ollama<br/>"
|
|
"EMBED_MESSAGES=true<br/>"
|
|
"EMBEDDING_VECTOR_DIMENSIONS=768",
|
|
styles["Code"]
|
|
))
|
|
story.append(PageBreak())
|
|
|
|
# ===== 6. COMMANDES UTILES =====
|
|
story.append(Paragraph("6. Commandes utiles", styles["SectionTitle"]))
|
|
story.append(HRFlowable(width="100%", thickness=0.5, color=ACCENT))
|
|
story.append(Spacer(1, 3*mm))
|
|
|
|
story.append(Paragraph("6.1 Sur Hermes (LXC 112)", styles["SubTitle"]))
|
|
cmds = [
|
|
("hermes honcho status", "Voir l'état de la connexion Honcho"),
|
|
("hermes honcho setup", "Lancer le wizard de configuration"),
|
|
("hermes honcho enable/disable", "Activer/désactiver Honcho"),
|
|
("hermes honcho peer --user <nom>", "Définir le nom du peer utilisateur"),
|
|
("hermes honcho mode hybrid|context|tools", "Changer le mode de rappel"),
|
|
("hermes honcho sessions", "Lister les sessions connues"),
|
|
("hermes honcho map <nom>", "Mapper le répertoire courant à une session"),
|
|
("hermes honcho sync", "Créer les host blocks pour tous les profils"),
|
|
("hermes memory status", "Voir le provider mémoire actif"),
|
|
("hermes memory off", "Désactiver la mémoire externe"),
|
|
]
|
|
for cmd, desc in cmds:
|
|
story.append(Paragraph(f"<b>{cmd}</b> — {desc}", styles["MyBullet"]))
|
|
|
|
story.append(Paragraph("6.2 Sur la VM postgres (192.168.30.35)", styles["SubTitle"]))
|
|
cmds2 = [
|
|
("docker compose ps", "Voir l'état des conteneurs"),
|
|
("docker compose logs api --tail 30", "Logs de l'API Honcho"),
|
|
("docker compose logs deriver --tail 30", "Logs du Deriver"),
|
|
("docker compose down && docker compose up -d", "Redémarrer le stack"),
|
|
("docker compose down -v && docker compose up -d --build", "Reset complet + rebuild"),
|
|
("curl http://localhost:8000/health", "Healthcheck"),
|
|
]
|
|
for cmd, desc in cmds2:
|
|
story.append(Paragraph(f"<b>{cmd}</b> — {desc}", styles["MyBullet"]))
|
|
|
|
story.append(Paragraph("6.3 Sur Kellerflix (192.168.30.10)", styles["SubTitle"]))
|
|
cmds3 = [
|
|
("ollama list", "Lister les modèles disponibles"),
|
|
("ollama pull <modele>", "Télécharger un modèle"),
|
|
("ollama run <modele>", "Tester un modèle en interactif"),
|
|
("curl http://localhost:11434/api/tags", "Lister les modèles via API"),
|
|
]
|
|
for cmd, desc in cmds3:
|
|
story.append(Paragraph(f"<b>{cmd}</b> — {desc}", styles["MyBullet"]))
|
|
story.append(PageBreak())
|
|
|
|
# ===== 7. SCHÉMA RÉSEAU =====
|
|
story.append(Paragraph("7. Schéma réseau", styles["SectionTitle"]))
|
|
story.append(HRFlowable(width="100%", thickness=0.5, color=ACCENT))
|
|
story.append(Spacer(1, 3*mm))
|
|
|
|
story.append(Paragraph(
|
|
"Le schéma ci-dessous représente les flux entre les composants :",
|
|
styles["Body"]
|
|
))
|
|
story.append(Spacer(1, 3*mm))
|
|
|
|
# Schéma ASCII
|
|
schema = """<font face="Courier" size="8">
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ RÉSEAU 192.168.30.0/24 │
|
|
├─────────────────────────────────────────────────────────────┤
|
|
│ │
|
|
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
|
|
│ │ Hermes Agent │ │ VM postgres (30.35) │ │
|
|
│ │ (LXC 112) │ │ │ │
|
|
│ │ │ │ ┌──────────────────────┐ │ │
|
|
│ │ honcho-ai SDK │────▶│ │ Honcho API (:8000) │ │ │
|
|
│ │ hermes honcho │ │ │ (FastAPI) │ │ │
|
|
│ │ │ │ └──────┬───────────────┘ │ │
|
|
│ └──────────────────┘ │ │ │ │
|
|
│ │ ▼ │ │
|
|
│ │ ┌──────────────────────┐ │ │
|
|
│ │ │ PostgreSQL pgvector │ │ │
|
|
│ │ │ (:5434) │ │ │
|
|
│ │ └──────────────────────┘ │ │
|
|
│ │ ▲ │ │
|
|
│ │ ┌──────┴───────────────┐ │ │
|
|
│ │ │ Honcho Deriver │ │ │
|
|
│ │ │ (worker background) │ │ │
|
|
│ │ └──────┬───────────────┘ │ │
|
|
│ └─────────┼────────────────────┘ │
|
|
│ │ │
|
|
│ ┌─────────┼────────────┐ │
|
|
│ │ ▼ │ │
|
|
│ │ ┌──────────────┐ │ │
|
|
│ │ │ Redis │ │ │
|
|
│ │ │ (30.36:6379) │ │ │
|
|
│ │ └──────────────┘ │ │
|
|
│ └──────────────────────┘ │
|
|
│ │ │
|
|
│ ┌─────────┼────────────┐ │
|
|
│ │ ▼ │ │
|
|
│ │ ┌──────────────────┐ │ │
|
|
│ │ │ Kellerflix │ │ │
|
|
│ │ │ (30.10:11434) │ │ │
|
|
│ │ │ Ollama │ │ │
|
|
│ │ │ ├─ nemotron-mini│ │ │
|
|
│ │ │ └─ nomic-embed │ │ │
|
|
│ │ └──────────────────┘ │ │
|
|
│ └────────────────────────┘ │
|
|
│ │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
</font>"""
|
|
story.append(Paragraph(schema, styles["Body"]))
|
|
story.append(PageBreak())
|
|
|
|
# ===== 8. DÉPANNAGE =====
|
|
story.append(Paragraph("8. Dépannage", styles["SectionTitle"]))
|
|
story.append(HRFlowable(width="100%", thickness=0.5, color=ACCENT))
|
|
story.append(Spacer(1, 3*mm))
|
|
|
|
issues = [
|
|
("Problème", "Cause probable", "Solution"),
|
|
("Honcho not configured", "memory.provider pas défini", "hermes config set memory.provider honcho"),
|
|
("API Honcho injoignable", "Conteneur down", "docker compose ps && docker compose logs api"),
|
|
("OpenAI API key required", "LLM_OPENAI_API_KEY manquant", "Ajouter LLM_OPENAI_API_KEY=ollama dans .env"),
|
|
("Embedding dim mismatch", "Dimensions changées après init", "docker compose down -v && docker compose up -d --build"),
|
|
("Deriver ne tourne pas", "Dépendance api pas healthy", "Vérifier les logs : docker compose logs deriver"),
|
|
("Peer conflict", "Peer déjà créé", "Utiliser un nom différent ou supprimer l'ancien"),
|
|
("Ollama inaccessible", "OLLAMA_HOST=127.0.0.1", "Vérifier ss -tlnp | grep 11434"),
|
|
("Mémoire non persistante", "writeFrequency = session", "Passer à async dans honcho.json"),
|
|
]
|
|
issues_table = Table(issues, colWidths=[3.5*cm, 4*cm, 6.5*cm])
|
|
issues_table.setStyle(TableStyle([
|
|
("BACKGROUND", (0, 0), (-1, 0), DARK),
|
|
("TEXTCOLOR", (0, 0), (-1, 0), white),
|
|
("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
|
|
("FONTSIZE", (0, 0), (-1, -1), 8),
|
|
("ALIGN", (0, 0), (-1, -1), "LEFT"),
|
|
("VALIGN", (0, 0), (-1, -1), "MIDDLE"),
|
|
("GRID", (0, 0), (-1, -1), 0.5, GRAY),
|
|
("BACKGROUND", (0, 1), (-1, -1), LIGHT),
|
|
("TOPPADDING", (0, 0), (-1, -1), 5),
|
|
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
|
|
("LEFTPADDING", (0, 0), (-1, -1), 4),
|
|
]))
|
|
story.append(issues_table)
|
|
story.append(Spacer(1, 5*mm))
|
|
|
|
story.append(Paragraph("Liens utiles :", styles["SubTitle"]))
|
|
story.append(Paragraph(
|
|
"Documentation Honcho : https://docs.honcho.dev<br/>"
|
|
"Repo Honcho : https://github.com/plastic-labs/honcho<br/>"
|
|
"Intégration Hermes : https://docs.honcho.dev/v3/guides/integrations/hermes<br/>"
|
|
"App Honcho Cloud : https://app.honcho.dev<br/>"
|
|
"Ollama : https://ollama.com",
|
|
styles["Body"]
|
|
))
|
|
|
|
# Build
|
|
doc.build(story)
|
|
print(f"PDF généré : {OUTPUT}")
|
|
print(f"Taille : {os.path.getsize(OUTPUT)} bytes")
|