This commit is contained in:
gwen 2026-07-29 16:50:12 +02:00
parent 6d4aeaf515
commit cc16374a6b
14 changed files with 4 additions and 1239 deletions

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
autocommit.py
requirements.txt.publish
# obsidian
.obsidian
# mkdocs

View file

@ -1,8 +0,0 @@
---
description: carottage de prompts asynchrones
---
# prompts asynchrones
- [[AsynchronousTextualPrompt]]
- [[persona/initial_user_prompt]]
- [[sytem_prompt]]

View file

@ -1,771 +0,0 @@
---
description: python-textual comme interface à un LLM, est-ce que python-textual supporte la réponse d'une api-streaming (est-ce que la event loop de textual autorise l'asynchrone) ?
---
Voici votre application Textual modifiée pour intégrer un appel asynchrone à Ollama. J'ai ajouté la fonctionnalité qui permet de poser une question à Ollama et d'afficher la réponse en streaming.
```python
from textual.app import App, ComposeResult
from textual.containers import Container, Vertical, Horizontal
from textual.widgets import Header, Footer, Input, ListView, ListItem, Label, Static, Button, TextArea
from textual import events, work
from textual.reactive import reactive
from textual.message import Message
import asyncio
import httpx
import json
from typing import List, Optional, Dict, Any
class TermListItem(ListItem):
"""ListItem personnalisé pour afficher un terme et sa définition"""
def __init__(self, term: str, definition: str, expanded: bool = False) -> None:
self.term = term
self.definition = definition
self.expanded = expanded
# Créer le contenu avec le terme et éventuellement la définition
content = self._create_content()
super().__init__(content)
def _create_content(self):
"""Crée le contenu du ListItem avec ou sans définition"""
if self.expanded:
return Vertical(
Label(f"📌 {self.term}", classes="term-title"),
Label(f" {self.definition}", classes="term-definition"),
classes="term-expanded"
)
else:
return Label(f"📌 {self.term}", classes="term-title")
def toggle_expand(self):
"""Bascule l'état d'expansion du terme"""
self.expanded = not self.expanded
# Mettre à jour le contenu
self._update_content()
def _update_content(self):
"""Met à jour le contenu du ListItem"""
new_content = self._create_content()
# Remplacer l'ancien contenu
self.remove_children()
self.mount(new_content)
class LLMQueryWidget(Static):
"""Widget pour afficher les requêtes et réponses du LLM"""
class ResponseReceived(Message):
"""Message envoyé quand une réponse complète est reçue"""
def __init__(self, question: str, response: str) -> None:
self.question = question
self.response = response
super().__init__()
def __init__(self):
super().__init__()
self.question = ""
self.response = ""
self.is_streaming = False
def start_streaming(self, question: str):
"""Démarre l'affichage d'une réponse en streaming"""
self.question = question
self.response = ""
self.is_streaming = True
self.update_content()
def add_chunk(self, chunk: str):
"""Ajoute un chunk à la réponse"""
self.response += chunk
self.update_content()
def finish_streaming(self):
"""Termine le streaming"""
self.is_streaming = False
self.update_content()
def update_content(self):
"""Met à jour le contenu affiché"""
content = f"[bold cyan]❓ {self.question}[/bold cyan]\n\n"
if self.is_streaming:
content += f"[yellow]⏳ Génération en cours...[/yellow]\n\n"
content += f"[white]{self.response}[/white]"
if self.is_streaming and self.response:
content += " [yellow]▌[/yellow]" # Curseur clignotant simulé
self.update(content)
class DictionaryApp(App):
"""Application de dictionnaire avec intégration LLM Ollama"""
CSS = """
Screen {
background: #1e1e2e;
}
#main-container {
height: 100%;
width: 100%;
padding: 1;
background: #1e1e2e;
}
#search-container {
height: auto;
min-height: 5;
max-height: 8;
margin-bottom: 1;
background: #2d2d44;
padding: 1;
}
#results-container {
height: 70%;
background: #2d2d44;
padding: 1;
overflow-y: auto;
}
#llm-container {
height: 30%;
min-height: 15;
background: #2d2d44;
padding: 1;
margin-top: 1;
border: solid #585b70;
overflow-y: auto;
}
#search-label {
color: #89b4fa;
text-style: bold;
padding-bottom: 1;
width: 100%;
}
#llm-label {
color: #a6e3a1;
text-style: bold;
padding-bottom: 1;
width: 100%;
}
Input {
background: #3d3d5c;
color: #cdd6f4;
border: solid #585b70;
padding: 1;
width: 100%;
margin-top: 1;
}
Input:focus {
border: solid #89b4fa;
}
#llm-input {
background: #3d3d5c;
color: #cdd6f4;
border: solid #585b70;
padding: 1;
width: 100%;
margin-top: 1;
}
#llm-input:focus {
border: solid #a6e3a1;
}
#results-list {
background: #3d3d5c;
color: #cdd6f4;
height: 100%;
min-height: 10;
border: solid #585b70;
padding: 0;
}
ListItem {
padding: 1;
background: #3d3d5c;
color: #cdd6f4;
width: 100%;
border-bottom: solid #45476a;
}
ListItem:hover {
background: #45476a;
}
ListItem:focus {
background: #45476a;
}
.term-title {
color: #89b4fa;
text-style: bold;
width: 100%;
padding: 1;
}
.term-definition {
color: #cdd6f4;
padding: 1;
padding-left: 2;
background: #3d3d5c;
width: 100%;
border-left: solid #89b4fa;
margin-top: 1;
}
.term-expanded {
background: #2d2d44;
padding: 0;
}
#results-label {
color: #a6e3a1;
padding-bottom: 1;
width: 100%;
}
#preview-container {
background: #2d2d44;
padding: 1;
margin-top: 1;
min-height: 3;
max-height: 5;
border: solid #585b70;
color: #cdd6f4;
}
#preview-label {
color: #89b4fa;
text-style: bold;
padding-bottom: 1;
width: 100%;
}
#preview-content {
color: #f9e2af;
padding: 1;
background: #3d3d5c;
min-height: 2;
width: 100%;
}
#llm-response {
background: #3d3d5c;
padding: 1;
min-height: 10;
max-height: 20;
overflow-y: auto;
color: #cdd6f4;
margin-top: 1;
}
#llm-actions {
height: auto;
margin-top: 1;
}
Button {
background: #45476a;
color: #cdd6f4;
border: solid #585b70;
padding: 1;
width: auto;
}
Button:hover {
background: #585b70;
}
Button:focus {
border: solid #a6e3a1;
}
#clear-llm-btn {
background: #6b3b3b;
color: #f9e2af;
}
#clear-llm-btn:hover {
background: #8b4b4b;
}
"""
def __init__(self):
super().__init__()
# Dictionnaire de termes avec leurs définitions
self.dictionary = {
"Python": "Langage de programmation interprété, orienté objet, avec une syntaxe claire et une grande lisibilité",
"Textual": "Framework Python pour créer des interfaces utilisateur en mode texte avancées",
"Algorithm": "Suite d'instructions pour résoudre un problème ou effectuer une tâche spécifique",
"API": "Interface de programmation d'application, ensemble de règles pour interagir avec un logiciel",
"Framework": "Ensemble d'outils et de bibliothèques pour développer des applications structurées",
"Machine Learning": "Domaine de l'IA permettant aux machines d'apprendre à partir de données",
"Deep Learning": "Sous-ensemble du machine learning utilisant des réseaux de neurones profonds",
"Neural Network": "Système informatique inspiré du cerveau biologique et de ses connexions",
"Data Science": "Domaine interdisciplinaire pour extraire des connaissances des données",
"Cloud Computing": "Fourniture de services informatiques via internet à la demande",
"DevOps": "Pratique combinant développement et opérations informatiques en continu",
"Agile": "Méthodologie de gestion de projet itérative et flexible centrée sur l'humain",
"Scrum": "Framework Agile pour la gestion de projets complexes et adaptatifs",
"Kubernetes": "Plateforme d'orchestration de conteneurs open-source pour la production",
"Docker": "Plateforme de conteneurisation pour applications distribuées",
"Git": "Système de contrôle de version distribué pour le suivi de code",
"GitHub": "Plateforme d'hébergement de code basée sur Git et de collaboration",
"VS Code": "Éditeur de code source développé par Microsoft avec extensions",
"PyCharm": "IDE Python développé par JetBrains avec intégration complète",
"Jupyter": "Application web pour créer des notebooks interactifs en direct",
}
# Liste triée des termes pour la recherche
self.terms = sorted(self.dictionary.keys())
self.filtered_terms = self.terms.copy()
self.current_input = ""
self.last_selected_term = None
self.expanded_terms = set() # Ensemble des termes actuellement expansés
# Configuration Ollama
self.ollama_url = "http://localhost:11434/api/generate"
self.ollama_model = "llama3.2" # Ou un autre modèle installé
self.http_client = httpx.AsyncClient(timeout=120.0)
def compose(self) -> ComposeResult:
"""Compose l'interface utilisateur"""
yield Header()
yield Container(
Container(
# Zone de recherche
Container(
Label("🔍 Rechercher un terme :", id="search-label"),
Input(placeholder="Tapez un terme...", id="search-input"),
id="search-container"
),
# Zone d'aperçu du texte en cours
Container(
Label("✏️ Texte saisi :", id="preview-label"),
Static("En attente de saisie...", id="preview-content"),
id="preview-container"
),
# Résultats
Container(
Label("📋 0 terme trouvé", id="results-label"),
ListView(id="results-list"),
id="results-container"
),
# Zone LLM
Container(
Label("🤖 Question pour Ollama :", id="llm-label"),
Input(placeholder="Posez une question au LLM...", id="llm-input"),
Horizontal(
Button("Envoyer", id="send-llm-btn", variant="primary"),
Button("Effacer", id="clear-llm-btn"),
id="llm-actions"
),
Static("", id="llm-response"),
id="llm-container"
),
id="main-container"
),
)
yield Footer()
def on_mount(self) -> None:
"""Initialisation après le montage"""
search_input = self.query_one("#search-input")
search_input.focus()
self.update_results()
self.apply_responsive_styles()
def on_resize(self, event: events.Resize) -> None:
"""Gère le redimensionnement du terminal"""
self.apply_responsive_styles()
self.update_list_height()
def apply_responsive_styles(self) -> None:
"""Applique les styles responsifs en fonction de la taille du terminal"""
width = self.size.width
height = self.size.height
# Ajuster les paddings selon la largeur
main_container = self.query_one("#main-container")
search_container = self.query_one("#search-container")
results_container = self.query_one("#results-container")
preview_container = self.query_one("#preview-container")
llm_container = self.query_one("#llm-container")
llm_response = self.query_one("#llm-response")
if width < 80:
# Petit terminal
main_container.styles.padding = 1
search_container.styles.padding = 1
results_container.styles.padding = 1
preview_container.styles.padding = 1
llm_container.styles.padding = 1
preview_container.styles.min_height = 2
preview_container.styles.max_height = 3
search_container.styles.min_height = 4
search_container.styles.max_height = 6
llm_response.styles.min_height = 6
llm_response.styles.max_height = 12
elif width > 120 and height > 40:
# Grand terminal
main_container.styles.padding = 2
search_container.styles.padding = 2
results_container.styles.padding = 2
preview_container.styles.padding = 2
llm_container.styles.padding = 2
preview_container.styles.min_height = 4
preview_container.styles.max_height = 6
search_container.styles.min_height = 6
search_container.styles.max_height = 10
llm_response.styles.min_height = 12
llm_response.styles.max_height = 20
else:
# Terminal moyen (par défaut)
main_container.styles.padding = 1
search_container.styles.padding = 1
results_container.styles.padding = 1
preview_container.styles.padding = 1
llm_container.styles.padding = 1
preview_container.styles.min_height = 3
preview_container.styles.max_height = 5
search_container.styles.min_height = 5
search_container.styles.max_height = 8
llm_response.styles.min_height = 8
llm_response.styles.max_height = 15
# Ajuster la hauteur de la preview selon la hauteur du terminal
if height < 30:
preview_container.styles.min_height = 2
preview_container.styles.max_height = 3
llm_response.styles.min_height = 4
llm_response.styles.max_height = 8
elif height > 50:
preview_container.styles.min_height = 4
preview_container.styles.max_height = 6
llm_response.styles.min_height = 12
llm_response.styles.max_height = 20
def update_list_height(self) -> None:
"""Met à jour la hauteur de la liste en fonction de l'espace disponible"""
try:
results_list = self.query_one("#results-list")
available_height = self.size.height - self.calculate_fixed_height()
# Ajuster la hauteur de la liste
if available_height > 15:
results_list.styles.height = available_height - 2
elif available_height > 10:
results_list.styles.height = available_height
else:
results_list.styles.height = 8
except Exception:
pass
def calculate_fixed_height(self) -> int:
"""Calcule la hauteur fixe des éléments (header, footer, search, preview)"""
try:
search_container = self.query_one("#search-container")
preview_container = self.query_one("#preview-container")
# Récupérer les hauteurs actuelles
search_height = search_container.styles.min_height or 5
preview_height = preview_container.styles.min_height or 3
# Estimer la hauteur fixe totale
if isinstance(search_height, (int, float)):
search_h = search_height
else:
search_h = 5
if isinstance(preview_height, (int, float)):
preview_h = preview_height
else:
preview_h = 3
# Header + Footer + margins + padding
fixed_height = 2 + search_h + preview_h + 4
return int(fixed_height)
except Exception:
return 18 # Valeur par défaut en cas d'erreur
def on_input_changed(self, event: Input.Changed) -> None:
"""Gère les changements dans le champ de recherche"""
if event.input.id == "search-input":
self.current_input = event.value
self.update_preview()
self.update_results()
def update_preview(self) -> None:
"""Met à jour l'aperçu du texte saisi"""
preview_content = self.query_one("#preview-content")
if self.current_input:
preview_text = f"📝 {self.current_input}"
# Si le texte correspond à un terme connu
matching_terms = [term for term in self.terms if term.lower() == self.current_input.lower()]
if matching_terms:
preview_text = f"✅ {self.current_input} (terme trouvé !)"
preview_content.update(preview_text)
else:
preview_content.update("En attente de saisie...")
def on_input_submitted(self, event: Input.Submitted) -> None:
"""Gère la soumission du champ de recherche (touche Entrée)"""
if event.input.id == "search-input":
# Sélectionner le premier résultat
results_list = self.query_one("#results-list")
if results_list.children:
first_item = results_list.children[0]
if isinstance(first_item, TermListItem):
self.toggle_term_expansion(first_item.term)
elif event.input.id == "llm-input":
# Soumettre la question au LLM
self.query_one("#send-llm-btn").press()
def update_results(self) -> None:
"""Met à jour la liste des résultats"""
search_text = self.current_input.lower().strip()
# Filtrer les termes
if search_text:
self.filtered_terms = [
term for term in self.terms
if search_text in term.lower()
]
else:
self.filtered_terms = self.terms.copy()
# Mettre à jour la ListView
results_list = self.query_one("#results-list")
results_list.clear()
for term in self.filtered_terms:
definition = self.dictionary[term]
# Vérifier si le terme est expansé
expanded = term in self.expanded_terms
item = TermListItem(term, definition, expanded)
results_list.append(item)
# Mettre à jour le compteur
results_label = self.query_one("#results-label")
count = len(self.filtered_terms)
if count == 0:
results_label.update("❌ Aucun résultat trouvé")
else:
results_label.update(f"📋 {count} terme{'s' if count > 1 else ''} trouvé{'s' if count > 1 else ''}")
def on_list_view_selected(self, event: ListView.Selected) -> None:
"""Gère la sélection d'un terme dans la liste"""
if event.item and isinstance(event.item, TermListItem):
# Basculer l'expansion du terme sélectionné
self.toggle_term_expansion(event.item.term)
def toggle_term_expansion(self, term: str) -> None:
"""Bascule l'état d'expansion d'un terme"""
if term in self.expanded_terms:
self.expanded_terms.remove(term)
else:
# Si un autre terme est expansé, le réduire
if len(self.expanded_terms) > 0:
# Réduire tous les autres termes
for other_term in list(self.expanded_terms):
if other_term != term:
self.expanded_terms.remove(other_term)
self.expanded_terms.add(term)
# Mettre à jour l'affichage
self.update_results()
# Mettre à jour le champ de recherche
search_input = self.query_one("#search-input")
search_input.value = term
self.current_input = term
self.update_preview()
def on_key(self, event: events.Key) -> None:
"""Gère les touches spéciales"""
if event.key == "escape":
# Effacer la recherche
search_input = self.query_one("#search-input")
search_input.value = ""
self.current_input = ""
self.expanded_terms.clear()
self.update_preview()
self.update_results()
search_input.focus()
elif event.key == "ctrl+f":
# Focus sur la recherche
self.query_one("#search-input").focus()
elif event.key == "ctrl+l":
# Focus sur le champ LLM
self.query_one("#llm-input").focus()
elif event.key == "enter":
# Si un item est sélectionné, basculer son expansion
results_list = self.query_one("#results-list")
if results_list.children and hasattr(results_list, 'highlighted_child'):
highlighted = results_list.highlighted_child
if highlighted and isinstance(highlighted, TermListItem):
self.toggle_term_expansion(highlighted.term)
@work(thread=True)
def send_to_ollama(self, question: str) -> None:
"""Envoie une question à Ollama et affiche la réponse en streaming"""
response_widget = self.query_one("#llm-response")
# Afficher la question
response_widget.update(f"[bold cyan]❓ {question}[/bold cyan]\n\n[yellow]⏳ Génération en cours...[/yellow]")
# Préparer la requête
payload = {
"model": self.ollama_model,
"prompt": question,
"stream": True
}
full_response = ""
try:
# Faire la requête HTTP avec streaming
with httpx.stream(
"POST",
self.ollama_url,
json=payload,
timeout=120.0
) as response:
if response.status_code != 200:
error_msg = f"❌ Erreur HTTP {response.status_code}: {response.text}"
self.call_from_thread(response_widget.update, error_msg)
return
# Lire le stream
for line in response.iter_lines():
if line:
try:
data = json.loads(line)
if "response" in data:
chunk = data["response"]
full_response += chunk
# Mettre à jour l'affichage depuis le thread principal
display_text = f"[bold cyan]❓ {question}[/bold cyan]\n\n{full_response}[yellow]▌[/yellow]"
self.call_from_thread(response_widget.update, display_text)
if data.get("done", False):
break
except json.JSONDecodeError:
continue
# Afficher la réponse complète
final_display = f"[bold cyan]❓ {question}[/bold cyan]\n\n{full_response}"
self.call_from_thread(response_widget.update, final_display)
except httpx.TimeoutException:
error_msg = "❌ Erreur : Timeout - Ollama ne répond pas"
self.call_from_thread(response_widget.update, error_msg)
except httpx.ConnectError:
error_msg = "❌ Erreur : Impossible de se connecter à Ollama sur localhost:11434"
self.call_from_thread(response_widget.update, error_msg)
except Exception as e:
error_msg = f"❌ Erreur : {str(e)}"
self.call_from_thread(response_widget.update, error_msg)
def on_button_pressed(self, event: Button.Pressed) -> None:
"""Gère les pressions de boutons"""
if event.button.id == "send-llm-btn":
llm_input = self.query_one("#llm-input")
question = llm_input.value.strip()
if not question:
response_widget = self.query_one("#llm-response")
response_widget.update("❌ Veuillez entrer une question.")
return
# Vérifier la connexion à Ollama
# Désactiver le bouton pendant le traitement
send_btn = self.query_one("#send-llm-btn")
send_btn.disabled = True
send_btn.label = "⏳ En cours..."
# Lancer la requête
self.send_to_ollama(question)
# Réactiver le bouton après un court délai
# Le bouton sera réactivé dans la méthode de réponse
elif event.button.id == "clear-llm-btn":
response_widget = self.query_one("#llm-response")
response_widget.update("")
llm_input = self.query_one("#llm-input")
llm_input.value = ""
llm_input.focus()
def after_send_to_ollama(self) -> None:
"""Réactive le bouton d'envoi après la réponse"""
send_btn = self.query_one("#send-llm-btn")
send_btn.disabled = False
send_btn.label = "Envoyer"
# Point d'entrée de l'application
if __name__ == "__main__":
app = DictionaryApp()
app.run()
```
## Principales modifications apportées :
### 1. **Ajout de la zone LLM**
- Un nouveau conteneur `#llm-container` avec un champ de saisie `#llm-input`
- Un bouton "Envoyer" pour soumettre la question
- Une zone `#llm-response` pour afficher la réponse en streaming
### 2. **Fonction de streaming asynchrone avec `@work(thread=True)`**
```python
@work(thread=True)
def send_to_ollama(self, question: str) -> None:
# Utilise httpx.stream pour lire les chunks
with httpx.stream(...) as response:
for line in response.iter_lines():
# Traite chaque chunk
self.call_from_thread(response_widget.update, display_text)
```
### 3. **Mise à jour en temps réel**
- Utilise `self.call_from_thread()` pour mettre à jour l'interface depuis le thread
- Affiche un curseur clignotant `▌` pendant le streaming
- La réponse s'affiche progressivement
### 4. **Gestion des erreurs**
- Timeout
- Connexion refusée
- Erreurs HTTP
### 5. **Raccourcis clavier**
- `Ctrl+L` : Focus sur le champ LLM
- `Entrée` dans le champ LLM : Soumet la question
## Installation des dépendances :
```bash
pip install textual httpx
```
## Configuration :
- Vérifiez que Ollama est installé et en cours d'exécution : `ollama serve`
- Vérifiez que le modèle `llama3.2` est disponible : `ollama pull llama3.2`
- Vous pouvez changer le modèle dans `self.ollama_model`
## Utilisation :
1. Lancez l'application
2. Utilisez la zone LLM en bas pour poser des questions
3. Les réponses s'affichent en streaming en temps réel
4. Vous pouvez toujours utiliser la recherche de dictionnaire en parallèle
L'interface reste parfaitement réactive pendant le streaming grâce à l'utilisation du thread séparé avec `@work(thread=True)`.

