File size: 3,196 Bytes
d18fdd2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# src/chimera/api_clients/gemini_client.py
import google.generativeai as genai
from ..config import GEMINI_API_KEY, GEMINI_MODEL_NAME
from ..utils.logging_config import logger
import asyncio

# Configure the Gemini client globally (or instantiate as needed)
if GEMINI_API_KEY:
    genai.configure(api_key=GEMINI_API_KEY)
else:
    logger.error("Gemini API Key not configured!")
    # Depending on your flow, you might raise an error or handle this state

async def generate_analysis(prompt: str, retries=3, delay=5) -> str:
    """
    Generates content using the Gemini API with async handling and retries.
    """
    if not GEMINI_API_KEY:
        return "Error: Gemini API Key not configured."

    try:
        model = genai.GenerativeModel(GEMINI_MODEL_NAME)
        # Note: The current google-generativeai SDK might not be fully async yet.
        # If performance becomes an issue, consider running sync calls
        # in an executor pool using asyncio.to_thread.
        # For now, we'll call it directly but within an async function context.

        logger.info(f"Sending prompt to Gemini (first ~100 chars): {prompt[:100]}...")

        # Placeholder for potential future truly async call
        # response = await model.generate_content_async(prompt)

        # Using run_in_executor for the synchronous call
        loop = asyncio.get_running_loop()
        for attempt in range(retries):
            try:
                # Wrap the synchronous call in run_in_executor
                response = await loop.run_in_executor(
                    None,  # Use default executor
                    lambda: model.generate_content(prompt)
                )
                logger.info("Received response from Gemini.")
                # Basic check for blocked content or empty response
                if not response.parts:
                     # Handle safety flags/blocks if necessary
                     if response.prompt_feedback.block_reason:
                         logger.warning(f"Gemini prompt blocked: {response.prompt_feedback.block_reason}")
                         return f"Error: Content generation blocked by safety filters ({response.prompt_feedback.block_reason})."
                     else:
                         logger.warning("Gemini returned empty response.")
                         return "Error: Gemini returned an empty response."

                return response.text

            except Exception as e: # Catch broad exceptions from the SDK
                logger.error(f"Gemini API call attempt {attempt + 1} failed: {e}")
                if attempt < retries - 1:
                    await asyncio.sleep(delay * (attempt + 1)) # Exponential backoff
                else:
                    logger.error("Gemini API call failed after multiple retries.")
                    return f"Error: Failed to get response from Gemini after {retries} attempts. ({e})"

    except Exception as e:
        logger.exception("Critical error during Gemini generation setup or execution.")
        return f"Error: An unexpected error occurred while contacting Gemini: {e}"

    return "Error: Unexpected exit from generate_analysis function." # Should not happen