212 lines
7.6 KiB
Python
212 lines
7.6 KiB
Python
"""Backend nodes for the standalone H3 Prompt IDE.
|
|
|
|
The prompt editor deliberately returns an ordinary STRING. Reference media
|
|
travels through a small authoring-only bundle on a separate node so the editor
|
|
does not grow H3 media sockets of its own.
|
|
"""
|
|
|
|
from typing_extensions import override
|
|
|
|
from comfy_api.latest import ComfyExtension, io
|
|
|
|
|
|
H3_PROMPT_REFERENCES = io.Custom("H3_PROMPT_REFERENCES")
|
|
PICTURE_NAMES = [f"<Picture {index}>" for index in range(1, 10)]
|
|
VIDEO_NAMES = [f"<Video {index}>" for index in range(1, 4)]
|
|
# MiniMax H3 can emit three video soundtracks followed by three standalone
|
|
# audio references. Audio ordinals are shared across those two sources.
|
|
AUDIO_NAMES = [f"<Audio {index}>" for index in range(1, 7)]
|
|
|
|
|
|
def _reference_records(source, names, kind, value_key):
|
|
"""Return connected media in H3 label order."""
|
|
|
|
values = source or {}
|
|
records = []
|
|
for token in names:
|
|
value = values.get(token)
|
|
if value is not None:
|
|
records.append({"token": token, "kind": kind, value_key: value})
|
|
return records
|
|
|
|
|
|
class H3PromptReferenceInputs(io.ComfyNode):
|
|
"""Collect prompt-authoring media using MiniMax H3's native labels."""
|
|
|
|
@classmethod
|
|
def define_schema(cls) -> io.Schema:
|
|
pictures = io.Autogrow.TemplateNames(
|
|
input=io.Image.Input(
|
|
"picture",
|
|
tooltip=(
|
|
"Reference picture for the matching MiniMax H3 token. "
|
|
"The next socket appears automatically when connected."
|
|
),
|
|
),
|
|
names=PICTURE_NAMES,
|
|
min=0,
|
|
)
|
|
videos = io.Autogrow.TemplateNames(
|
|
input=io.Image.Input(
|
|
"video",
|
|
tooltip=(
|
|
"Reference video frames for the matching MiniMax H3 token. "
|
|
"Use the same IMAGE frame batch sent to the native H3 "
|
|
"ref_videos input."
|
|
),
|
|
),
|
|
names=VIDEO_NAMES,
|
|
min=0,
|
|
)
|
|
audios = io.Autogrow.TemplateNames(
|
|
input=io.Audio.Input(
|
|
"audio",
|
|
tooltip=(
|
|
"Reference audio for the matching MiniMax H3 token. Audio "
|
|
"labels follow native presentation order: connected video "
|
|
"soundtracks first, then standalone audio."
|
|
),
|
|
),
|
|
names=AUDIO_NAMES,
|
|
min=0,
|
|
)
|
|
return io.Schema(
|
|
node_id="H3PromptReferenceInputs",
|
|
display_name="H3 Reference Inputs",
|
|
category="text/H3 Prompt IDE",
|
|
search_aliases=[
|
|
"h3 ref input",
|
|
"h3 reference media",
|
|
"h3 reference images videos audio",
|
|
"minimax picture video audio references",
|
|
],
|
|
description=(
|
|
"Authoring references for H3 Prompt IDE. Picture, video-frame, "
|
|
"and audio sockets auto-grow with native MiniMax H3 labels. "
|
|
"Connect the references output to the editor."
|
|
),
|
|
inputs=[
|
|
io.Autogrow.Input(
|
|
"pictures",
|
|
optional=True,
|
|
template=pictures,
|
|
tooltip=(
|
|
"Up to nine prompt reference pictures, numbered in "
|
|
"their H3 presentation order."
|
|
),
|
|
),
|
|
io.Autogrow.Input(
|
|
"videos",
|
|
optional=True,
|
|
template=videos,
|
|
tooltip=(
|
|
"Up to three reference video frame batches, numbered "
|
|
"<Video 1> through <Video 3>."
|
|
),
|
|
),
|
|
io.Autogrow.Input(
|
|
"audios",
|
|
optional=True,
|
|
template=audios,
|
|
tooltip=(
|
|
"Up to six emitted H3 audio labels: video soundtracks "
|
|
"first, then standalone audio."
|
|
),
|
|
),
|
|
],
|
|
outputs=[
|
|
H3_PROMPT_REFERENCES.Output(
|
|
display_name="references",
|
|
tooltip="Authoring references for H3 Prompt IDE.",
|
|
),
|
|
],
|
|
)
|
|
|
|
@classmethod
|
|
def execute(
|
|
cls,
|
|
pictures: io.Autogrow.Type = None,
|
|
videos: io.Autogrow.Type = None,
|
|
audios: io.Autogrow.Type = None,
|
|
) -> io.NodeOutput:
|
|
# Preserve H3 presentation order even if a workflow serializer returns
|
|
# the dynamic-input dictionaries in a different insertion order.
|
|
picture_records = _reference_records(pictures, PICTURE_NAMES, "picture", "image")
|
|
video_records = _reference_records(videos, VIDEO_NAMES, "video", "frames")
|
|
audio_records = _reference_records(audios, AUDIO_NAMES, "audio", "audio")
|
|
return io.NodeOutput(
|
|
{
|
|
"pictures": picture_records,
|
|
"videos": video_records,
|
|
"audios": audio_records,
|
|
"references": picture_records + video_records + audio_records,
|
|
}
|
|
)
|
|
|
|
|
|
class H3PromptIDE(io.ComfyNode):
|
|
"""Rich authoring UI whose runtime contract is a normal STRING."""
|
|
|
|
@classmethod
|
|
def define_schema(cls) -> io.Schema:
|
|
return io.Schema(
|
|
node_id="H3PromptIDE",
|
|
display_name="H3 Prompt IDE",
|
|
category="text/H3 Prompt IDE",
|
|
search_aliases=[
|
|
"rich text prompt",
|
|
"prompt editor",
|
|
"minimax h3 prompt editor",
|
|
],
|
|
description=(
|
|
"Standalone rich prompt editor with strict H3 mode schemas, "
|
|
"contextual completion, reference tokens, automatic MiniMax "
|
|
"H3 Edit instruction context, and an ordinary STRING output. "
|
|
"Reference media stays on the separate H3 Reference Inputs node."
|
|
),
|
|
inputs=[
|
|
io.String.Input(
|
|
"prompt",
|
|
default="",
|
|
multiline=True,
|
|
dynamic_prompts=True,
|
|
tooltip="The plain text serialized and returned by this node.",
|
|
),
|
|
H3_PROMPT_REFERENCES.Input(
|
|
"references",
|
|
optional=True,
|
|
raw_link=True,
|
|
tooltip=(
|
|
"Optional authoring-only link from H3 Reference Inputs. "
|
|
"It supplies the token palette and previews without "
|
|
"evaluating reference media when only text is queued."
|
|
),
|
|
),
|
|
],
|
|
outputs=[
|
|
io.String.Output(
|
|
display_name="text",
|
|
tooltip=(
|
|
"The prompt as an ordinary ComfyUI STRING. Connecting "
|
|
"this directly to TextEncodeH3Edit.prompt activates "
|
|
"the IDE's task-aware Edit instruction category."
|
|
),
|
|
),
|
|
],
|
|
)
|
|
|
|
@classmethod
|
|
def execute(cls, prompt: str, references=None) -> io.NodeOutput:
|
|
del references
|
|
return io.NodeOutput(str(prompt or ""))
|
|
|
|
|
|
class H3PromptIDEExtension(ComfyExtension):
|
|
@override
|
|
async def get_node_list(self):
|
|
return [H3PromptReferenceInputs, H3PromptIDE]
|
|
|
|
|
|
async def comfy_entrypoint() -> H3PromptIDEExtension:
|
|
return H3PromptIDEExtension()
|