HowdenLLM 1.6.0__tar.gz → 1.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,7 +9,6 @@ import os
9
9
  import json
10
10
  import re
11
11
 
12
- load_dotenv()
13
12
  class EmptyFileException(Exception):
14
13
  """Exception raised for empty 'filepath' argument"""
15
14
  def __init__(self, fp):
@@ -46,13 +45,13 @@ class LLM:
46
45
  if k not in ("self", "__class__", "__len__")
47
46
  }
48
47
 
49
-
48
+ load_dotenv()
50
49
  self.provider_name = provider_and_model.split(":")[0].lower()
51
50
  self.model = provider_and_model.split(":")[1]
52
51
  self.template = template
53
52
  self.name: str = name
54
53
  self.system: str = system
55
- self.client = ProviderFactory.create(self.provider_name)
54
+ self.provider = ProviderFactory.create(self.provider_name)
56
55
  self.use_web_search_tool = use_web_search_tool
57
56
  self.hashed = self.compute_hash(self.input_params)
58
57
 
@@ -88,18 +87,18 @@ class LLM:
88
87
  input_tokens = self._count_tokens(input_text)
89
88
 
90
89
  # --- run model ---
91
- output = self.client.complete(self.system, prompt, self.model, self.use_web_search_tool)
90
+ output = self.provider.complete(self.system, prompt, self.model, self.use_web_search_tool)
92
91
 
93
92
  # --- count output tokens ---
94
- #output_tokens = self._count_tokens(output)
93
+ output_tokens = self._count_tokens(output)
95
94
 
96
95
  # --- update totals ---
97
96
  self.total_input_tokens += input_tokens
98
- #self.total_output_tokens += output_tokens
97
+ self.total_output_tokens += output_tokens
99
98
  self.total_runs += 1
100
99
  print(f"[{self.name or 'LLM'}] "
101
100
  f"Input tokens: {input_tokens}, "
102
- #f"Output tokens: {output_tokens}, "
101
+ f"Output tokens: {output_tokens}, "
103
102
  f"Total_input: {self.total_input_tokens}, "
104
103
  f"Total_output: {self.total_output_tokens}, "
105
104
  f"Total_input_average: {round(self.total_input_tokens / self.total_runs, 2)}, "
@@ -0,0 +1,4 @@
1
+ class KnownProviders:
2
+ OpenAI = 'openai'
3
+ HuggingFace = 'huggingface'
4
+ Anthropic = 'anthropic'
@@ -1,15 +1,13 @@
1
1
  from abc import ABC
2
2
  from HowdenLLM.providers.base_provider import BaseProvider
3
3
  from anthropic import Anthropic
4
- import os
5
- from dotenv import load_dotenv
4
+ from .known_providers import KnownProviders
6
5
 
7
6
  class AnthropicProvider(BaseProvider, ABC):
8
- provider = "anthropic"
7
+ provider = KnownProviders.Anthropic
9
8
 
10
- def __init__(self):
11
- load_dotenv()
12
- self.client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
9
+ def __init__(self,client: Anthropic):
10
+ self.client = client
13
11
 
14
12
  def complete(self, system: str, prompt: str, model: str, use_web_search_tool: bool) -> str:
15
13
  if model in ["claude-opus-4-6","claude-sonnet-4-6"]:
@@ -1,23 +1,16 @@
1
1
  import importlib
2
2
  import inspect
3
3
  import pkgutil
4
-
4
+ import os
5
5
  from pathlib import Path
6
6
  from .provider_meta import ProviderMeta
7
-
7
+ from dotenv import load_dotenv
8
+ from .known_providers import KnownProviders
8
9
 
9
10
  class ProviderFactory:
10
11
  """Factory that dynamically loads provider modules and instantiates them."""
11
12
  clients_alive = {}
12
- providers: dict = None
13
-
14
- @staticmethod
15
- def get_providers() -> dict:
16
- if ProviderFactory.providers is None:
17
- ProviderFactory._load_all_providers()
18
- ProviderFactory.providers = ProviderMeta.get_registry()
19
-
20
- return ProviderFactory.providers
13
+ openai_client = None
21
14
 
22
15
  @staticmethod
23
16
  def _load_all_providers():
@@ -34,9 +27,9 @@ class ProviderFactory:
34
27
  @staticmethod
35
28
  def create(provider_name: str):
36
29
  """Instantiate a provider by name using the registry."""
37
- #ProviderFactory._load_all_providers()
38
- providers = ProviderFactory.get_providers()
30
+ ProviderFactory._load_all_providers()
39
31
 
32
+ providers = ProviderMeta.get_registry()
40
33
  key = provider_name.lower()
41
34
 
42
35
  if key not in providers:
@@ -46,7 +39,15 @@ class ProviderFactory:
46
39
  )
47
40
 
48
41
  if key not in ProviderFactory.clients_alive.keys():
