124 lines
5.0 KiB
JavaScript
124 lines
5.0 KiB
JavaScript
import { app } from "/scripts/app.js";
|
|
|
|
function generateRandomUuidV4() {
|
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
return crypto.randomUUID();
|
|
}
|
|
const randomBytes = new Uint8Array(16);
|
|
crypto.getRandomValues(randomBytes);
|
|
randomBytes[6] = (randomBytes[6] & 0x0f) | 0x40;
|
|
randomBytes[8] = (randomBytes[8] & 0x3f) | 0x80;
|
|
const hexByteStrings = Array.from(randomBytes, (byte) => byte.toString(16).padStart(2, "0"));
|
|
return (
|
|
hexByteStrings.slice(0, 4).join("") + "-" +
|
|
hexByteStrings.slice(4, 6).join("") + "-" +
|
|
hexByteStrings.slice(6, 8).join("") + "-" +
|
|
hexByteStrings.slice(8, 10).join("") + "-" +
|
|
hexByteStrings.slice(10, 16).join("")
|
|
);
|
|
}
|
|
|
|
// Non-serializable visual-only widget. Uses every marker ComfyUI versions
|
|
// inspect so it never contributes to widgets_values on save/load, which would
|
|
// otherwise scramble field values on reload.
|
|
function makeReadOnlyTextWidget(displayText, fontColorCss, fontStyleCss) {
|
|
return {
|
|
type: "info",
|
|
name: `__readonly__${displayText}`,
|
|
value: "",
|
|
options: { serialize: false },
|
|
serialize: false,
|
|
serializeValue() { return undefined; },
|
|
computeSize() { return [0, 18]; },
|
|
draw(ctx, node, widgetWidth, widgetYPosition, widgetHeight) {
|
|
ctx.save();
|
|
ctx.fillStyle = fontColorCss;
|
|
ctx.font = `${fontStyleCss} 12px sans-serif`;
|
|
ctx.textBaseline = "middle";
|
|
ctx.fillText(displayText, 10, widgetYPosition + widgetHeight * 0.5);
|
|
ctx.restore();
|
|
},
|
|
};
|
|
}
|
|
|
|
app.registerExtension({
|
|
name: "ClaudeCliVisionText.UuidAndHeaders",
|
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
|
if (nodeData?.name !== "ClaudeCliVisionText") {
|
|
return;
|
|
}
|
|
|
|
const originalOnNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function onNodeCreatedAppendOnly() {
|
|
const result = originalOnNodeCreated?.apply(this, arguments);
|
|
// We only APPEND widgets here (never splice into this.widgets at
|
|
// specific positions) so the widget order stays aligned with
|
|
// widgets_values on save/load. Defer UUID auto-fill to after
|
|
// onConfigure may have restored a saved value.
|
|
if (!this.__claudeCliEnhanced) {
|
|
this.__claudeCliEnhanced = true;
|
|
this.addWidget(
|
|
"button",
|
|
"Regenerate Session UUID",
|
|
null,
|
|
() => {
|
|
const sessionIdWidget = this.widgets?.find((w) => w.name === "session_id");
|
|
if (sessionIdWidget) {
|
|
sessionIdWidget.value = generateRandomUuidV4();
|
|
this.setDirtyCanvas(true, true);
|
|
}
|
|
},
|
|
{ serialize: false }
|
|
);
|
|
this.widgets.push(makeReadOnlyTextWidget(
|
|
"⚠ Regenerating creates a NEW session (~30k tokens cold-start).",
|
|
"#f6ad55",
|
|
"italic"
|
|
));
|
|
this.widgets.push(makeReadOnlyTextWidget(
|
|
"API Key — leave blank to use system OAuth credentials",
|
|
"#cbd5e0",
|
|
"bold"
|
|
));
|
|
}
|
|
// UUID auto-fill is deferred so any saved value from onConfigure
|
|
// is already applied by the time we look.
|
|
setTimeout(() => {
|
|
const sessionIdWidget = this.widgets?.find((w) => w.name === "session_id");
|
|
if (sessionIdWidget) {
|
|
sessionIdWidget.label = "Session UUID";
|
|
const currentValue = typeof sessionIdWidget.value === "string" ? sessionIdWidget.value.trim() : "";
|
|
if (!currentValue) {
|
|
sessionIdWidget.value = generateRandomUuidV4();
|
|
this.setDirtyCanvas(true, true);
|
|
}
|
|
}
|
|
}, 0);
|
|
|
|
return result;
|
|
};
|
|
},
|
|
});
|
|
|
|
app.registerExtension({
|
|
name: "SplitImageBatchToListOfImageBatches.StrideHint",
|
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
|
if (nodeData?.name !== "SplitImageBatchToListOfImageBatches") {
|
|
return;
|
|
}
|
|
const originalOnNodeCreated = nodeType.prototype.onNodeCreated;
|
|
nodeType.prototype.onNodeCreated = function onNodeCreatedAddStrideHint() {
|
|
const result = originalOnNodeCreated?.apply(this, arguments);
|
|
if (!this.__subBatchListStrideHintAdded) {
|
|
this.__subBatchListStrideHintAdded = true;
|
|
this.widgets.push(makeReadOnlyTextWidget(
|
|
"stride 0: stride = sub-batch size",
|
|
"#cbd5e0",
|
|
"italic"
|
|
));
|
|
}
|
|
return result;
|
|
};
|
|
},
|
|
});
|