llm_ticket3/test_mistral_api.py
2025-04-17 17:32:02 +02:00

267 lines
9.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Script simple pour tester directement l'API Mistral Large.
Ce script permet de diagnostiquer si le problème vient de l'API ou de notre application.
"""
import os
import sys
import json
import logging
import requests
from datetime import datetime
# Configuration du logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler(sys.stdout)
]
)
logger = logging.getLogger("test_mistral_api")
# Clés API à tester
API_KEYS = [
"2iGzTzE9csRQ9IoASoUjplHwEjA200Vh", # Clé actuelle dans MistralLarge
"sk-d359d9236ca84a5986f889631832d1e6" # Clé utilisée dans list_mistral_models.py
]
def test_api_key(api_key):
"""Test si la clé API est valide en listant les modèles disponibles."""
url = "https://api.mistral.ai/v1/models"
headers = {
"Authorization": f"Bearer {api_key}"
}
try:
logger.info(f"Test de la clé API: {api_key[:5]}...{api_key[-5:]}")
response = requests.get(url, headers=headers)
logger.info(f"Code de statut: {response.status_code}")
if response.status_code == 200:
logger.info("La clé API est valide!")
try:
models = response.json().get('data', [])
logger.info(f"Modèles disponibles: {[model.get('id') for model in models]}")
return True
except Exception as e:
logger.error(f"Erreur lors du parsing de la réponse: {e}")
logger.error(f"Réponse brute: {response.text}")
return False
else:
logger.error(f"Erreur API: {response.status_code}")
logger.error(f"Réponse d'erreur: {response.text}")
return False
except Exception as e:
logger.error(f"Exception lors du test de la clé API: {e}")
return False
def test_direct_chat_completion(api_key):
"""Test directement l'endpoint chat/completions."""
url = "https://api.mistral.ai/v1/chat/completions"
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
data = {
"model": "mistral-large-latest",
"messages": [
{"role": "system", "content": "Tu es un assistant utile."},
{"role": "user", "content": "Dis simplement 'API FONCTIONNE' sans rien ajouter."}
],
"temperature": 0.1,
"max_tokens": 100
}
try:
logger.info(f"Test d'appel direct à chat/completions avec la clé: {api_key[:5]}...{api_key[-5:]}")
response = requests.post(url, headers=headers, json=data)
logger.info(f"Code de statut: {response.status_code}")
if response.status_code in [200, 201]:
try:
result = response.json()
message = result.get("choices", [{}])[0].get("message", {}).get("content", "")
logger.info(f"Réponse: {message}")
return True
except Exception as e:
logger.error(f"Erreur lors du parsing de la réponse: {e}")
logger.error(f"Réponse brute: {response.text}")
return False
else:
logger.error(f"Erreur API: {response.status_code}")
logger.error(f"Réponse d'erreur: {response.text}")
return False
except Exception as e:
logger.error(f"Exception lors de l'appel direct: {e}")
return False
# Essayer d'importer la classe MistralLarge
try:
from llm_classes.mistral_large import MistralLarge
logger.info("Module MistralLarge importé avec succès")
except ImportError as e:
logger.error(f"Impossible d'importer MistralLarge: {e}")
sys.exit(1)
def test_simple_prompt():
"""Test avec un prompt simple pour vérifier que l'API répond."""
try:
logger.info("Initialisation du modèle Mistral Large...")
model = MistralLarge()
logger.info("Modèle initialisé avec succès")
# Afficher la clé API utilisée
api_key = model.cleAPI()
logger.info(f"Clé API utilisée: {api_key[:5]}...{api_key[-5:]}")
# Prompt simple pour tester la connexion
prompt = "Réponds uniquement avec le texte 'API MISTRAL FONCTIONNE' sans rien ajouter d'autre."
logger.info(f"Envoi du prompt simple: {prompt}")
start_time = datetime.now()
response = model.interroger(prompt)
end_time = datetime.now()
duration = (end_time - start_time).total_seconds()
logger.info(f"Réponse reçue en {duration} secondes")
if response:
logger.info(f"Réponse complète: {response}")
# Vérifier si la réponse contient une erreur API
if "erreur" in response.lower() or "error" in response.lower():
logger.error("La réponse contient une erreur")
logger.error(f"Détails de l'erreur: {response}")
return False
return True
else:
logger.error("Réponse vide reçue")
return False
except Exception as e:
logger.error(f"Erreur lors du test avec prompt simple: {e}")
import traceback
logger.error(traceback.format_exc())
return False
def test_json_prompt():
"""Test avec un prompt demandant un JSON pour vérifier si c'est le format qui pose problème."""
try:
logger.info("Initialisation du modèle Mistral Large...")
model = MistralLarge()
logger.info("Modèle initialisé avec succès")
# Prompt demandant un JSON simple
prompt = """
Réponds uniquement avec un JSON valide au format suivant, sans aucun texte avant ou après:
{
"test": "réussi",
"timestamp": "heure actuelle",
"message": "API Mistral fonctionne correctement"
}
"""
logger.info(f"Envoi du prompt JSON: {prompt}")
start_time = datetime.now()
response = model.interroger(prompt)
end_time = datetime.now()
duration = (end_time - start_time).total_seconds()
logger.info(f"Réponse reçue en {duration} secondes")
if response:
logger.info(f"Réponse complète: {response}")
# Vérifier si la réponse contient une erreur API
if "erreur" in response.lower() or "error" in response.lower():
logger.error("La réponse contient une erreur")
logger.error(f"Détails de l'erreur: {response}")
return False
# Essayer de parser le JSON
try:
# Chercher un bloc de code JSON
import re
match = re.search(r"```(?:json)?\s*([\s\S]*?)\s*```", response)
if match:
response_cleaned = match.group(1).strip()
logger.info(f"JSON trouvé dans un bloc de code Markdown")
else:
response_cleaned = response
json_response = json.loads(response_cleaned)
logger.info(f"JSON valide reçu: {json.dumps(json_response, indent=2)}")
return True
except json.JSONDecodeError as e:
logger.error(f"Réponse reçue mais JSON invalide: {e}")
return False
else:
logger.error("Réponse vide reçue")
return False
except Exception as e:
logger.error(f"Erreur lors du test avec prompt JSON: {e}")
import traceback
logger.error(traceback.format_exc())
return False
def dump_model_info():
"""Affiche les informations sur le modèle et sa configuration."""
try:
model = MistralLarge()
logger.info("Informations sur le modèle:")
# Récupérer et afficher les attributs du modèle
for attr_name in dir(model):
if not attr_name.startswith('_'): # Ignorer les attributs privés
try:
attr_value = getattr(model, attr_name)
# N'afficher que les attributs simples, pas les méthodes
if not callable(attr_value):
logger.info(f" {attr_name}: {attr_value}")
except Exception as e:
logger.warning(f" Impossible d'accéder à {attr_name}: {e}")
# Afficher les méthodes disponibles
methods = [m for m in dir(model) if not m.startswith('_') and callable(getattr(model, m))]
logger.info(f"Méthodes disponibles: {', '.join(methods)}")
return True
except Exception as e:
logger.error(f"Erreur lors de la récupération des informations du modèle: {e}")
return False
def main():
"""Fonction principale exécutant les tests."""
logger.info("=== DÉBUT DES TESTS API MISTRAL ===")
logger.info("=== TEST DES CLÉS API ===")
for api_key in API_KEYS:
test_api_key(api_key)
test_direct_chat_completion(api_key)
logger.info("\n=== INFORMATIONS SUR LE MODÈLE ===")
dump_model_info()
logger.info("\n=== TEST AVEC PROMPT SIMPLE ===")
test_simple = test_simple_prompt()
logger.info("\n=== TEST AVEC PROMPT JSON ===")
test_json = test_json_prompt()
logger.info("\n=== RÉSULTATS DES TESTS ===")
logger.info(f"Test simple: {'RÉUSSI' if test_simple else 'ÉCHEC'}")
logger.info(f"Test JSON: {'RÉUSSI' if test_json else 'ÉCHEC'}")
logger.info("=== FIN DES TESTS ===")
return 0 if test_simple and test_json else 1
if __name__ == "__main__":
sys.exit(main())