Files
rikanrino-Rikannodes/web/multi_lora_gate.js
T
2026-05-11 20:02:25 +08:00

195 lines
9.3 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { app } from "../../scripts/app.js";
app.registerExtension({
name: "prompt_relay.MultiLoraGateNative",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (nodeData.name === "RikanPromptRelayMultiLoraGate") {
const syncData = (node) => {
if (!node || !node.widgets) return;
const dataWidget = node.widgets.find(w => w.name === "lora_data");
if (!dataWidget) return;
const loras = [];
// Hanya memproses widget lora yang benar-benar eksis
const loraWidgets = node.widgets.filter(w => w.name && w.name.startsWith("lora_"));
loraWidgets.forEach(lw => {
const idx = lw.name.split("_")[1];
const wToggle = node.widgets.find(w => w.name === `enable_${idx}`);
const wSeg = node.widgets.find(w => w.name === `segment_${idx}`);
const wMod = node.widgets.find(w => w.name === `modelStr_${idx}`);
if (wToggle && wSeg && wMod) {
loras.push({
enable: wToggle.value,
name: lw.value,
segment: parseInt(wSeg.value) || 0,
modelStr: parseFloat(wMod.value) || 0.0
});
}
});
dataWidget.value = JSON.stringify(loras);
};
const addLoraRow = function(node, index, loraName = "None") {
const getLoraList = () => {
const loraLoader = LiteGraph.registered_node_types["LoraLoader"];
if (loraLoader && loraLoader.nodeData && loraLoader.nodeData.input && loraLoader.nodeData.input.required && loraLoader.nodeData.input.required.lora_name) {
return ["None"].concat(loraLoader.nodeData.input.required.lora_name[0] || []);
}
return ["None"];
};
const wToggle = node.addWidget("toggle", `enable_${index}`, true, () => syncData(node));
const wLora = node.addWidget("combo", `lora_${index}`, loraName, () => syncData(node), { values: getLoraList() });
// Segment default SELALU 0, dengan step 10 agar klik tombol panah bernilai +1
const wSeg = node.addWidget("number", `segment_${index}`, 0, () => syncData(node), { min: 0, max: 99, step: 10, precision: 0 });
// Strength default SELALU 0.80, dengan step 0.1 agar klik tombol panah bernilai +0.01
const wMod = node.addWidget("number", `modelStr_${index}`, 0.80, () => syncData(node), { min: -10.0, max: 10.0, step: 0.1, precision: 2 });
if (node.btnAddLora && node.btnRemoveLora) {
const idx2 = node.widgets.indexOf(node.btnAddLora);
if (idx2 !== -1) node.widgets.splice(idx2, 1);
const idx3 = node.widgets.indexOf(node.btnRemoveLora);
if (idx3 !== -1) node.widgets.splice(idx3, 1);
node.widgets.push(node.btnAddLora);
node.widgets.push(node.btnRemoveLora);
}
syncData(node);
};
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function () {
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
this.serialize_widgets = true;
this.loraCount = 0;
const wData = this.widgets.find(w => w.name === "lora_data");
if (wData) {
wData.type = "hidden";
wData.hidden = true;
wData.computeSize = () => [0, -4];
}
this.btnToggleAll = this.addWidget("button", "🔄 Toggle All", "toggle_all", () => {
let allOn = true;
for (const w of this.widgets) {
if (w.name && w.name.startsWith("enable_") && w.value === false) {
allOn = false;
break;
}
}
const targetState = !allOn;
for (const w of this.widgets) {
if (w.name && w.name.startsWith("enable_")) {
w.value = targetState;
}
}
syncData(this);
this.setDirtyCanvas(true, true);
});
this.btnAddLora = this.addWidget("button", "➕ Add LoRA", "add_lora", (value, widget, node, pos, event) => {
const loraLoader = LiteGraph.registered_node_types["LoraLoader"];
let loras = ["None"];
if (loraLoader && loraLoader.nodeData && loraLoader.nodeData.input && loraLoader.nodeData.input.required && loraLoader.nodeData.input.required.lora_name) {
loras = loraLoader.nodeData.input.required.lora_name[0].filter(l => l !== "None");
}
const menuItems = loras.map(loraName => ({
content: loraName,
callback: () => {
this.loraCount++;
addLoraRow(this, this.loraCount, loraName);
this.computeSize();
this.setDirtyCanvas(true, true);
}
}));
if (menuItems.length === 0) {
menuItems.push({ content: "No LoRAs found!", callback: () => {} });
}
const e = event || app.canvas.last_mouse_event;
new LiteGraph.ContextMenu(menuItems, { event: e, title: "Choose a LoRA" });
});
this.btnRemoveLora = this.addWidget("button", "➖ Remove Last LoRA", "remove_lora", () => {
if (this.loraCount > 0) {
const suffix = `_${this.loraCount}`;
for (let i = this.widgets.length - 1; i >= 0; i--) {
if (this.widgets[i].name && this.widgets[i].name.endsWith(suffix)) {
this.widgets.splice(i, 1);
}
}
this.loraCount--;
syncData(this);
this.computeSize();
this.setDirtyCanvas(true, true);
}
});
return r;
};
const onConfigure = nodeType.prototype.onConfigure;
nodeType.prototype.onConfigure = function (info) {
if (info && info.widgets_values) {
this.loraCount = 0;
let jsonData = "[]";
for(let v of info.widgets_values) {
if (typeof v === "string" && v.startsWith("[") && v.endsWith("]")) {
jsonData = v;
break;
}
}
try {
const savedLoras = JSON.parse(jsonData);
for (let i = 0; i < savedLoras.length; i++) {
const lora = savedLoras[i];
const idx = i + 1;
this.loraCount = idx;
addLoraRow(this, idx, lora.name);
const wToggle = this.widgets.find(w => w.name === `enable_${idx}`);
const wSegment = this.widgets.find(w => w.name === `segment_${idx}`);
const wModel = this.widgets.find(w => w.name === `modelStr_${idx}`);
if (wToggle) wToggle.value = lora.enable;
if (wSegment) wSegment.value = lora.segment;
if (wModel) wModel.value = lora.modelStr;
}
const wData = this.widgets.find(w => w.name === "lora_data");
if (wData) {
wData.type = "hidden";
wData.hidden = true;
wData.computeSize = () => [0, -4];
wData.value = jsonData;
}
} catch (e) {
console.error("[Rikan MultiLoraGate] Failed to parse saved JSON data:", e);
}
}
if (onConfigure) {
onConfigure.apply(this, arguments);
}
};
const onSerialize = nodeType.prototype.onSerialize;
nodeType.prototype.onSerialize = function (o) {
if (onSerialize) onSerialize.apply(this, arguments);
syncData(this);
};
}
}
});