Update H3 character helper outputs
This commit is contained in:
+56
-14
@@ -552,6 +552,30 @@ def _build_character_helper_text(
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _build_character_wardrobe_text(wardrobe, character_id, name, alias):
|
||||
text = _normalize_free_text(wardrobe)
|
||||
if not text:
|
||||
return ""
|
||||
|
||||
if text.lower().startswith("wardrobe:"):
|
||||
text = text.split(":", 1)[1].strip()
|
||||
if not text:
|
||||
return ""
|
||||
|
||||
# If the user already authored a full H3-style sheet entry, leave it alone.
|
||||
if "=" in text or ":" in text:
|
||||
return text
|
||||
|
||||
character_label = (
|
||||
_normalize_free_text(name)
|
||||
or _normalize_free_text(alias)
|
||||
or _normalize_free_text(character_id)
|
||||
)
|
||||
if character_label:
|
||||
return f"{character_label} = {text}"
|
||||
return text
|
||||
|
||||
|
||||
class DumasImageCompareNode:
|
||||
DESCRIPTION = (
|
||||
"Dumas Image Compare shows the difference between two images directly on "
|
||||
@@ -1092,13 +1116,14 @@ class DumasH3PlanExtractSceneImagesNode:
|
||||
|
||||
class DumasCharacterHelperNode:
|
||||
DESCRIPTION = (
|
||||
"Build a reusable character reference string from two IMAGE sockets and "
|
||||
"simple identity fields, while passing both images through unchanged."
|
||||
"Build a MiniMax H3-ready character reference prompt and wardrobe sheet "
|
||||
"from two IMAGE sockets plus simple identity fields, while passing both "
|
||||
"images through unchanged."
|
||||
)
|
||||
RETURN_TYPES = ("IMAGE", "IMAGE", "STRING")
|
||||
RETURN_NAMES = ("image1", "image2", "character_text")
|
||||
RETURN_TYPES = ("IMAGE", "IMAGE", "STRING", "STRING")
|
||||
RETURN_NAMES = ("image1", "image2", "reference_prompt", "wardrobe")
|
||||
FUNCTION = "build_character_text"
|
||||
CATEGORY = "Dumas/String"
|
||||
CATEGORY = "Dumas/MiniMax"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
@@ -1107,17 +1132,17 @@ class DumasCharacterHelperNode:
|
||||
"image1": ("IMAGE", {"tooltip": "Primary image to pass through and describe."}),
|
||||
"image2": ("IMAGE", {"tooltip": "Secondary image to pass through and describe."}),
|
||||
"image1_picture_id": (
|
||||
["2", "3", "4", "5", "6", "7"],
|
||||
["1", "2", "3", "4", "5", "6", "7", "8", "9"],
|
||||
{
|
||||
"default": "2",
|
||||
"tooltip": "Picture number to mention for image1 in the output string.",
|
||||
"default": "1",
|
||||
"tooltip": "Picture number to mention for image1 in the H3 reference prompt.",
|
||||
},
|
||||
),
|
||||
"image2_picture_id": (
|
||||
["2", "3", "4", "5", "6", "7"],
|
||||
["1", "2", "3", "4", "5", "6", "7", "8", "9"],
|
||||
{
|
||||
"default": "3",
|
||||
"tooltip": "Picture number to mention for image2 in the output string.",
|
||||
"default": "2",
|
||||
"tooltip": "Picture number to mention for image2 in the H3 reference prompt.",
|
||||
},
|
||||
),
|
||||
"character_id": (
|
||||
@@ -1203,7 +1228,15 @@ class DumasCharacterHelperNode:
|
||||
{
|
||||
"default": "",
|
||||
"multiline": True,
|
||||
"tooltip": "Optional freeform details appended as the last sentence.",
|
||||
"tooltip": "Optional non-clothing details appended as the last sentence of the H3 reference prompt.",
|
||||
},
|
||||
),
|
||||
"wardrobe": (
|
||||
"STRING",
|
||||
{
|
||||
"default": "",
|
||||
"multiline": True,
|
||||
"tooltip": "Optional H3 wardrobe/channel text. Plain clothing lists are auto-wrapped as 'Name = ...' when a name, alias, or character ID is present.",
|
||||
},
|
||||
),
|
||||
}
|
||||
@@ -1226,6 +1259,7 @@ class DumasCharacterHelperNode:
|
||||
height_inches,
|
||||
accent,
|
||||
general,
|
||||
wardrobe,
|
||||
):
|
||||
text = _build_character_helper_text(
|
||||
image1_picture_id,
|
||||
@@ -1242,7 +1276,13 @@ class DumasCharacterHelperNode:
|
||||
accent,
|
||||
general,
|
||||
)
|
||||
return (image1, image2, text)
|
||||
wardrobe_text = _build_character_wardrobe_text(
|
||||
wardrobe,
|
||||
character_id,
|
||||
name,
|
||||
alias,
|
||||
)
|
||||
return (image1, image2, text, wardrobe_text)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
@@ -1252,6 +1292,7 @@ NODE_CLASS_MAPPINGS = {
|
||||
"DumasH3PlanAttachSceneImages": DumasH3PlanAttachSceneImagesNode,
|
||||
"DumasH3PlanExtractSceneImages": DumasH3PlanExtractSceneImagesNode,
|
||||
"DumasCharacterHelper": DumasCharacterHelperNode,
|
||||
"DumasH3CharacterHelper": DumasCharacterHelperNode,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
@@ -1260,5 +1301,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"DumasLoadImagesFolder": "Load Images from Folder Dumas",
|
||||
"DumasH3PlanAttachSceneImages": "Dumas H3 Plan Attach Scene Images",
|
||||
"DumasH3PlanExtractSceneImages": "Dumas H3 Plan Extract Scene Images",
|
||||
"DumasCharacterHelper": "Dumas Character Helper",
|
||||
"DumasCharacterHelper": "Dumas H3 Character Helper",
|
||||
"DumasH3CharacterHelper": "Dumas H3 Character Helper",
|
||||
}
|
||||
|
||||
@@ -260,6 +260,7 @@ class DumasImageNodeTests(unittest.TestCase):
|
||||
height_inches="2",
|
||||
accent="English",
|
||||
general="wears a long grey coat",
|
||||
wardrobe="weathered red flight jacket, grey cargo shorts, black boots",
|
||||
)
|
||||
|
||||
self.assertIs(result[0], image1)
|
||||
@@ -274,6 +275,10 @@ class DumasImageNodeTests(unittest.TestCase):
|
||||
"wears a long grey coat."
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
result[3],
|
||||
"Dave = weathered red flight jacket, grey cargo shorts, black boots",
|
||||
)
|
||||
|
||||
def test_character_helper_handles_missing_optional_fields(self):
|
||||
node = self.image_nodes.DumasCharacterHelperNode()
|
||||
@@ -296,6 +301,7 @@ class DumasImageNodeTests(unittest.TestCase):
|
||||
height_inches="",
|
||||
accent="",
|
||||
general="",
|
||||
wardrobe="",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
@@ -306,6 +312,41 @@ class DumasImageNodeTests(unittest.TestCase):
|
||||
"<Picture 6> is a frontal facial reference for the character."
|
||||
),
|
||||
)
|
||||
self.assertEqual(result[3], "")
|
||||
|
||||
def test_character_helper_allows_picture_one_and_preserves_full_sheet_wardrobe(self):
|
||||
node = self.image_nodes.DumasCharacterHelperNode()
|
||||
image1 = FakeTensorBatch()
|
||||
image2 = FakeTensorBatch()
|
||||
|
||||
result = node.build_character_text(
|
||||
image1=image1,
|
||||
image2=image2,
|
||||
image1_picture_id="1",
|
||||
image2_picture_id="9",
|
||||
character_id="char_kristy",
|
||||
name="Kristy",
|
||||
alias="",
|
||||
gender="",
|
||||
age="",
|
||||
nationality="",
|
||||
occupation="",
|
||||
height_feet="",
|
||||
height_inches="",
|
||||
accent="",
|
||||
general="",
|
||||
wardrobe="Kristy = black coat, silver boots",
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
result[2],
|
||||
(
|
||||
"<Picture 1> and <Picture 9> reference the same character who is called Kristy.\n"
|
||||
"<Picture 1> is the primary full-body reference for Kristy.\n"
|
||||
"<Picture 9> is a frontal facial reference for Kristy."
|
||||
),
|
||||
)
|
||||
self.assertEqual(result[3], "Kristy = black coat, silver boots")
|
||||
|
||||
def test_save_image_returns_ui_entries_for_output_folder(self):
|
||||
node = self.image_nodes.DumasSaveImageNode()
|
||||
|
||||
Reference in New Issue
Block a user