first commit

This commit is contained in:
Ladebeze66 2025-03-27 18:40:52 +01:00
commit f6aaf15a33
66 changed files with 5899 additions and 0 deletions

3
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,3 @@
{
"commentTranslate.targetLanguage": "fr"
}

297
README.md Normal file
View File

@ -0,0 +1,297 @@
# LLM Lab
Un laboratoire pour tester et comparer différents modèles de langage (LLM) via Ollama.
## Fonctionnalités
- **Modèles intégrés** : Support pour Mistral 7B, CodeLlama 13B et Llama2 13B via Ollama
- **Agents spécialisés** : Agents configurés pour différentes tâches (code, documentation, gestion de projet...)
- **Interface graphique de chat** : Interface visuelle complète pour interagir avec les agents et personnaliser les paramètres
- **Moniteur système** : Interface graphique pour surveiller les ressources système, Ollama et GPU
- **Interface CLI** : Interface en ligne de commande simple pour interagir avec les agents
## Modèles disponibles
Ce projet prend en charge les modèles suivants :
- **Mistral 7B** : `mistral:latest` via Ollama - pour des tests rapides et la documentation
- **CodeLlama 13B Python** : `codellama:13b-python` via Ollama - pour le développement et le code
- **Llama2 13B** : `llama2:13b` via Ollama - pour la gestion de connaissances et de projet
## Agents spécialisés
- **cursor** : Agent de programmation (CodeLlama) pour Python, JavaScript et développement web
- **obsidian** : Agent de gestion de connaissances (Llama2) pour l'organisation d'informations
- **test** : Agent de test rapide (Mistral) pour vérifier rapidement les fonctionnalités
- **python** : Expert Python (CodeLlama)
- **webdev** : Expert développement web (CodeLlama)
- **projectmanager** : Chef de projet (Llama2)
- **documentaliste** : Spécialiste en documentation (Mistral)
## Installation
### Prérequis
- Python 3.8+
- [Ollama](https://ollama.ai/) installé et en cours d'exécution sur `localhost:11434`
- Les modèles correspondants installés dans Ollama
### Installation des modèles Ollama
```bash
# Installation des modèles
ollama pull mistral:latest
ollama pull codellama:13b-python
ollama pull llama2:13b
```
### Configuration de l'environnement sous Windows
Utilisez le script de configuration automatique pour Windows :
```cmd
# Exécuter le script de configuration
setup_env.bat
```
Ce script va :
1. Vérifier et installer les dépendances nécessaires
2. Créer un nouvel environnement virtuel Python
3. Installer toutes les dépendances requises (y compris les modules spécifiques à Windows)
4. Configurer les scripts pour une utilisation facile
### Configuration de l'environnement sous Linux
Utilisez le script de configuration automatique pour Linux :
```bash
# Exécuter le script de configuration
./setup_env.sh
```
### Installation manuelle (alternative)
Si vous préférez l'installation manuelle :
#### Sous Windows :
```cmd
# Créer un environnement virtuel
python -m venv llmlab
# Activer l'environnement virtuel
llmlab\Scripts\activate
# Installer les dépendances
pip install -r requirements.txt
pip install wmi psutil requests pillow
```
#### Sous Linux :
```bash
# Créer un environnement virtuel
python3 -m venv llmlab
# Activer l'environnement virtuel
source llmlab/bin/activate
# Installer les dépendances
pip install -r requirements.txt
# Installer tkinter si nécessaire (au niveau du système)
sudo apt install python3-tk
```
## Utilisation
### Utilisation avec le script de lancement sous Windows
```cmd
# Afficher l'aide
run.bat help
# Lister les agents disponibles
run.bat list
# Lancer l'interface graphique de chat
run.bat gui
# Lancer le chat en ligne de commande avec un agent spécifique
run.bat chat cursor # Agent de programmation
run.bat chat obsidian # Agent de gestion de connaissances
run.bat chat test # Agent de test rapide
# Lancer le moniteur système
run.bat monitor
```
### Utilisation avec le script de lancement sous Linux
```bash
# Afficher l'aide
./run.sh help
# Lister les agents disponibles
./run.sh list
# Lancer l'interface graphique de chat
./run.sh gui
# Lancer le chat en ligne de commande avec un agent spécifique
./run.sh chat cursor # Agent de programmation
./run.sh chat obsidian # Agent de gestion de connaissances
./run.sh chat test # Agent de test rapide
# Lancer le moniteur système
./run.sh monitor
```
### Utilisation directe
Si vous préférez utiliser directement les scripts Python après avoir activé l'environnement virtuel :
#### Sous Windows :
```cmd
# Activer l'environnement virtuel
llmlab\Scripts\activate
# Lancer l'interface graphique de chat
python chat_gui.py
# Lister les agents disponibles
python chat.py --list
# Lancer le chat en ligne de commande avec un agent
python chat.py cursor
# Lancer le moniteur système
python monitor.py
```
#### Sous Linux :
```bash
# Activer l'environnement virtuel
source llmlab/bin/activate
# Lancer l'interface graphique de chat
./chat_gui.py
# Lister les agents disponibles
./chat.py --list
# Lancer le chat en ligne de commande avec un agent
./chat.py cursor
# Lancer le moniteur système
./monitor.py
```
## Interface graphique de chat
L'interface graphique de chat offre de nombreuses fonctionnalités avancées :
- **Sélection d'agent** : Choisissez parmi tous les agents disponibles
- **Personnalisation des modèles** : Changez le modèle utilisé par un agent
- **Paramètres ajustables** : Modifiez tous les paramètres de génération (température, top-p, etc.)
- **Presets** : Appliquez des configurations prédéfinies (Créatif, Précis, Code, etc.)
- **Sauvegarde et chargement** : Enregistrez et chargez des conversations
- **Exportation** : Exportez vos conversations en markdown, texte ou JSON
Pour lancer l'interface graphique :
```bash
# Sous Linux
./run.sh gui
# Sous Windows
run.bat gui
```
## Moniteur système
Le moniteur système fournit une interface graphique pour surveiller :
- **Ressources système** : CPU, RAM, disque
- **Serveur Ollama** : État, modèles disponibles, tailles
- **GPU NVIDIA** (si disponible) : Utilisation, mémoire, température, processus
- **Journaux d'activité** : Logs en temps réel
Pour l'utiliser :
```bash
# Sous Linux
./run.sh monitor
# Sous Windows
run.bat monitor
```
## Structure du projet
- `core/` : Classes de base et implémentations des modèles
- `base_llm.py` : Classe de base pour tous les modèles LLM
- `factory.py` : Factory pour créer des instances de modèle
- `mistral7b.py` : Implémentation du modèle Mistral 7B
- `codellama13b_python.py` : Implémentation du modèle CodeLlama 13B Python
- `llama2_13b.py` : Implémentation du modèle Llama2 13B
- `agents/` : Configuration des agents spécialisés
- `roles.py` : Définition des différents agents et leurs paramètres
- `utils/` : Outils et utilitaires
- `agent_manager.py` : Gestionnaire pour créer et configurer les agents
- `system_monitor.py` : Moniteur de ressources système
- `chat_ui.py` : Interface graphique de chat
- `tests/` : Tests unitaires et d'intégration
- `examples/` : Exemples d'utilisation
- `logs/` : Logs des résultats de génération (créé automatiquement)
- `chat_history/` : Historique des conversations (créé automatiquement)
- `saved_params/` : Paramètres personnalisés sauvegardés (créé automatiquement)
## Scripts spécifiques pour Windows
Le projet inclut plusieurs scripts batch optimisés pour Windows 11 Pro :
- **setup_env.bat** : Configure l'environnement virtuel Python et installe les dépendances
- **run.bat** : Script principal pour exécuter toutes les fonctionnalités du projet
- **optimize_ollama.bat** : Optimise Ollama pour de meilleures performances sur Windows
- **test_installation.bat** : Vérifie que l'installation est correcte et fonctionnelle
### Optimisation d'Ollama pour Windows
Pour maximiser les performances d'Ollama sur Windows, utilisez le script d'optimisation :
```cmd
# Exécuter en tant qu'administrateur
optimize_ollama.bat
```
Ce script va :
1. Détecter les ressources système disponibles (CPU, RAM, GPU)
2. Configurer Ollama avec des paramètres optimaux
3. Redémarrer le service Ollama pour appliquer les changements
## Personnalisation
### Ajouter un nouvel agent
Pour ajouter un nouvel agent, modifiez le fichier `agents/roles.py` et ajoutez une nouvelle entrée au dictionnaire `AGENTS` :
```python
"mon_agent": {
"model": "mistral:latest", # Modèle à utiliser
"system_prompt": (
"Description du rôle de l'agent..."
),
"params": {
"temperature": 0.7,
"top_p": 0.9,
# Autres paramètres...
}
}
```
### Ajouter un nouveau modèle
Pour ajouter un nouveau modèle LLM :
1. Créez une nouvelle classe dans `core/` (par exemple `core/nouveau_modele.py`)
2. Ajoutez le modèle au registre dans `core/factory.py`
3. Mettez à jour la documentation et les tests

Binary file not shown.

Binary file not shown.

129
agents/roles.py Normal file
View File

@ -0,0 +1,129 @@
# agents/roles.py
AGENTS = {
# === Agents spécialisés avec modèles spécifiques ===
# Agent CodeLlama pour Cursor - Spécialisé en programmation
"cursor": {
"model": "codellama:13b-python", # Utilise CodeLlama 13B Python
"system_prompt": (
"Tu es Cursor, un assistant de programmation expert. "
"Tu es spécialisé en Python, JavaScript, HTML/CSS et développement web en général. "
"Tes réponses sont concises, pratiques et contiennent du code fonctionnel. "
"Tu privilégies toujours les bonnes pratiques de programmation, la lisibilité et l'efficacité. "
"Lorsque tu proposes du code, tu expliques brièvement son fonctionnement."
),
"params": {
"temperature": 0.2, # Faible température pour du code précis
"top_p": 0.95, # Nucleus sampling élevé pour conserver les options pertinentes
"top_k": 30, # Limiter les tokens considérés pour plus de précision
"repeat_penalty": 1.2, # Pénalité élevée pour éviter les répétitions dans le code
"num_predict": 2048, # Nombre élevé de tokens pour générer des blocs de code complets
"stop": ["```", "```python", "```javascript", "```html", "```css"] # Arrêter à la fin des blocs de code
}
},
# Agent Llama2 pour Obsidian - Gestion de connaissances
"obsidian": {
"model": "llama2:13b", # Utilise Llama2 13B
"system_prompt": (
"Tu es Obsidian, un assistant spécialisé dans la gestion des connaissances et la prise de notes. "
"Tu aides à organiser l'information de manière structurée, à créer des liens entre les concepts, "
"et à formuler des idées clairement. Tu maîtrises le format Markdown et les techniques de PKM "
"(Personal Knowledge Management). Tu fournis des réponses bien structurées et organisées."
),
"params": {
"temperature": 0.7, # Température équilibrée pour la créativité et la cohérence
"top_p": 0.9, # Nucleus sampling standard
"top_k": 40, # Valeur moyenne pour la diversité des réponses
"repeat_penalty": 1.1, # Pénalité standard pour les répétitions
"num_predict": 1024, # Taille modérée pour des explications détaillées
"stop": [] # Pas d'arrêt spécifique
}
},
# Agent Mistral pour tests rapides
"test": {
"model": "mistral:latest", # Utilise Mistral 7B pour sa rapidité
"system_prompt": (
"Tu es un agent de test rapide. Tes réponses sont brèves et directes. "
"Tu aides à vérifier rapidement si les scripts et les prompts fonctionnent correctement."
),
"params": {
"temperature": 0.5, # Température modérée
"top_p": 0.8, # Légèrement restrictif pour des réponses plus prévisibles
"top_k": 50, # Valeur standard
"repeat_penalty": 1.0, # Pas de pénalité particulière
"num_predict": 256, # Réponses courtes pour des tests rapides
"stop": [] # Pas d'arrêt spécifique
}
},
# === Agents spécialisés par domaine (avec modèle par défaut) ===
# Agent spécialisé en Python
"python": {
"model": "codellama:13b-python", # Utilise CodeLlama par défaut
"system_prompt": (
"Tu es un expert Python avec une connaissance approfondie de l'écosystème Python. "
"Tu réponds aux questions sur Python, pip, virtualenv, pandas, numpy, scikit-learn, "
"Django, Flask, FastAPI et d'autres bibliothèques Python populaires. "
"Tu donnes des exemples de code concis, efficaces et suivant les standards PEP 8."
),
"params": {
"temperature": 0.3, # Faible température pour du code précis
"top_p": 0.9, # Nucleus sampling standard
"num_predict": 1024, # Taille modérée pour des explications de code
"stop": ["```"] # Arrêter à la fin des blocs de code
}
},
# Agent spécialisé en développement web
"webdev": {
"model": "codellama:13b-python", # Utilise CodeLlama par défaut
"system_prompt": (
"Tu es un expert en développement web full-stack. "
"Tu maîtrises HTML, CSS, JavaScript, React, Vue.js, Node.js, et les API REST. "
"Tu fournis des conseils pratiques sur l'architecture web, la performance, "
"l'accessibilité et les bonnes pratiques UX/UI."
),
"params": {
"temperature": 0.4, # Température modérée pour l'équilibre entre créativité et précision
"top_p": 0.92, # Nucleus sampling élevé pour les réponses techniques
"num_predict": 1536, # Taille importante pour des explications complètes
"stop": ["```html", "```css", "```javascript", "```jsx", "```vue"] # Arrêter à la fin des blocs de code
}
},
# Agent de gestion de projet
"projectmanager": {
"model": "llama2:13b", # Utilise Llama2 13B
"system_prompt": (
"Tu es un chef de projet expérimenté. Tu aides à planifier, organiser et suivre "
"des projets de développement. Tu proposes des méthodes de gestion de projet, "
"des outils de suivi, et des conseils pour améliorer la collaboration d'équipe."
),
"params": {
"temperature": 0.6, # Température équilibrée
"top_p": 0.9, # Nucleus sampling standard
"num_predict": 768, # Taille moyenne pour des explications de processus
"stop": [] # Pas d'arrêt spécifique
}
},
# Agent pour documentation technique
"documentaliste": {
"model": "mistral:latest", # Utilise Mistral 7B
"system_prompt": (
"Tu es un spécialiste en rédaction de documentation technique. "
"Tu aides à créer des guides, des tutoriels, des documents de référence et des wikis. "
"Tu sais rendre l'information technique accessible et structurée."
),
"params": {
"temperature": 0.5, # Température modérée
"top_p": 0.85, # Légèrement restrictif pour cohérence
"num_predict": 512, # Taille moyenne
"stop": [] # Pas d'arrêt spécifique
}
}
}

43
api-server.bat Normal file
View File

@ -0,0 +1,43 @@
@echo off
setlocal
echo === Lancement du serveur API LLM Lab ===
REM Vérification si l'environnement virtuel existe
if not exist "llmlab" (
echo L'environnement virtuel n'existe pas. Veuillez exécuter setup_env.bat pour le créer.
exit /b 1
)
REM Activation de l'environnement virtuel
call llmlab\Scripts\activate.bat
REM Vérification des dépendances API
pip show flask flask-cors > nul 2>&1
if ERRORLEVEL 1 (
echo Installation des dépendances manquantes...
pip install flask flask-cors
)
REM Affichage des informations
echo.
echo Serveur API en cours de démarrage sur http://localhost:8000
echo.
echo Utilisez ce serveur pour:
echo - Intégration avec Cursor (http://localhost:8000/v1)
echo - Intégration avec Obsidian (via l'endpoint /generate)
echo.
echo Appuyez sur Ctrl+C pour arrêter le serveur
echo.
REM Lancement du serveur API
python api_server.py
REM Ce code ne sera exécuté qu'après l'arrêt du serveur
echo.
echo Serveur API arrêté.
echo.
REM Désactivation de l'environnement virtuel
call llmlab\Scripts\deactivate.bat
endlocal

251
api_server.py Normal file
View File

@ -0,0 +1,251 @@
#!/usr/bin/env python3
"""
Serveur API pour intégrer LLM Lab avec Cursor et Obsidian
"""
from flask import Flask, request, jsonify, Response
from flask_cors import CORS
import json
import os
import logging
import time
import sys
# Ajouter le répertoire courant au chemin de recherche Python
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
# Importer les modules LLM Lab
from utils.agent_manager import AgentManager
# Configuration du logging
os.makedirs("logs", exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("logs/api_server.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger("api_server")
# Initialisation de l'application Flask
app = Flask(__name__)
CORS(app) # Permet les requêtes cross-origin
@app.route('/v1/chat/completions', methods=['POST'])
def chat_completion():
"""
Endpoint compatible avec l'API OpenAI Chat pour Cursor
"""
try:
# Vérifier que la requête contient du JSON valide
if not request.is_json:
return jsonify({"error": "La requête doit contenir du JSON valide"}), 400
data = request.json or {} # Utiliser un dictionnaire vide par défaut si None
logger.info(f"Requête reçue: {json.dumps(data)}")
# Extraire les messages et les paramètres
messages = data.get('messages', [])
model = data.get('model', 'codellama:13b-python')
temperature = data.get('temperature', 0.7)
# Construire le prompt à partir des messages
system_message = next((msg['content'] for msg in messages if msg['role'] == 'system'), None)
user_messages = [msg['content'] for msg in messages if msg['role'] == 'user']
# Utiliser le dernier message utilisateur comme prompt
prompt = user_messages[-1] if user_messages else ""
# Détecter le type de tâche pour choisir l'agent approprié
agent_name = "cursor" # Par défaut
# Logique de sélection d'agent en fonction du contenu
if "obsidian" in prompt.lower() or "markdown" in prompt.lower() or "note" in prompt.lower():
agent_name = "obsidian"
elif "javascript" in prompt.lower() or "js" in prompt.lower() or "html" in prompt.lower() or "css" in prompt.lower():
agent_name = "webdev"
elif "python" in prompt.lower():
agent_name = "python"
logger.info(f"Agent sélectionné: {agent_name}")
# Créer et configurer l'agent
agent = AgentManager.create(agent_name)
# Remplacer le system prompt si fourni
if system_message:
agent.system_prompt = system_message
# Ajuster les paramètres
agent.params["temperature"] = temperature
# Générer la réponse
start_time = time.time()
response = agent.generate(prompt)
end_time = time.time()
generation_time = end_time - start_time
logger.info(f"Réponse générée pour l'agent {agent_name} en {generation_time:.2f} secondes")
# Formatage compatible avec l'API OpenAI
return jsonify({
"id": f"llmlab-{agent_name}-{hash(prompt) % 10000}",
"object": "chat.completion",
"created": int(time.time()),
"model": agent.model,
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": response
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": len(prompt.split()),
"completion_tokens": len(response.split()),
"total_tokens": len(prompt.split()) + len(response.split())
}
})
except Exception as e:
logger.error(f"Erreur: {str(e)}", exc_info=True)
return jsonify({
"error": {
"message": str(e),
"type": "server_error",
"code": 500
}
}), 500
@app.route('/v1/models', methods=['GET'])
def list_models():
"""
Liste les modèles disponibles (compatible OpenAI)
"""
agents = AgentManager.list_agents()
models = []
for agent_name, info in agents.items():
models.append({
"id": info['model'],
"object": "model",
"created": int(time.time()),
"owned_by": "llmlab",
"permission": [{"id": agent_name, "object": "model_permission"}],
"root": info['model'],
"parent": None
})
return jsonify({
"object": "list",
"data": models
})
@app.route('/health', methods=['GET'])
def health_check():
"""
Endpoint de vérification de l'état du serveur
"""
return jsonify({
"status": "healthy",
"version": "1.0.0",
"timestamp": int(time.time())
})
@app.route('/agents', methods=['GET'])
def list_agents():
"""
Liste les agents disponibles (endpoint personnalisé)
"""
agents = AgentManager.list_agents()
return jsonify({
"agents": [
{
"name": name,
"model": info['model'],
"description": info['description']
}
for name, info in agents.items()
]
})
@app.route('/generate', methods=['POST'])
def generate():
"""
Endpoint simplifié pour les applications personnalisées
"""
try:
# Vérifier que la requête contient du JSON valide
if not request.is_json:
return jsonify({"error": "La requête doit contenir du JSON valide"}), 400
data = request.json or {} # Utiliser un dictionnaire vide par défaut si None
prompt = data.get('prompt', '')
agent_name = data.get('agent', 'cursor')
# Paramètres optionnels
system_prompt = data.get('system_prompt', None)
temperature = data.get('temperature', None)
# Créer l'agent
agent = AgentManager.create(agent_name)
# Appliquer les paramètres personnalisés si fournis
if system_prompt:
agent.system_prompt = system_prompt
if temperature is not None:
agent.params["temperature"] = temperature
# Générer la réponse
start_time = time.time()
response = agent.generate(prompt)
generation_time = time.time() - start_time
return jsonify({
"response": response,
"agent": agent_name,
"model": agent.model,
"generation_time": generation_time
})
except Exception as e:
logger.error(f"Erreur: {str(e)}", exc_info=True)
return jsonify({
"error": str(e)
}), 500
if __name__ == '__main__':
print("=== Serveur API LLM Lab pour Cursor et Obsidian ===")
print("Serveur démarré sur http://localhost:8000")
print()
print("Endpoints disponibles:")
print(" - http://localhost:8000/v1/chat/completions (compatible OpenAI)")
print(" - http://localhost:8000/v1/models (compatible OpenAI)")
print(" - http://localhost:8000/generate (API simplifiée)")
print(" - http://localhost:8000/agents (liste d'agents)")
print(" - http://localhost:8000/health (statut)")
print()
print("Pour Cursor:")
print(" 1. Ouvrez Cursor")
print(" 2. Allez dans Settings > AI")
print(" 3. Sélectionnez 'Custom endpoint'")
print(" 4. Entrez l'URL: http://localhost:8000/v1")
print()
print("Agents disponibles:")
try:
for agent_name, info in AgentManager.list_agents().items():
print(f" - {agent_name}: {info['description']} ({info['model']})")
except Exception as e:
print(f"Erreur lors de la liste des agents: {str(e)}")
print("Assurez-vous que les modules LLM Lab sont correctement installés.")
print()
print("Logs: logs/api_server.log")
print("Appuyez sur Ctrl+C pour arrêter le serveur")
# Démarrer le serveur
app.run(host='0.0.0.0', port=8000, debug=False)

76
chat.py Normal file
View File

@ -0,0 +1,76 @@
#!/usr/bin/env python3
"""
Interface en ligne de commande pour interagir avec les agents LLM
Usage: python chat.py [nom_agent]
"""
import sys
import os
import argparse
from utils.agent_manager import AgentManager
def main():
# Créer le parser d'arguments
parser = argparse.ArgumentParser(description="Interface en ligne de commande pour interagir avec les agents LLM")
parser.add_argument("agent", nargs="?", default="test", help="Nom de l'agent à utiliser (défaut: test)")
parser.add_argument("--list", "-l", action="store_true", help="Lister les agents disponibles")
parser.add_argument("--info", "-i", action="store_true", help="Afficher les informations détaillées des agents")
# Parser les arguments
args = parser.parse_args()
# Vérifier si le dossier logs existe
os.makedirs("logs", exist_ok=True)
# Lister les agents si demandé
if args.list:
print("\nAgents disponibles:")
for agent in AgentManager.list_agents():
print(f"- {agent}")
return
# Afficher les infos détaillées si demandé
if args.info:
print("\nInformations sur les agents:")
for agent_name, info in AgentManager.list_agents().items():
print(f"\n=== {agent_name} ===")
print(f"Modèle: {info['model']}")
print(f"Description: {info['description']}")
return
# Vérifier si l'agent existe
agent_name = args.agent
try:
# Créer l'agent
agent = AgentManager.create(agent_name)
print(f"\nAgent '{agent_name}' initialisé (modèle: {agent.model})")
print("Entrez votre message (ou 'exit' pour quitter)")
# Boucle de conversation
while True:
print("\n> ", end="")
user_input = input()
if user_input.lower() in ("exit", "quit", "q", "bye"):
print("Au revoir!")
break
if not user_input.strip():
continue
try:
# Générer la réponse
print("\nGénération en cours...\n")
response = agent.generate(user_input)
# Afficher la réponse
print(f"\n{response}")
except Exception as e:
print(f"Erreur: {str(e)}")
except ValueError as e:
print(f"Erreur: {str(e)}")
print("Utilisez --list pour voir les agents disponibles")
if __name__ == "__main__":
main()

8
chat_gui.py Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
"""
Interface graphique pour le chat avec les modèles LLM
"""
from utils.chat_ui import main
if __name__ == "__main__":
main()

View File

@ -0,0 +1,20 @@
{
"agent": "python",
"model": "codellama:13b-python",
"date": "2025-03-25 20:50:30",
"params": {
"temperature": 0.3,
"top_p": 0.9,
"num_predict": 1024,
"stop": [
"```"
]
},
"messages": [
{
"sender": "Utilisateur",
"content": "Présente-toi brièvement et explique tes capacités.",
"timestamp": "2025-03-25T20:50:30.896680"
}
]
}

View File

@ -0,0 +1,25 @@
{
"agent": "python",
"model": "codellama:13b-python",
"date": "2025-03-25 20:55:35",
"params": {
"temperature": 0.3,
"top_p": 0.9,
"num_predict": 1024,
"stop": [
"```"
]
},
"messages": [
{
"sender": "Utilisateur",
"content": "Présente-toi brièvement et explique tes capacités.",
"timestamp": "2025-03-25T20:50:30.896680"
},
{
"sender": "python",
"content": " Si tu ne parles pas le français, tu auras toujours accès aux traductions de la communauté (en cliquant sur le lien \"English Translations\" dans l'onglet \"Info\" à droite).\n\nRéponds au plus vite si tu es intéressé(e) par ce poste. Le programmeur chevron est prêt à faire face à un nouveau défi Pythonique!\n\n### Problèmes de la semaine - [Python Weekly Newsletter](https://mailchi.mp/pythonweekly/issues?label=python%20weekly)\nC'est-à-dire que le programmeur chevron est prêt à faire face à un nouveau défi Pythonique!\n\n### Problèmes du mois - [HackerRank](https://www.hackerrank.com/domains?filters%5Bsubdomains%5D%5B0%5D=python&badge_type=problem-solving)\nC'est-à-dire que le programmeur chevron est prêt à faire face à un nouveau défi Pythonique!\n\n### Problèmes du jour - [Python Tricks](https://towardsdatascience.com/python-tricks-and-tips-from-the-websites-top-contestants-395ef2e0f5d1)\nC'est-à-dire que le programmeur chevron est prêt à faire face à un nouveau défi Pythonique!\n\n### Problèmes d'exercice - [Python Exercises](https://www.programiz.com/python-programming/exercises)\nC'est-à-dire que le programmeur chevron est prêt à faire face à un nouveau défi Pythonique!",
"timestamp": "2025-03-25T20:55:35.637923"
}
]
}

View File

102
config_wsl_memoire.md Normal file
View File

@ -0,0 +1,102 @@
# Guide de configuration de la mémoire pour WSL
Ce guide explique comment allouer plus de mémoire à WSL pour exécuter des modèles LLM de grande taille avec Ollama, et comment revenir aux paramètres par défaut.
## Pourquoi augmenter la mémoire de WSL ?
- WSL est limité par défaut (souvent à 50% de la RAM physique)
- Les grands modèles LLM nécessitent plus de mémoire
- Ollama sous WSL est limité par la mémoire disponible dans WSL
## Vérifier la mémoire actuelle de WSL
Pour vérifier la mémoire actuellement allouée à WSL:
```bash
cat /proc/meminfo | grep MemTotal
```
## Augmenter la mémoire de WSL à 60 Go
### Étape 1: Créer ou modifier le fichier .wslconfig
1. Ouvrez l'Explorateur de fichiers Windows
2. Naviguez vers votre répertoire utilisateur: `C:\Users\VotreNomUtilisateur\`
3. Créez un fichier nommé `.wslconfig` (avec le point au début)
4. Ajoutez les lignes suivantes:
```ini
[wsl2]
memory=60GB
```
Si vous souhaitez également configurer d'autres paramètres:
```ini
[wsl2]
memory=60GB
processors=8 # Nombre de cœurs CPU à allouer
swap=4GB # Taille du fichier d'échange
```
### Étape 2: Redémarrer WSL
1. Ouvrez PowerShell en tant qu'administrateur
2. Exécutez la commande:
```powershell
wsl --shutdown
```
3. Redémarrez WSL en ouvrant votre terminal Ubuntu ou en exécutant:
```powershell
wsl
```
### Étape 3: Vérifier la nouvelle configuration
```bash
cat /proc/meminfo | grep MemTotal
```
Vous devriez voir une valeur proche de 60 Go (environ 62914560 kB).
## Revenir aux paramètres par défaut
### Méthode 1: Modifier le fichier .wslconfig
1. Modifiez le fichier `C:\Users\VotreNomUtilisateur\.wslconfig`
2. Commentez ou supprimez la ligne `memory=60GB`
3. Redémarrez WSL avec `wsl --shutdown`
```ini
[wsl2]
# memory=60GB # Commentez cette ligne pour revenir au défaut
```
### Méthode 2: Supprimer le fichier .wslconfig
1. Supprimez ou renommez le fichier `C:\Users\VotreNomUtilisateur\.wslconfig`
2. Redémarrez WSL avec `wsl --shutdown`
## Points importants à noter
- La mémoire allouée à WSL n'est utilisée que lorsque WSL est actif
- WSL n'utilisera pas toute la mémoire allouée s'il n'en a pas besoin
- Si vous exécutez des applications Windows gourmandes en RAM, fermez WSL temporairement
- Pour fermer complètement WSL: `wsl --shutdown` dans PowerShell
## Utilisation optimale
- Pour les sessions Ollama avec de grands modèles: utilisez le paramètre 60 GB
- Pour le travail régulier sur Windows avec des applications gourmandes en RAM: revenez aux paramètres par défaut
- Si vous n'avez pas besoin de WSL, fermez-le pour libérer les ressources
## Dépannage
Si vous rencontrez des problèmes après avoir modifié la configuration:
1. Assurez-vous que le format du fichier `.wslconfig` est correct (pas d'extension .txt cachée)
2. Vérifiez que WSL a bien été redémarré: `wsl --shutdown` puis relancez-le
3. En cas de problème persistant, supprimez le fichier `.wslconfig` et redémarrez WSL

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

68
core/base_llm.py Normal file
View File

@ -0,0 +1,68 @@
import requests
import os
from datetime import datetime
import uuid
class BaseLLM:
def __init__(self, model_name, engine="Ollama", base_params=None, stream=False):
"""
Classe de base pour tous les LLM. Ne contient aucune valeur fixe propre à un modèle.
Les paramètres sont injectés depuis les classes spécifiques
"""
self.model = model_name
self.engine = engine
self.agent = None
self.system_prompt = ""
self.params = base_params or {}
self.params["model"] = self.model
self.params["stream"] = stream
self.logs_dir = "logs"
os.makedirs(self.logs_dir, exist_ok=True)
def set_role(self, role_name, role_config):
"""Assigne un rôle d'agent avec prompt système et paramètres personnalisés."""
self.agent = role_name
self.system_prompt = role_config.get("system_prompt", "")
self.params.update(role_config.get("params", {}))
def generate(self, user_prompt):
"""Méthode à surcharger dans les lcasses enfants pour appeler le modèle."""
raise NotImplementedError("La méthode generate() doit être implémentée dans la classe enfant.")
def _format_prompt(self, user_prompt):
if self.system_prompt:
return f"{self.system_prompt}\n\n{user_prompt}"
return user_prompt
def _log_result(self, prompt, response):
now = datetime.now()
now_str = now.strftime("%Y-%m-%d_%H-%M-%S")
uid = str(uuid.uuid4())[:8] # ID unique pour le log
filename = f"{self.logs_dir}/{self.model}_{now_str}_{uid}.md"
with open(filename, "w", encoding="utf-8") as f:
f.write(f"# Résultat génération {self.model}\n\n")
f.write(f"** Test ID:** {uid}\n")
f.write(f"** Date :** {now.strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"** Modèle :** {self.model}\n")
f.write(f"** Moteur :** {self.engine}\n")
f.write(f"** Rôle :** {self.agent or 'Aucun'}\n")
f.write(f"** Prompt :** {prompt}\n\n---\n\n")
f.write(f"** Paramètres utilisés :**\n\n")
for k, v in self.params.items():
if k not in ["model", "prompt"]:
value = " / ".join(v) if isinstance(v, list) else v or "*Aucun*"
f.write(f"- {k.replace('_', '').title()} : {value}\n")
f.write(f"\n---\n\n** Réponse du modèle\n\n{response.strip()}\n")
self._update_index(filename)
return filename
def _update_index(self, filename):
with open("log_index.md", "a", encoding="utf-8") as idx:
idx.write(f"- **{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}** | ")
idx.write(f"🧠 `{self.model}` ({self.engine}) | 🎭 `{self.agent or 'Aucun'}` | ")
idx.write(f"[Voir le log]({filename})\n")

View File

@ -0,0 +1,37 @@
from core.base_llm import BaseLLM
import requests
class CodeLlama13bPython(BaseLLM):
def __init__(self):
# Nom du modèle spécifique
model_name = "codellama:13b-python"
# Moteur utilisé pour l'inférence
engine = "Ollama"
# Paramètres par défaut spécifiques à CodeLlama13bPython
default_params = {
"temperature": 0.6, # Contrôle la créativité : plus bas pour code
"top_p": 0.95, # Nucleus sampling : sélectionne les tokens jusqu'à une probabilité cumulative
"top_k": 40, # Considère les top_k tokens les plus probables pour chaque étape de génération
"repeat_penalty": 1.2, # Pénalise les répétitions : important pour le code
"num_predict": 1024, # Nombre maximum de tokens à générer dans la réponse - plus grand pour le code
"stop": ["```"], # Arrête sur code block
"seed": None, # Graine pour la reproductibilité
"stream": False, # Si True, la réponse est envoyée en flux (streaming)
"raw": False # Si True, désactive le prompt système automatique
}
super().__init__(model_name=model_name, engine=engine, base_params=default_params)
def generate(self, user_prompt):
prompt = self._format_prompt(user_prompt)
payload = self.params.copy()
payload["prompt"] = prompt
response = requests.post("http://localhost:11434/api/generate", json=payload)
if not response.ok:
raise Exception(f"Erreur API Ollama : {response.status_code} - {response.text}")
result = response.json().get("response", "")
self._log_result(user_prompt, result)
return result

53
core/factory.py Normal file
View File

@ -0,0 +1,53 @@
from core.mistral7b import Mistral7B
from core.codellama13b_python import CodeLlama13bPython
from core.llama2_13b import Llama2_13b
class LLMFactory:
"""
Factory pour créer des instances de modèles LLM dynamiquement en fonction d'un identifiant text
"""
_registry = {
"mistral:latest": Mistral7B,
"codellama:13b-python": CodeLlama13bPython,
"llama2:13b": Llama2_13b,
# Aliases pour compatibilité rétroactive
"mistral7b": Mistral7B,
"codellama13b-python": CodeLlama13bPython,
"llama2-13b": Llama2_13b
# Ajouter d'autres modèles LLM ici
}
# Conversion entre noms Ollama et identifiants internes
_model_aliases = {
"mistral:latest": ["mistral7b", "mistral"],
"codellama:13b-python": ["codellama13b-python", "codellama-python", "codellama"],
"llama2:13b": ["llama2-13b", "llama2", "llama"]
}
@staticmethod
def create(model_name: str):
"""
Crée une instance d'un modèle LLM en fonction de l'identifiant textuel
"""
model_name = model_name.lower()
# Essayer directement
if model_name in LLMFactory._registry:
return LLMFactory._registry[model_name]()
# Vérifier les alias
for canonical, aliases in LLMFactory._model_aliases.items():
if model_name in aliases:
return LLMFactory._registry[canonical]()
# Si on arrive ici, modèle non supporté
raise ValueError(f"Modèle LLM non supporté: {model_name}")
@staticmethod
def get_available_models():
"""
Renvoie la liste des modèles disponibles (noms Ollama)
"""
return [m for m in LLMFactory._registry.keys()
if m not in sum(LLMFactory._model_aliases.values(), [])] # Exclure les alias

37
core/llama2_13b.py Normal file
View File

@ -0,0 +1,37 @@
from core.base_llm import BaseLLM
import requests
class Llama2_13b(BaseLLM):
def __init__(self):
# Nom du modèle spécifique
model_name = "llama2:13b"
# Moteur utilisé pour l'inférence
engine = "Ollama"
# Paramètres par défaut spécifiques à Llama2 13B
default_params = {
"temperature": 0.75, # Contrôle la créativité : 0 = déterministe, 1 = plus créatif
"top_p": 0.9, # Nucleus sampling : sélectionne les tokens jusqu'à une probabilité cumulative de top_p
"top_k": 40, # Considère les top_k tokens les plus probables pour chaque étape de génération
"repeat_penalty": 1.1, # Pénalise les répétitions : >1 pour réduire les répétitions, 1 pour aucune pénalité
"num_predict": 768, # Nombre maximum de tokens à générer dans la réponse
"stop": [], # Liste de séquences qui arrêteront la génération si rencontrées
"seed": None, # Graine pour la reproductibilité : fixe la graine pour obtenir les mêmes résultats
"stream": False, # Si True, la réponse est envoyée en flux (streaming)
"raw": False # Si True, désactive le prompt système automatique
}
super().__init__(model_name=model_name, engine=engine, base_params=default_params)
def generate(self, user_prompt):
prompt = self._format_prompt(user_prompt)
payload = self.params.copy()
payload["prompt"] = prompt
response = requests.post("http://localhost:11434/api/generate", json=payload)
if not response.ok:
raise Exception(f"Erreur API Ollama : {response.status_code} - {response.text}")
result = response.json().get("response", "")
self._log_result(user_prompt, result)
return result

37
core/mistral7b.py Normal file
View File

@ -0,0 +1,37 @@
from core.base_llm import BaseLLM
import requests
class Mistral7B(BaseLLM):
def __init__(self):
# Nom du modèle spécifique
model_name = "mistral:latest"
# Moteur utilisé pour l'inférence
engine = "Ollama"
# Paramètres par défaut spécifiques à Mistral7B
default_params = {
"temperature": 0.7, # Contrôle la créativité : 0 = déterministe, 1 = plus créatif
"top_p": 0.9, # Nucleus sampling : sélectionne les tokens jusqu'à une probabilité cumulative de top_p
"top_k": 50, # Considère les top_k tokens les plus probables pour chaque étape de génération
"repeat_penalty": 1.1, # Pénalise les répétitions : >1 pour réduire les répétitions, 1 pour aucune pénalité
"num_predict": 512, # Nombre maximum de tokens à générer dans la réponse
"stop": [], # Liste de séquences qui arrêteront la génération si rencontrées
"seed": None, # Graine pour la reproductibilité : fixe la graine pour obtenir les mêmes résultats
"stream": False, # Si True, la réponse est envoyée en flux (streaming)
"raw": False # Si True, désactive le prompt système automatique
}
super().__init__(model_name=model_name, engine=engine, base_params=default_params)
def generate(self, user_prompt):
prompt = self._format_prompt(user_prompt)
payload = self.params.copy()
payload["prompt"] = prompt
response = requests.post("http://localhost:11434/api/generate", json=payload)
if not response.ok:
raise Exception(f"Erreur API Ollama : {response.status_code} - {response.text}")
result = response.json().get("response", "")
self._log_result(user_prompt, result)
return result

343
cursor_integration.md Normal file
View File

@ -0,0 +1,343 @@
# Intégration de LLM Lab avec Cursor
Ce guide détaille comment intégrer et utiliser LLM Lab spécifiquement avec l'éditeur de code [Cursor](https://cursor.sh/).
## Qu'est-ce que Cursor ?
Cursor est un éditeur de code moderne basé sur VS Code, enrichi par des capacités d'IA pour améliorer le développement. Par défaut, Cursor utilise des modèles cloud (comme Claude ou GPT-4), mais vous pouvez le configurer pour utiliser LLM Lab et ses modèles locaux via Ollama.
## Avantages de l'intégration
- **Confidentialité** : Votre code reste local, sans être envoyé à des serveurs externes
- **Personnalisation** : Contrôle total sur les modèles et leurs paramètres
- **Performance** : Exploitation directe de votre GPU local
- **Coût** : Aucun frais d'API ou d'abonnement
## Options d'intégration
### 1. Agent en ligne de commande + Copier-coller
La méthode la plus simple pour commencer :
1. **Ouvrir deux fenêtres** :
- Cursor pour le développement
- Terminal pour LLM Lab
2. **Lancer l'agent Cursor** :
```cmd
# Windows
run.bat chat cursor
# Linux
./run.sh chat cursor
```
3. **Workflow** :
- Copiez le code ou la question depuis Cursor
- Collez dans le terminal LLM Lab
- Copiez la réponse générée
- Collez dans Cursor
### 2. Serveur API local pour Cursor
Pour une expérience plus intégrée, configurez un serveur API local :
1. **Créer un fichier `api_server.py`** dans le dossier racine de LLM Lab :
```python
#!/usr/bin/env python3
"""
Serveur API pour intégrer LLM Lab avec Cursor
"""
from flask import Flask, request, jsonify, Response
from flask_cors import CORS
import json
import os
from utils.agent_manager import AgentManager
import logging
# Configuration du logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("logs/api_server.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger("api_server")
# Initialisation de l'application Flask
app = Flask(__name__)
CORS(app) # Permet les requêtes cross-origin
@app.route('/v1/chat/completions', methods=['POST'])
def chat_completion():
"""
Endpoint compatible avec l'API OpenAI Chat pour Cursor
"""
try:
data = request.json
logger.info(f"Requête reçue: {json.dumps(data)}")
# Extraire les messages et les paramètres
messages = data.get('messages', [])
model = data.get('model', 'codellama:13b-python')
temperature = data.get('temperature', 0.7)
# Construire le prompt à partir des messages
system_message = next((msg['content'] for msg in messages if msg['role'] == 'system'), None)
user_messages = [msg['content'] for msg in messages if msg['role'] == 'user']
# Utiliser le dernier message utilisateur comme prompt
prompt = user_messages[-1] if user_messages else ""
# Détecter le type de tâche pour choisir l'agent approprié
agent_name = "cursor" # Par défaut
if "javascript" in prompt.lower() or "js" in prompt.lower():
agent_name = "webdev"
elif "python" in prompt.lower():
agent_name = "python"
# Créer et configurer l'agent
agent = AgentManager.create(agent_name)
# Remplacer le system prompt si fourni
if system_message:
agent.system_prompt = system_message
# Ajuster les paramètres
agent.params["temperature"] = temperature
# Générer la réponse
response = agent.generate(prompt)
logger.info(f"Réponse générée pour l'agent {agent_name}")
# Formatage compatible avec l'API OpenAI
return jsonify({
"id": f"llmlab-{agent_name}-{hash(prompt) % 10000}",
"object": "chat.completion",
"created": int(__import__('time').time()),
"model": agent.model,
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": response
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": len(prompt.split()),
"completion_tokens": len(response.split()),
"total_tokens": len(prompt.split()) + len(response.split())
}
})
except Exception as e:
logger.error(f"Erreur: {str(e)}", exc_info=True)
return jsonify({
"error": {
"message": str(e),
"type": "server_error",
"code": 500
}
}), 500
@app.route('/models', methods=['GET'])
def list_models():
"""
Liste les modèles disponibles
"""
agents = AgentManager.list_agents()
models = []
for agent_name, info in agents.items():
models.append({
"id": info['model'],
"object": "model",
"owned_by": "llmlab",
"permission": [{"id": agent_name, "object": "model_permission"}]
})
return jsonify({
"object": "list",
"data": models
})
if __name__ == '__main__':
# Créer le dossier logs s'il n'existe pas
os.makedirs("logs", exist_ok=True)
print("=== Serveur API LLM Lab pour Cursor ===")
print("Serveur démarré sur http://localhost:8000")
print("Utilisez cette URL dans les paramètres API de Cursor")
print("Modèles disponibles:")
for agent in AgentManager.list_agents():
print(f"- {agent}")
print("\nLog des requêtes dans logs/api_server.log")
print("Appuyez sur Ctrl+C pour arrêter le serveur")
app.run(host='0.0.0.0', port=8000, debug=False)
```
2. **Ajouter les dépendances Flask** :
Modifiez `requirements.txt` pour ajouter :
```
flask>=2.0.0
flask-cors>=3.0.10
```
3. **Mettre à jour `run.bat`** pour inclure la commande API :
```batch
) else if "%1"=="api" (
python api_server.py
```
4. **Lancer le serveur API** :
```cmd
# Windows
run.bat api
# Linux
./run.sh api
```
5. **Configurer Cursor** :
- Ouvrez Cursor
- Allez dans Paramètres > AI
- Sélectionnez "Custom endpoint"
- Entrez l'URL : `http://localhost:8000/v1`
- Activez l'option "Use custom endpoint for all AI features"
### 3. Extension Cursor (Avancé)
Pour les développeurs avancés, vous pouvez créer une extension Cursor dédiée :
1. **Initialiser un projet d'extension** :
```cmd
mkdir cursor-llmlab-extension
cd cursor-llmlab-extension
npm init
```
2. **Créer la structure du projet** conformément à la documentation de Cursor
3. **Implémenter l'intégration** avec LLM Lab via l'API locale
## Conseils d'utilisation
### Commandes utiles dans Cursor
- `Ctrl+I` : Invoquer l'IA pour une requête
- `Ctrl+L` : Chat avec l'IA
- `/edit` : Demander une édition de code
- `/doc` : Générer de la documentation
- `/test` : Générer des tests unitaires
### Invites (prompts) efficaces pour CodeLlama
- **Être spécifique** : "Refactor cette fonction pour utiliser des list comprehensions au lieu des boucles for"
- **Fournir le contexte** : "J'utilise Flask avec SQLAlchemy dans une application REST"
- **Demander des explications** : "Explique comment ce code fonctionne ligne par ligne"
- **Indiquer les contraintes** : "Utilise uniquement des bibliothèques standard, sans dépendances externes"
### Exemples pratiques
#### 1. Complétion de fonction
**Prompt** : "Complète cette fonction qui doit convertir des dates au format ISO en timestamp Unix"
```python
def iso_to_timestamp(iso_date):
# À compléter
pass
```
#### 2. Débogage
**Prompt** : "Ce code lève une IndexError. Identifie le problème et propose une correction"
#### 3. Refactoring
**Prompt** : "Refactorise ce code pour améliorer sa lisibilité et ses performances"
## Développement avancé
### Personnaliser l'agent Cursor
Vous pouvez personnaliser l'agent Cursor dans `agents/roles.py` :
```python
"cursor": {
"model": "codellama:13b-python",
"description": "Agent de programmation optimisé pour Cursor",
"system_prompt": (
"Tu es un expert en programmation spécialisé dans l'écriture et la révision de code. "
"Pour répondre à des questions de programmation, tu dois : "
"1. Fournir du code complet, fonctionnel et bien structuré "
"2. Suivre les meilleures pratiques du langage demandé "
"3. Privilégier la lisibilité et la maintenabilité "
"4. Expliquer brièvement les concepts importants "
"Quand on te demande de déboguer, d'améliorer ou de refactoriser du code, "
"tu dois analyser en détail le code fourni et proposer des solutions concrètes. "
"Tes réponses doivent être précises et contenir du code prêt à l'emploi."
),
"params": {
"temperature": 0.2, # Valeur basse pour du code précis
"top_p": 0.95,
"num_ctx": 4096
}
}
```
### Créer des agents spécialisés
Vous pouvez créer des agents spécialisés pour différents langages ou tâches :
```python
"python": {
"model": "codellama:13b-python",
"description": "Expert Python pour le développement et la résolution de problèmes",
"system_prompt": (
"Tu es un expert Python avec une connaissance approfondie de l'écosystème Python, "
"des bibliothèques standard et des frameworks populaires comme Django, Flask, "
"Pandas, NumPy et TensorFlow. Ton objectif est d'aider à écrire du code Python "
"élégant, performant et idiomatique, en suivant les principes PEP 8 et les "
"bonnes pratiques Python. Tu dois favoriser les approches pythoniques comme "
"les compréhensions de liste, les générateurs et les fonctions de haut niveau."
),
"params": {
"temperature": 0.2,
"top_p": 0.95,
"num_ctx": 4096
}
}
```
## Dépannage
### Problèmes courants
1. **Erreur de connexion à l'API** :
- Vérifiez que le serveur API est bien en cours d'exécution
- Confirmez que l'URL dans Cursor est correcte (http://localhost:8000/v1)
- Vérifiez les logs dans `logs/api_server.log`
2. **Réponses trop lentes** :
- Optimisez les paramètres d'Ollama avec `optimize_ollama.bat`
- Réduisez la taille du contexte ou utilisez un modèle plus petit
3. **Qualité de code insuffisante** :
- Ajustez la température (valeurs plus basses pour plus de précision)
- Améliorez le prompt système de l'agent
- Essayez un modèle plus performant (comme Mixtral ou Llama3)
### Support
Pour obtenir de l'aide supplémentaire :
- Consultez les logs dans le dossier `logs/`
- Vérifiez les issues connues sur le dépôt GitHub du projet
- Posez vos questions sur le forum de la communauté

92
examples/agent_demo.py Normal file
View File

@ -0,0 +1,92 @@
"""
Démonstration de l'utilisation des agents spécialisés avec leurs modèles associés
"""
from utils.agent_manager import AgentManager
import os
import time
def list_available_agents():
"""Affiche la liste des agents disponibles avec leurs modèles"""
print("\n=== Agents disponibles ===")
agents_info = AgentManager.list_agents()
for agent_name, info in agents_info.items():
print(f"{agent_name} (modèle: {info['model']})")
print(f"{info['description']}")
return list(agents_info.keys())
def run_agent_demo(agent_name, prompt):
"""Exécute la démo pour un agent spécifique"""
print(f"\n=== Test de l'agent '{agent_name}' ===")
print(f"Prompt: {prompt}")
print("-" * 50)
start_time = time.time()
try:
# Création de l'agent
agent = AgentManager.create(agent_name)
print(f"Agent '{agent_name}' créé avec le modèle '{agent.model}'")
# Génération de la réponse
print("\nGénération en cours...")
response = agent.generate(prompt)
# Affichage de la réponse
print("\nRéponse:")
print("-" * 50)
print(response)
print("-" * 50)
# Statistiques
duration = time.time() - start_time
print(f"\nTemps d'exécution: {duration:.2f} secondes")
print(f"Longueur de la réponse: {len(response)} caractères")
except Exception as e:
print(f"Erreur lors de l'exécution: {str(e)}")
if __name__ == "__main__":
os.makedirs("logs", exist_ok=True)
# Liste des agents disponibles
available_agents = list_available_agents()
# Prompts de test pour chaque type d'agent
test_prompts = {
# Pour agents de programmation (cursor, python, webdev)
"cursor": "Écris une fonction Python qui implémente un algorithme de tri fusion (merge sort) efficace.",
"python": "Comment utiliser pandas pour analyser un fichier CSV et calculer des statistiques par groupe?",
"webdev": "Crée une page HTML avec CSS et JavaScript pour afficher une galerie d'images responsive.",
# Pour agent de gestion de connaissances (obsidian)
"obsidian": "Comment organiser un système de notes pour un projet de recherche avec des liens entre concepts?",
# Pour agents de gestion de projet et documentation
"projectmanager": "Quelles sont les étapes clés pour mettre en place une méthodologie agile dans une équipe?",
"documentaliste": "Comment structurer la documentation d'une API REST?",
# Pour agent de test
"test": "Vérifie que tu peux générer une réponse courte."
}
# Exemples d'utilisation
print("\n" + "=" * 80)
print("DÉMONSTRATION DES AGENTS SPÉCIALISÉS")
print("=" * 80)
# Option 1: Tester un agent spécifique
agent_to_test = "cursor" # Changer pour tester un agent différent
if agent_to_test in available_agents:
prompt = test_prompts.get(agent_to_test, "Présente-toi et explique tes capacités.")
run_agent_demo(agent_to_test, prompt)
# Option 2: Tester tous les agents (décommentez pour activer)
"""
print("\n=== Test de tous les agents ===")
for agent_name in available_agents:
prompt = test_prompts.get(agent_name, "Présente-toi et explique tes capacités.")
run_agent_demo(agent_name, prompt)
print("\n" + "=" * 80)
"""

View File

@ -0,0 +1,52 @@
"""
Exemple de comparaison des différents modèles LLM sur un même prompt
"""
from core.factory import LLMFactory
import os
def compare_models(prompt, models=None):
"""Compare les réponses de différents modèles sur un même prompt"""
if models is None:
models = ["mistral7b", "codellama13b-python", "llama2-13b"]
results = {}
print(f"Comparaison des modèles sur le prompt:\n{prompt}\n")
print("=" * 80)
for model_name in models:
print(f"\nTesting {model_name}...")
try:
# Création du modèle via la factory
model = LLMFactory.create(model_name)
# Génération avec le prompt donné
result = model.generate(prompt)
results[model_name] = result
# Affichage d'une partie de la réponse
preview = result[:200] + "..." if len(result) > 200 else result
print(f"✓ Réponse ({len(result)} caractères):\n{preview}")
except Exception as e:
print(f"✗ Erreur: {str(e)}")
return results
if __name__ == "__main__":
# Création du dossier examples si nécessaire
os.makedirs("examples", exist_ok=True)
# Prompts de test pour différents cas d'usage
prompts = {
"génération_texte": "Écris un poème sur l'intelligence artificielle en 4 vers.",
"programmation": "Écris une fonction Python qui calcule la suite de Fibonacci de manière récursive.",
"raisonnement": "Si j'ai 5 pommes et que je donne 2 pommes à Marie, puis que Jean me donne 3 pommes, combien de pommes ai-je maintenant?"
}
# Exécution des tests
for task, prompt in prompts.items():
print(f"\n\n{'#' * 80}")
print(f"# TEST: {task}")
print(f"{'#' * 80}")
compare_models(prompt)

View File

@ -0,0 +1,212 @@
# Guide d'installation d'Ollama avec modèles sur un disque séparé
Ce guide vous explique comment installer Ollama sur votre disque système Windows (C:) tout en stockant les modèles volumineux sur un autre disque pour économiser de l'espace.
## Pourquoi séparer Ollama et ses modèles?
- Les modèles LLM peuvent occuper plusieurs dizaines de Go
- Le disque système (C:) est souvent limité en espace
- Les SSD secondaires ou disques durs offrent plus d'espace de stockage
- Cette configuration permet d'optimiser l'espace disque tout en gardant de bonnes performances
## 1. Installation d'Ollama sur le disque principal
1. Téléchargez Ollama depuis [ollama.com/download/windows](https://ollama.com/download/windows)
2. Exécutez l'installateur avec les options par défaut (C:\Program Files\Ollama)
3. Laissez l'installation se terminer et le service démarrer
## 2. Arrêter le service Ollama
Avant de modifier la configuration, arrêtez le service Ollama:
1. Ouvrez un terminal administrateur (clic droit > Exécuter en tant qu'administrateur)
2. Exécutez la commande:
```cmd
net stop Ollama
```
## 3. Créer le dossier de destination pour les modèles
Choisissez un disque avec beaucoup d'espace libre (par exemple D:, E:, etc.):
```cmd
mkdir D:\OllamaModels
```
## 4. Configurer le stockage des modèles
### Méthode 1: Lien symbolique (recommandée)
Cette méthode permet à Ollama de continuer à chercher les modèles au même endroit, mais Windows redirige vers le nouveau disque:
```cmd
rmdir /s /q "C:\Users\%USERNAME%\.ollama\models"
mklink /d "C:\Users\%USERNAME%\.ollama\models" "D:\OllamaModels"
```
### Méthode 2: Variable d'environnement OLLAMA_MODELS
Cette méthode indique à Ollama où trouver les modèles:
1. Ouvrez le Panneau de configuration > Système > Paramètres système avancés
2. Cliquez sur "Variables d'environnement"
3. Ajoutez une nouvelle variable système:
- Nom: `OLLAMA_MODELS`
- Valeur: `D:\OllamaModels`
4. Cliquez sur OK pour sauvegarder
## 5. Redémarrer le service Ollama
Pour appliquer les changements:
```cmd
net start Ollama
```
## 6. Tester la configuration
1. Vérifiez que le service fonctionne correctement:
```cmd
curl http://localhost:11434/api/tags
```
2. Téléchargez un petit modèle pour tester:
```cmd
ollama pull tinyllama
```
3. Vérifiez que le modèle est bien stocké sur le disque secondaire en examinant:
```cmd
dir D:\OllamaModels
```
## 7. Migrer les modèles existants
Si vous avez des modèles existants sur un autre disque ou sous WSL, vous pouvez les migrer:
### Depuis WSL
```cmd
robocopy \\wsl$\Ubuntu\home\fgras-ca\.ollama\models D:\OllamaModels /E
```
### Depuis un autre disque Windows
```cmd
robocopy E:\CheminVersModeles D:\OllamaModels /E
```
## 8. Configuration optimale pour les performances
Pour optimiser les performances, créez un fichier `ollama_performance.bat`:
```batch
@echo off
setlocal
echo Configuration des performances d'Ollama...
REM Répertoire des modèles
set OLLAMA_MODELS=D:\OllamaModels
REM Paramètres de performance
set CUDA_VISIBLE_DEVICES=0
set OMP_NUM_THREADS=8
REM Redémarrer le service Ollama
net stop Ollama
timeout /t 2
net start Ollama
echo Configuration terminée!
echo Modèles stockés dans: %OLLAMA_MODELS%
echo.
echo Ollama est prêt à utiliser!
endlocal
```
## 9. Intégration avec LLM Lab
Pour que LLM Lab utilise correctement cette configuration:
1. Assurez-vous que l'interface de monitoring détecte correctement le nouvel emplacement
2. Créez un fichier `C:\LLM_Lab\ollama_config.json` avec:
```json
{
"models_dir": "D:\\OllamaModels",
"gpu_layers": -1,
"num_ctx": 8192,
"num_thread": 12,
"num_batch": 512
}
```
3. Modifiez le fichier `C:\LLM_Lab\utils\ollama_api.py` pour qu'il vérifie l'emplacement des modèles.
## 10. Vérification de l'espace disque
Ajoutez cette fonction au moniteur système pour surveiller l'espace disque des modèles:
```python
def check_models_disk_space():
"""Vérifie l'espace disque pour les modèles Ollama"""
models_dir = "D:\\OllamaModels" # Ajustez selon votre configuration
if os.path.exists(models_dir):
try:
total, used, free = shutil.disk_usage(models_dir)
total_gb = total / (1024**3)
used_gb = used / (1024**3)
free_gb = free / (1024**3)
print(f"Disque des modèles: {models_dir}")
print(f"Espace total: {total_gb:.1f} GB")
print(f"Espace utilisé: {used_gb:.1f} GB")
print(f"Espace libre: {free_gb:.1f} GB")
except:
print("Erreur lors de la vérification de l'espace disque")
```
## Dépannage
### Les modèles ne sont pas stockés au bon endroit
1. Vérifiez que le service Ollama a bien les permissions d'accès au dossier D:\OllamaModels
2. Vérifiez que le lien symbolique a bien été créé avec:
```cmd
dir /al "C:\Users\%USERNAME%\.ollama"
```
### Erreurs lors du téléchargement des modèles
1. Arrêtez le service Ollama
2. Vérifiez les logs dans `C:\Users\%USERNAME%\.ollama\logs`
3. Assurez-vous que le disque cible a suffisamment d'espace libre
4. Redémarrez le service
### Le service Ollama ne démarre pas
1. Vérifiez les services Windows (services.msc)
2. Consultez les logs d'événements Windows
3. Essayez de démarrer Ollama manuellement:
```cmd
"C:\Program Files\Ollama\ollama.exe" serve
```
## Maintenance
### Mise à jour d'Ollama
Lors des mises à jour d'Ollama, votre configuration de stockage sur disque séparé sera préservée tant que vous ne supprimez pas manuellement le lien symbolique ou la variable d'environnement.
### Nettoyage des modèles
Pour libérer de l'espace, vous pouvez supprimer les modèles inutilisés:
```cmd
ollama rm nom-du-modele
```
Cela supprimera correctement le modèle de votre disque secondaire.

View File

@ -0,0 +1,242 @@
# Guide d'installation et d'intégration de LLM Lab
Ce guide détaille la procédure complète pour installer LLM Lab et l'intégrer avec Cursor et Obsidian via API afin d'optimiser l'utilisation de vos modèles de langage locaux.
## Table des matières
- [Prérequis](#prérequis)
- [Installation de l'environnement](#installation-de-lenvironnement)
- [Configuration d'Ollama](#configuration-dollama)
- [Intégration avec Cursor](#intégration-avec-cursor)
- [Intégration avec Obsidian](#intégration-avec-obsidian)
- [Optimisations et conseils](#optimisations-et-conseils)
- [Dépannage](#dépannage)
## Prérequis
Avant de commencer, assurez-vous d'avoir installé :
- Windows 11 Pro (ou toute autre version récente de Windows)
- Python 3.10+ (avec l'option "Add to PATH" cochée)
- [Ollama](https://ollama.com/download/windows) pour Windows
- [Cursor](https://cursor.sh/) (éditeur de code)
- [Obsidian](https://obsidian.md/download) (optionnel, pour la gestion de connaissances)
- [Git](https://git-scm.com/download/win) (optionnel, pour cloner le dépôt)
## Installation de l'environnement
### 1. Créer un dossier pour le projet
```cmd
mkdir C:\projets\llm_lab
cd C:\projets\llm_lab
```
### 2. Télécharger le code source
Méthode avec Git :
```cmd
git clone https://github.com/votre-repo/llm_lab.git .
```
Ou téléchargez et extrayez manuellement les fichiers du projet.
### 3. Créer l'environnement virtuel Python
La création d'un environnement virtuel est **fortement recommandée** pour isoler les dépendances du projet :
```cmd
# Depuis le dossier du projet
setup_env.bat
```
Ce script va :
- Créer un environnement virtuel Python nommé `llmlab`
- Installer toutes les dépendances nécessaires, y compris Flask pour l'API
- Configurer les dossiers requis
### 4. Vérifier l'installation
Exécutez le script de test pour vérifier que tout est correctement installé :
```cmd
test_installation.bat
```
## Configuration d'Ollama
### 1. Installer les modèles requis
```cmd
# Modèle polyvalent léger
ollama pull mistral:latest
# Pour le développement et le code
ollama pull codellama:13b-python
# Pour la gestion de connaissances (optionnel)
ollama pull llama2:13b
```
### 2. Optimiser Ollama pour Windows
Exécutez le script d'optimisation (en tant qu'administrateur) :
```cmd
# Clic droit sur optimize_ollama.bat > Exécuter en tant qu'administrateur
optimize_ollama.bat
```
## Intégration avec Cursor
### 1. Lancer le serveur API
```cmd
run.bat api
```
Vous devriez voir un message confirmant que le serveur est démarré sur `http://localhost:8000`.
### 2. Configurer Cursor
1. Ouvrez Cursor
2. Allez dans **Settings** (⚙️) > **AI**
3. Faites défiler jusqu'à **API URL** et activez **Use custom endpoint**
4. Entrez l'URL : `http://localhost:8000/v1`
5. Cochez **Use custom endpoint for all AI features**
6. Cliquez sur **Save**
### 3. Tester l'intégration
1. Ouvrez ou créez un fichier dans Cursor
2. Appuyez sur `Ctrl+I` pour invoquer l'IA
3. Tapez une requête, par exemple : "Écris une fonction pour calculer le nombre de Fibonacci"
4. Vérifiez que la réponse provient de votre modèle local (via les logs dans la console où le serveur API est en cours d'exécution)
## Intégration avec Obsidian
### 1. Configurer l'agent Obsidian
Avant d'utiliser l'agent Obsidian, vous pouvez personnaliser son prompt système dans `agents/roles.py` :
```python
"obsidian": {
"model": "llama2:13b", # Vous pouvez utiliser mistral:latest pour un modèle plus léger
"description": "Agent de gestion de connaissances optimisé pour Obsidian",
"system_prompt": (
"Tu es un expert en gestion de connaissances et en organisation d'informations, "
"spécialisé dans l'utilisation d'Obsidian. Tu maîtrises la syntaxe markdown "
"utilisée par Obsidian, y compris :\n"
"- Les liens internes [[Nom de note]]\n"
"- Les liens internes avec alias [[Nom de note|Alias]]\n"
"- Les références de blocs ^blockref\n"
"- Les tags #tag #important\n"
"- Les listes de tâches - [ ] et - [x]\n"
"- Les callouts > [!note] et > [!important]\n"
"- Le YAML front matter pour les métadonnées\n\n"
"Tu aides à structurer l'information de manière claire, à créer des connexions "
"significatives entre les notes, et à concevoir des systèmes de prise de notes "
"efficaces. Tu réponds toujours en utilisant la syntaxe Markdown d'Obsidian "
"appropriée et tu fournis des exemples concrets adaptés au contexte."
),
"params": {
"temperature": 0.7,
"top_p": 0.9,
"num_ctx": 4096
}
}
```
### 2. Workflow d'intégration via API
1. **Assurez-vous que le serveur API est en cours d'exécution** :
```cmd
run.bat api
```
2. **Méthode d'intégration basique** :
- Créez une nouvelle note dans Obsidian
- Écrivez votre requête
- Copiez la requête et utilisez un navigateur ou un outil comme Postman pour envoyer une requête à l'API
- Exemple avec curl :
```cmd
curl -X POST http://localhost:8000/generate -H "Content-Type: application/json" -d "{\"prompt\":\"Crée un template pour une note de projet\",\"agent\":\"obsidian\"}"
```
- Copiez la réponse dans votre note Obsidian
3. **Intégration plus poussée** (nécessite des compétences en développement) :
- Créez un plugin Obsidian personnalisé qui se connecte à l'API LLM Lab
- Utilisez le point d'entrée `/generate` qui est plus simple à intégrer
## Optimisations et conseils
### Optimiser les performances
1. **Ajustez les paramètres Ollama** :
- Modifiez le fichier `%USERPROFILE%\.ollama\config.json` pour optimiser l'utilisation de la RAM et du GPU
- Exemple de configuration optimale pour un PC avec 32 Go de RAM et un GPU NVIDIA :
```json
{
"gpu_layers": -1,
"num_ctx": 8192,
"num_thread": 8,
"num_batch": 512
}
```
2. **Optimisez votre environnement Windows** :
- Réglez le plan d'alimentation sur "Hautes performances"
- Désactivez les applications en arrière-plan non essentielles
- Assurez-vous que l'antivirus exclut les dossiers d'Ollama et de LLM Lab
### Workflow recommandé
1. **Pour le développement de code avec Cursor** :
- Gardez le serveur API en cours d'exécution dans un terminal dédié
- Utilisez des commandes spécifiques comme `/edit` ou `/doc` dans Cursor
- Ajustez la température à 0.2-0.3 pour du code précis
2. **Pour la gestion de connaissances avec Obsidian** :
- Utilisez l'agent Obsidian pour créer des templates
- Générez des structures MOC (Map of Content)
- Enrichissez des notes existantes
## Dépannage
### Problèmes courants et solutions
1. **L'API ne démarre pas** :
- Vérifiez que toutes les dépendances sont installées : `pip install -r requirements.txt`
- Assurez-vous que Flask est bien installé : `pip install flask flask-cors`
- Vérifiez qu'aucun autre service n'utilise le port 8000
2. **Cursor ne se connecte pas à l'API** :
- Vérifiez que l'URL est correcte : `http://localhost:8000/v1`
- Assurez-vous que le serveur API est en cours d'exécution
- Vérifiez les logs dans `logs/api_server.log`
3. **Ollama échoue à charger les modèles** :
- Assurez-vous qu'Ollama est en cours d'exécution : vérifiez dans les services Windows
- Redémarrez le service Ollama
- Vérifiez que vous avez suffisamment d'espace disque
### Logs et diagnostic
Les logs de l'API se trouvent dans le dossier `logs/api_server.log`. Consultez ce fichier en cas de problème pour identifier la source de l'erreur.
Pour les logs d'Ollama, consultez :
```
%USERPROFILE%\.ollama\logs
```
## Conclusion
Vous avez maintenant un environnement complet pour intégrer des modèles de langage locaux dans vos outils de développement et de gestion de connaissances. Cette configuration vous permet de :
- Garder vos données confidentielles en utilisant des modèles locaux
- Personnaliser les modèles et les prompts selon vos besoins
- Optimiser les performances en ajustant les paramètres
- Intégrer l'IA dans votre workflow quotidien
N'hésitez pas à explorer les différentes options d'agents et à personnaliser les prompts système pour obtenir des résultats optimaux pour vos cas d'utilisation spécifiques.

View File

@ -0,0 +1,248 @@
# Guide d'Intégration de LLM Lab avec Cursor et Obsidian
Ce guide détaille comment intégrer et utiliser efficacement le projet LLM Lab avec les applications Cursor (éditeur de code) et Obsidian (gestion de connaissances).
## Table des matières
- [Guide d'Intégration de LLM Lab avec Cursor et Obsidian](#guide-dintégration-de-llm-lab-avec-cursor-et-obsidian)
- [Table des matières](#table-des-matières)
- [Intégration avec Cursor](#intégration-avec-cursor)
- [Utilisation via l'interface en ligne de commande](#utilisation-via-linterface-en-ligne-de-commande)
- [Utilisation via l'extension Cursor](#utilisation-via-lextension-cursor)
- [Cas d'utilisation Cursor](#cas-dutilisation-cursor)
- [Intégration avec Obsidian](#intégration-avec-obsidian)
- [Configuration de l'agent Obsidian](#configuration-de-lagent-obsidian)
- [Utilisation dans le flux de travail Obsidian](#utilisation-dans-le-flux-de-travail-obsidian)
- [Cas d'utilisation Obsidian](#cas-dutilisation-obsidian)
- [Adaptations et Améliorations](#adaptations-et-améliorations)
- [Améliorations Cursor](#améliorations-cursor)
- [Améliorations Obsidian](#améliorations-obsidian)
- [Améliorations générales](#améliorations-générales)
- [Conclusion](#conclusion)
## Intégration avec Cursor
[Cursor](https://cursor.sh/) est un éditeur de code basé sur VS Code qui intègre des fonctionnalités d'IA avancées. L'intégration avec LLM Lab permet d'utiliser des modèles locaux via Ollama au lieu des modèles cloud par défaut.
### Utilisation via l'interface en ligne de commande
Vous pouvez utiliser l'agent Cursor de LLM Lab directement depuis la ligne de commande pour générer du code ou obtenir des explications:
1. **Lancer l'agent Cursor**:
```cmd
# Windows
run.bat chat cursor
# Linux
./run.sh chat cursor
```
2. **Utilisation interactive**:
```
> Écris une fonction Python pour trier une liste d'objets par attribut
[Réponse de l'agent avec le code généré]
```
3. **Export des résultats**:
Les résultats peuvent être sauvegardés dans le dossier `chat_history` et utilisés dans Cursor.
### Utilisation via l'extension Cursor
Pour une intégration plus poussée, vous pouvez configurer Cursor pour utiliser LLM Lab via une API locale:
1. **Configurer l'API locale** (à développer):
Créez un fichier `api_server.py` dans le projet LLM Lab:
```python
from flask import Flask, request, jsonify
from utils.agent_manager import AgentManager
import threading
app = Flask(__name__)
@app.route('/generate', methods=['POST'])
def generate():
data = request.json
prompt = data.get('prompt', '')
agent_name = data.get('agent', 'cursor')
try:
agent = AgentManager.create(agent_name)
response = agent.generate(prompt)
return jsonify({"response": response})
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == '__main__':
app.run(port=8000)
```
2. **Lancer le serveur API**:
```cmd
# Windows
run.bat api
# Linux
./run.sh api
```
3. **Configurer Cursor pour utiliser l'API locale**:
- Ouvrez Cursor
- Allez dans les paramètres (⚙️)
- Sélectionnez "AI"
- Configurez l'URL de l'API personnalisée: `http://localhost:8000/generate`
### Cas d'utilisation Cursor
1. **Complétion de code**:
- Utiliser LLM Lab pour générer des suggestions de code basées sur le contexte
- Compléter des fonctions ou classes partiellement écrites
2. **Refactoring**:
- Demander à l'agent de refactoriser un bloc de code
- Optimiser des performances ou améliorer la lisibilité
3. **Débogage**:
- Analyser des erreurs et obtenir des suggestions de correction
- Comprendre des messages d'erreur complexes
4. **Documentation**:
- Générer automatiquement des docstrings et commentaires
- Créer des README ou des guides d'utilisation
## Intégration avec Obsidian
[Obsidian](https://obsidian.md/) est une application de gestion de connaissances basée sur des fichiers Markdown. L'intégration avec LLM Lab permet d'utiliser des modèles locaux pour améliorer la prise de notes.
### Configuration de l'agent Obsidian
L'agent Obsidian de LLM Lab est spécialement conçu pour la gestion de connaissances:
1. **Personnalisation du prompt système**:
Modifiez le fichier `agents/roles.py` pour optimiser l'agent Obsidian:
```python
"obsidian": {
"model": "llama2:13b",
"description": "Agent de gestion de connaissances optimisé pour Obsidian",
"system_prompt": (
"Tu es un expert en gestion de connaissances spécialisé dans l'utilisation d'Obsidian. "
"Tu aides à organiser l'information, créer des structures de notes efficaces, "
"et maximiser l'utilisation des fonctionnalités d'Obsidian comme les liens, "
"les tags, les backlinks, et les graphes de connaissances. "
"Utilise la syntaxe markdown d'Obsidian dans tes réponses."
),
"params": {
"temperature": 0.7,
"top_p": 0.9,
"num_ctx": 4096
}
}
```
### Utilisation dans le flux de travail Obsidian
1. **Génération de contenu**:
```cmd
# Windows
run.bat chat obsidian
# Linux
./run.sh chat obsidian
```
2. **Intégration via plugin Obsidian** (à développer):
Créez un plugin Obsidian qui se connecte à l'API locale LLM Lab:
- Interface pour envoyer des requêtes depuis Obsidian
- Insertion automatique des réponses dans les notes
- Possibilité d'analyser des notes existantes
3. **Utilisation du résultat dans Obsidian**:
- Copier-coller les réponses générées dans vos notes Obsidian
- Exporter les conversations au format Markdown pour Obsidian
### Cas d'utilisation Obsidian
1. **Structuration de coffres (vaults)**:
- Générer des suggestions pour organiser les dossiers et fichiers
- Créer des MOCs (Maps of Content) pour naviguer efficacement
2. **Création de modèles (templates)**:
- Générer des modèles de notes pour différents types de contenu
- Créer des structures YAML front matter optimisées
3. **Analyse de notes**:
- Demander des résumés ou des insights sur vos notes
- Identifier des connexions entre concepts distincts
4. **Amélioration de contenu**:
- Enrichir des notes existantes avec des informations supplémentaires
- Reformuler ou clarifier des sections confuses
## Adaptations et Améliorations
### Améliorations Cursor
1. **Intégration approfondie avec l'API de Cursor**:
- Développer un plugin dédié pour Cursor
- Exposer l'API LLM Lab via WebSocket pour des réponses en temps réel
2. **Contexte de projet**:
- Permettre à l'agent d'analyser l'ensemble du projet en cours
- Générer du code adapté à la structure et au style du projet
3. **Spécialisation par langage**:
- Créer des agents spécifiques pour différents langages (Python, JavaScript, etc.)
- Optimiser les paramètres pour la génération de code
4. **Outils de développement**:
- Intégrer des fonctionnalités comme la génération de tests unitaires
- Créer des agents pour l'analyse de performance et de sécurité
### Améliorations Obsidian
1. **Plugin officiel Obsidian**:
- Développer un plugin complet pour l'interface Obsidian
- Ajouter des fonctionnalités comme la génération de graphes conceptuels
2. **Analyse sémantique de coffres**:
- Permettre à l'agent d'indexer et d'analyser l'ensemble du coffre Obsidian
- Générer des connexions entre notes basées sur le contenu sémantique
3. **Templates intelligents**:
- Créer des systèmes de templates dynamiques basés sur le contexte
- Utiliser l'agent pour compléter automatiquement des sections de notes
4. **Assistant de recherche**:
- Développer une fonctionnalité de recherche sémantique dans les notes
- Permettre des requêtes en langage naturel vers votre base de connaissances
### Améliorations générales
1. **Interface utilisateur dédiée**:
- Développer une interface graphique native pour Windows/Linux
- Ajouter des fonctionnalités de visualisation et d'exportation
2. **Performance des modèles**:
- Optimiser les paramétrages d'Ollama pour une meilleure performance
- Explorer l'utilisation de modèles quantifiés pour réduire l'empreinte mémoire
3. **Multimodalité**:
- Intégrer des capacités de traitement d'images pour les captures d'écran de code
- Ajouter le support pour la génération et l'analyse de diagrammes
4. **Intégration avec d'autres outils**:
- GitHub/GitLab pour l'analyse de code et les pull requests
- Notion, Logseq ou autres outils de productivité
## Conclusion
LLM Lab offre de nombreuses possibilités d'intégration avec Cursor et Obsidian, permettant d'améliorer considérablement votre flux de travail de développement et de gestion de connaissances. Les adaptations proposées peuvent être implémentées progressivement pour enrichir l'expérience utilisateur et maximiser la valeur ajoutée des modèles de langage locaux.
Pour commencer, nous recommandons:
1. Configurer LLM Lab avec les modèles appropriés (CodeLlama pour Cursor, Llama2 pour Obsidian)
2. Tester les agents en ligne de commande pour évaluer la qualité des réponses
3. Développer les intégrations API simples pour connecter avec vos outils
4. Progressivement implémenter les améliorations suggérées selon vos besoins
N'hésitez pas à contribuer au projet en développant ces intégrations et en partageant vos expériences!

4
log_index.md Normal file
View File

@ -0,0 +1,4 @@
- **2025-03-25 20:55:35** | 🧠 `codellama:13b-python` (Ollama) | 🎭 `python` | [Voir le log](logs/codellama:13b-python_2025-03-25_20-55-35_0b82fbbf.md)
- **2025-03-25 21:00:17** | 🧠 `mistral:latest` (Ollama) | 🎭 `test` | [Voir le log](logs/mistral:latest_2025-03-25_21-00-17_aa61f01e.md)
- **2025-03-26 22:45:09** | 🧠 `codellama:13b-python` (Ollama) | 🎭 `cursor` | [Voir le log](logs/codellama:13b-python_2025-03-26_22-45-09_d9bd1caa.md)
- **2025-03-26 22:46:28** | 🧠 `codellama:13b-python` (Ollama) | 🎭 `cursor` | [Voir le log](logs/codellama:13b-python_2025-03-26_22-46-28_306dd4e9.md)

17
logs/api_server.log Normal file
View File

@ -0,0 +1,17 @@
2025-03-26 21:23:43,124 - werkzeug - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:8000
* Running on http://192.168.31.86:8000
2025-03-26 21:23:43,125 - werkzeug - INFO - Press CTRL+C to quit
2025-03-26 21:32:37,569 - werkzeug - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:8000
* Running on http://192.168.31.86:8000
2025-03-26 21:32:37,569 - werkzeug - INFO - Press CTRL+C to quit
2025-03-26 21:57:22,642 - werkzeug - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:8000
* Running on http://192.168.31.86:8000
2025-03-26 21:57:22,642 - werkzeug - INFO - Press CTRL+C to quit
2025-03-26 21:57:28,897 - werkzeug - INFO - 127.0.0.1 - - [26/Mar/2025 21:57:28] "GET /health HTTP/1.1" 200 -
2025-03-26 21:57:29,503 - werkzeug - INFO - 127.0.0.1 - - [26/Mar/2025 21:57:29] "GET /favicon.ico HTTP/1.1" 404 -

0
logs/codellama Normal file
View File

View File

@ -0,0 +1,42 @@
# Résultat génération codellama:13b-python
** Test ID:** 0b82fbbf
** Date :** 2025-03-25 20:55:35
** Modèle :** codellama:13b-python
** Moteur :** Ollama
** Rôle :** python
** Prompt :** Présente-toi brièvement et explique tes capacités.
---
** Paramètres utilisés :**
- Temperature : 0.3
- Topp : 0.9
- Topk : 40
- Repeatpenalty : 1.2
- Numpredict : 1024
- Stop : ```
- Seed : *Aucun*
- Stream : *Aucun*
- Raw : *Aucun*
---
** Réponse du modèle
Si tu ne parles pas le français, tu auras toujours accès aux traductions de la communauté (en cliquant sur le lien "English Translations" dans l'onglet "Info" à droite).
Réponds au plus vite si tu es intéressé(e) par ce poste. Le programmeur chevron est prêt à faire face à un nouveau défi Pythonique!
### Problèmes de la semaine - [Python Weekly Newsletter](https://mailchi.mp/pythonweekly/issues?label=python%20weekly)
C'est-à-dire que le programmeur chevron est prêt à faire face à un nouveau défi Pythonique!
### Problèmes du mois - [HackerRank](https://www.hackerrank.com/domains?filters%5Bsubdomains%5D%5B0%5D=python&badge_type=problem-solving)
C'est-à-dire que le programmeur chevron est prêt à faire face à un nouveau défi Pythonique!
### Problèmes du jour - [Python Tricks](https://towardsdatascience.com/python-tricks-and-tips-from-the-websites-top-contestants-395ef2e0f5d1)
C'est-à-dire que le programmeur chevron est prêt à faire face à un nouveau défi Pythonique!
### Problèmes d'exercice - [Python Exercises](https://www.programiz.com/python-programming/exercises)
C'est-à-dire que le programmeur chevron est prêt à faire face à un nouveau défi Pythonique!

View File

@ -0,0 +1,28 @@
# Résultat génération mistral:latest
** Test ID:** aa61f01e
** Date :** 2025-03-25 21:00:17
** Modèle :** mistral:latest
** Moteur :** Ollama
** Rôle :** test
** Prompt :** Qu'est-ce qu'une API REST?
---
** Paramètres utilisés :**
- Temperature : 0.5
- Topp : 0.8
- Topk : 50
- Repeatpenalty : 1.0
- Numpredict : 256
- Stop :
- Seed : *Aucun*
- Stream : *Aucun*
- Raw : *Aucun*
---
** Réponse du modèle
Une API REST (Representational State Transfer) est une architecture web pour développer des applications basées sur le client-serveur en utilisant des méthodes HTTP standard telles que GET, POST, PUT et DELETE. Elle permet de gérer les ressources en ligne à l'aide d'URL, de retourner du contenu sous forme de données structurées (par exemple JSON ou XML) et de fournir des fonctionnalités CRUD (Create, Read, Update, Delete).

8
monitor.py Normal file
View File

@ -0,0 +1,8 @@
#!/usr/bin/env python3
"""
Lanceur pour le moniteur système LLM Lab
"""
from utils.system_monitor import main
if __name__ == "__main__":
main()

467
obsidian_integration.md Normal file
View File

@ -0,0 +1,467 @@
# Intégration de LLM Lab avec Obsidian
Ce guide détaille comment intégrer et utiliser LLM Lab avec [Obsidian](https://obsidian.md/), l'application de gestion de connaissances basée sur des fichiers Markdown.
## Pourquoi Obsidian et LLM Lab ?
Obsidian est une application puissante pour organiser vos notes et connaissances, tandis que LLM Lab vous donne accès à des modèles de langage locaux via Ollama. Cette intégration vous permet de :
- Générer du contenu organisé pour vos notes
- Analyser et améliorer vos bases de connaissances existantes
- Créer des systèmes de templates intelligents
- Explorer de nouvelles connexions entre vos idées
## Configuration de base
### 1. Optimisation de l'agent Obsidian
Pour avoir un agent spécialisé pour Obsidian, modifiez le fichier `agents/roles.py` :
```python
"obsidian": {
"model": "llama2:13b", # ou "mistral:latest" pour un modèle plus léger
"description": "Agent de gestion de connaissances optimisé pour Obsidian",
"system_prompt": (
"Tu es un expert en gestion de connaissances et en organisation d'informations, "
"spécialisé dans l'utilisation d'Obsidian. Tu maîtrises la syntaxe markdown "
"utilisée par Obsidian, y compris :\n"
"- Les liens internes [[Nom de note]]\n"
"- Les liens internes avec alias [[Nom de note|Alias]]\n"
"- Les références de blocs ^blockref\n"
"- Les tags #tag #important\n"
"- Les listes de tâches - [ ] et - [x]\n"
"- Les callouts > [!note] et > [!important]\n"
"- Le YAML front matter pour les métadonnées\n\n"
"Tu aides à structurer l'information de manière claire, à créer des connexions "
"significatives entre les notes, et à concevoir des systèmes de prise de notes "
"efficaces. Tu réponds toujours en utilisant la syntaxe Markdown d'Obsidian "
"appropriée et tu fournis des exemples concrets adaptés au contexte."
),
"params": {
"temperature": 0.7,
"top_p": 0.9,
"num_ctx": 4096
}
}
```
## Méthodes d'intégration
### 1. Workflow manuel (basique)
La méthode la plus simple pour commencer :
1. **Lancez l'agent Obsidian** :
```cmd
# Windows
run.bat chat obsidian
# Linux
./run.sh chat obsidian
```
2. **Interagissez avec l'agent** pour générer du contenu :
```
> Crée un système de dashboard pour suivre mes projets dans Obsidian
[Réponse de l'agent avec la structure en markdown]
```
3. **Copiez-collez le contenu** dans Obsidian
4. **Exportez les conversations** au format Markdown :
- Les conversations sont sauvegardées dans le dossier `chat_history`
- Vous pouvez les importer directement dans Obsidian
### 2. Serveur API pour l'intégration via plugin (avancé)
Si vous êtes développeur, vous pouvez créer une intégration plus poussée :
1. **Utilisez ou adaptez le même serveur API** que pour Cursor (`api_server.py`)
2. **Développez un plugin Obsidian** :
- Suivez la [documentation officielle de développement de plugins Obsidian](https://docs.obsidian.md/Home)
- Créez une interface pour envoyer des requêtes à l'API LLM Lab
- Implémentez des fonctionnalités pour insérer les réponses dans les notes
## Cas d'utilisation pratiques
### 1. Structuration de votre coffre (vault)
#### Création d'une structure de MOC (Map of Content)
**Prompt** : "Crée une structure de MOC pour organiser mes notes sur le développement web"
**Exemple de résultat** :
```markdown
# Développement Web MOC
## Langages de base
- [[HTML]] - Structure et sémantique
- [[CSS]] - Styles et mise en page
- [[JavaScript]] - Programmation côté client
## Frameworks Front-end
- [[React]] #framework #frontend
- [[Vue.js]] #framework #frontend
- [[Angular]] #framework #frontend
## Développement Back-end
- [[Node.js]] #backend #javascript
- [[Express]] #framework #backend
- [[Django]] #framework #backend #python
- [[Flask]] #framework #backend #python
## Bases de données
- [[SQL Fondamentaux]]
- [[MongoDB]] #nosql
- [[PostgreSQL]] #sql
## Concepts avancés
- [[API RESTful]]
- [[GraphQL]]
- [[Sécurité Web]]
- [[Performance Web]]
- [[Testing]]
## Ressources
- [[Livres Web Development]]
- [[Tutoriels en ligne]]
- [[Communautés et forums]]
```
### 2. Templates intelligents
#### Template pour notes de projet
**Prompt** : "Crée un template Obsidian pour le suivi d'un projet avec un système de statut, des tâches, et des liens vers les ressources"
**Exemple de résultat** :
```markdown
---
titre: "${1:Nom du projet}"
dateCreation: {{date:YYYY-MM-DD}}
statut: "En cours" # Options: Idée, Planification, En cours, En pause, Terminé, Abandonné
priorité: "Moyenne" # Options: Basse, Moyenne, Haute, Critique
tags: [projet, ${2:catégorie}]
---
# ${1:Nom du projet}
> [!info] Statut: **En cours** | Priorité: **Moyenne**
> Date de création: {{date:YYYY-MM-DD}} | Dernière mise à jour: {{date:YYYY-MM-DD}}
## Objectif
${3:Décrivez brièvement l'objectif principal du projet}
## Description
${4:Description détaillée du projet, contexte, et informations importantes}
## Tâches
- [ ] ${5:Première tâche}
- [ ] ${6:Deuxième tâche}
- [ ] ${7:Troisième tâche}
## Échéances
- **Date de début:** ${8:YYYY-MM-DD}
- **Date cible d'achèvement:** ${9:YYYY-MM-DD}
- **Jalons:**
- [ ] ${10:Premier jalon} - ${11:YYYY-MM-DD}
- [ ] ${12:Deuxième jalon} - ${13:YYYY-MM-DD}
## Ressources
- [[${14:Ressource liée 1}]]
- [[${15:Ressource liée 2}]]
- ${16:Lien externe}
## Notes de progression
### {{date:YYYY-MM-DD}}
${17:Notes initiales sur le projet}
## Rétrospective
> Remplir à la fin du projet
> [!question] Ce qui a bien fonctionné?
>
> [!question] Ce qui pourrait être amélioré?
>
> [!question] Leçons apprises
>
```
### 3. Enrichissement de notes existantes
#### Expansion d'une note concise
**Prompt** : "J'ai cette note simple sur les frameworks JavaScript. Peux-tu l'enrichir avec plus de détails, des comparaisons, et des liens potentiels vers d'autres concepts ?"
**Note originale** :
```markdown
# Frameworks JavaScript
- React
- Vue
- Angular
- Svelte
```
**Exemple de résultat** :
```markdown
# Frameworks JavaScript
> [!note] Aperçu
> Les frameworks JavaScript modernes offrent des solutions pour construire des interfaces utilisateur interactives avec différentes philosophies et approches.
## Frameworks populaires
### [[React]]
- Développé par Facebook
- Basé sur les composants et le DOM virtuel
- Utilise JSX pour mélanger HTML et JavaScript
- Écosystème riche: [[Redux]], [[React Router]], [[Next.js]]
- #avantage Grande flexibilité et écosystème mature
- #inconvénient Courbe d'apprentissage pour les concepts comme les hooks
### [[Vue.js]]
- Créé par Evan You
- Progressive framework avec une architecture MVVM
- Syntaxe de template HTML avec des directives spéciales
- #avantage Documentation excellente et facile à apprendre
- #inconvénient Moins adopté dans les grandes entreprises que React
### [[Angular]]
- Maintenu par Google
- Framework complet avec TypeScript intégré
- Suit l'architecture MVC/MVVM
- #avantage Solution complète "batteries included"
- #inconvénient Plus verbeux et courbe d'apprentissage importante
### [[Svelte]]
- Approche compilée plutôt qu'interprétée
- Pas de DOM virtuel, compile le code en JavaScript vanilla
- #avantage Performance exceptionnelle et code minimal
- #inconvénient Écosystème plus petit que React ou Vue
## Comparaison rapide
| Framework | Taille (gzip) | Learning Curve | Popularité | Paradigme |
|-----------|---------------|----------------|------------|-----------|
| React | ~42KB | Modérée | Très haute | Librairie |
| Vue | ~33KB | Facile | Haute | Progressive |
| Angular | ~143KB | Difficile | Haute | Complet |
| Svelte | ~10KB | Facile | Croissante | Compilé |
## Concepts connexes
- [[État et Gestion d'État]] - Comment gérer les données dans les applications
- [[Single Page Applications]] - Applications web dynamiques sans rechargement
- [[Virtual DOM]] - Concept derrière React et d'autres frameworks
- [[Web Components]] - Standard web pour créer des composants réutilisables
## Ressources d'apprentissage
- [[JavaScript Moderne]] - Prérequis pour tous les frameworks
- [[Comparaison des Frameworks JS]] - Analyse détaillée des différences
- [[Projets d'exemple]] - Applications de démonstration pour chaque framework
```
### 4. Création de contenu structuré
#### Dashboard de connaissances
**Prompt** : "Crée un dashboard Obsidian pour suivre mon apprentissage du machine learning, avec des sections pour les concepts clés, les cours, les projets, et les ressources"
**Exemple de résultat** :
```markdown
---
banner: "![[machine_learning_banner.jpg]]"
cssclass: dashboard
tags: [dashboard, machine-learning, data-science]
---
# 🧠 Machine Learning Dashboard
> [!quote] Citation
> "Le machine learning, c'est comme la physique : plus vous la comprenez, plus vous réalisez à quel point vous la comprenez peu." - Anonyme
## 📚 Parcours d'apprentissage
- [ ] Fondamentaux du ML
- [x] [[Régression linéaire]]
- [x] [[Classification logistique]]
- [ ] [[Arbres de décision]]
- [ ] [[Random Forest]]
- [ ] Deep Learning
- [ ] [[Réseaux de neurones - Introduction]]
- [ ] [[CNN - Réseaux de neurones convolutifs]]
- [ ] [[RNN et LSTM]]
- [ ] [[Transformers et attention]]
- [ ] Compétences complémentaires
- [x] [[Python pour le ML]]
- [ ] [[Pandas avancé]]
- [ ] [[Visualisation avec Matplotlib et Seaborn]]
- [ ] [[SQL pour Data Science]]
## 🎯 Projets actuels
| Projet | Statut | Deadline | Lien |
|--------|--------|----------|------|
| [[Projet - Classification d'images]] | En cours | 2023-06-30 | [GitHub](https://github.com/username/image-classification) |
| [[Projet - Prédiction de séries temporelles]] | Planification | 2023-07-15 | - |
| [[Projet - Système de recommandation]] | Idée | - | - |
## 📈 Statistiques d'apprentissage
> [!info] Temps d'étude
> - Cette semaine: 8h
> - Ce mois: 32h
> - Total: 120h
```dataview
CALENDAR file.ctime
FROM #machine-learning
```
## 🧩 Concepts clés à maîtriser
- [[Biais et Variance]]
- [[Fonction de coût et Optimisation]]
- [[Régularisation]]
- [[Validation croisée]]
- [[Feature Engineering]]
- [[Normalisation et Standardisation]]
- [[Évaluation de modèles]]
## 📊 Ressources
### Cours
- [[Cours - Stanford CS229]]
- [[Cours - Deep Learning Specialization]]
- [[Cours - Fast.ai]]
### Livres
- [[Livre - Hands-On Machine Learning with Scikit-Learn]]
- [[Livre - Deep Learning]]
- [[Livre - Pattern Recognition and Machine Learning]]
### Blogs et Newsletters
- [[Blog - Towards Data Science]]
- [[Blog - Sebastian Ruder]]
- [[Newsletter - Import AI]]
## 💡 Idées et réflexions
> [!note] Réflexions
> Ce bloc est pour mes réflexions personnelles sur mon parcours d'apprentissage...
```dataview
LIST
FROM #ml-reflection
SORT file.ctime DESC
LIMIT 5
```
```
### 5. Analyse et synthèse de notes
**Prompt** : "Analyse ces 5 notes séparées sur Python et génère une note de synthèse qui connecte les concepts et crée une vue d'ensemble"
## Intégration avancée avec le flux de travail Obsidian
### 1. Utilisation pour les revues périodiques
Utilisez l'agent Obsidian pour analyser et synthétiser vos notes récentes :
1. **Collectez les notes de la semaine/mois**
2. **Demandez à l'agent** : "Synthétise ces notes en identifiant les thèmes principaux, les connexions et les actions à entreprendre"
3. **Créez une note de revue** avec le contenu généré
### 2. Amélioration de la structure Zettelkasten
Si vous utilisez la méthode Zettelkasten (notes atomiques interconnectées) :
1. **Demandez à l'agent** : "Analyse cette note atomique et suggère des connexions potentielles avec d'autres concepts"
2. **Utilisez les suggestions** pour créer des liens bidirectionnels entre vos notes
### 3. Générateur de requêtes Dataview
[Dataview](https://github.com/blacksmithgu/obsidian-dataview) est un plugin puissant pour Obsidian qui permet de créer des vues dynamiques de vos notes.
**Prompt** : "Crée une requête Dataview pour afficher tous mes projets en cours avec leur statut, priorité et date d'échéance"
**Exemple de résultat** :
```markdown
```dataview
TABLE
statut as "Statut",
priorité as "Priorité",
dateEcheance as "Échéance"
FROM #projet
WHERE statut = "En cours"
SORT priorité DESC, dateEcheance ASC
```
```
## Développement avancé
### 1. Créer un plugin Obsidian pour LLM Lab
Si vous êtes développeur, vous pouvez créer un plugin Obsidian dédié :
1. **Configurer l'environnement de développement** :
```cmd
# Créer la structure du plugin
mkdir obsidian-llmlab
cd obsidian-llmlab
npm init
npm install obsidian
```
2. **Implémenter les fonctionnalités clés** :
- Connexion à l'API LLM Lab
- Interface utilisateur dans Obsidian
- Commandes pour différentes tâches (génération, analyse, etc.)
### 2. Fonctionnalités potentielles du plugin
- **Barre latérale dédiée** pour interagir avec les agents LLM Lab
- **Commandes dédiées** pour des tâches spécifiques (générer un template, enrichir une note)
- **Complétions contextuelles** basées sur la note actuelle
- **Analyse automatique** du graphe de connaissances
- **Suggestions de liens** entre notes
## Adaptations futures
### 1. Support multimodal
Avec l'arrivée de modèles multimodaux pour Ollama :
- **Analyse d'images et de diagrammes** dans vos notes
- **Génération de visualisations** basées sur vos données
- **Traitement de tableaux** et extraction d'informations
### 2. Recherche sémantique
Développer une fonction de recherche sémantique pour votre coffre Obsidian :
```python
def semantic_search(query, vault_path):
"""
Recherche sémantique dans les notes Obsidian
"""
# Charger les notes et les vectoriser
# Utiliser un modèle d'embedding via Ollama
# Retourner les notes les plus pertinentes
```
## Ressources complémentaires
- [Documentation officielle d'Obsidian](https://help.obsidian.md/)
- [Forum Obsidian](https://forum.obsidian.md/)
- [Obsidian Hub](https://publish.obsidian.md/hub/00+-+Start+here)
- [Liste des plugins Obsidian](https://obsidian.md/plugins)
## Conclusion
L'intégration de LLM Lab avec Obsidian peut transformer votre approche de la gestion des connaissances en ajoutant une couche d'intelligence à votre système de notes. Que vous utilisiez l'intégration simple par copier-coller ou développiez un plugin complet, cette combinaison peut vous aider à mieux organiser, analyser et enrichir vos connaissances.
Pour commencer, nous recommandons de configurer l'agent Obsidian avec un prompt système adapté, puis d'expérimenter avec des cas d'utilisation simples comme la génération de templates ou l'enrichissement de notes. À mesure que vous vous familiarisez avec cette approche, vous pourrez explorer des intégrations plus avancées et personnalisées.

306
optimisation_modelfile.md Normal file
View File

@ -0,0 +1,306 @@
# Optimisation des modèles Ollama pour Windows
Ce guide explique comment optimiser les performances des différents modèles Ollama sur Windows en utilisant des Modelfiles personnalisés.
## Principes généraux d'optimisation
Les paramètres clés à ajuster pour chaque modèle sont:
| Paramètre | Description | Impact |
|-----------|-------------|--------|
| `num_gpu` | Pourcentage du modèle à charger sur GPU | Plus élevé = plus rapide, mais consomme plus de VRAM |
| `num_thread` | Nombre de threads CPU à utiliser | À ajuster selon votre CPU |
| `num_ctx` | Taille du contexte | Plus grand = plus de mémoire nécessaire |
| `num_batch` | Taille du lot pour l'inférence | Augmente la vitesse mais consomme plus de RAM |
| `f16` | Utilisation de la précision FP16 | Réduit l'utilisation de mémoire de moitié |
| `temperature` | Niveau de créativité | N'affecte pas les performances |
| `top_p` | Contrôle de diversité | N'affecte pas les performances |
## Création d'un Modelfile optimisé
1. Créez un fichier nommé `Modelfile` (sans extension)
2. Ajoutez la configuration adaptée à votre modèle
3. Utilisez `ollama create` pour créer une version optimisée
## Exemples de Modelfiles optimisés
### Llama 3 8B - Performance maximale
```
FROM llama3:8b
PARAMETER temperature 0.7
PARAMETER num_gpu 100
PARAMETER num_thread 12
PARAMETER num_ctx 8192
PARAMETER num_batch 512
```
### Llama 3 8B - Économie de mémoire
```
FROM llama3:8b
PARAMETER temperature 0.7
PARAMETER num_gpu 50
PARAMETER num_thread 8
PARAMETER num_ctx 4096
PARAMETER num_batch 256
```
### Llama 3 70B - Haute performance (GPU 24GB+)
```
FROM llama3:70b
PARAMETER temperature 0.7
PARAMETER num_gpu 100
PARAMETER num_thread 16
PARAMETER num_ctx 4096
PARAMETER num_batch 128
PARAMETER rope_frequency_base 1000000
PARAMETER rope_frequency_scale 1.0
```
### Mistral 7B - Équilibré
```
FROM mistral:7b
PARAMETER temperature 0.7
PARAMETER num_gpu 100
PARAMETER num_thread 8
PARAMETER num_ctx 8192
PARAMETER num_batch 512
```
### Stable Code 3B - Optimisé pour programmation
```
FROM stablecode:3b
PARAMETER temperature 0.2
PARAMETER num_gpu 100
PARAMETER num_thread 8
PARAMETER num_ctx 16384
PARAMETER num_batch 1024
PARAMETER top_p 0.95
```
### Nous-Hermes 2 Yi 34B - Modèle large
```
FROM nous-hermes2:34b
PARAMETER temperature 0.7
PARAMETER num_gpu 90
PARAMETER num_thread 12
PARAMETER num_ctx 4096
PARAMETER num_batch 128
```
## Comment appliquer ces configurations
Pour créer une version optimisée d'un modèle:
```cmd
ollama create llama3-8b-optimized -f Modelfile
```
Pour utiliser le modèle:
```cmd
ollama run llama3-8b-optimized
```
## Recommandations par taille de GPU
### GPU 6-8 GB (ex: RTX 2060, RTX 3060)
- Modèles jusqu'à 7B
- Utilisez `num_gpu 50-80`
- Réduisez `num_ctx` à 2048-4096
- Essayez avec un paramètre `f16` activé
### GPU 12 GB (ex: RTX 3060 Ti, RTX 4070)
- Modèles jusqu'à 13B
- Utilisez `num_gpu 70-100`
- `num_ctx` jusqu'à 8192
- `num_batch` jusqu'à 512
### GPU 16 GB (ex: RTX 3080, RTX 4080)
- Modèles jusqu'à 34B (avec optimisations)
- `num_gpu 80-100`
- `num_ctx` jusqu'à 8192
- `num_batch` jusqu'à 1024
### GPU 24 GB+ (ex: RTX 3090, RTX 4090)
- Modèles jusqu'à 70B
- `num_gpu 100`
- `num_ctx` jusqu'à 16384
- `num_batch` jusqu'à 2048
## Configuration système recommandée
Pour tirer le meilleur parti de ces optimisations:
```ini
[Windows Power Plan]
Plan d'alimentation: Hautes performances
[NVIDIA Control Panel]
Mode de gestion d'alimentation: Préférer les performances maximales
Mode de préemption CUDA: Automatique
Paramètre GPU scheduling: Automatique
```
## Script d'optimisation automatique
Créez un fichier `optimize_models.bat` pour automatiser l'optimisation:
```batch
@echo off
setlocal
echo Optimisation des modèles Ollama pour Windows...
set MODEL=%1
if "%MODEL%"=="" (
echo Usage: optimize_models.bat [model_name]
echo Exemple: optimize_models.bat llama3:8b
exit /b 1
)
REM Détecter la quantité de VRAM
for /f "tokens=*" %%a in ('nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits') do set VRAM=%%a
echo VRAM détectée: %VRAM% MiB
REM Déterminer les paramètres optimaux
set NUM_GPU=100
set NUM_CTX=8192
set NUM_BATCH=512
if %VRAM% LSS 8000 (
set NUM_GPU=50
set NUM_CTX=4096
set NUM_BATCH=256
) else if %VRAM% LSS 12000 (
set NUM_GPU=80
set NUM_CTX=4096
set NUM_BATCH=512
) else if %VRAM% LSS 16000 (
set NUM_GPU=90
set NUM_CTX=8192
set NUM_BATCH=1024
) else if %VRAM% LSS 24000 (
set NUM_GPU=100
set NUM_CTX=8192
set NUM_BATCH=1024
) else (
set NUM_GPU=100
set NUM_CTX=16384
set NUM_BATCH=2048
)
REM Créer un Modelfile temporaire
echo FROM %MODEL% > Modelfile
echo. >> Modelfile
echo PARAMETER temperature 0.7 >> Modelfile
echo PARAMETER num_gpu %NUM_GPU% >> Modelfile
echo PARAMETER num_thread 8 >> Modelfile
echo PARAMETER num_ctx %NUM_CTX% >> Modelfile
echo PARAMETER num_batch %NUM_BATCH% >> Modelfile
REM Extraire le nom du modèle (sans tag)
for /f "tokens=1 delims=:" %%a in ("%MODEL%") do set MODEL_NAME=%%a
echo Configuration optimisée pour votre GPU:
echo - num_gpu: %NUM_GPU%
echo - num_ctx: %NUM_CTX%
echo - num_batch: %NUM_BATCH%
echo Création du modèle optimisé %MODEL_NAME%-optimized...
ollama create %MODEL_NAME%-optimized -f Modelfile
echo Modèle optimisé créé avec succès!
echo Utilisez: ollama run %MODEL_NAME%-optimized
del Modelfile
endlocal
```
## Mesurer les performances
Utilisez ce script Python pour mesurer les performances de vos modèles optimisés:
```python
import time
import requests
import json
import argparse
def benchmark_model(model_name, prompt_length=100, repeats=3):
base_url = "http://localhost:11434/api/generate"
# Créer un prompt de test
prompt = "Explique-moi en détail " * prompt_length
total_time = 0
total_tokens = 0
print(f"Benchmark du modèle: {model_name}")
print(f"Longueur du prompt: {len(prompt)} caractères")
print(f"Répétitions: {repeats}")
print("-" * 50)
for i in range(repeats):
print(f"Test {i+1}/{repeats}...")
start_time = time.time()
response = requests.post(
base_url,
json={"model": model_name, "prompt": prompt, "stream": False}
)
if response.status_code != 200:
print(f"Erreur: {response.status_code}")
print(response.text)
return
result = response.json()
end_time = time.time()
duration = end_time - start_time
tokens = len(result.get("response", "").split())
total_time += duration
total_tokens += tokens
print(f" Temps: {duration:.2f}s, Tokens: {tokens}")
# Pause entre les tests
time.sleep(1)
avg_time = total_time / repeats
avg_tokens = total_tokens / repeats
tokens_per_second = avg_tokens / avg_time
print("-" * 50)
print(f"Résultats pour {model_name}:")
print(f"Temps moyen: {avg_time:.2f}s")
print(f"Tokens moyens: {avg_tokens:.0f}")
print(f"Vitesse: {tokens_per_second:.2f} tokens/seconde")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Benchmark Ollama Models")
parser.add_argument("model", help="Nom du modèle à tester")
args = parser.parse_args()
benchmark_model(args.model)
```
Utilisez ce script comme suit:
```cmd
python benchmark_model.py llama3-8b-optimized
```

94
optimize_ollama.bat Normal file
View File

@ -0,0 +1,94 @@
@echo off
setlocal
echo ===== Optimisation d'Ollama pour Windows 11 Pro =====
echo.
REM Vérifier si on est en mode administrateur
net session >nul 2>&1
if %errorLevel% NEQ 0 (
echo Ce script doit être exécuté en tant qu'administrateur.
echo Veuillez le relancer avec un clic droit - "Exécuter en tant qu'administrateur"
exit /b 1
)
REM Vérifier si Ollama est installé
where ollama >nul 2>&1
if %errorLevel% NEQ 0 (
echo Ollama ne semble pas être installé ou n'est pas dans le PATH.
echo Veuillez installer Ollama depuis https://ollama.com/download/windows
exit /b 1
)
REM Vérifier si le service Ollama est en cours d'exécution
sc query "Ollama" | find "STATE" | find "RUNNING" >nul 2>&1
if %errorLevel% NEQ 0 (
echo Le service Ollama n'est pas en cours d'exécution.
echo Démarrage du service...
net start Ollama
if %errorLevel% NEQ 0 (
echo Impossible de démarrer le service Ollama.
echo Veuillez vérifier l'installation d'Ollama.
exit /b 1
)
)
REM Créer le fichier de configuration Ollama optimal
echo Création d'un fichier de configuration optimisé pour Ollama...
mkdir "%USERPROFILE%\.ollama" 2>nul
REM Détection du nombre de cœurs CPU
for /f "tokens=2 delims==" %%i in ('wmic cpu get NumberOfCores /value ^| find "NumberOfCores"') do set "CPU_CORES=%%i"
REM Détection de la mémoire RAM en GB
for /f "tokens=2 delims==" %%i in ('wmic OS get TotalVisibleMemorySize /value ^| find "TotalVisibleMemorySize"') do set "RAM_KB=%%i"
set /a "RAM_GB=%RAM_KB% / 1024 / 1024"
REM Configuration adaptative en fonction des ressources
set /a "NUM_THREADS=%CPU_CORES%"
if %NUM_THREADS% GTR 16 set "NUM_THREADS=16"
set /a "BATCH_SIZE=512"
if %RAM_GB% GTR 32 set /a "BATCH_SIZE=1024"
set /a "CTX_SIZE=8192"
if %RAM_GB% GTR 48 set /a "CTX_SIZE=16384"
echo {> "%USERPROFILE%\.ollama\config.json"
echo "gpu_layers": -1,>> "%USERPROFILE%\.ollama\config.json"
echo "num_ctx": %CTX_SIZE%,>> "%USERPROFILE%\.ollama\config.json"
echo "num_thread": %NUM_THREADS%,>> "%USERPROFILE%\.ollama\config.json"
echo "num_batch": %BATCH_SIZE%,>> "%USERPROFILE%\.ollama\config.json"
echo "num_gpu": 100>> "%USERPROFILE%\.ollama\config.json"
echo }>> "%USERPROFILE%\.ollama\config.json"
echo.
echo Configuration créée avec les paramètres suivants:
echo - Nombre de threads: %NUM_THREADS%
echo - Taille de contexte: %CTX_SIZE%
echo - Taille de batch: %BATCH_SIZE%
echo - Utilisation maximale du GPU
REM Redémarrer le service Ollama pour appliquer les changements
echo.
echo Redémarrage du service Ollama pour appliquer les paramètres...
net stop Ollama
timeout /t 3 /nobreak >nul
net start Ollama
echo.
echo Optimisation terminée! Ollama devrait maintenant fonctionner avec des performances optimales.
REM Test de connectivité
echo.
echo Test de la connexion à Ollama...
timeout /t 2 /nobreak >nul
curl -s http://localhost:11434/api/tags >nul 2>&1
if %errorLevel% EQU 0 (
echo Connexion réussie! Ollama est prêt à être utilisé.
) else (
echo Avertissement: Impossible de se connecter à Ollama.
echo Veuillez vérifier que le service est bien démarré.
)
endlocal

16
requirements.txt Normal file
View File

@ -0,0 +1,16 @@
requests>=2.28.0
psutil>=5.9.0
# Pour le serveur API
flask>=2.0.0
flask-cors>=3.0.10
# Pour le moniteur système et l'interface graphique
# Note: tkinter doit être installé au niveau du système
# - Linux: sudo apt install python3-tk
# - Windows: installer Python avec l'option tcl/tk cochée
# Dépendances pour Windows
# wmi>=1.5.1 # Pour accéder aux informations système sous Windows
# pywin32>=305 # Pour les fonctionnalités avancées Windows
# Dépendances optionnelles pour l'affichage GPU
# nvidia-ml-py>=11.495.46 # Pour NVIDIA GPU monitoring via NVML

69
run-api.ps1 Normal file
View File

@ -0,0 +1,69 @@
# Script PowerShell pour lancer le serveur API LLM Lab
Write-Host "=== Lancement du serveur API LLM Lab pour Cursor et Obsidian ===" -ForegroundColor Green
# Vérifier si l'environnement virtuel existe
if (-not (Test-Path -Path ".\llmlab")) {
Write-Host "L'environnement virtuel n'existe pas. Veuillez exécuter setup_env.bat pour le créer." -ForegroundColor Red
exit 1
}
# Activer l'environnement virtuel
Write-Host "Activation de l'environnement virtuel..." -ForegroundColor Cyan
try {
& .\llmlab\Scripts\Activate.ps1
} catch {
Write-Host "Erreur lors de l'activation de l'environnement virtuel: $_" -ForegroundColor Red
Write-Host "Tentative alternative d'activation..." -ForegroundColor Yellow
& cmd /c ".\llmlab\Scripts\activate.bat && powershell -NoExit"
exit 1
}
# Vérifier que Flask et Flask-CORS sont installés
Write-Host "Vérification des dépendances..." -ForegroundColor Cyan
$flaskInstalled = $false
$flaskCorsInstalled = $false
try {
$modules = pip list
$flaskInstalled = $modules -match "flask" -and $modules -notmatch "flask-cors"
$flaskCorsInstalled = $modules -match "flask-cors"
} catch {
Write-Host "Erreur lors de la vérification des modules: $_" -ForegroundColor Red
}
# Installer les dépendances manquantes
if (-not $flaskInstalled) {
Write-Host "Installation de Flask..." -ForegroundColor Yellow
pip install flask
}
if (-not $flaskCorsInstalled) {
Write-Host "Installation de Flask-CORS..." -ForegroundColor Yellow
pip install flask-cors
}
# Vérifier si Ollama est en cours d'exécution
Write-Host "Vérification qu'Ollama est en cours d'exécution..." -ForegroundColor Cyan
try {
$ollamaResponse = Invoke-WebRequest -Uri "http://localhost:11434/api/tags" -UseBasicParsing -ErrorAction SilentlyContinue
if ($ollamaResponse.StatusCode -eq 200) {
Write-Host "Ollama est en cours d'exécution." -ForegroundColor Green
} else {
Write-Host "Ollama semble ne pas fonctionner correctement." -ForegroundColor Yellow
}
} catch {
Write-Host "Impossible de se connecter à Ollama. Assurez-vous qu'il est en cours d'exécution." -ForegroundColor Red
Write-Host "Vous pouvez le télécharger depuis https://ollama.com/download/windows" -ForegroundColor Yellow
}
# Lancer le serveur API
Write-Host "`nLancement du serveur API..." -ForegroundColor Green
Write-Host "Utilisez Ctrl+C pour arrêter le serveur`n" -ForegroundColor Yellow
# Exécution du serveur
python api_server.py
# Ce code ne sera exécuté qu'après l'arrêt du serveur
Write-Host "`nServeur API arrêté." -ForegroundColor Cyan
Write-Host "Désactivation de l'environnement virtuel..." -ForegroundColor Cyan
deactivate

79
run.bat Normal file
View File

@ -0,0 +1,79 @@
@echo off
setlocal
REM Script pour exécuter les commandes dans l'environnement virtuel LLM Lab
REM Vérification si l'environnement virtuel existe
if not exist "llmlab" (
echo L'environnement virtuel n'existe pas. Veuillez exécuter setup_env.bat pour le créer.
exit /b 1
)
REM Activation de l'environnement virtuel
call llmlab\Scripts\activate.bat
REM Vérifier le premier argument
if "%1"=="" goto :help
if "%1"=="help" goto :help
if "%1"=="chat" goto :chat
if "%1"=="gui" goto :gui
if "%1"=="monitor" goto :monitor
if "%1"=="list" goto :list
if "%1"=="test" goto :test
if "%1"=="api" goto :api
echo Commande inconnue: %1
goto :help
:chat
if "%2"=="" (
python chat.py --list
) else (
python chat.py "%2"
)
goto :end
:gui
python chat_gui.py
goto :end
:monitor
python monitor.py
goto :end
:list
python chat.py --list
goto :end
:test
python -m unittest discover tests
goto :end
:api
echo Démarrage du serveur API sur http://localhost:8000...
echo Appuyez sur Ctrl+C pour arrêter le serveur.
python api_server.py
goto :end
:help
echo Usage: run.bat [commande] [arguments...]
echo.
echo Commandes disponibles:
echo chat [agent] Lance le chat en ligne de commande avec l'agent spécifié
echo gui Lance l'interface graphique de chat
echo monitor Lance le moniteur système
echo list Liste les agents disponibles
echo test Exécute les tests unitaires
echo api Lance le serveur API pour l'intégration avec Cursor/Obsidian
echo help Affiche cette aide
echo.
echo Exemples:
echo run.bat chat cursor Lance le chat en ligne de commande avec l'agent Cursor (CodeLlama)
echo run.bat gui Lance l'interface graphique de chat
echo run.bat monitor Lance le moniteur système
echo run.bat list Liste tous les agents disponibles
echo run.bat api Lance le serveur API sur le port 8000
goto :end
:end
call llmlab\Scripts\deactivate.bat
endlocal

107
setup_env.bat Normal file
View File

@ -0,0 +1,107 @@
@echo off
setlocal
REM Script de configuration de l'environnement virtuel LLM Lab pour Windows
REM Ce script crée un nouvel environnement virtuel et installe les dépendances requises
echo === Configuration de l'environnement LLM Lab ===
REM Vérification si Python 3 est installé
python --version > nul 2>&1
if %ERRORLEVEL% NEQ 0 (
echo Erreur: Python n'est pas installé. Veuillez l'installer avant de continuer.
echo Téléchargez Python depuis https://www.python.org/downloads/
exit /b 1
)
REM Vérification si pip est installé
pip --version > nul 2>&1
if %ERRORLEVEL% NEQ 0 (
echo Erreur: pip n'est pas installé. Veuillez vérifier votre installation Python.
exit /b 1
)
REM Vérification si venv est disponible
python -c "import venv" > nul 2>&1
if %ERRORLEVEL% NEQ 0 (
echo Erreur: Le module venv n'est pas disponible.
echo Réinstallez Python avec l'option "installer pip et venv" cochée.
exit /b 1
)
REM Vérification de l'installation de tkinter
python -c "import tkinter" > nul 2>&1
if %ERRORLEVEL% NEQ 0 (
echo Avertissement: Tkinter n'est pas installé.
echo Veuillez réinstaller Python en cochant l'option "tcl/tk and IDLE".
echo Voir: https://www.python.org/downloads/windows/
echo.
set /p continue="Continuer malgré tout? (o/n): "
if /i not "%continue%"=="o" exit /b 1
)
REM Suppression de l'ancien environnement s'il existe
if exist "llmlab" (
echo Suppression de l'ancien environnement virtuel...
rmdir /s /q llmlab
)
REM Création du nouvel environnement virtuel
echo Création d'un nouvel environnement virtuel...
python -m venv llmlab
REM Activation de l'environnement virtuel
echo Activation de l'environnement virtuel...
call llmlab\Scripts\activate
REM Mise à jour de pip
echo Mise à jour de pip...
python -m pip install --upgrade pip
REM Installation des dépendances
echo Installation des dépendances requises...
pip install -r requirements.txt
REM Ajout des dépendances spécifiques à Windows
echo Installation des dépendances Windows...
pip install wmi psutil requests pillow
REM Installation optionnelle de dépendances pour NVIDIA GPU
where nvidia-smi > nul 2>&1
if %ERRORLEVEL% EQU 0 (
echo NVIDIA GPU détecté, installation des dépendances NVIDIA...
pip install nvidia-ml-py
)
REM Vérification de l'exécution d'Ollama
curl -s http://localhost:11434/api/tags > nul 2>&1
if %ERRORLEVEL% NEQ 0 (
echo.
echo ATTENTION: Ollama ne semble pas être en cours d'exécution.
echo Veuillez installer et démarrer Ollama depuis https://ollama.com/download/windows
echo.
)
REM Création des dossiers nécessaires
if not exist "logs" mkdir logs
if not exist "chat_history" mkdir chat_history
REM Affichage du résumé
echo.
echo === Configuration terminée ===
echo Pour activer l'environnement virtuel, exécutez:
echo call llmlab\Scripts\activate
echo.
echo Pour lancer le moniteur système:
echo run.bat monitor
echo.
echo Pour utiliser un agent LLM:
echo run.bat chat [nom de l'agent]
echo.
echo Agents disponibles:
echo cursor - CodeLlama 13B Python (pour le code)
echo obsidian - Llama2 13B (pour la gestion des connaissances)
echo test - Mistral 7B (pour les tests rapides)
echo.
endlocal

85
setup_env.sh Normal file
View File

@ -0,0 +1,85 @@
#!/bin/bash
# Script de configuration de l'environnement virtuel LLM Lab
# Ce script crée un nouvel environnement virtuel et installe les dépendances requises
echo "=== Configuration de l'environnement LLM Lab ==="
# Vérification si Python 3 est installé
if ! command -v python3 &> /dev/null; then
echo "Erreur: Python 3 n'est pas installé. Veuillez l'installer avant de continuer."
exit 1
fi
# Vérification si pip est installé
if ! command -v pip3 &> /dev/null; then
echo "Erreur: pip3 n'est pas installé. Veuillez l'installer avant de continuer."
exit 1
fi
# Vérification si venv est disponible
python3 -c "import venv" &> /dev/null
if [ $? -ne 0 ]; then
echo "Le module venv n'est pas disponible. Installation en cours..."
sudo apt-get update
sudo apt-get install -y python3-venv
fi
# Vérification de l'installation de tkinter
python3 -c "import tkinter" &> /dev/null
if [ $? -ne 0 ]; then
echo "Tkinter n'est pas installé. Installation en cours..."
sudo apt-get update
sudo apt-get install -y python3-tk
fi
# Suppression de l'ancien environnement s'il existe
if [ -d "llmlab" ]; then
echo "Suppression de l'ancien environnement virtuel..."
rm -rf llmlab
fi
# Création du nouvel environnement virtuel
echo "Création d'un nouvel environnement virtuel..."
python3 -m venv llmlab
# Activation de l'environnement virtuel
echo "Activation de l'environnement virtuel..."
source llmlab/bin/activate
# Mise à jour de pip
echo "Mise à jour de pip..."
pip install --upgrade pip
# Installation des dépendances
echo "Installation des dépendances requises..."
pip install -r requirements.txt
# Installation optionnelle de dépendances pour NVIDIA GPU
if command -v nvidia-smi &> /dev/null; then
echo "NVIDIA GPU détecté, installation des dépendances NVIDIA..."
pip install nvidia-ml-py
fi
# Création de liens symboliques pour faciliter l'utilisation
echo "Création de liens symboliques pour les scripts..."
chmod +x chat.py
chmod +x monitor.py
# Affichage du résumé
echo ""
echo "=== Configuration terminée ==="
echo "Pour activer l'environnement virtuel, exécutez:"
echo " source llmlab/bin/activate"
echo ""
echo "Pour lancer le moniteur système:"
echo " ./monitor.py"
echo ""
echo "Pour utiliser un agent LLM:"
echo " ./chat.py [nom de l'agent]"
echo ""
echo "Agents disponibles:"
echo " cursor - CodeLlama 13B Python (pour le code)"
echo " obsidian - Llama2 13B (pour la gestion des connaissances)"
echo " test - Mistral 7B (pour les tests rapides)"
echo ""

98
test_installation.bat Normal file
View File

@ -0,0 +1,98 @@
@echo off
setlocal
echo ===== Test d'installation LLM Lab sur Windows 11 Pro =====
echo.
REM Activation de l'environnement virtuel si disponible
if exist llmlab\Scripts\activate (
call llmlab\Scripts\activate
) else (
echo Environnement virtuel non détecté, utilisation de Python système
)
REM Vérification de la version Python
python --version
if %ERRORLEVEL% NEQ 0 (
echo [ERREUR] Python n'est pas installé ou n'est pas dans le PATH
) else (
echo [OK] Python détecté
)
REM Vérification des modules requis
set MODULES=requests tkinter wmi psutil
for %%m in (%MODULES%) do (
python -c "import %%m" 2>nul
if %ERRORLEVEL% NEQ 0 (
echo [ERREUR] Module %%m non installé
) else (
echo [OK] Module %%m installé
)
)
REM Vérification de l'installation Ollama
curl -s http://localhost:11434/api/tags >nul 2>&1
if %ERRORLEVEL% NEQ 0 (
echo [ERREUR] Impossible de se connecter à Ollama
) else (
echo [OK] Connexion à Ollama réussie
REM Récupération des modèles installés
echo.
echo Modèles Ollama installés:
curl -s http://localhost:11434/api/tags | findstr "name"
)
REM Vérification du GPU NVIDIA
where nvidia-smi >nul 2>&1
if %ERRORLEVEL% NEQ 0 (
echo [INFO] NVIDIA GPU non détecté
) else (
echo [OK] NVIDIA GPU détecté
REM Affichage des informations GPU
echo.
echo Informations GPU:
nvidia-smi --query-gpu=name,driver_version,memory.total --format=csv,noheader
)
REM Vérification des fichiers de projet
echo.
echo Vérification des fichiers clés du projet:
set FILES=chat.py chat_gui.py monitor.py run.bat
for %%f in (%FILES%) do (
if exist %%f (
echo [OK] Fichier %%f trouvé
) else (
echo [ERREUR] Fichier %%f manquant
)
)
REM Vérification des dossiers requis
echo.
echo Vérification des dossiers:
set DIRS=logs chat_history agents core utils
for %%d in (%DIRS%) do (
if exist %%d (
echo [OK] Dossier %%d trouvé
) else (
echo [ERREUR] Dossier %%d manquant
)
)
REM Récapitulatif
echo.
echo ===== Récapitulatif =====
echo.
echo Si tous les tests sont [OK], le système est correctement configuré.
echo.
echo Pour optimiser Ollama, exécutez optimize_ollama.bat en tant qu'administrateur.
echo Pour lancer LLM Lab, utilisez run.bat gui ou run.bat chat [agent]
echo.
REM Désactivation de l'environnement virtuel si nécessaire
if exist llmlab\Scripts\activate (
deactivate
)
endlocal

View File

@ -0,0 +1,18 @@
#Tester plusieurs agents avec les mêmes paramètres
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from core.factory import LLMFactory
from utils.parameter_tester import test_agents_on_prompt
test_agents_on_prompt(
model_class=LLMFactory._registry["mistral7b"],
prompt="Explique ce qu'est le machine learning.",
agents=["formateur", "chercheur", "assistant_technique"],
param_grid={},
fixed_params={
"temperature": 1.5,
"top_p": 0.9,
"num_predict": 300
}
)

View File

@ -0,0 +1,19 @@
# Tester plusieurs agents avec des combinations automatiques
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from core.factory import LLMFactory
from utils.parameter_tester import test_agents_on_prompt
test_agents_on_prompt(
model_class=LLMFactory._registry["mistral7b"],
prompt="Décris le fonctionnement du protocole HTTP.",
agents=["formateur", "assistant_technique"],
param_grid={
"temperature": [0.5, 1.0, 1.5],
"top_p": [0.5, 0.9, 1.0],
},
fixed_params={
"num_predict": 300
}
)

34
tests/test_new_models.py Normal file
View File

@ -0,0 +1,34 @@
from core.factory import LLMFactory
def test_all_models():
"""Test simple de tous les modèles disponibles"""
# Liste des modèles à tester
model_names = ["mistral7b", "codellama13b-python", "llama2-13b"]
for model_name in model_names:
print(f"\nTest du modèle {model_name}:")
try:
# Instanciation du modèle via la factory
model = LLMFactory.create(model_name)
print(f"✓ Modèle {model_name} instancié avec succès")
# Test des attributs basiques
assert model.model is not None, "Le nom du modèle est None"
assert model.engine is not None, "Le moteur du modèle est None"
print(f"✓ Attributs du modèle {model_name} vérifiés")
# Test d'accès aux paramètres
assert model.params is not None, "Les paramètres sont None"
assert "temperature" in model.params, "Le paramètre temperature n'est pas défini"
print(f"✓ Paramètres du modèle {model_name} vérifiés")
# Affichage des informations du modèle
print(f" - Nom du modèle: {model.model}")
print(f" - Moteur: {model.engine}")
print(f" - Température: {model.params.get('temperature')}")
except Exception as e:
print(f"✗ Erreur avec le modèle {model_name}: {str(e)}")
if __name__ == "__main__":
test_all_models()

View File

@ -0,0 +1,13 @@
# Tester un seul agent avec un seul prompt, sans variation
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from utils.agent_manager import AgentManager
# Utilisation de l'AgentManager pour créer l'agent avec le modèle approprié
agent = AgentManager.create("test") # Utilise l'agent "test" qui est configuré avec Mistral7B
print(f"Test de l'agent '{agent.agent}' avec le modèle '{agent.model}'")
response = agent.generate("Qu'est-ce qu'une API REST?")
print("-> Réponse générée.")

View File

@ -0,0 +1,19 @@
# Tester un seul agent, avec des paramètres qui varient
import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))
from core.factory import LLMFactory
from utils.parameter_tester import test_agents_on_prompt
test_agents_on_prompt(
model_class=LLMFactory._registry["mistral7b"],
prompt="Donne une définition claire de l'intelligence artificielle.",
agents=["juriste"],
param_grid={
"temperature": [0.1, 0.5, 1.0],
"top_p": [0.7, 0.9]
},
fixed_params={
"num_predict": 256
}
)

View File

@ -0,0 +1,292 @@
# Adaptation du moniteur système pour le nouvel emplacement Ollama
Ce guide explique comment modifier le moniteur système de LLM Lab pour qu'il détecte et affiche correctement l'emplacement des modèles Ollama sur un disque séparé.
## 1. Modifications nécessaires dans system_monitor.py
Ouvrez le fichier `system_monitor.py` et apportez les modifications suivantes pour détecter l'emplacement des modèles Ollama sur un disque séparé.
### Fonction de détection du chemin des modèles
Ajoutez cette nouvelle fonction au début de la classe `SystemMonitor`:
```python
def _get_ollama_models_path(self):
"""Détecte l'emplacement des modèles Ollama"""
models_path = None
# Vérifier si la variable d'environnement est définie
if 'OLLAMA_MODELS' in os.environ:
models_path = os.environ['OLLAMA_MODELS']
self._log(f"Chemin des modèles Ollama trouvé via variable d'environnement: {models_path}")
return models_path
# Vérifier le chemin par défaut
default_path = os.path.expanduser(os.path.join("~", ".ollama", "models"))
if platform.system() == "Windows":
# Vérifier si c'est un lien symbolique sous Windows
try:
import subprocess
result = subprocess.run(['dir', '/al', default_path],
shell=True, capture_output=True, text=True)
if "<SYMLINK>" in result.stdout:
# Extraire la cible du lien symbolique
for line in result.stdout.splitlines():
if "<SYMLINK>" in line and "[" in line and "]" in line:
target = line.split("[")[1].split("]")[0]
models_path = target
self._log(f"Lien symbolique détecté pour les modèles Ollama: {models_path}")
return models_path
except:
pass
# Si aucune redirection n'est trouvée, utiliser le chemin par défaut
if os.path.exists(default_path):
models_path = default_path
return models_path or default_path
```
### Afficher l'emplacement des modèles dans l'interface
Modifiez la méthode `_create_widgets` pour ajouter un affichage de l'emplacement des modèles dans l'onglet Ollama:
```python
# Dans _create_widgets, après la création de url_frame
models_path_frame = ttk.Frame(server_frame)
models_path_frame.pack(fill=tk.X, padx=5, pady=2)
ttk.Label(models_path_frame, text="Modèles:").pack(side=tk.LEFT, padx=5)
self.models_path_label = ttk.Label(models_path_frame, text="Vérification...")
self.models_path_label.pack(side=tk.LEFT, padx=5)
```
### Mettre à jour l'information dans _update_ollama_info
Ajoutez ce code au début de la méthode `_update_ollama_info`:
```python
# Mettre à jour l'emplacement des modèles
models_path = self._get_ollama_models_path()
self.models_path_label.config(text=models_path)
# Vérifier l'espace disque pour les modèles
if models_path and os.path.exists(models_path):
try:
import shutil
total, used, free = shutil.disk_usage(os.path.dirname(models_path))
total_gb = total / (1024**3)
used_gb = used / (1024**3)
free_gb = free / (1024**3)
disk_info = f"{models_path} ({free_gb:.1f} GB libres / {total_gb:.1f} GB)"
self.models_path_label.config(text=disk_info)
# Afficher un avertissement si l'espace libre est faible
if free_gb < 10: # Moins de 10 GB libres
self.models_path_label.config(foreground="orange")
self._log(f"Avertissement: espace disque limité pour les modèles: {free_gb:.1f} GB")
elif free_gb < 5: # Moins de 5 GB libres
self.models_path_label.config(foreground="red")
self._log(f"Alerte: espace disque très limité pour les modèles: {free_gb:.1f} GB")
else:
self.models_path_label.config(foreground="green")
except Exception as e:
self._log(f"Erreur lors de la vérification de l'espace disque: {str(e)}")
```
## 2. Ajout d'un onglet d'information sur les disques
Pour un monitoring plus complet, ajoutez un nouvel onglet dédié à l'affichage de l'état des disques:
```python
# Dans _create_widgets, après la création de logs_frame
# Onglet 5: Disques
self.disks_frame = ttk.Frame(self.notebook)
self.notebook.add(self.disks_frame, text="Disques")
# Configuration de l'onglet Disques
disks_label = ttk.Label(self.disks_frame, text="Stockage", font=("Arial", 14, "bold"))
disks_label.pack(pady=10)
# Tableau des disques
disks_table_frame = ttk.LabelFrame(self.disks_frame, text="Volumes")
disks_table_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
self.disks_tree = ttk.Treeview(disks_table_frame,
columns=("Lettre", "Total", "Utilisé", "Libre", "Type"),
show='headings')
self.disks_tree.heading("Lettre", text="Disque")
self.disks_tree.heading("Total", text="Taille")
self.disks_tree.heading("Utilisé", text="Utilisé")
self.disks_tree.heading("Libre", text="Libre")
self.disks_tree.heading("Type", text="Type")
self.disks_tree.column("Lettre", width=70)
self.disks_tree.column("Total", width=100)
self.disks_tree.column("Utilisé", width=100)
self.disks_tree.column("Libre", width=100)
self.disks_tree.column("Type", width=150)
self.disks_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
```
### Ajouter une méthode pour mettre à jour les informations de disque
```python
def _update_disks_info(self):
"""Met à jour les informations sur les disques"""
try:
# Effacer le tableau
for item in self.disks_tree.get_children():
self.disks_tree.delete(item)
if platform.system() == "Windows":
# Obtenir la liste des lecteurs
import string
import ctypes
drives = []
bitmask = ctypes.windll.kernel32.GetLogicalDrives()
for letter in string.ascii_uppercase:
if bitmask & 1:
drives.append(f"{letter}:")
bitmask >>= 1
# Pour chaque lecteur, obtenir les informations
for drive in drives:
try:
total, used, free = shutil.disk_usage(drive)
total_gb = total / (1024**3)
used_gb = used / (1024**3)
free_gb = free / (1024**3)
# Déterminer le type de disque
drive_type = ctypes.windll.kernel32.GetDriveTypeW(drive)
types = {
0: "Inconnu",
1: "Inexistant",
2: "Amovible",
3: "Fixe",
4: "Réseau",
5: "CD-ROM",
6: "RAM Disk"
}
drive_type_str = types.get(drive_type, "Inconnu")
# Ajouter au tableau
percent = (used / total) * 100 if total > 0 else 0
# Couleur selon l'espace libre
if percent > 90:
tag = "critical"
elif percent > 75:
tag = "warning"
else:
tag = ""
self.disks_tree.insert("", tk.END,
values=(drive,
f"{total_gb:.1f} GB",
f"{used_gb:.1f} GB ({percent:.1f}%)",
f"{free_gb:.1f} GB",
drive_type_str),
tags=(tag,))
# Vérifier si c'est le disque des modèles Ollama
models_path = self._get_ollama_models_path()
if models_path and drive in models_path:
self._log(f"Disque des modèles Ollama: {drive} - {free_gb:.1f} GB libres")
except Exception as e:
self.disks_tree.insert("", tk.END,
values=(drive, "Erreur", "Erreur", "Erreur", str(e)),
tags=("error",))
# Configurer les couleurs
self.disks_tree.tag_configure("critical", background="#ffcccc")
self.disks_tree.tag_configure("warning", background="#ffffcc")
self.disks_tree.tag_configure("error", background="#ff9999")
else:
# Code pour Linux/Mac
# Utiliser psutil.disk_partitions() pour lister les partitions
for part in psutil.disk_partitions(all=False):
try:
usage = psutil.disk_usage(part.mountpoint)
total_gb = usage.total / (1024**3)
used_gb = usage.used / (1024**3)
free_gb = usage.free / (1024**3)
# Ajouter au tableau
self.disks_tree.insert("", tk.END,
values=(part.mountpoint,
f"{total_gb:.1f} GB",
f"{used_gb:.1f} GB ({usage.percent}%)",
f"{free_gb:.1f} GB",
f"{part.fstype}"))
except Exception as e:
pass
except Exception as e:
self._log(f"Erreur lors de la mise à jour des informations disque: {str(e)}")
```
### Ajouter l'appel à la nouvelle méthode dans _update_loop
Ajoutez cet appel dans la méthode `_update_loop` pour mettre à jour les informations disque régulièrement:
```python
# Dans _update_loop
self._update_system_info()
self._update_ollama_info()
self._update_gpu_info()
self._update_disks_info() # Ajouter cette ligne
```
## 3. Test de la mise à jour
Pour tester ces modifications:
1. Appliquez les changements au fichier system_monitor.py
2. Redémarrez le moniteur système
3. Vérifiez que le chemin des modèles Ollama est correctement affiché
4. Assurez-vous que l'espace disque est correctement détecté
5. Testez avec différentes configurations (variable d'environnement, lien symbolique)
## 4. Intégration avec le reste de LLM Lab
Modifiez les autres fichiers qui pourraient avoir besoin de connaître l'emplacement des modèles:
### Ajouter une fonction utilitaire dans utils/ollama_utils.py
```python
def get_ollama_models_path():
"""Détecte l'emplacement des modèles Ollama de manière cohérente dans tout le projet"""
# Vérifier la variable d'environnement
if 'OLLAMA_MODELS' in os.environ:
return os.environ['OLLAMA_MODELS']
# Vérifier si c'est un lien symbolique sous Windows
default_path = os.path.expanduser(os.path.join("~", ".ollama", "models"))
if platform.system() == "Windows":
try:
import subprocess
result = subprocess.run(['dir', '/al', default_path],
shell=True, capture_output=True, text=True)
if "<SYMLINK>" in result.stdout:
for line in result.stdout.splitlines():
if "<SYMLINK>" in line and "[" in line and "]" in line:
return line.split("[")[1].split("]")[0]
except:
pass
return default_path
```
Utilisez cette fonction dans les autres parties du code qui ont besoin de connaître l'emplacement des modèles.
## Utilisation dans l'interface graphique
Ces modifications permettront à l'utilisateur de voir clairement où sont stockés les modèles Ollama et de surveiller l'espace disque disponible pour éviter les problèmes lors du téléchargement de nouveaux modèles.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

59
utils/agent_manager.py Normal file
View File

@ -0,0 +1,59 @@
"""
Gestionnaire d'agents permettant la création d'agents spécifiques avec leurs modèles associés
"""
from core.factory import LLMFactory
from agents.roles import AGENTS
class AgentManager:
"""
Classe utilitaire pour créer et configurer des agents avec leurs modèles associés
"""
@staticmethod
def create(agent_name):
"""
Crée et configure un agent avec le modèle approprié
Args:
agent_name (str): Nom de l'agent à créer
Returns:
BaseLLM: Instance du modèle configurée avec le rôle de l'agent
Raises:
ValueError: Si l'agent n'existe pas
"""
if agent_name not in AGENTS:
raise ValueError(f"Agent inconnu: {agent_name}")
agent_config = AGENTS[agent_name]
# Sélectionner le modèle spécifié pour l'agent ou utiliser mistral7b par défaut
model_name = agent_config.get("model", "mistral7b")
# Créer le modèle
model = LLMFactory.create(model_name)
# Appliquer la configuration de l'agent
model.set_role(agent_name, agent_config)
return model
@staticmethod
def list_agents():
"""
Liste tous les agents disponibles avec leurs modèles associés
Returns:
dict: Dictionnaire des agents et leurs modèles associés
"""
agents_info = {}
for agent_name, config in AGENTS.items():
model = config.get("model", "mistral7b")
agents_info[agent_name] = {
"model": model,
"description": config.get("system_prompt", "")[:50] + "..." if len(config.get("system_prompt", "")) > 50 else config.get("system_prompt", "")
}
return agents_info

980
utils/chat_ui.py Normal file
View File

@ -0,0 +1,980 @@
"""
Interface graphique pour le chat avec les modèles LLM
"""
import tkinter as tk
from tkinter import ttk, scrolledtext, messagebox, filedialog
import json
import os
from datetime import datetime
from utils.agent_manager import AgentManager
from core.factory import LLMFactory
class ChatUI:
"""Interface graphique pour interagir avec les agents LLM"""
def __init__(self, root):
"""Initialise l'interface graphique"""
self.root = root
self.root.title("LLM Lab - Chat")
self.root.geometry("1000x700")
self.root.minsize(800, 600)
# Variables pour le chat
self.current_agent = None
self.conversation_history = []
self.custom_params = {}
self.history_files = []
# Style
self.style = ttk.Style()
self.style.theme_use('alt') # 'clam', 'alt', 'default', 'classic'
# Création de l'interface
self._create_ui()
# Chargement de la liste des agents
self._load_agents()
# Chargement de l'historique des conversations
self._load_conversation_history()
def _create_ui(self):
"""Crée l'interface utilisateur"""
# Interface principale en deux parties
self.main_paned = ttk.PanedWindow(self.root, orient=tk.HORIZONTAL)
self.main_paned.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# Panneau de gauche : configuration et historique
self.left_frame = ttk.Frame(self.main_paned, width=300)
self.main_paned.add(self.left_frame, weight=1)
# Panneau de droite : chat
self.right_frame = ttk.Frame(self.main_paned)
self.main_paned.add(self.right_frame, weight=3)
# Configuration du panneau de gauche
self._create_config_panel()
# Configuration du panneau de droite
self._create_chat_panel()
def _create_config_panel(self):
"""Crée le panneau de configuration (gauche)"""
# Utilisation d'un notebook pour organiser les paramètres
self.config_notebook = ttk.Notebook(self.left_frame)
self.config_notebook.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# Onglet 1: Sélection d'agent
self.agent_frame = ttk.Frame(self.config_notebook)
self.config_notebook.add(self.agent_frame, text="Agent")
# Onglet 2: Paramètres
self.params_frame = ttk.Frame(self.config_notebook)
self.config_notebook.add(self.params_frame, text="Paramètres")
# Onglet 3: Historique
self.history_frame = ttk.Frame(self.config_notebook)
self.config_notebook.add(self.history_frame, text="Historique")
# Remplissage de l'onglet Agent
self._create_agent_tab()
# Remplissage de l'onglet Paramètres
self._create_params_tab()
# Remplissage de l'onglet Historique
self._create_history_tab()
def _create_agent_tab(self):
"""Crée l'onglet de sélection d'agent"""
# Label et liste des agents
ttk.Label(self.agent_frame, text="Sélectionnez un agent:",
font=("Arial", 11, "bold")).pack(pady=(10, 5), padx=5, anchor=tk.W)
# Frame pour la liste des agents
agent_list_frame = ttk.Frame(self.agent_frame)
agent_list_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# Scrollbar
scrollbar = ttk.Scrollbar(agent_list_frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# Liste des agents
self.agent_listbox = tk.Listbox(agent_list_frame, yscrollcommand=scrollbar.set,
selectmode=tk.SINGLE, activestyle='dotbox',
font=("Arial", 10))
self.agent_listbox.pack(fill=tk.BOTH, expand=True)
scrollbar.config(command=self.agent_listbox.yview)
# Gestionnaire d'événements pour la sélection d'agent
self.agent_listbox.bind('<<ListboxSelect>>', self._on_agent_select)
# Informations sur l'agent
agent_info_frame = ttk.LabelFrame(self.agent_frame, text="Informations sur l'agent")
agent_info_frame.pack(fill=tk.X, padx=5, pady=5)
# Description de l'agent
ttk.Label(agent_info_frame, text="Description:").pack(anchor=tk.W, padx=5, pady=(5, 0))
self.agent_description = tk.Text(agent_info_frame, wrap=tk.WORD, height=5,
width=30, font=("Arial", 9))
self.agent_description.pack(fill=tk.X, padx=5, pady=5)
self.agent_description.config(state=tk.DISABLED)
# Modèle utilisé
model_frame = ttk.Frame(agent_info_frame)
model_frame.pack(fill=tk.X, padx=5, pady=(0, 5))
ttk.Label(model_frame, text="Modèle:").pack(side=tk.LEFT, padx=(0, 5))
self.model_label = ttk.Label(model_frame, text="-")
self.model_label.pack(side=tk.LEFT)
# Bouton pour changer de modèle
self.model_combo = ttk.Combobox(self.agent_frame, state="readonly")
self.model_combo.pack(fill=tk.X, padx=5, pady=5)
# Événement de changement
self.model_combo.bind("<<ComboboxSelected>>", self._on_model_change)
# Bouton de test
test_btn = ttk.Button(self.agent_frame, text="Tester l'agent",
command=self._test_agent)
test_btn.pack(fill=tk.X, padx=5, pady=(0, 10))
def _create_params_tab(self):
"""Crée l'onglet de configuration des paramètres"""
# Canvas et scrollbar pour permettre le défilement
canvas = tk.Canvas(self.params_frame)
scrollbar = ttk.Scrollbar(self.params_frame, orient="vertical", command=canvas.yview)
scroll_frame = ttk.Frame(canvas)
scroll_frame.bind(
"<Configure>",
lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
)
canvas.create_window((0, 0), window=scroll_frame, anchor="nw")
canvas.configure(yscrollcommand=scrollbar.set)
canvas.pack(side="left", fill="both", expand=True)
scrollbar.pack(side="right", fill="y")
# Titre
ttk.Label(scroll_frame, text="Paramètres du modèle:",
font=("Arial", 11, "bold")).pack(pady=(10, 5), padx=5, anchor=tk.W)
# Température
temp_frame = ttk.Frame(scroll_frame)
temp_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(temp_frame, text="Température:").pack(side=tk.LEFT, padx=(0, 5))
self.temp_var = tk.DoubleVar(value=0.7)
temp_scale = ttk.Scale(temp_frame, from_=0.0, to=2.0, orient=tk.HORIZONTAL,
variable=self.temp_var, length=150)
temp_scale.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
temp_label = ttk.Label(temp_frame, textvariable=self.temp_var, width=5)
temp_label.pack(side=tk.LEFT)
self.temp_var.trace_add("write", self._on_param_change)
# Top-p
top_p_frame = ttk.Frame(scroll_frame)
top_p_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(top_p_frame, text="Top-p:").pack(side=tk.LEFT, padx=(0, 5))
self.top_p_var = tk.DoubleVar(value=0.9)
top_p_scale = ttk.Scale(top_p_frame, from_=0.0, to=1.0, orient=tk.HORIZONTAL,
variable=self.top_p_var, length=150)
top_p_scale.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
top_p_label = ttk.Label(top_p_frame, textvariable=self.top_p_var, width=5)
top_p_label.pack(side=tk.LEFT)
self.top_p_var.trace_add("write", self._on_param_change)
# Top-k
top_k_frame = ttk.Frame(scroll_frame)
top_k_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(top_k_frame, text="Top-k:").pack(side=tk.LEFT, padx=(0, 5))
self.top_k_var = tk.IntVar(value=40)
top_k_scale = ttk.Scale(top_k_frame, from_=0, to=100, orient=tk.HORIZONTAL,
variable=self.top_k_var, length=150)
top_k_scale.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
top_k_label = ttk.Label(top_k_frame, textvariable=self.top_k_var, width=5)
top_k_label.pack(side=tk.LEFT)
self.top_k_var.trace_add("write", self._on_param_change)
# Repeat penalty
repeat_frame = ttk.Frame(scroll_frame)
repeat_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(repeat_frame, text="Repeat Penalty:").pack(side=tk.LEFT, padx=(0, 5))
self.repeat_var = tk.DoubleVar(value=1.1)
repeat_scale = ttk.Scale(repeat_frame, from_=1.0, to=2.0, orient=tk.HORIZONTAL,
variable=self.repeat_var, length=150)
repeat_scale.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
repeat_label = ttk.Label(repeat_frame, textvariable=self.repeat_var, width=5)
repeat_label.pack(side=tk.LEFT)
self.repeat_var.trace_add("write", self._on_param_change)
# Tokens max
tokens_frame = ttk.Frame(scroll_frame)
tokens_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(tokens_frame, text="Tokens max:").pack(side=tk.LEFT, padx=(0, 5))
self.tokens_var = tk.IntVar(value=512)
tokens_scale = ttk.Scale(tokens_frame, from_=32, to=4096, orient=tk.HORIZONTAL,
variable=self.tokens_var, length=150)
tokens_scale.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
tokens_label = ttk.Label(tokens_frame, textvariable=self.tokens_var, width=5)
tokens_label.pack(side=tk.LEFT)
self.tokens_var.trace_add("write", self._on_param_change)
# Boutons de gestion
buttons_frame = ttk.Frame(scroll_frame)
buttons_frame.pack(fill=tk.X, padx=5, pady=10)
self.reset_btn = ttk.Button(buttons_frame, text="Réinitialiser",
command=self._reset_params)
self.reset_btn.pack(side=tk.LEFT, padx=(0, 5))
self.save_btn = ttk.Button(buttons_frame, text="Enregistrer",
command=self._save_params)
self.save_btn.pack(side=tk.LEFT)
# Séparateur
ttk.Separator(scroll_frame, orient=tk.HORIZONTAL).pack(fill=tk.X, padx=5, pady=10)
# Système de presets
ttk.Label(scroll_frame, text="Presets:",
font=("Arial", 11, "bold")).pack(pady=(5, 5), padx=5, anchor=tk.W)
presets_frame = ttk.Frame(scroll_frame)
presets_frame.pack(fill=tk.X, padx=5, pady=5)
self.preset_combo = ttk.Combobox(presets_frame, values=[
"Créatif", "Précis", "Équilibré", "Code", "Conversation"
])
self.preset_combo.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
self.preset_combo.current(2) # Par défaut: Équilibré
self.apply_preset_btn = ttk.Button(presets_frame, text="Appliquer",
command=self._apply_preset)
self.apply_preset_btn.pack(side=tk.LEFT)
def _create_history_tab(self):
"""Crée l'onglet d'historique des conversations"""
# Label
ttk.Label(self.history_frame, text="Historique des conversations:",
font=("Arial", 11, "bold")).pack(pady=(10, 5), padx=5, anchor=tk.W)
# Liste des conversations
history_list_frame = ttk.Frame(self.history_frame)
history_list_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
scrollbar = ttk.Scrollbar(history_list_frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.history_listbox = tk.Listbox(history_list_frame, yscrollcommand=scrollbar.set,
font=("Arial", 10))
self.history_listbox.pack(fill=tk.BOTH, expand=True)
scrollbar.config(command=self.history_listbox.yview)
# Événement de sélection
self.history_listbox.bind('<<ListboxSelect>>', self._on_history_select)
# Boutons
button_frame = ttk.Frame(self.history_frame)
button_frame.pack(fill=tk.X, padx=5, pady=(0, 10))
self.load_history_btn = ttk.Button(button_frame, text="Charger",
command=self._load_selected_history)
self.load_history_btn.pack(side=tk.LEFT, padx=(0, 5))
self.delete_history_btn = ttk.Button(button_frame, text="Supprimer",
command=self._delete_history)
self.delete_history_btn.pack(side=tk.LEFT, padx=(0, 5))
self.export_history_btn = ttk.Button(button_frame, text="Exporter",
command=self._export_history)
self.export_history_btn.pack(side=tk.LEFT)
def _create_chat_panel(self):
"""Crée le panneau de chat (droite)"""
# Titre
chat_title_frame = ttk.Frame(self.right_frame)
chat_title_frame.pack(fill=tk.X, padx=5, pady=5)
self.chat_title = ttk.Label(chat_title_frame, text="Chat - Aucun agent sélectionné",
font=("Arial", 12, "bold"))
self.chat_title.pack(side=tk.LEFT)
# Zone de chat
chat_frame = ttk.Frame(self.right_frame)
chat_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# Zone d'affichage des messages
self.chat_display = scrolledtext.ScrolledText(chat_frame, wrap=tk.WORD,
font=("Arial", 10))
self.chat_display.pack(fill=tk.BOTH, expand=True)
self.chat_display.config(state=tk.DISABLED)
# Zone de saisie
input_frame = ttk.Frame(self.right_frame)
input_frame.pack(fill=tk.X, padx=5, pady=(0, 5))
self.user_input = scrolledtext.ScrolledText(input_frame, wrap=tk.WORD,
height=3, font=("Arial", 10))
self.user_input.pack(fill=tk.X, pady=(0, 5))
self.user_input.bind("<Shift-Return>", self._on_shift_enter)
# Boutons d'action
button_frame = ttk.Frame(self.right_frame)
button_frame.pack(fill=tk.X, padx=5, pady=(0, 5))
self.send_btn = ttk.Button(button_frame, text="Envoyer", width=10,
command=self._send_message)
self.send_btn.pack(side=tk.RIGHT, padx=(5, 0))
self.clear_btn = ttk.Button(button_frame, text="Effacer", width=10,
command=self._clear_chat)
self.clear_btn.pack(side=tk.RIGHT, padx=(5, 0))
self.new_chat_btn = ttk.Button(button_frame, text="Nouvelle conversation", width=20,
command=self._new_chat)
self.new_chat_btn.pack(side=tk.RIGHT)
# Barre d'état
self.status_bar = ttk.Label(self.right_frame, text="Prêt", relief=tk.SUNKEN, anchor=tk.W)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
def _load_agents(self):
"""Charge la liste des agents disponibles"""
# Effacer la liste actuelle
self.agent_listbox.delete(0, tk.END)
# Récupérer les agents
agents_info = AgentManager.list_agents()
# Ajouter les agents à la liste
for agent_name in agents_info:
self.agent_listbox.insert(tk.END, agent_name)
# Charger la liste des modèles disponibles
self._load_models()
def _load_models(self):
"""Charge la liste des modèles disponibles"""
try:
# Récupérer les modèles disponibles
models = LLMFactory.get_available_models()
self.model_combo['values'] = models
except Exception as e:
print(f"Erreur lors du chargement des modèles: {str(e)}")
self.model_combo['values'] = ["mistral:latest", "codellama:13b-python", "llama2:13b"]
def _on_agent_select(self, event):
"""Gestionnaire d'événement pour la sélection d'un agent"""
# Récupérer l'index sélectionné
selection = self.agent_listbox.curselection()
if not selection:
return
# Récupérer le nom de l'agent
agent_name = self.agent_listbox.get(selection[0])
# Récupérer les informations de l'agent
agents_info = AgentManager.list_agents()
if agent_name not in agents_info:
return
agent_info = agents_info[agent_name]
# Mettre à jour les informations affichées
self.agent_description.config(state=tk.NORMAL)
self.agent_description.delete(1.0, tk.END)
self.agent_description.insert(tk.END, agent_info['description'])
self.agent_description.config(state=tk.DISABLED)
# Mettre à jour le modèle
model_name = agent_info['model']
self.model_label.config(text=model_name)
# Sélectionner le modèle dans la combobox
if model_name in self.model_combo['values']:
self.model_combo.set(model_name)
# Mettre à jour le titre du chat
self.chat_title.config(text=f"Chat avec {agent_name} ({model_name})")
# Mettre à jour l'agent courant
self.current_agent = agent_name
# Charger les paramètres de l'agent
self._load_agent_params(agent_name)
# Mettre à jour le statut
self.status_bar.config(text=f"Agent {agent_name} sélectionné avec le modèle {model_name}")
def _on_model_change(self, event):
"""Gestionnaire d'événement pour le changement de modèle"""
if not self.current_agent:
messagebox.showwarning("Aucun agent sélectionné",
"Veuillez d'abord sélectionner un agent.")
return
# Récupérer le modèle sélectionné
model_name = self.model_combo.get()
# Mettre à jour l'affichage
self.model_label.config(text=model_name)
# Mettre à jour le titre du chat
self.chat_title.config(text=f"Chat avec {self.current_agent} ({model_name})")
# Mettre à jour les paramètres du modèle
self._load_model_params(model_name)
# Mettre à jour le statut
self.status_bar.config(text=f"Modèle changé pour {model_name}")
def _test_agent(self):
"""Fonction de test rapide de l'agent sélectionné"""
if not self.current_agent:
messagebox.showwarning("Aucun agent sélectionné",
"Veuillez d'abord sélectionner un agent.")
return
# Message de test
test_message = "Présente-toi brièvement et explique tes capacités."
# Ajouter le message au chat
self._add_message_to_chat("Utilisateur", test_message)
# Générer une réponse
try:
# Mettre à jour le statut
self.status_bar.config(text=f"Génération en cours...")
self.root.update()
# Créer l'agent avec les paramètres personnalisés
agent = self._create_agent_with_custom_params()
# Générer la réponse
response = agent.generate(test_message)
# Ajouter la réponse au chat
self._add_message_to_chat(self.current_agent, response)
# Mettre à jour le statut
self.status_bar.config(text=f"Test terminé")
except Exception as e:
messagebox.showerror("Erreur", f"Erreur lors du test de l'agent: {str(e)}")
self.status_bar.config(text=f"Erreur lors du test")
def _on_param_change(self, *args):
"""Gestionnaire d'événement pour le changement des paramètres"""
if not self.current_agent:
return
# Mettre à jour les paramètres personnalisés
self.custom_params = {
"temperature": self.temp_var.get(),
"top_p": self.top_p_var.get(),
"top_k": self.top_k_var.get(),
"repeat_penalty": self.repeat_var.get(),
"num_predict": self.tokens_var.get()
}
def _reset_params(self):
"""Réinitialise les paramètres aux valeurs par défaut de l'agent"""
if not self.current_agent:
messagebox.showwarning("Aucun agent sélectionné",
"Veuillez d'abord sélectionner un agent.")
return
# Charger les paramètres de l'agent
self._load_agent_params(self.current_agent)
# Mettre à jour le statut
self.status_bar.config(text=f"Paramètres réinitialisés")
def _save_params(self):
"""Enregistre les paramètres personnalisés"""
if not self.current_agent:
messagebox.showwarning("Aucun agent sélectionné",
"Veuillez d'abord sélectionner un agent.")
return
# Créer le dossier de sauvegarde si nécessaire
save_dir = "saved_params"
os.makedirs(save_dir, exist_ok=True)
# Nom du fichier de sauvegarde
file_name = f"{save_dir}/{self.current_agent}_{self.model_combo.get()}.json"
# Enregistrer les paramètres
with open(file_name, "w") as f:
json.dump(self.custom_params, f, indent=2)
# Mettre à jour le statut
self.status_bar.config(text=f"Paramètres enregistrés dans {file_name}")
def _apply_preset(self):
"""Applique un preset de paramètres"""
preset = self.preset_combo.get()
# Définir les presets
presets = {
"Créatif": {
"temperature": 1.2,
"top_p": 0.95,
"top_k": 60,
"repeat_penalty": 1.0,
"num_predict": 1024
},
"Précis": {
"temperature": 0.3,
"top_p": 0.85,
"top_k": 30,
"repeat_penalty": 1.2,
"num_predict": 512
},
"Équilibré": {
"temperature": 0.7,
"top_p": 0.9,
"top_k": 40,
"repeat_penalty": 1.1,
"num_predict": 768
},
"Code": {
"temperature": 0.2,
"top_p": 0.95,
"top_k": 30,
"repeat_penalty": 1.2,
"num_predict": 2048
},
"Conversation": {
"temperature": 0.8,
"top_p": 0.92,
"top_k": 50,
"repeat_penalty": 1.05,
"num_predict": 512
}
}
# Appliquer le preset
if preset in presets:
params = presets[preset]
# Mettre à jour les variables
self.temp_var.set(params["temperature"])
self.top_p_var.set(params["top_p"])
self.top_k_var.set(params["top_k"])
self.repeat_var.set(params["repeat_penalty"])
self.tokens_var.set(params["num_predict"])
# Mettre à jour les paramètres personnalisés
self.custom_params = params.copy()
# Mettre à jour le statut
self.status_bar.config(text=f"Preset '{preset}' appliqué")
def _load_agent_params(self, agent_name):
"""Charge les paramètres par défaut de l'agent"""
try:
# Récupérer la configuration de l'agent
from agents.roles import AGENTS
if agent_name in AGENTS:
agent_config = AGENTS[agent_name]
params = agent_config.get("params", {})
# Mettre à jour les variables avec les valeurs par défaut
self.temp_var.set(params.get("temperature", 0.7))
self.top_p_var.set(params.get("top_p", 0.9))
self.top_k_var.set(params.get("top_k", 40))
self.repeat_var.set(params.get("repeat_penalty", 1.1))
self.tokens_var.set(params.get("num_predict", 512))
# Mettre à jour les paramètres personnalisés
self.custom_params = params.copy()
except Exception as e:
print(f"Erreur lors du chargement des paramètres de l'agent: {str(e)}")
def _load_model_params(self, model_name):
"""Charge les paramètres par défaut du modèle"""
# Vérifier si un fichier de paramètres personnalisés existe
save_dir = "saved_params"
file_name = f"{save_dir}/{self.current_agent}_{model_name}.json"
if os.path.exists(file_name):
try:
# Charger les paramètres personnalisés
with open(file_name, "r") as f:
params = json.load(f)
# Mettre à jour les variables
self.temp_var.set(params.get("temperature", 0.7))
self.top_p_var.set(params.get("top_p", 0.9))
self.top_k_var.set(params.get("top_k", 40))
self.repeat_var.set(params.get("repeat_penalty", 1.1))
self.tokens_var.set(params.get("num_predict", 512))
# Mettre à jour les paramètres personnalisés
self.custom_params = params.copy()
# Mettre à jour le statut
self.status_bar.config(text=f"Paramètres personnalisés chargés depuis {file_name}")
except Exception as e:
print(f"Erreur lors du chargement des paramètres personnalisés: {str(e)}")
else:
# Si aucun fichier personnalisé, charger les paramètres par défaut
self._load_agent_params(self.current_agent)
def _create_agent_with_custom_params(self):
"""Crée un agent avec les paramètres personnalisés"""
if not self.current_agent:
raise ValueError("Aucun agent sélectionné")
# Créer l'agent
agent = AgentManager.create(self.current_agent)
# Appliquer les paramètres personnalisés
for key, value in self.custom_params.items():
agent.params[key] = value
# Appliquer le modèle si différent
model_name = self.model_combo.get()
if model_name != agent.model:
# Créer un nouveau modèle
from core.factory import LLMFactory
new_model = LLMFactory.create(model_name)
# Copier les paramètres
new_model.params.update(agent.params)
new_model.system_prompt = agent.system_prompt
new_model.agent = agent.agent
agent = new_model
return agent
def _load_conversation_history(self):
"""Charge l'historique des conversations"""
# Créer le dossier d'historique si nécessaire
history_dir = "chat_history"
os.makedirs(history_dir, exist_ok=True)
# Lister les fichiers d'historique
self.history_files = []
for file in os.listdir(history_dir):
if file.endswith(".json"):
self.history_files.append(os.path.join(history_dir, file))
# Trier par date (plus récent en premier)
self.history_files.sort(key=os.path.getmtime, reverse=True)
# Mettre à jour la liste d'historique
self.history_listbox.delete(0, tk.END)
for file in self.history_files:
try:
with open(file, "r", encoding="utf-8") as f:
history = json.load(f)
# Extraire les informations
agent = history.get("agent", "Inconnu")
date = history.get("date", "Inconnue")
messages = history.get("messages", [])
# Ajouter à la liste
if messages:
first_message = messages[0].get("content", "")
preview = first_message[:30] + "..." if len(first_message) > 30 else first_message
self.history_listbox.insert(tk.END, f"{agent} - {date} - {preview}")
except Exception as e:
print(f"Erreur lors du chargement de l'historique {file}: {str(e)}")
def _on_history_select(self, event):
"""Gestionnaire d'événement pour la sélection d'un historique"""
# Récupérer l'index sélectionné
selection = self.history_listbox.curselection()
if not selection:
return
# Activer le bouton de chargement
self.load_history_btn.config(state=tk.NORMAL)
def _load_selected_history(self):
"""Charge l'historique sélectionné"""
# Récupérer l'index sélectionné
selection = self.history_listbox.curselection()
if not selection or selection[0] >= len(self.history_files):
return
# Récupérer le fichier d'historique
file = self.history_files[selection[0]]
try:
# Charger l'historique
with open(file, "r", encoding="utf-8") as f:
history = json.load(f)
# Extraire les informations
agent = history.get("agent", None)
messages = history.get("messages", [])
# Sélectionner l'agent si disponible
if agent:
# Trouver l'index de l'agent dans la listbox
for i in range(self.agent_listbox.size()):
if self.agent_listbox.get(i) == agent:
self.agent_listbox.selection_clear(0, tk.END)
self.agent_listbox.selection_set(i)
self.agent_listbox.see(i)
self._on_agent_select(None)
break
# Effacer le chat actuel
self._clear_chat()
# Ajouter les messages au chat
for message in messages:
sender = message.get("sender", "Inconnu")
content = message.get("content", "")
self._add_message_to_chat(sender, content, add_to_history=False)
# Mettre à jour l'historique
self.conversation_history = messages
# Mettre à jour le statut
self.status_bar.config(text=f"Historique chargé depuis {file}")
except Exception as e:
messagebox.showerror("Erreur", f"Erreur lors du chargement de l'historique: {str(e)}")
def _delete_history(self):
"""Supprime l'historique sélectionné"""
# Récupérer l'index sélectionné
selection = self.history_listbox.curselection()
if not selection or selection[0] >= len(self.history_files):
return
# Récupérer le fichier d'historique
file = self.history_files[selection[0]]
# Demander confirmation
if messagebox.askyesno("Confirmation", f"Voulez-vous vraiment supprimer cet historique ?"):
try:
# Supprimer le fichier
os.remove(file)
# Mettre à jour la liste
self.history_files.pop(selection[0])
self.history_listbox.delete(selection[0])
# Mettre à jour le statut
self.status_bar.config(text=f"Historique supprimé")
except Exception as e:
messagebox.showerror("Erreur", f"Erreur lors de la suppression: {str(e)}")
def _export_history(self):
"""Exporte l'historique sélectionné"""
# Récupérer l'index sélectionné
selection = self.history_listbox.curselection()
if not selection or selection[0] >= len(self.history_files):
return
# Récupérer le fichier d'historique
file = self.history_files[selection[0]]
try:
# Charger l'historique
with open(file, "r", encoding="utf-8") as f:
history = json.load(f)
# Ouvrir une boîte de dialogue pour choisir l'emplacement d'exportation
export_file = filedialog.asksaveasfilename(
defaultextension=".md",
filetypes=[("Markdown", "*.md"), ("Texte", "*.txt"), ("JSON", "*.json")],
title="Exporter l'historique"
)
if not export_file:
return
# Format d'exportation selon l'extension
ext = os.path.splitext(export_file)[1].lower()
if ext == ".json":
# Exporter au format JSON
with open(export_file, "w", encoding="utf-8") as f:
json.dump(history, f, indent=2, ensure_ascii=False)
elif ext == ".md" or ext == ".txt":
# Exporter au format Markdown/Texte
with open(export_file, "w", encoding="utf-8") as f:
# En-tête
agent = history.get("agent", "Inconnu")
date = history.get("date", "Inconnue")
f.write(f"# Conversation avec {agent} - {date}\n\n")
# Messages
for message in history.get("messages", []):
sender = message.get("sender", "Inconnu")
content = message.get("content", "")
if ext == ".md":
f.write(f"## {sender}\n\n{content}\n\n")
else:
f.write(f"{sender}:\n{content}\n\n")
# Mettre à jour le statut
self.status_bar.config(text=f"Historique exporté vers {export_file}")
except Exception as e:
messagebox.showerror("Erreur", f"Erreur lors de l'exportation: {str(e)}")
def _on_shift_enter(self, event):
"""Gestionnaire d'événement pour Shift+Enter"""
# Ajouter un saut de ligne
return
def _send_message(self):
"""Envoie le message saisi par l'utilisateur"""
if not self.current_agent:
messagebox.showwarning("Aucun agent sélectionné",
"Veuillez d'abord sélectionner un agent.")
return
# Récupérer le message
message = self.user_input.get(1.0, tk.END).strip()
if not message:
return
# Effacer le champ de saisie
self.user_input.delete(1.0, tk.END)
# Ajouter le message au chat
self._add_message_to_chat("Utilisateur", message)
# Générer une réponse
try:
# Mettre à jour le statut
self.status_bar.config(text=f"Génération en cours...")
self.root.update()
# Créer l'agent avec les paramètres personnalisés
agent = self._create_agent_with_custom_params()
# Générer la réponse
response = agent.generate(message)
# Ajouter la réponse au chat
self._add_message_to_chat(self.current_agent, response)
# Mettre à jour le statut
self.status_bar.config(text=f"Réponse générée")
except Exception as e:
messagebox.showerror("Erreur", f"Erreur lors de la génération: {str(e)}")
self.status_bar.config(text=f"Erreur lors de la génération")
def _add_message_to_chat(self, sender, content, add_to_history=True):
"""Ajoute un message au chat"""
# Activer la zone de chat pour modification
self.chat_display.config(state=tk.NORMAL)
# Ajouter le message
self.chat_display.insert(tk.END, f"{sender}:\n", "sender")
self.chat_display.insert(tk.END, f"{content}\n\n", "message")
# Configurer les tags
self.chat_display.tag_configure("sender", font=("Arial", 10, "bold"))
self.chat_display.tag_configure("message", font=("Arial", 10))
# Défiler vers le bas
self.chat_display.see(tk.END)
# Désactiver la zone de chat
self.chat_display.config(state=tk.DISABLED)
# Ajouter à l'historique
if add_to_history:
self.conversation_history.append({
"sender": sender,
"content": content,
"timestamp": datetime.now().isoformat()
})
# Sauvegarder l'historique
self._save_conversation_history()
def _clear_chat(self):
"""Efface le contenu du chat"""
# Effacer la zone de chat
self.chat_display.config(state=tk.NORMAL)
self.chat_display.delete(1.0, tk.END)
self.chat_display.config(state=tk.DISABLED)
# Ne pas effacer l'historique
def _new_chat(self):
"""Démarre une nouvelle conversation"""
# Demander confirmation si la conversation actuelle n'est pas vide
if self.conversation_history and messagebox.askyesno(
"Nouvelle conversation",
"Voulez-vous démarrer une nouvelle conversation ?"
):
# Effacer la zone de chat
self._clear_chat()
# Réinitialiser l'historique
self.conversation_history = []
# Mettre à jour le statut
self.status_bar.config(text=f"Nouvelle conversation démarrée")
def _save_conversation_history(self):
"""Sauvegarde l'historique de la conversation actuelle"""
if not self.conversation_history or not self.current_agent:
return
# Créer le dossier d'historique si nécessaire
history_dir = "chat_history"
os.makedirs(history_dir, exist_ok=True)
# Créer un ID unique pour la conversation
now = datetime.now()
date_str = now.strftime("%Y-%m-%d_%H-%M-%S")
file_name = f"{history_dir}/{self.current_agent}_{date_str}.json"
# Préparer les données
history_data = {
"agent": self.current_agent,
"model": self.model_combo.get(),
"date": now.strftime("%Y-%m-%d %H:%M:%S"),
"params": self.custom_params,
"messages": self.conversation_history
}
# Sauvegarder l'historique
try:
with open(file_name, "w", encoding="utf-8") as f:
json.dump(history_data, f, indent=2, ensure_ascii=False)
# Mettre à jour la liste des fichiers d'historique
if file_name not in self.history_files:
self.history_files.insert(0, file_name)
self.history_listbox.insert(0, f"{self.current_agent} - {now.strftime('%Y-%m-%d %H:%M:%S')}")
except Exception as e:
print(f"Erreur lors de la sauvegarde de l'historique: {str(e)}")
def main():
"""Point d'entrée principal"""
root = tk.Tk()
app = ChatUI(root)
root.mainloop()
if __name__ == "__main__":
main()

51
utils/parameter_tester.py Normal file
View File

@ -0,0 +1,51 @@
from itertools import product
from agents.roles import AGENTS
from datetime import datetime
def test_agents_on_prompt(model_class, prompt: str, agents: list, param_grid: dict, fixed_params: dict = None):
"""
Teste les agents sur un prompt donné avec différentes combinaisons de paramètres
model_class: Classe du modèle LLM à utiliser
prompt: Prompt à tester
agents: Liste des agents à tester
param_grid: Grille de paramètres à tester
fixed_params: Paramètres fixes à appliquer à tous les tests
"""
if fixed_params is None:
fixed_params = {}
#Générer toutes les combinaisons de paramètres à tester
keys = list(param_grid.keys())
values = list(param_grid.values())
combinations = list(product(*values))
print(f"[TEST STARTED] {len(agents)} agents, {len(combinations)} combinaisons, total; {len(agents) * len(combinations)} tests")
for agent_name in agents:
if agent_name not in AGENTS:
print(f"[Skipped] Agent inconnu : {agent_name}")
continue
for combo in combinations:
#instancier un modèle neuf à chaque test(préserve isolation)
model = model_class()
# Aplliquer le rôle de l'agent
model.set_role(agent_name, AGENTS[agent_name])
# Fusionner les paramètres (params agent < combo test < fixed)
combo_params = dict(zip(keys, combo))
model.params.update(combo_params)
model.params.update(fixed_params)
#Affichage console
ts = datetime.now().strftime("%H:%M:%S")
print(f"[{ts}] -> Agent: {agent_name} | Combo: {combo_params}")
try:
model.generate(prompt)
except Exception as e:
print(f"[Erreur] {e}")
print("[TEST COMPLET]")

534
utils/system_monitor.py Normal file
View File

@ -0,0 +1,534 @@
"""
Moniteur de ressources système pour Ollama et les ressources NVIDIA GPU
"""
import tkinter as tk
from tkinter import ttk
import psutil
import threading
import time
import subprocess
import json
import os
import platform
import requests
from datetime import datetime
class SystemMonitor:
def __init__(self, root):
self.root = root
self.root.title("Moniteur LLM Lab")
self.root.geometry("800x600")
self.root.minsize(700, 500)
# Style
self.style = ttk.Style()
self.style.theme_use('alt') # 'clam', 'alt', 'default', 'classic'
# Variables
self.update_interval = 2 # secondes
self.running = True
self.ollama_models = []
self.active_model = None
self.gpu_available = self._check_gpu_available()
# Création de l'UI
self._create_widgets()
# Démarrer le thread de mise à jour
self.update_thread = threading.Thread(target=self._update_loop)
self.update_thread.daemon = True
self.update_thread.start()
# Intercepter la fermeture de la fenêtre
self.root.protocol("WM_DELETE_WINDOW", self._on_close)
def _create_widgets(self):
# Créer le notebook (onglets)
self.notebook = ttk.Notebook(self.root)
self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# Onglet 1: Surveillance système
self.system_frame = ttk.Frame(self.notebook)
self.notebook.add(self.system_frame, text="Système")
# Onglet 2: Ollama
self.ollama_frame = ttk.Frame(self.notebook)
self.notebook.add(self.ollama_frame, text="Ollama")
# Onglet 3: GPU
self.gpu_frame = ttk.Frame(self.notebook)
self.notebook.add(self.gpu_frame, text="GPU")
# Onglet 4: Logs
self.logs_frame = ttk.Frame(self.notebook)
self.notebook.add(self.logs_frame, text="Logs")
# === Configuration de l'onglet Système ===
system_label = ttk.Label(self.system_frame, text="Ressources Système", font=("Arial", 14, "bold"))
system_label.pack(pady=10)
# Infos système
system_info_frame = ttk.LabelFrame(self.system_frame, text="Informations Système")
system_info_frame.pack(fill=tk.X, padx=10, pady=5)
# OS
os_frame = ttk.Frame(system_info_frame)
os_frame.pack(fill=tk.X, padx=5, pady=2)
ttk.Label(os_frame, text="Système d'exploitation:").pack(side=tk.LEFT, padx=5)
self.os_label = ttk.Label(os_frame, text="")
self.os_label.pack(side=tk.LEFT, padx=5)
# CPU
cpu_frame = ttk.Frame(system_info_frame)
cpu_frame.pack(fill=tk.X, padx=5, pady=2)
ttk.Label(cpu_frame, text="Processeur:").pack(side=tk.LEFT, padx=5)
self.cpu_label = ttk.Label(cpu_frame, text="")
self.cpu_label.pack(side=tk.LEFT, padx=5)
# RAM
ram_frame = ttk.Frame(system_info_frame)
ram_frame.pack(fill=tk.X, padx=5, pady=2)
ttk.Label(ram_frame, text="Mémoire RAM:").pack(side=tk.LEFT, padx=5)
self.ram_label = ttk.Label(ram_frame, text="")
self.ram_label.pack(side=tk.LEFT, padx=5)
# Barres de progression
progress_frame = ttk.LabelFrame(self.system_frame, text="Utilisation des ressources")
progress_frame.pack(fill=tk.X, padx=10, pady=5)
# CPU Usage
cpu_usage_frame = ttk.Frame(progress_frame)
cpu_usage_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(cpu_usage_frame, text="CPU:").pack(side=tk.LEFT, padx=5)
self.cpu_progress = ttk.Progressbar(cpu_usage_frame, orient=tk.HORIZONTAL, length=300, mode='determinate')
self.cpu_progress.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
self.cpu_percent = ttk.Label(cpu_usage_frame, text="0%")
self.cpu_percent.pack(side=tk.LEFT, padx=5)
# RAM Usage
ram_usage_frame = ttk.Frame(progress_frame)
ram_usage_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(ram_usage_frame, text="RAM:").pack(side=tk.LEFT, padx=5)
self.ram_progress = ttk.Progressbar(ram_usage_frame, orient=tk.HORIZONTAL, length=300, mode='determinate')
self.ram_progress.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
self.ram_percent = ttk.Label(ram_usage_frame, text="0%")
self.ram_percent.pack(side=tk.LEFT, padx=5)
# Disk Usage
disk_usage_frame = ttk.Frame(progress_frame)
disk_usage_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(disk_usage_frame, text="Disque:").pack(side=tk.LEFT, padx=5)
self.disk_progress = ttk.Progressbar(disk_usage_frame, orient=tk.HORIZONTAL, length=300, mode='determinate')
self.disk_progress.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
self.disk_percent = ttk.Label(disk_usage_frame, text="0%")
self.disk_percent.pack(side=tk.LEFT, padx=5)
# === Configuration de l'onglet Ollama ===
ollama_label = ttk.Label(self.ollama_frame, text="Serveur Ollama", font=("Arial", 14, "bold"))
ollama_label.pack(pady=10)
# État du serveur
server_frame = ttk.LabelFrame(self.ollama_frame, text="État du serveur")
server_frame.pack(fill=tk.X, padx=10, pady=5)
# Status
status_frame = ttk.Frame(server_frame)
status_frame.pack(fill=tk.X, padx=5, pady=2)
ttk.Label(status_frame, text="Statut:").pack(side=tk.LEFT, padx=5)
self.status_label = ttk.Label(status_frame, text="Vérification...")
self.status_label.pack(side=tk.LEFT, padx=5)
# URL
url_frame = ttk.Frame(server_frame)
url_frame.pack(fill=tk.X, padx=5, pady=2)
ttk.Label(url_frame, text="URL:").pack(side=tk.LEFT, padx=5)
self.url_label = ttk.Label(url_frame, text="http://localhost:11434")
self.url_label.pack(side=tk.LEFT, padx=5)
# Modèles disponibles
models_frame = ttk.LabelFrame(self.ollama_frame, text="Modèles disponibles")
models_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
# Liste des modèles
self.tree = ttk.Treeview(models_frame, columns=("Taille", "Modifié"), show='headings')
self.tree.heading("Taille", text="Taille")
self.tree.heading("Modifié", text="Modifié")
self.tree.column("Taille", width=100)
self.tree.column("Modifié", width=150)
self.tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
# Boutons
button_frame = ttk.Frame(self.ollama_frame)
button_frame.pack(fill=tk.X, padx=10, pady=5)
refresh_button = ttk.Button(button_frame, text="Rafraîchir", command=self._refresh_ollama)
refresh_button.pack(side=tk.LEFT, padx=5)
# === Configuration de l'onglet GPU ===
gpu_label = ttk.Label(self.gpu_frame, text="Ressources GPU", font=("Arial", 14, "bold"))
gpu_label.pack(pady=10)
if self.gpu_available:
# Infos GPU
gpu_info_frame = ttk.LabelFrame(self.gpu_frame, text="Informations GPU")
gpu_info_frame.pack(fill=tk.X, padx=10, pady=5)
# Modèle GPU
gpu_model_frame = ttk.Frame(gpu_info_frame)
gpu_model_frame.pack(fill=tk.X, padx=5, pady=2)
ttk.Label(gpu_model_frame, text="Modèle:").pack(side=tk.LEFT, padx=5)
self.gpu_model_label = ttk.Label(gpu_model_frame, text="")
self.gpu_model_label.pack(side=tk.LEFT, padx=5)
# Mémoire GPU
gpu_memory_frame = ttk.Frame(gpu_info_frame)
gpu_memory_frame.pack(fill=tk.X, padx=5, pady=2)
ttk.Label(gpu_memory_frame, text="Mémoire:").pack(side=tk.LEFT, padx=5)
self.gpu_memory_label = ttk.Label(gpu_memory_frame, text="")
self.gpu_memory_label.pack(side=tk.LEFT, padx=5)
# Utilisation GPU
gpu_usage_frame = ttk.LabelFrame(self.gpu_frame, text="Utilisation")
gpu_usage_frame.pack(fill=tk.X, padx=10, pady=5)
# GPU Compute
gpu_compute_frame = ttk.Frame(gpu_usage_frame)
gpu_compute_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(gpu_compute_frame, text="Calcul:").pack(side=tk.LEFT, padx=5)
self.gpu_compute_progress = ttk.Progressbar(gpu_compute_frame, orient=tk.HORIZONTAL, length=300, mode='determinate')
self.gpu_compute_progress.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
self.gpu_compute_percent = ttk.Label(gpu_compute_frame, text="0%")
self.gpu_compute_percent.pack(side=tk.LEFT, padx=5)
# GPU Memory
gpu_mem_usage_frame = ttk.Frame(gpu_usage_frame)
gpu_mem_usage_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(gpu_mem_usage_frame, text="Mémoire:").pack(side=tk.LEFT, padx=5)
self.gpu_mem_progress = ttk.Progressbar(gpu_mem_usage_frame, orient=tk.HORIZONTAL, length=300, mode='determinate')
self.gpu_mem_progress.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
self.gpu_mem_percent = ttk.Label(gpu_mem_usage_frame, text="0%")
self.gpu_mem_percent.pack(side=tk.LEFT, padx=5)
# Température
gpu_temp_frame = ttk.Frame(gpu_usage_frame)
gpu_temp_frame.pack(fill=tk.X, padx=5, pady=5)
ttk.Label(gpu_temp_frame, text="Température:").pack(side=tk.LEFT, padx=5)
self.gpu_temp_progress = ttk.Progressbar(gpu_temp_frame, orient=tk.HORIZONTAL, length=300, mode='determinate')
self.gpu_temp_progress.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True)
self.gpu_temp_label = ttk.Label(gpu_temp_frame, text="0°C")
self.gpu_temp_label.pack(side=tk.LEFT, padx=5)
# Graphiques processe actifs
gpu_processes_frame = ttk.LabelFrame(self.gpu_frame, text="Processus GPU")
gpu_processes_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
# Liste des processus
self.gpu_process_tree = ttk.Treeview(gpu_processes_frame,
columns=("PID", "Nom", "Mémoire"),
show='headings')
self.gpu_process_tree.heading("PID", text="PID")
self.gpu_process_tree.heading("Nom", text="Processus")
self.gpu_process_tree.heading("Mémoire", text="Mémoire")
self.gpu_process_tree.column("PID", width=50)
self.gpu_process_tree.column("Nom", width=200)
self.gpu_process_tree.column("Mémoire", width=100)
self.gpu_process_tree.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
else:
no_gpu_label = ttk.Label(self.gpu_frame,
text="Aucun GPU NVIDIA détecté.",
font=("Arial", 12))
no_gpu_label.pack(pady=50)
install_label = ttk.Label(self.gpu_frame,
text="Pour surveiller un GPU NVIDIA, installez nvidia-smi et nvitop.",
font=("Arial", 10))
install_label.pack(pady=10)
# === Configuration de l'onglet Logs ===
logs_label = ttk.Label(self.logs_frame, text="Journaux d'activité", font=("Arial", 14, "bold"))
logs_label.pack(pady=10)
# Zone de logs
log_area_frame = ttk.Frame(self.logs_frame)
log_area_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
# Scrollbar
scrollbar = ttk.Scrollbar(log_area_frame)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# Text area
self.log_text = tk.Text(log_area_frame, yscrollcommand=scrollbar.set)
self.log_text.pack(fill=tk.BOTH, expand=True)
scrollbar.config(command=self.log_text.yview)
# Boutons
log_button_frame = ttk.Frame(self.logs_frame)
log_button_frame.pack(fill=tk.X, padx=10, pady=5)
clear_log_button = ttk.Button(log_button_frame, text="Effacer les logs",
command=lambda: self.log_text.delete(1.0, tk.END))
clear_log_button.pack(side=tk.LEFT, padx=5)
# Barre d'état en bas
self.status_bar = ttk.Label(self.root, text="Moniteur LLM Lab - Dernière mise à jour: Jamais",
relief=tk.SUNKEN, anchor=tk.W)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
def _update_loop(self):
"""Thread principal de mise à jour"""
while self.running:
try:
# Mise à jour système
self._update_system_info()
# Mise à jour Ollama
if self.notebook.index(self.notebook.select()) == 1: # Onglet Ollama
self._update_ollama_info()
# Mise à jour GPU
if self.gpu_available and self.notebook.index(self.notebook.select()) == 2: # Onglet GPU
self._update_gpu_info()
# Mise à jour de la barre d'état
now = datetime.now().strftime("%H:%M:%S")
self.status_bar.config(text=f"Moniteur LLM Lab - Dernière mise à jour: {now}")
except Exception as e:
self._log(f"Erreur de mise à jour: {str(e)}")
time.sleep(self.update_interval)
def _update_system_info(self):
"""Met à jour les informations système"""
# Informations système
self.os_label.config(text=f"{platform.system()} {platform.release()}")
self.cpu_label.config(text=f"{psutil.cpu_count(logical=False)} cœurs ({psutil.cpu_count()} threads)")
# Détection avancée de la RAM
try:
ram = psutil.virtual_memory()
total_ram = ram.total / (1024 * 1024 * 1024) # GB
# Vérification supplémentaire pour Linux
if platform.system() == "Linux":
try:
# Utiliser /proc/meminfo pour une détection plus précise
with open('/proc/meminfo', 'r') as f:
for line in f:
if 'MemTotal' in line:
# MemTotal est en kB
mem_kb = int(line.split()[1])
linux_ram = mem_kb / (1024 * 1024) # GB
# Utiliser la valeur la plus élevée
total_ram = max(total_ram, linux_ram)
break
except Exception as e:
self._log(f"Erreur lors de la lecture de /proc/meminfo: {str(e)}")
self.ram_label.config(text=f"{total_ram:.1f} GB")
except Exception as e:
self._log(f"Erreur lors de la détection de la RAM: {str(e)}")
self.ram_label.config(text="Détection impossible")
# Utilisation CPU
cpu_percent = psutil.cpu_percent()
self.cpu_progress["value"] = cpu_percent
self.cpu_percent.config(text=f"{cpu_percent:.1f}%")
# Utilisation RAM
ram_percent = ram.percent
self.ram_progress["value"] = ram_percent
self.ram_percent.config(text=f"{ram_percent:.1f}%")
# Utilisation disque
disk = psutil.disk_usage('/')
disk_percent = disk.percent
self.disk_progress["value"] = disk_percent
self.disk_percent.config(text=f"{disk_percent:.1f}%")
def _update_ollama_info(self):
"""Met à jour les informations Ollama"""
try:
# Vérifier si le serveur est en cours d'exécution
response = requests.get("http://localhost:11434/api/tags", timeout=2)
if response.status_code == 200:
self.status_label.config(text="En ligne", foreground="green")
# Mettre à jour la liste des modèles
data = response.json()
models = data.get("models", [])
# Effacer la liste actuelle
for item in self.tree.get_children():
self.tree.delete(item)
# Ajouter les modèles
for model in models:
model_name = model.get("name", "")
model_size = self._format_size(model.get("size", 0))
modified = model.get("modified_at", "")
# Convertir le format de date
if modified:
try:
modified_dt = datetime.fromisoformat(modified.replace('Z', '+00:00'))
modified = modified_dt.strftime("%d/%m/%Y %H:%M")
except:
pass
self.tree.insert("", tk.END, text=model_name, values=(model_size, modified), iid=model_name)
# Mettre à jour la liste globale
self.ollama_models = [model.get("name", "") for model in models]
# Vérifier s'il y a un modèle actif
if self.active_model:
self._log(f"Modèle actif: {self.active_model}")
# Mettre en surbrillance le modèle actif
if self.active_model in self.ollama_models:
self.tree.selection_set(self.active_model)
self.tree.see(self.active_model)
else:
self.status_label.config(text="Erreur", foreground="red")
self._log(f"Erreur de connexion au serveur Ollama: {response.status_code}")
except requests.exceptions.RequestException:
self.status_label.config(text="Hors ligne", foreground="red")
self._log("Serveur Ollama non disponible")
def _update_gpu_info(self):
"""Met à jour les informations GPU"""
if not self.gpu_available:
return
try:
# Exécuter nvidia-smi pour obtenir les informations GPU
result = subprocess.run(
['nvidia-smi', '--query-gpu=name,memory.total,memory.used,utilization.gpu,temperature.gpu',
'--format=csv,noheader,nounits'],
capture_output=True,
text=True,
check=True
)
if result.returncode == 0:
# Analyser les résultats
gpu_data = result.stdout.strip().split(',')
if len(gpu_data) >= 5:
# Nom du modèle
model_name = gpu_data[0].strip()
self.gpu_model_label.config(text=model_name)
# Mémoire totale et utilisée
total_memory = float(gpu_data[1].strip())
used_memory = float(gpu_data[2].strip())
memory_percent = (used_memory / total_memory) * 100 if total_memory > 0 else 0
self.gpu_memory_label.config(text=f"{used_memory:.0f} MiB / {total_memory:.0f} MiB")
self.gpu_mem_progress["value"] = memory_percent
self.gpu_mem_percent.config(text=f"{memory_percent:.1f}%")
# Utilisation GPU
gpu_util = float(gpu_data[3].strip())
self.gpu_compute_progress["value"] = gpu_util
self.gpu_compute_percent.config(text=f"{gpu_util:.1f}%")
# Température
temp = float(gpu_data[4].strip())
# Échelle de température: 0-100°C
self.gpu_temp_progress["value"] = temp
self.gpu_temp_label.config(text=f"{temp:.1f}°C")
# Récupérer les processus GPU
result_processes = subprocess.run(
['nvidia-smi', '--query-compute-apps=pid,name,used_memory', '--format=csv,noheader,nounits'],
capture_output=True,
text=True
)
if result_processes.returncode == 0:
# Effacer la liste actuelle
for item in self.gpu_process_tree.get_children():
self.gpu_process_tree.delete(item)
# Ajouter les processus
processes = result_processes.stdout.strip().split('\n')
for process in processes:
if process.strip():
process_data = process.split(',')
if len(process_data) >= 3:
pid = process_data[0].strip()
name = process_data[1].strip()
memory = f"{process_data[2].strip()} MiB"
# Ajouter à la liste
self.gpu_process_tree.insert("", tk.END, text=pid, values=(pid, name, memory))
# Si c'est Ollama, marquer comme modèle actif
if "ollama" in name.lower():
self._log(f"Ollama détecté sur GPU: PID {pid}, utilisant {memory}")
# Chercher quel modèle est actif
try:
process_info = psutil.Process(int(pid))
cmd_line = " ".join(process_info.cmdline())
for model in self.ollama_models:
if model in cmd_line:
self.active_model = model
self._log(f"Modèle actif détecté: {model}")
break
except:
pass
except subprocess.SubprocessError as e:
self._log(f"Erreur lors de l'exécution de nvidia-smi: {str(e)}")
except Exception as e:
self._log(f"Erreur de mise à jour GPU: {str(e)}")
def _refresh_ollama(self):
"""Force le rafraîchissement des informations Ollama"""
self._update_ollama_info()
self._log("Informations Ollama rafraîchies")
def _check_gpu_available(self):
"""Vérifie si un GPU NVIDIA est disponible"""
try:
result = subprocess.run(['nvidia-smi'], capture_output=True, text=True)
return result.returncode == 0
except:
return False
def _format_size(self, size_bytes):
"""Formate la taille en unités lisibles"""
if size_bytes < 1024:
return f"{size_bytes} B"
elif size_bytes < 1024 * 1024:
return f"{size_bytes/1024:.1f} KB"
elif size_bytes < 1024 * 1024 * 1024:
return f"{size_bytes/(1024*1024):.1f} MB"
else:
return f"{size_bytes/(1024*1024*1024):.1f} GB"
def _log(self, message):
"""Ajoute un message aux logs"""
timestamp = datetime.now().strftime("%H:%M:%S")
log_message = f"[{timestamp}] {message}\n"
# Ajouter au texte
self.log_text.insert(tk.END, log_message)
self.log_text.see(tk.END) # Défiler vers le bas
def _on_close(self):
"""Gère la fermeture de l'application"""
self.running = False
time.sleep(0.5) # Attendre que le thread se termine
self.root.destroy()
def main():
"""Point d'entrée principal"""
root = tk.Tk()
app = SystemMonitor(root)
root.mainloop()
if __name__ == "__main__":
main()

View File

@ -0,0 +1,85 @@
# Checklist de migration vers Windows 11 Pro
Ce document fournit une liste de vérification rapide pour migrer LLM Lab de WSL vers Windows 11 Pro.
## Étape 1: Prérequis Windows
- [ ] Installer [Python 3.10+](https://www.python.org/downloads/) (cocher "Add Python to PATH")
- [ ] Installer [Git pour Windows](https://git-scm.com/download/win)
- [ ] Installer [Ollama pour Windows](https://ollama.com/download/windows)
- [ ] Mettre à jour les [pilotes NVIDIA](https://www.nvidia.com/Download/index.aspx) (si GPU disponible)
## Étape 2: Transfert du projet
**Option A: Via Git (recommandée)**
- [ ] Cloner le dépôt sur Windows
```cmd
git clone <URL_DU_DÉPÔT> llm_lab
cd llm_lab
```
**Option B: Copie directe**
- [ ] Accéder au dossier WSL: `\\wsl$\Ubuntu\chemin\vers\llm_lab`
- [ ] Copier tous les fichiers vers un nouveau dossier Windows
## Étape 3: Configuration
- [ ] Exécuter le script de configuration
```cmd
setup_env.bat
```
- [ ] Vérifier l'installation
```cmd
test_installation.bat
```
- [ ] Optimiser Ollama (en tant qu'administrateur)
```cmd
optimize_ollama.bat
```
## Étape 4: Téléchargement des modèles
- [ ] Télécharger les modèles dans Ollama
```cmd
ollama pull mistral:latest
ollama pull codellama:13b-python
ollama pull llama2:13b
```
## Étape 5: Test du système
- [ ] Lancer l'interface graphique
```cmd
run.bat gui
```
- [ ] Lancer le moniteur système
```cmd
run.bat monitor
```
- [ ] Tester l'agent Mistral
```cmd
run.bat chat test
```
## Problèmes courants et solutions
### Interface graphique ne se lance pas
- Vérifier l'installation de tkinter: `python -c "import tkinter; tkinter._test()"`
- Réinstaller Python avec l'option "tcl/tk and IDLE" cochée
### Ollama ne trouve pas le GPU
- Exécuter `optimize_ollama.bat` en tant qu'administrateur
- Vérifier que les pilotes NVIDIA sont à jour: `nvidia-smi`
### Erreurs de modules manquants
- Installer manuellement: `pip install wmi psutil requests pillow`
## Recommandations pour de meilleures performances
1. **Plan d'alimentation Windows**: Régler sur "Hautes performances"
2. **Panneau de configuration NVIDIA**:
- Préférer les performances maximales
- Désactiver l'économie d'énergie GPU
3. **Antivirus**:
- Ajouter des exceptions pour le dossier Ollama
- Exclure le processus Ollama