Spaces:
Sleeping
Sleeping
File size: 7,050 Bytes
9c84f9d | 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 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | """CLI configuration from YAML file and environment variables."""
import logging
import os
from pathlib import Path
from typing import Any
import yaml
DEFAULT_CONFIG_PATH = Path.home() / ".upstage-cloud-dev" / "solar-eval-config.yaml"
logger = logging.getLogger(__name__)
def default_projects_dir() -> Path:
"""CBS ๊ณต์ฉ ๋ฐ์ดํฐ ํ ์๋์ ํ๋ก์ ํธ ๋ฃจํธ (huggingface ์บ์์ ๊ฐ์ ๋ฐฉ์).
- ๊ธฐ๋ณธ๊ฐ: ``~/.cache/cbs-data/solar-eval-projects``
- ``CBS_DATA_HOME`` ์ด ์ค์ ๋๋ฉด ๋ฐ์ดํฐ ํ ์์ฒด๋ฅผ ์ฎ๊ธด๋ค: ``$CBS_DATA_HOME/solar-eval-projects``
- ``XDG_CACHE_HOME`` ์ด ์ค์ ๋๋ฉด ์บ์ ๋ฃจํธ๋ก ์กด์คํ๋ค: ``$XDG_CACHE_HOME/cbs-data/solar-eval-projects``
"""
data_home = os.environ.get("CBS_DATA_HOME")
if data_home:
return Path(data_home).expanduser() / "solar-eval-projects"
cache_root = os.environ.get("XDG_CACHE_HOME", "~/.cache")
return Path(cache_root).expanduser() / "cbs-data" / "solar-eval-projects"
def find_repo_root() -> Path | None:
"""์ด ํจํค์ง๊ฐ harness ๋ ํฌ ์ฒดํฌ์์ ์์ vendored ๋์ด ์์ผ๋ฉด ๋ ํฌ ๋ฃจํธ๋ฅผ ์ฐพ๋๋ค.
``SOLAR_EVAL_CONFIG_ROOT`` ํ๊ฒฝ๋ณ์๊ฐ ์์ผ๋ฉด ๊ทธ ๊ฒฝ๋ก๋ฅผ ์ด๋ค (ํ
์คํธ/ํน์ ํ๊ฒฝ์ฉ).
๋ ํฌ ๋ฐ standalone ์ค์น๋ฉด None โ ์ด๋๋ ๋ฐ์ดํฐ ํ ๋จ์ผ ๋ฃจํธ๋ก ๋์ํ๋ค.
"""
override = os.environ.get("SOLAR_EVAL_CONFIG_ROOT")
if override:
path = Path(override).expanduser()
return path if path.is_dir() else None
for parent in Path(__file__).resolve().parents:
if (parent / "pnpm-workspace.yaml").is_file():
return parent
return None
def discover_config_dirs(repo_root: Path | None) -> dict[str, Path]:
"""๋ ํฌ์ ``accounts/*/*/03-evaluation/project.yaml`` ์์ ํ๋ก์ ํธ๋ช
โ config ๋๋ ํ ๋ฆฌ ๋งต.
hydra/DVC ์ ๋ถ๋ฆฌ์ ๋ฐ๊ฒฌ ๋จ๊ณ: config(project.yamlยทpromptsยทpipelines)๋ git ์ด ์ ๋ณธ,
datasets/artifacts ๋ ๋ฐ์ดํฐ ํ์ด ์ ๋ณธ์ด๋ค.
"""
if repo_root is None:
return {}
found: dict[str, Path] = {}
for manifest in sorted(repo_root.glob("accounts/*/*/03-evaluation/project.yaml")):
try:
with open(manifest) as f:
doc = yaml.safe_load(f)
except Exception as e:
logger.warning("Failed to read %s: %s", manifest, e)
continue
name = doc.get("name") if isinstance(doc, dict) else None
if isinstance(name, str) and name:
found[name] = manifest.parent
return found
def _load_yaml_config(config_path: Path | None = None) -> dict[str, Any]:
"""YAML ์ค์ ํ์ผ ๋ก๋. ํ์ผ ์์ผ๋ฉด ๋น dict ๋ฐํ."""
path = config_path or Path(os.environ.get("SOLAR_EVAL_CONFIG", str(DEFAULT_CONFIG_PATH)))
if not path.is_file():
return {}
try:
with open(path) as f:
data = yaml.safe_load(f)
return data if isinstance(data, dict) else {}
except Exception as e:
logger.warning("Failed to load config from %s: %s", path, e)
return {}
class CLIConfig:
"""Configuration for the Solar Eval CLI.
Priority (low โ high):
1. Hard-coded defaults (projects_dir: ~/.cache/cbs-data/solar-eval-projects)
2. YAML config file (~/.upstage-cloud-dev/solar-eval-config.yaml)
3. Environment variables (SOLAR_EVAL_URL, CBS_DATA_HOME, SOLAR_EVAL_PROJECTS, etc.)
4. CLI options (--remote, etc.)
"""
def __init__(self, config_path: Path | None = None) -> None:
yaml_cfg = _load_yaml_config(config_path)
yaml_remote = yaml_cfg.get("remote_url") or yaml_cfg.get("remote")
self.remote_url: str | None = os.environ.get("SOLAR_EVAL_URL", yaml_remote)
yaml_timeout = yaml_cfg.get("timeout", 300)
self.timeout = int(os.environ.get("SOLAR_EVAL_TIMEOUT", yaml_timeout))
# SOLAR_EVAL_PROJECTS(๊ตฌ์ฒด) > CBS_DATA_HOME(๋ฐ์ดํฐ ํ) > YAML projects_dir > ์บ์ ๊ธฐ๋ณธ๊ฐ
env_projects = os.environ.get("SOLAR_EVAL_PROJECTS")
yaml_projects = yaml_cfg.get("projects_dir")
if env_projects:
self.projects_dir = Path(env_projects).expanduser()
explicit_root = True
elif os.environ.get("CBS_DATA_HOME") or not yaml_projects:
self.projects_dir = default_projects_dir()
explicit_root = False
else:
self.projects_dir = Path(yaml_projects).expanduser()
explicit_root = True
# config ์ค๋ฒ๋ ์ด (hydra/W&B/DVC ํจํด): ํ์ค ๋ฐ์ดํฐ ํ์์๋ ๋ ํฌ์
# accounts/*/*/03-evaluation ์ด config ์ ๋ณธ์ด๋ค. ๋ช
์์ ์ผ๋ก ์ง์ ๋ ๋ฃจํธ
# (SOLAR_EVAL_PROJECTSยทYAML projects_dirยท--projects-dir)๋ ๊ณผ๊ฑฐ ์์นด์ด๋ธ ๋ฑ
# ์๊ธ์์กฑ ํธ๋ฆฌ๋ฅผ ๊ฐ๋ฆฌํค๋ ์ฉ๋์ด๋ฏ๋ก ์ค๋ฒ๋ ์ดํ์ง ์๋๋ค.
self.repo_root: Path | None = None if explicit_root else find_repo_root()
self.config_dirs: dict[str, Path] = discover_config_dirs(self.repo_root)
# Load provider API keys from YAML (env vars take precedence)
upstage_cfg = yaml_cfg.get("upstage", {})
if upstage_cfg.get("api_key") and not os.environ.get("UPSTAGE_API_KEY"):
os.environ["UPSTAGE_API_KEY"] = upstage_cfg["api_key"]
openai_cfg = yaml_cfg.get("openai", {})
if openai_cfg.get("api_key") and not os.environ.get("OPENAI_API_KEY"):
os.environ["OPENAI_API_KEY"] = openai_cfg["api_key"]
@property
def is_remote(self) -> bool:
return self.remote_url is not None
def override_projects_dir(self, path: Path) -> None:
"""``--projects-dir`` ํ๋๊ทธ: ์ง์ ํ ๋ฃจํธ๋ฅผ ์๊ธ์์กฑ ์์นด์ด๋ธ๋ก ์ด๋ค (์ค๋ฒ๋ ์ด ํด์ )."""
self.projects_dir = path
self.repo_root = None
self.config_dirs = {}
def is_repo_managed(self, project: str) -> bool:
"""์ด ํ๋ก์ ํธ์ config ์ ๋ณธ์ด ๋ ํฌ(accounts)์ ์๋๊ฐ."""
return project in self.config_dirs
def config_dir(self, project: str) -> Path:
"""config(project.yamlยทpromptsยทpipelines) ๋ฃจํธ โ ๋ ํฌ ๊ด๋ฆฌ๋ฉด ๋ ํฌ ์ชฝ, ์๋๋ฉด ๋ฐ์ดํฐ ํ."""
return self.config_dirs.get(project) or self.projects_dir / project
def data_dir(self, project: str) -> Path:
"""data(datasetsยทartifacts) ๋ฃจํธ โ ํญ์ ๋ฐ์ดํฐ ํ."""
return self.projects_dir / project
def artifacts_dir(self, project: str) -> Path:
"""Run ์ฐ์ถ๋ฌผ ๋๋ ํ ๋ฆฌ โ ํญ์ ๋ฐ์ดํฐ ํ์ ์ด๋ค."""
return self.data_dir(project) / "artifacts"
def prompts_dir(self, project: str) -> Path:
"""ํ๋กฌํํธ ๋๋ ํ ๋ฆฌ โ ๋ ํฌ ๊ด๋ฆฌ ํ๋ก์ ํธ๋ฉด git ์ชฝ์ด ์ ๋ณธ."""
return self.config_dir(project) / "prompts"
def pipelines_dir(self, project: str) -> Path:
"""ํ์ดํ๋ผ์ธ ๋๋ ํ ๋ฆฌ โ ๋ ํฌ ๊ด๋ฆฌ ํ๋ก์ ํธ๋ฉด git ์ชฝ์ด ์ ๋ณธ."""
return self.config_dir(project) / "pipelines"
config = CLIConfig()
|