From 9f7fbc2c86f0f0aae7e77c63649f4ce08c3035da Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Tue, 3 Feb 2026 01:23:59 +0000 Subject: [PATCH] Add models and utils modules --- src/utils/config.py | 133 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 src/utils/config.py diff --git a/src/utils/config.py b/src/utils/config.py new file mode 100644 index 0000000..b1bb287 --- /dev/null +++ b/src/utils/config.py @@ -0,0 +1,133 @@ +"""Configuration management for the application.""" + +import os +from pathlib import Path +from typing import Any, Optional + +import yaml +from dotenv import load_dotenv + + +class Config: + """Configuration management class supporting env vars and YAML config.""" + + def __init__( + self, + config_path: Optional[Path] = None, + env_path: Optional[Path] = None, + ): + self._config: dict[str, Any] = {} + self._config_path = config_path or Path.cwd() / "config.yaml" + self._load_env(env_path) + self._load_config() + + def _load_env(self, env_path: Optional[Path] = None) -> None: + """Load environment variables from .env file.""" + env_file = env_path or Path.cwd() / ".env" + if env_file.exists(): + load_dotenv(env_file) + + def _load_config(self) -> None: + """Load configuration from YAML file.""" + if self._config_path.exists(): + with open(self._config_path, "r") as f: + self._config = yaml.safe_load(f) or {} + else: + self._config = {} + + def get(self, key: str, default: Any = None) -> Any: + """Get configuration value with environment variable override.""" + env_key = f"API_DOCS_{key.upper()}" + env_value = os.environ.get(env_key) + + if env_value is not None: + return self._cast_env_value(env_value) + + return self._config.get(key, default) + + def _cast_env_value(self, value: str) -> Any: + """Cast environment variable string to appropriate type.""" + if value.lower() in ("true", "false"): + return value.lower() == "true" + try: + return int(value) + except ValueError: + pass + try: + return float(value) + except ValueError: + pass + return value + + @property + def index_path(self) -> Path: + """Get the documentation index path.""" + return Path(self.get("index_path", "./docs")) + + @property + def model_name(self) -> str: + """Get the embedding model name.""" + return self.get("model_name", "all-MiniLM-L6-v2") + + @property + def embedding_device(self) -> str: + """Get the embedding device.""" + return self.get("embedding_device", "cpu") + + @property + def chroma_persist_dir(self) -> Path: + """Get the ChromaDB persistence directory.""" + return Path(self.get("chroma_persist_dir", ".api-docs/chroma")) + + @property + def default_limit(self) -> int: + """Get the default search result limit.""" + return int(self.get("default_limit", 10)) + + @property + def verbose(self) -> bool: + """Get verbose mode setting.""" + return self.get("verbose", False) + + def set(self, key: str, value: Any) -> None: + """Set a configuration value.""" + self._config[key] = value + + def save(self) -> None: + """Save configuration to YAML file.""" + with open(self._config_path, "w") as f: + yaml.dump(self._config, f, default_flow_style=False) + + def reset(self) -> None: + """Reset configuration to defaults.""" + self._config = {} + if self._config_path.exists(): + self._config_path.unlink() + + def to_dict(self) -> dict: + """Return configuration as dictionary.""" + return { + "index_path": str(self.index_path), + "model_name": self.model_name, + "embedding_device": self.embedding_device, + "chroma_persist_dir": str(self.chroma_persist_dir), + "default_limit": self.default_limit, + "verbose": self.verbose, + } + + +_config: Optional[Config] = None + + +def get_config(config_path: Optional[Path] = None) -> Config: + """Get or create the global configuration instance.""" + global _config + if _config is None: + _config = Config(config_path) + return _config + + +def reset_config() -> None: + """Reset the global configuration instance.""" + global _config + _config = None