diff --git a/backend/app/services/llm_service.py b/backend/app/services/llm_service.py index 0d47b55b..1dcf6a54 100755 --- a/backend/app/services/llm_service.py +++ b/backend/app/services/llm_service.py @@ -20,25 +20,39 @@ import io # Set up the Gemini API key (client created lazily to avoid event loop issues) GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY', 'AIzaSyAc50jzC3k9K1PmKT1vGFi0sCdhhnqsvl0') _gemini_client = None +_gemini_client_loop = None # Set up OpenAI API key (client created lazily to avoid event loop issues) OPENAI_API_KEY = os.environ.get('OPENAI_API_KEY', 'REDACTED_OPENAI_KEY') _openai_client = None +_openai_client_loop = None def get_gemini_client(): - """Get or create the Gemini client lazily within the running event loop.""" - global _gemini_client - if _gemini_client is None: + """Get or create the Gemini client for the current event loop. + + Recreates the client if the event loop has changed to avoid + 'Future attached to a different loop' errors in ASGI environments. + """ + global _gemini_client, _gemini_client_loop + current_loop = asyncio.get_running_loop() + if _gemini_client is None or _gemini_client_loop is not current_loop: _gemini_client = genai.Client(api_key=GEMINI_API_KEY) + _gemini_client_loop = current_loop return _gemini_client def get_openai_client(): - """Get or create the OpenAI client lazily within the running event loop.""" - global _openai_client - if _openai_client is None: + """Get or create the OpenAI client for the current event loop. + + Recreates the client if the event loop has changed to avoid + 'Future attached to a different loop' errors in ASGI environments. + """ + global _openai_client, _openai_client_loop + current_loop = asyncio.get_running_loop() + if _openai_client is None or _openai_client_loop is not current_loop: _openai_client = AsyncOpenAI(api_key=OPENAI_API_KEY, timeout=600.0) + _openai_client_loop = current_loop return _openai_client # The default model we're using