both toggle

This commit is contained in:
JJ
2026-02-10 16:33:46 +00:00
parent 8d4c6f6f75
commit 013a962cfd
4 changed files with 82 additions and 14 deletions
+23 -8
View File
@@ -368,7 +368,8 @@ class PowerLoraLoaderV2:
def __init__(self):
self.properties = {
"Show Strengths": "Single Strength" # Single Strength or Separate Model & Clip
"Show Strengths": "Single Strength", # Single Strength or Separate Model & Clip
"output_both": False # Apply all loras to model_low using low strength values
}
@classmethod
@@ -397,10 +398,13 @@ class PowerLoraLoaderV2:
"""Combines functionality from both v1 and v2 loaders."""
# Get show_strengths property
show_strengths = getattr(self, 'Show Strengths', 'Single Strength')
# Check if clip is actually connected (from JavaScript hasClip property)
has_clip = getattr(self, 'hasClip', clip is not None)
# Check if output_both is enabled (from widget value or property)
output_both = kwargs.get('output_both', self.properties.get('output_both', False))
# Initialize lists for WanVideo format
loras_list = []
low_loras_list = []
@@ -438,7 +442,6 @@ class PowerLoraLoaderV2:
if os.path.exists(lora_path):
# Extract just the filename for consistency with the rest of the code
lora_filename = os.path.basename(lora_name.replace('\\', '/'))
print(f"[PowerLoraLoaderV2] Found LoRA at full path: '{lora_path}'")
else:
print(f"[PowerLoraLoaderV2] LoRA file '{lora_name}' not found in loras folder.")
continue
@@ -499,6 +502,23 @@ class PowerLoraLoaderV2:
loras_list.append(lora_entry)
# Handle output_both mode - apply all loras to model_low using low_strength
if output_both:
if model_low is not None:
low_strength = value.get('low_strength', strength_model)
if low_strength is None:
low_strength = 0.0
try:
if not has_clip:
model_low, _ = LoraLoader().load_lora(model_low, None, lora_filename, low_strength, 0)
else:
model_low, clip = LoraLoader().load_lora(model_low, clip, lora_filename, low_strength, 0)
low_loras_summary.append((low_strength, f"{lora_filename} (output_both)"))
except Exception as e:
print(f"[PowerLoraLoaderV2] Error applying LoRA to model_low (output_both): {e}")
else:
pass # model_low is None, cannot apply OUTPUT_BOTH
# Check if JavaScript detected special mode flags
use_for_both = value.get('use_for_both', False)
low_only = value.get('low_only', False)
@@ -511,12 +531,10 @@ class PowerLoraLoaderV2:
# Handle different LoRA states for PowerLoraLoaderV2
if high_only:
# "High only" mode - apply to main model only (same as default but with visual indicator)
print(f"[PowerLoraLoaderV2] Using LoRA '{lora_filename}' for HIGH model only")
high_loras_summary.append((strength_model, f"{lora_filename} (high only)"))
elif low_only:
# "Low only" mode - apply to model_low only
print(f"[PowerLoraLoaderV2] Using LoRA '{lora_filename}' for LOW model only")
# Apply LoRA to model_low if it exists
if model_low is not None:
try:
@@ -531,7 +549,6 @@ class PowerLoraLoaderV2:
elif use_for_both:
# "Enable for both" mode - apply to both main and model_low
print(f"[PowerLoraLoaderV2] Using LoRA '{lora_filename}' for both HIGH and LOW models")
high_loras_summary.append((strength_model, f"{lora_filename} (both)"))
# Apply LoRA to model_low if it exists
@@ -581,8 +598,6 @@ class PowerLoraLoaderV2:
else:
# Clip provided, apply to model_low with clip
model_low, _ = LoraLoader().load_lora(model_low, clip, low_lora_path, low_strength, strength_clip if strength_clip is not None else 0)
print(f"[PowerLoraLoaderV2] Applied low variant LoRA '{low_variant_name}' (strength: {low_strength}) to model_low")
except Exception as e:
print(f"[PowerLoraLoaderV2] Error applying low variant LoRA '{low_variant_name}' to model_low: {e}")
-5
View File
@@ -434,12 +434,10 @@ async def api_save_lora_preview_image(request):
base_dir = folder_paths.get_folder_paths('checkpoints')[0]
# Use _power_preview subdirectory for model previews
power_preview_dir = os.path.join(base_dir, '_power_preview')
print(f"[Preview Image Debug] MODEL: Using directory {power_preview_dir}")
else:
# For LoRAs, use loras directory
base_dir = folder_paths.get_folder_paths('loras')[0]
power_preview_dir = os.path.join(base_dir, '_power_preview')
print(f"[Preview Image Debug] LORA: Using directory {power_preview_dir}")
if lora_path:
save_dir = os.path.join(power_preview_dir, lora_path)
@@ -448,13 +446,10 @@ async def api_save_lora_preview_image(request):
# Ensure directory exists
os.makedirs(save_dir, exist_ok=True)
print(f"[Preview Image Debug] Directory ensured: {save_dir}")
print(f"[Preview Image Debug] Directory exists check: {os.path.exists(save_dir)}")
# Construct save path with optional suffix
filename = f"{lora_name}{suffix}.jpg"
save_path = os.path.join(save_dir, filename)
print(f"[Preview Image Debug] Saving image to: {save_path}")
# Read image data
image_data = image_file.file.read()
@@ -146,6 +146,7 @@ app.registerExtension({
this.hasClip = false; // Initialize clip connection state
this.properties = this.properties || {};
this.properties['Show Strengths'] = "Single Strength";
this.properties['output_both'] = false;
this.addNonLoraWidgets();
@@ -221,6 +222,12 @@ app.registerExtension({
}
}
}
// Sync output_both property to widget
const outputBothWidget = this.widgets.find(w => w.name === "output_both");
if (outputBothWidget && this.properties.output_both !== undefined) {
outputBothWidget.value = this.properties.output_both;
}
};
nodeType.prototype.addNewLoraWidget = function () {
@@ -253,6 +260,12 @@ app.registerExtension({
{ serialize: true });
uiStateWidget.type = "hidden";
// Keep serialize: true to ensure UI state is saved in workflow JSON
// Add hidden widget for output_both toggle state
const outputBothValue = this.properties.output_both || false;
const outputBothWidget = this.addWidget("boolean", "output_both", outputBothValue, () => {},
{ serialize: true });
outputBothWidget.type = "hidden";
};
nodeType.prototype.allLorasState = function() {
+46 -1
View File
@@ -252,6 +252,7 @@ export class StrengthCopyWidget extends RgthreeBaseWidget {
super("StrengthCopyWidget");
this.value = {};
this.hitAreas = {
output_both_toggle: { bounds: [0, 0] },
high_to_low_button: { bounds: [0, 0] },
low_to_high_button: { bounds: [0, 0] },
};
@@ -260,19 +261,39 @@ export class StrengthCopyWidget extends RgthreeBaseWidget {
}
draw(ctx, node, w, posY, height) {
// Ensure property exists (off by default)
if (!node.properties) node.properties = {};
if (node.properties['output_both'] === undefined) node.properties['output_both'] = false;
// Constants
const margin = 20;
const buttonWidth = 25;
const buttonHeight = height;
const buttonSpacing = 36;
const rightOffset = 25;
const innerMargin = 8;
// Calculated values
const midY = posY + height * 0.5;
const totalButtonsWidth = (buttonWidth * 2) + buttonSpacing;
const rightX = w - margin - totalButtonsWidth - rightOffset;
ctx.save();
ctx.textAlign = "left";
ctx.textBaseline = "middle";
ctx.fillStyle = LiteGraph.WIDGET_TEXT_COLOR;
// Draw "Output both" toggle
const toggleSpacing = 15; // Extra spacing between toggle and buttons
let posX = w - margin - totalButtonsWidth - rightOffset - toggleSpacing;
const outputBothValue = node.properties['output_both'] || false;
// Draw label and toggle from right to left
const toggleBounds = drawTogglePart(ctx, [posX - height * 1.5, posY], height, outputBothValue);
this.hitAreas['output_both_toggle'].bounds = toggleBounds;
const labelText = "Use loras on both";
ctx.fillText(labelText, posX - height * 1.5 - ctx.measureText(labelText).width - innerMargin, midY);
// Adjust rightX for buttons (they stay in same position)
const rightX = w - margin - totalButtonsWidth - rightOffset;
// Draw ">" button (high to low)
const highToLowX = rightX;
@@ -288,6 +309,21 @@ export class StrengthCopyWidget extends RgthreeBaseWidget {
}
onMouseDown(event, pos, node) {
// Ensure property exists
if (!node.properties) node.properties = {};
if (node.properties['output_both'] === undefined) node.properties['output_both'] = false;
if (this.clickWasWithinBounds(pos, this.hitAreas.output_both_toggle.bounds)) {
node.properties['output_both'] = !node.properties['output_both'];
// Also sync to hidden widget for Python to read
const outputBothWidget = node.widgets.find(w => w.name === "output_both");
if (outputBothWidget) {
outputBothWidget.value = node.properties['output_both'];
}
this.cancelMouseDown();
node.setDirtyCanvas(true, true);
return true;
}
if (this.clickWasWithinBounds(pos, this.hitAreas.high_to_low_button.bounds)) {
this.highToLowPressed = true;
node.setDirtyCanvas(true, true);
@@ -339,6 +375,15 @@ export class StrengthCopyWidget extends RgthreeBaseWidget {
}
}
serializeValue(node, index) {
// Ensure output_both property exists and is synchronized
if (!node.properties) node.properties = {};
if (node.properties['output_both'] === undefined) node.properties['output_both'] = false;
// Return the value to ensure it's serialized
node.properties['output_both'] = node.properties['output_both'] || false;
return {};
}
computeSize(width) {
return [width, LiteGraph.NODE_WIDGET_HEIGHT];
}