Spaces:
Sleeping
Sleeping
| """Shared utilities: project paths, logging, deterministic seeding. | |
| This module is the single source of truth for *where files live* in the | |
| project. All other modules import path constants from here rather than | |
| hard-coding paths, so the project is portable across machines/OSes. | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| import os | |
| import random | |
| import sys | |
| from pathlib import Path | |
| import numpy as np | |
| # --------------------------------------------------------------------------- | |
| # Paths | |
| # --------------------------------------------------------------------------- | |
| # PROJECT_ROOT = parent of `src/`. Works on Windows, macOS, Linux. | |
| PROJECT_ROOT: Path = Path(__file__).resolve().parent.parent | |
| DATA_DIR: Path = PROJECT_ROOT / "data" | |
| MODELS_DIR: Path = PROJECT_ROOT / "models" | |
| RESULTS_DIR: Path = PROJECT_ROOT / "results" | |
| DOCS_DIR: Path = PROJECT_ROOT / "docs" | |
| NOTEBOOKS_DIR: Path = PROJECT_ROOT / "notebooks" | |
| # Ensure standard directories exist (idempotent) | |
| for _d in (DATA_DIR, MODELS_DIR, RESULTS_DIR, DOCS_DIR): | |
| _d.mkdir(parents=True, exist_ok=True) | |
| # --------------------------------------------------------------------------- | |
| # Logging | |
| # --------------------------------------------------------------------------- | |
| def get_logger(name: str, level: int = logging.INFO) -> logging.Logger: | |
| """Return a configured logger with a consistent format across modules. | |
| Parameters | |
| ---------- | |
| name : str | |
| Logger name, usually `__name__` from the calling module. | |
| level : int | |
| Logging level (default: INFO). | |
| """ | |
| logger = logging.getLogger(name) | |
| if not logger.handlers: | |
| handler = logging.StreamHandler(sys.stdout) | |
| handler.setFormatter( | |
| logging.Formatter( | |
| fmt="%(asctime)s | %(name)s | %(levelname)s | %(message)s", | |
| datefmt="%H:%M:%S", | |
| ) | |
| ) | |
| logger.addHandler(handler) | |
| logger.setLevel(level) | |
| logger.propagate = False | |
| return logger | |
| # --------------------------------------------------------------------------- | |
| # Reproducibility | |
| # --------------------------------------------------------------------------- | |
| def set_seed(seed: int = 42) -> None: | |
| """Seed all RNGs we use (Python, NumPy, optional PyTorch/TF).""" | |
| random.seed(seed) | |
| np.random.seed(seed) | |
| os.environ["PYTHONHASHSEED"] = str(seed) | |
| try: | |
| import torch | |
| torch.manual_seed(seed) | |
| if torch.cuda.is_available(): | |
| torch.cuda.manual_seed_all(seed) | |
| except ImportError: | |
| pass | |
| try: | |
| import tensorflow as tf | |
| tf.random.set_seed(seed) | |
| except ImportError: | |
| pass | |
| # --------------------------------------------------------------------------- | |
| # Convenience | |
| # --------------------------------------------------------------------------- | |
| def human_bytes(n: int) -> str: | |
| """Format a byte count as KB/MB/GB.""" | |
| for unit in ("B", "KB", "MB", "GB"): | |
| if n < 1024: | |
| return f"{n:.1f} {unit}" | |
| n /= 1024 | |
| return f"{n:.1f} TB" | |
| if __name__ == "__main__": | |
| log = get_logger("utils") | |
| log.info(f"PROJECT_ROOT = {PROJECT_ROOT}") | |
| log.info(f"DATA_DIR = {DATA_DIR}") | |
| log.info(f"MODELS_DIR = {MODELS_DIR}") | |
| log.info(f"RESULTS_DIR = {RESULTS_DIR}") | |