View file

@ -1,25 +0,0 @@
Voici une liste de bases de données graphes open source qui supportent Cypher. Elle inclut les bases que vous avez mentionnées et d'autres options.
### Liste des bases de données open source supportant Cypher
* **Memgraph** : Base de données en mémoire, optimisée pour les scénarios nécessitant de très faibles latences, comme la détection de fraude en temps réel ou l'analyse de flux de données. Elle est reconnue pour son efficacité mémoire comparée à Neo4j.
* **ONgDB (Open Native Graph Database)** : Un fork open source de Neo4j Enterprise Edition. Son principal avantage est de proposer des fonctionnalités de clustering et de haute disponibilité gratuitement, contrairement à Neo4j. Sa consommation mémoire est proche de celle de Neo4j.
* **JanusGraph** : Conçue pour le passage à l'échelle et les données massives. Elle est distribuée et s'appuie sur des systèmes de stockage comme Cassandra ou HBase. Elle est donc plus complexe à opérer, mais est un choix pour de très gros volumes de données. Elle utilise nativement le langage Gremlin, mais peut supporter Cypher via des extensions.
* **RedisGraph** : Un module pour Redis qui utilise le langage Cypher. Étant entièrement en mémoire, elle excelle pour des requêtes en temps réel ultra-rapides. En revanche, elle est moins adaptée pour des analyses de graphes très profondes.
* **ArcadeDB** : Une base de données multi-modèle (Graphe, Document, Clé-Valeur, etc.) sous licence Apache 2.0, ce qui est très permissif pour une utilisation commerciale. Son moteur openCypher est compatible, ce qui facilite la migration depuis Neo4j.
* **Kùzu** : Une base de données de graphes *embarquable* (comme SQLite), écrite en C++ et optimisée pour la vitesse. Elle implémente Cypher, ce qui en fait un bon choix pour des applications légères, intégrées ou pour les tests.
---
### 🔎 Faire le bon choix
Pour vous aider à décider, voici une synthèse des forces de chaque base en fonction de vos besoins :
* **Pour les performances en temps réel et la mémoire** : **Memgraph** est un excellent candidat si votre priorité est la vitesse, car elle fonctionne en mémoire et est optimisée en C++ .
* **Pour la haute disponibilité open source** : **ONgDB** est une alternative directe à Neo4j Enterprise, offrant des fonctionnalités de clustering sans coût de licence .
* **Pour passer à l'échelle avec d'énormes volumes de données** : **JanusGraph** est conçu pour la distribution, mais cela ajoute de la complexité .
* **Pour la flexibilité et un modèle de données unique** : **ArcadeDB** se distingue par son approche multi-modèle et sa licence permissive . **Kùzu** est idéal si vous cherchez une base de données légère et embarquable .
* **Pour des requêtes ultra-rapides sur des données légères** : **RedisGraph**, en tant que module Redis en mémoire, est parfait pour des cas comme la personnalisation en temps réel .
Avez-vous une idée plus précise de votre cas d'usage (ex: volume de données, besoin de scalabilité, type d'analyses) pour que je puisse vous aiguiller plus finement ?

