Spaces:
Sleeping
Sleeping
| # 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. | | |