File size: 2,341 Bytes
68c1777
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
"""Load and schema-validate all configs at startup (spec P1 refinement).

Invalid entries are reported precisely and skipped — the app never guesses at a
malformed entry, and never rejects a well-formed entry because of its name.
"""

import pathlib

import yaml
from pydantic import ValidationError

from src.schemas import DomainEntry, HardwareProfile, ModelEntry, ProviderEntry

CONFIG_DIR = pathlib.Path(__file__).resolve().parent.parent / "configs"


class Configs:
    def __init__(self):
        self.errors: list[str] = []
        self.models: list[ModelEntry] = self._load_list("models.yaml", "models", ModelEntry)
        self.providers: list[ProviderEntry] = self._load_list("providers.yaml", "providers", ProviderEntry)
        self.domains: list[DomainEntry] = self._load_list("domains.yaml", "domains", DomainEntry)
        self.hardware: list[HardwareProfile] = self._load_list("hardware.yaml", "profiles", HardwareProfile)
        self.limits: dict = self._load_raw("limits.yaml")
        raw_providers = self._load_raw("providers.yaml")
        self.default_provider: str = raw_providers.get("default", self.providers[0].id if self.providers else "")

    def _load_raw(self, fname):
        try:
            with open(CONFIG_DIR / fname) as f:
                return yaml.safe_load(f) or {}
        except Exception as e:  # noqa: BLE001
            self.errors.append(f"{fname}: {e}")
            return {}

    def _load_list(self, fname, key, model_cls):
        raw = self._load_raw(fname)
        out = []
        for i, entry in enumerate(raw.get(key, [])):
            try:
                out.append(model_cls(**entry))
            except ValidationError as e:
                name = entry.get("name") or entry.get("id") or f"#{i}"
                self.errors.append(f"{fname}[{name}]: {e.errors()[0]['msg']} ({e.errors()[0]['loc']})")
        return out

    def model_by_name(self, name):
        return next((m for m in self.models if m.name == name), None)

    def provider_by_id(self, pid):
        return next((p for p in self.providers if p.id == pid), None)

    def domain_by_id(self, did):
        return next((d for d in self.domains if d.id == did), None)


_CONFIGS = None


def get_configs() -> Configs:
    global _CONFIGS
    if _CONFIGS is None:
        _CONFIGS = Configs()
    return _CONFIGS