View file

@ -1,46 +0,0 @@
---
description: manipuler les variables d'une configuration d'une manière légère, approche orientée graph
---
# Graph based tools
L'idée est d'organiser en graphe et de représenter un ensemble des variables susceptibles d'évoluer dynamiquement. On démarrera à partir d'un lexique (dictionnaire) existant et on essayera de "dégager des faits" pour faire en sorte que le dictionnaire ne soit pas trop lourd à manipuler.
deux options :
- graph based
- Rougail ! -> FIXME [[RougailBasedAppStructuration]]
Le faire grâce à Rougail, qui est très générique et qui peut avoir un usage en "data modeling", est évident. Mais il s'agit de ne négliger aucune piste.
Concernant le choix d'une graph database, pourquoi pas graph db, enfin la version libre. 
Leur doc est pas mal,
[https://graphdb.dev/article/Introduction_to_Graph_Databases.html](https://graphdb.dev/article/Introduction_to_Graph_Databases.html)
C'est bien pensé.
Je sais pas quel est ton niveau en graphe de, voici un bon tuto :
[https://graphdb.dev/article/Introduction_to_Graph_Databases.html](https://graphdb.dev/article/Introduction_to_Graph_Databases.html)
[https://www.emilien-guilmineau.fr/posts/graphdb/10-what-is-it/](https://www.emilien-guilmineau.fr/posts/graphdb/10-what-is-it/)
Et sur comment modéliser les datas :
[https://www.emilien-guilmineau.fr/posts/graphdb/20-how-to-model-data-for-graph/](https://www.emilien-guilmineau.fr/posts/graphdb/20-how-to-model-data-for-graph/)
## bases possibles
- [[CypherBasedGraphDB]]
- [[SparqlVsCypher]]
### pas d'ontologies
Perso je ne sais pas encore ce que je vais choisir comme base, enfin je n'ai pas besoin de modéliser ça en ontologies avec du RDF donc ça simplifie les choses, parce que les ontologies c'est un peu lourd, je te déconseille ça.

View file

@ -1,97 +0,0 @@
## question
comment trouver une meilleure manière de faire du développement d'IHM (UI) aujourd'hui dans l'ère de l'IA ?
Faut-il centrer nos UI sur le prompt ?
Dans ce cas,
- quelles librairies choisir, qui permette de construire un prompt web et aussi d'afficher des widgets, charts, etc... adaptés à l'utilisateur
- quel système de génération d'UI ?
l'ui doit être plus dynamique, "generative ui", elle doit s'adapter au contexte.
Cela est bien différent d'une SPA (single page app), et necessite une structuration pour ne pas produire des widgets hallucinés par l'ia.
Est-ce que l'approche API first est toujours valable ?
# A propos des UI
Il faut complètement repenser les IHM (UI).
L'arrivée des IA a complètement changé l'interface utilisateur.
Elle reste une appli web, mais :
- "generative UI" (une application web qui est conçue par l'IA en fonction
du contexte de l'utilisateur, donc une application beaucoup plus générique
une application générée en fonction du contexte en quelque sorte,
- prompt first. L'injonction de centrer l'app sur un dialogue avec l'IA est forte.
le point d'entrée est le promt. Les widgets qui doivent apparaître sont
issues d'interaction avec le prompt (champs de formulaires, charts, etc...)
L'application doit donc devenir dynamique. Pas seulement dynamique au niveau
des pages web et des queries. Dynamique au niveau de l'ergonomie.
Les widgets doivent apparaître en fonction de la demande utilisateur.
Mais il faut une base structurelle forte qui permette d'éviter des widgets
complètement hallucinés et ne correspondant pas au contexte.
Il faut des outils de validation de la consistency, de la cohérence
de l'application.
La réponse courte est **oui, l'ère de l'IA redéfinit fondamentalement le développement d'IHM**. Il ne s'agit plus de concevoir des interfaces statiques, mais de créer des surfaces d'interaction dynamiques, générées et adaptées par l'IA en fonction du contexte. Cette approche, appelée "Generative UI" ou "Agent-driven UI", place le prompt et la conversation au centre de l'expérience .
Cependant, cette nouvelle liberté apporte son lot de défis, principalement autour de la fiabilité, de la sécurité et de la cohérence.
Voici une feuille de route pour naviguer dans ce nouveau paradigme.
### 🤔 Centrer l'UI sur le prompt ? Oui, mais...
Oui, l'interface utilisateur doit être centrée sur le prompt, mais de manière structurée. Le prompt devient le principal vecteur d'intention de l'utilisateur. L'IA interprète cette intention et génère une interface utilisateur dédiée à la tâche à accomplir.
Cela ne signifie pas pour autant abandonner les widgets, graphiques et autres composants d'interface riches. L'IA doit être capable de les assembler et de les configurer à la volée. La clé est que l'interface (UI) est dictée par le besoin de l'utilisateur, qui est lui-même exprimé par le prompt, transformant l'agent en un véritable "orchestrateur d'interface".
### 🎨 Choisir les bonnes librairies et systèmes de génération d'UI
La génération d'UI par l'IA se décline en plusieurs approches, classées du plus contrôlé au plus ouvert. Comprendre ces approches vous aidera à choisir les outils adaptés.
**1. L'approche "UI Déclarative" (Recommandée)**
C'est l'approche qui répond le mieux à votre besoin de sécurité et de contrôle. L'IA ne génère pas de code exécutable, mais un **spécification JSON structurée** qui décrit l'UI (les composants, leurs propriétés et leurs données). Le front-end possède un "catalogue" de composants prédéfinis qu'il sait rendre, et il utilise cette spécification pour les afficher .
* **Avantages:** Sécurisé (pas d'exécution de code arbitraire), contrôle total sur le rendu, possibilité de streamer l'UI au fur et à mesure de la génération, et "data-binding" intégré pour des interactions réactives .
* **Librairies clés pour cette approche:**
| Librairie/Framework | Description | Points clés |
| :--- | :--- | :--- |
| **`json-render`** | Framework "Generative UI" polyvalent. | Permet de définir un catalogue de composants avec leurs schémas. L'IA génère un JSON conforme. Supporte React, Vue, React Native, et même Web Components. Idéal pour un contrôle total avec un rendu cross-platform . |
| **`genui` (Flutter)** | Package Flutter pour UI génératives. | Utilise les concepts de catalogue et de modèle de données. Le `GenUiConversation` gère tout le cycle de vie, de l'envoi du prompt au rendu et à la gestion des interactions . |
| **A2UI (Agent-to-User Interface)** | Protocole standardisé (Google) pour ce type d'UI. | C'est une spécification ouverte, soutenue par des implémentations comme **CopilotKit** (React) ou **Freesail** (React). Elle standardise les messages (création de surface, mise à jour des composants, mise à jour des données) pour une meilleure interopérabilité . |
| **`prefab-ui` (Python)** | Framework pour construire des UIs en Python, conçu pour MCP Apps. | Idéal si vous voulez que l'agent génère lui-même l'UI en Python. Il propose un DSL (Domain Specific Language) en Python pour décrire l'interface, qui est ensuite compilée en JSON et rendue par un front-end React . |
**2. L'approche "UI Contrôlée"**
C'est l'approche la plus simple et la plus sûre. Le développeur crée des composants UI (par exemple, `WeatherCard`, `DataChart`) et l'agent décide lequel utiliser et avec quelles données, souvent via l'appel d'un outil. L'UI est pré-construite, l'IA ne fait que la sélectionner et la paramétrer .
* **Exemple:** L'agent appelle un outil `get_weather`. Sur le front-end, on sait que cet outil doit afficher un composant `WeatherCard`. On peut même montrer différents états (chargement, résultat) .
**3. L'approche "UI Ouverte" (À Utiliser avec Prudence)**
L'agent génère du code complet (HTML, etc.) qui est rendu dans un conteneur sécurisé (comme un iframe). C'est la plus flexible, mais aussi la plus risquée en termes de sécurité et de cohérence visuelle .
### 🔒 Éviter les "Widgets Hallucinés" : L'Importance du Design System
C'est ici que la structuration est cruciale. Pour éviter que l'IA ne "produise des widgets hallucinés", vous devez lui fournir un cadre strict. L'outil principal est le **Design System** et le **Catalogue de Composants**.
1. **Définissez un Catalogue :** Vous créez une "boîte à outils" de composants que l'IA est autorisée à utiliser. Pour chaque composant, vous définissez son nom, sa description et son schéma de propriétés (c'est-à-dire quelles données il accepte). Par exemple, un composant `Card` peut avoir une propriété `title` .
2. **Fournissez le Catalogue à l'IA :** Ce catalogue est inclus dans le prompt système de l'IA. Elle sait ainsi quels sont les "briques" à sa disposition, ce qu'elles font et comment les utiliser .
3. **Validez la Sortie :** Sur le front-end ou via une passerelle, on valide que la spécification JSON générée par l'IA respecte bien le schéma défini dans le catalogue. Cela permet d'ignorer ou de corriger toute tentative de génération de composants non autorisés, éliminant les "hallucinations" structurelles .
> **Point de vigilance :** Les librairies mentionnées (json-render, genui, A2UI) intègrent toutes ce mécanisme de catalogue. C'est la pierre angulaire d'une UI générative fiable.
### 🧱 Structuration d'une UI Dynamique vs SPA
Une UI générative (GenUI) n'est pas une SPA classique. Là où la SPA a un état et un routage prédéfinis, la GenUI est éphémère et contextuelle. Cependant, elle peut s'appuyer sur des architectures existantes.
* **L'approche "API First" est toujours valable et même essentielle.** L'UI générative est une nouvelle couche client qui **consomme** et **envoie** des données via des APIs. La séparation entre le front-end et le back-end reste la bonne pratique.
* **Nouveaux concepts architecturaux à intégrer:**
* **Surfaces :** L'IA peut créer des "surfaces" (comme des zones ou des fenêtres) dans l'UI pour y placer des composants . La chat peut n'être qu'une surface parmi d'autres.
* **Data Binding :** Les composants UI sont liés à un modèle de données. Les interactions de l'utilisateur (ex: remplir un champ) mettent à jour ce modèle, ce qui peut déclencher de nouvelles actions de l'agent ou la mise à jour d'autres composants .
* **State Store :** Des bibliothèques comme Zustand, Jotai ou Redux peuvent être utilisées comme l'état central de l'UI générative, notamment pour gérer le data binding et les conditions d'affichage .
### 💎 Conclusion : Comment se lancer ?
Le développement d'IHM à l'ère de l'IA est un changement de paradigme majeur, mais il repose sur des principes solides.
1. **Définissez votre approche :** Commencez avec une approche **"UI Contrôlée"** en utilisant des outils comme `useFrontendTool` de CopilotKit pour des cas simples. Elle est plus facile à mettre en œuvre et très sécurisée .
2. **Construisez votre Catalogue :** Pour une approche plus dynamique, choisissez un framework supportant l'UI déclarative (**json-render**, **A2UI avec CopilotKit/Freesail**) et investissez du temps à définir un **design system et un catalogue de composants solide** . C'est la clé pour garder le contrôle et la cohérence.
3. **Pensez "Maîtriser pour Déléguer" :** Comme le souligne la pratique "Claude Design" chez GitLab, l'IA est un accélérateur de créativité et un partenaire de réflexion puissant, mais elle ne remplace pas le jugement humain . Utilisez-la pour explorer, itérer et générer rapidement des hypothèses, puis affinez et validez les résultats. Votre rôle évolue de "constructeur d'UI" à "architecte et validateur d'UI générées".

View file

@ -1,2 +0,0 @@
# TODO

View file

@ -1,34 +0,0 @@
Cypher n'est pas une alternative directe à SPARQL, car ils sont conçus pour des modèles de données fondamentalement différents. Le choix entre les deux dépend donc avant tout de la nature de vos données et de vos objectifs.
La différence réside dans la distinction entre les **graphes de propriétés** (Property Graphs) et les **graphes RDF** (Resource Description Framework).
### 📊 La différence fondamentale : le modèle de données
| Caractéristique | Cypher (et les graphes de propriétés) | SPARQL (et les graphes RDF) |
| :--- | :--- | :--- |
| **Modèle de données** | Graphes de propriétés : nœuds et relations (arcs) qui peuvent tous deux posséder des paires clé-valeur (propriétés). | Graphes RDF : un ensemble de triplets (sujet, prédicat, objet). C'est un modèle standardisé par le W3C, conçu pour le Web sémantique. |
| **Philosophie & Standardisation** | Langage industriel de fait (originellement pour Neo4j) qui s'oriente vers une norme ISO (GQL). | Standard officiel du W3C (SPARQL 1.1), garantissant une forte interopérabilité entre systèmes. |
| **Force principale** | **Exploration intuitive et performante** des relations. Excellent pour les applications où la structure du graphe et ses attributs sont au premier plan (réseaux sociaux, détection de fraude, recommandation). | **Intégration et raisonnement sémantique**. Excellent pour relier des données hétérogènes, utiliser des ontologies et effectuer des requêtes fédérées sur des sources de données distribuées. |
| **Expressivité des Relations** | Les relations sont des citoyens de première classe, peuvent avoir des propriétés (ex: une relation `ACHAT` avec les propriétés `date` et `montant`). | Les relations (prédicats) ne peuvent pas avoir de propriétés directement. Pour ajouter des métadonnées à une relation, il faut utiliser des techniques de "réification", qui sont plus complexes. |
### 🤔 Comment faire votre choix ?
Le choix dépend entièrement de votre cas d'usage :
* **Choisissez Cypher (graphe de propriétés)** si :
* Vous construisez une application opérationnelle comme un moteur de recommandation, un outil de détection de fraude, une analyse de réseau social ou de parcours client.
* Vous avez besoin d'une syntaxe intuitive et visuelle (en ASCII-art) pour exprimer des motifs de graphe (ex: `(a:Person)-[:KNOWS]->(b)`).
* La performance et la simplicité de modélisation d'attributs sur les relations sont essentielles.
* **Choisissez SPARQL (graphe RDF)** si :
* Vous travaillez dans un contexte où l'interopérabilité et le partage de données sont clés (ex: données gouvernementales liées, publications scientifiques, bases de connaissances).
* Vous devez effectuer des requêtes fédérées sur plusieurs bases de données RDF distantes.
* Vous avez besoin de capacités de raisonnement sémantique avancées en utilisant des ontologies (OWL, RDFS).
### 🚀 La convergence : GQL et l'interopérabilité
Le paysage est en pleine évolution. Le nouveau standard **ISO GQL (Graph Query Language)** s'inspire fortement de Cypher, ce qui pourrait en faire le futur langage unifié pour les graphes de propriétés. Par ailleurs, des solutions comme **Amazon Neptune** montrent que l'interopérabilité est possible en supportant à la fois SPARQL et openCypher sur des données RDF, ou en permettant à openCypher d'interroger directement un graphe RDF.
En résumé, Cypher est l'outil idéal pour les "applications graphiques" intuitives, tandis que SPARQL est le standard pour l'échange de données et le Web sémantique.
Si vous avez un cas d'usage plus spécifique en tête, je pourrai vous aider à préciser la solution la plus adaptée.

View file

@ -1,18 +0,0 @@
# Baklava's documentation
## Repenser les UI
[[PromptBasedApplications]]
## Variable name search engine
- [[lexique]]
- [[lexique_variable]]
## UI structuration tool
- [[GraphBasedTool]]
## LLM prompt UI
- [[AsynchronousPrompts]]

View file

@ -1,93 +0,0 @@
---
description: comment faire pour que le LLM puisse repérer les bons noms de variable dans une conversation
---
Voici une solution complète pour transformer votre lexique en **persona LLM spécialisé en recherche de mots-clés**, avec un comportement précis pour quil devine le mot que vous cherchez pendant une conversation.
---
## 1. Constitution du lexique (format à lui fournir)
Donnez votre lexique au LLM sous forme structurée, par exemple :
```json
{
"lexique": [
{
"mot": "épistémè",
"domaine": "philosophie",
"définition": "ensemble des connaissances et des discours qui fondent une époque",
"synonymes": ["savoir", "paradigme"],
"associations": ["Foucault", "archéologie du savoir"]
},
{
"mot": "sérendipité",
"domaine": "méthodologie",
"définition": "découverte inattendue par hasard et sagacité",
"synonymes": ["heureux hasard", "découverte fortuite"],
"associations": ["Walpole", "recherche"]
}
]
}
```
---
## 2. Prompt système pour le comportement de lagent
> **System prompt :**
>
> Tu es un **lexicographe interactif**. Ton rôle est didentifier le mot-clé quun utilisateur cherche, en utilisant uniquement le lexique que je tai fourni.
>
> **Règles strictes de ton comportement :**
> 1. **Tu ne donnes jamais directement le mot** avant davoir fait un diagnostic.
> 2. **Tu poses au maximum 3 questions** pour cerner le mot recherché (domaine, sens, contexte, synonyme connu, etc.).
> 3. Après tes questions, tu **proposes une unique suggestion** (le mot le plus probable), accompagnée de sa définition courte.
> 4. Si lutilisateur confirme, tu arrêtes.
> 5. Si lutilisateur infirme, tu **proposes un second mot** (sans refaire 3 questions).
> 6. Si après 2 essais tu échoues, tu réponds : « Je ne trouve pas ce mot dans mon lexique. Pouvez-vous me donner un synonyme ou une phrase dexemple ? »
> 7. **Tu ne sors jamais du lexique** tu ne fabriques pas de mots.
---
## 3. Comportement conversationnel détaillé (à ajouter dans le prompt)
> **Ton flux de dialogue :**
> - Accueil : *« Je connais [N] mots. Décrivez-moi le mot que vous cherchez en quelques mots (domaine, usage, idée générale). »*
> - Après la réponse de lutilisateur :
> - Filtre le lexique par domaine, synonymes, associations.
> - Si plusieurs mots correspondent, pose **une question discriminante** (ex : « Est-ce plutôt lié à la science ou à lart ? »).
> - Si un mot correspond à 90 %, **propose-le**.
> - Si lutilisateur est vague, reformule : *« Pourriez-vous me donner une phrase vide où ce mot irait ? »*
> - Toujours **citer la définition** quand tu proposes un mot.
> - **Ne pas lister plusieurs mots** toujours un seul par proposition.
---
## 4. Exemple de dialogue attendu
**Vous :** *Je cherche un mot qui veut dire « trouver quelque chose sans le chercher ».*
**Agent :** *Domaine : plutôt scientifique, littéraire ou quotidien ?*
**Vous :** *Scientifique, dans les méthodes.*
**Agent :** *Je pense au mot « sérendipité » découverte inattendue par hasard et sagacité. Est-ce celui-là ?*
**Vous :** *Oui !*
**Agent :** *Parfait !*
---
## 5. Bonus : comportement en cas de mot proche mais absent
> Si lutilisateur décrit un mot qui nexiste pas dans votre lexique, mais quun mot très proche existe, vous dites :
> *« Le mot le plus proche dans mon lexique est [X] (définition). Est-ce que cela correspond à votre idée ? »*
---
## 6. Option : mode « devinette » (plus ludique)
Vous pouvez ajouter dans le prompt :
> *Si lutilisateur le demande, tu peux jouer à « 20 questions » en te limitant à 5 questions fermées (oui/non) pour trouver le mot.*

View file

@ -1,100 +0,0 @@
---
description: personas pour que le lexique puisse se comporter comme un moteur de recherche de nom de variables
---
Parfait. Voici le **prompt système final**, prêt à être copié-collé dans ChatGPT, Claude ou tout autre LLM (mode personnalisé / système).
Ce prompt intègre :
- le comportement de recherche
- la règle des 3 questions max
- la suggestion unique
- la gestion de léchec
- **la prise en compte explicite du mot recherché en tant que "variable"** (lutilisateur peut lappeler ainsi)
---
## PROMPT SYSTÈME À COPIER
```
Tu es un lexicographe interactif spécialisé dans la recherche de mots-clés à partir dun lexique que je tai fourni.
TON RÔLE :
Tu dois identifier le mot que lutilisateur cherche. Lutilisateur peut désigner ce mot recherché par le terme "variable" (ex : "je cherche une variable", "ma variable est...", "aide-moi à trouver cette variable"). Dans ce contexte, "variable" est un synonyme de "mot recherché" ou "mot-clé". Tu dois interpréter cela naturellement.
RÈGLES DE COMPORTEMENT STRICTES :
1. Tu ne donnes JAMAIS le mot directement avant davoir fait un diagnostic.
2. Tu poses AU MAXIMUM 3 questions pour cerner le mot (domaine, sens, contexte, synonyme connu, usage, etc.).
3. Après ces questions, tu PROPOSES UNE UNIQUE SUGGESTION (le mot le plus probable), accompagnée de sa définition courte.
4. Si lutilisateur confirme, tu tarrêtes et tu affiches : "Variable trouvée : [mot]".
5. Si lutilisateur infirme, tu PROPOSES UN SECOND MOT (sans poser de nouvelles questions).
6. Si après 2 essais tu échoues, tu réponds : "Je ne trouve pas cette variable dans mon lexique. Pouvez-vous me donner un synonyme ou une phrase dexemple ?"
7. Tu ne sors JAMAIS du lexique tu ninventes pas de mots.
8. Tu ne listes jamais plusieurs mots en même temps. Une seule proposition à la fois.
FLUX DE DIALOGUE OBLIGATOIRE :
- Ouverture : "Je connais [N] mots dans mon lexique. Décrivez-moi la variable que vous cherchez (domaine, usage, idée générale)."
- Après la réponse de lutilisateur :
- Filtre le lexique par domaine, synonymes, associations.
- Si plusieurs mots correspondent, pose UNE question discriminante (ex : "Est-ce lié à la science ou à lart ?").
- Si un mot correspond à 90 %, propose-le.
- Si lutilisateur est vague, reformule : "Pouvez-vous me donner une phrase vide où cette variable irait ?"
- Quand tu proposes un mot, tu cites toujours sa définition.
CAS PARTICULIER :
Si lutilisateur dit explicitement "variable" pour désigner le mot cherché, tu considères que c'est son mot pour "mot-clé". Tu réponds normalement en utilisant parfois le mot "variable" dans tes réponses pour faire écho à son langage (ex : "Je pense que votre variable est...").
OBJECTIF FINAL :
Retrouver la variable (le mot) avec le moins de questions possible, en restant strictement dans le lexique fourni.
```
---
## PROMPT UTILISATEUR INITIAL (à envoyer juste après)
```
Voici mon lexique (au format JSON) :
[COLLE ICI TON LEXIQUE]
Maintenant, applique le rôle que je viens de te donner. Je vais chercher une variable dans ce lexique. Commence.
```
---
## EXEMPLE DE DIALOGUE AVEC LA NOTION DE "VARIABLE"
**Utilisateur :** *Je cherche une variable en philosophie.*
**Agent :** *Je connais 42 mots dans mon lexique. Pouvez-vous me donner une idée du sens de cette variable ?*
**Utilisateur :** *Cest un mot qui désigne un système de pensée propre à une époque.*
**Agent :** *Votre variable est-elle plutôt liée à un auteur précis ?*
**Utilisateur :** *Oui, Foucault.*
**Agent :** *Je pense que votre variable est « épistémè » ensemble des connaissances et des discours qui fondent une époque. Est-ce bien cela ?*
**Utilisateur :** *Oui !*
**Agent :** *Variable trouvée : épistémè.*
---
## VARIANTE SI L'UTILISATEUR DIT "VARIABLE" DÈS LE DÉBUT
**Utilisateur :** *Aide-moi à trouver une variable.*
**Agent :** *Je connais 42 variables dans mon lexique. Décrivez-moi celle que vous cherchez (domaine, usage, idée générale).*
---
## SI L'UTILISATEUR PARLE DE "VARIABLE" EN COURS DE ROUTE
**Utilisateur :** *En fait, cette variable, je lai déjà entendue dans un contexte de méthodologie.*
**Agent :** *Merci pour cette précision. Je reformule : votre variable serait-elle liée à une découverte fortuite ?*
---
Souhaitez-vous que jajoute une **version plus courte** pour les LLM avec limite de tokens, ou une **version avec exemples intégrés** directement dans le prompt système ?

View file

@ -1,10 +0,0 @@
---
type: persona
description: initial user prompt
---
Voici mon lexique (au format JSON) :
[COLLE ICI TON LEXIQUE]
Maintenant, applique le rôle que je viens de te donner. Je vais chercher une variable dans ce lexique. Commence.

View file

@ -1,35 +0,0 @@
---
type: persona
description: prompt système
---
Tu es un lexicographe interactif spécialisé dans la recherche de mots-clés à partir dun lexique que je tai fourni.
TON RÔLE :
Tu dois identifier le mot que lutilisateur cherche. Lutilisateur peut désigner ce mot recherché par le terme "variable" (ex : "je cherche une variable", "ma variable est...", "aide-moi à trouver cette variable"). Dans ce contexte, "variable" est un synonyme de "mot recherché" ou "mot-clé". Tu dois interpréter cela naturellement.
RÈGLES DE COMPORTEMENT STRICTES :
1. Tu ne donnes JAMAIS le mot directement avant davoir fait un diagnostic.
2. Tu poses AU MAXIMUM 3 questions pour cerner le mot (domaine, sens, contexte, synonyme connu, usage, etc.).
3. Après ces questions, tu PROPOSES UNE UNIQUE SUGGESTION (le mot le plus probable), accompagnée de sa définition courte.
4. Si lutilisateur confirme, tu tarrêtes et tu affiches : "Variable trouvée : [mot]".
5. Si lutilisateur infirme, tu PROPOSES UN SECOND MOT (sans poser de nouvelles questions).
6. Si après 2 essais tu échoues, tu réponds : "Je ne trouve pas cette variable dans mon lexique. Pouvez-vous me donner un synonyme ou une phrase dexemple ?"
7. Tu ne sors JAMAIS du lexique tu ninventes pas de mots.
8. Tu ne listes jamais plusieurs mots en même temps. Une seule proposition à la fois.
FLUX DE DIALOGUE OBLIGATOIRE :
- Ouverture : "Je connais [N] mots dans mon lexique. Décrivez-moi la variable que vous cherchez (domaine, usage, idée générale)."
- Après la réponse de lutilisateur :
- Filtre le lexique par domaine, synonymes, associations.
- Si plusieurs mots correspondent, pose UNE question discriminante (ex : "Est-ce lié à la science ou à lart ?").
- Si un mot correspond à 90 %, propose-le.
- Si lutilisateur est vague, reformule : "Pouvez-vous me donner une phrase vide où cette variable irait ?"
- Quand tu proposes un mot, tu cites toujours sa définition.
CAS PARTICULIER :
Si lutilisateur dit explicitement "variable" pour désigner le mot cherché, tu considères que c'est son mot pour "mot-clé". Tu réponds normalement en utilisant parfois le mot "variable" dans tes réponses pour faire écho à son langage (ex : "Je pense que votre variable est...").
OBJECTIF FINAL :
Retrouver la variable (le mot) avec le moins de questions possible, en restant strictement dans le lexique fourni.

View file

@ -2,3 +2,5 @@
mkdocs build
# local VM publication
rsync -avH --force --stats ./site/* ../../../site/static/bribes/baklava/
# publish static website
./autocommit.py