feat: split frame strength into high/low noise strength per frame

Each frame path now has two strength fields instead of one:
'start frame high strength', 'start frame low strength' (and same
for middle/end). Migration splits old single 'X frame strength' into
both new keys using the same value.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 14:34:03 +02:00
parent 4b40d0f50c
commit c771fa3451
3 changed files with 36 additions and 17 deletions
+11 -4
View File
@@ -96,9 +96,12 @@ def _get_data(name: str, file_name: str, seq: int = Query(default=1)) -> dict[st
result = dict(match)
# Inject strength defaults if not yet saved to JSON
for key, default in (
("start frame strength", 1.0),
("middle frame strength", 1.0),
("end frame strength", 1.0),
("start frame high strength", 1.0),
("start frame low strength", 1.0),
("middle frame high strength", 1.0),
("middle frame low strength", 1.0),
("end frame high strength", 1.0),
("end frame low strength", 1.0),
):
result.setdefault(key, default)
# Computed stem names from frame paths
@@ -133,7 +136,11 @@ def _get_keys(name: str, file_name: str, seq: int = Query(default=1)) -> dict[st
else:
types.append("STRING")
# Injected defaults — always present even if not yet saved to JSON
for key in ("start frame strength", "middle frame strength", "end frame strength"):
for key in (
"start frame high strength", "start frame low strength",
"middle frame high strength", "middle frame low strength",
"end frame high strength", "end frame low strength",
):
if key not in match:
keys.append(key)
types.append("FLOAT")
+12 -10
View File
@@ -317,9 +317,9 @@ def render_batch_processor(state: AppState):
'seed', 'camera', KEY_SEQUENCE_NUMBER,
'frame_to_skip', 'logic index', 'transition', 'vace_length',
'input_a_frames', 'input_b_frames', 'reference switch', 'vace schedule',
'start frame path', 'start frame strength',
'middle frame path', 'middle frame strength',
'end frame path', 'end frame strength',
'start frame path', 'start frame high strength', 'start frame low strength',
'middle frame path', 'middle frame high strength', 'middle frame low strength',
'end frame path', 'end frame high strength', 'end frame low strength',
'video file path',
}
standard_keys.update(lora_keys)
@@ -560,10 +560,10 @@ def _render_sequence_card(i, seq, batch_list, data, file_path, state,
# --- Frame paths (start / middle / end) ---
logic_val = int(seq.get('logic index', 0))
for bit, img_label, img_key, str_key in [
(0, 'Start Frame', 'start frame path', 'start frame strength'),
(1, 'Middle Frame', 'middle frame path', 'middle frame strength'),
(2, 'End Frame', 'end frame path', 'end frame strength'),
for bit, img_label, img_key, hi_key, lo_key in [
(0, 'Start Frame', 'start frame path', 'start frame high strength', 'start frame low strength'),
(1, 'Middle Frame', 'middle frame path', 'middle frame high strength', 'middle frame low strength'),
(2, 'End Frame', 'end frame path', 'end frame high strength', 'end frame low strength'),
]:
ui.label(img_label).classes('text-caption text-weight-bold q-mt-sm')
with ui.row().classes('w-full items-center no-wrap q-mt-xs'):
@@ -581,11 +581,13 @@ def _render_sequence_card(i, seq, batch_list, data, file_path, state,
f'style="width:36px;height:36px;object-fit:cover;'
f'border-radius:4px;cursor:pointer;flex-shrink:0">'
).on('click', img_dlg.open)
str_inp = dict_number('Strength', seq, str_key, default=1.0,
step=0.05, format='%.2f').style(
'width:80px').props('outlined dense')
sw = ui.switch(value=bool((logic_val >> bit) & 1))
frame_switches.append(sw)
with ui.row().classes('w-full no-wrap q-mt-xs q-gutter-xs'):
dict_number('High', seq, hi_key, default=1.0,
step=0.05, format='%.2f').classes('col').props('outlined dense')
dict_number('Low', seq, lo_key, default=1.0,
step=0.05, format='%.2f').classes('col').props('outlined dense')
with splitter.after:
# Mode
+13 -3
View File
@@ -44,11 +44,14 @@ DEFAULTS = {
"reference switch": 1,
"video file path": "",
"start frame path": "",
"start frame strength": 1.0,
"start frame high strength": 1.0,
"start frame low strength": 1.0,
"middle frame path": "",
"middle frame strength": 1.0,
"middle frame high strength": 1.0,
"middle frame low strength": 1.0,
"end frame path": "",
"end frame strength": 1.0,
"end frame high strength": 1.0,
"end frame low strength": 1.0,
# --- LoRAs (name as STRING, strength as FLOAT) ---
"lora 1 high": "",
@@ -173,6 +176,13 @@ def _migrate_key_renames(data: dict) -> None:
item['end frame path'] = item.pop('flf image path')
if 'reference image path' in item and 'start frame path' not in item:
item['start frame path'] = item.pop('reference image path')
# Split old single strength into high+low
for prefix in ('start frame', 'middle frame', 'end frame'):
old_key = f'{prefix} strength'
if old_key in item:
val = item.pop(old_key)
item.setdefault(f'{prefix} high strength', val)
item.setdefault(f'{prefix} low strength', val)
def _migrate_lora_keys(data: dict) -> None: