Add per-axis seed modes

This commit is contained in:
2026-06-24 15:34:33 +02:00
parent cad2f4b4e4
commit 81d9b20db7
3 changed files with 90 additions and 22 deletions
+10 -2
View File
@@ -532,7 +532,15 @@ alone.
## Seed Control
The main `seed` input is still the default master seed. Connect `SxCP Seed
Control` to `seed_config` when you want to lock or vary specific axes.
Control` to `seed_config` when you want to lock or vary specific axes. Each
axis has its own mode plus seed value:
- `auto`: legacy behavior; `-1` follows the main seed, `0` or higher fixes that
axis to the entered value.
- `follow_main`: always follows the final generator's main `seed` input and
ignores the entered axis seed.
- `fixed`: always uses the entered axis seed.
- `random`: generates a fresh axis seed when the node runs.
For normal prompt iteration, `SxCP Seed Locker` is usually simpler:
@@ -542,7 +550,7 @@ For normal prompt iteration, `SxCP Seed Locker` is usually simpler:
- `reroll_seed`: `-1` makes the selected axis follow the main prompt seed;
`0` or higher pins that selected axis to a specific seed.
Seed values:
Seed values in `auto` mode:
- `-1`: follow the main seed.
- `0` or higher: override only that axis.
+45 -11
View File
@@ -1,6 +1,7 @@
from __future__ import annotations
import json
import random
try:
from .prompt_builder import (
@@ -40,6 +41,7 @@ try:
ethnicity_choices,
generation_profile_choices,
load_character_profile_json,
seed_mode_choices,
subcategory_choices,
)
from .caption_naturalizer import naturalize_caption
@@ -82,6 +84,7 @@ except ImportError:
ethnicity_choices,
generation_profile_choices,
load_character_profile_json,
seed_mode_choices,
subcategory_choices,
)
from caption_naturalizer import naturalize_caption
@@ -192,21 +195,27 @@ class SxCPPromptBuilder:
class SxCPSeedControl:
SEED_AXES = (
"category",
"subcategory",
"content",
"person",
"scene",
"pose",
"role",
"expression",
"composition",
)
@classmethod
def INPUT_TYPES(cls):
seed_spec = {"default": -1, "min": -1, "max": 0xFFFFFFFF, "step": 1}
required = {}
for axis in cls.SEED_AXES:
required[f"{axis}_seed_mode"] = (seed_mode_choices(), {"default": "auto"})
required[f"{axis}_seed"] = ("INT", seed_spec)
return {
"required": {
"category_seed": ("INT", seed_spec),
"subcategory_seed": ("INT", seed_spec),
"content_seed": ("INT", seed_spec),
"person_seed": ("INT", seed_spec),
"scene_seed": ("INT", seed_spec),
"pose_seed": ("INT", seed_spec),
"role_seed": ("INT", seed_spec),
"expression_seed": ("INT", seed_spec),
"composition_seed": ("INT", seed_spec),
}
"required": required
}
RETURN_TYPES = ("STRING",)
@@ -214,16 +223,32 @@ class SxCPSeedControl:
FUNCTION = "build"
CATEGORY = "prompt_builder"
@classmethod
def IS_CHANGED(cls, *args, **kwargs):
values = list(args) + list(kwargs.values())
if "random" in values:
return random.random()
return tuple(args), tuple(sorted(kwargs.items()))
def build(
self,
category_seed_mode,
category_seed,
subcategory_seed_mode,
subcategory_seed,
content_seed_mode,
content_seed,
person_seed_mode,
person_seed,
scene_seed_mode,
scene_seed,
pose_seed_mode,
pose_seed,
role_seed_mode,
role_seed,
expression_seed_mode,
expression_seed,
composition_seed_mode,
composition_seed,
):
return (
@@ -237,6 +262,15 @@ class SxCPSeedControl:
role_seed=role_seed,
expression_seed=expression_seed,
composition_seed=composition_seed,
category_seed_mode=category_seed_mode,
subcategory_seed_mode=subcategory_seed_mode,
content_seed_mode=content_seed_mode,
person_seed_mode=person_seed_mode,
scene_seed_mode=scene_seed_mode,
pose_seed_mode=pose_seed_mode,
role_seed_mode=role_seed_mode,
expression_seed_mode=expression_seed_mode,
composition_seed_mode=composition_seed_mode,
),
)
+35 -9
View File
@@ -60,6 +60,7 @@ SEED_LOCK_AXES = (
"expression",
"composition",
)
SEED_MODE_CHOICES = ["auto", "follow_main", "fixed", "random"]
ETHNICITY_FILTER_CHOICES = [
"any",
@@ -860,6 +861,10 @@ def subcategory_choices() -> list[str]:
return choices
def seed_mode_choices() -> list[str]:
return list(SEED_MODE_CHOICES)
CATEGORY_PRESETS = {
"auto_weighted": ("auto_weighted", RANDOM_SUBCATEGORY),
"women_casual": ("Casual clothes", RANDOM_SUBCATEGORY),
@@ -1192,18 +1197,39 @@ def build_seed_config_json(
role_seed: int = -1,
expression_seed: int = -1,
composition_seed: int = -1,
category_seed_mode: str = "auto",
subcategory_seed_mode: str = "auto",
content_seed_mode: str = "auto",
person_seed_mode: str = "auto",
scene_seed_mode: str = "auto",
pose_seed_mode: str = "auto",
role_seed_mode: str = "auto",
expression_seed_mode: str = "auto",
composition_seed_mode: str = "auto",
) -> str:
rng = random.SystemRandom()
def axis_seed(value: int, mode: str) -> int:
mode = mode if mode in SEED_MODE_CHOICES else "auto"
if mode == "auto":
return int(value)
if mode == "random":
return rng.randint(0, 0xFFFFFFFF)
if mode == "fixed":
return max(0, int(value))
return -1
return json.dumps(
{
"category_seed": int(category_seed),
"subcategory_seed": int(subcategory_seed),
"content_seed": int(content_seed),
"person_seed": int(person_seed),
"scene_seed": int(scene_seed),
"pose_seed": int(pose_seed),
"role_seed": int(role_seed),
"expression_seed": int(expression_seed),
"composition_seed": int(composition_seed),
"category_seed": axis_seed(category_seed, category_seed_mode),
"subcategory_seed": axis_seed(subcategory_seed, subcategory_seed_mode),
"content_seed": axis_seed(content_seed, content_seed_mode),
"person_seed": axis_seed(person_seed, person_seed_mode),
"scene_seed": axis_seed(scene_seed, scene_seed_mode),
"pose_seed": axis_seed(pose_seed, pose_seed_mode),
"role_seed": axis_seed(role_seed, role_seed_mode),
"expression_seed": axis_seed(expression_seed, expression_seed_mode),
"composition_seed": axis_seed(composition_seed, composition_seed_mode),
},
ensure_ascii=True,
sort_keys=True,