mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-24 14:42:11 -03:00
feat(randomizer): add LoRA locking and roll modes
- Implement LoRA locking to prevent specific LoRAs from being changed during randomization - Add visual styling for locked state with amber accents and distinct backgrounds - Introduce `roll_mode` configuration with 'backend' (execute current selection while generating new) and 'frontend' (execute newly generated selection) behaviors - Move LoraPoolNode to 'Lora Manager/randomizer' category and remove standalone class mappings - Standardize RETURN_NAMES in LoraRandomizerNode for consistency
This commit is contained in:
@@ -175,6 +175,20 @@
|
||||
box-shadow: 0 0 0 1px rgba(66, 153, 225, 0.3) !important;
|
||||
}
|
||||
|
||||
.lm-lora-entry[data-selected="true"][data-locked="true"] {
|
||||
background-color: rgba(66, 153, 225, 0.2) !important;
|
||||
border-left: 3px solid rgba(245, 158, 11, 0.8) !important;
|
||||
border-right: 1px solid rgba(66, 153, 225, 0.6) !important;
|
||||
border-top: 1px solid rgba(66, 153, 225, 0.6) !important;
|
||||
border-bottom: 1px solid rgba(66, 153, 225, 0.6) !important;
|
||||
box-shadow: 0 0 0 1px rgba(66, 153, 225, 0.3), inset 0 0 20px rgba(245, 158, 11, 0.04) !important;
|
||||
}
|
||||
|
||||
.lm-lora-entry[data-selected="true"][data-locked="true"][data-active="false"] {
|
||||
background-color: rgba(48, 42, 36, 0.5) !important;
|
||||
border-left: 3px solid rgba(245, 158, 11, 0.6) !important;
|
||||
}
|
||||
|
||||
.lm-lora-name {
|
||||
margin-left: 4px;
|
||||
flex: 1;
|
||||
@@ -236,7 +250,6 @@
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-size: 12px;
|
||||
color: rgba(226, 232, 240, 0.8);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
@@ -246,6 +259,11 @@
|
||||
transform: scale(1.2);
|
||||
}
|
||||
|
||||
.lm-lora-arrow svg {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.lm-lora-expand-button {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
@@ -254,7 +272,6 @@
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-size: 10px;
|
||||
color: rgba(226, 232, 240, 0.7);
|
||||
background-color: rgba(45, 55, 72, 0.3);
|
||||
border: 1px solid rgba(226, 232, 240, 0.2);
|
||||
@@ -262,7 +279,6 @@
|
||||
transition: all 0.2s ease;
|
||||
flex-shrink: 0;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@@ -314,13 +330,17 @@
|
||||
justify-content: center;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
font-size: 14px;
|
||||
color: rgba(226, 232, 240, 0.6);
|
||||
transition: all 0.2s ease;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.lm-lora-drag-handle svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.lm-lora-drag-handle:hover {
|
||||
color: rgba(226, 232, 240, 0.9);
|
||||
transform: scale(1.1);
|
||||
@@ -330,6 +350,83 @@
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.lm-lora-lock-button {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
background-color: rgba(45, 55, 72, 0.3);
|
||||
border: 1px solid rgba(226, 232, 240, 0.2);
|
||||
border-radius: 3px;
|
||||
transition: all 0.2s ease;
|
||||
flex-shrink: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
margin-right: 8px;
|
||||
color: rgba(226, 232, 240, 0.8);
|
||||
}
|
||||
|
||||
.lm-lora-lock-button svg {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
}
|
||||
|
||||
.lm-lora-lock-button:hover {
|
||||
background-color: rgba(66, 153, 225, 0.2);
|
||||
border-color: rgba(66, 153, 225, 0.4);
|
||||
color: rgba(226, 232, 240, 0.95);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.lm-lora-lock-button:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.lm-lora-lock-button:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.lm-lora-lock-button:focus-visible {
|
||||
box-shadow: 0 0 0 2px rgba(66, 153, 225, 0.5);
|
||||
}
|
||||
|
||||
.lm-lora-lock-button--locked {
|
||||
background-color: rgba(245, 158, 11, 0.25);
|
||||
border-color: rgba(245, 158, 11, 0.7);
|
||||
color: rgba(251, 191, 36, 0.95);
|
||||
box-shadow: 0 0 8px rgba(245, 158, 11, 0.15);
|
||||
}
|
||||
|
||||
.lm-lora-lock-button--locked:hover {
|
||||
background-color: rgba(245, 158, 11, 0.35);
|
||||
border-color: rgba(245, 158, 11, 0.85);
|
||||
box-shadow: 0 0 12px rgba(245, 158, 11, 0.25);
|
||||
}
|
||||
|
||||
/* Visual styling for locked lora entries */
|
||||
.lm-lora-entry[data-locked="true"] {
|
||||
background-color: rgba(60, 50, 40, 0.75);
|
||||
border-left: 3px solid rgba(245, 158, 11, 0.7);
|
||||
box-shadow: inset 0 0 20px rgba(245, 158, 11, 0.04);
|
||||
}
|
||||
|
||||
.lm-lora-entry[data-locked="true"]:hover {
|
||||
background-color: rgba(65, 55, 45, 0.85);
|
||||
box-shadow: inset 0 0 24px rgba(245, 158, 11, 0.06);
|
||||
}
|
||||
|
||||
.lm-lora-entry[data-locked="true"][data-active="false"] {
|
||||
background-color: rgba(48, 42, 36, 0.6);
|
||||
border-left: 3px solid rgba(245, 158, 11, 0.5);
|
||||
}
|
||||
|
||||
.lm-lora-entry[data-locked="true"][data-active="false"]:hover {
|
||||
background-color: rgba(52, 46, 40, 0.7);
|
||||
}
|
||||
|
||||
body.lm-lora-strength-dragging,
|
||||
body.lm-lora-strength-dragging * {
|
||||
cursor: ew-resize !important;
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
getActiveLorasFromNode,
|
||||
collectActiveLorasFromChain,
|
||||
updateConnectedTriggerWords,
|
||||
updateDownstreamLoaders,
|
||||
chainCallback,
|
||||
mergeLoras,
|
||||
setupInputWidgetWithAutocomplete,
|
||||
@@ -169,41 +170,3 @@ app.registerExtension({
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
// Helper function to find and update downstream Lora Loader nodes
|
||||
function updateDownstreamLoaders(startNode, visited = new Set()) {
|
||||
const nodeKey = getNodeKey(startNode);
|
||||
if (!nodeKey || visited.has(nodeKey)) return;
|
||||
visited.add(nodeKey);
|
||||
|
||||
// Check each output link
|
||||
if (startNode.outputs) {
|
||||
for (const output of startNode.outputs) {
|
||||
if (output.links) {
|
||||
for (const linkId of output.links) {
|
||||
const link = getLinkFromGraph(startNode.graph, linkId);
|
||||
if (link) {
|
||||
const targetNode = startNode.graph?.getNodeById?.(link.target_id);
|
||||
|
||||
// If target is a Lora Loader, collect all active loras in the chain and update
|
||||
if (
|
||||
targetNode &&
|
||||
targetNode.comfyClass === "Lora Loader (LoraManager)"
|
||||
) {
|
||||
const allActiveLoraNames =
|
||||
collectActiveLorasFromChain(targetNode);
|
||||
updateConnectedTriggerWords(targetNode, allActiveLoraNames);
|
||||
}
|
||||
// If target is another Lora Stacker, recursively check its outputs
|
||||
else if (
|
||||
targetNode &&
|
||||
targetNode.comfyClass === "Lora Stacker (LoraManager)"
|
||||
) {
|
||||
updateDownstreamLoaders(targetNode, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createToggle, createArrowButton, createDragHandle, updateEntrySelection, createExpandButton, updateExpandButtonState } from "./loras_widget_components.js";
|
||||
import { createToggle, createArrowButton, createDragHandle, updateEntrySelection, createExpandButton, updateExpandButtonState, createLockButton, updateLockButtonState } from "./loras_widget_components.js";
|
||||
import {
|
||||
parseLoraValue,
|
||||
formatLoraValue,
|
||||
@@ -27,6 +27,9 @@ export function addLorasWidget(node, name, opts, callback) {
|
||||
// Set initial height using CSS variables approach
|
||||
const defaultHeight = 200;
|
||||
|
||||
// Check if this is a randomizer node (lock button instead of drag handle)
|
||||
const isRandomizerNode = opts?.isRandomizerNode === true;
|
||||
|
||||
// Initialize default value
|
||||
const defaultValue = opts?.defaultVal || [];
|
||||
const onSelectionChange = typeof opts?.onSelectionChange === "function"
|
||||
@@ -255,32 +258,52 @@ export function addLorasWidget(node, name, opts, callback) {
|
||||
const loraEl = document.createElement("div");
|
||||
loraEl.className = "lm-lora-entry";
|
||||
|
||||
// Store lora name and active state in dataset for selection
|
||||
// Store lora name, active state, and locked state in dataset
|
||||
loraEl.dataset.loraName = name;
|
||||
loraEl.dataset.active = active ? "true" : "false";
|
||||
loraEl.dataset.locked = (loraData.locked || false) ? "true" : "false";
|
||||
|
||||
// Add click handler for selection
|
||||
loraEl.addEventListener('click', (e) => {
|
||||
// Skip if clicking on interactive elements
|
||||
if (e.target.closest('.lm-lora-toggle') ||
|
||||
e.target.closest('input') ||
|
||||
if (e.target.closest('.lm-lora-toggle') ||
|
||||
e.target.closest('input') ||
|
||||
e.target.closest('.lm-lora-arrow') ||
|
||||
e.target.closest('.lm-lora-drag-handle') ||
|
||||
e.target.closest('.lm-lora-lock-button') ||
|
||||
e.target.closest('.lm-lora-expand-button')) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
selectLora(name);
|
||||
container.focus(); // Focus container for keyboard events
|
||||
});
|
||||
|
||||
// Create drag handle for reordering
|
||||
const dragHandle = createDragHandle();
|
||||
|
||||
// Initialize reorder drag functionality
|
||||
initReorderDrag(dragHandle, name, widget, renderLoras);
|
||||
// Conditionally create drag handle OR lock button
|
||||
let dragHandleOrLockButton;
|
||||
|
||||
if (isRandomizerNode) {
|
||||
// For randomizer node, show lock button instead of drag handle
|
||||
const isLocked = loraData.locked || false;
|
||||
dragHandleOrLockButton = createLockButton(isLocked, (newLocked) => {
|
||||
// Update this lora's locked state
|
||||
const lorasData = parseLoraValue(widget.value);
|
||||
const loraIndex = lorasData.findIndex(l => l.name === name);
|
||||
|
||||
if (loraIndex >= 0) {
|
||||
lorasData[loraIndex].locked = newLocked;
|
||||
const newValue = formatLoraValue(lorasData);
|
||||
updateWidgetValue(newValue);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// For other nodes, show drag handle
|
||||
dragHandleOrLockButton = createDragHandle();
|
||||
// Initialize reorder drag functionality
|
||||
initReorderDrag(dragHandleOrLockButton, name, widget, renderLoras);
|
||||
}
|
||||
|
||||
// Create toggle for this lora
|
||||
const toggle = createToggle(active, (newActive) => {
|
||||
@@ -481,8 +504,8 @@ export function addLorasWidget(node, name, opts, callback) {
|
||||
// Assemble entry
|
||||
const leftSection = document.createElement("div");
|
||||
leftSection.className = "lm-lora-entry-left";
|
||||
|
||||
leftSection.appendChild(dragHandle); // Add drag handle first
|
||||
|
||||
leftSection.appendChild(dragHandleOrLockButton); // Add drag handle or lock button first
|
||||
leftSection.appendChild(toggle);
|
||||
leftSection.appendChild(expandButton); // Add expand button
|
||||
leftSection.appendChild(nameEl);
|
||||
@@ -685,16 +708,17 @@ export function addLorasWidget(node, name, opts, callback) {
|
||||
}, []);
|
||||
|
||||
// Apply existing clip strength values and transfer them to the new value
|
||||
const updatedValue = uniqueValue.map(lora => {
|
||||
const updatedValue = uniqueValue.map(lora => {
|
||||
// For new loras, default clip strength to model strength and expanded to false
|
||||
// unless clipStrength is already different from strength
|
||||
const clipStrength = lora.clipStrength || lora.strength;
|
||||
return {
|
||||
...lora,
|
||||
clipStrength: clipStrength,
|
||||
expanded: lora.hasOwnProperty('expanded') ?
|
||||
lora.expanded :
|
||||
Number(clipStrength) !== Number(lora.strength)
|
||||
expanded: lora.hasOwnProperty('expanded') ?
|
||||
lora.expanded :
|
||||
Number(clipStrength) !== Number(lora.strength),
|
||||
locked: lora.hasOwnProperty('locked') ? lora.locked : false // Initialize locked to false if not present
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -22,7 +22,9 @@ export function updateToggleStyle(toggleEl, active) {
|
||||
export function createArrowButton(direction, onClick) {
|
||||
const button = document.createElement("div");
|
||||
button.className = `lm-lora-arrow lm-lora-arrow-${direction}`;
|
||||
button.textContent = direction === "left" ? "◀" : "▶";
|
||||
button.innerHTML = direction === "left"
|
||||
? `<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>`
|
||||
: `<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>`;
|
||||
|
||||
button.addEventListener("click", (e) => {
|
||||
e.stopPropagation();
|
||||
@@ -36,7 +38,7 @@ export function createArrowButton(direction, onClick) {
|
||||
export function createDragHandle() {
|
||||
const handle = document.createElement("div");
|
||||
handle.className = "lm-lora-drag-handle";
|
||||
handle.innerHTML = "≡";
|
||||
handle.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="12" r="1"/><circle cx="9" cy="5" r="1"/><circle cx="9" cy="19" r="1"/><circle cx="15" cy="12" r="1"/><circle cx="15" cy="5" r="1"/><circle cx="15" cy="19" r="1"/></svg>`;
|
||||
handle.title = "Drag to reorder LoRA";
|
||||
return handle;
|
||||
}
|
||||
@@ -102,10 +104,42 @@ export function createExpandButton(isExpanded, onClick) {
|
||||
// Helper function to update expand button state
|
||||
export function updateExpandButtonState(button, isExpanded) {
|
||||
if (isExpanded) {
|
||||
button.innerHTML = "▼"; // Down arrow for expanded
|
||||
button.innerHTML = `<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>`;
|
||||
button.title = "Collapse clip controls";
|
||||
} else {
|
||||
button.innerHTML = "▶"; // Right arrow for collapsed
|
||||
button.innerHTML = `<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>`;
|
||||
button.title = "Expand clip controls";
|
||||
}
|
||||
}
|
||||
|
||||
// Function to create lock button
|
||||
export function createLockButton(isLocked, onChange) {
|
||||
const button = document.createElement("button");
|
||||
button.className = "lm-lora-lock-button";
|
||||
button.type = "button";
|
||||
button.tabIndex = -1;
|
||||
|
||||
// Set icon based on locked state
|
||||
updateLockButtonState(button, isLocked);
|
||||
|
||||
button.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
onChange(!isLocked);
|
||||
});
|
||||
|
||||
return button;
|
||||
}
|
||||
|
||||
// Helper function to update lock button state
|
||||
export function updateLockButtonState(button, isLocked) {
|
||||
if (isLocked) {
|
||||
button.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>`;
|
||||
button.title = "Unlock this LoRA (allow re-rolling)";
|
||||
button.classList.add("lm-lora-lock-button--locked");
|
||||
} else {
|
||||
button.innerHTML = `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="11" x="3" y="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path></svg>`;
|
||||
button.title = "Lock this LoRA (prevent re-rolling)";
|
||||
button.classList.remove("lm-lora-lock-button--locked");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,6 +239,7 @@ app.registerExtension({
|
||||
|
||||
// Handle trigger word updates from Python
|
||||
handleTriggerWordUpdate(id, graphId, message) {
|
||||
console.log('trigger word update: ', id, graphId, message);
|
||||
const node = getNodeFromGraph(graphId, id);
|
||||
if (!node || node.comfyClass !== "TriggerWord Toggle (LoraManager)") {
|
||||
console.warn("Node not found or not a TriggerWordToggle:", id);
|
||||
|
||||
@@ -233,7 +233,7 @@ export function getConnectedInputStackers(node) {
|
||||
}
|
||||
|
||||
const sourceNode = node.graph?.getNodeById?.(link.origin_id);
|
||||
if (sourceNode && sourceNode.comfyClass === "Lora Stacker (LoraManager)") {
|
||||
if (sourceNode && (sourceNode.comfyClass === "Lora Stacker (LoraManager)" || sourceNode.comfyClass === "Lora Randomizer (LoraManager)")) {
|
||||
connectedStackers.push(sourceNode);
|
||||
}
|
||||
}
|
||||
@@ -274,9 +274,13 @@ export function getConnectedTriggerToggleNodes(node) {
|
||||
export function getActiveLorasFromNode(node) {
|
||||
const activeLoraNames = new Set();
|
||||
|
||||
// For lorasWidget style entries (array of objects)
|
||||
if (node.lorasWidget && node.lorasWidget.value) {
|
||||
node.lorasWidget.value.forEach(lora => {
|
||||
let lorasWidget = node.lorasWidget;
|
||||
if (!lorasWidget && node.widgets) {
|
||||
lorasWidget = node.widgets.find(w => w.name === 'loras');
|
||||
}
|
||||
|
||||
if (lorasWidget && lorasWidget.value) {
|
||||
lorasWidget.value.forEach(lora => {
|
||||
if (lora.active) {
|
||||
activeLoraNames.add(lora.name);
|
||||
}
|
||||
@@ -324,6 +328,8 @@ export function updateConnectedTriggerWords(node, loraNames) {
|
||||
.map((connectedNode) => getNodeReference(connectedNode))
|
||||
.filter((reference) => reference !== null);
|
||||
|
||||
console.log('node ids: ', nodeIds, loraNames);
|
||||
|
||||
if (nodeIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -467,3 +473,78 @@ export function forwardMiddleMouseToCanvas(container) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Get connected Lora Pool node from pool_config input
|
||||
export function getConnectedPoolConfigNode(node) {
|
||||
if (!node?.inputs) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (const input of node.inputs) {
|
||||
if (input.name !== "pool_config" || !input.link) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const link = getLinkFromGraph(node.graph, input.link);
|
||||
if (!link) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const sourceNode = node.graph?.getNodeById?.(link.origin_id);
|
||||
if (sourceNode && sourceNode.comfyClass === "Lora Pool (LoraManager)") {
|
||||
return sourceNode;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get pool config widget value from connected Lora Pool node
|
||||
export function getPoolConfigFromConnectedNode(node) {
|
||||
const poolNode = getConnectedPoolConfigNode(node);
|
||||
if (!poolNode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const poolWidget = poolNode.widgets?.find(w => w.name === "pool_config");
|
||||
return poolWidget?.value || null;
|
||||
}
|
||||
|
||||
// Helper function to find and update downstream Lora Loader nodes
|
||||
export function updateDownstreamLoaders(startNode, visited = new Set()) {
|
||||
const nodeKey = getNodeKey(startNode);
|
||||
if (!nodeKey || visited.has(nodeKey)) return;
|
||||
visited.add(nodeKey);
|
||||
|
||||
// Check each output link
|
||||
if (startNode.outputs) {
|
||||
for (const output of startNode.outputs) {
|
||||
if (output.links) {
|
||||
for (const linkId of output.links) {
|
||||
const link = getLinkFromGraph(startNode.graph, linkId);
|
||||
if (link) {
|
||||
const targetNode = startNode.graph?.getNodeById?.(link.target_id);
|
||||
|
||||
// If target is a Lora Loader, collect all active loras in the chain and update
|
||||
if (
|
||||
targetNode &&
|
||||
targetNode.comfyClass === "Lora Loader (LoraManager)"
|
||||
) {
|
||||
const allActiveLoraNames =
|
||||
collectActiveLorasFromChain(targetNode);
|
||||
updateConnectedTriggerWords(targetNode, allActiveLoraNames);
|
||||
}
|
||||
// If target is another Lora Stacker or Lora Randomizer, recursively check its outputs
|
||||
else if (
|
||||
targetNode &&
|
||||
(targetNode.comfyClass === "Lora Stacker (LoraManager)" ||
|
||||
targetNode.comfyClass === "Lora Randomizer (LoraManager)")
|
||||
) {
|
||||
updateDownstreamLoaders(targetNode, visited);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user