themis-eval 0.2.3__py3-none-any.whl → 1.0.0__py3-none-any.whl

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.
Files changed (37) hide show
  1. themis/__init__.py +5 -2
  2. themis/_version.py +14 -1
  3. themis/api.py +83 -145
  4. themis/backends/storage.py +5 -0
  5. themis/cli/commands/info.py +2 -11
  6. themis/cli/main.py +231 -40
  7. themis/comparison/engine.py +7 -13
  8. themis/core/entities.py +4 -0
  9. themis/evaluation/metric_pipeline.py +12 -0
  10. themis/evaluation/pipeline.py +22 -0
  11. themis/evaluation/pipelines/__init__.py +4 -0
  12. themis/evaluation/pipelines/composable_pipeline.py +55 -0
  13. themis/evaluation/pipelines/standard_pipeline.py +16 -0
  14. themis/experiment/__init__.py +2 -2
  15. themis/experiment/cache_manager.py +15 -1
  16. themis/experiment/definitions.py +1 -1
  17. themis/experiment/orchestrator.py +21 -11
  18. themis/experiment/share.py +264 -0
  19. themis/experiment/storage.py +345 -298
  20. themis/generation/router.py +22 -4
  21. themis/generation/runner.py +16 -1
  22. themis/presets/benchmarks.py +602 -17
  23. themis/server/app.py +38 -26
  24. themis/session.py +125 -0
  25. themis/specs/__init__.py +7 -0
  26. themis/specs/execution.py +26 -0
  27. themis/specs/experiment.py +33 -0
  28. themis/specs/storage.py +18 -0
  29. themis/storage/__init__.py +6 -0
  30. themis/storage/experiment_storage.py +7 -0
  31. {themis_eval-0.2.3.dist-info → themis_eval-1.0.0.dist-info}/METADATA +47 -34
  32. {themis_eval-0.2.3.dist-info → themis_eval-1.0.0.dist-info}/RECORD +35 -28
  33. {themis_eval-0.2.3.dist-info → themis_eval-1.0.0.dist-info}/WHEEL +1 -1
  34. themis/experiment/builder.py +0 -151
  35. themis/experiment/export_csv.py +0 -159
  36. {themis_eval-0.2.3.dist-info → themis_eval-1.0.0.dist-info}/licenses/LICENSE +0 -0
  37. {themis_eval-0.2.3.dist-info → themis_eval-1.0.0.dist-info}/top_level.txt +0 -0
@@ -2,22 +2,40 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Mapping
5
+ from typing import Mapping, Tuple, Union
6
6
 
7
7
  from themis.core import entities as core_entities
8
8
  from themis.interfaces import ModelProvider
9
9
 
10
10
 
11
+ ProviderKey = Union[str, Tuple[str, str]]
12
+
13
+
14
+ def _model_key(provider: str, identifier: str) -> str:
15
+ return f"{provider}:{identifier}"
16
+
17
+
11
18
  class ProviderRouter(ModelProvider):
12
19
  """Dispatches generation tasks to concrete providers by model identifier."""
13
20
 
14
- def __init__(self, providers: Mapping[str, ModelProvider]):
15
- self._providers = dict(providers)
21
+ def __init__(self, providers: Mapping[ProviderKey, ModelProvider]):
22
+ normalized: dict[str, ModelProvider] = {}
23
+
24
+ for key, provider in providers.items():
25
+ if isinstance(key, tuple):
26
+ provider_name, model_id = key
27
+ normalized[_model_key(provider_name, model_id)] = provider
28
+ else:
29
+ normalized[str(key)] = provider
30
+
31
+ self._providers = normalized
16
32
 
17
33
  def generate(
18
34
  self, task: core_entities.GenerationTask
19
35
  ) -> core_entities.GenerationRecord: # type: ignore[override]
20
- provider = self._providers.get(task.model.identifier)
36
+ provider = self._providers.get(_model_key(task.model.provider, task.model.identifier))
37
+ if provider is None:
38
+ provider = self._providers.get(task.model.identifier)
21
39
  if provider is None:
22
40
  known = ", ".join(sorted(self._providers)) or "<none>"
23
41
  raise RuntimeError(
@@ -26,6 +26,7 @@ class GenerationRunner:
26
26
  [core_entities.GenerationTask], strategies.GenerationStrategy
27
27
  ]
28
28
  | None = None,
29
+ execution_backend: object | None = None,
29
30
  max_parallel: int = 1,
30
31
  max_retries: int = 3,
31
32
  retry_initial_delay: float = 0.5,
@@ -36,6 +37,7 @@ class GenerationRunner:
36
37
  self._strategy_resolver = strategy_resolver or (
37
38
  lambda task: strategies.SingleAttemptStrategy()
38
39
  )
40
+ self._execution_backend = execution_backend
39
41
  self._max_parallel = max(1, max_parallel)
40
42
  self._max_retries = max(1, int(max_retries))
41
43
  self._retry_initial_delay = max(0.0, retry_initial_delay)
@@ -53,7 +55,20 @@ class GenerationRunner:
53
55
  return
54
56
 
55
57
  logger.info(f"Runner: Starting execution of {len(task_list)} tasks with {self._max_parallel} workers")
56
-
58
+
59
+ if self._execution_backend is not None:
60
+ logger.info("Runner: Using custom execution backend")
61
+ backend = self._execution_backend
62
+ try:
63
+ for result in backend.map(
64
+ self._execute_task, task_list, max_workers=self._max_parallel
65
+ ):
66
+ yield result
67
+ except Exception as e:
68
+ logger.error(f"Runner: Execution backend failed: {e}")
69
+ raise
70
+ return
71
+
57
72
  if self._max_parallel <= 1:
58
73
  logger.info("Runner: Using sequential execution (1 worker)")
59
74
  for i, task in enumerate(task_list, 1):