Extract formatter nodes
This commit is contained in:
+10
-214
@@ -412,6 +412,10 @@ try:
|
|||||||
NODE_CLASS_MAPPINGS as HARDCORE_POSITION_NODE_CLASS_MAPPINGS,
|
NODE_CLASS_MAPPINGS as HARDCORE_POSITION_NODE_CLASS_MAPPINGS,
|
||||||
NODE_DISPLAY_NAME_MAPPINGS as HARDCORE_POSITION_NODE_DISPLAY_NAME_MAPPINGS,
|
NODE_DISPLAY_NAME_MAPPINGS as HARDCORE_POSITION_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
)
|
)
|
||||||
|
from .node_formatter import (
|
||||||
|
NODE_CLASS_MAPPINGS as FORMATTER_NODE_CLASS_MAPPINGS,
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS as FORMATTER_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
|
)
|
||||||
from .node_profile_filter import (
|
from .node_profile_filter import (
|
||||||
NODE_CLASS_MAPPINGS as PROFILE_FILTER_NODE_CLASS_MAPPINGS,
|
NODE_CLASS_MAPPINGS as PROFILE_FILTER_NODE_CLASS_MAPPINGS,
|
||||||
NODE_DISPLAY_NAME_MAPPINGS as PROFILE_FILTER_NODE_DISPLAY_NAME_MAPPINGS,
|
NODE_DISPLAY_NAME_MAPPINGS as PROFILE_FILTER_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
@@ -437,9 +441,6 @@ try:
|
|||||||
save_character_profile_payload,
|
save_character_profile_payload,
|
||||||
subcategory_choices,
|
subcategory_choices,
|
||||||
)
|
)
|
||||||
from .caption_naturalizer import naturalize_caption
|
|
||||||
from .krea_formatter import format_krea2_prompt
|
|
||||||
from .sdxl_formatter import format_sdxl_prompt, sdxl_quality_preset_choices, sdxl_style_preset_choices
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from loop_nodes import (
|
from loop_nodes import (
|
||||||
LOOP_NODE_CLASS_MAPPINGS,
|
LOOP_NODE_CLASS_MAPPINGS,
|
||||||
@@ -461,6 +462,10 @@ except ImportError:
|
|||||||
NODE_CLASS_MAPPINGS as HARDCORE_POSITION_NODE_CLASS_MAPPINGS,
|
NODE_CLASS_MAPPINGS as HARDCORE_POSITION_NODE_CLASS_MAPPINGS,
|
||||||
NODE_DISPLAY_NAME_MAPPINGS as HARDCORE_POSITION_NODE_DISPLAY_NAME_MAPPINGS,
|
NODE_DISPLAY_NAME_MAPPINGS as HARDCORE_POSITION_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
)
|
)
|
||||||
|
from node_formatter import (
|
||||||
|
NODE_CLASS_MAPPINGS as FORMATTER_NODE_CLASS_MAPPINGS,
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS as FORMATTER_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
|
)
|
||||||
from node_profile_filter import (
|
from node_profile_filter import (
|
||||||
NODE_CLASS_MAPPINGS as PROFILE_FILTER_NODE_CLASS_MAPPINGS,
|
NODE_CLASS_MAPPINGS as PROFILE_FILTER_NODE_CLASS_MAPPINGS,
|
||||||
NODE_DISPLAY_NAME_MAPPINGS as PROFILE_FILTER_NODE_DISPLAY_NAME_MAPPINGS,
|
NODE_DISPLAY_NAME_MAPPINGS as PROFILE_FILTER_NODE_DISPLAY_NAME_MAPPINGS,
|
||||||
@@ -486,9 +491,6 @@ except ImportError:
|
|||||||
save_character_profile_payload,
|
save_character_profile_payload,
|
||||||
subcategory_choices,
|
subcategory_choices,
|
||||||
)
|
)
|
||||||
from caption_naturalizer import naturalize_caption
|
|
||||||
from krea_formatter import format_krea2_prompt
|
|
||||||
from sdxl_formatter import format_sdxl_prompt, sdxl_quality_preset_choices, sdxl_style_preset_choices
|
|
||||||
|
|
||||||
|
|
||||||
if PromptServer is not None and web is not None:
|
if PromptServer is not None and web is not None:
|
||||||
@@ -762,208 +764,6 @@ class SxCPPromptBuilderFromConfigs:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SxCPCaptionNaturalizer:
|
|
||||||
@classmethod
|
|
||||||
def INPUT_TYPES(cls):
|
|
||||||
return {
|
|
||||||
"required": {
|
|
||||||
"source_text": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
"input_hint": (["auto", "metadata_json", "caption_or_prompt"], {"default": "auto"}),
|
|
||||||
"detail_level": (["balanced", "concise", "dense"], {"default": "balanced"}),
|
|
||||||
"style_policy": (["drop_style_tail", "keep_style_terms"], {"default": "drop_style_tail"}),
|
|
||||||
"trigger": ("STRING", {"default": "sxcppnl7"}),
|
|
||||||
"include_trigger": ("BOOLEAN", {"default": True}),
|
|
||||||
},
|
|
||||||
"optional": {
|
|
||||||
"source_text_input": ("STRING", {"forceInput": True}),
|
|
||||||
"metadata_json": ("STRING", {"forceInput": True}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_TYPES = ("STRING", "STRING")
|
|
||||||
RETURN_NAMES = ("natural_caption", "method")
|
|
||||||
FUNCTION = "build"
|
|
||||||
CATEGORY = "prompt_builder"
|
|
||||||
|
|
||||||
def build(
|
|
||||||
self,
|
|
||||||
source_text,
|
|
||||||
input_hint,
|
|
||||||
detail_level,
|
|
||||||
style_policy,
|
|
||||||
trigger,
|
|
||||||
include_trigger,
|
|
||||||
source_text_input="",
|
|
||||||
metadata_json="",
|
|
||||||
):
|
|
||||||
active_source_text = source_text_input or source_text or ""
|
|
||||||
return naturalize_caption(
|
|
||||||
source_text=active_source_text,
|
|
||||||
metadata_json=metadata_json or "",
|
|
||||||
input_hint=input_hint,
|
|
||||||
trigger=trigger,
|
|
||||||
include_trigger=include_trigger,
|
|
||||||
detail_level=detail_level,
|
|
||||||
style_policy=style_policy,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SxCPKrea2Formatter:
|
|
||||||
@classmethod
|
|
||||||
def INPUT_TYPES(cls):
|
|
||||||
return {
|
|
||||||
"required": {
|
|
||||||
"source_text": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
"input_hint": (["auto", "metadata_json", "prompt"], {"default": "auto"}),
|
|
||||||
"target": (["auto", "single", "softcore", "hardcore"], {"default": "auto"}),
|
|
||||||
"detail_level": (["balanced", "concise", "dense"], {"default": "balanced"}),
|
|
||||||
"style_mode": (["preserve", "photographic", "minimal"], {"default": "preserve"}),
|
|
||||||
"preserve_trigger": ("BOOLEAN", {"default": False}),
|
|
||||||
},
|
|
||||||
"optional": {
|
|
||||||
"metadata_json": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
"negative_prompt": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
"extra_positive": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
"extra_negative": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING", "STRING", "STRING", "STRING")
|
|
||||||
RETURN_NAMES = (
|
|
||||||
"krea_prompt",
|
|
||||||
"negative_prompt",
|
|
||||||
"krea_softcore_prompt",
|
|
||||||
"krea_hardcore_prompt",
|
|
||||||
"softcore_negative_prompt",
|
|
||||||
"hardcore_negative_prompt",
|
|
||||||
"method",
|
|
||||||
)
|
|
||||||
FUNCTION = "build"
|
|
||||||
CATEGORY = "prompt_builder"
|
|
||||||
|
|
||||||
def build(
|
|
||||||
self,
|
|
||||||
source_text,
|
|
||||||
input_hint,
|
|
||||||
target,
|
|
||||||
detail_level,
|
|
||||||
style_mode,
|
|
||||||
preserve_trigger,
|
|
||||||
metadata_json="",
|
|
||||||
negative_prompt="",
|
|
||||||
extra_positive="",
|
|
||||||
extra_negative="",
|
|
||||||
):
|
|
||||||
row = format_krea2_prompt(
|
|
||||||
source_text=source_text or "",
|
|
||||||
metadata_json=metadata_json or "",
|
|
||||||
negative_prompt=negative_prompt or "",
|
|
||||||
input_hint=input_hint,
|
|
||||||
target=target,
|
|
||||||
detail_level=detail_level,
|
|
||||||
style_mode=style_mode,
|
|
||||||
preserve_trigger=preserve_trigger,
|
|
||||||
extra_positive=extra_positive or "",
|
|
||||||
extra_negative=extra_negative or "",
|
|
||||||
)
|
|
||||||
return (
|
|
||||||
row["krea_prompt"],
|
|
||||||
row["negative_prompt"],
|
|
||||||
row["krea_softcore_prompt"],
|
|
||||||
row["krea_hardcore_prompt"],
|
|
||||||
row["softcore_negative_prompt"],
|
|
||||||
row["hardcore_negative_prompt"],
|
|
||||||
row["method"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SxCPSDXLFormatter:
|
|
||||||
@classmethod
|
|
||||||
def INPUT_TYPES(cls):
|
|
||||||
return {
|
|
||||||
"required": {
|
|
||||||
"source_text": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
"input_hint": (["auto", "metadata_json", "prompt"], {"default": "auto"}),
|
|
||||||
"target": (["auto", "single", "softcore", "hardcore"], {"default": "auto"}),
|
|
||||||
"style_preset": (sdxl_style_preset_choices(), {"default": "flat_vector_pony"}),
|
|
||||||
"quality_preset": (sdxl_quality_preset_choices(), {"default": "pony_high"}),
|
|
||||||
"trigger": ("STRING", {"default": "mythp0rt", "multiline": False}),
|
|
||||||
"prepend_trigger_to_prompt": ("BOOLEAN", {"default": True}),
|
|
||||||
"preserve_trigger": ("BOOLEAN", {"default": False}),
|
|
||||||
"nude_weight": ("FLOAT", {"default": 1.29, "min": 0.1, "max": 3.0, "step": 0.01}),
|
|
||||||
},
|
|
||||||
"optional": {
|
|
||||||
"source_text_input": ("STRING", {"forceInput": True}),
|
|
||||||
"metadata_json": ("STRING", {"forceInput": True}),
|
|
||||||
"negative_prompt": ("STRING", {"forceInput": True}),
|
|
||||||
"custom_style": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
"custom_quality": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
"extra_positive": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
"extra_negative": ("STRING", {"default": "", "multiline": True}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING", "STRING", "STRING", "STRING")
|
|
||||||
RETURN_NAMES = (
|
|
||||||
"sdxl_prompt",
|
|
||||||
"negative_prompt",
|
|
||||||
"sdxl_softcore_prompt",
|
|
||||||
"sdxl_hardcore_prompt",
|
|
||||||
"softcore_negative_prompt",
|
|
||||||
"hardcore_negative_prompt",
|
|
||||||
"method",
|
|
||||||
)
|
|
||||||
FUNCTION = "build"
|
|
||||||
CATEGORY = "prompt_builder"
|
|
||||||
|
|
||||||
def build(
|
|
||||||
self,
|
|
||||||
source_text,
|
|
||||||
input_hint,
|
|
||||||
target,
|
|
||||||
style_preset,
|
|
||||||
quality_preset,
|
|
||||||
trigger,
|
|
||||||
prepend_trigger_to_prompt,
|
|
||||||
preserve_trigger,
|
|
||||||
nude_weight,
|
|
||||||
source_text_input="",
|
|
||||||
metadata_json="",
|
|
||||||
negative_prompt="",
|
|
||||||
custom_style="",
|
|
||||||
custom_quality="",
|
|
||||||
extra_positive="",
|
|
||||||
extra_negative="",
|
|
||||||
):
|
|
||||||
active_source_text = source_text_input or source_text or ""
|
|
||||||
row = format_sdxl_prompt(
|
|
||||||
source_text=active_source_text,
|
|
||||||
metadata_json=metadata_json or "",
|
|
||||||
negative_prompt=negative_prompt or "",
|
|
||||||
input_hint=input_hint,
|
|
||||||
target=target,
|
|
||||||
style_preset=style_preset,
|
|
||||||
quality_preset=quality_preset,
|
|
||||||
trigger=trigger,
|
|
||||||
prepend_trigger=prepend_trigger_to_prompt,
|
|
||||||
preserve_trigger=preserve_trigger,
|
|
||||||
nude_weight=nude_weight,
|
|
||||||
custom_style=custom_style or "",
|
|
||||||
custom_quality=custom_quality or "",
|
|
||||||
extra_positive=extra_positive or "",
|
|
||||||
extra_negative=extra_negative or "",
|
|
||||||
)
|
|
||||||
return (
|
|
||||||
row["sdxl_prompt"],
|
|
||||||
row["negative_prompt"],
|
|
||||||
row["sdxl_softcore_prompt"],
|
|
||||||
row["sdxl_hardcore_prompt"],
|
|
||||||
row["softcore_negative_prompt"],
|
|
||||||
row["hardcore_negative_prompt"],
|
|
||||||
row["method"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SxCPInstaOFOptions:
|
class SxCPInstaOFOptions:
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(cls):
|
def INPUT_TYPES(cls):
|
||||||
@@ -1151,13 +951,11 @@ 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(CHARACTER_NODE_CLASS_MAPPINGS)
|
NODE_CLASS_MAPPINGS.update(CHARACTER_NODE_CLASS_MAPPINGS)
|
||||||
NODE_CLASS_MAPPINGS.update(HARDCORE_POSITION_NODE_CLASS_MAPPINGS)
|
NODE_CLASS_MAPPINGS.update(HARDCORE_POSITION_NODE_CLASS_MAPPINGS)
|
||||||
|
NODE_CLASS_MAPPINGS.update(FORMATTER_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(PROFILE_FILTER_NODE_CLASS_MAPPINGS)
|
||||||
NODE_CLASS_MAPPINGS.update({
|
NODE_CLASS_MAPPINGS.update({
|
||||||
"SxCPPromptBuilderFromConfigs": SxCPPromptBuilderFromConfigs,
|
"SxCPPromptBuilderFromConfigs": SxCPPromptBuilderFromConfigs,
|
||||||
"SxCPCaptionNaturalizer": SxCPCaptionNaturalizer,
|
|
||||||
"SxCPKrea2Formatter": SxCPKrea2Formatter,
|
|
||||||
"SxCPSDXLFormatter": SxCPSDXLFormatter,
|
|
||||||
"SxCPInstaOFOptions": SxCPInstaOFOptions,
|
"SxCPInstaOFOptions": SxCPInstaOFOptions,
|
||||||
"SxCPInstaOFPromptPair": SxCPInstaOFPromptPair,
|
"SxCPInstaOFPromptPair": SxCPInstaOFPromptPair,
|
||||||
})
|
})
|
||||||
@@ -1171,13 +969,11 @@ 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(CHARACTER_NODE_DISPLAY_NAME_MAPPINGS)
|
NODE_DISPLAY_NAME_MAPPINGS.update(CHARACTER_NODE_DISPLAY_NAME_MAPPINGS)
|
||||||
NODE_DISPLAY_NAME_MAPPINGS.update(HARDCORE_POSITION_NODE_DISPLAY_NAME_MAPPINGS)
|
NODE_DISPLAY_NAME_MAPPINGS.update(HARDCORE_POSITION_NODE_DISPLAY_NAME_MAPPINGS)
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS.update(FORMATTER_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(PROFILE_FILTER_NODE_DISPLAY_NAME_MAPPINGS)
|
||||||
NODE_DISPLAY_NAME_MAPPINGS.update({
|
NODE_DISPLAY_NAME_MAPPINGS.update({
|
||||||
"SxCPPromptBuilderFromConfigs": "SxCP Prompt Builder From Configs",
|
"SxCPPromptBuilderFromConfigs": "SxCP Prompt Builder From Configs",
|
||||||
"SxCPCaptionNaturalizer": "SxCP Caption Naturalizer",
|
|
||||||
"SxCPKrea2Formatter": "SxCP Krea2 Formatter",
|
|
||||||
"SxCPSDXLFormatter": "SxCP SDXL Formatter",
|
|
||||||
"SxCPInstaOFOptions": "SxCP Insta/OF Options",
|
"SxCPInstaOFOptions": "SxCP Insta/OF Options",
|
||||||
"SxCPInstaOFPromptPair": "SxCP Insta/OF Prompt Pair",
|
"SxCPInstaOFPromptPair": "SxCP Insta/OF Prompt Pair",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -273,8 +273,8 @@ 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_character.py`, `node_hardcore_position.py`, `node_route_config.py`,
|
`node_character.py`, `node_hardcore_position.py`, `node_formatter.py`,
|
||||||
`node_profile_filter.py`, `loop_nodes.py`, `web/*.js`.
|
`node_route_config.py`, `node_profile_filter.py`, `loop_nodes.py`, `web/*.js`.
|
||||||
|
|
||||||
Keep here:
|
Keep here:
|
||||||
|
|
||||||
@@ -287,6 +287,7 @@ Keep here:
|
|||||||
- character pool, slot, and profile node declarations in `node_character.py`.
|
- character pool, slot, and profile node declarations in `node_character.py`.
|
||||||
- hardcore position pool/filter node declarations in
|
- hardcore position pool/filter node declarations in
|
||||||
`node_hardcore_position.py`.
|
`node_hardcore_position.py`.
|
||||||
|
- caption/Krea2/SDXL formatter node declarations in `node_formatter.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`.
|
- profile/filter/ethnicity-list node declarations in `node_profile_filter.py`.
|
||||||
@@ -303,6 +304,8 @@ Already isolated:
|
|||||||
- hardcore position pool and action filter nodes live in
|
- hardcore position pool and action filter nodes live in
|
||||||
`node_hardcore_position.py`, with registration maps imported by
|
`node_hardcore_position.py`, with registration maps imported by
|
||||||
`__init__.py`.
|
`__init__.py`.
|
||||||
|
- caption naturalizer, Krea2 formatter, and SDXL formatter nodes live in
|
||||||
|
`node_formatter.py`, with registration maps imported by `__init__.py`.
|
||||||
- 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`.
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ When a result is wrong, first identify which layer owns the bad text:
|
|||||||
- 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`, `node_character.py`,
|
as `node_seed_resolution.py`, `node_camera.py`, `node_character.py`,
|
||||||
`node_hardcore_position.py`, `node_route_config.py`, or
|
`node_hardcore_position.py`, `node_formatter.py`, `node_route_config.py`, or
|
||||||
`node_profile_filter.py`, `loop_nodes.py`, or `web/*.js`.
|
`node_profile_filter.py`, `loop_nodes.py`, or `web/*.js`.
|
||||||
|
|
||||||
## High-Level Routes
|
## High-Level Routes
|
||||||
@@ -697,6 +697,7 @@ These do not own prompt pool wording, but they affect execution and review:
|
|||||||
| 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. |
|
||||||
| Character utility nodes | `node_character.py`, imported by `__init__.py` | Hair, age/body/eyes/clothing pools, manual details, character slots, and profile save/load nodes. |
|
| Character utility nodes | `node_character.py`, imported by `__init__.py` | Hair, age/body/eyes/clothing pools, manual details, character slots, and profile save/load nodes. |
|
||||||
| Hardcore position utility nodes | `node_hardcore_position.py`, imported by `__init__.py` | Position-family pool and action/filter gates for hardcore routes. |
|
| Hardcore position utility nodes | `node_hardcore_position.py`, imported by `__init__.py` | Position-family pool and action/filter gates for hardcore routes. |
|
||||||
|
| Formatter utility nodes | `node_formatter.py`, imported by `__init__.py` | Caption naturalizer, Krea2 formatter, and SDXL formatter node wrappers. |
|
||||||
| 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. |
|
| Profile/filter utility nodes | `node_profile_filter.py`, imported by `__init__.py` | Generation profile, advanced filter config, and ethnicity list helpers. |
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,225 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .caption_naturalizer import naturalize_caption
|
||||||
|
from .krea_formatter import format_krea2_prompt
|
||||||
|
from .sdxl_formatter import format_sdxl_prompt, sdxl_quality_preset_choices, sdxl_style_preset_choices
|
||||||
|
except ImportError: # Allows local smoke tests from the repository root.
|
||||||
|
from caption_naturalizer import naturalize_caption
|
||||||
|
from krea_formatter import format_krea2_prompt
|
||||||
|
from sdxl_formatter import format_sdxl_prompt, sdxl_quality_preset_choices, sdxl_style_preset_choices
|
||||||
|
|
||||||
|
|
||||||
|
class SxCPCaptionNaturalizer:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"source_text": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
"input_hint": (["auto", "metadata_json", "caption_or_prompt"], {"default": "auto"}),
|
||||||
|
"detail_level": (["balanced", "concise", "dense"], {"default": "balanced"}),
|
||||||
|
"style_policy": (["drop_style_tail", "keep_style_terms"], {"default": "drop_style_tail"}),
|
||||||
|
"trigger": ("STRING", {"default": "sxcppnl7"}),
|
||||||
|
"include_trigger": ("BOOLEAN", {"default": True}),
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"source_text_input": ("STRING", {"forceInput": True}),
|
||||||
|
"metadata_json": ("STRING", {"forceInput": True}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("STRING", "STRING")
|
||||||
|
RETURN_NAMES = ("natural_caption", "method")
|
||||||
|
FUNCTION = "build"
|
||||||
|
CATEGORY = "prompt_builder"
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
source_text,
|
||||||
|
input_hint,
|
||||||
|
detail_level,
|
||||||
|
style_policy,
|
||||||
|
trigger,
|
||||||
|
include_trigger,
|
||||||
|
source_text_input="",
|
||||||
|
metadata_json="",
|
||||||
|
):
|
||||||
|
active_source_text = source_text_input or source_text or ""
|
||||||
|
return naturalize_caption(
|
||||||
|
source_text=active_source_text,
|
||||||
|
metadata_json=metadata_json or "",
|
||||||
|
input_hint=input_hint,
|
||||||
|
trigger=trigger,
|
||||||
|
include_trigger=include_trigger,
|
||||||
|
detail_level=detail_level,
|
||||||
|
style_policy=style_policy,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SxCPKrea2Formatter:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"source_text": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
"input_hint": (["auto", "metadata_json", "prompt"], {"default": "auto"}),
|
||||||
|
"target": (["auto", "single", "softcore", "hardcore"], {"default": "auto"}),
|
||||||
|
"detail_level": (["balanced", "concise", "dense"], {"default": "balanced"}),
|
||||||
|
"style_mode": (["preserve", "photographic", "minimal"], {"default": "preserve"}),
|
||||||
|
"preserve_trigger": ("BOOLEAN", {"default": False}),
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"metadata_json": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
"negative_prompt": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
"extra_positive": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
"extra_negative": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING", "STRING", "STRING", "STRING")
|
||||||
|
RETURN_NAMES = (
|
||||||
|
"krea_prompt",
|
||||||
|
"negative_prompt",
|
||||||
|
"krea_softcore_prompt",
|
||||||
|
"krea_hardcore_prompt",
|
||||||
|
"softcore_negative_prompt",
|
||||||
|
"hardcore_negative_prompt",
|
||||||
|
"method",
|
||||||
|
)
|
||||||
|
FUNCTION = "build"
|
||||||
|
CATEGORY = "prompt_builder"
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
source_text,
|
||||||
|
input_hint,
|
||||||
|
target,
|
||||||
|
detail_level,
|
||||||
|
style_mode,
|
||||||
|
preserve_trigger,
|
||||||
|
metadata_json="",
|
||||||
|
negative_prompt="",
|
||||||
|
extra_positive="",
|
||||||
|
extra_negative="",
|
||||||
|
):
|
||||||
|
row = format_krea2_prompt(
|
||||||
|
source_text=source_text or "",
|
||||||
|
metadata_json=metadata_json or "",
|
||||||
|
negative_prompt=negative_prompt or "",
|
||||||
|
input_hint=input_hint,
|
||||||
|
target=target,
|
||||||
|
detail_level=detail_level,
|
||||||
|
style_mode=style_mode,
|
||||||
|
preserve_trigger=preserve_trigger,
|
||||||
|
extra_positive=extra_positive or "",
|
||||||
|
extra_negative=extra_negative or "",
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
row["krea_prompt"],
|
||||||
|
row["negative_prompt"],
|
||||||
|
row["krea_softcore_prompt"],
|
||||||
|
row["krea_hardcore_prompt"],
|
||||||
|
row["softcore_negative_prompt"],
|
||||||
|
row["hardcore_negative_prompt"],
|
||||||
|
row["method"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class SxCPSDXLFormatter:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"source_text": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
"input_hint": (["auto", "metadata_json", "prompt"], {"default": "auto"}),
|
||||||
|
"target": (["auto", "single", "softcore", "hardcore"], {"default": "auto"}),
|
||||||
|
"style_preset": (sdxl_style_preset_choices(), {"default": "flat_vector_pony"}),
|
||||||
|
"quality_preset": (sdxl_quality_preset_choices(), {"default": "pony_high"}),
|
||||||
|
"trigger": ("STRING", {"default": "mythp0rt", "multiline": False}),
|
||||||
|
"prepend_trigger_to_prompt": ("BOOLEAN", {"default": True}),
|
||||||
|
"preserve_trigger": ("BOOLEAN", {"default": False}),
|
||||||
|
"nude_weight": ("FLOAT", {"default": 1.29, "min": 0.1, "max": 3.0, "step": 0.01}),
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"source_text_input": ("STRING", {"forceInput": True}),
|
||||||
|
"metadata_json": ("STRING", {"forceInput": True}),
|
||||||
|
"negative_prompt": ("STRING", {"forceInput": True}),
|
||||||
|
"custom_style": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
"custom_quality": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
"extra_positive": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
"extra_negative": ("STRING", {"default": "", "multiline": True}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("STRING", "STRING", "STRING", "STRING", "STRING", "STRING", "STRING")
|
||||||
|
RETURN_NAMES = (
|
||||||
|
"sdxl_prompt",
|
||||||
|
"negative_prompt",
|
||||||
|
"sdxl_softcore_prompt",
|
||||||
|
"sdxl_hardcore_prompt",
|
||||||
|
"softcore_negative_prompt",
|
||||||
|
"hardcore_negative_prompt",
|
||||||
|
"method",
|
||||||
|
)
|
||||||
|
FUNCTION = "build"
|
||||||
|
CATEGORY = "prompt_builder"
|
||||||
|
|
||||||
|
def build(
|
||||||
|
self,
|
||||||
|
source_text,
|
||||||
|
input_hint,
|
||||||
|
target,
|
||||||
|
style_preset,
|
||||||
|
quality_preset,
|
||||||
|
trigger,
|
||||||
|
prepend_trigger_to_prompt,
|
||||||
|
preserve_trigger,
|
||||||
|
nude_weight,
|
||||||
|
source_text_input="",
|
||||||
|
metadata_json="",
|
||||||
|
negative_prompt="",
|
||||||
|
custom_style="",
|
||||||
|
custom_quality="",
|
||||||
|
extra_positive="",
|
||||||
|
extra_negative="",
|
||||||
|
):
|
||||||
|
active_source_text = source_text_input or source_text or ""
|
||||||
|
row = format_sdxl_prompt(
|
||||||
|
source_text=active_source_text,
|
||||||
|
metadata_json=metadata_json or "",
|
||||||
|
negative_prompt=negative_prompt or "",
|
||||||
|
input_hint=input_hint,
|
||||||
|
target=target,
|
||||||
|
style_preset=style_preset,
|
||||||
|
quality_preset=quality_preset,
|
||||||
|
trigger=trigger,
|
||||||
|
prepend_trigger=prepend_trigger_to_prompt,
|
||||||
|
preserve_trigger=preserve_trigger,
|
||||||
|
nude_weight=nude_weight,
|
||||||
|
custom_style=custom_style or "",
|
||||||
|
custom_quality=custom_quality or "",
|
||||||
|
extra_positive=extra_positive or "",
|
||||||
|
extra_negative=extra_negative or "",
|
||||||
|
)
|
||||||
|
return (
|
||||||
|
row["sdxl_prompt"],
|
||||||
|
row["negative_prompt"],
|
||||||
|
row["sdxl_softcore_prompt"],
|
||||||
|
row["sdxl_hardcore_prompt"],
|
||||||
|
row["softcore_negative_prompt"],
|
||||||
|
row["hardcore_negative_prompt"],
|
||||||
|
row["method"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
NODE_CLASS_MAPPINGS = {
|
||||||
|
"SxCPCaptionNaturalizer": SxCPCaptionNaturalizer,
|
||||||
|
"SxCPKrea2Formatter": SxCPKrea2Formatter,
|
||||||
|
"SxCPSDXLFormatter": SxCPSDXLFormatter,
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
|
"SxCPCaptionNaturalizer": "SxCP Caption Naturalizer",
|
||||||
|
"SxCPKrea2Formatter": "SxCP Krea2 Formatter",
|
||||||
|
"SxCPSDXLFormatter": "SxCP SDXL Formatter",
|
||||||
|
}
|
||||||
@@ -2059,6 +2059,62 @@ def smoke_node_hardcore_position_registration() -> None:
|
|||||||
_expect("blocked=" in filter_summary, "Hardcore Action Filter summary lost blocked-gate details")
|
_expect("blocked=" in filter_summary, "Hardcore Action Filter summary lost blocked-gate details")
|
||||||
|
|
||||||
|
|
||||||
|
def smoke_node_formatter_registration() -> None:
|
||||||
|
required_nodes = [
|
||||||
|
"SxCPCaptionNaturalizer",
|
||||||
|
"SxCPKrea2Formatter",
|
||||||
|
"SxCPSDXLFormatter",
|
||||||
|
]
|
||||||
|
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")
|
||||||
|
|
||||||
|
krea_node = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPKrea2Formatter"]
|
||||||
|
krea_inputs = krea_node.INPUT_TYPES().get("required") or {}
|
||||||
|
_expect("source_text" in krea_inputs, "Krea2 Formatter lost source_text input")
|
||||||
|
_expect("tooltip" in krea_inputs["source_text"][1], "Krea2 Formatter tooltip injection missing")
|
||||||
|
|
||||||
|
caption, caption_method = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPCaptionNaturalizer"]().build(
|
||||||
|
"A woman standing by a window, best quality",
|
||||||
|
"caption_or_prompt",
|
||||||
|
"concise",
|
||||||
|
"drop_style_tail",
|
||||||
|
"sxcppnl7",
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
_expect_text("node_formatter.caption", caption, 20)
|
||||||
|
_expect(caption.startswith("sxcppnl7"), "Caption Naturalizer did not prepend trigger")
|
||||||
|
_expect("text(" in caption_method, "Caption Naturalizer method changed unexpectedly")
|
||||||
|
|
||||||
|
krea_output = krea_node().build(
|
||||||
|
"sxcppnl7 A woman standing by a window",
|
||||||
|
"prompt",
|
||||||
|
"single",
|
||||||
|
"concise",
|
||||||
|
"preserve",
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
_expect_text("node_formatter.krea_prompt", krea_output[0], 20)
|
||||||
|
_expect("sxcppnl7" in krea_output[0], "Krea2 Formatter did not preserve trigger when enabled")
|
||||||
|
_expect(krea_output[6].startswith("text("), "Krea2 Formatter method changed unexpectedly")
|
||||||
|
|
||||||
|
sdxl_output = sxcp_nodes.NODE_CLASS_MAPPINGS["SxCPSDXLFormatter"]().build(
|
||||||
|
"A woman standing by a window",
|
||||||
|
"prompt",
|
||||||
|
"single",
|
||||||
|
"flat_vector_pony",
|
||||||
|
"pony_high",
|
||||||
|
"mythp0rt",
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
1.29,
|
||||||
|
)
|
||||||
|
_expect_text("node_formatter.sdxl_prompt", sdxl_output[0], 40)
|
||||||
|
_expect_trigger_once("node_formatter.sdxl_prompt", sdxl_output[0], "mythp0rt")
|
||||||
|
_expect_text("node_formatter.sdxl_negative", sdxl_output[1], 20)
|
||||||
|
_expect(sdxl_output[6].startswith("text("), "SDXL Formatter method changed unexpectedly")
|
||||||
|
|
||||||
|
|
||||||
def smoke_node_profile_filter_registration() -> None:
|
def smoke_node_profile_filter_registration() -> None:
|
||||||
required_nodes = [
|
required_nodes = [
|
||||||
"SxCPGenerationProfile",
|
"SxCPGenerationProfile",
|
||||||
@@ -2168,6 +2224,7 @@ SMOKE_CASES: list[tuple[str, Callable[[], None]]] = [
|
|||||||
("node_route_config_registration", smoke_node_route_config_registration),
|
("node_route_config_registration", smoke_node_route_config_registration),
|
||||||
("node_character_registration", smoke_node_character_registration),
|
("node_character_registration", smoke_node_character_registration),
|
||||||
("node_hardcore_position_registration", smoke_node_hardcore_position_registration),
|
("node_hardcore_position_registration", smoke_node_hardcore_position_registration),
|
||||||
|
("node_formatter_registration", smoke_node_formatter_registration),
|
||||||
("node_profile_filter_registration", smoke_node_profile_filter_registration),
|
("node_profile_filter_registration", smoke_node_profile_filter_registration),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user