"""LLM service - Factory for creating LLM instances.""" from typing import Optional from langchain_openai import ChatOpenAI from langchain_mistralai import ChatMistralAI from langchain_core.language_models.chat_models import BaseChatModel from domain.enums import ModelName, ModelProvider from config import settings class LLMService: """Service for managing LLM instances across different providers.""" def __init__(self): """Initialize LLM service.""" self._openai_api_key = settings.openai_api_key self._mistralai_api_key = settings.mistralai_api_key def get_llm( self, model_name: ModelName, temperature: float = 0.7, streaming: bool = False, max_tokens: Optional[int] = None ) -> BaseChatModel: """ Factory method to create an LLM instance based on model name. Args: model_name: Model enum value temperature: Sampling temperature (0.0 to 2.0) streaming: Enable streaming mode max_tokens: Maximum tokens to generate Returns: LLM instance (ChatOpenAI or ChatMistralAI) Raises: ValueError: If model provider is unknown """ provider = model_name.provider if provider == ModelProvider.OPENAI: return self._create_openai_llm( model_name=model_name.value, temperature=temperature, streaming=streaming, max_tokens=max_tokens ) elif provider == ModelProvider.MISTRALAI: return self._create_mistralai_llm( model_name=model_name.value, temperature=temperature, streaming=streaming, max_tokens=max_tokens ) else: raise ValueError(f"Unknown provider: {provider}") def _create_openai_llm( self, model_name: str, temperature: float, streaming: bool, max_tokens: Optional[int] ) -> ChatOpenAI: """Create OpenAI LLM instance.""" return ChatOpenAI( model=model_name, temperature=temperature, streaming=streaming, max_tokens=max_tokens, api_key=self._openai_api_key ) def _create_mistralai_llm( self, model_name: str, temperature: float, streaming: bool, max_tokens: Optional[int] ) -> ChatMistralAI: """Create Mistral AI LLM instance.""" return ChatMistralAI( model=model_name, temperature=temperature, streaming=streaming, max_tokens=max_tokens, mistral_api_key=self._mistralai_api_key ) @staticmethod def list_available_models() -> list[dict]: """ List all available models with their metadata. Returns: List of model information dictionaries """ models = [] # OpenAI models openai_models = [ { "name": ModelName.GPT_5_PRO.value, "provider": "openai", "description": "GPT-4 Pro", # "supports_streaming": True, # "context_window": 128000 }, # { # "name": ModelName.GPT_4_TURBO.value, # "provider": "openai", # "description": "GPT-4 Turbo - Fast and powerful", # "supports_streaming": True, # "context_window": 128000 # }, # { # "name": ModelName.GPT_4.value, # "provider": "openai", # "description": "GPT-4 - High quality", # "supports_streaming": True, # "context_window": 8192 # }, # { # "name": ModelName.GPT_35_TURBO.value, # "provider": "openai", # "description": "GPT-3.5 Turbo - Fast and efficient", # "supports_streaming": True, # "context_window": 16385 # } ] # Mistral AI models mistral_models = [ { "name": ModelName.MISTRAL_LARGE.value, "provider": "mistralai", "description": "Mistral Large", "supports_streaming": True, "context_window": 32000 }, # { # "name": ModelName.MISTRAL_MEDIUM.value, # "provider": "mistralai", # "description": "Mistral Medium - Balanced performance", # "supports_streaming": True, # "context_window": 32000 # }, # { # "name": ModelName.MISTRAL_SMALL.value, # "provider": "mistralai", # "description": "Mistral Small - Fast and efficient", # "supports_streaming": True, # "context_window": 32000 # }, # { # "name": ModelName.MISTRAL_TINY.value, # "provider": "mistralai", # "description": "Mistral Tiny - Ultra-fast", # "supports_streaming": True, # "context_window": 32000 # } ] models.extend(openai_models) models.extend(mistral_models) return models # Singleton instance llm_service = LLMService()