Add editable system prompt input + Krea2 System Prompt node

- TextEncodeKrea2 gains a system_prompt forceInput (unconnected = Krea2's
  trained descriptor; wire a text node to override the VLM framing)
- New Krea2SystemPrompt node: text node preloaded with an instruct/edit-style
  system prompt that fuses the prompt with the reference image (experimental)
- README: document the system prompt input and the instruct preset

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Ethanfel
2026-06-25 04:43:34 +02:00
co-authored by Claude Opus 4.8
parent 6593a179f9
commit e979af29b3
2 changed files with 85 additions and 2 deletions
+21
View File
@@ -48,8 +48,29 @@ downstream of this node — that works generically at the sampler level.)
| `image1…N` | IMAGE | Optional reference images; slots grow as you connect them. |
| `mask1…N` | MASK | Optional per-image mask; crops `imageN` to the masked bounding box. |
| `mask_padding` | FLOAT | Context kept around the mask, as a fraction of image size per side (`0` = tight, default). |
| `system_prompt` | STRING input | Optional. Wire a text node to override the system instruction; unconnected = Krea2's default descriptor. See below. |
| `vision_megapixels` | FLOAT | Max size before the vision encoder; references are downscaled to this cap, never upscaled (default `1.0`). |
## System prompt (making the prompt interact with the image)
`system_prompt` is a connectable text **input**, not a widget — leave it unconnected to use
Krea2's trained descriptor (the in-distribution default), or wire a text node to override it.
Provide just the instruction text; the node wraps it in the chat-template scaffolding.
By default the VLM is only told to *describe* the image, so your prompt and the reference sit
side by side. To make them **interact** (à la Qwen-Image-Edit), feed an instruct-style
instruction. The package ships a **`Krea2 System Prompt`** node preloaded with that instruction —
just drop it and wire its output into `system_prompt` (edit the text if you like). Its default
text is:
> Describe the key features of the reference image (color, shape, size, texture, objects,
> background), then explain how the user's instruction should combine with or alter it, and
> generate a new image meeting the instruction while staying consistent with the reference
> where appropriate:
This is **experimental / out-of-distribution** — Krea2 was trained on the fixed descriptor, so
results may drift. A/B it against the default.
Output is a standard `CONDITIONING` for the Krea2 sampler. With no images connected it
works as a plain Krea2 text encoder.
+64 -2
View File
@@ -35,6 +35,25 @@ except Exception: # pragma: no cover - portability shim
"<|im_start|>user\n{}<|im_end|>\n<|im_start|>assistant\n"
)
# The user-facing system_prompt field holds just the system *message text*; the node wraps it in
# the chat-template scaffolding. Pull the default (Krea2's trained descriptor) out of the template
# so it stays in sync with whatever comfy ships.
_sys = re.search(r"<\|im_start\|>system\n(.*?)<\|im_end\|>", KREA2_TEMPLATE, re.S)
KREA2_SYSTEM_DEFAULT = _sys.group(1) if _sys else (
"Describe the image by detailing the color, shape, size, texture, quantity, text, "
"spatial relationships of the objects and background:"
)
# Instruct/edit-style framing (à la TextEncodeQwenImageEditPlus): paste this into system_prompt to
# make the VLM fuse the user's text WITH the reference image instead of just describing it.
# Out-of-distribution for Krea2's trained descriptor — experimental.
KREA2_INSTRUCT_SYSTEM = (
"Describe the key features of the reference image (color, shape, size, texture, objects, "
"background), then explain how the user's instruction should combine with or alter it, and "
"generate a new image meeting the instruction while staying consistent with the reference "
"where appropriate:"
)
class TextEncodeKrea2:
@classmethod
@@ -60,6 +79,14 @@ class TextEncodeKrea2:
"image size added on EACH side. 0 = tight crop to the mask; 0.1 = ~10% "
"margin of surroundings. Only applies when a mask is connected.",
}),
"system_prompt": ("STRING", {
"forceInput": True,
"tooltip": "Optional system-instruction input. Wire a text node to override how the "
"VLM frames the reference + your prompt; leave unconnected to use Krea2's "
"trained descriptor (in-distribution). Use an instruct/edit-style "
"instruction (see README) to fuse the prompt with the image. The node "
"adds the chat-template scaffolding; provide just the instruction text.",
}),
},
}
@@ -116,7 +143,8 @@ class TextEncodeKrea2:
return image[:, y0:y1 + 1, x0:x1 + 1, :]
def encode(self, clip, prompt, vision_megapixels=1.0, mask_padding=0.0, **kwargs):
def encode(self, clip, prompt, vision_megapixels=1.0, mask_padding=0.0,
system_prompt=KREA2_SYSTEM_DEFAULT, **kwargs):
images = self._collect_indexed(kwargs, "image")
masks = self._collect_indexed(kwargs, "mask")
ordered = sorted(images.keys())
@@ -144,15 +172,49 @@ class TextEncodeKrea2:
else:
image_prompt += "<|vision_start|><|image_pad|><|vision_end|>"
tokens = clip.tokenize(image_prompt + prompt, images=images_vl, llama_template=KREA2_TEMPLATE)
system = system_prompt.strip() or KREA2_SYSTEM_DEFAULT
template = ("<|im_start|>system\n" + system + "<|im_end|>\n"
"<|im_start|>user\n{}<|im_end|>\n<|im_start|>assistant\n")
tokens = clip.tokenize(image_prompt + prompt, images=images_vl, llama_template=template)
conditioning = clip.encode_from_tokens_scheduled(tokens)
return (conditioning,)
class Krea2SystemPrompt:
"""Generic text node preloaded with the instruct/edit-style system prompt. Wire its
output into TextEncodeKrea2's `system_prompt` input to make the prompt fuse with the
reference image (experimental / out-of-distribution). Edit the text freely."""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": ("STRING", {
"multiline": True, "default": KREA2_INSTRUCT_SYSTEM,
"tooltip": "System instruction for Krea2's VLM. Defaults to an instruct/edit-style "
"framing that fuses your prompt with the reference image. Edit as needed; "
"paste the plain descriptor to fall back to default behavior.",
}),
},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("system_prompt",)
FUNCTION = "run"
CATEGORY = "model/conditioning/krea2"
DESCRIPTION = ("Text node preloaded with an instruct-style system prompt for Text Encode (Krea2). "
"Wire its output into the encoder's system_prompt input.")
def run(self, text):
return (text,)
NODE_CLASS_MAPPINGS = {
"TextEncodeKrea2": TextEncodeKrea2,
"Krea2SystemPrompt": Krea2SystemPrompt,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"TextEncodeKrea2": "Text Encode (Krea2)",
"Krea2SystemPrompt": "Krea2 System Prompt",
}