Add per-axis seed modes
This commit is contained in:
@@ -532,7 +532,15 @@ alone.
|
|||||||
## Seed Control
|
## Seed Control
|
||||||
|
|
||||||
The main `seed` input is still the default master seed. Connect `SxCP Seed
|
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:
|
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;
|
- `reroll_seed`: `-1` makes the selected axis follow the main prompt seed;
|
||||||
`0` or higher pins that selected axis to a specific seed.
|
`0` or higher pins that selected axis to a specific seed.
|
||||||
|
|
||||||
Seed values:
|
Seed values in `auto` mode:
|
||||||
|
|
||||||
- `-1`: follow the main seed.
|
- `-1`: follow the main seed.
|
||||||
- `0` or higher: override only that axis.
|
- `0` or higher: override only that axis.
|
||||||
|
|||||||
+45
-11
@@ -1,6 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import random
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from .prompt_builder import (
|
from .prompt_builder import (
|
||||||
@@ -40,6 +41,7 @@ try:
|
|||||||
ethnicity_choices,
|
ethnicity_choices,
|
||||||
generation_profile_choices,
|
generation_profile_choices,
|
||||||
load_character_profile_json,
|
load_character_profile_json,
|
||||||
|
seed_mode_choices,
|
||||||
subcategory_choices,
|
subcategory_choices,
|
||||||
)
|
)
|
||||||
from .caption_naturalizer import naturalize_caption
|
from .caption_naturalizer import naturalize_caption
|
||||||
@@ -82,6 +84,7 @@ except ImportError:
|
|||||||
ethnicity_choices,
|
ethnicity_choices,
|
||||||
generation_profile_choices,
|
generation_profile_choices,
|
||||||
load_character_profile_json,
|
load_character_profile_json,
|
||||||
|
seed_mode_choices,
|
||||||
subcategory_choices,
|
subcategory_choices,
|
||||||
)
|
)
|
||||||
from caption_naturalizer import naturalize_caption
|
from caption_naturalizer import naturalize_caption
|
||||||
@@ -192,21 +195,27 @@ class SxCPPromptBuilder:
|
|||||||
|
|
||||||
|
|
||||||
class SxCPSeedControl:
|
class SxCPSeedControl:
|
||||||
|
SEED_AXES = (
|
||||||
|
"category",
|
||||||
|
"subcategory",
|
||||||
|
"content",
|
||||||
|
"person",
|
||||||
|
"scene",
|
||||||
|
"pose",
|
||||||
|
"role",
|
||||||
|
"expression",
|
||||||
|
"composition",
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(cls):
|
def INPUT_TYPES(cls):
|
||||||
seed_spec = {"default": -1, "min": -1, "max": 0xFFFFFFFF, "step": 1}
|
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 {
|
return {
|
||||||
"required": {
|
"required": 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),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_TYPES = ("STRING",)
|
RETURN_TYPES = ("STRING",)
|
||||||
@@ -214,16 +223,32 @@ class SxCPSeedControl:
|
|||||||
FUNCTION = "build"
|
FUNCTION = "build"
|
||||||
CATEGORY = "prompt_builder"
|
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(
|
def build(
|
||||||
self,
|
self,
|
||||||
|
category_seed_mode,
|
||||||
category_seed,
|
category_seed,
|
||||||
|
subcategory_seed_mode,
|
||||||
subcategory_seed,
|
subcategory_seed,
|
||||||
|
content_seed_mode,
|
||||||
content_seed,
|
content_seed,
|
||||||
|
person_seed_mode,
|
||||||
person_seed,
|
person_seed,
|
||||||
|
scene_seed_mode,
|
||||||
scene_seed,
|
scene_seed,
|
||||||
|
pose_seed_mode,
|
||||||
pose_seed,
|
pose_seed,
|
||||||
|
role_seed_mode,
|
||||||
role_seed,
|
role_seed,
|
||||||
|
expression_seed_mode,
|
||||||
expression_seed,
|
expression_seed,
|
||||||
|
composition_seed_mode,
|
||||||
composition_seed,
|
composition_seed,
|
||||||
):
|
):
|
||||||
return (
|
return (
|
||||||
@@ -237,6 +262,15 @@ class SxCPSeedControl:
|
|||||||
role_seed=role_seed,
|
role_seed=role_seed,
|
||||||
expression_seed=expression_seed,
|
expression_seed=expression_seed,
|
||||||
composition_seed=composition_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
@@ -60,6 +60,7 @@ SEED_LOCK_AXES = (
|
|||||||
"expression",
|
"expression",
|
||||||
"composition",
|
"composition",
|
||||||
)
|
)
|
||||||
|
SEED_MODE_CHOICES = ["auto", "follow_main", "fixed", "random"]
|
||||||
|
|
||||||
ETHNICITY_FILTER_CHOICES = [
|
ETHNICITY_FILTER_CHOICES = [
|
||||||
"any",
|
"any",
|
||||||
@@ -860,6 +861,10 @@ def subcategory_choices() -> list[str]:
|
|||||||
return choices
|
return choices
|
||||||
|
|
||||||
|
|
||||||
|
def seed_mode_choices() -> list[str]:
|
||||||
|
return list(SEED_MODE_CHOICES)
|
||||||
|
|
||||||
|
|
||||||
CATEGORY_PRESETS = {
|
CATEGORY_PRESETS = {
|
||||||
"auto_weighted": ("auto_weighted", RANDOM_SUBCATEGORY),
|
"auto_weighted": ("auto_weighted", RANDOM_SUBCATEGORY),
|
||||||
"women_casual": ("Casual clothes", RANDOM_SUBCATEGORY),
|
"women_casual": ("Casual clothes", RANDOM_SUBCATEGORY),
|
||||||
@@ -1192,18 +1197,39 @@ def build_seed_config_json(
|
|||||||
role_seed: int = -1,
|
role_seed: int = -1,
|
||||||
expression_seed: int = -1,
|
expression_seed: int = -1,
|
||||||
composition_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:
|
) -> 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(
|
return json.dumps(
|
||||||
{
|
{
|
||||||
"category_seed": int(category_seed),
|
"category_seed": axis_seed(category_seed, category_seed_mode),
|
||||||
"subcategory_seed": int(subcategory_seed),
|
"subcategory_seed": axis_seed(subcategory_seed, subcategory_seed_mode),
|
||||||
"content_seed": int(content_seed),
|
"content_seed": axis_seed(content_seed, content_seed_mode),
|
||||||
"person_seed": int(person_seed),
|
"person_seed": axis_seed(person_seed, person_seed_mode),
|
||||||
"scene_seed": int(scene_seed),
|
"scene_seed": axis_seed(scene_seed, scene_seed_mode),
|
||||||
"pose_seed": int(pose_seed),
|
"pose_seed": axis_seed(pose_seed, pose_seed_mode),
|
||||||
"role_seed": int(role_seed),
|
"role_seed": axis_seed(role_seed, role_seed_mode),
|
||||||
"expression_seed": int(expression_seed),
|
"expression_seed": axis_seed(expression_seed, expression_seed_mode),
|
||||||
"composition_seed": int(composition_seed),
|
"composition_seed": axis_seed(composition_seed, composition_seed_mode),
|
||||||
},
|
},
|
||||||
ensure_ascii=True,
|
ensure_ascii=True,
|
||||||
sort_keys=True,
|
sort_keys=True,
|
||||||
|
|||||||
Reference in New Issue
Block a user