Centralize helper seed selection

This commit is contained in:
2026-06-27 14:16:03 +02:00
parent c7e4bdc373
commit 7bc08ada47
4 changed files with 57 additions and 39 deletions
+7 -19
View File
@@ -13,6 +13,7 @@ try:
from .prompt_builder import ( from .prompt_builder import (
subcategory_choices, subcategory_choices,
) )
from .seed_config import configured_seed_from_axes
from .location_config import ( from .location_config import (
build_composition_pool_json, build_composition_pool_json,
build_location_pool_json, build_location_pool_json,
@@ -31,6 +32,7 @@ except ImportError: # Allows local smoke tests from the repository root.
from prompt_builder import ( from prompt_builder import (
subcategory_choices, subcategory_choices,
) )
from seed_config import configured_seed_from_axes
from location_config import ( from location_config import (
build_composition_pool_json, build_composition_pool_json,
build_location_pool_json, build_location_pool_json,
@@ -224,25 +226,11 @@ class SxCPCastBias:
@staticmethod @staticmethod
def _configured_cast_seed(seed_config): def _configured_cast_seed(seed_config):
if not seed_config: return configured_seed_from_axes(
return None seed_config,
if isinstance(seed_config, dict): ("category", "content", "role"),
raw = seed_config extra_keys=("seed", "global_seed"),
else: )
try:
raw = json.loads(str(seed_config))
except (TypeError, ValueError, json.JSONDecodeError):
return None
if not isinstance(raw, dict):
return None
for key in ("category_seed", "content_seed", "role_seed", "seed", "global_seed"):
try:
value = int(raw.get(key))
except (TypeError, ValueError):
continue
if value >= 0:
return value
return None
@staticmethod @staticmethod
def _weight_pairs(weights_text, start_count): def _weight_pairs(weights_text, start_count):
+7 -19
View File
@@ -8,6 +8,7 @@ try:
from .seed_config import ( from .seed_config import (
build_seed_config_json, build_seed_config_json,
build_seed_lock_config_json, build_seed_lock_config_json,
configured_seed_from_axes,
normalize_reroll_axis, normalize_reroll_axis,
seed_reroll_axis_choices, seed_reroll_axis_choices,
seed_mode_choices, seed_mode_choices,
@@ -16,6 +17,7 @@ except ImportError: # Allows local smoke tests from the repository root.
from seed_config import ( from seed_config import (
build_seed_config_json, build_seed_config_json,
build_seed_lock_config_json, build_seed_lock_config_json,
configured_seed_from_axes,
normalize_reroll_axis, normalize_reroll_axis,
seed_reroll_axis_choices, seed_reroll_axis_choices,
seed_mode_choices, seed_mode_choices,
@@ -225,25 +227,11 @@ class SxCPSDXLBucketSize:
@staticmethod @staticmethod
def _configured_bucket_seed(seed_config): def _configured_bucket_seed(seed_config):
if not seed_config: return configured_seed_from_axes(
return None seed_config,
if isinstance(seed_config, dict): ("composition", "content"),
raw = seed_config extra_keys=("seed", "global_seed"),
else: )
try:
raw = json.loads(str(seed_config))
except (TypeError, ValueError, json.JSONDecodeError):
return None
if not isinstance(raw, dict):
return None
for key in ("composition_seed", "content_seed", "seed", "global_seed"):
try:
value = int(raw.get(key))
except (TypeError, ValueError):
continue
if value >= 0:
return value
return None
@classmethod @classmethod
def IS_CHANGED(cls, *args, **kwargs): def IS_CHANGED(cls, *args, **kwargs):
+22 -1
View File
@@ -2,7 +2,7 @@ from __future__ import annotations
import json import json
import random import random
from typing import Any from typing import Any, Iterable
SEED_AXIS_SALTS = { SEED_AXIS_SALTS = {
@@ -189,6 +189,27 @@ def configured_axis_seed(seed_config: dict[str, int], axis: str) -> int | None:
return None return None
def configured_seed_from_axes(
seed_config: str | dict[str, Any] | None,
axes: Iterable[str],
*,
extra_keys: Iterable[str] = (),
) -> int | None:
try:
parsed = parse_seed_config(seed_config)
except ValueError:
return None
for axis in axes:
value = configured_axis_seed(parsed, axis)
if value is not None:
return value
for key in extra_keys:
value = parsed.get(str(key))
if value is not None and value >= 0:
return value
return None
def axis_rng(seed_config: dict[str, int], axis: str, base_seed: int, row_number: int) -> random.Random: def axis_rng(seed_config: dict[str, int], axis: str, base_seed: int, row_number: int) -> random.Random:
configured = configured_axis_seed(seed_config, axis) configured = configured_axis_seed(seed_config, axis)
salt = SEED_AXIS_SALTS.get(axis, 0) salt = SEED_AXIS_SALTS.get(axis, 0)
+21
View File
@@ -5762,6 +5762,14 @@ def smoke_node_utility_registration() -> None:
bucket_b = bucket_node.build("portrait", 77, 3, 0) bucket_b = bucket_node.build("portrait", 77, 3, 0)
_expect(bucket_a == bucket_b, "SDXL bucket should be deterministic for fixed seed and row") _expect(bucket_a == bucket_b, "SDXL bucket should be deterministic for fixed seed and row")
_expect(bucket_a[3] == "portrait", "SDXL bucket ignored orientation filter") _expect(bucket_a[3] == "portrait", "SDXL bucket ignored orientation filter")
bucket_seed_config = json.dumps({"camera_seed": 9001})
bucket_seeded_a = bucket_node.build("landscape", -1, 4, 0, bucket_seed_config)
bucket_seeded_b = bucket_node.build("landscape", -1, 4, 0, bucket_seed_config)
_expect(bucket_seeded_a == bucket_seeded_b, "SDXL bucket should honor seed_config aliases deterministically")
_expect(
bucket_node._configured_bucket_seed({"camera_seed": "42"}) == 42,
"SDXL bucket seed should delegate through composition/camera seed aliases",
)
krea_node = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPKrea2ResolutionSelector"]() krea_node = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPKrea2ResolutionSelector"]()
krea_width, krea_height, _resolution, aspect_ratio, api_aspect, _api_resolution, *_rest = krea_node.select("1.0MP", "9:16") krea_width, krea_height, _resolution, aspect_ratio, api_aspect, _api_resolution, *_rest = krea_node.select("1.0MP", "9:16")
@@ -5888,6 +5896,14 @@ def smoke_seed_config_policy() -> None:
_expect(parsed == {"item_seed": 44, "pose_seed": 55}, "seed parser should keep integer-like values only") _expect(parsed == {"item_seed": 44, "pose_seed": 55}, "seed parser should keep integer-like values only")
_expect(pb._configured_axis_seed(parsed, "content") == 44, "content axis should honor item_seed alias") _expect(pb._configured_axis_seed(parsed, "content") == 44, "content axis should honor item_seed alias")
_expect(pb._configured_axis_seed(parsed, "role") == 55, "role axis should honor pose seed alias") _expect(pb._configured_axis_seed(parsed, "role") == 55, "role axis should honor pose seed alias")
_expect(
seed_config.configured_seed_from_axes({"camera_seed": "88", "content_seed": "99"}, ("composition", "content")) == 88,
"seed helper should honor axis aliases in precedence order",
)
_expect(
seed_config.configured_seed_from_axes('{"bad": "json"', ("content",)) is None,
"seed helper should return no seed for invalid config JSON",
)
locked = json.loads(pb.build_seed_lock_config_json(base_seed=100, reroll_axis="content pose", reroll_seed=999)) locked = json.loads(pb.build_seed_lock_config_json(base_seed=100, reroll_axis="content pose", reroll_seed=999))
_expect(locked["content_seed"] == 999, "content_pose reroll should alter content seed") _expect(locked["content_seed"] == 999, "content_pose reroll should alter content seed")
@@ -6089,6 +6105,11 @@ def smoke_node_route_config_registration() -> None:
_expect(bias_a == bias_b, "Cast Bias should be deterministic for fixed seed and row") _expect(bias_a == bias_b, "Cast Bias should be deterministic for fixed seed and row")
_expect(bias_a[1] + bias_a[2] >= 1, "Cast Bias empty behavior allowed empty cast") _expect(bias_a[1] + bias_a[2] >= 1, "Cast Bias empty behavior allowed empty cast")
_expect("weighted cast:" in bias_a[3], "Cast Bias summary lost weighted cast label") _expect("weighted cast:" in bias_a[3], "Cast Bias summary lost weighted cast label")
bias_seed_config = json.dumps({"category": 702})
seeded_bias_a = cast_bias.build(-1, 2, "0.7,0.3", 1, "0.4,0.6", 0, "force_one_woman", bias_seed_config)
seeded_bias_b = cast_bias.build(-1, 2, "0.7,0.3", 1, "0.4,0.6", 0, "force_one_woman", bias_seed_config)
_expect(seeded_bias_a == seeded_bias_b, "Cast Bias should honor seed_config aliases deterministically")
_expect(cast_bias._configured_cast_seed({"category": "702"}) == 702, "Cast Bias seed should delegate through category aliases")
def smoke_node_character_registration() -> None: def smoke_node_character_registration() -> None: