mirror of
https://github.com/Ladebeze66/llm_lab_perso.git
synced 2025-12-13 09:06:50 +01:00
first commit
This commit is contained in:
commit
f6aaf15a33
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"commentTranslate.targetLanguage": "fr"
|
||||
}
|
||||
297
README.md
Normal file
297
README.md
Normal 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
|
||||
BIN
agents/__pycache__/roles.cpython-312.pyc
Normal file
BIN
agents/__pycache__/roles.cpython-312.pyc
Normal file
Binary file not shown.
BIN
agents/__pycache__/roles.cpython-313.pyc
Normal file
BIN
agents/__pycache__/roles.cpython-313.pyc
Normal file
Binary file not shown.
129
agents/roles.py
Normal file
129
agents/roles.py
Normal 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
43
api-server.bat
Normal 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
251
api_server.py
Normal 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
76
chat.py
Normal 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
8
chat_gui.py
Normal 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()
|
||||
20
chat_history/python_2025-03-25_20-50-30.json
Normal file
20
chat_history/python_2025-03-25_20-50-30.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
25
chat_history/python_2025-03-25_20-55-35.json
Normal file
25
chat_history/python_2025-03-25_20-55-35.json
Normal 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
0
config/mistral7b_config.yaml
Normal file
0
config/mistral7b_config.yaml
Normal file
102
config_wsl_memoire.md
Normal file
102
config_wsl_memoire.md
Normal 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
|
||||
BIN
core/__pycache__/base_llm.cpython-312.pyc
Normal file
BIN
core/__pycache__/base_llm.cpython-312.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/base_llm.cpython-313.pyc
Normal file
BIN
core/__pycache__/base_llm.cpython-313.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/codellama13b_python.cpython-312.pyc
Normal file
BIN
core/__pycache__/codellama13b_python.cpython-312.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/codellama13b_python.cpython-313.pyc
Normal file
BIN
core/__pycache__/codellama13b_python.cpython-313.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/factory.cpython-312.pyc
Normal file
BIN
core/__pycache__/factory.cpython-312.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/factory.cpython-313.pyc
Normal file
BIN
core/__pycache__/factory.cpython-313.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/llama2_13b.cpython-312.pyc
Normal file
BIN
core/__pycache__/llama2_13b.cpython-312.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/llama2_13b.cpython-313.pyc
Normal file
BIN
core/__pycache__/llama2_13b.cpython-313.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/mistral7b.cpython-312.pyc
Normal file
BIN
core/__pycache__/mistral7b.cpython-312.pyc
Normal file
Binary file not shown.
BIN
core/__pycache__/mistral7b.cpython-313.pyc
Normal file
BIN
core/__pycache__/mistral7b.cpython-313.pyc
Normal file
Binary file not shown.
68
core/base_llm.py
Normal file
68
core/base_llm.py
Normal 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")
|
||||
|
||||
37
core/codellama13b_python.py
Normal file
37
core/codellama13b_python.py
Normal 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
53
core/factory.py
Normal 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
37
core/llama2_13b.py
Normal 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
37
core/mistral7b.py
Normal 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
343
cursor_integration.md
Normal 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
92
examples/agent_demo.py
Normal 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)
|
||||
"""
|
||||
52
examples/model_comparison.py
Normal file
52
examples/model_comparison.py
Normal 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)
|
||||
212
installation_ollama_disques_separes.md
Normal file
212
installation_ollama_disques_separes.md
Normal 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.
|
||||
242
llm_lab_installation_guide.md
Normal file
242
llm_lab_installation_guide.md
Normal 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.
|
||||
248
llm_lab_integration_guide.md
Normal file
248
llm_lab_integration_guide.md
Normal 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
4
log_index.md
Normal 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
17
logs/api_server.log
Normal file
@ -0,0 +1,17 @@
|
||||
2025-03-26 21:23:43,124 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* 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 - [33mPress CTRL+C to quit[0m
|
||||
2025-03-26 21:32:37,569 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* 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 - [33mPress CTRL+C to quit[0m
|
||||
2025-03-26 21:57:22,642 - werkzeug - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||
* 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 - [33mPress CTRL+C to quit[0m
|
||||
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] "[33mGET /favicon.ico HTTP/1.1[0m" 404 -
|
||||
0
logs/codellama
Normal file
0
logs/codellama
Normal file
42
logs/codellama13b-python_2025-03-25_20-55-35_0b82fbbf.md
Normal file
42
logs/codellama13b-python_2025-03-25_20-55-35_0b82fbbf.md
Normal 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!
|
||||
28
logs/mistrallatest_2025-03-25_21-00-17_aa61f01e.md
Normal file
28
logs/mistrallatest_2025-03-25_21-00-17_aa61f01e.md
Normal 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
8
monitor.py
Normal 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
467
obsidian_integration.md
Normal 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
306
optimisation_modelfile.md
Normal 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
94
optimize_ollama.bat
Normal 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
16
requirements.txt
Normal 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
69
run-api.ps1
Normal 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
79
run.bat
Normal 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
107
setup_env.bat
Normal 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
85
setup_env.sh
Normal 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
98
test_installation.bat
Normal 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
|
||||
18
tests/test_multi_agent_fixed_params.py
Normal file
18
tests/test_multi_agent_fixed_params.py
Normal 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
|
||||
}
|
||||
)
|
||||
19
tests/test_multi_agent_grid.py
Normal file
19
tests/test_multi_agent_grid.py
Normal 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
34
tests/test_new_models.py
Normal 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()
|
||||
13
tests/test_single_agent.py
Normal file
13
tests/test_single_agent.py
Normal 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.")
|
||||
19
tests/test_single_agent_param_grid.py
Normal file
19
tests/test_single_agent_param_grid.py
Normal 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
|
||||
}
|
||||
)
|
||||
292
update_monitor_for_ollama_path.md
Normal file
292
update_monitor_for_ollama_path.md
Normal 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.
|
||||
BIN
utils/__pycache__/agent_manager.cpython-312.pyc
Normal file
BIN
utils/__pycache__/agent_manager.cpython-312.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/agent_manager.cpython-313.pyc
Normal file
BIN
utils/__pycache__/agent_manager.cpython-313.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/chat_ui.cpython-312.pyc
Normal file
BIN
utils/__pycache__/chat_ui.cpython-312.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/parameter_tester.cpython-312.pyc
Normal file
BIN
utils/__pycache__/parameter_tester.cpython-312.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/system_monitor.cpython-312.pyc
Normal file
BIN
utils/__pycache__/system_monitor.cpython-312.pyc
Normal file
Binary file not shown.
BIN
utils/__pycache__/system_monitor.cpython-313.pyc
Normal file
BIN
utils/__pycache__/system_monitor.cpython-313.pyc
Normal file
Binary file not shown.
59
utils/agent_manager.py
Normal file
59
utils/agent_manager.py
Normal 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
980
utils/chat_ui.py
Normal 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
51
utils/parameter_tester.py
Normal 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
534
utils/system_monitor.py
Normal 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()
|
||||
85
windows_migration_checklist.md
Normal file
85
windows_migration_checklist.md
Normal 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
|
||||
Loading…
x
Reference in New Issue
Block a user