PERI-AI-dev / src /config_loader.py
Nelly-43's picture
Update src/config_loader.py
b1b0945 verified
Raw
History Blame Contribute Delete
2.02 kB
"""Loads config.yaml and .env, exposes settings as a dict."""
import os
from pathlib import Path
import yaml
from dotenv import load_dotenv
_ENV_KEY_MAP = {
"openai": "OPENAI_API_KEY",
"anthropic": "ANTHROPIC_API_KEY",
"gemini": "GEMINI_API_KEY",
"hugging-face": "HF_API_KEY",
}
def load_config(config_path: str = None) -> dict:
if config_path is None:
config_path = Path(__file__).resolve().parent.parent / "config.yaml"
env_path = Path(config_path).resolve().parent / ".env"
if env_path.exists():
load_dotenv(str(env_path))
if not Path(config_path).exists():
raise FileNotFoundError(
f"Config file not found: {config_path}\n"
"Run 'python setup.py' first to generate config.yaml and .env."
)
with open(config_path, "r", encoding="utf-8") as f:
cfg = yaml.safe_load(f) or {}
if not isinstance(cfg, dict):
raise ValueError(
f"Config file must contain a YAML mapping (dict), got {type(cfg).__name__}. "
"Run 'python setup.py' to regenerate config.yaml."
)
# Normalize None-valued sections to empty dicts so chained .get() never
# fails with AttributeError (e.g. `llm:` with no sub-keys → None).
# Recurse into nested dicts so `paths:\n vector_db:` also gets normalized.
def _normalize_nulls(d):
for key in list(d.keys()):
if d[key] is None:
d[key] = {}
elif isinstance(d[key], dict):
_normalize_nulls(d[key])
_normalize_nulls(cfg)
for provider, env_var in _ENV_KEY_MAP.items():
env_val = os.environ.get(env_var)
if env_val:
cfg.setdefault("api_keys", {})[provider] = env_val
return cfg
def get_api_key(cfg: dict, provider: str) -> str:
env_var = _ENV_KEY_MAP.get(provider)
if env_var:
env_val = os.environ.get(env_var)
if env_val:
return env_val
return cfg.get("api_keys", {}).get(provider, "")