/ src / llm_provider.py
llm_provider.py
  1  """
  2  Generic LLM Provider - Supports Multiple LLMs
  3  
  4  Supports:
  5  - OpenAI (GPT-4, GPT-3.5, GPT-4o-mini)
  6  - Anthropic Claude (Claude 3 Opus, Sonnet, Haiku)
  7  - Google Gemini (Gemini 2.5 Pro, 1.5 Pro, 1.5 Flash)
  8  - Ollama (Local models: qwen3, llama3, mistral, , etc.)
  9  """
 10  
 11  from langchain_core.language_models import BaseChatModel
 12  from langchain_openai import ChatOpenAI
 13  from langchain_anthropic import ChatAnthropic
 14  from langchain_google_genai import ChatGoogleGenerativeAI
 15  from langchain_community.chat_models import ChatOllama
 16  from pydantic import SecretStr
 17  import os
 18  from enum import Enum
 19  
 20  
 21  # ============================================================================
 22  # LLM PROVIDER ENUM
 23  # ============================================================================
 24  
 25  class LLMProvider(str, Enum):
 26      """Supported LLM providers"""
 27      OPENAI = "openai"
 28      ANTHROPIC = "anthropic"
 29      GEMINI = "gemini"
 30      OLLAMA = "ollama"
 31  
 32  # ============================================================================
 33  # LLM FACTORY
 34  # ============================================================================
 35  
 36  class LLMFactory:
 37      """
 38      Factory class to create LLM instances based on provider
 39      """
 40  
 41      @staticmethod
 42      def create_llm(
 43          provider: str = None,
 44          model: str = None,
 45          temperature: float = 0.3,
 46          max_tokens: int = 1000,
 47          api_key: str = None,
 48          base_url: str = None,
 49          **kwargs
 50      ) -> BaseChatModel:
 51          """
 52          Create an LLM instance based on provider
 53  
 54          Args:
 55              provider: LLM provider (openai, anthropic, gemini, ollama, mock)
 56              model: Model name
 57              temperature: Temperature setting (0-1)
 58              max_tokens: Maximum tokens in response
 59              api_key: API key for the provider
 60              base_url: Base URL for API (for Ollama or custom endpoints)
 61              **kwargs: Additional provider-specific parameters
 62  
 63          Returns:
 64              Configured LLM instance
 65          """
 66          # Get provider from environment if not specified
 67          if provider is None:
 68              provider = os.getenv("LLM_PROVIDER", "openai").lower()
 69  
 70          provider = provider.lower()
 71  
 72          # Create LLM based on provider
 73          if provider == LLMProvider.OPENAI:
 74              return LLMFactory._create_openai(model, temperature, max_tokens, api_key, **kwargs)
 75  
 76          elif provider == LLMProvider.ANTHROPIC:
 77              return LLMFactory._create_anthropic(model, temperature, max_tokens, api_key, **kwargs)
 78  
 79          elif provider == LLMProvider.GEMINI:
 80              return LLMFactory._create_gemini(model, temperature, max_tokens, api_key, **kwargs)
 81  
 82          elif provider == LLMProvider.OLLAMA:
 83              return LLMFactory._create_ollama(model, temperature, max_tokens, base_url, **kwargs)
 84  
 85          else:
 86              raise ValueError(f"Unsupported LLM provider: {provider}")
 87  
 88      @staticmethod
 89      def _create_openai(
 90          model: str = None,
 91          temperature: float = 0.3,
 92          max_tokens: int = 1000,
 93          api_key: str = None,
 94          **kwargs
 95      ) -> ChatOpenAI:
 96          """Create OpenAI LLM instance"""
 97          model = model or os.getenv("OPENAI_MODEL", "gpt-4o-mini")
 98          api_key = api_key or os.getenv("OPENAI_API_KEY")
 99  
