# modules/gemini_handler.py """ Dedicated module for all interactions with the Google Gemini API. It initializes and configures the models, and provides clean, async functions for both text and multi-modal (vision) generation, including robust error handling. """ import google.generativeai as genai from PIL import Image # ============================================================================== # CORRECTED LINE: The import path now correctly points to api_clients/config.py from api_clients.config import GEMINI_API_KEY # ============================================================================== # --- Configuration --- if not GEMINI_API_KEY: raise ValueError("FATAL: GEMINI_API_KEY not found. Please set it in your environment/secrets.") genai.configure(api_key=GEMINI_API_KEY) # Configuration for predictable, factual responses generation_config = { "temperature": 0.1, "top_p": 0.95, "top_k": 40, "max_output_tokens": 8192, # Increased for detailed reports } # Safety settings are relaxed slightly for medical context, but still block high-risk content. # This prevents the model from refusing to discuss health topics. safety_settings = [ {"category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"}, {"category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_MEDIUM_AND_ABOVE"}, {"category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_ONLY_HIGH"}, {"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_MEDIUM_AND_ABOVE"}, ] # --- Model Initialization --- try: # Model for text-based tasks (synthesis, extraction) text_model = genai.GenerativeModel( model_name="gemini-1.5-flash-latest", # Use a fast and capable model generation_config=generation_config, safety_settings=safety_settings ) # Model for multi-modal tasks (analyzing medical images) vision_model = genai.GenerativeModel( model_name="gemini-1.5-flash-latest", # Vision models are also great at text generation_config=generation_config, safety_settings=safety_settings ) except Exception as e: raise RuntimeError(f"Failed to initialize Gemini models: {e}") async def generate_text_response(prompt: str) -> str: """ Calls the Gemini text model with a given prompt. Args: prompt (str): The detailed prompt for the AI. Returns: str: The AI's generated text response, or an error message. """ try: response = await text_model.generate_content_async(prompt) if not response.parts: return "Error: The AI response was blocked, possibly due to safety filters or lack of content. Please rephrase." return response.text except Exception as e: print(f"Gemini API Error (Text): {e}") return f"An error occurred while communicating with the AI model. Details: {e}" async def analyze_image_with_text(prompt: str, image: Image.Image) -> str: """ Calls the Gemini vision model with a text prompt and an image. Args: prompt (str): The text prompt to guide the image analysis. image (Image.Image): The PIL image to be analyzed. Returns: str: The AI's generated text analysis, or an error message. """ try: response = await vision_model.generate_content_async([prompt, image]) if not response.parts: return "Error: The AI response for the image was blocked. The image may violate safety policies." return response.text except Exception as e: print(f"Gemini API Error (Vision): {e}") return f"An error occurred while analyzing the image with the AI. Details: {e}"