67 lines
1.9 KiB
Python
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})"
|