Spaces:
Sleeping
Sleeping
File size: 10,119 Bytes
896ae7d 61e3968 896ae7d 61e3968 896ae7d 61e3968 c403f04 61e3968 c403f04 61e3968 896ae7d c403f04 896ae7d 3f26297 61e3968 896ae7d 61e3968 896ae7d 61e3968 c403f04 61e3968 c403f04 61e3968 c403f04 896ae7d 61e3968 896ae7d 61e3968 c403f04 61e3968 3f26297 61e3968 c403f04 896ae7d 61e3968 896ae7d 61e3968 c403f04 61e3968 c403f04 896ae7d 61e3968 896ae7d 61e3968 c403f04 3f26297 c403f04 896ae7d 61e3968 896ae7d 7bfa09d 896ae7d 61e3968 896ae7d 61e3968 c403f04 61e3968 c403f04 61e3968 896ae7d c403f04 3f26297 c403f04 896ae7d c403f04 896ae7d 61e3968 896ae7d 61e3968 896ae7d 61e3968 896ae7d c403f04 896ae7d 61e3968 c403f04 61e3968 896ae7d c403f04 896ae7d 61e3968 896ae7d 61e3968 896ae7d 61e3968 c403f04 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | # Tech Stack
## Architecture (Hackathon-Simple)
Single Python file Gradio app. Everything runs in one process on a GPU-enabled HF Space.
```
βββββββββββββββββββββββββββββββββββββββββββββββββββ
β Hugging Face Space (GPU: T4 or A10G) β
β β
β app.py (Gradio + gr.Server) β
β βββ UI: Stitch-styled tabs/cards β
β βββ QWEN-TTS-0.6B (voice clone + chunks) β
β βββ Whisper-small (ASR for child questions) β
β βββ Qwen2.5-3B-Instruct (story Q&A) β
β β
β stories/ (3β5 .txt files, public domain) β
βββββββββββββββββββββββββββββββββββββββββββββββββββ
```
No database. No external storage. No external LLM API. Stories are flat files. Audio is generated as interruptible chunks, then cached in the session for replay and resume.
**VRAM Budget (T4 β 16 GB):**
| Component | Estimated VRAM | Notes |
|---|---|---|
| QWEN-TTS-0.6B | ~1.2 GB | Always loaded |
| Qwen2.5-3B-Instruct (4-bit) | ~2 GB | Always loaded |
| Whisper-small | ~1 GB | Loaded on demand |
| Gradio + PyTorch overhead | ~1β2 GB | Runtime |
| **Total** | **~5β6 GB** | ~10 GB headroom for KV cache and activations |
**Concurrency:** Single-process Gradio serializes concurrent users. The hackathon demo is single-user. For multi-user, consider Gradio queue or separate worker processes.
---
## 1. Front-End
| Choice | Why |
|---|---|
| Gradio 5.x | Zero frontend code, instant HF Space deploy |
| `gr.Server` | Custom CSS/JS for Stitch-style polish (animations, palette, layout) |
| `gr.Audio` | Record/upload parent voice sample |
| `gr.Dropdown` / `gr.Gallery` | Story selection with cover art |
| `gr.Audio` (output) | Playback of streamed story chunks / Q&A answer |
| `gr.Textbox` + `gr.Audio` (input) | Child question via text or voice |
| Play/Pause/Ask buttons | Manual interruption and resume without open-mic barge-in |
**UI Tabs:**
1. **π€ Clone Voice** β record/upload 15β30s, preview clone
2. **π Listen** β pick story, hear streamed chunks in cloned voice
3. **β Ask** β pause narration, ask about the story, hear answer, resume
---
## 2. Voice Model (QWEN-TTS-0.6B)
| Aspect | Detail |
|---|---|
| Model | `Qwen/Qwen-TTS-0.6B` from Hugging Face Hub |
| Size | 0.6B params β fits comfortably on T4 (16GB VRAM) |
| Capability | Zero-shot voice cloning + TTS from text chunks |
| Input | Reference audio (β₯5s) + target text |
| Output | WAV audio in cloned voice (24 kHz, 16-bit, mono) |
| Latency | ~3β5s for a paragraph on T4 |
| Optimization | Cache the voice representation after recording; generate story audio in interruptible paragraph chunks |
---
## 3. ASR (Child Voice Input)
| Choice | Detail |
|---|---|
| Model | Whisper-small checkpoint via Transformers (local, 244M params) |
| Why | Fast, accurate for short child utterances; fits in GPU alongside TTS |
| Load strategy | Load only when the Ask tab receives audio; text questions bypass ASR |
| Fallback | Whisper-tiny/base or browser transcription if GPU memory or latency is tight |
---
## 4. Q&A (Story Comprehension)
| Choice | Detail |
|---|---|
| Model | `Qwen/Qwen2.5-3B-Instruct` |
| Why | Strong small-model instruction following with lower latency and VRAM pressure than an 8B-class model |
| Method | Current story position + relevant story passages + strict answer-from-story instruction + child question β short answer |
| Retrieval | TF-IDF cosine similarity between the child's question and each story paragraph; return the top-2 paragraphs as context. Full-story prompt is the fallback when retrieval scores are low. |
| Output cap | 1β2 child-friendly sentences, typically 40β80 new tokens |
| Runtime note | Use 4-bit/8-bit loading on T4; use bf16 or 8-bit on A10G for more headroom |
---
## 5. Stories (Content)
10 public domain children's stories stored as `.txt` in `stories/`, sourced from [Project Gutenberg](https://www.gutenberg.org/) via the `story_downloader/` pipeline:
| Story | Words | Author/Tradition |
|---|---|---|
| The Tale of Peter Rabbit | 948 | Beatrix Potter |
| The Tale of Benjamin Bunny | 1,118 | Beatrix Potter |
| The Tale of Jemima Puddle-Duck | 1,245 | Beatrix Potter |
| The Tale of Tom Kitten | 691 | Beatrix Potter |
| The History of Tom Thumb | 2,912 | Traditional |
| The Story of the Three Little Pigs | 956 | Traditional |
| The Little Red Hen | 1,295 | Traditional |
| The Little Gingerbread Man | 1,823 | Traditional |
| The Sleeping Beauty | 1,783 | Traditional |
| The Adventures of Puss in Boots | 503 | Traditional (verse) |
Each file: title on line 1, blank line, then story prose β ready for direct TTS chunking. No metadata DB needed.
**Story Pipeline (`story_downloader/`):**
- `gutenberg_downloader.py` β reusable downloader/parser for Project Gutenberg texts
- `download_stories.py` β fetches 10 specific children's stories by Gutenberg ID
- `clean_stories.py` β strips Gutenberg headers/footers, illustration tags, and metadata for TTS-clean output
---
## 6. Deployment
| What | How |
|---|---|
| Platform | Hugging Face Spaces |
| SDK | Gradio |
| Hardware | T4 with quantized Qwen for the budget path; A10G for lower risk live demos |
| Deploy | `git push` to HF Space repo |
| Secrets | None for LLM inference; `HF_TOKEN` only if any selected model requires gated access |
| Domain | `huggingface.co/spaces/{user}/readbookmom` |
---
## 7. Latency Plan
| Flow | Target | Implementation |
|---|---|---|
| Voice setup | One-time after recording | Compute and cache the voice representation before story generation. |
| Story narration start | First streamed chunk in β€ 5s | Split the story into paragraph chunks; synthesize and play the first chunk first. |
| Narration interruption | Pause in β€ 500ms after Ask tap | Stop playback, preserve current chunk index, and cancel or deprioritize queued narration jobs. |
| Q&A interruption loop | Spoken answer starts in β€ 8s | Use current story position, retrieve relevant passages, cap answer length, then synthesize the final answer. |
| Story resume | β€ 1s when next chunk is cached | Resume from the paused chunk or the next queued chunk after the answer finishes. |
| Story replay | Immediate after first generation | Cache generated audio by voice session and story ID. |
| Child audio transcription | 1β2s target | Load ASR only for audio questions; prefer lighter ASR fallback for demo mode. |
| Q&A text answer | 1β3s target | Send only relevant story passages to Qwen and cap output tokens. |
| Spoken Q&A answer | β€ 8s total target | Synthesize only the final short answer, not intermediate reasoning or context. |
## 8. Interaction State
| State | Meaning | Key Data |
|---|---|---|
| `playing` | Story chunk is currently playing. | `story_id`, `voice_session_id`, `current_chunk_index` |
| `paused` | Playback is paused by user action. | Current chunk, elapsed position if available |
| `asking` | Narration is interrupted while the child asks a question. | Current chunk, relevant passages, pending ASR input |
| `answering` | Qwen answer or answer TTS is being generated. | Question text, short answer, answer audio path |
| `resuming` | Answer finished and story playback is restarting. | Resume chunk index, cached next chunk |
| `finished` | Story narration completed. | Cached full-story audio |
**Legal transitions:**
```
playing β paused β playing
playing β asking β answering β resuming β playing
playing β finished
paused β asking β answering β resuming β playing
asking β asking (child asks a follow-up before answer starts)
```
All other transitions are illegal. The UI should disable buttons that would trigger an illegal transition.
---
## 9. Local Dev
```bash
pip install gradio transformers torch accelerate bitsandbytes soundfile numpy
python app.py
# β http://localhost:7860
```
No Docker, no DB, no infra setup.
---
## 10. Dependencies
```
gradio>=5.0
transformers
torch
accelerate
bitsandbytes
soundfile
numpy
```
---
## 11. Google Stitch UI Customization (via gr.Server)
`gr.Server` injects custom HTML/CSS/JS to achieve Stitch-quality polish:
- **Custom CSS**: Rounded cards, warm color palette (#FFB347 accent, #FFF8E7 background), playful fonts (Nunito/Fredoka)
- **Micro-animations**: Fade-in on story cards, pulse on recording button, waveform visualization
- **Layout overrides**: Full-bleed hero on clone tab, grid gallery for stories
- **Custom favicon + title**: Branded for demo presentation
All in a `static/` folder loaded by gr.Server mount.
---
## 12. Review Notes
| Area | Critique | Upgrade |
|---|---|---|
| Privacy | Using an external Q&A API would undermine the local-inference claim. | Qwen2.5-3B-Instruct keeps questions, story text, and generated answers inside the Space runtime. |
| GPU fit | QWEN-TTS-0.6B, Whisper-small, and a 3B-class LLM are a more realistic fit for a single Space than an 8B-class LLM, but running all three hot can still pressure T4. | Quantize Qwen on T4, use A10G for demo headroom, cache voice/story artifacts, and load ASR only when the Ask tab receives audio. |
| Latency | Full-story generation and spoken Q&A can feel slow if every step waits for complete outputs. | Use interruptible paragraph chunks, cache full narration, retrieve only relevant passages, and synthesize only short final answers. |
| Interaction | Streaming without cancellation can still feel rigid if the child must wait for a chunk to finish. | Add explicit playback state, Ask interruption, queued job cancellation/deprioritization, and resume from the saved chunk. |
| Dependencies | External LLM SDKs and API secrets are no longer aligned with the model choice. | Use local inference dependencies and optional HF authentication only. |
|