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.
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
# 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
|
||||
```ini
|
||||
# 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
|
||||
```python
|
||||
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
|
||||
```python
|
||||
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
|
||||
```python
|
||||
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
|
||||
```python
|
||||
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
|
||||
```bash
|
||||
# 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
|
||||
```bash
|
||||
# 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`.
|
||||
Reference in New Issue
Block a user