127 lines
4.0 KiB
Python
127 lines
4.0 KiB
Python
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})
|