mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-03-21 21:22:11 -03:00
refactor(lora-provider): extract mode change logic to shared TypeScript module
- Extract common mode change logic from lora_randomizer.js and lora_stacker.js into new mode-change-handler.ts TypeScript module - Add LORA_PROVIDER_NODE_TYPES constant to centralize LoRA provider node types - Update getActiveLorasFromNode in utils.js to support Lora Cycler's cycler_config widget (single current_lora_filename) - Update getConnectedInputStackers and updateDownstreamLoaders to use isLoraProviderNode helper instead of hardcoded class checks - Register mode change handlers in main.ts for all LoRA provider nodes (Lora Stacker, Lora Randomizer, Lora Cycler) - Add value change callback to Lora Cycler widget to trigger updateDownstreamLoaders when current_lora_filename changes - Remove duplicate mode change logic from lora_stacker.js - Delete lora_randomizer.js (logic now centralized) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,11 @@ import LoraRandomizerWidget from '@/components/LoraRandomizerWidget.vue'
|
|||||||
import LoraCyclerWidget from '@/components/LoraCyclerWidget.vue'
|
import LoraCyclerWidget from '@/components/LoraCyclerWidget.vue'
|
||||||
import JsonDisplayWidget from '@/components/JsonDisplayWidget.vue'
|
import JsonDisplayWidget from '@/components/JsonDisplayWidget.vue'
|
||||||
import type { LoraPoolConfig, LegacyLoraPoolConfig, RandomizerConfig, CyclerConfig } from './composables/types'
|
import type { LoraPoolConfig, LegacyLoraPoolConfig, RandomizerConfig, CyclerConfig } from './composables/types'
|
||||||
|
import {
|
||||||
|
setupModeChangeHandler,
|
||||||
|
createModeChangeCallback,
|
||||||
|
LORA_PROVIDER_NODE_TYPES
|
||||||
|
} from './mode-change-handler'
|
||||||
|
|
||||||
const LORA_POOL_WIDGET_MIN_WIDTH = 500
|
const LORA_POOL_WIDGET_MIN_WIDTH = 500
|
||||||
const LORA_POOL_WIDGET_MIN_HEIGHT = 400
|
const LORA_POOL_WIDGET_MIN_HEIGHT = 400
|
||||||
@@ -237,10 +242,15 @@ function createLoraCyclerWidget(node) {
|
|||||||
return internalValue
|
return internalValue
|
||||||
},
|
},
|
||||||
setValue(v: CyclerConfig) {
|
setValue(v: CyclerConfig) {
|
||||||
|
const oldFilename = internalValue?.current_lora_filename
|
||||||
internalValue = v
|
internalValue = v
|
||||||
if (typeof widget.onSetValue === 'function') {
|
if (typeof widget.onSetValue === 'function') {
|
||||||
widget.onSetValue(v)
|
widget.onSetValue(v)
|
||||||
}
|
}
|
||||||
|
// Update downstream loaders when the active LoRA filename changes
|
||||||
|
if (oldFilename !== v?.current_lora_filename) {
|
||||||
|
updateDownstreamLoaders(node)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
serialize: true,
|
serialize: true,
|
||||||
getMinHeight() {
|
getMinHeight() {
|
||||||
@@ -250,7 +260,12 @@ function createLoraCyclerWidget(node) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
widget.updateConfig = (v: CyclerConfig) => {
|
widget.updateConfig = (v: CyclerConfig) => {
|
||||||
|
const oldFilename = internalValue?.current_lora_filename
|
||||||
internalValue = v
|
internalValue = v
|
||||||
|
// Update downstream loaders when the active LoRA filename changes
|
||||||
|
if (oldFilename !== v?.current_lora_filename) {
|
||||||
|
updateDownstreamLoaders(node)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add method to get pool config from connected node
|
// Add method to get pool config from connected node
|
||||||
@@ -392,8 +407,30 @@ app.registerExtension({
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Add display-only widget to Debug Metadata node
|
// Add display-only widget to Debug Metadata node
|
||||||
|
// Register mode change handlers for LoRA provider nodes
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
async beforeRegisterNodeDef(nodeType, nodeData) {
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
||||||
|
const comfyClass = nodeType.comfyClass
|
||||||
|
|
||||||
|
// Register mode change handlers for LoRA provider nodes
|
||||||
|
if (LORA_PROVIDER_NODE_TYPES.includes(comfyClass)) {
|
||||||
|
const originalOnNodeCreated = nodeType.prototype.onNodeCreated
|
||||||
|
|
||||||
|
nodeType.prototype.onNodeCreated = function () {
|
||||||
|
originalOnNodeCreated?.apply(this, arguments)
|
||||||
|
|
||||||
|
// Create node-specific callback for Lora Stacker (updates direct trigger toggles)
|
||||||
|
const nodeSpecificCallback = comfyClass === "Lora Stacker (LoraManager)"
|
||||||
|
? (activeLoraNames: Set<string>) => updateConnectedTriggerWords(this, activeLoraNames)
|
||||||
|
: undefined
|
||||||
|
|
||||||
|
// Create and set up the mode change handler
|
||||||
|
const onModeChange = createModeChangeCallback(this, updateDownstreamLoaders, nodeSpecificCallback)
|
||||||
|
setupModeChangeHandler(this, onModeChange)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the JSON display widget to Debug Metadata node
|
||||||
if (nodeData.name === 'Debug Metadata (LoraManager)') {
|
if (nodeData.name === 'Debug Metadata (LoraManager)') {
|
||||||
const onNodeCreated = nodeType.prototype.onNodeCreated
|
const onNodeCreated = nodeType.prototype.onNodeCreated
|
||||||
|
|
||||||
|
|||||||
153
vue-widgets/src/mode-change-handler.ts
Normal file
153
vue-widgets/src/mode-change-handler.ts
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/**
|
||||||
|
* Mode change handler for LoRA provider nodes.
|
||||||
|
*
|
||||||
|
* Provides common mode change logic for nodes that provide LoRA configurations:
|
||||||
|
* - Lora Stacker (LoraManager)
|
||||||
|
* - Lora Randomizer (LoraManager)
|
||||||
|
* - Lora Cycler (LoraManager)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of node types that act as LoRA providers in the workflow chain.
|
||||||
|
* These nodes can be traversed when collecting active LoRAs and can trigger
|
||||||
|
* downstream loader updates when their mode or active LoRAs change.
|
||||||
|
*/
|
||||||
|
export const LORA_PROVIDER_NODE_TYPES = [
|
||||||
|
"Lora Stacker (LoraManager)",
|
||||||
|
"Lora Randomizer (LoraManager)",
|
||||||
|
"Lora Cycler (LoraManager)",
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type LoraProviderNodeType = typeof LORA_PROVIDER_NODE_TYPES[number];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a node class is a LoRA provider node.
|
||||||
|
*/
|
||||||
|
export function isLoraProviderNode(comfyClass: string): comfyClass is LoraProviderNodeType {
|
||||||
|
return LORA_PROVIDER_NODE_TYPES.includes(comfyClass as LoraProviderNodeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract active LoRA filenames from a node based on its type.
|
||||||
|
*
|
||||||
|
* For Lora Stacker and Lora Randomizer: extracts from lorasWidget (array of loras, filtered by active)
|
||||||
|
* For Lora Cycler: extracts from cycler_config widget (single current_lora_filename)
|
||||||
|
*/
|
||||||
|
export function getActiveLorasFromNodeByType(node: any): Set<string> {
|
||||||
|
const comfyClass = node?.comfyClass;
|
||||||
|
|
||||||
|
if (comfyClass === "Lora Cycler (LoraManager)") {
|
||||||
|
return extractFromCyclerConfig(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default: use lorasWidget (works for Stacker and Randomizer)
|
||||||
|
return extractFromLorasWidget(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract active LoRAs from a node's lorasWidget.
|
||||||
|
* Used by Lora Stacker and Lora Randomizer.
|
||||||
|
*/
|
||||||
|
function extractFromLorasWidget(node: any): Set<string> {
|
||||||
|
const activeLoraNames = new Set<string>();
|
||||||
|
const lorasWidget = node.lorasWidget || node.widgets?.find((w: any) => w.name === 'loras');
|
||||||
|
|
||||||
|
if (lorasWidget?.value) {
|
||||||
|
lorasWidget.value.forEach((lora: any) => {
|
||||||
|
if (lora.active) {
|
||||||
|
activeLoraNames.add(lora.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return activeLoraNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract the active LoRA from a Lora Cycler node.
|
||||||
|
* The Cycler has only one active LoRA at a time, stored in cycler_config.current_lora_filename.
|
||||||
|
*/
|
||||||
|
function extractFromCyclerConfig(node: any): Set<string> {
|
||||||
|
const activeLoraNames = new Set<string>();
|
||||||
|
const cyclerWidget = node.widgets?.find((w: any) => w.name === 'cycler_config');
|
||||||
|
|
||||||
|
if (cyclerWidget?.value?.current_lora_filename) {
|
||||||
|
activeLoraNames.add(cyclerWidget.value.current_lora_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return activeLoraNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a mode value represents an active node.
|
||||||
|
* Active modes: 0 (Always), 3 (On Trigger)
|
||||||
|
* Inactive modes: 2 (Never), 4 (Bypass)
|
||||||
|
*/
|
||||||
|
export function isNodeActive(mode: number | undefined): boolean {
|
||||||
|
return mode === undefined || mode === 0 || mode === 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup a mode change handler for a node.
|
||||||
|
*
|
||||||
|
* Intercepts the mode property setter to trigger a callback when the mode changes.
|
||||||
|
* This is needed because ComfyUI sets the mode property directly without using a setter.
|
||||||
|
*
|
||||||
|
* @param node - The node to set up the handler for
|
||||||
|
* @param onModeChange - Callback function called when mode changes (receives newMode and oldMode)
|
||||||
|
*/
|
||||||
|
export function setupModeChangeHandler(
|
||||||
|
node: any,
|
||||||
|
onModeChange: (newMode: number, oldMode: number) => void
|
||||||
|
): void {
|
||||||
|
let _mode = node.mode;
|
||||||
|
|
||||||
|
Object.defineProperty(node, 'mode', {
|
||||||
|
get() {
|
||||||
|
return _mode;
|
||||||
|
},
|
||||||
|
set(value: number) {
|
||||||
|
const oldValue = _mode;
|
||||||
|
_mode = value;
|
||||||
|
|
||||||
|
if (oldValue !== value) {
|
||||||
|
onModeChange(value, oldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a mode change callback that updates downstream loaders.
|
||||||
|
*
|
||||||
|
* This is the standard callback used by all LoRA provider nodes.
|
||||||
|
* When mode changes:
|
||||||
|
* 1. Determine if the node is active (mode 0 or 3)
|
||||||
|
* 2. Get active LoRAs (empty set if inactive)
|
||||||
|
* 3. Call the optional node-specific callback (e.g., updateConnectedTriggerWords for Stacker)
|
||||||
|
* 4. Update downstream loaders
|
||||||
|
*
|
||||||
|
* @param node - The node instance
|
||||||
|
* @param updateDownstreamLoaders - Function to update downstream loaders (from utils.js)
|
||||||
|
* @param nodeSpecificCallback - Optional callback for node-specific behavior
|
||||||
|
*/
|
||||||
|
export function createModeChangeCallback(
|
||||||
|
node: any,
|
||||||
|
updateDownstreamLoaders: (node: any) => void,
|
||||||
|
nodeSpecificCallback?: (activeLoraNames: Set<string>) => void
|
||||||
|
): (newMode: number, oldMode: number) => void {
|
||||||
|
return (newMode: number, _oldMode: number) => {
|
||||||
|
const isNodeCurrentlyActive = isNodeActive(newMode);
|
||||||
|
const activeLoraNames = isNodeCurrentlyActive
|
||||||
|
? getActiveLorasFromNodeByType(node)
|
||||||
|
: new Set<string>();
|
||||||
|
|
||||||
|
// Node-specific handling (e.g., Lora Stacker's direct trigger toggle updates)
|
||||||
|
if (nodeSpecificCallback) {
|
||||||
|
nodeSpecificCallback(activeLoraNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always update downstream loaders
|
||||||
|
updateDownstreamLoaders(node);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
import { app } from "../../scripts/app.js";
|
|
||||||
import {
|
|
||||||
getActiveLorasFromNode,
|
|
||||||
updateDownstreamLoaders,
|
|
||||||
chainCallback,
|
|
||||||
} from "./utils.js";
|
|
||||||
|
|
||||||
app.registerExtension({
|
|
||||||
name: "LoraManager.LoraRandomizer",
|
|
||||||
|
|
||||||
async beforeRegisterNodeDef(nodeType, nodeData, app) {
|
|
||||||
if (nodeType.comfyClass === "Lora Randomizer (LoraManager)") {
|
|
||||||
chainCallback(nodeType.prototype, "onNodeCreated", async function () {
|
|
||||||
this.serialize_widgets = true;
|
|
||||||
|
|
||||||
let _mode = this.mode;
|
|
||||||
const self = this;
|
|
||||||
Object.defineProperty(this, 'mode', {
|
|
||||||
get() {
|
|
||||||
return _mode;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
const oldValue = _mode;
|
|
||||||
_mode = value;
|
|
||||||
|
|
||||||
if (self.onModeChange) {
|
|
||||||
self.onModeChange(value, oldValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.onModeChange = function(newMode, oldMode) {
|
|
||||||
const isNodeActive = newMode === 0 || newMode === 3;
|
|
||||||
const activeLoraNames = isNodeActive ? getActiveLorasFromNode(self) : new Set();
|
|
||||||
updateDownstreamLoaders(self);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
@@ -31,34 +31,6 @@ app.registerExtension({
|
|||||||
let isUpdating = false;
|
let isUpdating = false;
|
||||||
let isSyncingInput = false;
|
let isSyncingInput = false;
|
||||||
|
|
||||||
// Mechanism 3: Property descriptor to listen for mode changes
|
|
||||||
const self = this;
|
|
||||||
let _mode = this.mode;
|
|
||||||
Object.defineProperty(this, 'mode', {
|
|
||||||
get() {
|
|
||||||
return _mode;
|
|
||||||
},
|
|
||||||
set(value) {
|
|
||||||
const oldValue = _mode;
|
|
||||||
_mode = value;
|
|
||||||
|
|
||||||
// Trigger mode change handler
|
|
||||||
if (self.onModeChange) {
|
|
||||||
self.onModeChange(value, oldValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Define the mode change handler
|
|
||||||
this.onModeChange = function(newMode, oldMode) {
|
|
||||||
// Update connected trigger word toggle nodes and downstream loader trigger word toggle nodes
|
|
||||||
// when mode changes, similar to when loras change
|
|
||||||
const isNodeActive = newMode === 0 || newMode === 3; // Active when mode is Always (0) or On Trigger (3)
|
|
||||||
const activeLoraNames = isNodeActive ? getActiveLorasFromNode(self) : new Set();
|
|
||||||
updateConnectedTriggerWords(self, activeLoraNames);
|
|
||||||
updateDownstreamLoaders(self);
|
|
||||||
};
|
|
||||||
|
|
||||||
const inputWidget = this.widgets[0];
|
const inputWidget = this.widgets[0];
|
||||||
inputWidget.options.getMaxHeight = () => 100;
|
inputWidget.options.getMaxHeight = () => 100;
|
||||||
this.inputWidget = inputWidget;
|
this.inputWidget = inputWidget;
|
||||||
|
|||||||
@@ -4,6 +4,16 @@ import { AutoComplete } from "./autocomplete.js";
|
|||||||
|
|
||||||
const ROOT_GRAPH_ID = "root";
|
const ROOT_GRAPH_ID = "root";
|
||||||
|
|
||||||
|
export const LORA_PROVIDER_NODE_TYPES = [
|
||||||
|
"Lora Stacker (LoraManager)",
|
||||||
|
"Lora Randomizer (LoraManager)",
|
||||||
|
"Lora Cycler (LoraManager)",
|
||||||
|
];
|
||||||
|
|
||||||
|
export function isLoraProviderNode(comfyClass) {
|
||||||
|
return LORA_PROVIDER_NODE_TYPES.includes(comfyClass);
|
||||||
|
}
|
||||||
|
|
||||||
function isMapLike(collection) {
|
function isMapLike(collection) {
|
||||||
return collection && typeof collection.entries === "function" && typeof collection.values === "function";
|
return collection && typeof collection.entries === "function" && typeof collection.values === "function";
|
||||||
}
|
}
|
||||||
@@ -233,7 +243,7 @@ export function getConnectedInputStackers(node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sourceNode = node.graph?.getNodeById?.(link.origin_id);
|
const sourceNode = node.graph?.getNodeById?.(link.origin_id);
|
||||||
if (sourceNode && (sourceNode.comfyClass === "Lora Stacker (LoraManager)" || sourceNode.comfyClass === "Lora Randomizer (LoraManager)")) {
|
if (sourceNode && isLoraProviderNode(sourceNode.comfyClass)) {
|
||||||
connectedStackers.push(sourceNode);
|
connectedStackers.push(sourceNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,12 +283,22 @@ export function getConnectedTriggerToggleNodes(node) {
|
|||||||
// Extract active lora names from a node's widgets
|
// Extract active lora names from a node's widgets
|
||||||
export function getActiveLorasFromNode(node) {
|
export function getActiveLorasFromNode(node) {
|
||||||
const activeLoraNames = new Set();
|
const activeLoraNames = new Set();
|
||||||
|
|
||||||
|
// Handle Lora Cycler (single LoRA from cycler_config widget)
|
||||||
|
if (node.comfyClass === "Lora Cycler (LoraManager)") {
|
||||||
|
const cyclerWidget = node.widgets?.find(w => w.name === 'cycler_config');
|
||||||
|
if (cyclerWidget?.value?.current_lora_filename) {
|
||||||
|
activeLoraNames.add(cyclerWidget.value.current_lora_filename);
|
||||||
|
}
|
||||||
|
return activeLoraNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle Lora Stacker and Lora Randomizer (lorasWidget)
|
||||||
let lorasWidget = node.lorasWidget;
|
let lorasWidget = node.lorasWidget;
|
||||||
if (!lorasWidget && node.widgets) {
|
if (!lorasWidget && node.widgets) {
|
||||||
lorasWidget = node.widgets.find(w => w.name === 'loras');
|
lorasWidget = node.widgets.find(w => w.name === 'loras');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lorasWidget && lorasWidget.value) {
|
if (lorasWidget && lorasWidget.value) {
|
||||||
lorasWidget.value.forEach(lora => {
|
lorasWidget.value.forEach(lora => {
|
||||||
if (lora.active) {
|
if (lora.active) {
|
||||||
@@ -286,7 +306,7 @@ export function getActiveLorasFromNode(node) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return activeLoraNames;
|
return activeLoraNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -715,12 +735,8 @@ export function updateDownstreamLoaders(startNode, visited = new Set()) {
|
|||||||
collectActiveLorasFromChain(targetNode);
|
collectActiveLorasFromChain(targetNode);
|
||||||
updateConnectedTriggerWords(targetNode, allActiveLoraNames);
|
updateConnectedTriggerWords(targetNode, allActiveLoraNames);
|
||||||
}
|
}
|
||||||
// If target is another Lora Stacker or Lora Randomizer, recursively check its outputs
|
// If target is another LoRA provider node, recursively check its outputs
|
||||||
else if (
|
else if (targetNode && isLoraProviderNode(targetNode.comfyClass)) {
|
||||||
targetNode &&
|
|
||||||
(targetNode.comfyClass === "Lora Stacker (LoraManager)" ||
|
|
||||||
targetNode.comfyClass === "Lora Randomizer (LoraManager)")
|
|
||||||
) {
|
|
||||||
updateDownstreamLoaders(targetNode, visited);
|
updateDownstreamLoaders(targetNode, visited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13225,8 +13225,78 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
const JsonDisplayWidget = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-0f202476"]]);
|
const JsonDisplayWidget = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-0f202476"]]);
|
||||||
|
const LORA_PROVIDER_NODE_TYPES$1 = [
|
||||||
|
"Lora Stacker (LoraManager)",
|
||||||
|
"Lora Randomizer (LoraManager)",
|
||||||
|
"Lora Cycler (LoraManager)"
|
||||||
|
];
|
||||||
|
function getActiveLorasFromNodeByType(node) {
|
||||||
|
const comfyClass = node == null ? void 0 : node.comfyClass;
|
||||||
|
if (comfyClass === "Lora Cycler (LoraManager)") {
|
||||||
|
return extractFromCyclerConfig(node);
|
||||||
|
}
|
||||||
|
return extractFromLorasWidget(node);
|
||||||
|
}
|
||||||
|
function extractFromLorasWidget(node) {
|
||||||
|
var _a;
|
||||||
|
const activeLoraNames = /* @__PURE__ */ new Set();
|
||||||
|
const lorasWidget = node.lorasWidget || ((_a = node.widgets) == null ? void 0 : _a.find((w2) => w2.name === "loras"));
|
||||||
|
if (lorasWidget == null ? void 0 : lorasWidget.value) {
|
||||||
|
lorasWidget.value.forEach((lora) => {
|
||||||
|
if (lora.active) {
|
||||||
|
activeLoraNames.add(lora.name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return activeLoraNames;
|
||||||
|
}
|
||||||
|
function extractFromCyclerConfig(node) {
|
||||||
|
var _a, _b;
|
||||||
|
const activeLoraNames = /* @__PURE__ */ new Set();
|
||||||
|
const cyclerWidget = (_a = node.widgets) == null ? void 0 : _a.find((w2) => w2.name === "cycler_config");
|
||||||
|
if ((_b = cyclerWidget == null ? void 0 : cyclerWidget.value) == null ? void 0 : _b.current_lora_filename) {
|
||||||
|
activeLoraNames.add(cyclerWidget.value.current_lora_filename);
|
||||||
|
}
|
||||||
|
return activeLoraNames;
|
||||||
|
}
|
||||||
|
function isNodeActive(mode) {
|
||||||
|
return mode === void 0 || mode === 0 || mode === 3;
|
||||||
|
}
|
||||||
|
function setupModeChangeHandler(node, onModeChange) {
|
||||||
|
let _mode = node.mode;
|
||||||
|
Object.defineProperty(node, "mode", {
|
||||||
|
get() {
|
||||||
|
return _mode;
|
||||||
|
},
|
||||||
|
set(value) {
|
||||||
|
const oldValue = _mode;
|
||||||
|
_mode = value;
|
||||||
|
if (oldValue !== value) {
|
||||||
|
onModeChange(value, oldValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function createModeChangeCallback(node, updateDownstreamLoaders2, nodeSpecificCallback) {
|
||||||
|
return (newMode, _oldMode) => {
|
||||||
|
const isNodeCurrentlyActive = isNodeActive(newMode);
|
||||||
|
const activeLoraNames = isNodeCurrentlyActive ? getActiveLorasFromNodeByType(node) : /* @__PURE__ */ new Set();
|
||||||
|
if (nodeSpecificCallback) {
|
||||||
|
nodeSpecificCallback(activeLoraNames);
|
||||||
|
}
|
||||||
|
updateDownstreamLoaders2(node);
|
||||||
|
};
|
||||||
|
}
|
||||||
const app = {};
|
const app = {};
|
||||||
const ROOT_GRAPH_ID = "root";
|
const ROOT_GRAPH_ID = "root";
|
||||||
|
const LORA_PROVIDER_NODE_TYPES = [
|
||||||
|
"Lora Stacker (LoraManager)",
|
||||||
|
"Lora Randomizer (LoraManager)",
|
||||||
|
"Lora Cycler (LoraManager)"
|
||||||
|
];
|
||||||
|
function isLoraProviderNode(comfyClass) {
|
||||||
|
return LORA_PROVIDER_NODE_TYPES.includes(comfyClass);
|
||||||
|
}
|
||||||
function isMapLike(collection) {
|
function isMapLike(collection) {
|
||||||
return collection && typeof collection.entries === "function" && typeof collection.values === "function";
|
return collection && typeof collection.entries === "function" && typeof collection.values === "function";
|
||||||
}
|
}
|
||||||
@@ -13278,7 +13348,7 @@ function getConnectedInputStackers(node) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const sourceNode = (_b = (_a = node.graph) == null ? void 0 : _a.getNodeById) == null ? void 0 : _b.call(_a, link.origin_id);
|
const sourceNode = (_b = (_a = node.graph) == null ? void 0 : _a.getNodeById) == null ? void 0 : _b.call(_a, link.origin_id);
|
||||||
if (sourceNode && (sourceNode.comfyClass === "Lora Stacker (LoraManager)" || sourceNode.comfyClass === "Lora Randomizer (LoraManager)")) {
|
if (sourceNode && isLoraProviderNode(sourceNode.comfyClass)) {
|
||||||
connectedStackers.push(sourceNode);
|
connectedStackers.push(sourceNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13308,7 +13378,15 @@ function getConnectedTriggerToggleNodes(node) {
|
|||||||
return connectedNodes;
|
return connectedNodes;
|
||||||
}
|
}
|
||||||
function getActiveLorasFromNode(node) {
|
function getActiveLorasFromNode(node) {
|
||||||
|
var _a, _b;
|
||||||
const activeLoraNames = /* @__PURE__ */ new Set();
|
const activeLoraNames = /* @__PURE__ */ new Set();
|
||||||
|
if (node.comfyClass === "Lora Cycler (LoraManager)") {
|
||||||
|
const cyclerWidget = (_a = node.widgets) == null ? void 0 : _a.find((w2) => w2.name === "cycler_config");
|
||||||
|
if ((_b = cyclerWidget == null ? void 0 : cyclerWidget.value) == null ? void 0 : _b.current_lora_filename) {
|
||||||
|
activeLoraNames.add(cyclerWidget.value.current_lora_filename);
|
||||||
|
}
|
||||||
|
return activeLoraNames;
|
||||||
|
}
|
||||||
let lorasWidget = node.lorasWidget;
|
let lorasWidget = node.lorasWidget;
|
||||||
if (!lorasWidget && node.widgets) {
|
if (!lorasWidget && node.widgets) {
|
||||||
lorasWidget = node.widgets.find((w2) => w2.name === "loras");
|
lorasWidget = node.widgets.find((w2) => w2.name === "loras");
|
||||||
@@ -13331,8 +13409,8 @@ function collectActiveLorasFromChain(node, visited = /* @__PURE__ */ new Set())
|
|||||||
return /* @__PURE__ */ new Set();
|
return /* @__PURE__ */ new Set();
|
||||||
}
|
}
|
||||||
visited.add(nodeKey);
|
visited.add(nodeKey);
|
||||||
const isNodeActive = node.mode === void 0 || node.mode === 0 || node.mode === 3;
|
const isNodeActive2 = node.mode === void 0 || node.mode === 0 || node.mode === 3;
|
||||||
const allActiveLoraNames = isNodeActive ? getActiveLorasFromNode(node) : /* @__PURE__ */ new Set();
|
const allActiveLoraNames = isNodeActive2 ? getActiveLorasFromNode(node) : /* @__PURE__ */ new Set();
|
||||||
const inputStackers = getConnectedInputStackers(node);
|
const inputStackers = getConnectedInputStackers(node);
|
||||||
for (const stacker of inputStackers) {
|
for (const stacker of inputStackers) {
|
||||||
const stackerLoras = collectActiveLorasFromChain(stacker, visited);
|
const stackerLoras = collectActiveLorasFromChain(stacker, visited);
|
||||||
@@ -13383,8 +13461,8 @@ function getPoolConfigFromConnectedNode(node) {
|
|||||||
if (!poolNode) {
|
if (!poolNode) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const isNodeActive = poolNode.mode === void 0 || poolNode.mode === 0 || poolNode.mode === 3;
|
const isNodeActive2 = poolNode.mode === void 0 || poolNode.mode === 0 || poolNode.mode === 3;
|
||||||
if (!isNodeActive) {
|
if (!isNodeActive2) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const poolWidget = (_a = poolNode.widgets) == null ? void 0 : _a.find((w2) => w2.name === "pool_config");
|
const poolWidget = (_a = poolNode.widgets) == null ? void 0 : _a.find((w2) => w2.name === "pool_config");
|
||||||
@@ -13405,7 +13483,7 @@ function updateDownstreamLoaders(startNode, visited = /* @__PURE__ */ new Set())
|
|||||||
if (targetNode && targetNode.comfyClass === "Lora Loader (LoraManager)") {
|
if (targetNode && targetNode.comfyClass === "Lora Loader (LoraManager)") {
|
||||||
const allActiveLoraNames = collectActiveLorasFromChain(targetNode);
|
const allActiveLoraNames = collectActiveLorasFromChain(targetNode);
|
||||||
updateConnectedTriggerWords(targetNode, allActiveLoraNames);
|
updateConnectedTriggerWords(targetNode, allActiveLoraNames);
|
||||||
} else if (targetNode && (targetNode.comfyClass === "Lora Stacker (LoraManager)" || targetNode.comfyClass === "Lora Randomizer (LoraManager)")) {
|
} else if (targetNode && isLoraProviderNode(targetNode.comfyClass)) {
|
||||||
updateDownstreamLoaders(targetNode, visited);
|
updateDownstreamLoaders(targetNode, visited);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13597,10 +13675,14 @@ function createLoraCyclerWidget(node) {
|
|||||||
return internalValue;
|
return internalValue;
|
||||||
},
|
},
|
||||||
setValue(v2) {
|
setValue(v2) {
|
||||||
|
const oldFilename = internalValue == null ? void 0 : internalValue.current_lora_filename;
|
||||||
internalValue = v2;
|
internalValue = v2;
|
||||||
if (typeof widget.onSetValue === "function") {
|
if (typeof widget.onSetValue === "function") {
|
||||||
widget.onSetValue(v2);
|
widget.onSetValue(v2);
|
||||||
}
|
}
|
||||||
|
if (oldFilename !== (v2 == null ? void 0 : v2.current_lora_filename)) {
|
||||||
|
updateDownstreamLoaders(node);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
serialize: true,
|
serialize: true,
|
||||||
getMinHeight() {
|
getMinHeight() {
|
||||||
@@ -13609,7 +13691,11 @@ function createLoraCyclerWidget(node) {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
widget.updateConfig = (v2) => {
|
widget.updateConfig = (v2) => {
|
||||||
|
const oldFilename = internalValue == null ? void 0 : internalValue.current_lora_filename;
|
||||||
internalValue = v2;
|
internalValue = v2;
|
||||||
|
if (oldFilename !== (v2 == null ? void 0 : v2.current_lora_filename)) {
|
||||||
|
updateDownstreamLoaders(node);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
node.getPoolConfig = () => getPoolConfigFromConnectedNode(node);
|
node.getPoolConfig = () => getPoolConfigFromConnectedNode(node);
|
||||||
const vueApp = createApp(LoraCyclerWidget, {
|
const vueApp = createApp(LoraCyclerWidget, {
|
||||||
@@ -13726,8 +13812,19 @@ app$1.registerExtension({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
// Add display-only widget to Debug Metadata node
|
// Add display-only widget to Debug Metadata node
|
||||||
|
// Register mode change handlers for LoRA provider nodes
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
async beforeRegisterNodeDef(nodeType, nodeData) {
|
async beforeRegisterNodeDef(nodeType, nodeData) {
|
||||||
|
const comfyClass = nodeType.comfyClass;
|
||||||
|
if (LORA_PROVIDER_NODE_TYPES$1.includes(comfyClass)) {
|
||||||
|
const originalOnNodeCreated = nodeType.prototype.onNodeCreated;
|
||||||
|
nodeType.prototype.onNodeCreated = function() {
|
||||||
|
originalOnNodeCreated == null ? void 0 : originalOnNodeCreated.apply(this, arguments);
|
||||||
|
const nodeSpecificCallback = comfyClass === "Lora Stacker (LoraManager)" ? (activeLoraNames) => updateConnectedTriggerWords(this, activeLoraNames) : void 0;
|
||||||
|
const onModeChange = createModeChangeCallback(this, updateDownstreamLoaders, nodeSpecificCallback);
|
||||||
|
setupModeChangeHandler(this, onModeChange);
|
||||||
|
};
|
||||||
|
}
|
||||||
if (nodeData.name === "Debug Metadata (LoraManager)") {
|
if (nodeData.name === "Debug Metadata (LoraManager)") {
|
||||||
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
const onNodeCreated = nodeType.prototype.onNodeCreated;
|
||||||
nodeType.prototype.onNodeCreated = function() {
|
nodeType.prototype.onNodeCreated = function() {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user