Takosaga commited on
Commit
95dea62
Β·
1 Parent(s): 5151540

docs: add regenerate cards on parameter change design spec

Browse files
docs/superpowers/specs/2026-06-13-regenerate-cards-on-parameter-change-design.md ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Regenerate Cards on Parameter Change β€” Design Spec
2
+
3
+ **Date:** 2026-06-13
4
+ **Status:** Approved
5
+
6
+ ## Problem
7
+
8
+ After Phase 2 (translation + media generation) completes, both the **Generate Text** and **Generate Cards** buttons are hidden by `_on_media_generation_complete()`. The user cannot regenerate cards with different parameters β€” changing language, toggles, or voice has no effect because the Generate Cards button is invisible.
9
+
10
+ The `_phase1_texts` global is preserved through Phase 2 (never cleared), so the English source text remains available. The `generate_media_async()` function already supports all needed parameters (language, audio, images, voice). The missing piece is UI event wiring to restore the Generate Cards button when any parameter changes.
11
+
12
+ ## Solution Overview
13
+
14
+ Add chained `.then()` handlers to four events that affect Phase 2 output. Each chain restores the Generate Cards button's visibility and interactivity after the primary handler completes.
15
+
16
+ ### Events to Wire
17
+
18
+ | # | Event | Primary Handler | New Chained Handler |
19
+ |---|---|---|---|
20
+ | 1 | Language dropdown `.change()` | `_reset_to_idle()` | `_restore_generate_cards_button()` |
21
+ | 2 | Audio toggle `.change()` | `_on_audio_toggle_change()` | `_restore_generate_cards_button()` |
22
+ | 3 | Image toggle `.change()` | *(none)* | `_restore_generate_cards_button()` |
23
+ | 4 | Voice dropdown `.change()` | *(none)* | `_restore_generate_cards_button()` |
24
+
25
+ ### Output Changes
26
+
27
+ **`_reset_to_idle()` returns tuple:** Currently outputs 8 elements:
28
+ `(generate_text_btn, images_toggle, audio_toggle, generate_cards_btn, voice_dropdown, phase_css, export_btn, export_file)`
29
+
30
+ The `generate_cards_btn` is already set to `visible=True, interactive=False`. The chained handler will update it to `visible=True, interactive=True`.
31
+
32
+ **Current event chains:**
33
+ - Language change: `.change(_reset_to_idle, outputs=[...8 elements...])` β€” no `.then()`
34
+ - Audio toggle: `.change(fn=_on_audio_toggle_change, inputs=[audio_toggle], outputs=[voice_dropdown, phase_css])` β€” no `.then()`, does NOT include `generate_cards_btn`
35
+ - Image toggle: **not wired**
36
+ - Voice dropdown: **not wired**
37
+
38
+ ### New Code in `widgets.py`
39
+
40
+ #### 1. New helper function `_restore_generate_cards_button()`
41
+
42
+ ```python
43
+ def _restore_generate_cards_button():
44
+ """After a parameter change, restore the Generate Cards button so user can regenerate media.
45
+
46
+ Called as a chained .then() handler after primary event handlers.
47
+ Unhides the button and makes it interactive. Export button stays disabled.
48
+
49
+ Returns:
50
+ Tuple of (generate_cards_btn, export_btn) Gradio updates.
51
+ """
52
+ import gradio as gr
53
+ return (
54
+ gr.Button(visible=True, interactive=True), # generate_cards_btn
55
+ gr.Button(visible=True, interactive=False), # export_btn (disabled until Phase 2)
56
+ )
57
+ ```
58
+
59
+ #### 2. Updated event chains in `build_ui()`
60
+
61
+ **Language dropdown β€” add `.then()`:**
62
+ ```python
63
+ language_dropdown.change(
64
+ fn=_reset_to_idle,
65
+ inputs=[],
66
+ outputs=[generate_text_btn, images_toggle, audio_toggle, generate_cards_btn, voice_dropdown, phase_css, export_btn, export_file],
67
+ ).then(
68
+ fn=_restore_generate_cards_button,
69
+ inputs=[],
70
+ outputs=[generate_cards_btn, export_btn],
71
+ )
72
+ ```
73
+
74
+ **Audio toggle β€” add `generate_cards_btn` and `export_btn` to outputs + `.then()`:**
75
+ ```python
76
+ audio_toggle.change(
77
+ fn=_on_audio_toggle_change,
78
+ inputs=[audio_toggle],
79
+ outputs=[voice_dropdown, phase_css, generate_cards_btn, export_btn],
80
+ ).then(
81
+ fn=_restore_generate_cards_button,
82
+ inputs=[],
83
+ outputs=[generate_cards_btn, export_btn],
84
+ )
85
+ ```
86
+
87
+ **Image toggle β€” new event wire:**
88
+ ```python
89
+ images_toggle.change(
90
+ fn=lambda: (gr.Button(visible=True, interactive=True), gr.Button(visible=True, interactive=False)),
91
+ inputs=[],
92
+ outputs=[generate_cards_btn, export_btn],
93
+ )
94
+ ```
95
+
96
+ **Voice dropdown β€” new event wire:**
97
+ ```python
98
+ voice_dropdown.change(
99
+ fn=lambda: (gr.Button(visible=True, interactive=True), gr.Button(visible=True, interactive=False)),
100
+ inputs=[],
101
+ outputs=[generate_cards_btn, export_btn],
102
+ )
103
+ ```
104
+
105
+ ### Files Changed
106
+
107
+ | File | Changes |
108
+ |---|---|
109
+ | `frontend/ui/widgets.py` | Add `_restore_generate_cards_button()` helper; update language dropdown event chain; update audio toggle event chain with new outputs and `.then()`; add image toggle event wire; add voice dropdown event wire. |
110
+ | `tests/widgets_test.py` | Add tests for `_restore_generate_cards_button()` function; update existing tests that reference audio toggle outputs to include new elements. |
111
+
112
+ ### Behavior Summary
113
+
114
+ 1. User completes Phase 2 β†’ both buttons hidden, cards displayed with media.
115
+ 2. User changes **any** phase-2 parameter (language, audio toggle, image toggle, voice) β†’ Generate Cards button becomes visible and interactive. Export button stays disabled.
116
+ 3. User clicks **Generate Cards** β†’ `generate_media_async()` runs with the new parameters, using existing `_phase1_texts` as source.
117
+ 4. After Phase 2 completes again β†’ buttons hidden again (same as before).
118
+
119
+ ### Edge Cases Handled
120
+
121
+ - **Changing language after Phase 2:** Language dropdown already calls `_reset_to_idle()` which keeps cards visible and resets toggles to OFF. The new `.then()` restores the Generate Cards button so user can regenerate with the new language.
122
+ - **Toggling audio ON/OFF:** Audio toggle change already updates voice dropdown interactivity and CSS. Adding Generate Cards button restoration lets user re-generate with or without audio.
123
+ - **Voice change while audio is OFF:** Voice dropdown is disabled when audio is OFF, so this event won't fire. No issue.
124
+ - **Rapid parameter changes:** Gradio queues events sequentially; each `.then()` waits for the previous handler to complete. No race conditions.
125
+
126
+ ### Testing
127
+
128
+ - Unit test: `_restore_generate_cards_button()` returns correct tuple of `(gr.Button(visible=True, interactive=True), gr.Button(visible=True, interactive=False))`.
129
+ - Integration test: Simulate audio toggle change β†’ verify Generate Cards button becomes visible and interactive.
130
+ - Existing widget tests that reference `_reset_to_idle()` or audio toggle outputs must be updated to match new output counts.