Files
context-continuity/trilium_automation_setup.md
T
Master 01629780f4 chore: versioning initial du systeme Context Continuity
Code du systeme de memoire multi-LLM sur Trilium :
- trilium_api.py : wrapper trilium-py (notes, labels, relations)
- mcp_server.py : serveur MCP Starlette (19 tools, OAuth + Bearer)
- api_context.py : API REST FastAPI
- trilium_context.py : workflow CLI
- watchdog.sh, start_*.sh : supervision et demarrage
- skills, docs et ontologie associes
Secrets (.env, oauth_state.json) exclus via .gitignore.
2026-06-29 11:02:22 +02:00

9.0 KiB

Trilium Automation Setup - Fichier Unique avec Tous les Scripts

Projet : Context Continuity

Date : 27 mai 2026


Description

Ce fichier contient tous les scripts Python et configurations nécessaires pour automatiser la gestion de contexte multi-LLM avec Trilium.


Structure des Fichiers

trilium_automation/
├── init_trilium_architecture.py  # Initialise l'arborescence Trilium
├── trilium_api.py               # Bibliothèque pour interagir avec l'API ETAPI
├── create_conversation.py      # Crée des notes de conversation LLM
├── generate_context.py          # Génère un contexte pour les LLM
└── .env.example                 # Exemple de fichier d'environnement

1. Fichier .env.example

# Fichier : .env
# À placer dans /volume1/homes/Master/App/Automation/
# Ne jamais commiter ce fichier dans Git !

TRILIUM_TOKEN=ton_token_etapi_ici
TRILIUM_API_URL=http://localhost:4292/etapi
ROOT_NOTE_ID=root

2. Script : init_trilium_architecture.py

import requests
import json
import os
from dotenv import load_dotenv

# Charger les variables d'environnement depuis .env
load_dotenv()

# ===== CONFIGURATION =====
TRILIUM_API_URL = os.getenv("TRILIUM_API_URL", "http://localhost:4292/etapi")
TRILIUM_TOKEN = os.getenv("TRILIUM_TOKEN")
HEADERS = {
    "Authorization": TRILIUM_TOKEN,
    "Content-Type": "application/json"
}

# ID de la note racine (root) - à remplacer par le tien
ROOT_NOTE_ID = os.getenv("ROOT_NOTE_ID", "root")

# ===== FONCTIONS =====
def create_note(parent_id, title, note_type="book"):
    """Crée une note de type 'book' (dossier) ou 'text' dans Trilium."""
    data = {
        "parentNoteId": parent_id,
        "title": title,
        "type": note_type,
        "content": f"# {title}\n\n*Dossier créé automatiquement via API ETAPI.*"
    }
    response = requests.post(
        f"{TRILIUM_API_URL}/notes",
        headers=HEADERS,
        json=data
    )
    if response.status_code == 200:
        note_id = response.json().get("noteId")
        print(f"✅ Dossier créé : {title} (ID: {note_id})")
        return note_id
    else:
        raise Exception(f"❌ Erreur {response.status_code} : {response.text}")

def get_note_id_by_title(title, parent_id):
    """Récupère l'ID d'une note par son titre (pour éviter les doublons)."""
    search_url = f"{TRILIUM_API_URL}/search?q=title:{title}"
    response = requests.get(search_url, headers=HEADERS)
    if response.status_code == 200:
        notes = response.json()
        for note in notes:
            if note.get("title") == title and note.get("parentNoteId") == parent_id:
                return note.get("noteId")
    return None

# ===== EXÉCUTION =====
def main():
    print(" Initialisation de l'architecture Trilium pour 'Context Continuity'...")

    # 1. Créer le dossier principal "Context Continuity" (s'il n'existe pas)
    context_continuity_id = get_note_id_by_title("Context Continuity", ROOT_NOTE_ID)
    if not context_continuity_id:
        context_continuity_id = create_note(ROOT_NOTE_ID, "Context Continuity", "book")
    else:
        print(f"✅ Dossier existant : Context Continuity (ID: {context_continuity_id})")

    # 2. Créer les sous-dossiers
    subfolders = ["Conversations", "Backlog", "Décisions", "Glossaire", "Historique"]
    folder_ids = {}

    for folder in subfolders:
        folder_id = get_note_id_by_title(folder, context_continuity_id)
        if not folder_id:
            folder_id = create_note(context_continuity_id, folder, "book")
        else:
            print(f"✅ Dossier existant : {folder} (ID: {folder_id})")
        folder_ids[folder] = folder_id

    # 3. Afficher les IDs pour référence
    print("\n IDs des dossiers créés (à utiliser dans tes scripts) :")
    for folder, folder_id in folder_ids.items():
        print(f"{folder}: {folder_id}")

    # 4. Sauvegarder les IDs dans un fichier JSON
    with open("trilium_folder_ids.json", "w") as f:
        json.dump({
            "root_id": ROOT_NOTE_ID,
            "context_continuity_id": context_continuity_id,
            **folder_ids
        }, f, indent=4)
    print("\n IDs sauvegardés dans trilium_folder_ids.json")

if __name__ == "__main__":
    main()

3. Script : trilium_api.py

