Extract MSR characters into reusable nodes
This commit is contained in:
126
msr_character.py
Normal file
126
msr_character.py
Normal file
@@ -0,0 +1,126 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from comfy_api.latest import io
|
||||
|
||||
|
||||
MSRCharacterData = io.Custom("MSR_CHARACTER")
|
||||
MSRCharacterSetData = io.Custom("MSR_CHARACTER_SET")
|
||||
|
||||
|
||||
def _compact_alias(alias: str) -> str:
|
||||
if not alias:
|
||||
return ""
|
||||
alias = alias.strip()
|
||||
if alias.startswith("@"):
|
||||
alias = alias[1:]
|
||||
return alias.strip()
|
||||
|
||||
|
||||
class MSRCharacter(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
return io.Schema(
|
||||
node_id="MSRCharacterCS",
|
||||
display_name="MSR Character CS",
|
||||
category="WhatDreamsCost CS",
|
||||
description=(
|
||||
"Reusable MSR character payload. Accepts up to two reference images plus "
|
||||
"a description and optional alias for @alias prompt replacement."
|
||||
),
|
||||
inputs=[
|
||||
io.Image.Input(
|
||||
"image_1",
|
||||
optional=True,
|
||||
tooltip="Optional first reference image for this character.",
|
||||
),
|
||||
io.Image.Input(
|
||||
"image_2",
|
||||
optional=True,
|
||||
tooltip="Optional second reference image for this character.",
|
||||
),
|
||||
io.String.Input(
|
||||
"description",
|
||||
multiline=True,
|
||||
default="",
|
||||
optional=True,
|
||||
tooltip="Manual or generated appearance description used for prompt replacement.",
|
||||
),
|
||||
io.String.Input(
|
||||
"alias",
|
||||
default="",
|
||||
optional=True,
|
||||
tooltip="Optional alias. Prompts can use @alias alongside @charN/@characterN.",
|
||||
),
|
||||
],
|
||||
outputs=[
|
||||
MSRCharacterData.Output(display_name="character"),
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(cls, image_1=None, image_2=None, description="", alias="") -> io.NodeOutput:
|
||||
images = []
|
||||
if image_1 is not None:
|
||||
images.append(image_1)
|
||||
if image_2 is not None:
|
||||
images.append(image_2)
|
||||
|
||||
payload = {
|
||||
"images": images,
|
||||
"description": (description or "").strip(),
|
||||
"alias": _compact_alias(alias or ""),
|
||||
}
|
||||
return io.NodeOutput(payload)
|
||||
|
||||
|
||||
class MSRCharacterSet(io.ComfyNode):
|
||||
@classmethod
|
||||
def define_schema(cls):
|
||||
return io.Schema(
|
||||
node_id="MSRCharacterSetCS",
|
||||
display_name="MSR Character Set CS",
|
||||
category="WhatDreamsCost CS",
|
||||
description="Bundles up to six MSR Character nodes into one character set for the director.",
|
||||
inputs=[
|
||||
MSRCharacterData.Input("character_1", optional=True),
|
||||
MSRCharacterData.Input("character_2", optional=True),
|
||||
MSRCharacterData.Input("character_3", optional=True),
|
||||
MSRCharacterData.Input("character_4", optional=True),
|
||||
MSRCharacterData.Input("character_5", optional=True),
|
||||
MSRCharacterData.Input("character_6", optional=True),
|
||||
],
|
||||
outputs=[
|
||||
MSRCharacterSetData.Output(display_name="character_set"),
|
||||
],
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def execute(
|
||||
cls,
|
||||
character_1=None,
|
||||
character_2=None,
|
||||
character_3=None,
|
||||
character_4=None,
|
||||
character_5=None,
|
||||
character_6=None,
|
||||
) -> io.NodeOutput:
|
||||
characters = []
|
||||
for item in (
|
||||
character_1,
|
||||
character_2,
|
||||
character_3,
|
||||
character_4,
|
||||
character_5,
|
||||
character_6,
|
||||
):
|
||||
if not item:
|
||||
continue
|
||||
characters.append(
|
||||
{
|
||||
"images": list(item.get("images") or []),
|
||||
"description": (item.get("description") or "").strip(),
|
||||
"alias": _compact_alias(item.get("alias") or ""),
|
||||
}
|
||||
)
|
||||
|
||||
return io.NodeOutput({"characters": characters})
|
||||
Reference in New Issue
Block a user