Spaces:
Running
Running
| """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, "") | |