From 707e789f02a0ab5b5c2d60b7041b100fa39b4dd7 Mon Sep 17 00:00:00 2001 From: facok <128763816+facok@users.noreply.github.com> Date: Tue, 17 Mar 2026 05:50:59 +0800 Subject: [PATCH] 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. --- nodes/intervene.py | 37 ++++++++++++++++++++++++++++--------- web/js/tone_preset.js | 5 +++-- 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/nodes/intervene.py b/nodes/intervene.py index baff7e6..3663fad 100644 --- a/nodes/intervene.py +++ b/nodes/intervene.py @@ -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): diff --git a/web/js/tone_preset.js b/web/js/tone_preset.js index f0cbfe7..d6dd76e 100644 --- a/web/js/tone_preset.js +++ b/web/js/tone_preset.js @@ -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 },