Files
EthanfelandClaude Opus 4.8 38da10b0d4 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 <noreply@anthropic.com>
2026-06-27 09:20:24 +02:00

113 lines
3.5 KiB
JavaScript

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"]);
const IMAGE_RE = /^image(\d+)$/;
function pairNumbers(node) {
const nums = [];
for (const inp of node.inputs || []) {
const m = IMAGE_RE.exec(inp.name);
if (m) nums.push(parseInt(m[1], 10));
}
nums.sort((a, b) => a - b);
return nums;
}
function inputIndex(node, name) {
return (node.inputs || []).findIndex((i) => i.name === name);
}
function linked(node, name) {
const idx = inputIndex(node, name);
return idx >= 0 && node.inputs[idx].link != null;
}
function addPair(node, n) {
node.addInput(`image${n}`, "IMAGE");
node.addInput(`mask${n}`, "MASK");
}
function removePair(node, n) {
// Remove mask first (it sits after the image, so the image index stays valid).
let idx = inputIndex(node, `mask${n}`);
if (idx >= 0) node.removeInput(idx);
idx = inputIndex(node, `image${n}`);
if (idx >= 0) node.removeInput(idx);
}
function pairEmpty(node, n) {
return !linked(node, `image${n}`) && !linked(node, `mask${n}`);
}
// Self-heal: guarantee every imageN has a companion maskN (e.g. nodes saved before
// masks existed, or a stale Python schema that only defined image1).
function ensureMasks(node) {
for (const n of pairNumbers(node)) {
if (inputIndex(node, `mask${n}`) < 0) {
node.addInput(`mask${n}`, "MASK");
}
}
}
function syncPairs(node) {
if (pairNumbers(node).length === 0) addPair(node, 1);
ensureMasks(node);
// Collapse trailing fully-empty pairs down to a single spare.
for (;;) {
const nums = pairNumbers(node);
if (nums.length <= 1) break;
const last = nums[nums.length - 1];
const prev = nums[nums.length - 2];
if (pairEmpty(node, last) && pairEmpty(node, prev)) {
removePair(node, last);
} else {
break;
}
}
// If the last pair is in use, append a fresh spare pair.
const nums = pairNumbers(node);
const last = nums[nums.length - 1];
if (!pairEmpty(node, last)) {
addPair(node, last + 1);
}
node.setDirtyCanvas(true, true);
}
app.registerExtension({
name: "krea2.textencode.dynamicimages",
async beforeRegisterNodeDef(nodeType, nodeData) {
if (!NODE_NAMES.has(nodeData.name)) return;
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
syncPairs(this);
return r;
};
const onConnectionsChange = nodeType.prototype.onConnectionsChange;
nodeType.prototype.onConnectionsChange = function (slotType) {
const r = onConnectionsChange ? onConnectionsChange.apply(this, arguments) : undefined;
// LiteGraph.INPUT === 1; only react to input-side connection changes.
if (slotType === 1) {
syncPairs(this);
}
return r;
};
// Restore the spare pair after a saved graph is loaded.
const onConfigure = nodeType.prototype.onConfigure;
nodeType.prototype.onConfigure = function () {
const r = onConfigure ? onConfigure.apply(this, arguments) : undefined;
syncPairs(this);
return r;
};
},
});