100          llm_kwargs = {
101              "model": model,
102              "temperature": temperature,
103              "max_tokens": max_tokens,
104          }
105  
106          if api_key:
107              llm_kwargs["api_key"] = SecretStr(api_key)
108  
109          # Add any additional kwargs
110          llm_kwargs.update(kwargs)
111  
112          return ChatOpenAI(**llm_kwargs)
113  
114      @staticmethod
115      def _create_anthropic(
116          model: str = None,
117          temperature: float = 0.3,
118          max_tokens: int = 1000,
119          api_key: str = None,
120          **kwargs
121      ) -> ChatAnthropic:
122          """Create Anthropic Claude LLM instance"""
123          model = model or os.getenv("ANTHROPIC_MODEL", "claude-3-5-sonnet-20241022")
124          api_key = api_key or os.getenv("ANTHROPIC_API_KEY")
125  
126          llm_kwargs = {
127              "model": model,
128              "temperature": temperature,
129              "max_tokens": max_tokens,
130          }
131  
132          if api_key:
133              llm_kwargs["api_key"] = SecretStr(api_key)
134  
135          # Add any additional kwargs
136          llm_kwargs.update(kwargs)
137  
138          return ChatAnthropic(**llm_kwargs)
139  
140      @staticmethod
141      def _create_gemini(
142          model: str = None,
143          temperature: float = 0.3,
144          max_tokens: int = 1000,
145          api_key: str = None,
146          **kwargs
147      ) -> ChatGoogleGenerativeAI:
148          """Create Google Gemini LLM instance"""
149          model = model or os.getenv("GEMINI_MODEL", "gemini-2.5-pro")
150          api_key = api_key or os.getenv("GEMINI_API_KEY") or os.getenv("GOOGLE_API_KEY")
151  
152          llm_kwargs = {
153              "model": model,
154              "temperature": temperature,
155              "max_tokens": max_tokens,
156          }
157  
158          if api_key:
159              llm_kwargs["google_api_key"] = api_key
160  
161          # Add any additional kwargs
162          llm_kwargs.update(kwargs)
163  
164          return ChatGoogleGenerativeAI(**llm_kwargs)
165  
166      @staticmethod
167      def _create_ollama(
168          model: str = None,
169          temperature: float = 0.3,
170          max_tokens: int = 1000,
171          base_url: str = None,
172          **kwargs
173      ) -> ChatOllama:
174          """Create Ollama (local) LLM instance"""
175          model = model or os.getenv("OLLAMA_MODEL", "qwen3:8b")
176          base_url = base_url or os.getenv("OLLAMA_BASE_URL", "http://localhost:11434")
177  
178          llm_kwargs = {
179              "model": model,
180              "temperature": temperature,
181              "base_url": base_url,
182          }
183  
184          # Add any additional kwargs
185          llm_kwargs.update(kwargs)
186  
187          return ChatOllama(**llm_kwargs)
188  
189  
190  # ============================================================================
191  # CONVENIENCE FUNCTIONS
192  # ============================================================================
193  
194  def create_extraction_llm(
195      provider: str = None,
196      model: str = None,
197      api_key: str = None
198  ) -> BaseChatModel:
199      """
200      Create LLM optimized for data extraction
201  
202      Args:
203          provider: LLM provider (openai, anthropic, ollama, mock)
204          model: Specific model name (optional)
205          api_key: API key (optional, uses env var if not provided)
206      """
207      return LLMFactory.create_llm(
208          provider=provider,
209          model=model,
210          temperature=0.2,
211          max_tokens=500,
212          api_key=api_key
213      )
214  
215  
216  def create_job_skills_llm(
217      provider: str = None,
218      model: str = None,
219      api_key: str = None
220  ) -> BaseChatModel:
221      """
222      Create LLM optimized for job skills extraction
223  
224      Args:
225          provider: LLM provider (openai, anthropic, ollama, mock)
226          model: Specific model name (optional)
227          api_key: API key (optional, uses env var if not provided)
228      """
229      return LLMFactory.create_llm(
230          provider=provider,
231          model=model,
232          temperature=0.0,
233          max_tokens=600,
234          api_key=api_key
235      )
236  
237  
238  def create_summary_llm(
239      provider: str = None,
240      model: str = None,
241      api_key: str = None
242  ) -> BaseChatModel:
243      """
244      Create LLM optimized for summarization
245  
246      Args:
247          provider: LLM provider (openai, anthropic, ollama, mock)
248          model: Specific model name (optional)
249          api_key: API key (optional, uses env var if not provided)
250      """
251      return LLMFactory.create_llm(
252          provider=provider,
253          model=model,
254          temperature=0.5,
255          max_tokens=300,
256          api_key=api_key
257      )
258  
259  
260  def create_evaluation_llm(
261      provider: str = None,
262      model: str = None,
263      api_key: str = None
264  ) -> BaseChatModel:
265      """
266      Create LLM optimized for evaluation
267  
268      Args:
269          provider: LLM provider (openai, anthropic, ollama, mock)
270          model: Specific model name (optional)
271          api_key: API key (optional, uses env var if not provided)
272      """
273      return LLMFactory.create_llm(
274          provider=provider,
275          model=model,
276          temperature=0.4,
277          max_tokens=600,
278          api_key=api_key
279      )
280  
281  
282  # ============================================================================
283  # USAGE EXAMPLES
284  # ============================================================================
285  
286  """
287  Example 1: Using OpenAI (Default)
288  ----------------------------------
289  llm = create_summary_llm()
290  # or
291  llm = create_summary_llm(provider="openai", model="gpt-4")
292  
293  
294  Example 2: Using Anthropic Claude
295  ----------------------------------
296  llm = create_summary_llm(
297      provider="anthropic",
298      model="claude-3-5-sonnet-20241022",
299      api_key="your-anthropic-key"
300  )
301  
302  
303  Example 3: Using Google Gemini
304  -------------------------------
305  llm = create_summary_llm(
306      provider="gemini",
307      model="gemini-2.5-pro",
308      api_key="your-google-api-key"
309  )
310  
311  
312  Example 4: Using Ollama (Local, Free)
313  --------------------------------------
314  llm = create_summary_llm(
315      provider="ollama",
316      model="qwen3:8b"
317  )
318  
319  
320  Example 6: Using Environment Variables
321  ---------------------------------------
322  # Set in .env:
323  # LLM_PROVIDER=gemini
324  # GEMINI_API_KEY=your-key
325  # GEMINI_MODEL=gemini-2.5-pro
326  
327  llm = create_summary_llm()  # Automatically uses env vars
328  
329  
330  Example 7: Custom Configuration
331  --------------------------------
332  llm = LLMFactory.create_llm(
333      provider="gemini",
334      model="gemini-1.5-pro",
335      temperature=0.7,
336      max_tokens=2000,
337      top_p=0.9
338  )
339  """