Extract profile filter nodes
This commit is contained in:
+10
-221
@@ -404,6 +404,10 @@ try:
|
|||||||
NODE_CLASS_MAPPINGS as CAMERA_NODE_CLASS_MAPPINGS,
|
NODE_CLASS_MAPPINGS as CAMERA_NODE_CLASS_MAPPINGS,
|
||||||
NODE_DISPLAY_NAME_MAPPINGS as CAMERA_NODE_DISPLAY_NAME_MAPPINGS,
|
NODE_DISPLAY_NAME_MAPPINGS as CAMERA_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
)
|
)
|
||||||
|
from .node_profile_filter import (
|
||||||
|
NODE_CLASS_MAPPINGS as PROFILE_FILTER_NODE_CLASS_MAPPINGS,
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS as PROFILE_FILTER_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
|
)
|
||||||
from .node_route_config import (
|
from .node_route_config import (
|
||||||
NODE_CLASS_MAPPINGS as ROUTE_CONFIG_NODE_CLASS_MAPPINGS,
|
NODE_CLASS_MAPPINGS as ROUTE_CONFIG_NODE_CLASS_MAPPINGS,
|
||||||
NODE_DISPLAY_NAME_MAPPINGS as ROUTE_CONFIG_NODE_DISPLAY_NAME_MAPPINGS,
|
NODE_DISPLAY_NAME_MAPPINGS as ROUTE_CONFIG_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
@@ -417,9 +421,6 @@ try:
|
|||||||
build_character_manual_config_json,
|
build_character_manual_config_json,
|
||||||
build_character_profile_json,
|
build_character_profile_json,
|
||||||
build_characteristics_config_json,
|
build_characteristics_config_json,
|
||||||
build_ethnicity_list_json,
|
|
||||||
build_filter_config_json,
|
|
||||||
build_generation_profile_json,
|
|
||||||
build_hair_config_json,
|
build_hair_config_json,
|
||||||
build_hardcore_action_filter_json,
|
build_hardcore_action_filter_json,
|
||||||
build_hardcore_position_pool_json,
|
build_hardcore_position_pool_json,
|
||||||
@@ -449,7 +450,6 @@ try:
|
|||||||
character_softcore_outfit_values,
|
character_softcore_outfit_values,
|
||||||
character_woman_body_choices,
|
character_woman_body_choices,
|
||||||
ethnicity_choices,
|
ethnicity_choices,
|
||||||
generation_profile_choices,
|
|
||||||
hardcore_position_family_choices,
|
hardcore_position_family_choices,
|
||||||
hardcore_position_focus_choices,
|
hardcore_position_focus_choices,
|
||||||
hardcore_position_key_choices,
|
hardcore_position_key_choices,
|
||||||
@@ -474,6 +474,10 @@ except ImportError:
|
|||||||
NODE_CLASS_MAPPINGS as CAMERA_NODE_CLASS_MAPPINGS,
|
NODE_CLASS_MAPPINGS as CAMERA_NODE_CLASS_MAPPINGS,
|
||||||
NODE_DISPLAY_NAME_MAPPINGS as CAMERA_NODE_DISPLAY_NAME_MAPPINGS,
|
NODE_DISPLAY_NAME_MAPPINGS as CAMERA_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
)
|
)
|
||||||
|
from node_profile_filter import (
|
||||||
|
NODE_CLASS_MAPPINGS as PROFILE_FILTER_NODE_CLASS_MAPPINGS,
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS as PROFILE_FILTER_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
|
)
|
||||||
from node_route_config import (
|
from node_route_config import (
|
||||||
NODE_CLASS_MAPPINGS as ROUTE_CONFIG_NODE_CLASS_MAPPINGS,
|
NODE_CLASS_MAPPINGS as ROUTE_CONFIG_NODE_CLASS_MAPPINGS,
|
||||||
NODE_DISPLAY_NAME_MAPPINGS as ROUTE_CONFIG_NODE_DISPLAY_NAME_MAPPINGS,
|
NODE_DISPLAY_NAME_MAPPINGS as ROUTE_CONFIG_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
@@ -487,9 +491,6 @@ except ImportError:
|
|||||||
build_character_manual_config_json,
|
build_character_manual_config_json,
|
||||||
build_character_profile_json,
|
build_character_profile_json,
|
||||||
build_characteristics_config_json,
|
build_characteristics_config_json,
|
||||||
build_ethnicity_list_json,
|
|
||||||
build_filter_config_json,
|
|
||||||
build_generation_profile_json,
|
|
||||||
build_hair_config_json,
|
build_hair_config_json,
|
||||||
build_hardcore_action_filter_json,
|
build_hardcore_action_filter_json,
|
||||||
build_hardcore_position_pool_json,
|
build_hardcore_position_pool_json,
|
||||||
@@ -519,7 +520,6 @@ except ImportError:
|
|||||||
character_softcore_outfit_values,
|
character_softcore_outfit_values,
|
||||||
character_woman_body_choices,
|
character_woman_body_choices,
|
||||||
ethnicity_choices,
|
ethnicity_choices,
|
||||||
generation_profile_choices,
|
|
||||||
hardcore_position_family_choices,
|
hardcore_position_family_choices,
|
||||||
hardcore_position_focus_choices,
|
hardcore_position_focus_choices,
|
||||||
hardcore_position_key_choices,
|
hardcore_position_key_choices,
|
||||||
@@ -724,213 +724,6 @@ class SxCPPromptBuilder:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SxCPGenerationProfile:
|
|
||||||
@classmethod
|
|
||||||
def INPUT_TYPES(cls):
|
|
||||||
return {
|
|
||||||
"required": {
|
|
||||||
"profile": (generation_profile_choices(), {"default": "balanced"}),
|
|
||||||
"clothing_override": (["profile_default", "random", "full", "minimal"], {"default": "profile_default"}),
|
|
||||||
"poses_override": (["profile_default", "random", "standard", "evocative"], {"default": "profile_default"}),
|
|
||||||
"expression_enabled": ("BOOLEAN", {"default": True}),
|
|
||||||
"expression_intensity_mode": (["profile_default", "random", "fixed"], {"default": "profile_default"}),
|
|
||||||
"expression_intensity": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}),
|
|
||||||
"backside_bias": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}),
|
|
||||||
"minimal_clothing_ratio": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}),
|
|
||||||
"standard_pose_ratio": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}),
|
|
||||||
"trigger_policy": (["profile_default", "prepend_trigger", "do_not_prepend"], {"default": "profile_default"}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_TYPES = (SXCP_GENERATION_PROFILE, "STRING")
|
|
||||||
RETURN_NAMES = ("generation_profile", "summary")
|
|
||||||
FUNCTION = "build"
|
|
||||||
CATEGORY = "prompt_builder"
|
|
||||||
|
|
||||||
def build(
|
|
||||||
self,
|
|
||||||
profile,
|
|
||||||
clothing_override,
|
|
||||||
poses_override,
|
|
||||||
expression_enabled,
|
|
||||||
expression_intensity_mode,
|
|
||||||
expression_intensity,
|
|
||||||
backside_bias,
|
|
||||||
minimal_clothing_ratio,
|
|
||||||
standard_pose_ratio,
|
|
||||||
trigger_policy,
|
|
||||||
):
|
|
||||||
config = build_generation_profile_json(
|
|
||||||
profile=profile,
|
|
||||||
clothing_override=clothing_override,
|
|
||||||
poses_override=poses_override,
|
|
||||||
expression_enabled=expression_enabled,
|
|
||||||
expression_intensity_mode=expression_intensity_mode,
|
|
||||||
expression_intensity=expression_intensity,
|
|
||||||
backside_bias=backside_bias,
|
|
||||||
minimal_clothing_ratio=minimal_clothing_ratio,
|
|
||||||
standard_pose_ratio=standard_pose_ratio,
|
|
||||||
trigger_policy=trigger_policy,
|
|
||||||
)
|
|
||||||
parsed = json.loads(config)
|
|
||||||
if not parsed.get("expression_enabled", True):
|
|
||||||
expression_summary = "expression disabled"
|
|
||||||
elif float(parsed.get("expression_intensity", 0.5)) < 0:
|
|
||||||
expression_summary = "expression random"
|
|
||||||
else:
|
|
||||||
expression_summary = f"expression {parsed['expression_intensity']}"
|
|
||||||
summary = f"{parsed['profile']}: {parsed['clothing']}, {parsed['poses']}, {expression_summary}"
|
|
||||||
return config, summary
|
|
||||||
|
|
||||||
|
|
||||||
class SxCPAdvancedFilters:
|
|
||||||
@classmethod
|
|
||||||
def INPUT_TYPES(cls):
|
|
||||||
return {
|
|
||||||
"required": {
|
|
||||||
"include_european": ("BOOLEAN", {"default": True}),
|
|
||||||
"include_mediterranean_mena": ("BOOLEAN", {"default": True}),
|
|
||||||
"include_latina": ("BOOLEAN", {"default": True}),
|
|
||||||
"include_east_asian": ("BOOLEAN", {"default": True}),
|
|
||||||
"include_southeast_asian": ("BOOLEAN", {"default": True}),
|
|
||||||
"include_south_asian": ("BOOLEAN", {"default": True}),
|
|
||||||
"include_black_african": ("BOOLEAN", {"default": True}),
|
|
||||||
"include_indigenous": ("BOOLEAN", {"default": True}),
|
|
||||||
"include_mixed": ("BOOLEAN", {"default": True}),
|
|
||||||
"include_plus_size": ("BOOLEAN", {"default": True}),
|
|
||||||
"figure": (["random", "curvy", "balanced", "bombshell"], {"default": "random"}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_TYPES = (SXCP_FILTER_CONFIG,)
|
|
||||||
RETURN_NAMES = ("filter_config",)
|
|
||||||
FUNCTION = "build"
|
|
||||||
CATEGORY = "prompt_builder"
|
|
||||||
|
|
||||||
def build(
|
|
||||||
self,
|
|
||||||
include_european,
|
|
||||||
include_mediterranean_mena,
|
|
||||||
include_latina,
|
|
||||||
include_east_asian,
|
|
||||||
include_southeast_asian,
|
|
||||||
include_south_asian,
|
|
||||||
include_black_african,
|
|
||||||
include_indigenous,
|
|
||||||
include_mixed,
|
|
||||||
include_plus_size,
|
|
||||||
figure,
|
|
||||||
):
|
|
||||||
return (
|
|
||||||
build_filter_config_json(
|
|
||||||
figure=figure,
|
|
||||||
include_european=include_european,
|
|
||||||
include_mediterranean_mena=include_mediterranean_mena,
|
|
||||||
include_latina=include_latina,
|
|
||||||
include_east_asian=include_east_asian,
|
|
||||||
include_southeast_asian=include_southeast_asian,
|
|
||||||
include_south_asian=include_south_asian,
|
|
||||||
include_black_african=include_black_african,
|
|
||||||
include_indigenous=include_indigenous,
|
|
||||||
include_mixed=include_mixed,
|
|
||||||
include_plus_size=include_plus_size,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SxCPEthnicityList:
|
|
||||||
@classmethod
|
|
||||||
def INPUT_TYPES(cls):
|
|
||||||
return {
|
|
||||||
"required": {
|
|
||||||
"include_european": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_mediterranean_mena": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_latina": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_east_asian": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_southeast_asian": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_south_asian": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_black_african": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_indigenous": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_mixed": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_asian": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_white_asian": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_western_european": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_french_european": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_germanic_european": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_nordic_european": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_celtic_european": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_slavic_european": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_baltic_european": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_alpine_european": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_balkan_european": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_greek_mediterranean": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_italian_mediterranean": ("BOOLEAN", {"default": False}),
|
|
||||||
"include_iberian_mediterranean": ("BOOLEAN", {"default": False}),
|
|
||||||
"strict_excludes": ("BOOLEAN", {"default": True}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_TYPES = (SXCP_ETHNICITY_LIST, SXCP_FILTER_CONFIG, "STRING")
|
|
||||||
RETURN_NAMES = ("ethnicity_list", "filter_config", "summary")
|
|
||||||
FUNCTION = "build"
|
|
||||||
CATEGORY = "prompt_builder"
|
|
||||||
|
|
||||||
def build(
|
|
||||||
self,
|
|
||||||
include_european,
|
|
||||||
include_mediterranean_mena,
|
|
||||||
include_latina,
|
|
||||||
include_east_asian,
|
|
||||||
include_southeast_asian,
|
|
||||||
include_south_asian,
|
|
||||||
include_black_african,
|
|
||||||
include_indigenous,
|
|
||||||
include_mixed,
|
|
||||||
include_asian,
|
|
||||||
include_white_asian,
|
|
||||||
include_western_european,
|
|
||||||
include_french_european,
|
|
||||||
include_germanic_european,
|
|
||||||
include_nordic_european,
|
|
||||||
include_celtic_european,
|
|
||||||
include_slavic_european,
|
|
||||||
include_baltic_european,
|
|
||||||
include_alpine_european,
|
|
||||||
include_balkan_european,
|
|
||||||
include_greek_mediterranean,
|
|
||||||
include_italian_mediterranean,
|
|
||||||
include_iberian_mediterranean,
|
|
||||||
strict_excludes,
|
|
||||||
):
|
|
||||||
result = build_ethnicity_list_json(
|
|
||||||
include_european=include_european,
|
|
||||||
include_mediterranean_mena=include_mediterranean_mena,
|
|
||||||
include_latina=include_latina,
|
|
||||||
include_east_asian=include_east_asian,
|
|
||||||
include_southeast_asian=include_southeast_asian,
|
|
||||||
include_south_asian=include_south_asian,
|
|
||||||
include_black_african=include_black_african,
|
|
||||||
include_indigenous=include_indigenous,
|
|
||||||
include_mixed=include_mixed,
|
|
||||||
include_asian=include_asian,
|
|
||||||
include_white_asian=include_white_asian,
|
|
||||||
include_western_european=include_western_european,
|
|
||||||
include_french_european=include_french_european,
|
|
||||||
include_germanic_european=include_germanic_european,
|
|
||||||
include_nordic_european=include_nordic_european,
|
|
||||||
include_celtic_european=include_celtic_european,
|
|
||||||
include_slavic_european=include_slavic_european,
|
|
||||||
include_baltic_european=include_baltic_european,
|
|
||||||
include_alpine_european=include_alpine_european,
|
|
||||||
include_balkan_european=include_balkan_european,
|
|
||||||
include_greek_mediterranean=include_greek_mediterranean,
|
|
||||||
include_italian_mediterranean=include_italian_mediterranean,
|
|
||||||
include_iberian_mediterranean=include_iberian_mediterranean,
|
|
||||||
strict_excludes=strict_excludes,
|
|
||||||
)
|
|
||||||
return result["ethnicity"], result["filter_config"], result["summary"]
|
|
||||||
|
|
||||||
|
|
||||||
class _SxCPHairAxisNode:
|
class _SxCPHairAxisNode:
|
||||||
AXIS = "color"
|
AXIS = "color"
|
||||||
PREFIX = "include"
|
PREFIX = "include"
|
||||||
@@ -2199,9 +1992,8 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
NODE_CLASS_MAPPINGS.update(SEED_RESOLUTION_NODE_CLASS_MAPPINGS)
|
NODE_CLASS_MAPPINGS.update(SEED_RESOLUTION_NODE_CLASS_MAPPINGS)
|
||||||
NODE_CLASS_MAPPINGS.update(CAMERA_NODE_CLASS_MAPPINGS)
|
NODE_CLASS_MAPPINGS.update(CAMERA_NODE_CLASS_MAPPINGS)
|
||||||
NODE_CLASS_MAPPINGS.update(ROUTE_CONFIG_NODE_CLASS_MAPPINGS)
|
NODE_CLASS_MAPPINGS.update(ROUTE_CONFIG_NODE_CLASS_MAPPINGS)
|
||||||
|
NODE_CLASS_MAPPINGS.update(PROFILE_FILTER_NODE_CLASS_MAPPINGS)
|
||||||
NODE_CLASS_MAPPINGS.update({
|
NODE_CLASS_MAPPINGS.update({
|
||||||
"SxCPGenerationProfile": SxCPGenerationProfile,
|
|
||||||
"SxCPEthnicityList": SxCPEthnicityList,
|
|
||||||
"SxCPHairLength": SxCPHairLength,
|
"SxCPHairLength": SxCPHairLength,
|
||||||
"SxCPHairColor": SxCPHairColor,
|
"SxCPHairColor": SxCPHairColor,
|
||||||
"SxCPHairStyle": SxCPHairStyle,
|
"SxCPHairStyle": SxCPHairStyle,
|
||||||
@@ -2214,7 +2006,6 @@ NODE_CLASS_MAPPINGS.update({
|
|||||||
"SxCPHardcorePositionPool": SxCPHardcorePositionPool,
|
"SxCPHardcorePositionPool": SxCPHardcorePositionPool,
|
||||||
"SxCPHardcoreActionFilter": SxCPHardcoreActionFilter,
|
"SxCPHardcoreActionFilter": SxCPHardcoreActionFilter,
|
||||||
"SxCPCharacterManualDetails": SxCPCharacterManualDetails,
|
"SxCPCharacterManualDetails": SxCPCharacterManualDetails,
|
||||||
"SxCPAdvancedFilters": SxCPAdvancedFilters,
|
|
||||||
"SxCPPromptBuilderFromConfigs": SxCPPromptBuilderFromConfigs,
|
"SxCPPromptBuilderFromConfigs": SxCPPromptBuilderFromConfigs,
|
||||||
"SxCPWomanSlot": SxCPWomanSlot,
|
"SxCPWomanSlot": SxCPWomanSlot,
|
||||||
"SxCPManSlot": SxCPManSlot,
|
"SxCPManSlot": SxCPManSlot,
|
||||||
@@ -2236,9 +2027,8 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
|||||||
NODE_DISPLAY_NAME_MAPPINGS.update(SEED_RESOLUTION_NODE_DISPLAY_NAME_MAPPINGS)
|
NODE_DISPLAY_NAME_MAPPINGS.update(SEED_RESOLUTION_NODE_DISPLAY_NAME_MAPPINGS)
|
||||||
NODE_DISPLAY_NAME_MAPPINGS.update(CAMERA_NODE_DISPLAY_NAME_MAPPINGS)
|
NODE_DISPLAY_NAME_MAPPINGS.update(CAMERA_NODE_DISPLAY_NAME_MAPPINGS)
|
||||||
NODE_DISPLAY_NAME_MAPPINGS.update(ROUTE_CONFIG_NODE_DISPLAY_NAME_MAPPINGS)
|
NODE_DISPLAY_NAME_MAPPINGS.update(ROUTE_CONFIG_NODE_DISPLAY_NAME_MAPPINGS)
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS.update(PROFILE_FILTER_NODE_DISPLAY_NAME_MAPPINGS)
|
||||||
NODE_DISPLAY_NAME_MAPPINGS.update({
|
NODE_DISPLAY_NAME_MAPPINGS.update({
|
||||||
"SxCPGenerationProfile": "SxCP Generation Profile",
|
|
||||||
"SxCPEthnicityList": "SxCP Ethnicity List",
|
|
||||||
"SxCPHairLength": "SxCP Hair Length",
|
"SxCPHairLength": "SxCP Hair Length",
|
||||||
"SxCPHairColor": "SxCP Hair Color",
|
"SxCPHairColor": "SxCP Hair Color",
|
||||||
"SxCPHairStyle": "SxCP Hair Style/Cut",
|
"SxCPHairStyle": "SxCP Hair Style/Cut",
|
||||||
@@ -2251,7 +2041,6 @@ NODE_DISPLAY_NAME_MAPPINGS.update({
|
|||||||
"SxCPHardcorePositionPool": "SxCP Hardcore Position Pool",
|
"SxCPHardcorePositionPool": "SxCP Hardcore Position Pool",
|
||||||
"SxCPHardcoreActionFilter": "SxCP Hardcore Action Filter",
|
"SxCPHardcoreActionFilter": "SxCP Hardcore Action Filter",
|
||||||
"SxCPCharacterManualDetails": "SxCP Character Manual Details",
|
"SxCPCharacterManualDetails": "SxCP Character Manual Details",
|
||||||
"SxCPAdvancedFilters": "SxCP Advanced Filters",
|
|
||||||
"SxCPPromptBuilderFromConfigs": "SxCP Prompt Builder From Configs",
|
"SxCPPromptBuilderFromConfigs": "SxCP Prompt Builder From Configs",
|
||||||
"SxCPWomanSlot": "SxCP Woman Slot",
|
"SxCPWomanSlot": "SxCP Woman Slot",
|
||||||
"SxCPManSlot": "SxCP Man Slot",
|
"SxCPManSlot": "SxCP Man Slot",
|
||||||
|
|||||||
@@ -273,7 +273,7 @@ Improve later:
|
|||||||
### Node / UI Path
|
### Node / UI Path
|
||||||
|
|
||||||
Owner: `__init__.py`, `node_seed_resolution.py`, `node_camera.py`,
|
Owner: `__init__.py`, `node_seed_resolution.py`, `node_camera.py`,
|
||||||
`node_route_config.py`, `loop_nodes.py`, `web/*.js`.
|
`node_route_config.py`, `node_profile_filter.py`, `loop_nodes.py`, `web/*.js`.
|
||||||
|
|
||||||
Keep here:
|
Keep here:
|
||||||
|
|
||||||
@@ -285,6 +285,7 @@ Keep here:
|
|||||||
- camera utility node declarations in `node_camera.py`.
|
- camera utility node declarations in `node_camera.py`.
|
||||||
- route/category/location/composition/cast config node declarations in
|
- route/category/location/composition/cast config node declarations in
|
||||||
`node_route_config.py`.
|
`node_route_config.py`.
|
||||||
|
- profile/filter/ethnicity-list node declarations in `node_profile_filter.py`.
|
||||||
|
|
||||||
Already isolated:
|
Already isolated:
|
||||||
|
|
||||||
@@ -295,6 +296,8 @@ Already isolated:
|
|||||||
- category preset, location/composition pool, location theme, and cast config
|
- category preset, location/composition pool, location theme, and cast config
|
||||||
utility nodes live in `node_route_config.py`, with registration maps imported
|
utility nodes live in `node_route_config.py`, with registration maps imported
|
||||||
by `__init__.py`.
|
by `__init__.py`.
|
||||||
|
- generation profile, advanced filter, and ethnicity list utility nodes live in
|
||||||
|
`node_profile_filter.py`, with registration maps imported by `__init__.py`.
|
||||||
|
|
||||||
Improve later:
|
Improve later:
|
||||||
|
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ When a result is wrong, first identify which layer owns the bad text:
|
|||||||
- Raw builder prompt acceptable, SDXL tags wrong: edit `sdxl_formatter.py`.
|
- Raw builder prompt acceptable, SDXL tags wrong: edit `sdxl_formatter.py`.
|
||||||
- Natural caption/training caption wrong: edit `caption_naturalizer.py`.
|
- Natural caption/training caption wrong: edit `caption_naturalizer.py`.
|
||||||
- UI/preview/loop behavior wrong: edit `__init__.py`, node family modules such
|
- UI/preview/loop behavior wrong: edit `__init__.py`, node family modules such
|
||||||
as `node_seed_resolution.py`, `node_camera.py`, or `node_route_config.py`,
|
as `node_seed_resolution.py`, `node_camera.py`, `node_route_config.py`, or
|
||||||
`loop_nodes.py`, or `web/*.js`.
|
`node_profile_filter.py`, `loop_nodes.py`, or `web/*.js`.
|
||||||
|
|
||||||
## High-Level Routes
|
## High-Level Routes
|
||||||
|
|
||||||
@@ -695,6 +695,7 @@ These do not own prompt pool wording, but they affect execution and review:
|
|||||||
| Seed and resolution utility nodes | `node_seed_resolution.py`, imported by `__init__.py` | Global/per-axis seed configs plus SDXL/Krea width/height helpers. |
|
| Seed and resolution utility nodes | `node_seed_resolution.py`, imported by `__init__.py` | Global/per-axis seed configs plus SDXL/Krea width/height helpers. |
|
||||||
| Camera utility nodes | `node_camera.py`, imported by `__init__.py` | Direct camera config, orbit-to-camera config, and Qwen MultiAngle camera translation. |
|
| Camera utility nodes | `node_camera.py`, imported by `__init__.py` | Direct camera config, orbit-to-camera config, and Qwen MultiAngle camera translation. |
|
||||||
| Route config utility nodes | `node_route_config.py`, imported by `__init__.py` | Category preset, location/composition pool, location theme, and cast config helpers. |
|
| Route config utility nodes | `node_route_config.py`, imported by `__init__.py` | Category preset, location/composition pool, location theme, and cast config helpers. |
|
||||||
|
| Profile/filter utility nodes | `node_profile_filter.py`, imported by `__init__.py` | Generation profile, advanced filter config, and ethnicity list helpers. |
|
||||||
|
|
||||||
## Drift Audit Helper
|
## Drift Audit Helper
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,243 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .prompt_builder import (
|
||||||
|
build_ethnicity_list_json,
|
||||||
|
build_filter_config_json,
|
||||||
|
build_generation_profile_json,
|
||||||
|
generation_profile_choices,
|
||||||
|
)
|
||||||
|
except ImportError: # Allows local smoke tests from the repository root.
|
||||||
|
from prompt_builder import (
|
||||||
|
build_ethnicity_list_json,
|
||||||
|
build_filter_config_json,
|
||||||
|
build_generation_profile_json,
|
||||||
|
generation_profile_choices,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
SXCP_GENERATION_PROFILE = "SXCP_GENERATION_PROFILE"
|
||||||
|
SXCP_FILTER_CONFIG = "SXCP_FILTER_CONFIG"
|
||||||
|
SXCP_ETHNICITY_LIST = "SXCP_ETHNICITY_LIST"
|
||||||
|
|
||||||
|
|
||||||
|
class SxCPGenerationProfile:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"profile": (generation_profile_choices(), {"default": "balanced"}),
|
||||||
|
"clothing_override": (["profile_default", "random", "full", "minimal"], {"default": "profile_default"}),
|
||||||
|
"poses_override": (["profile_default", "random", "standard", "evocative"], {"default": "profile_default"}),
|
||||||
|
"expression_enabled": ("BOOLEAN", {"default": True}),
|
||||||
|
"expression_intensity_mode": (["profile_default", "random", "fixed"], {"default": "profile_default"}),
|
||||||
|
"expression_intensity": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}),
|
||||||
|
"backside_bias": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}),
|
||||||
|
"minimal_clothing_ratio": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}),
|
||||||
|
"standard_pose_ratio": ("FLOAT", {"default": -1.0, "min": -1.0, "max": 1.0, "step": 0.01}),
|
||||||
|
"trigger_policy": (["profile_default", "prepend_trigger", "do_not_prepend"], {"default": "profile_default"}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = (SXCP_GENERATION_PROFILE, "STRING")
|
||||||
|
RETURN_NAMES = ("generation_profile", "summary")
|
||||||
|
FUNCTION = "build"
|
||||||
|
CATEGORY = "prompt_builder"
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
profile,
|
||||||
|
clothing_override,
|
||||||
|
poses_override,
|
||||||
|
expression_enabled,
|
||||||
|
expression_intensity_mode,
|
||||||
|
expression_intensity,
|
||||||
|
backside_bias,
|
||||||
|
minimal_clothing_ratio,
|
||||||
|
standard_pose_ratio,
|
||||||
|
trigger_policy,
|
||||||
|
):
|
||||||
|
config = build_generation_profile_json(
|
||||||
|
profile=profile,
|
||||||
|
clothing_override=clothing_override,
|
||||||
|
poses_override=poses_override,
|
||||||
|
expression_enabled=expression_enabled,
|
||||||
|
expression_intensity_mode=expression_intensity_mode,
|
||||||
|
expression_intensity=expression_intensity,
|
||||||
|
backside_bias=backside_bias,
|
||||||
|
minimal_clothing_ratio=minimal_clothing_ratio,
|
||||||
|
standard_pose_ratio=standard_pose_ratio,
|
||||||
|
trigger_policy=trigger_policy,
|
||||||
|
)
|
||||||
|
parsed = json.loads(config)
|
||||||
|
if not parsed.get("expression_enabled", True):
|
||||||
|
expression_summary = "expression disabled"
|
||||||
|
elif float(parsed.get("expression_intensity", 0.5)) < 0:
|
||||||
|
expression_summary = "expression random"
|
||||||
|
else:
|
||||||
|
expression_summary = f"expression {parsed['expression_intensity']}"
|
||||||
|
summary = f"{parsed['profile']}: {parsed['clothing']}, {parsed['poses']}, {expression_summary}"
|
||||||
|
return config, summary
|
||||||
|
|
||||||
|
|
||||||
|
class SxCPAdvancedFilters:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"include_european": ("BOOLEAN", {"default": True}),
|
||||||
|
"include_mediterranean_mena": ("BOOLEAN", {"default": True}),
|
||||||
|
"include_latina": ("BOOLEAN", {"default": True}),
|
||||||
|
"include_east_asian": ("BOOLEAN", {"default": True}),
|
||||||
|
"include_southeast_asian": ("BOOLEAN", {"default": True}),
|
||||||
|
"include_south_asian": ("BOOLEAN", {"default": True}),
|
||||||
|
"include_black_african": ("BOOLEAN", {"default": True}),
|
||||||
|
"include_indigenous": ("BOOLEAN", {"default": True}),
|
||||||
|
"include_mixed": ("BOOLEAN", {"default": True}),
|
||||||
|
"include_plus_size": ("BOOLEAN", {"default": True}),
|
||||||
|
"figure": (["random", "curvy", "balanced", "bombshell"], {"default": "random"}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = (SXCP_FILTER_CONFIG,)
|
||||||
|
RETURN_NAMES = ("filter_config",)
|
||||||
|
FUNCTION = "build"
|
||||||
|
CATEGORY = "prompt_builder"
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
include_european,
|
||||||
|
include_mediterranean_mena,
|
||||||
|
include_latina,
|
||||||
|
include_east_asian,
|
||||||
|
include_southeast_asian,
|
||||||
|
include_south_asian,
|
||||||
|
include_black_african,
|
||||||
|
include_indigenous,
|
||||||
|
include_mixed,
|
||||||
|
include_plus_size,
|
||||||
|
figure,
|
||||||
|
):
|
||||||
|
return (
|
||||||
|
build_filter_config_json(
|
||||||
|
figure=figure,
|
||||||
|
include_european=include_european,
|
||||||
|
include_mediterranean_mena=include_mediterranean_mena,
|
||||||
|
include_latina=include_latina,
|
||||||
|
include_east_asian=include_east_asian,
|
||||||
|
include_southeast_asian=include_southeast_asian,
|
||||||
|
include_south_asian=include_south_asian,
|
||||||
|
include_black_african=include_black_african,
|
||||||
|
include_indigenous=include_indigenous,
|
||||||
|
include_mixed=include_mixed,
|
||||||
|
include_plus_size=include_plus_size,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SxCPEthnicityList:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"include_european": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_mediterranean_mena": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_latina": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_east_asian": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_southeast_asian": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_south_asian": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_black_african": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_indigenous": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_mixed": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_asian": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_white_asian": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_western_european": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_french_european": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_germanic_european": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_nordic_european": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_celtic_european": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_slavic_european": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_baltic_european": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_alpine_european": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_balkan_european": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_greek_mediterranean": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_italian_mediterranean": ("BOOLEAN", {"default": False}),
|
||||||
|
"include_iberian_mediterranean": ("BOOLEAN", {"default": False}),
|
||||||
|
"strict_excludes": ("BOOLEAN", {"default": True}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = (SXCP_ETHNICITY_LIST, SXCP_FILTER_CONFIG, "STRING")
|
||||||
|
RETURN_NAMES = ("ethnicity_list", "filter_config", "summary")
|
||||||
|
FUNCTION = "build"
|
||||||
|
CATEGORY = "prompt_builder"
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
include_european,
|
||||||
|
include_mediterranean_mena,
|
||||||
|
include_latina,
|
||||||
|
include_east_asian,
|
||||||
|
include_southeast_asian,
|
||||||
|
include_south_asian,
|
||||||
|
include_black_african,
|
||||||
|
include_indigenous,
|
||||||
|
include_mixed,
|
||||||
|
include_asian,
|
||||||
|
include_white_asian,
|
||||||
|
include_western_european,
|
||||||
|
include_french_european,
|
||||||
|
include_germanic_european,
|
||||||
|
include_nordic_european,
|
||||||
|
include_celtic_european,
|
||||||
|
include_slavic_european,
|
||||||
|
include_baltic_european,
|
||||||
|
include_alpine_european,
|
||||||
|
include_balkan_european,
|
||||||
|
include_greek_mediterranean,
|
||||||
|
include_italian_mediterranean,
|
||||||
|
include_iberian_mediterranean,
|
||||||
|
strict_excludes,
|
||||||
|
):
|
||||||
|
result = build_ethnicity_list_json(
|
||||||
|
include_european=include_european,
|
||||||
|
include_mediterranean_mena=include_mediterranean_mena,
|
||||||
|
include_latina=include_latina,
|
||||||
|
include_east_asian=include_east_asian,
|
||||||
|
include_southeast_asian=include_southeast_asian,
|
||||||
|
include_south_asian=include_south_asian,
|
||||||
|
include_black_african=include_black_african,
|
||||||
|
include_indigenous=include_indigenous,
|
||||||
|
include_mixed=include_mixed,
|
||||||
|
include_asian=include_asian,
|
||||||
|
include_white_asian=include_white_asian,
|
||||||
|
include_western_european=include_western_european,
|
||||||
|
include_french_european=include_french_european,
|
||||||
|
include_germanic_european=include_germanic_european,
|
||||||
|
include_nordic_european=include_nordic_european,
|
||||||
|
include_celtic_european=include_celtic_european,
|
||||||
|
include_slavic_european=include_slavic_european,
|
||||||
|
include_baltic_european=include_baltic_european,
|
||||||
|
include_alpine_european=include_alpine_european,
|
||||||
|
include_balkan_european=include_balkan_european,
|
||||||
|
include_greek_mediterranean=include_greek_mediterranean,
|
||||||
|
include_italian_mediterranean=include_italian_mediterranean,
|
||||||
|
include_iberian_mediterranean=include_iberian_mediterranean,
|
||||||
|
strict_excludes=strict_excludes,
|
||||||
|
)
|
||||||
|
return result["ethnicity"], result["filter_config"], result["summary"]
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"SxCPGenerationProfile": SxCPGenerationProfile,
|
||||||
|
"SxCPAdvancedFilters": SxCPAdvancedFilters,
|
||||||
|
"SxCPEthnicityList": SxCPEthnicityList,
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
|
"SxCPGenerationProfile": "SxCP Generation Profile",
|
||||||
|
"SxCPAdvancedFilters": "SxCP Advanced Filters",
|
||||||
|
"SxCPEthnicityList": "SxCP Ethnicity List",
|
||||||
|
}
|
||||||
@@ -1848,6 +1848,87 @@ def smoke_node_route_config_registration() -> None:
|
|||||||
_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")
|
||||||
|
|
||||||
|
|
||||||
|
def smoke_node_profile_filter_registration() -> None:
|
||||||
|
required_nodes = [
|
||||||
|
"SxCPGenerationProfile",
|
||||||
|
"SxCPAdvancedFilters",
|
||||||
|
"SxCPEthnicityList",
|
||||||
|
]
|
||||||
|
for node_name in required_nodes:
|
||||||
|
_expect(node_name in sxcp_nodes.NODE_CLASS_MAPPINGS, f"{node_name} missing from node registry")
|
||||||
|
_expect(node_name in sxcp_nodes.NODE_DISPLAY_NAME_MAPPINGS, f"{node_name} missing from display registry")
|
||||||
|
|
||||||
|
profile_node = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPGenerationProfile"]
|
||||||
|
profile_inputs = profile_node.INPUT_TYPES().get("required") or {}
|
||||||
|
_expect("profile" in profile_inputs, "Generation Profile lost profile input")
|
||||||
|
_expect("tooltip" in profile_inputs["profile"][1], "Generation Profile tooltip injection missing")
|
||||||
|
profile_config, profile_summary = profile_node().build(
|
||||||
|
profile="balanced",
|
||||||
|
clothing_override="profile_default",
|
||||||
|
poses_override="profile_default",
|
||||||
|
expression_enabled=True,
|
||||||
|
expression_intensity_mode="fixed",
|
||||||
|
expression_intensity=0.5,
|
||||||
|
backside_bias=-1,
|
||||||
|
minimal_clothing_ratio=-1,
|
||||||
|
standard_pose_ratio=-1,
|
||||||
|
trigger_policy="profile_default",
|
||||||
|
)
|
||||||
|
parsed_profile = json.loads(profile_config)
|
||||||
|
_expect(parsed_profile.get("profile") == "balanced", "Generation Profile output lost profile")
|
||||||
|
_expect(parsed_profile.get("expression_intensity") == 0.5, "Generation Profile output lost fixed expression intensity")
|
||||||
|
_expect("balanced:" in profile_summary, "Generation Profile summary changed unexpectedly")
|
||||||
|
|
||||||
|
filter_config = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPAdvancedFilters"]().build(
|
||||||
|
include_european=True,
|
||||||
|
include_mediterranean_mena=False,
|
||||||
|
include_latina=False,
|
||||||
|
include_east_asian=False,
|
||||||
|
include_southeast_asian=False,
|
||||||
|
include_south_asian=False,
|
||||||
|
include_black_african=True,
|
||||||
|
include_indigenous=False,
|
||||||
|
include_mixed=False,
|
||||||
|
include_plus_size=False,
|
||||||
|
figure="curvy",
|
||||||
|
)[0]
|
||||||
|
parsed_filter = json.loads(filter_config)
|
||||||
|
_expect(parsed_filter.get("figure") == "curvy", "Advanced Filters lost figure")
|
||||||
|
_expect(parsed_filter.get("ethnicity_includes") == ["european", "black_african"], "Advanced Filters ethnicity includes changed")
|
||||||
|
_expect(parsed_filter.get("no_plus_women") is True, "Advanced Filters should set no_plus_women when plus size is excluded")
|
||||||
|
|
||||||
|
ethnicity, ethnicity_filter_config, ethnicity_summary = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPEthnicityList"]().build(
|
||||||
|
include_european=False,
|
||||||
|
include_mediterranean_mena=False,
|
||||||
|
include_latina=False,
|
||||||
|
include_east_asian=False,
|
||||||
|
include_southeast_asian=False,
|
||||||
|
include_south_asian=False,
|
||||||
|
include_black_african=False,
|
||||||
|
include_indigenous=False,
|
||||||
|
include_mixed=False,
|
||||||
|
include_asian=False,
|
||||||
|
include_white_asian=False,
|
||||||
|
include_western_european=False,
|
||||||
|
include_french_european=True,
|
||||||
|
include_germanic_european=False,
|
||||||
|
include_nordic_european=False,
|
||||||
|
include_celtic_european=False,
|
||||||
|
include_slavic_european=False,
|
||||||
|
include_baltic_european=False,
|
||||||
|
include_alpine_european=False,
|
||||||
|
include_balkan_european=False,
|
||||||
|
include_greek_mediterranean=False,
|
||||||
|
include_italian_mediterranean=False,
|
||||||
|
include_iberian_mediterranean=False,
|
||||||
|
strict_excludes=True,
|
||||||
|
)
|
||||||
|
parsed_ethnicity_filter = json.loads(ethnicity_filter_config)
|
||||||
|
_expect("french_european" in ethnicity, "Ethnicity List output lost selected regional ethnicity")
|
||||||
|
_expect(parsed_ethnicity_filter.get("ethnicity_includes") == ["french_european"], "Ethnicity List filter output changed")
|
||||||
|
_expect("ethnicity list:" in ethnicity_summary, "Ethnicity List summary changed unexpectedly")
|
||||||
|
|
||||||
|
|
||||||
SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
||||||
("builtin_single_woman", smoke_builtin_single),
|
("builtin_single_woman", smoke_builtin_single),
|
||||||
("camera_scene_single", smoke_camera_scene_single),
|
("camera_scene_single", smoke_camera_scene_single),
|
||||||
@@ -1874,6 +1955,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
|||||||
("node_utility_registration", smoke_node_utility_registration),
|
("node_utility_registration", smoke_node_utility_registration),
|
||||||
("node_camera_registration", smoke_node_camera_registration),
|
("node_camera_registration", smoke_node_camera_registration),
|
||||||
("node_route_config_registration", smoke_node_route_config_registration),
|
("node_route_config_registration", smoke_node_route_config_registration),
|
||||||
|
("node_profile_filter_registration", smoke_node_profile_filter_registration),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user