Files
s-canvas/harness/seed_manager.py

67 lines
1.9 KiB
Python

"""Seed 관리자 - 작업별 Seed 고정 및 추적."""
from __future__ import annotations
import hashlib
import random
from typing import Optional
from sqlalchemy.orm import Session
from harness.logger import JobRecord, get_db_session
class SeedManager:
"""DXF 파일 해시 기반 결정론적 seed를 생성하고 이력을 관리한다."""
MAX_SEED = 2**32 - 1
def get_seed(
self,
file_hash: str,
fixed_seed: Optional[int] = None,
deterministic: bool = True,
) -> int:
"""
Args:
file_hash: DXF 파일의 SHA256 해시 앞 16자
fixed_seed: 사용자가 직접 지정한 seed (None이면 자동)
deterministic: True면 파일 해시 기반, False면 랜덤
"""
if fixed_seed is not None:
return int(fixed_seed) % (self.MAX_SEED + 1)
if deterministic:
return self._hash_to_seed(file_hash)
return random.randint(0, self.MAX_SEED)
def get_or_create_seed(
self,
db: Session,
job_id: int,
file_hash: str,
fixed_seed: Optional[int] = None,
deterministic: bool = True,
) -> int:
"""DB에서 기존 seed를 조회하거나 새로 생성한다."""
existing = db.query(JobRecord).filter_by(id=job_id).first()
if existing and existing.seed is not None:
return existing.seed
seed = self.get_seed(file_hash, fixed_seed, deterministic)
if existing:
existing.seed = seed
db.commit()
return seed
@staticmethod
def _hash_to_seed(file_hash: str) -> int:
"""파일 해시를 정수 seed로 변환한다."""
digest = hashlib.sha256(file_hash.encode()).digest()
return int.from_bytes(digest[:4], "big")
@staticmethod
def describe(seed: int) -> str:
return f"seed={seed} (0x{seed:08X})"