Spaces:
Running
Running
Download solar_eval/core/fingerprint.py from dev-strender/proofread-demo: direct link, hf CLI and curl.
- Browser
- Download file 5.04 kB
-
https://huggingface.co/spaces/dev-strender/proofread-demo/resolve/483134ace86f21c444532ef540c77505aadb29b9/solar_eval/core/fingerprint.py
- Command line
-
hf download hf://spaces/dev-strender/proofread-demo@483134ace86f21c444532ef540c77505aadb29b9/solar_eval/core/fingerprint.py
-
curl -L -o fingerprint.py https://huggingface.co/spaces/dev-strender/proofread-demo/resolve/483134ace86f21c444532ef540c77505aadb29b9/solar_eval/core/fingerprint.py
5.04 kB
| """์ค์ ์ **๋ด์ฉ ์ง๋ฌธ** โ ์ด๋ฆ์ด ์๋๋ผ ๋ด์ฉ์ผ๋ก ์คํ์ ์๋ณํ๋ค. | |
| ์ ํ์ํ๊ฐ: ์ด ์์ง์ ์์ฐ์ ์ค๋ ์ด๋ฆ์ผ๋ก๋ง ์๋ณ๋ผ ์๊ณ (`prompt_dev_v23` | |
| โ `pipeline_dev_v24` ์ฒ๋ผ ์ง์ ๋ฒํธ๊ฐ ์ด๊ธ๋๋ ์ผ์ด ์ฆ์๋ค), ๊ทธ๋์ | |
| "์ด๋ฆ์ด ๋ค๋ฅธ ๋ run ์ด ์ฌ์ค ๊ฐ์ ์ค์ " ์ธ์ง๋ฅผ ์ฌ๋์ด ํด์๋ฅผ ๋ ์ ๋์กฐํด์ผ ํ๋ค | |
| (`insights/lab_notes_archive.md#260803_etd_regression_prod_vs_v24` ์ '์ด๋ฆ ๋งคํ' ์ ์ด ๊ทธ ํ์ ์ด๋ค). | |
| run ์ ์ง๋ฌธ์ ์ฐ์ด ๋๋ฉด ๊ทธ ๋์กฐ๊ฐ ์กฐํ ํ ๋ฒ์ผ๋ก ๋๋๋ค. | |
| ์ง๋ฌธ์ **ํด์์ด ๋๋ ์ค์ **์ ๋์์ผ๋ก ๊ณ์ฐํ๋ค. `extends`/override ๋ก ์กฐ๋ฆฝํ | |
| ํ์ดํ๋ผ์ธ๊ณผ ๊ฐ์ ๋ด์ฉ์ ํต์งธ๋ก ์ ์ด ๋ ํ์ผ์ ๊ฐ์ ์ง๋ฌธ์ ๊ฐ์ ธ์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค | |
| (๊ทธ ๋ฑ๊ฐ์ฑ์ด ํ์ผ ๋ณต์ ๋ฅผ override ๋ก ์ฎ๊ธธ ๋์ ์์ ๋ง์ด๋ค). | |
| ํ์: `sha256:<์ 12์>` โ ๋์ผ๋ก ๋น๊ตํ ์ ์์ ๋งํผ ์งง๊ณ , ํ๋ก์ ํธ๋น ์๋ฐฑ ๊ฐ | |
| ๊ท๋ชจ์์ ์ถฉ๋ํ์ง ์์ ๋งํผ ๊ธธ๋ค. | |
| """ | |
| import hashlib | |
| import json | |
| from collections.abc import Mapping, Sequence | |
| from pathlib import Path | |
| from typing import Any | |
| #: ์ง๋ฌธ ๊ณ์ฐ์์ ์ ์ธํ๋ ํค โ ์ฌ๋์ด ์ฝ๋ ๋ผ๋ฒจ์ผ ๋ฟ ์คํ์ ์ํฅ์ ์ฃผ์ง ์๋๋ค. | |
| #: ์ด๊ฑธ ์ ์ธํด์ผ "์ด๋ฆ๋ง ๋ฐ๊พผ ์ฌ๋ณธ"์ด ๊ฐ์ ์ง๋ฌธ์ผ๋ก ์กํ๋ค. | |
| NON_FUNCTIONAL_KEYS = frozenset({"name", "description", "comment", "extends", "overrides"}) | |
| #: ์คํ ํ์์์ ์ ์ธํ๋ ํค โ ์คํ ์ `name` ์ ํ๋กฌํํธ ํคยทrule ํ์ ์กฐํ์ | |
| #: ์ฐ์ด๋ฏ๋ก (`pipelines/registry.py:resolve_step`) ๊ธฐ๋ฅ์ ์ด๋ค. ์ง์ฐ๋ฉด ์ ๋๋ค. | |
| NON_FUNCTIONAL_STEP_KEYS = frozenset({"description", "comment"}) | |
| #: ํ๋กฌํํธ ๋๋ ํ ๋ฆฌ์์ ์ง๋ฌธ ๋์์ผ๋ก ์ผ๋ ํ์ฅ์. | |
| PROMPT_ASSET_SUFFIXES = frozenset({".txt", ".yaml", ".yml", ".json"}) | |
| _DIGEST_PREFIX = "sha256" | |
| _DIGEST_LENGTH = 12 | |
| def digest(payload: Any) -> str: | |
| """JSON ์ง๋ ฌํ ๊ฐ๋ฅํ ๊ฐ์ ์ ๊ท ์ง๋ฌธ.""" | |
| canonical = json.dumps(payload, sort_keys=True, ensure_ascii=False, separators=(",", ":")) | |
| full = hashlib.sha256(canonical.encode("utf-8")).hexdigest() | |
| return f"{_DIGEST_PREFIX}:{full[:_DIGEST_LENGTH]}" | |
| def pipeline_fingerprint(config: Mapping[str, Any] | None) -> str | None: | |
| """ํด์์ด ๋๋ ํ์ดํ๋ผ์ธ ์ค์ ์ ์ง๋ฌธ. | |
| Args: | |
| config: `extends`/override ํด์๊น์ง ๋๋ ํ์ดํ๋ผ์ธ dict. | |
| None ์ด๊ฑฐ๋ ๋น์ด ์์ผ๋ฉด None ์ ๋ฐํํ๋ค (single_step ์ฒ๋ผ ํ์ดํ๋ผ์ธ | |
| ํ์ผ์ด ์๋ ํ์คํฌ๊ฐ ์๋ค). | |
| Returns: | |
| `sha256:xxxxxxxxxxxx` ๋๋ None. | |
| """ | |
| if not config: | |
| return None | |
| return digest(_strip_pipeline(config)) | |
| def prompt_fingerprint(path: Path) -> str | None: | |
| """ํ๋กฌํํธ ์์ฐ์ ์ง๋ฌธ โ ๋๋ ํ ๋ฆฌ(์ฌ๋ฌ ํ์ผ)์ ๋จ์ผ ํ์ผ ๋ชจ๋ ์ง์ํ๋ค. | |
| ๋๋ ํ ๋ฆฌ๋ฉด ํ์ ์์ฐ ํ์ผ์ ์๋๊ฒฝ๋ก๋ก ์ ๋ ฌํด `{๊ฒฝ๋ก: ๋ด์ฉํด์}` ๋งต์ ๋ง๋ค๊ณ | |
| ๊ทธ ๋งต์ ์ง๋ฌธ์ ๋ธ๋ค. ํ์ผ ํ๋๊ฐ ๋ฐ๋๋ฉด ์ ์ฒด ์ง๋ฌธ์ด ๋ฐ๋๊ณ , ํ์ผ ์์๋ | |
| ๋๋ ํ ๋ฆฌ ์ด๋ฆ์ด ๋ฐ๋์ด๋ ๋ด์ฉ์ด ๊ฐ์ผ๋ฉด ์ง๋ฌธ์ ์ ์ง๋๋ค. | |
| Args: | |
| path: ํ๋กฌํํธ ๋๋ ํ ๋ฆฌ ๋๋ YAML ํ์ผ ๊ฒฝ๋ก. | |
| Returns: | |
| `sha256:xxxxxxxxxxxx`, ๊ฒฝ๋ก๊ฐ ์๊ฑฐ๋ ์ฝ์ ์ ์์ผ๋ฉด None. | |
| """ | |
| try: | |
| if path.is_dir(): | |
| assets = _collect_prompt_assets(path) | |
| if not assets: | |
| return None | |
| return digest(assets) | |
| if path.is_file(): | |
| return digest({path.name: _file_digest(path)}) | |
| except OSError: | |
| return None | |
| return None | |
| def _collect_prompt_assets(root: Path) -> dict[str, str]: | |
| """ํ๋กฌํํธ ๋๋ ํ ๋ฆฌ์ `{์๋๊ฒฝ๋ก: ํ์ผ์ง๋ฌธ}` ๋งต. ์จ๊น ํ์ผ์ ์ ์ธํ๋ค.""" | |
| assets: dict[str, str] = {} | |
| for file in sorted(root.rglob("*")): | |
| if not file.is_file() or file.suffix.lower() not in PROMPT_ASSET_SUFFIXES: | |
| continue | |
| if any(part.startswith(".") for part in file.relative_to(root).parts): | |
| continue | |
| assets[file.relative_to(root).as_posix()] = _file_digest(file) | |
| return assets | |
| def _file_digest(path: Path) -> str: | |
| """ํ์ผ ๋ฐ์ดํธ์ ์ง๋ฌธ โ ํ ์คํธ ์ธ์ฝ๋ฉยท๊ฐํ ์ ๊ทํ๋ฅผ ํ์ง ์๋๋ค(์๋ ๊ทธ๋๋ก).""" | |
| return hashlib.sha256(path.read_bytes()).hexdigest()[:_DIGEST_LENGTH] | |
| def _strip_pipeline(config: Mapping[str, Any]) -> dict[str, Any]: | |
| """ํ์ดํ๋ผ์ธ dict ์์ ๋น๊ธฐ๋ฅ ํ๋๋ฅผ ๊ฑท์ด๋ธ ์ฌ๋ณธ.""" | |
| stripped = {k: v for k, v in config.items() if k not in NON_FUNCTIONAL_KEYS} | |
| steps = stripped.get("steps") | |
| if isinstance(steps, Sequence) and not isinstance(steps, str | bytes): | |
| stripped["steps"] = [_strip_step(s) for s in steps] | |
| return stripped | |
| def _strip_step(step: Any) -> Any: | |
| if not isinstance(step, Mapping): | |
| return step | |
| return {k: v for k, v in step.items() if k not in NON_FUNCTIONAL_STEP_KEYS} | |