From 38da10b0d4655098d867c14af10093baa76a85c4 Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Sat, 27 Jun 2026 09:20:24 +0200 Subject: [PATCH] Release 1.0.6: remove Krea2 VLM Preview node The preview only exposed the decode-path (lm_head) refusals of abliterated models and didn't reflect the conditioning (hidden-state) path, so it was misleading. Encoder + Krea2 System Prompt nodes unchanged. Co-Authored-By: Claude Opus 4.8 --- README.md | 12 ------ nodes.py | 76 +------------------------------------ pyproject.toml | 2 +- web/krea2_dynamic_images.js | 2 +- 4 files changed, 3 insertions(+), 89 deletions(-) diff --git a/README.md b/README.md index 151b074..99cbab5 100644 --- a/README.md +++ b/README.md @@ -56,18 +56,6 @@ downstream of this node — that works generically at the sampler level.) **Output:** `conditioning` for the Krea2 sampler. (`print_prompt` dumps the assembled Qwen3-VL prompt to the console for debugging.) -## Inspecting what the VLM sees — `Krea2 VLM Preview` - -The conditioning path only extracts hidden states; it never generates text. To actually *read* -how Qwen3-VL interprets your image + prompt, use the **`Krea2 VLM Preview`** node: it mirrors the -encoder's image/template prep, then runs the model **generatively** (`clip.generate` → `decode`) -and outputs the text. Same `vision_megapixels` / `mask_padding` / `vision_position` / `system_prompt` -controls, plus `max_length` / `temperature` / `seed`. - -Notes: it's a *proxy* (the generated text shares the VLM's forward understanding but isn't the -hidden-state tensor the sampler uses); it needs the encoder's `lm_head` weights; and image inputs -require a **bf16** encoder (FP8 vision is unsupported — see below). - ## System prompt (making the prompt interact with the image) `system_prompt` is a connectable text **input**, not a widget — leave it unconnected to use diff --git a/nodes.py b/nodes.py index 7a5a531..a588855 100644 --- a/nodes.py +++ b/nodes.py @@ -157,8 +157,7 @@ class TextEncodeKrea2: @classmethod def _prepare_vision(cls, kwargs, vision_megapixels, mask_padding): - """Crop+resize each connected reference and build the vision-token string. - Shared by the encoder and the VLM preview so both feed the model identically.""" + """Crop+resize each connected reference and build the vision-token string.""" images = cls._collect_indexed(kwargs, "image") masks = cls._collect_indexed(kwargs, "mask") ordered = sorted(images.keys()) @@ -207,19 +206,6 @@ class TextEncodeKrea2: ) return None - @staticmethod - def _quiet_token_progress(): - """Silence ComfyUI's per-token tqdm bar during generation (it prints one console line - per token on consoles that don't honor carriage returns). The UI progress ring, driven - by a separate comfy.utils.ProgressBar, still updates. Returns a restore() callable.""" - try: - import comfy.text_encoders.llama as _llama - orig = _llama.tqdm - _llama.tqdm = lambda it=None, *a, **k: (it if it is not None else orig(*a, **k)) - return lambda: setattr(_llama, "tqdm", orig) - except Exception: - return lambda: None - def encode(self, clip, prompt, vision_megapixels=1.0, mask_padding=0.0, system_prompt=KREA2_SYSTEM_DEFAULT, vision_position="before prompt", print_prompt=False, **kwargs): @@ -272,72 +258,12 @@ class Krea2SystemPrompt: return (text,) -class Krea2VLMPreview: - """Runs Krea2's Qwen3-VL encoder GENERATIVELY on the same image+prompt the encoder feeds, - returning the model's text output — a proxy for what the VLM 'sees'. Needs the encoder's - lm_head in the weights; use a bf16/fp16 encoder for image inputs (FP8 vision is unsupported).""" - - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "clip": ("CLIP",), - "prompt": ("STRING", {"multiline": True, "dynamicPrompts": True}), - }, - "optional": { - "system_prompt": ("STRING", { - "forceInput": True, - "tooltip": "Same as the encoder's system_prompt input; unconnected = Krea2 descriptor.", - }), - "image1": ("IMAGE",), - "mask1": ("MASK",), - "vision_megapixels": ("FLOAT", {"default": 1.0, "min": 0.1, "max": 8.0, "step": 0.1}), - "mask_padding": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 1.0, "step": 0.02}), - "vision_position": (["before prompt", "after prompt"], {"default": "before prompt"}), - "max_length": ("INT", {"default": 256, "min": 1, "max": 8192, - "tooltip": "Max number of tokens to generate."}), - "temperature": ("FLOAT", {"default": 0.7, "min": 0.0, "max": 2.0, "step": 0.01, - "tooltip": "0 = greedy/deterministic."}), - "seed": ("INT", {"default": 0, "min": 0, "max": 0xffffffffffffffff}), - }, - } - - RETURN_TYPES = ("STRING",) - RETURN_NAMES = ("vlm_text",) - FUNCTION = "preview" - CATEGORY = "model/conditioning/krea2" - DESCRIPTION = ("Generate text from Krea2's Qwen3-VL encoder on the same image+prompt the encoder " - "sends, to inspect how the VLM reads your reference. Needs lm_head weights; use a " - "bf16 encoder for image inputs.") - - def preview(self, clip, prompt, vision_megapixels=1.0, mask_padding=0.0, - system_prompt=KREA2_SYSTEM_DEFAULT, vision_position="before prompt", - max_length=256, temperature=0.7, seed=0, **kwargs): - images_vl, image_prompt = TextEncodeKrea2._prepare_vision(kwargs, vision_megapixels, mask_padding) - text, template = TextEncodeKrea2._build_text(system_prompt, prompt, image_prompt, vision_position) - tokens = clip.tokenize(text, images=images_vl, llama_template=template) - restore = TextEncodeKrea2._quiet_token_progress() - try: - ids = clip.generate(tokens, do_sample=(temperature > 0.0), max_length=max_length, - temperature=max(temperature, 0.01), seed=seed) - except NotImplementedError as exc: - hint = TextEncodeKrea2._fp8_hint(exc, images_vl) - if hint is not None: - raise hint from exc - raise - finally: - restore() - return (clip.decode(ids),) - - NODE_CLASS_MAPPINGS = { "TextEncodeKrea2": TextEncodeKrea2, "Krea2SystemPrompt": Krea2SystemPrompt, - "Krea2VLMPreview": Krea2VLMPreview, } NODE_DISPLAY_NAME_MAPPINGS = { "TextEncodeKrea2": "Text Encode (Krea2)", "Krea2SystemPrompt": "Krea2 System Prompt", - "Krea2VLMPreview": "Krea2 VLM Preview", } diff --git a/pyproject.toml b/pyproject.toml index 339395c..aaa16af 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "comfyui-krea2-text-encoder" description = "Vision-aware text conditioning for the Krea2 / K2 model. Feeds reference images through the Qwen3-VL-4B vision path with the Krea2 descriptor template; optional per-image mask crops to the masked region. No VAE (Krea2 has no reference-latent pathway). Auto-growing image+mask slots." -version = "1.0.5" +version = "1.0.6" license = "MIT" requires-python = ">=3.10" dependencies = [] diff --git a/web/krea2_dynamic_images.js b/web/krea2_dynamic_images.js index 154a6d3..a3bedf8 100644 --- a/web/krea2_dynamic_images.js +++ b/web/krea2_dynamic_images.js @@ -3,7 +3,7 @@ import { app } from "../../scripts/app.js"; // Auto-growing reference slots for "Text Encode (Krea2)": each reference is an // (imageN, maskN) pair. Keep exactly one empty trailing pair, appending a fresh // pair whenever the last one gets connected. -const NODE_NAMES = new Set(["TextEncodeKrea2", "Krea2VLMPreview"]); +const NODE_NAMES = new Set(["TextEncodeKrea2"]); const IMAGE_RE = /^image(\d+)$/; function pairNumbers(node) {