mirror of
https://github.com/Ladebeze66/llm_lab_perso.git
synced 2025-12-16 00:36:50 +01:00
251 lines
8.2 KiB
Python
251 lines
8.2 KiB
Python
#!/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) |