Add SDXL bucket size node

This commit is contained in:
2026-06-25 14:10:29 +02:00
parent 57587fccf3
commit f2c768458f
2 changed files with 131 additions and 0 deletions
+8
View File
@@ -9,6 +9,7 @@ The node is registered as:
- `prompt_builder / SxCP Global Seed` - `prompt_builder / SxCP Global Seed`
- `prompt_builder / SxCP Seed Control` - `prompt_builder / SxCP Seed Control`
- `prompt_builder / SxCP Seed Locker` - `prompt_builder / SxCP Seed Locker`
- `prompt_builder / util / SxCP SDXL Bucket Size`
- `prompt_builder / SxCP Camera Control` - `prompt_builder / SxCP Camera Control`
- `prompt_builder / SxCP Camera Orbit Control` - `prompt_builder / SxCP Camera Orbit Control`
- `prompt_builder / SxCP Qwen Camera Translator` - `prompt_builder / SxCP Qwen Camera Translator`
@@ -309,6 +310,13 @@ you like, choose one `reroll_axis`, and connect its `seed_config`. All other
axes stay frozen to `base_seed`; the rerolled axis follows `reroll_seed`, or the axes stay frozen to `base_seed`; the rerolled axis follows `reroll_seed`, or the
main prompt seed when `reroll_seed=-1`. main prompt seed when `reroll_seed=-1`.
`SxCP SDXL Bucket Size` randomly selects one of the built-in SDXL bucket
resolutions and outputs `width`, `height`, and a `resolution` string. Use
`orientation` to restrict the pool to portrait, square, or landscape. Leave
`bucket_index=0` for random selection, or set `bucket_index` to pick a specific
position inside the filtered pool. Connect `SxCP Global Seed` or Seed Locker's
`seed_config` when the bucket choice must be reproducible.
`SxCP Camera Control` and `SxCP Camera Orbit Control` output `camera_config`, `SxCP Camera Control` and `SxCP Camera Orbit Control` output `camera_config`,
which can be connected to the prompt builder or the Insta/OF pair node. They which can be connected to the prompt builder or the Insta/OF pair node. They
make camera/framing first-class instead of relying on a weak phrase inside the make camera/framing first-class instead of relying on a weak phrase inside the
+123
View File
@@ -27,6 +27,20 @@ SXCP_CHARACTER_CAST = "SXCP_CHARACTER_CAST"
SXCP_CHARACTER_SLOT = "SXCP_CHARACTER_SLOT" SXCP_CHARACTER_SLOT = "SXCP_CHARACTER_SLOT"
SXCP_CHARACTER_PROFILE = "SXCP_CHARACTER_PROFILE" SXCP_CHARACTER_PROFILE = "SXCP_CHARACTER_PROFILE"
SDXL_BUCKET_RESOLUTIONS = [
{"orientation": "portrait", "width": 896, "height": 1792, "aspect": 0.50, "mp": 1.61},
{"orientation": "portrait", "width": 960, "height": 1664, "aspect": 0.58, "mp": 1.60},
{"orientation": "portrait", "width": 1024, "height": 1600, "aspect": 0.64, "mp": 1.64},
{"orientation": "portrait", "width": 1088, "height": 1472, "aspect": 0.74, "mp": 1.60},
{"orientation": "portrait", "width": 1152, "height": 1408, "aspect": 0.82, "mp": 1.62},
{"orientation": "portrait", "width": 1216, "height": 1344, "aspect": 0.90, "mp": 1.63},
{"orientation": "square", "width": 1280, "height": 1280, "aspect": 1.00, "mp": 1.64},
{"orientation": "landscape", "width": 1344, "height": 1216, "aspect": 1.11, "mp": 1.63},
{"orientation": "landscape", "width": 1408, "height": 1152, "aspect": 1.22, "mp": 1.62},
{"orientation": "landscape", "width": 1472, "height": 1088, "aspect": 1.35, "mp": 1.60},
{"orientation": "landscape", "width": 1536, "height": 1024, "aspect": 1.50, "mp": 1.57},
]
COMMON_INPUT_TOOLTIPS = { COMMON_INPUT_TOOLTIPS = {
"row_number": "Generation row to use. Changing it advances the deterministic selection without changing the main seed.", "row_number": "Generation row to use. Changing it advances the deterministic selection without changing the main seed.",
@@ -63,6 +77,8 @@ COMMON_INPUT_TOOLTIPS = {
"extra_negative": "Extra negative text appended after the generated negative prompt.", "extra_negative": "Extra negative text appended after the generated negative prompt.",
"trigger": "Training or style trigger token.", "trigger": "Training or style trigger token.",
"prepend_trigger_to_prompt": "If enabled, put the trigger token at the start of generated prompts.", "prepend_trigger_to_prompt": "If enabled, put the trigger token at the start of generated prompts.",
"bucket_index": "0 picks a random bucket. 1+ picks that position inside the selected orientation pool.",
"megapixels": "Approximate megapixel count for the selected bucket.",
"enabled": "Enable this node's effect while keeping it wired in the graph.", "enabled": "Enable this node's effect while keeping it wired in the graph.",
"combine_mode": "replace starts a new pool/config; add merges selected values into the incoming config.", "combine_mode": "replace starts a new pool/config; add merges selected values into the incoming config.",
"manual": "Manual character details config. Non-empty manual fields override generated slot details.", "manual": "Manual character details config. Non-empty manual fields override generated slot details.",
@@ -187,6 +203,13 @@ NODE_INPUT_TOOLTIPS = {
"SxCPSeedLocker": { "SxCPSeedLocker": {
"reroll_axis": "Choose the one axis to change while the rest stays locked. Use pose for sexual pose, scene for location, person for appearance.", "reroll_axis": "Choose the one axis to change while the rest stays locked. Use pose for sexual pose, scene for location, person for appearance.",
}, },
"SxCPSDXLBucketSize": {
"orientation": "Bucket orientation filter. any uses the full table; portrait/square/landscape restrict random selection.",
"seed": "Fixed bucket seed. Use -1 for a fresh random bucket each queue, or connect Global Seed for reproducible sizes.",
"row_number": "Deterministic row offset for the bucket. With a fixed seed, changing this advances the bucket choice.",
"bucket_index": "0=random. 1+ selects that bucket position inside the selected orientation pool and ignores seed.",
"seed_config": "Optional seed config. The composition seed controls bucket choice, so Seed Locker can keep sizes fixed while rerolling pose/person.",
},
"SxCPCameraControl": { "SxCPCameraControl": {
"camera_mode": "Camera style preset. Use from_camera_config in Insta/OF options to consume this.", "camera_mode": "Camera style preset. Use from_camera_config in Insta/OF options to consume this.",
"priority": "locked makes the camera wording strict; soft_hint allows the model more freedom.", "priority": "locked makes the camera wording strict; soft_hint allows the model more freedom.",
@@ -817,6 +840,104 @@ class SxCPSeedLocker:
return config, summary return config, summary
class SxCPSDXLBucketSize:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"orientation": (["any", "portrait", "square", "landscape"], {"default": "any"}),
"seed": ("INT", {"default": -1, "min": -1, "max": 0xFFFFFFFF, "step": 1}),
"row_number": ("INT", {"default": 1, "min": 1, "max": 1000000, "step": 1}),
"bucket_index": ("INT", {"default": 0, "min": 0, "max": len(SDXL_BUCKET_RESOLUTIONS), "step": 1}),
},
"optional": {
"seed_config": (SXCP_SEED_CONFIG,),
},
}
RETURN_TYPES = ("INT", "INT", "STRING", "STRING", "FLOAT", "FLOAT", "INT", "STRING")
RETURN_NAMES = ("width", "height", "resolution", "orientation", "aspect", "megapixels", "bucket_index", "summary")
FUNCTION = "build"
CATEGORY = "prompt_builder/util"
@staticmethod
def _configured_bucket_seed(seed_config):
if not seed_config:
return None
if isinstance(seed_config, dict):
raw = seed_config
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
def IS_CHANGED(cls, *args, **kwargs):
seed_value = kwargs.get("seed")
if seed_value is None and len(args) > 1:
seed_value = args[1]
bucket_index = kwargs.get("bucket_index")
if bucket_index is None and len(args) > 3:
bucket_index = args[3]
seed_config = kwargs.get("seed_config", "")
if not seed_config and len(args) > 4:
seed_config = args[4]
try:
seed = int(seed_value)
except (TypeError, ValueError):
seed = -1
try:
index = int(bucket_index)
except (TypeError, ValueError):
index = 0
if index <= 0 and seed < 0 and cls._configured_bucket_seed(seed_config) is None:
return random.random()
return tuple(args), tuple(sorted(kwargs.items()))
def build(self, orientation, seed, row_number, bucket_index, seed_config=""):
orientation = str(orientation or "any").strip().lower()
pool = [
(index + 1, bucket)
for index, bucket in enumerate(SDXL_BUCKET_RESOLUTIONS)
if orientation == "any" or bucket["orientation"] == orientation
]
if not pool:
pool = list(enumerate(SDXL_BUCKET_RESOLUTIONS, start=1))
if int(bucket_index) > 0:
pool_position = max(1, min(len(pool), int(bucket_index))) - 1
else:
configured_seed = self._configured_bucket_seed(seed_config)
if configured_seed is None and int(seed) < 0:
rng = random.Random(random.getrandbits(64))
else:
bucket_seed = configured_seed if configured_seed is not None else int(seed)
rng = random.Random(f"sdxl_bucket:{bucket_seed}:{int(row_number)}:{orientation}")
pool_position = rng.randrange(len(pool))
selected_index, selected = pool[pool_position]
width = int(selected["width"])
height = int(selected["height"])
selected_orientation = str(selected["orientation"])
aspect = float(selected["aspect"])
mp = float(selected["mp"])
resolution = f"{width}x{height}"
summary = (
f"{selected_orientation} bucket {pool_position + 1}/{len(pool)} "
f"(table {selected_index}): {resolution}, aspect {aspect:.2f}, {mp:.2f} MP"
)
return width, height, resolution, selected_orientation, aspect, mp, selected_index, summary
class SxCPCameraControl: class SxCPCameraControl:
@classmethod @classmethod
def INPUT_TYPES(cls): def INPUT_TYPES(cls):
@@ -2475,6 +2596,7 @@ NODE_CLASS_MAPPINGS = {
"SxCPGlobalSeed": SxCPGlobalSeed, "SxCPGlobalSeed": SxCPGlobalSeed,
"SxCPSeedControl": SxCPSeedControl, "SxCPSeedControl": SxCPSeedControl,
"SxCPSeedLocker": SxCPSeedLocker, "SxCPSeedLocker": SxCPSeedLocker,
"SxCPSDXLBucketSize": SxCPSDXLBucketSize,
"SxCPCameraControl": SxCPCameraControl, "SxCPCameraControl": SxCPCameraControl,
"SxCPCameraOrbitControl": SxCPCameraOrbitControl, "SxCPCameraOrbitControl": SxCPCameraOrbitControl,
"SxCPQwenCameraTranslator": SxCPQwenCameraTranslator, "SxCPQwenCameraTranslator": SxCPQwenCameraTranslator,
@@ -2515,6 +2637,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"SxCPGlobalSeed": "SxCP Global Seed", "SxCPGlobalSeed": "SxCP Global Seed",
"SxCPSeedControl": "SxCP Seed Control", "SxCPSeedControl": "SxCP Seed Control",
"SxCPSeedLocker": "SxCP Seed Locker", "SxCPSeedLocker": "SxCP Seed Locker",
"SxCPSDXLBucketSize": "SxCP SDXL Bucket Size",
"SxCPCameraControl": "SxCP Camera Control", "SxCPCameraControl": "SxCP Camera Control",
"SxCPCameraOrbitControl": "SxCP Camera Orbit Control", "SxCPCameraOrbitControl": "SxCP Camera Orbit Control",
"SxCPQwenCameraTranslator": "SxCP Qwen Camera Translator", "SxCPQwenCameraTranslator": "SxCP Qwen Camera Translator",