diff --git a/py/nodes/lora_loader.py b/py/nodes/lora_loader.py index 60c91472..295ca6d3 100644 --- a/py/nodes/lora_loader.py +++ b/py/nodes/lora_loader.py @@ -72,6 +72,7 @@ class LoraManagerLoader: # Add trigger words to collection all_trigger_words.extend(trigger_words) - trigger_words_text = ", ".join(all_trigger_words) if all_trigger_words else "" + # use ',, ' to separate trigger words for group mode + trigger_words_text = ",, ".join(all_trigger_words) if all_trigger_words else "" return (model, clip, trigger_words_text) \ No newline at end of file diff --git a/py/nodes/trigger_word_toggle.py b/py/nodes/trigger_word_toggle.py index 8dda5596..3e934e08 100644 --- a/py/nodes/trigger_word_toggle.py +++ b/py/nodes/trigger_word_toggle.py @@ -10,7 +10,9 @@ class TriggerWordToggle: @classmethod def INPUT_TYPES(cls): return { - "required": {}, + "required": { + "group_mode": ("BOOLEAN", {"default": True}), + }, "optional": { **FlexibleOptionalInputType(any_type), "trigger_words": ("STRING", {"default": "", "defaultInput": True}), diff --git a/web/comfyui/trigger_word_toggle.js b/web/comfyui/trigger_word_toggle.js index 40474c96..5687c238 100644 --- a/web/comfyui/trigger_word_toggle.js +++ b/web/comfyui/trigger_word_toggle.js @@ -2,6 +2,8 @@ import { app } from "../../scripts/app.js"; import { api } from "../../scripts/api.js"; import { addTagsWidget } from "./tags_widget.js"; +const CONVERTED_TYPE = 'converted-widget' + // TriggerWordToggle extension for ComfyUI app.registerExtension({ name: "LoraManager.TriggerWordToggle", @@ -28,13 +30,30 @@ app.registerExtension({ node.tagWidget = result.widget; + // Add hidden widget to store original message + const hiddenWidget = node.addWidget('text', 'orinalMessage', ''); + hiddenWidget.type = CONVERTED_TYPE; + hiddenWidget.hidden = true; + hiddenWidget.computeSize = () => [0, -4]; + // Restore saved value if exists if (node.widgets_values && node.widgets_values.length > 0) { - // 0 is input, 1 is tag widget - const savedValue = node.widgets_values[1]; + // 0 is group mode, 1 is input, 2 is tag widget, 3 is original message + const savedValue = node.widgets_values[2]; if (savedValue) { result.widget.value = savedValue; } + const originalMessage = node.widgets_values[3]; + if (originalMessage) { + hiddenWidget.value = originalMessage; + } + } + + const groupModeWidget = node.widgets[0]; + groupModeWidget.callback = (value) => { + if (node.widgets[3].value) { + this.updateTagsBasedOnMode(node, node.widgets[3].value, value); + } } }); } @@ -48,31 +67,63 @@ app.registerExtension({ return; } + // Store the original message for mode switching + node.widgets[3].value = message; + if (node.tagWidget) { - // Convert comma-separated message to tag object format - if (typeof message === 'string') { - // Get existing tags to preserve active states - const existingTags = node.tagWidget.value || []; - - // Create a map of existing tags and their active states - const existingTagMap = {}; - existingTags.forEach(tag => { - existingTagMap[tag.text] = tag.active; - }); - - // Process the incoming message - const tagArray = message - .split(',') - .map(word => word.trim()) - .filter(word => word) - .map(word => ({ - text: word, - // Keep previous active state if exists, otherwise default to true - active: existingTagMap[word] !== undefined ? existingTagMap[word] : true - })); - - node.tagWidget.value = tagArray; - } + // Parse tags based on current group mode + const groupMode = node.widgets[0] ? node.widgets[0].value : false; + this.updateTagsBasedOnMode(node, message, groupMode); } }, + + // Update tags display based on group mode + updateTagsBasedOnMode(node, message, groupMode) { + if (!node.tagWidget) return; + + const existingTags = node.tagWidget.value || []; + const existingTagMap = {}; + + // Create a map of existing tags and their active states + existingTags.forEach(tag => { + existingTagMap[tag.text] = tag.active; + }); + + let tagArray = []; + + if (groupMode) { + if (message.trim() === '') { + tagArray = []; + } + // Group mode: split by ',,' and treat each group as a single tag + else if (message.includes(',,')) { + const groups = message.split(/,{2,}/); // Match 2 or more consecutive commas + tagArray = groups + .map(group => group.trim()) + .filter(group => group) + .map(group => ({ + text: group, + active: existingTagMap[group] !== undefined ? existingTagMap[group] : true + })); + } else { + // If no ',,' delimiter, treat the entire message as one group + tagArray = [{ + text: message.trim(), + active: existingTagMap[message.trim()] !== undefined ? existingTagMap[message.trim()] : true + }]; + } + } else { + // Normal mode: split by commas and treat each word as a separate tag + tagArray = message + .split(',') + .map(word => word.trim()) + .filter(word => word) + .map(word => ({ + text: word, + active: existingTagMap[word] !== undefined ? existingTagMap[word] : true + })); + } + + node.tagWidget.value = tagArray; + } });