MomsVoiceAI / sprint.md
minhahwang's picture
docs: update sprint.md with progress summary and remaining tasks
ee79c05
|
Raw
History Blame Contribute Delete
12.1 kB
# Sprint Plan β€” 2-Day Hackathon
## Current Progress (Updated 2026-06-13 10:00 PM)
**Completed: 19/25 tasks (76%)**
βœ… Core ML pipeline: Voice cloning (Qwen3-TTS), ASR (Whisper-small), Q&A (Qwen2.5-3B-Instruct)
βœ… Gradio UI: 4 tabs, book grid, player, clone studio, profile
βœ… Latency optimizations: bfloat16, flash-attn, streaming, reduced sampling, torch.compile
βœ… UI cleanup: removed dead widgets/debug tools, tightened integration
βœ… Tests: 92 passing (18 latency + 74 integration)
βœ… Documentation: README, SPEC, tech_stack, sprint, mission all updated
**Remaining: 6 tasks β€” see [Remaining Tasks](#remaining-tasks) below**
---
## Goal
Ship a public Hugging Face Space: parent clones voice β†’ story streams in that voice β†’ child can interrupt, ask, hear the answer, and resume.
---
## Day 1: Core Pipeline (Get It Working)
### Morning (4h) β€” Voice Clone + TTS
| # | Task | Time | Done |
|---|---|---|---|
| 1 | Set up repo: `app.py`, `requirements.txt`, `stories/` | 30m | β˜‘ |
| 2 | Load QWEN-TTS-0.6B locally, test basic TTS (text β†’ audio) | 1h | β˜‘ | *(switched to Supertonic TTS; wired in `tts.py`, tested in `test_modules/`)* |
| 3 | Implement voice cloning and cache voice representation after recording | 1.5h | β˜‘ | *(Qwen3-TTS voice cloning in `voice_clone.py`; `create_voice_profile()` extracts speaker embedding, cached server-side; preview synthesis on clone; profile_id flows via `gr.State` to narration + Q&A)* |
| 4 | Add 10 short stories as `.txt` files (public domain, from Project Gutenberg) | 30m | β˜‘ |
| 5 | Wire up: pick story β†’ stream first narration chunk, track chunk index, cache story audio | 1h | β˜‘ | *(`handle_book_select` loads paragraphs + splits chunks; `stream_tts` generator streams audio with play/pause/chunk-index tracking)* |
**Checkpoint:** Can generate a story audio file in a cloned voice from CLI.
### Afternoon (4h) β€” Gradio UI + Q&A
| # | Task | Time | Done |
|---|---|---|---|
| 6 | Build Gradio app with 3 tabs (Clone, Listen, Ask) | 1h | β˜‘ | *(4 tabs: Explore, Library+Player, Clone Voice Studio, Profile & Sandbox)* |
| 7 | Tab 1 (Clone): `gr.Audio` record/upload + preview button | 45m | β˜‘ | *(Clone Voice Studio tab: mic recorder, extract button, status pipeline, preview audio)* |
| 8 | Tab 2 (Listen): story dropdown + play/pause/resume controls for streamed chunks | 45m | β˜‘ | *(Library tab: book card grid + integrated player panel with play/pause/resume/chunk status)* |
| 9 | Add on-demand ASR for child voice input; use lighter ASR fallback if needed | 30m | β˜‘ | *(Whisper-small loaded on-demand in `inference.py`; transcribes child audio in `handle_question_submit`)* |
| 10 | Tab 3 (Ask): interrupt narration β†’ short grounded Qwen answer β†’ TTS β†’ resume story | 2h | β˜‘ | *(Qwen2.5-3B-Instruct in `inference.py` generates grounded 1-2 sentence answers from story context; answer synthesized via Supertonic TTS; full pipeline wired in `handle_question_submit`)* |
| 10a | Pre-generate 2–3 anticipated Q&A pairs per chunk during narration playback (background task) | 30m | ☐ |
**Checkpoint:** Full loop works locally β€” clone β†’ listen β†’ interrupt β†’ ask β†’ resume. Ugly but functional.
**Day 1 Overflow Plan:** If the afternoon runs past 8h, cut Task 9 (on-demand ASR) and rely on text-only questions. CSS polish (Tasks 12–14) is the next cut candidate on Day 2.
---
## Day 2: Polish + Deploy (Make It Demo-Ready)
### Morning (4h) β€” UI Polish (Google Stitch)
| # | Task | Time | Done |
|---|---|---|---|
| 11 | Set up `gr.Server` with custom static files (`static/style.css`) | 30m | β˜‘ | *(`css_code` loaded from `static/style.css` in `app.py`; `allowed_paths` set for `assets/`)* |
| 12 | Stitch-style CSS: color palette, card layout, rounded corners, fonts | 1h | β˜‘ | *(179-line `static/style.css`: Inter/Playfair Display fonts, cream/amber palette, card grid, hero spotlight, progress bar)* |
| 13 | Recording UX: waveform animation, countdown timer, status indicators | 1h | ☐ | *(pulse-ring CSS animation + status indicators done; no countdown timer yet)* |
| 14 | Story gallery: cover images (AI-generated or placeholder), card grid | 45m | β˜‘ | *(10 cover PNGs in `assets/covers/`; `generate_library_html` renders card grid with cover, progress bar, narrator)* |
| 15 | Loading states: playback status, paused state, TTS progress, and background chunk generation | 30m | β˜‘ | *(PLAYING/PAUSED/READY/DONE status bars + chunk counter HTML; `stream_tts` generator updates per chunk)* |
| 16 | Mobile-responsive check (parents use laptops, demo on projector) | 15m | ☐ |
**Checkpoint:** App looks polished and professional. Ready for live demo.
### Afternoon (4h) β€” Deploy + Demo Prep
| # | Task | Time | Done |
|---|---|---|---|
| 17 | Create HF Space (T4 with 4-bit/8-bit loading, or A10G for headroom), push code, verify model downloads | 1h | ☐ |
| 18 | Confirm no external LLM API secrets are required; set `HF_TOKEN` only if gated models require it | 5m | β˜‘ | *(all inference local via Supertonic + Qwen; no external API calls in codebase)* |
| 19 | End-to-end test on live Space (clone β†’ listen β†’ interrupt β†’ ask β†’ resume) | 30m | ☐ |
| 20 | Fix latency issues: preload weights, cache voice/story audio, cap Q&A tokens, validate pause/resume | 45m | β˜‘ | *(bfloat16/flash-attn/streaming/reduced sampling params in `voice_clone.py`; torch.compile on decoder; ref audio trimming; 0.6B CustomVoice as fast fallback)* |
| 20a | Measure and log all latency targets from mission.md (first chunk, pause, Q&A, resume, replay) | 30m | ☐ |
| 20b | Validate playback state machine: test all 6 states and legal transitions from tech_stack.md | 30m | β˜‘ | *(92 tests in `test_modules/`: state machine consistency, handler wiring, dead code removal verified)* |
| 21 | Add error handling: graceful failures, loading messages | 30m | ☐ |
| 22 | Record backup demo video (in case live demo fails) | 30m | ☐ |
| 23 | Write README.md for the Space (screenshot, description) | 15m | β˜‘ | *(full README with HF Space YAML header, model table, story list, architecture, privacy section)* |
| 24 | Practice 3-minute demo walkthrough | 30m | ☐ |
**Checkpoint:** Live public URL works. Demo rehearsed.
---
## Risk Mitigations
| Risk | Mitigation |
|---|---|
| Qwen3-TTS voice quality insufficient | Fall back to longer reference audio (30s+); use Supertonic stock voice as backup |
| GPU OOM with Qwen3-TTS + Whisper + Qwen Q&A | All models lazy-loaded on demand; 4-bit Qwen Q&A on T4; prefer A10G for live demo |
| HF Space cold start too slow | Use persistent Space (not sleep); lazy-load models on first use rather than at startup |
| Qwen3-TTS synthesis too slow (~30s/sentence) | β˜‘ Mitigated: bfloat16, flash-attn, streaming mode, top_k=20/temp=0.7, max_new_tokens=1024, torch.compile, ref audio trimmed to ≀10s |
| Qwen answer latency too slow | Keep answers to 1–2 sentences; cap story prompt length; cache answers per story/question pair |
| Interrupt/resume feels brittle | Track playback state, current chunk index, queued generation jobs, and cached next chunks |
| ASR adds too much delay | Let text questions bypass ASR; use Whisper-tiny/base or browser transcription for demo mode |
| Live demo fails | Pre-recorded backup video ready |
---
## File Structure (Final)
```
VoiceClone/
β”œβ”€β”€ app.py # Main Gradio app (UI + wiring)
β”œβ”€β”€ voice_clone.py # Qwen3-TTS voice cloning + profile cache
β”œβ”€β”€ tts.py # Unified TTS interface (Qwen3 or Supertonic)
β”œβ”€β”€ inference.py # ASR (Whisper-small) + Q&A (Qwen2.5-3B-Instruct)
β”œβ”€β”€ requirements.txt # Python deps
β”œβ”€β”€ README.md # HF Space description
β”œβ”€β”€ stories/ # 10 cleaned TTS-ready story texts
β”‚ β”œβ”€β”€ The_Tale_of_Peter_Rabbit.txt
β”‚ β”œβ”€β”€ The_Tale_of_Benjamin_Bunny.txt
β”‚ β”œβ”€β”€ The_Tale_of_Jemima_Puddle_Duck.txt
β”‚ β”œβ”€β”€ The_Tale_of_Tom_Kitten.txt
β”‚ β”œβ”€β”€ The_History_of_Tom_Thumb.txt
β”‚ β”œβ”€β”€ The_Story_of_the_Three_Little_Pigs.txt
β”‚ β”œβ”€β”€ The_Little_Red_Hen.txt
β”‚ β”œβ”€β”€ The_Little_Gingerbread_Man.txt
β”‚ β”œβ”€β”€ The_Sleeping_Beauty.txt
β”‚ └── The_Adventures_of_Puss_in_Boots.txt
β”œβ”€β”€ story_downloader/ # Story acquisition & cleaning pipeline
β”‚ β”œβ”€β”€ gutenberg_downloader.py # Reusable Project Gutenberg downloader/parser
β”‚ β”œβ”€β”€ download_stories.py # Downloads 10 children's stories
β”‚ └── clean_stories.py # Strips Gutenberg boilerplate for TTS
β”œβ”€β”€ static/
β”‚ β”œβ”€β”€ style.css # Stitch-style custom CSS
β”‚ β”œβ”€β”€ script.js # Animations, waveform
β”‚ └── favicon.png
β”œβ”€β”€ assets/
β”‚ └── covers/ # Story cover images
β”œβ”€β”€ test_modules/ # Component and integration tests
β”œβ”€β”€ mission.md # Product vision (this hackathon)
β”œβ”€β”€ tech_stack.md # Technical decisions
β”œβ”€β”€ sprint.md # This file
└── future_mobile_app_considerations.md # Mobile deployment guidance
```
---
## Key Decisions (Locked)
- **No database** β€” stateless demo, voice profiles held in server-side memory cache
- **No auth** β€” open access for hackathon judges
- **Interruptible chunked streaming** β€” play sentence chunks, pause on Ask, answer, then resume from the saved story position
- **Qwen3-TTS-1.7B for voice cloning** β€” zero-shot speaker embedding extraction from recorded audio; synthesis in cloned voice
- **Supertonic TTS as fallback** β€” fast stock voice when no voice profile exists
- **Qwen2.5-3B-Instruct for Q&A** β€” keeps story comprehension local while improving latency and GPU fit
- **Short grounded Q&A** β€” retrieve relevant story passages, cap answers to 1–2 sentences, then synthesize audio
- **Button-based interruption first** β€” tap Ask to pause narration; always-listening voice barge-in is out of scope for the hackathon
- **Modular design** β€” `voice_clone.py`, `tts.py`, `inference.py` separated from `app.py` for clarity
---
## Review Notes
| Area | Critique | Upgrade |
|---|---|---|
| Model plan | Replacing an external Q&A API with Qwen2.5-3B-Instruct removes API risk while keeping latency practical. | Treat T4 with quantization as viable; use A10G when demo reliability matters more than cost. |
| Secrets | The old plan required an external LLM API secret, which contradicts the privacy-first positioning. | Remove LLM API secrets from deployment; use only HF credentials when required for model access. |
| Demo schedule | The original plan left little time for model loading, user-visible wait states, and interruption edge cases. | Add explicit validation around model downloads, quantization, cold-start behavior, chunked playback, pause/resume, and cache hits. |
---
## Remaining Tasks
| # | Task | Est. | Priority | Notes |
|---|---|---|---|---|
| 10a | Pre-generate anticipated Q&A pairs per chunk during narration | 30m | Low | Nice-to-have; reduces Q&A latency but not critical for demo |
| 13 | Recording UX: countdown timer in Clone Studio | 30m | Medium | Pulse animation done; timer would improve UX |
| 16 | Mobile-responsive check | 15m | Low | Demo is on laptop/projector; mobile is stretch goal |
| 17 | Create HF Space, push, verify model downloads | 1h | **Critical** | Must do before demo β€” deploy to T4/A10G Space |
| 19 | End-to-end test on live Space | 30m | **Critical** | Full clone→listen→ask→resume loop on deployed Space |
| 20a | Measure and log latency targets | 30m | Medium | Document actual vs target for first-chunk, Q&A, resume |
| 21 | Error handling: graceful failures, loading messages | 30m | Medium | Model load failures, OOM, timeout messaging |
| 22 | Record backup demo video | 30m | **Critical** | Insurance against live demo failure |
| 24 | Practice 3-minute demo walkthrough | 30m | **Critical** | Rehearse narrative + live interaction flow |
**Critical path:** 17 β†’ 19 β†’ 22 β†’ 24 (deploy β†’ test β†’ backup video β†’ rehearse)