Prompt-driven roles: drop imageN_role widgets, styleN/characterN decide per-slot processing
This commit is contained in:
@@ -63,14 +63,17 @@ Civitai / Hugging Face and put it in `models/loras/`.
|
||||
|
||||
### Krea 2 Reference Encode (`TextEncodeKrea2Reference`)
|
||||
|
||||
Prompt + up to 4 reference images. Refer to them as `Picture 1..4` (or
|
||||
`image1..4` — auto-normalized). Images connected but not mentioned get a role
|
||||
clause appended automatically.
|
||||
Prompt + up to 4 reference images. **Roles live in the prompt**: write
|
||||
`character1..4` for identity references and `style1..4` for style-only
|
||||
references (their patches are shuffled so the subject can't leak; `characterN`
|
||||
wins if both appear). Both expand to the exact clauses the LoRA trains on —
|
||||
`"The character1 driving a car in the style2"` is a complete prompt. Plain
|
||||
`image1..4` / `Picture 1..4` also work; connected images never mentioned get a
|
||||
character clause appended automatically.
|
||||
|
||||
| Input | Description |
|
||||
|---|---|
|
||||
| `imageN_detail` | vision tokens per ref: low/normal/high/max = 256/512/1024/1280px. High for characters, low for style/pose hints |
|
||||
| `imageN_role` | `content` (identity) or `style` (32px grid patch-shuffle: destroys the subject, keeps the style) |
|
||||
| `imageN_mask` | crop to mask bbox + white-out background before encoding |
|
||||
| `bg_removal` | wire `LoadBackgroundRemovalModel`: auto-cleans content refs |
|
||||
| `layout_split` | first fraction of steps conditioned on text only (0.25 kills collage layouts zero-shot; unnecessary with the LoRA) |
|
||||
|
||||
+11
-17
@@ -21,10 +21,6 @@ DETAIL = {"low": 256, "normal": 512, "high": 1024, "max": 1280}
|
||||
DETAIL_TIP = ("Longest side this reference is scaled to before the vision encoder. Higher = more "
|
||||
"vision tokens = stronger, more literal reference. Use high for the character/subject "
|
||||
"and low/normal for pose or style hints to avoid side-by-side collages.")
|
||||
ROLE_TIP = ("content: the image is used literally (character, subject, pose). "
|
||||
"style: its patches are shuffled before the vision encoder, destroying the subject's "
|
||||
"shape so only palette/linework/texture transfer — prevents the style image's subject "
|
||||
"from appearing in the output.")
|
||||
SPLIT_TIP = ("Fraction of the denoise steps that see TEXT-ONLY conditioning before the references "
|
||||
"kick in. The first steps fix the layout, so 0.25 strongly prevents side-by-side "
|
||||
"collages of the references. 0 disables.")
|
||||
@@ -89,8 +85,8 @@ EDIT_TEMPLATE = (
|
||||
_IMG_WORD = re.compile(r"\b(?:image|img|imagen|picture)[ _]?([1-4])\b", re.IGNORECASE)
|
||||
|
||||
# Role-typed shorthand: "character1" / "style2" expand to the exact clauses the
|
||||
# reference LoRA trains on, and "styleN" additionally forces that slot's role to
|
||||
# style (patch shuffle) — the prompt wins over the widget.
|
||||
# reference LoRA trains on. Roles are prompt-driven: styleN shuffles that slot's
|
||||
# patches (style-only transfer); characterN keeps it literal and wins over styleN.
|
||||
_CHAR_WORD = re.compile(r"\b(?:character|char|personaje)[ _]?([1-4])\b", re.IGNORECASE)
|
||||
_STYLE_WORD = re.compile(r"\b(?:style|estilo)[ _]?([1-4])\b", re.IGNORECASE)
|
||||
|
||||
@@ -98,11 +94,16 @@ _STYLE_WORD = re.compile(r"\b(?:style|estilo)[ _]?([1-4])\b", re.IGNORECASE)
|
||||
def expand_role_tokens(prompt):
|
||||
"""'The character1 in a car in the style2' ->
|
||||
'The character from Picture 1 in a car in the exact art style of Picture 2'.
|
||||
Returns (text, slots_forced_to_style)."""
|
||||
Returns (text, roles): roles are prompt-driven — styleN marks the slot as
|
||||
style (patch shuffle); characterN marks it content and wins if both appear
|
||||
for the same slot (identity needs the unshuffled image)."""
|
||||
style_slots = {int(m.group(1)) - 1 for m in _STYLE_WORD.finditer(prompt)}
|
||||
char_slots = {int(m.group(1)) - 1 for m in _CHAR_WORD.finditer(prompt)}
|
||||
text = _CHAR_WORD.sub(lambda m: "character from Picture " + m.group(1), prompt)
|
||||
text = _STYLE_WORD.sub(lambda m: "exact art style of Picture " + m.group(1), text)
|
||||
return text, style_slots
|
||||
roles = tuple("style" if i in style_slots and i not in char_slots else "content"
|
||||
for i in range(4))
|
||||
return text, roles
|
||||
|
||||
|
||||
# Auto-added when the prompt doesn't mention a connected image. Mirrors the
|
||||
@@ -142,26 +143,22 @@ class TextEncodeKrea2Reference:
|
||||
"prompt": ("STRING", {
|
||||
"multiline": True,
|
||||
"dynamicPrompts": True,
|
||||
"tooltip": "Shorthand: character1..4 / style1..4 expand to the trained clauses (styleN also sets that slot to style role). Or refer to refs as image1..4 / Picture 1..4, "
|
||||
"tooltip": "Roles come from the prompt: character1..4 = identity reference, style1..4 = style-only (patches shuffled). Both expand to the clauses the LoRA trains on. Plain image1..4 / Picture 1..4 also work, "
|
||||
"e.g. 'Redraw the character from image1 in the pose of image2'.",
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"image1": ("IMAGE",),
|
||||
"image1_detail": (list(DETAIL), {"default": "high", "tooltip": DETAIL_TIP}),
|
||||
"image1_role": (["content", "style"], {"default": "content", "tooltip": ROLE_TIP}),
|
||||
"image1_mask": ("MASK", {"tooltip": MASK_TIP}),
|
||||
"image2": ("IMAGE",),
|
||||
"image2_detail": (list(DETAIL), {"default": "high", "tooltip": DETAIL_TIP}),
|
||||
"image2_role": (["content", "style"], {"default": "content", "tooltip": ROLE_TIP}),
|
||||
"image2_mask": ("MASK", {"tooltip": MASK_TIP}),
|
||||
"image3": ("IMAGE",),
|
||||
"image3_detail": (list(DETAIL), {"default": "high", "tooltip": DETAIL_TIP}),
|
||||
"image3_role": (["content", "style"], {"default": "content", "tooltip": ROLE_TIP}),
|
||||
"image3_mask": ("MASK", {"tooltip": MASK_TIP}),
|
||||
"image4": ("IMAGE",),
|
||||
"image4_detail": (list(DETAIL), {"default": "high", "tooltip": DETAIL_TIP}),
|
||||
"image4_role": (["content", "style"], {"default": "content", "tooltip": ROLE_TIP}),
|
||||
"image4_mask": ("MASK", {"tooltip": MASK_TIP}),
|
||||
"bg_removal": ("BACKGROUND_REMOVAL", {"tooltip": BG_TIP}),
|
||||
"layout_split": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 0.9, "step": 0.05, "tooltip": SPLIT_TIP}),
|
||||
@@ -177,15 +174,12 @@ class TextEncodeKrea2Reference:
|
||||
|
||||
def encode(self, clip, prompt, image1=None, image2=None, image3=None, image4=None,
|
||||
image1_detail="high", image2_detail="high", image3_detail="high", image4_detail="high",
|
||||
image1_role="content", image2_role="content", image3_role="content", image4_role="content",
|
||||
image1_mask=None, image2_mask=None, image3_mask=None, image4_mask=None,
|
||||
bg_removal=None, layout_split=0.0):
|
||||
slots = (image1, image2, image3, image4)
|
||||
details = (image1_detail, image2_detail, image3_detail, image4_detail)
|
||||
masks = (image1_mask, image2_mask, image3_mask, image4_mask)
|
||||
prompt, style_slots = expand_role_tokens(prompt)
|
||||
roles = tuple("style" if i in style_slots else r
|
||||
for i, r in enumerate((image1_role, image2_role, image3_role, image4_role)))
|
||||
prompt, roles = expand_role_tokens(prompt)
|
||||
full_prompt, connected = build_image_prompt(prompt, slots, roles)
|
||||
|
||||
images_vl = []
|
||||
|
||||
Reference in New Issue
Block a user