Files
GenorTG-ComfyUI-PromptForge/image_actions_node.py
T

80 lines
5.5 KiB
Python

"""PromptForge Action node: a pose or act plus place, camera, light and outfit for still-image prompts."""
import time
from . import image_actions, random_picks
class PROMPTFORGE_ImageAction:
CATEGORY = "🔮 PromptForge/Prompts"
RETURN_TYPES = ("PROMPTFORGE_ACTION", "STRING")
RETURN_NAMES = ("ACTION", "BRIEF")
FUNCTION = "build"
DESCRIPTION = ("A pose, place and camera as a binding brief for the prompt writer, for any image model. "
"Works from an input image or from words, for one person or two. Every picker has a random option rolled per run.")
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"category": ([random_picks.RANDOM] + list(image_actions.CATEGORIES), {"default": image_actions.CATEGORIES[0]}),
"action": ([random_picks.RANDOM] + [f"{group} · {label}" for label, (_, group, _) in image_actions.ACTIONS.items()],
{"default": f"{next(iter(image_actions.ACTIONS.values()))[1]} · {next(iter(image_actions.ACTIONS))}"}),
"source": (list(image_actions.SUBJECT_SOURCES), {"default": "input image",
"tooltip": "input image: keep the person from the connected image. text description: the writer invents the person from the text below."}),
"place": ([random_picks.RANDOM] + list(image_actions.PLACES), {"default": "auto"}),
"camera": ([random_picks.RANDOM] + list(image_actions.CAMERAS), {"default": "auto"}),
"lighting": ([random_picks.RANDOM] + list(image_actions.LIGHTING), {"default": "auto"}),
"outfit": ([random_picks.RANDOM] + list(image_actions.OUTFITS), {"default": "as in the image"}),
"style": ([random_picks.RANDOM] + list(image_actions.STYLES), {"default": "auto"}),
},
"optional": {
"subject_1": ("STRING", {"default": "", "multiline": True, "placeholder": "Who the first person is. Empty keeps the person from the input image.", "tooltip": "Identity text for the first person. With an image source this adds to the image; without one it is all the writer knows."}),
"subject_2": ("STRING", {"default": "", "multiline": True, "placeholder": "Who the second person is. Empty = the other person in the image, or an invented man.", "tooltip": "Identity text for the second person in a couple act."}),
"notes": ("STRING", {"default": "", "multiline": True, "placeholder": "Anything else: mood, props, weather, exact framing.", "tooltip": "Extra binding detail for this shot."}),
"overrides": ("STRING", {"default": "", "multiline": True, "placeholder": "Hard overrides, for example: red dress, no glasses.", "tooltip": "Passed last and wins over the rest of the brief."}),
"instructions": ("STRING", {"default": "", "multiline": True, "placeholder": "Extra instructions for this shot: mood, prop, exact framing. Replaces the enhancer prompt while the action is on.", "tooltip": "Custom instructions appended to the action brief."}),
},
"hidden": {"unique_id": "UNIQUE_ID"},
}
@classmethod
def IS_CHANGED(cls, **values):
return time.time_ns() if random_picks.RANDOM in values.values() else "static"
def build(self, category, action, source, place, camera, lighting, outfit, style,
subject_1="", subject_2="", notes="", overrides="", instructions="", unique_id=None):
picks = []
if action == random_picks.RANDOM:
pool = [label for label, (_, group, _) in image_actions.ACTIONS.items()
if category == random_picks.RANDOM or group == category]
action = random_picks.pick(pool)
else:
action = action.split(" · ", 1)[-1]
if category == random_picks.RANDOM:
category = image_actions.ACTIONS[action][1]
picks.append(("Category", category))
picks.append(("Action", action))
if place == random_picks.RANDOM:
place = random_picks.pick(key for key in image_actions.PLACES if key != "auto")
picks.append(("Place", place))
if camera == random_picks.RANDOM:
count = image_actions.ACTIONS[action][0]
camera = random_picks.pick(key for key in image_actions.CAMERAS
if key != "auto" and not (count == 1 and key == "side view, full bodies"))
picks.append(("Camera", camera))
if lighting == random_picks.RANDOM:
lighting = random_picks.pick(key for key in image_actions.LIGHTING if key != "auto")
picks.append(("Lighting", lighting))
if outfit == random_picks.RANDOM:
outfit = random_picks.pick(key for key in image_actions.OUTFITS if key != "as in the image")
picks.append(("Outfit", outfit))
if style == random_picks.RANDOM:
style = random_picks.pick(key for key in image_actions.STYLES if key != "auto")
picks.append(("Style", style))
random_picks.announce(unique_id, picks)
data = {"action": action, "source": source, "place": place, "camera": camera, "lighting": lighting,
"outfit": outfit, "style": style, "subject_1": subject_1,
"subject_2": subject_2, "notes": notes, "overrides": overrides, "instructions": instructions}
text = image_actions.brief(action, (subject_1, subject_2), camera, place, lighting, outfit, style, notes, overrides, source, instructions)
return (data, text)