feat: complete production hardening implementation, specialty canonicalization, google-genai migration, voice reliability, sqlite concurrency, and test suite consolidation
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
"""
|
||||
Providers package.
|
||||
"""
|
||||
|
||||
from app.ai.providers.base import LLMProvider
|
||||
from app.ai.providers.openai import OpenAIProvider
|
||||
from app.ai.providers.gemini import GeminiProvider
|
||||
|
||||
__all__ = ["LLMProvider", "OpenAIProvider", "GeminiProvider"]
|
||||
@@ -0,0 +1,30 @@
|
||||
"""
|
||||
Base LLM Provider interface with hard async timeout enforcement.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class LLMProvider(ABC):
|
||||
"""
|
||||
Abstract LLM Provider interface.
|
||||
Enforces a strict hard timeout (default 4 seconds).
|
||||
"""
|
||||
def __init__(self, timeout_seconds: float = 4.0):
|
||||
self.timeout_seconds = timeout_seconds
|
||||
|
||||
async def generate_response_with_timeout(self, system_prompt: str, user_message: str) -> Optional[str]:
|
||||
try:
|
||||
return await asyncio.wait_for(
|
||||
self._generate_internal(system_prompt, user_message),
|
||||
timeout=self.timeout_seconds
|
||||
)
|
||||
except (asyncio.TimeoutError, Exception) as e:
|
||||
print(f"[{self.__class__.__name__} Failed / Timed out]: {e}")
|
||||
return None
|
||||
|
||||
@abstractmethod
|
||||
async def _generate_internal(self, system_prompt: str, user_message: str) -> Optional[str]:
|
||||
pass
|
||||
@@ -0,0 +1,19 @@
|
||||
"""
|
||||
Gemini LLM Provider.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from app.ai.providers.base import LLMProvider
|
||||
from app.ai.gemini_client import GeminiClient
|
||||
|
||||
|
||||
class GeminiProvider(LLMProvider):
|
||||
def __init__(self, timeout_seconds: float = 4.0):
|
||||
super().__init__(timeout_seconds=timeout_seconds)
|
||||
self.client = GeminiClient()
|
||||
|
||||
async def _generate_internal(self, system_prompt: str, user_message: str) -> Optional[str]:
|
||||
api_key = getattr(self.client, "api_key", None)
|
||||
if not api_key or api_key in ["your_gemini_key", "your_gemini_api_key", ""]:
|
||||
return None
|
||||
return await self.client.generate_response(system_prompt, user_message)
|
||||
@@ -0,0 +1,19 @@
|
||||
"""
|
||||
OpenAI LLM Provider.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
from app.ai.providers.base import LLMProvider
|
||||
from app.ai.openai_client import OpenAIClient
|
||||
|
||||
|
||||
class OpenAIProvider(LLMProvider):
|
||||
def __init__(self, timeout_seconds: float = 4.0):
|
||||
super().__init__(timeout_seconds=timeout_seconds)
|
||||
self.client = OpenAIClient()
|
||||
|
||||
async def _generate_internal(self, system_prompt: str, user_message: str) -> Optional[str]:
|
||||
api_key = getattr(self.client, "api_key", None)
|
||||
if not api_key or api_key in ["your_openai_key", "your_openai_api_key", ""]:
|
||||
return None
|
||||
return await self.client.generate_response(system_prompt, user_message)
|
||||
Reference in New Issue
Block a user