Spaces:
Running on Zero
Running on Zero
Commit ·
c45a944
1
Parent(s): d2864d0
Fix fireRegen: use correct prototype for textarea native setter
Browse files
app.py
CHANGED
|
@@ -1397,11 +1397,16 @@ def _make_output_slots(tab_prefix: str) -> tuple:
|
|
| 1397 |
"""Build MAX_SLOTS output groups for one tab.
|
| 1398 |
|
| 1399 |
Each slot has: video, waveform HTML, hidden regen trigger textbox,
|
| 1400 |
-
|
| 1401 |
-
|
| 1402 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1403 |
"""
|
| 1404 |
-
grps, vids, waveforms, regen_triggers, seg_states = [], [], [], [], []
|
| 1405 |
for i in range(MAX_SLOTS):
|
| 1406 |
with gr.Group(visible=(i == 0)) as g:
|
| 1407 |
slot_id = f"{tab_prefix}_{i}"
|
|
@@ -1409,11 +1414,7 @@ def _make_output_slots(tab_prefix: str) -> tuple:
|
|
| 1409 |
waveforms.append(gr.HTML(
|
| 1410 |
value="<p style='color:#888;font-size:12px'>Generate audio to see waveform.</p>",
|
| 1411 |
))
|
| 1412 |
-
# Regen trigger:
|
| 1413 |
-
# Gradio 5 SSR omits visible=False components from the DOM entirely,
|
| 1414 |
-
# so getElementById() returns null and JS can never fire the event.
|
| 1415 |
-
# By keeping it visible=True but hiding with CSS (elem_classes),
|
| 1416 |
-
# the input element exists in the DOM and JS can write to it.
|
| 1417 |
regen_triggers.append(gr.Textbox(
|
| 1418 |
value="",
|
| 1419 |
elem_id=f"regen_trigger_{slot_id}",
|
|
@@ -1421,19 +1422,23 @@ def _make_output_slots(tab_prefix: str) -> tuple:
|
|
| 1421 |
label="",
|
| 1422 |
show_label=False,
|
| 1423 |
))
|
| 1424 |
-
#
|
| 1425 |
-
# and embed it in the trigger value (avoids having this component in
|
| 1426 |
-
# both inputs AND outputs of the same .change() handler, which causes
|
| 1427 |
-
# Gradio 5 SSR "Too many arguments" validation errors).
|
| 1428 |
seg_states.append(gr.Textbox(
|
| 1429 |
value="",
|
| 1430 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1431 |
elem_classes=["wf-hidden-input"],
|
| 1432 |
label="",
|
| 1433 |
show_label=False,
|
| 1434 |
))
|
| 1435 |
grps.append(g)
|
| 1436 |
-
return grps, vids, waveforms, regen_triggers, seg_states
|
| 1437 |
|
| 1438 |
|
| 1439 |
def _unpack_outputs(flat: list, n: int, tab_prefix: str) -> list:
|
|
@@ -1555,33 +1560,27 @@ _GLOBAL_JS = """
|
|
| 1555 |
const input = el.querySelector('input, textarea');
|
| 1556 |
if (!input) { console.warn('[fireRegen] no input inside regen_trigger:', slot_id); return; }
|
| 1557 |
|
| 1558 |
-
//
|
| 1559 |
-
//
|
| 1560 |
-
//
|
| 1561 |
-
//
|
| 1562 |
-
|
| 1563 |
-
|
| 1564 |
-
|
| 1565 |
-
|
| 1566 |
-
|
| 1567 |
-
return;
|
| 1568 |
-
}
|
| 1569 |
-
|
| 1570 |
-
// Use native setter to bypass React's controlled-input tracking.
|
| 1571 |
-
// We do NOT clear to '' first — that would fire a spurious .change() event
|
| 1572 |
-
// which (as a generator function) causes an SSE stream error that blocks
|
| 1573 |
-
// the real call. Instead we use a timestamp suffix to ensure uniqueness
|
| 1574 |
-
// so repeat clicks on the same segment always look like a new value.
|
| 1575 |
-
const desc = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')
|
| 1576 |
-
|| Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value');
|
| 1577 |
function setNative(val) {
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1578 |
if (desc && desc.set) desc.set.call(input, val);
|
| 1579 |
else input.value = val;
|
| 1580 |
input.dispatchEvent(new Event('input', {bubbles: true}));
|
| 1581 |
input.dispatchEvent(new Event('change', {bubbles: true}));
|
| 1582 |
}
|
| 1583 |
-
// Encode: "slot_id|seg_idx|
|
| 1584 |
-
const triggerVal = slot_id + '|' + idx + '|' + Date.now()
|
| 1585 |
setNative(triggerVal);
|
| 1586 |
console.log('[fireRegen] fired trigger for', slot_id, 'seg', idx);
|
| 1587 |
|
|
@@ -1644,7 +1643,8 @@ with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) a
|
|
| 1644 |
with gr.Column():
|
| 1645 |
(taro_slot_grps, taro_slot_vids,
|
| 1646 |
taro_slot_waves, taro_slot_rtrigs,
|
| 1647 |
-
taro_slot_states
|
|
|
|
| 1648 |
|
| 1649 |
for trigger in [taro_video, taro_steps, taro_cf_dur]:
|
| 1650 |
trigger.change(
|
|
@@ -1681,24 +1681,30 @@ with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) a
|
|
| 1681 |
outputs=taro_slot_grps,
|
| 1682 |
))
|
| 1683 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1684 |
# Per-slot regen trigger wiring for TARO
|
| 1685 |
for _i, _rtrig in enumerate(taro_slot_rtrigs):
|
| 1686 |
_slot_id = f"taro_{_i}"
|
| 1687 |
print(f"[startup] registering regen handler for slot {_slot_id}")
|
| 1688 |
def _make_taro_regen(_si, _sid):
|
| 1689 |
-
def _do(trigger_val, video, seed, cfg, steps, mode, cf_dur, cf_db):
|
| 1690 |
-
print(f"[regen TARO]
|
| 1691 |
if not trigger_val:
|
| 1692 |
print(f"[regen TARO] early-exit: trigger_val empty")
|
| 1693 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1694 |
-
|
| 1695 |
-
|
| 1696 |
-
|
| 1697 |
-
|
|
|
|
|
|
|
|
|
|
| 1698 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1699 |
-
seg_idx
|
| 1700 |
-
|
| 1701 |
-
print(f"[regen TARO] slot={_sid} seg_idx={seg_idx} state_json_len={len(state_json)}")
|
| 1702 |
lock = _get_slot_lock(_sid)
|
| 1703 |
with lock:
|
| 1704 |
print(f"[regen TARO] slot={_sid} seg_idx={seg_idx} — lock acquired, showing spinner")
|
|
@@ -1723,7 +1729,7 @@ with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) a
|
|
| 1723 |
_rtrig.change(
|
| 1724 |
fn=_make_taro_regen(_i, _slot_id),
|
| 1725 |
inputs=[_rtrig, taro_video, taro_seed, taro_cfg, taro_steps,
|
| 1726 |
-
taro_mode, taro_cf_dur, taro_cf_db],
|
| 1727 |
outputs=[taro_slot_vids[_i], taro_slot_waves[_i], taro_slot_states[_i]],
|
| 1728 |
)
|
| 1729 |
|
|
@@ -1747,7 +1753,8 @@ with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) a
|
|
| 1747 |
with gr.Column():
|
| 1748 |
(mma_slot_grps, mma_slot_vids,
|
| 1749 |
mma_slot_waves, mma_slot_rtrigs,
|
| 1750 |
-
mma_slot_states
|
|
|
|
| 1751 |
|
| 1752 |
mma_samples.change(
|
| 1753 |
fn=_update_slot_visibility,
|
|
@@ -1775,22 +1782,27 @@ with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) a
|
|
| 1775 |
outputs=mma_slot_grps,
|
| 1776 |
))
|
| 1777 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1778 |
for _i, _rtrig in enumerate(mma_slot_rtrigs):
|
| 1779 |
_slot_id = f"mma_{_i}"
|
| 1780 |
def _make_mma_regen(_si, _sid):
|
| 1781 |
-
def _do(trigger_val, video, prompt, neg, seed, cfg, steps, cf_dur, cf_db):
|
| 1782 |
-
print(f"[regen MMA]
|
| 1783 |
if not trigger_val:
|
| 1784 |
print(f"[regen MMA] early-exit: trigger_val empty")
|
| 1785 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1786 |
-
|
| 1787 |
-
|
| 1788 |
-
if len(parts) != 4 or parts[0] != _sid:
|
| 1789 |
-
print(f"[regen MMA] early-exit: parts={parts[:2]} expected slot={_sid!r}")
|
| 1790 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1791 |
-
|
| 1792 |
-
|
| 1793 |
-
|
|
|
|
|
|
|
|
|
|
| 1794 |
lock = _get_slot_lock(_sid)
|
| 1795 |
with lock:
|
| 1796 |
print(f"[regen MMA] slot={_sid} seg_idx={seg_idx} — lock acquired, showing spinner")
|
|
@@ -1815,7 +1827,7 @@ with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) a
|
|
| 1815 |
_rtrig.change(
|
| 1816 |
fn=_make_mma_regen(_i, _slot_id),
|
| 1817 |
inputs=[_rtrig, mma_video, mma_prompt, mma_neg, mma_seed,
|
| 1818 |
-
mma_cfg, mma_steps, mma_cf_dur, mma_cf_db],
|
| 1819 |
outputs=[mma_slot_vids[_i], mma_slot_waves[_i], mma_slot_states[_i]],
|
| 1820 |
)
|
| 1821 |
|
|
@@ -1840,7 +1852,8 @@ with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) a
|
|
| 1840 |
with gr.Column():
|
| 1841 |
(hf_slot_grps, hf_slot_vids,
|
| 1842 |
hf_slot_waves, hf_slot_rtrigs,
|
| 1843 |
-
hf_slot_states
|
|
|
|
| 1844 |
|
| 1845 |
hf_samples.change(
|
| 1846 |
fn=_update_slot_visibility,
|
|
@@ -1868,22 +1881,27 @@ with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) a
|
|
| 1868 |
outputs=hf_slot_grps,
|
| 1869 |
))
|
| 1870 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1871 |
for _i, _rtrig in enumerate(hf_slot_rtrigs):
|
| 1872 |
_slot_id = f"hf_{_i}"
|
| 1873 |
def _make_hf_regen(_si, _sid):
|
| 1874 |
-
def _do(trigger_val, video, prompt, neg, seed, guidance, steps, size, cf_dur, cf_db):
|
| 1875 |
-
print(f"[regen HF]
|
| 1876 |
if not trigger_val:
|
| 1877 |
print(f"[regen HF] early-exit: trigger_val empty")
|
| 1878 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1879 |
-
|
| 1880 |
-
|
| 1881 |
-
|
| 1882 |
-
|
|
|
|
|
|
|
| 1883 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1884 |
-
seg_idx
|
| 1885 |
-
|
| 1886 |
-
print(f"[regen HF] slot={_sid} seg_idx={seg_idx} state_json_len={len(state_json)}")
|
| 1887 |
lock = _get_slot_lock(_sid)
|
| 1888 |
with lock:
|
| 1889 |
print(f"[regen HF] slot={_sid} seg_idx={seg_idx} — lock acquired, showing spinner")
|
|
@@ -1908,7 +1926,7 @@ with gr.Blocks(title="Generate Audio for Video", css=_SLOT_CSS, js=_GLOBAL_JS) a
|
|
| 1908 |
_rtrig.change(
|
| 1909 |
fn=_make_hf_regen(_i, _slot_id),
|
| 1910 |
inputs=[_rtrig, hf_video, hf_prompt, hf_neg, hf_seed,
|
| 1911 |
-
hf_guidance, hf_steps, hf_size, hf_cf_dur, hf_cf_db],
|
| 1912 |
outputs=[hf_slot_vids[_i], hf_slot_waves[_i], hf_slot_states[_i]],
|
| 1913 |
)
|
| 1914 |
|
|
|
|
| 1397 |
"""Build MAX_SLOTS output groups for one tab.
|
| 1398 |
|
| 1399 |
Each slot has: video, waveform HTML, hidden regen trigger textbox,
|
| 1400 |
+
and TWO state textboxes:
|
| 1401 |
+
- seg_states (write): written by main gen + regen; also an output
|
| 1402 |
+
- seg_state_reads (read): mirrors seg_states via .change() relay;
|
| 1403 |
+
used as input-only for regen handlers so that
|
| 1404 |
+
no component ever appears in BOTH inputs AND
|
| 1405 |
+
outputs of the same event (which causes Gradio
|
| 1406 |
+
5 "Too many arguments" even with SSR disabled).
|
| 1407 |
+
Returns (grps, vids, waveforms, regen_triggers, seg_states, seg_state_reads).
|
| 1408 |
"""
|
| 1409 |
+
grps, vids, waveforms, regen_triggers, seg_states, seg_state_reads = [], [], [], [], [], []
|
| 1410 |
for i in range(MAX_SLOTS):
|
| 1411 |
with gr.Group(visible=(i == 0)) as g:
|
| 1412 |
slot_id = f"{tab_prefix}_{i}"
|
|
|
|
| 1414 |
waveforms.append(gr.HTML(
|
| 1415 |
value="<p style='color:#888;font-size:12px'>Generate audio to see waveform.</p>",
|
| 1416 |
))
|
| 1417 |
+
# Regen trigger: CSS-hidden so JS can find and write to it.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1418 |
regen_triggers.append(gr.Textbox(
|
| 1419 |
value="",
|
| 1420 |
elem_id=f"regen_trigger_{slot_id}",
|
|
|
|
| 1422 |
label="",
|
| 1423 |
show_label=False,
|
| 1424 |
))
|
| 1425 |
+
# Write-only state: updated by main gen and regen outputs.
|
|
|
|
|
|
|
|
|
|
| 1426 |
seg_states.append(gr.Textbox(
|
| 1427 |
value="",
|
| 1428 |
+
elem_classes=["wf-hidden-input"],
|
| 1429 |
+
label="",
|
| 1430 |
+
show_label=False,
|
| 1431 |
+
))
|
| 1432 |
+
# Read-only mirror: fed into regen handler inputs only.
|
| 1433 |
+
# Stays in sync via a .change() relay wired after slot creation.
|
| 1434 |
+
seg_state_reads.append(gr.Textbox(
|
| 1435 |
+
value="",
|
| 1436 |
elem_classes=["wf-hidden-input"],
|
| 1437 |
label="",
|
| 1438 |
show_label=False,
|
| 1439 |
))
|
| 1440 |
grps.append(g)
|
| 1441 |
+
return grps, vids, waveforms, regen_triggers, seg_states, seg_state_reads
|
| 1442 |
|
| 1443 |
|
| 1444 |
def _unpack_outputs(flat: list, n: int, tab_prefix: str) -> list:
|
|
|
|
| 1560 |
const input = el.querySelector('input, textarea');
|
| 1561 |
if (!input) { console.warn('[fireRegen] no input inside regen_trigger:', slot_id); return; }
|
| 1562 |
|
| 1563 |
+
// Use native setter to bypass Svelte's controlled-input tracking.
|
| 1564 |
+
// Timestamp suffix ensures repeat clicks on the same segment always
|
| 1565 |
+
// produce a new value so Svelte's change detection always fires.
|
| 1566 |
+
// State JSON is passed via a separate Gradio input (seg_state_read),
|
| 1567 |
+
// not embedded in the trigger string — Gradio's own state is reliable,
|
| 1568 |
+
// whereas reading the DOM input.value returns '' for Svelte-controlled inputs.
|
| 1569 |
+
// IMPORTANT: Gradio 5 renders Textbox as <textarea>, NOT <input>.
|
| 1570 |
+
// Must use HTMLTextAreaElement.prototype setter — using HTMLInputElement.prototype
|
| 1571 |
+
// on a textarea causes "TypeError: Illegal invocation" and silently aborts.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1572 |
function setNative(val) {
|
| 1573 |
+
const proto = input.tagName === 'TEXTAREA'
|
| 1574 |
+
? HTMLTextAreaElement.prototype
|
| 1575 |
+
: HTMLInputElement.prototype;
|
| 1576 |
+
const desc = Object.getOwnPropertyDescriptor(proto, 'value');
|
| 1577 |
if (desc && desc.set) desc.set.call(input, val);
|
| 1578 |
else input.value = val;
|
| 1579 |
input.dispatchEvent(new Event('input', {bubbles: true}));
|
| 1580 |
input.dispatchEvent(new Event('change', {bubbles: true}));
|
| 1581 |
}
|
| 1582 |
+
// Encode: "slot_id|seg_idx|timestamp"
|
| 1583 |
+
const triggerVal = slot_id + '|' + idx + '|' + Date.now();
|
| 1584 |
setNative(triggerVal);
|
| 1585 |
console.log('[fireRegen] fired trigger for', slot_id, 'seg', idx);
|
| 1586 |
|
|
|
|
| 1643 |
with gr.Column():
|
| 1644 |
(taro_slot_grps, taro_slot_vids,
|
| 1645 |
taro_slot_waves, taro_slot_rtrigs,
|
| 1646 |
+
taro_slot_states,
|
| 1647 |
+
taro_slot_state_reads) = _make_output_slots("taro")
|
| 1648 |
|
| 1649 |
for trigger in [taro_video, taro_steps, taro_cf_dur]:
|
| 1650 |
trigger.change(
|
|
|
|
| 1681 |
outputs=taro_slot_grps,
|
| 1682 |
))
|
| 1683 |
|
| 1684 |
+
# Relay: keep seg_state_reads in sync with seg_states (write→read mirror)
|
| 1685 |
+
for _st, _str in zip(taro_slot_states, taro_slot_state_reads):
|
| 1686 |
+
_st.change(fn=lambda v: v, inputs=[_st], outputs=[_str])
|
| 1687 |
+
|
| 1688 |
# Per-slot regen trigger wiring for TARO
|
| 1689 |
for _i, _rtrig in enumerate(taro_slot_rtrigs):
|
| 1690 |
_slot_id = f"taro_{_i}"
|
| 1691 |
print(f"[startup] registering regen handler for slot {_slot_id}")
|
| 1692 |
def _make_taro_regen(_si, _sid):
|
| 1693 |
+
def _do(trigger_val, video, seed, cfg, steps, mode, cf_dur, cf_db, state_json):
|
| 1694 |
+
print(f"[regen TARO] trigger_val={trigger_val!r} state_json_len={len(state_json) if state_json else 0}")
|
| 1695 |
if not trigger_val:
|
| 1696 |
print(f"[regen TARO] early-exit: trigger_val empty")
|
| 1697 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1698 |
+
if not state_json:
|
| 1699 |
+
print(f"[regen TARO] early-exit: state_json empty")
|
| 1700 |
+
yield gr.update(), gr.update(), gr.update(); return
|
| 1701 |
+
# Trigger format: "slot_id|seg_idx|timestamp"
|
| 1702 |
+
parts = trigger_val.split("|", 2)
|
| 1703 |
+
if len(parts) < 2 or parts[0] != _sid:
|
| 1704 |
+
print(f"[regen TARO] early-exit: parts[0]={parts[0]!r} expected={_sid!r}")
|
| 1705 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1706 |
+
seg_idx = int(parts[1])
|
| 1707 |
+
print(f"[regen TARO] slot={_sid} seg_idx={seg_idx} — acquiring lock")
|
|
|
|
| 1708 |
lock = _get_slot_lock(_sid)
|
| 1709 |
with lock:
|
| 1710 |
print(f"[regen TARO] slot={_sid} seg_idx={seg_idx} — lock acquired, showing spinner")
|
|
|
|
| 1729 |
_rtrig.change(
|
| 1730 |
fn=_make_taro_regen(_i, _slot_id),
|
| 1731 |
inputs=[_rtrig, taro_video, taro_seed, taro_cfg, taro_steps,
|
| 1732 |
+
taro_mode, taro_cf_dur, taro_cf_db, taro_slot_state_reads[_i]],
|
| 1733 |
outputs=[taro_slot_vids[_i], taro_slot_waves[_i], taro_slot_states[_i]],
|
| 1734 |
)
|
| 1735 |
|
|
|
|
| 1753 |
with gr.Column():
|
| 1754 |
(mma_slot_grps, mma_slot_vids,
|
| 1755 |
mma_slot_waves, mma_slot_rtrigs,
|
| 1756 |
+
mma_slot_states,
|
| 1757 |
+
mma_slot_state_reads) = _make_output_slots("mma")
|
| 1758 |
|
| 1759 |
mma_samples.change(
|
| 1760 |
fn=_update_slot_visibility,
|
|
|
|
| 1782 |
outputs=mma_slot_grps,
|
| 1783 |
))
|
| 1784 |
|
| 1785 |
+
# Relay: keep mma_slot_state_reads in sync with mma_slot_states
|
| 1786 |
+
for _st, _str in zip(mma_slot_states, mma_slot_state_reads):
|
| 1787 |
+
_st.change(fn=lambda v: v, inputs=[_st], outputs=[_str])
|
| 1788 |
+
|
| 1789 |
for _i, _rtrig in enumerate(mma_slot_rtrigs):
|
| 1790 |
_slot_id = f"mma_{_i}"
|
| 1791 |
def _make_mma_regen(_si, _sid):
|
| 1792 |
+
def _do(trigger_val, video, prompt, neg, seed, cfg, steps, cf_dur, cf_db, state_json):
|
| 1793 |
+
print(f"[regen MMA] trigger_val={trigger_val!r} state_json_len={len(state_json) if state_json else 0}")
|
| 1794 |
if not trigger_val:
|
| 1795 |
print(f"[regen MMA] early-exit: trigger_val empty")
|
| 1796 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1797 |
+
if not state_json:
|
| 1798 |
+
print(f"[regen MMA] early-exit: state_json empty")
|
|
|
|
|
|
|
| 1799 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1800 |
+
parts = trigger_val.split("|", 2)
|
| 1801 |
+
if len(parts) < 2 or parts[0] != _sid:
|
| 1802 |
+
print(f"[regen MMA] early-exit: parts[0]={parts[0]!r} expected={_sid!r}")
|
| 1803 |
+
yield gr.update(), gr.update(), gr.update(); return
|
| 1804 |
+
seg_idx = int(parts[1])
|
| 1805 |
+
print(f"[regen MMA] slot={_sid} seg_idx={seg_idx} — acquiring lock")
|
| 1806 |
lock = _get_slot_lock(_sid)
|
| 1807 |
with lock:
|
| 1808 |
print(f"[regen MMA] slot={_sid} seg_idx={seg_idx} — lock acquired, showing spinner")
|
|
|
|
| 1827 |
_rtrig.change(
|
| 1828 |
fn=_make_mma_regen(_i, _slot_id),
|
| 1829 |
inputs=[_rtrig, mma_video, mma_prompt, mma_neg, mma_seed,
|
| 1830 |
+
mma_cfg, mma_steps, mma_cf_dur, mma_cf_db, mma_slot_state_reads[_i]],
|
| 1831 |
outputs=[mma_slot_vids[_i], mma_slot_waves[_i], mma_slot_states[_i]],
|
| 1832 |
)
|
| 1833 |
|
|
|
|
| 1852 |
with gr.Column():
|
| 1853 |
(hf_slot_grps, hf_slot_vids,
|
| 1854 |
hf_slot_waves, hf_slot_rtrigs,
|
| 1855 |
+
hf_slot_states,
|
| 1856 |
+
hf_slot_state_reads) = _make_output_slots("hf")
|
| 1857 |
|
| 1858 |
hf_samples.change(
|
| 1859 |
fn=_update_slot_visibility,
|
|
|
|
| 1881 |
outputs=hf_slot_grps,
|
| 1882 |
))
|
| 1883 |
|
| 1884 |
+
# Relay: keep hf_slot_state_reads in sync with hf_slot_states
|
| 1885 |
+
for _st, _str in zip(hf_slot_states, hf_slot_state_reads):
|
| 1886 |
+
_st.change(fn=lambda v: v, inputs=[_st], outputs=[_str])
|
| 1887 |
+
|
| 1888 |
for _i, _rtrig in enumerate(hf_slot_rtrigs):
|
| 1889 |
_slot_id = f"hf_{_i}"
|
| 1890 |
def _make_hf_regen(_si, _sid):
|
| 1891 |
+
def _do(trigger_val, video, prompt, neg, seed, guidance, steps, size, cf_dur, cf_db, state_json):
|
| 1892 |
+
print(f"[regen HF] trigger_val={trigger_val!r} state_json_len={len(state_json) if state_json else 0}")
|
| 1893 |
if not trigger_val:
|
| 1894 |
print(f"[regen HF] early-exit: trigger_val empty")
|
| 1895 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1896 |
+
if not state_json:
|
| 1897 |
+
print(f"[regen HF] early-exit: state_json empty")
|
| 1898 |
+
yield gr.update(), gr.update(), gr.update(); return
|
| 1899 |
+
parts = trigger_val.split("|", 2)
|
| 1900 |
+
if len(parts) < 2 or parts[0] != _sid:
|
| 1901 |
+
print(f"[regen HF] early-exit: parts[0]={parts[0]!r} expected={_sid!r}")
|
| 1902 |
yield gr.update(), gr.update(), gr.update(); return
|
| 1903 |
+
seg_idx = int(parts[1])
|
| 1904 |
+
print(f"[regen HF] slot={_sid} seg_idx={seg_idx} — acquiring lock")
|
|
|
|
| 1905 |
lock = _get_slot_lock(_sid)
|
| 1906 |
with lock:
|
| 1907 |
print(f"[regen HF] slot={_sid} seg_idx={seg_idx} — lock acquired, showing spinner")
|
|
|
|
| 1926 |
_rtrig.change(
|
| 1927 |
fn=_make_hf_regen(_i, _slot_id),
|
| 1928 |
inputs=[_rtrig, hf_video, hf_prompt, hf_neg, hf_seed,
|
| 1929 |
+
hf_guidance, hf_steps, hf_size, hf_cf_dur, hf_cf_db, hf_slot_state_reads[_i]],
|
| 1930 |
outputs=[hf_slot_vids[_i], hf_slot_waves[_i], hf_slot_states[_i]],
|
| 1931 |
)
|
| 1932 |
|