import requests
import os
from dotenv import load_dotenv

# Charger les variables d'environnement
load_dotenv()

TRILIUM_API_URL = os.getenv("TRILIUM_API_URL", "http://localhost:4292/etapi")
TRILIUM_TOKEN = os.getenv("TRILIUM_TOKEN")
HEADERS = {
    "Authorization": TRILIUM_TOKEN,
    "Content-Type": "application/json"
}

def create_note(parent_id, title, content, note_type="text"):
    """Crée une note dans Trilium."""
    data = {
        "parentNoteId": parent_id,
        "title": title,
        "type": note_type,
        "content": content
    }
    response = requests.post(
        f"{TRILIUM_API_URL}/notes",
        headers=HEADERS,
        json=data
    )
    if response.status_code == 200:
        return response.json().get("noteId")
    else:
        raise Exception(f"Erreur {response.status_code} : {response.text}")

def get_note(note_id):
    """Récupère une note par son ID."""
    response = requests.get(
        f"{TRILIUM_API_URL}/notes/{note_id}",
        headers=HEADERS
    )
    return response.json()

def update_note(note_id, content):
    """Met à jour une note existante."""
    data = {"content": content}
    response = requests.put(
        f"{TRILIUM_API_URL}/notes/{note_id}",
        headers=HEADERS,
        json=data
    )
    return response.status_code == 200

def search_notes(query):
    """Recherche des notes par titre ou contenu."""
    response = requests.get(
        f"{TRILIUM_API_URL}/search?q={query}",
        headers=HEADERS
    )
    return response.json()

4. Script : create_conversation.py

from trilium_api import create_note
from datetime import datetime
import os
from dotenv import load_dotenv

load_dotenv()

# IDs des dossiers (à remplacer par les tiens)
CONVERSATIONS_ID = os.getenv("CONVERSATIONS_ID", "ID_DU_DOSSIER_CONVERSATIONS")

def create_conversation(llm, title, content):
    """Crée une note de conversation dans Trilium."""
    date = datetime.now().strftime("%Y-%m-%d %H:%M")
    note_title = f"[{llm}] - {date} - {title}"
    note_content = f"""# {note_title}

**Projet** : [[Context Continuity]]
**LLM** : {llm}
**Date** : {date}
**Statut** : En cours

---
## Contexte
{content}

---
**Liens** :
- [[Backlog/]]
- [[Décisions/]]
"""
    note_id = create_note(
        parent_id=CONVERSATIONS_ID,
        title=note_title,
        content=note_content
    )
    print(f"Note créée : {note_id} ({note_title})")
    return note_id

# Exemple d'utilisation
if __name__ == "__main__":
    create_conversation(
        llm="Le Chat",
        title="Configuration Trilium pour Context Continuity",
        content="Discussion sur la configuration de Trilium pour synchroniser les contextes entre LLM."
    )

5. Script : generate_context.py

from trilium_api import search_notes, get_note
from datetime import datetime
import os
from dotenv import load_dotenv

load_dotenv()

CONTEXT_CONTINUITY_ID = os.getenv("CONTEXT_CONTINUITY_ID", "ID_DU_DOSSIER_CONTEXT_CONTINUITY")

def generate_context(project_name, limit=10):
    """Génère un contexte pour un projet donné en agrégeant les notes Trilium."""
    query = f"projet:{project_name}"
    notes = search_notes(query)

    context = f"# Contexte du projet : {project_name}\n\n"
    context += "## Conversations récentes\n"
    for note in notes[:limit]:
        note_data = get_note(note["noteId"])
        context += f"- **{note_data['title']}** (LLM: {note_data.get('llm', 'N/A')}, Date: {note_data.get('date', 'N/A')})\n"
        context += f"  {note_data['content'][:200]}...\n\n"

    context += f"\n*Généré le {datetime.now().strftime('%Y-%m-%d %H:%M')}*"
    return context

# Exemple d'utilisation
if __name__ == "__main__":
    context = generate_context("Context Continuity")
    print(context)

Instructions d'Utilisation

1. Préparer l'environnement

# Installer les dépendances
pip install requests python-dotenv

# Créer le fichier .env
cd /volume1/homes/Master/App/Automation/
echo "TRILIUM_TOKEN=ton_token_etapi" > .env
echo "TRILIUM_API_URL=http://localhost:4292/etapi" >> .env
echo "ROOT_NOTE_ID=root" >> .env

2. Exécuter les scripts

# Initialiser l'arborescence Trilium
python3 init_trilium_architecture.py

# Créer une conversation
python3 create_conversation.py

# Générer un contexte
python3 generate_context.py > contexte.md

3. Vérifier les résultats

  • Ouvre Trilium et vérifie que les dossiers et notes sont créés.
  • Le fichier trilium_folder_ids.json contient les IDs des dossiers.

Notes Importantes

  • Ne jamais partager le fichier .env (il contient ton token ETAPI).
  • Les scripts supposent que Trilium est accessible via http://localhost:4292/etapi.
  • Si tu utilises le Reverse Proxy, remplace TRILIUM_API_URL par https://trilium.bertha-cloud.fr/etapi.