49
- ProviderFactory.clients_alive[key] = providers[key]()
50
-
51
- return ProviderFactory.clients_alive[key]
52
-
42
+ load_dotenv()
43
+ if key == KnownProviders.OpenAI:
44
+ from openai import OpenAI
45
+ ProviderFactory.clients_alive[key] = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
46
+ elif key == KnownProviders.HuggingFace:
47
+ from huggingface_hub import InferenceClient
48
+ ProviderFactory.clients_alive[key] = InferenceClient(token=os.getenv("HUGGINGFACE_API_KEY"))
49
+ elif key == KnownProviders.Anthropic:
50
+ from anthropic import Anthropic
51
+ ProviderFactory.clients_alive[key] = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
52
+
53
+ return providers[key](ProviderFactory.clients_alive[key])
@@ -2,15 +2,14 @@ from HowdenLLM.providers.base_provider import BaseProvider
2
2
  from dotenv import load_dotenv
3
3
  import os
4
4
  from huggingface_hub import InferenceClient
5
-
5
+ from .known_providers import KnownProviders
6
6
 
7
7
 
8
8
  class HuggingFaceProvider(BaseProvider):
9
- provider = 'huggingface'
9
+ provider = KnownProviders.HuggingFace
10
10
 
11
- def __init__(self):
12
- load_dotenv()
13
- self.client = InferenceClient(token=os.getenv("HUGGINGFACE_API_KEY"))
11
+ def __init__(self,client: InferenceClient):
12
+ self.client = client
14
13
 
15
14
  def complete(self, system: str, prompt: str, model: str, use_web_search_tool: bool) -> str:
16
15
  full_prompt = f"[System]: {system}\n[User]: {prompt}\n"
@@ -0,0 +1,34 @@
1
+ from abc import ABC
2
+ from HowdenLLM.providers.base_provider import BaseProvider
3
+ from openai import OpenAI
4
+ from .known_providers import KnownProviders
5
+
6
+ class OpenAIProvider(BaseProvider, ABC):
7
+ provider = KnownProviders.OpenAI
8
+
9
+ def __init__(self,client: OpenAI):
10
+ self.client = client
11
+
12
+ def complete(self, system: str, prompt: str, model: str, use_web_search_tool: bool) -> str:
13
+
14
+ if use_web_search_tool:
15
+ tools = [
16
+ { "type": "web_search" }
17
+ ]
18
+ else:
19
+ tools = None
20
+
21
+ if model in ["gpt-5", "gpt-5.2", "gpt-5-mini", "gpt-5.4-mini", "gpt-5-nano"]:
22
+ response = self.client.responses.create(
23
+ model=model,
24
+ input=[
25
+ {"role": "system", "content": system},
26
+ {"role": "user", "content": prompt}
27
+ ],
28
+ tools=tools,
29
+ max_output_tokens=16000
30
+ )
31
+ else:
32
+ raise Exception(f"Unsupported model: {model}")
33
+
34
+ return response.output_text
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: HowdenLLM
3
- Version: 1.6.0
3
+ Version: 1.6.2
4
4
  Summary: A simple configuration manager with Pydantic and JSON export.
5
5
  License: MIT
6
6
  Keywords: config,configuration,pydantic,json
@@ -14,7 +14,7 @@ build-backend = "poetry.core.masonry.api"
14
14
 
15
15
  [tool.poetry]
16
16
  name = "HowdenLLM"
17
- version = "1.6.0"
17
+ version = "1.6.2"
18
18
  description = "A simple configuration manager with Pydantic and JSON export."
19
19
  authors = [ "JesperThoftIllemannJ <jesper.jaeger@howdendanmark.dk>",]
20
20
  readme = "README.md"
@@ -1,2 +0,0 @@
1
- class KnownProviders:
2
- Anthropic = 'anthropic'
@@ -1,40 +0,0 @@
1
- from abc import ABC
2
- from HowdenLLM.providers.base_provider import BaseProvider
3
- from openai import OpenAI, AsyncOpenAI
4
- import os
5
- from dotenv import load_dotenv
6
- import asyncio
7
-
8
-
9
- SEMAPHORE = asyncio.Semaphore(3)
10
-
11
- class OpenAIProvider(BaseProvider, ABC):
12
- provider = "openai"
13
-
14
- def __init__(self):
15
- load_dotenv()
16
- self.client = AsyncOpenAI(api_key=os.getenv("OPENAI_API_KEY"))
17
-
18
- async def complete(self, system: str, prompt: str, model: str, use_web_search_tool: bool) -> str:
19
- async with SEMAPHORE:
20
- if use_web_search_tool:
21
- tools = [
22
- { "type": "web_search" }
23
- ]
24
- else:
25
- tools = None
26
-
27
- if model in ["gpt-5", "gpt-5-mini", "gpt-5-nano"]:
28
- response = await self.client.responses.create(
29
- model=model,
30
- input=[
31
- {"role": "system", "content": system},
32
- {"role": "user", "content": prompt}
33
- ],
34
- tools=tools,
35
- max_output_tokens=16000
36
- )
37
- else:
38
- raise Exception(f"Unsupported model: {model}")
39
-
40
- return response.output_text
File without changes