import os import sys import json from google import genai from google.genai.errors import APIError # Importation de genai.types.Part pour construire la partie fichier from google.genai.types import Part from config import GEMINI_API_KEY_INTERNAL, GEMINI_MODEL_NAME, DEFAULT_MAX_TOKENS, DEFAULT_TEMPERATURE # --- Configuration du Client Gemini --- # Le prompt système (System Instruction) pour guider le modèle SYSTEM_PROMPT = "Vous êtes un assistant IA appler Ernestmind et tu as ete entrener pas l'entreprise ErnestMind AI, expert en programmation, développement web (full-stack), et résolution de problèmes techniques. Répondez de manière concise, précise et professionnelle selon la langue utilisateur, en utilisant la mise en forme Markdown appropriée (blocs de code si nécessaire)." # Instance du client et indicateur de chargement client = None MODEL_LOADED_SUCCESSFULLY = False def get_model_instance(): """ Initialise ou retourne l'instance du client Gemini. """ global client, MODEL_LOADED_SUCCESSFULLY if client is None: try: # Utilisation de la clé interne pour initialiser le client client = genai.Client(api_key=GEMINI_API_KEY_INTERNAL) MODEL_LOADED_SUCCESSFULLY = True print(f"INFO: Client Gemini initialisé. Modèle configuré pour utiliser {GEMINI_MODEL_NAME}.") except Exception as e: print(f"ALERTE: Échec de l'initialisation du client Gemini: {e}", file=sys.stderr) MODEL_LOADED_SUCCESSFULLY = False return client # Initialisation du client lors du chargement du module get_model_instance() def generate_code_response(prompt: str, user_id: str, file_data: tuple[bytes, str] | None = None, max_tokens: int = DEFAULT_MAX_TOKENS, temperature: float = DEFAULT_TEMPERATURE): """ Génère une réponse en streaming en utilisant l'API Gemini, supportant le multimodal. file_data est un tuple (contenu_binaire: bytes, mime_type: str) ou None. """ if not MODEL_LOADED_SUCCESSFULLY or client is None: yield "Erreur: La clé API Gemini est manquante ou invalide. Le service est désactivé." return # Configuration de la requête config = { "systemInstruction": SYSTEM_PROMPT, "temperature": temperature, "maxOutputTokens": max_tokens, } # --- Construction du contenu multimodal --- contents = [] if file_data: file_bytes, mime_type = file_data # Créer la partie fichier pour l'API Gemini try: file_part = Part.from_bytes(data=file_bytes, mime_type=mime_type) contents.append(file_part) except Exception as e: # Si la création de la 'Part' échoue (ex: format non supporté) error_message = f"Erreur de traitement du fichier: {str(e)}. Le fichier n'a pas été envoyé au modèle." print(f"Erreur Fichier (user_id: {user_id}): {error_message}", file=sys.stderr) # On laisse le prompt texte passer, mais on log l'erreur # Ajouter le prompt texte contents.append({"role": "user", "parts": [{"text": prompt}]}) # Sécurité: le contenu ne doit pas être vide if not contents: yield "Erreur: Le contenu de la requête (prompt ou fichier) est vide." return try: # --- Appel à l'API STREAMING --- response_stream = client.models.generate_content_stream( model=GEMINI_MODEL_NAME, contents=contents, # Contents contient maintenant le fichier et le texte config=config, ) # Itérer sur le flux et retourner chaque morceau de texte (token) for chunk in response_stream: if chunk.text: yield chunk.text except APIError as e: error_message = f"Erreur de l'API Gemini: {e.message}" print(f"Erreur API (user_id: {user_id}): {error_message}", file=sys.stderr) yield f"Erreur: {error_message}" except Exception as e: error_message = f"Erreur de streaming inattendue: {str(e)}" print(f"Erreur Inattendue (user_id: {user_id}): {error_message}", file=sys.stderr) yield f"Erreur: {error_message}"