Spaces:
Build error
Build error
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.
|