Add server-side preset fallback for headless/batch execution

Frontend JS syncs preset values into sliders on user interaction,
but headless runners (e.g. Lumi-Batcher) skip the frontend entirely.
When a preset is selected but all sliders are still at defaults,
execute() now applies the preset values server-side as a fallback.
This commit is contained in:
facok
2026-03-17 05:50:59 +08:00
parent 98bd528bb4
commit 707e789f02
2 changed files with 31 additions and 11 deletions
+28 -9
View File
@@ -447,12 +447,22 @@ def _build_tone_fn(lcs_data, contrast, brightness, saturation, color_temperature
return post_cfg_fn
# Preset names for the combo widget. Actual values live in web/js/tone_preset.js
# which syncs them into the slider widgets on the frontend.
TONE_PRESET_NAMES = [
"Custom", "Base", "Cinematic", "HDR", "Vivid", "Dramatic",
"Low Key", "High Key", "Warm", "Cool", "Desaturated",
]
# Preset definitions. Frontend JS (web/js/tone_preset.js) syncs these into
# sliders on user interaction. The Python-side copy serves as fallback for
# headless / batch execution where frontend JS does not run.
TONE_PRESETS = {
"Custom": None,
"Base": {"contrast": 1.0, "brightness": 0.0, "saturation": 1.0, "color_temperature": 0.0},
"Cinematic": {"contrast": 1.20, "brightness": -0.05, "saturation": 0.90, "color_temperature": 0.05},
"HDR": {"contrast": 1.40, "brightness": 0.0, "saturation": 1.20, "color_temperature": 0.0},
"Vivid": {"contrast": 1.10, "brightness": 0.0, "saturation": 1.50, "color_temperature": 0.0},
"Dramatic": {"contrast": 1.50, "brightness": -0.10, "saturation": 0.85, "color_temperature": 0.0},
"Low Key": {"contrast": 1.30, "brightness": -0.20, "saturation": 0.80, "color_temperature": 0.0},
"High Key": {"contrast": 0.80, "brightness": 0.20, "saturation": 0.90, "color_temperature": 0.0},
"Warm": {"contrast": 1.0, "brightness": 0.0, "saturation": 1.0, "color_temperature": 0.15},
"Cool": {"contrast": 1.0, "brightness": 0.0, "saturation": 1.0, "color_temperature": -0.15},
"Desaturated": {"contrast": 1.0, "brightness": 0.0, "saturation": 0.40, "color_temperature": 0.0},
}
class LCSToneAdjust(io.ComfyNode):
@@ -477,7 +487,7 @@ class LCSToneAdjust(io.ComfyNode):
inputs=[
io.Model.Input("model"),
LCS_DATA.Input("lcs_data", tooltip="Calibration data from LCSCalibrate or LCSLoadData"),
io.Combo.Input("preset", options=TONE_PRESET_NAMES, default="Custom",
io.Combo.Input("preset", options=list(TONE_PRESETS.keys()), default="Custom",
tooltip="Select a tonal preset or Custom to use the sliders below"),
io.Float.Input("contrast", default=1.0, min=0.0, max=3.0, step=0.05,
tooltip="Lightness contrast multiplier (>1 = more contrast, <1 = less, 1 = no change)"),
@@ -504,9 +514,18 @@ class LCSToneAdjust(io.ComfyNode):
color_temperature, start_step, end_step, mask=None) -> io.NodeOutput:
"""Clone model, attach LCS tone adjustment hook. Returns patched MODEL.
The preset combo sets slider values via frontend JS; execute() always
uses the actual slider values so the user can tweak after selecting a preset.
Frontend JS syncs preset values into sliders on user interaction.
For headless/batch execution (no frontend), if a preset is selected
but sliders are still at defaults, apply the preset values server-side.
"""
# Headless fallback: preset selected but sliders untouched → apply preset
p = TONE_PRESETS.get(preset)
if p is not None and _is_default_tone(contrast, brightness, saturation, color_temperature):
contrast = p["contrast"]
brightness = p["brightness"]
saturation = p["saturation"]
color_temperature = p["color_temperature"]
m = model.clone()
# Skip hook entirely when all parameters are at default (true no-op)
if not _is_default_tone(contrast, brightness, saturation, color_temperature):
+3 -2
View File
@@ -1,7 +1,8 @@
import { app } from "../../../scripts/app.js";
// Preset values — the single source of truth for preset parameters.
// TONE_PRESET_NAMES in nodes/intervene.py must list matching keys.
// Preset values — must match TONE_PRESETS in nodes/intervene.py.
// Frontend syncs these into sliders on user interaction; Python has
// a copy as fallback for headless/batch execution without frontend.
const TONE_PRESETS = {
"Base": { contrast: 1.0, brightness: 0.0, saturation: 1.0, color_temperature: 0.0 },
"Cinematic": { contrast: 1.20, brightness: -0.05, saturation: 0.90, color_temperature: 0.05 },