Spaces:
Runtime error
Runtime error
Commit Β·
e308c53
1
Parent(s): 215fff0
docs: update all docs to reflect Qwen3-TTS architecture
Browse filesUpdate README.md, SPEC.md, tech_stack.md, sprint.md, and mission.md:
- Replace QWEN-TTS-0.6B references with Qwen3-TTS-1.7B-Base
- Add Supertonic as explicit fallback in model tables
- Update architecture diagram with modular file structure
- Update VRAM budget estimates for new model lineup
- Update project structure with voice_clone.py, tts.py, inference.py
- Update risk mitigations for Qwen3-TTS latency characteristics
- Update key decisions with actual model choices and module design
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- README.md +11 -6
- SPEC.md +11 -7
- mission.md +3 -3
- sprint.md +14 -8
- tech_stack.md +38 -29
README.md
CHANGED
|
@@ -31,17 +31,18 @@ Built for the Hugging Face Hackathon. Runs entirely on local models inside a Gra
|
|
| 31 |
|
| 32 |
| Step | What Happens | Model |
|
| 33 |
|---|---|---|
|
| 34 |
-
| **Clone** | Parent records or uploads 15β30s of audio.
|
| 35 |
-
| **Listen** | Story plays in the cloned voice as interruptible
|
| 36 |
| **Ask** | Child taps Ask, narration pauses, child types or speaks a question. | Whisper-small (ASR, on-demand) |
|
| 37 |
-
| **Answer** | A short grounded answer is generated from the story context and spoken in the cloned voice. | Qwen2.5-3B-Instruct +
|
| 38 |
| **Resume** | Story continues from where it left off. | Cached chunks |
|
| 39 |
|
| 40 |
## Models
|
| 41 |
|
| 42 |
| Model | Role | Size |
|
| 43 |
|---|---|---|
|
| 44 |
-
| [
|
|
|
|
| 45 |
| [Qwen2.5-3B-Instruct](https://huggingface.co/Qwen/Qwen2.5-3B-Instruct) | Story Q&A | 3B params (4-bit on T4) |
|
| 46 |
| [Whisper-small](https://huggingface.co/openai/whisper-small) | Child speech-to-text | 244M params (loaded on demand) |
|
| 47 |
|
|
@@ -57,7 +58,7 @@ Built for the Hugging Face Hackathon. Runs entirely on local models inside a Gra
|
|
| 57 |
```bash
|
| 58 |
git clone https://github.com/MomsVoiceAI/HuggingFace_Hack.git
|
| 59 |
cd HuggingFace_Hack
|
| 60 |
-
pip install
|
| 61 |
python app.py
|
| 62 |
# β http://localhost:7860
|
| 63 |
```
|
|
@@ -65,7 +66,10 @@ python app.py
|
|
| 65 |
## Project Structure
|
| 66 |
|
| 67 |
```
|
| 68 |
-
βββ app.py # Main Gradio app
|
|
|
|
|
|
|
|
|
|
| 69 |
βββ requirements.txt # Python deps
|
| 70 |
βββ stories/ # 10 cleaned public domain story texts (TTS-ready)
|
| 71 |
βββ story_downloader/ # Story acquisition & cleaning pipeline
|
|
@@ -74,6 +78,7 @@ python app.py
|
|
| 74 |
β βββ clean_stories.py # Strips Gutenberg boilerplate for TTS
|
| 75 |
βββ static/ # Custom CSS/JS for Stitch-style UI
|
| 76 |
βββ assets/covers/ # Story cover images
|
|
|
|
| 77 |
βββ mission.md # Product vision
|
| 78 |
βββ sprint.md # 2-day hackathon sprint plan
|
| 79 |
βββ tech_stack.md # Technical architecture
|
|
|
|
| 31 |
|
| 32 |
| Step | What Happens | Model |
|
| 33 |
|---|---|---|
|
| 34 |
+
| **Clone** | Parent records or uploads 15β30s of audio. Speaker embedding is extracted and cached server-side. | Qwen3-TTS-1.7B |
|
| 35 |
+
| **Listen** | Story plays in the cloned voice as interruptible sentence chunks. Falls back to Supertonic stock voice if no clone. | Qwen3-TTS-1.7B / Supertonic |
|
| 36 |
| **Ask** | Child taps Ask, narration pauses, child types or speaks a question. | Whisper-small (ASR, on-demand) |
|
| 37 |
+
| **Answer** | A short grounded answer is generated from the story context and spoken in the cloned voice. | Qwen2.5-3B-Instruct + Qwen3-TTS-1.7B |
|
| 38 |
| **Resume** | Story continues from where it left off. | Cached chunks |
|
| 39 |
|
| 40 |
## Models
|
| 41 |
|
| 42 |
| Model | Role | Size |
|
| 43 |
|---|---|---|
|
| 44 |
+
| [Qwen3-TTS-1.7B-Base](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-Base) | Zero-shot voice cloning + TTS | 1.7B params |
|
| 45 |
+
| [Supertonic TTS](https://huggingface.co/niclas-pham/supertonic-3) | Fast stock-voice TTS fallback | ONNX model |
|
| 46 |
| [Qwen2.5-3B-Instruct](https://huggingface.co/Qwen/Qwen2.5-3B-Instruct) | Story Q&A | 3B params (4-bit on T4) |
|
| 47 |
| [Whisper-small](https://huggingface.co/openai/whisper-small) | Child speech-to-text | 244M params (loaded on demand) |
|
| 48 |
|
|
|
|
| 58 |
```bash
|
| 59 |
git clone https://github.com/MomsVoiceAI/HuggingFace_Hack.git
|
| 60 |
cd HuggingFace_Hack
|
| 61 |
+
pip install -r requirements.txt
|
| 62 |
python app.py
|
| 63 |
# β http://localhost:7860
|
| 64 |
```
|
|
|
|
| 66 |
## Project Structure
|
| 67 |
|
| 68 |
```
|
| 69 |
+
βββ app.py # Main Gradio app (UI + wiring)
|
| 70 |
+
βββ voice_clone.py # Qwen3-TTS voice cloning + profile cache
|
| 71 |
+
βββ tts.py # Unified TTS interface (Qwen3 or Supertonic)
|
| 72 |
+
βββ inference.py # ASR (Whisper) + Q&A (Qwen2.5-3B-Instruct)
|
| 73 |
βββ requirements.txt # Python deps
|
| 74 |
βββ stories/ # 10 cleaned public domain story texts (TTS-ready)
|
| 75 |
βββ story_downloader/ # Story acquisition & cleaning pipeline
|
|
|
|
| 78 |
β βββ clean_stories.py # Strips Gutenberg boilerplate for TTS
|
| 79 |
βββ static/ # Custom CSS/JS for Stitch-style UI
|
| 80 |
βββ assets/covers/ # Story cover images
|
| 81 |
+
βββ test_modules/ # Component and integration tests
|
| 82 |
βββ mission.md # Product vision
|
| 83 |
βββ sprint.md # 2-day hackathon sprint plan
|
| 84 |
βββ tech_stack.md # Technical architecture
|
SPEC.md
CHANGED
|
@@ -20,17 +20,18 @@ Built for the Hugging Face Hackathon. Runs entirely on local models inside a Gra
|
|
| 20 |
|
| 21 |
| Step | What Happens | Model |
|
| 22 |
|---|---|---|
|
| 23 |
-
| **Clone** | Parent records or uploads 15β30s of audio.
|
| 24 |
-
| **Listen** | Story plays in the cloned voice as interruptible
|
| 25 |
-
| **Ask** | Child taps Ask, narration pauses, child types or speaks a question. | Whisper-small (ASR, on-demand) |
|
| 26 |
-
| **Answer** | A short grounded answer is generated from the story context and spoken in the cloned voice. | Qwen2.5-3B-Instruct +
|
| 27 |
| **Resume** | Story continues from where it left off. | Cached chunks |
|
| 28 |
|
| 29 |
## Models
|
| 30 |
|
| 31 |
| Model | Role | Size |
|
| 32 |
|---|---|---|
|
| 33 |
-
| [
|
|
|
|
| 34 |
| [Qwen2.5-3B-Instruct](https://huggingface.co/Qwen/Qwen2.5-3B-Instruct) | Story Q&A | 3B params (4-bit on T4) |
|
| 35 |
| [Whisper-small](https://huggingface.co/openai/whisper-small) | Child speech-to-text | 244M params (loaded on demand) |
|
| 36 |
|
|
@@ -46,7 +47,7 @@ Built for the Hugging Face Hackathon. Runs entirely on local models inside a Gra
|
|
| 46 |
```bash
|
| 47 |
git clone https://github.com/MomsVoiceAI/HuggingFace_Hack.git
|
| 48 |
cd HuggingFace_Hack
|
| 49 |
-
pip install
|
| 50 |
python app.py
|
| 51 |
# β http://localhost:7860
|
| 52 |
```
|
|
@@ -54,7 +55,10 @@ python app.py
|
|
| 54 |
## Project Structure
|
| 55 |
|
| 56 |
```
|
| 57 |
-
βββ app.py # Main Gradio app
|
|
|
|
|
|
|
|
|
|
| 58 |
βββ requirements.txt # Python deps
|
| 59 |
βββ stories/ # 10 cleaned public domain story texts (TTS-ready)
|
| 60 |
βββ story_downloader/ # Story acquisition & cleaning pipeline
|
|
|
|
| 20 |
|
| 21 |
| Step | What Happens | Model |
|
| 22 |
|---|---|---|
|
| 23 |
+
| **Clone** | Parent records or uploads 15β30s of audio. Speaker embedding is extracted and cached server-side. | Qwen3-TTS-1.7B (`voice_clone.py`) |
|
| 24 |
+
| **Listen** | Story plays in the cloned voice as interruptible sentence chunks. Falls back to Supertonic stock voice if no clone. | Qwen3-TTS-1.7B / Supertonic (`tts.py`) |
|
| 25 |
+
| **Ask** | Child taps Ask, narration pauses, child types or speaks a question. | Whisper-small (ASR, on-demand, `inference.py`) |
|
| 26 |
+
| **Answer** | A short grounded answer is generated from the story context and spoken in the cloned voice. | Qwen2.5-3B-Instruct + Qwen3-TTS-1.7B (`inference.py` + `tts.py`) |
|
| 27 |
| **Resume** | Story continues from where it left off. | Cached chunks |
|
| 28 |
|
| 29 |
## Models
|
| 30 |
|
| 31 |
| Model | Role | Size |
|
| 32 |
|---|---|---|
|
| 33 |
+
| [Qwen3-TTS-1.7B-Base](https://huggingface.co/Qwen/Qwen3-TTS-12Hz-1.7B-Base) | Zero-shot voice cloning + TTS | 1.7B params |
|
| 34 |
+
| [Supertonic TTS](https://huggingface.co/niclas-pham/supertonic-3) | Fast stock-voice TTS fallback | ONNX model |
|
| 35 |
| [Qwen2.5-3B-Instruct](https://huggingface.co/Qwen/Qwen2.5-3B-Instruct) | Story Q&A | 3B params (4-bit on T4) |
|
| 36 |
| [Whisper-small](https://huggingface.co/openai/whisper-small) | Child speech-to-text | 244M params (loaded on demand) |
|
| 37 |
|
|
|
|
| 47 |
```bash
|
| 48 |
git clone https://github.com/MomsVoiceAI/HuggingFace_Hack.git
|
| 49 |
cd HuggingFace_Hack
|
| 50 |
+
pip install -r requirements.txt
|
| 51 |
python app.py
|
| 52 |
# β http://localhost:7860
|
| 53 |
```
|
|
|
|
| 55 |
## Project Structure
|
| 56 |
|
| 57 |
```
|
| 58 |
+
βββ app.py # Main Gradio app (UI + wiring)
|
| 59 |
+
βββ voice_clone.py # Qwen3-TTS voice cloning + profile cache
|
| 60 |
+
βββ tts.py # Unified TTS interface (Qwen3 or Supertonic)
|
| 61 |
+
βββ inference.py # ASR (Whisper) + Q&A (Qwen2.5-3B-Instruct)
|
| 62 |
βββ requirements.txt # Python deps
|
| 63 |
βββ stories/ # 10 cleaned public domain story texts (TTS-ready)
|
| 64 |
βββ story_downloader/ # Story acquisition & cleaning pipeline
|
mission.md
CHANGED
|
@@ -29,9 +29,9 @@ Latency and natural interruption are part of the demo promise: the story should
|
|
| 29 |
## Hackathon Goal (2 days)
|
| 30 |
|
| 31 |
Ship a working Hugging Face Space that demonstrates:
|
| 32 |
-
1. **Voice cloning** β parent uploads/records a short audio clip
|
| 33 |
-
2. **Interruptible story narration** β
|
| 34 |
-
3. **Voice Q&A during narration** β child taps Ask, narration pauses, Qwen2.5-3B-Instruct answers from the story context, then
|
| 35 |
|
| 36 |
## Target Demo User
|
| 37 |
|
|
|
|
| 29 |
## Hackathon Goal (2 days)
|
| 30 |
|
| 31 |
Ship a working Hugging Face Space that demonstrates:
|
| 32 |
+
1. **Voice cloning** β parent uploads/records a short audio clip, Qwen3-TTS extracts speaker embedding
|
| 33 |
+
2. **Interruptible story narration** β Qwen3-TTS streams sentence-sized chunks in the cloned voice (Supertonic fallback for stock voice)
|
| 34 |
+
3. **Voice Q&A during narration** β child taps Ask, narration pauses, Qwen2.5-3B-Instruct answers from the story context, then Qwen3-TTS speaks the answer in the cloned voice
|
| 35 |
|
| 36 |
## Target Demo User
|
| 37 |
|
sprint.md
CHANGED
|
@@ -74,11 +74,11 @@ Ship a public Hugging Face Space: parent clones voice β story streams in that
|
|
| 74 |
|
| 75 |
| Risk | Mitigation |
|
| 76 |
|---|---|
|
| 77 |
-
|
|
| 78 |
-
| GPU OOM with TTS + Whisper + Qwen
|
| 79 |
-
| HF Space cold start too slow | Use persistent Space (not sleep);
|
|
|
|
| 80 |
| Qwen answer latency too slow | Keep answers to 1β2 sentences; cap story prompt length; cache answers per story/question pair |
|
| 81 |
-
| Story narration feels slow | Stream paragraph chunks; play the first chunk quickly; continue remaining chunks in the background; cache full narration |
|
| 82 |
| Interrupt/resume feels brittle | Track playback state, current chunk index, queued generation jobs, and cached next chunks |
|
| 83 |
| ASR adds too much delay | Let text questions bypass ASR; use Whisper-tiny/base or browser transcription for demo mode |
|
| 84 |
| Live demo fails | Pre-recorded backup video ready |
|
|
@@ -89,7 +89,10 @@ Ship a public Hugging Face Space: parent clones voice β story streams in that
|
|
| 89 |
|
| 90 |
```
|
| 91 |
VoiceClone/
|
| 92 |
-
βββ app.py # Main Gradio app (
|
|
|
|
|
|
|
|
|
|
| 93 |
βββ requirements.txt # Python deps
|
| 94 |
βββ README.md # HF Space description
|
| 95 |
βββ stories/ # 10 cleaned TTS-ready story texts
|
|
@@ -113,6 +116,7 @@ VoiceClone/
|
|
| 113 |
β βββ favicon.png
|
| 114 |
βββ assets/
|
| 115 |
β βββ covers/ # Story cover images
|
|
|
|
| 116 |
βββ mission.md # Product vision (this hackathon)
|
| 117 |
βββ tech_stack.md # Technical decisions
|
| 118 |
βββ sprint.md # This file
|
|
@@ -123,13 +127,15 @@ VoiceClone/
|
|
| 123 |
|
| 124 |
## Key Decisions (Locked)
|
| 125 |
|
| 126 |
-
- **No database** β stateless demo, voice
|
| 127 |
- **No auth** β open access for hackathon judges
|
| 128 |
-
- **Interruptible chunked streaming** β play
|
|
|
|
|
|
|
| 129 |
- **Qwen2.5-3B-Instruct for Q&A** β keeps story comprehension local while improving latency and GPU fit
|
| 130 |
- **Short grounded Q&A** β retrieve relevant story passages, cap answers to 1β2 sentences, then synthesize audio
|
| 131 |
- **Button-based interruption first** β tap Ask to pause narration; always-listening voice barge-in is out of scope for the hackathon
|
| 132 |
-
- **
|
| 133 |
|
| 134 |
---
|
| 135 |
|
|
|
|
| 74 |
|
| 75 |
| Risk | Mitigation |
|
| 76 |
|---|---|
|
| 77 |
+
| Qwen3-TTS voice quality insufficient | Fall back to longer reference audio (30s+); use Supertonic stock voice as backup |
|
| 78 |
+
| 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 |
|
| 79 |
+
| HF Space cold start too slow | Use persistent Space (not sleep); lazy-load models on first use rather than at startup |
|
| 80 |
+
| Qwen3-TTS synthesis too slow (~30s/sentence) | Stream sentence chunks with background thread; pre-generate next chunk while current plays; cache generated audio |
|
| 81 |
| Qwen answer latency too slow | Keep answers to 1β2 sentences; cap story prompt length; cache answers per story/question pair |
|
|
|
|
| 82 |
| Interrupt/resume feels brittle | Track playback state, current chunk index, queued generation jobs, and cached next chunks |
|
| 83 |
| ASR adds too much delay | Let text questions bypass ASR; use Whisper-tiny/base or browser transcription for demo mode |
|
| 84 |
| Live demo fails | Pre-recorded backup video ready |
|
|
|
|
| 89 |
|
| 90 |
```
|
| 91 |
VoiceClone/
|
| 92 |
+
βββ app.py # Main Gradio app (UI + wiring)
|
| 93 |
+
βββ voice_clone.py # Qwen3-TTS voice cloning + profile cache
|
| 94 |
+
βββ tts.py # Unified TTS interface (Qwen3 or Supertonic)
|
| 95 |
+
βββ inference.py # ASR (Whisper-small) + Q&A (Qwen2.5-3B-Instruct)
|
| 96 |
βββ requirements.txt # Python deps
|
| 97 |
βββ README.md # HF Space description
|
| 98 |
βββ stories/ # 10 cleaned TTS-ready story texts
|
|
|
|
| 116 |
β βββ favicon.png
|
| 117 |
βββ assets/
|
| 118 |
β βββ covers/ # Story cover images
|
| 119 |
+
βββ test_modules/ # Component and integration tests
|
| 120 |
βββ mission.md # Product vision (this hackathon)
|
| 121 |
βββ tech_stack.md # Technical decisions
|
| 122 |
βββ sprint.md # This file
|
|
|
|
| 127 |
|
| 128 |
## Key Decisions (Locked)
|
| 129 |
|
| 130 |
+
- **No database** β stateless demo, voice profiles held in server-side memory cache
|
| 131 |
- **No auth** β open access for hackathon judges
|
| 132 |
+
- **Interruptible chunked streaming** β play sentence chunks, pause on Ask, answer, then resume from the saved story position
|
| 133 |
+
- **Qwen3-TTS-1.7B for voice cloning** β zero-shot speaker embedding extraction from recorded audio; synthesis in cloned voice
|
| 134 |
+
- **Supertonic TTS as fallback** β fast stock voice when no voice profile exists
|
| 135 |
- **Qwen2.5-3B-Instruct for Q&A** β keeps story comprehension local while improving latency and GPU fit
|
| 136 |
- **Short grounded Q&A** β retrieve relevant story passages, cap answers to 1β2 sentences, then synthesize audio
|
| 137 |
- **Button-based interruption first** β tap Ask to pause narration; always-listening voice barge-in is out of scope for the hackathon
|
| 138 |
+
- **Modular design** β `voice_clone.py`, `tts.py`, `inference.py` separated from `app.py` for clarity
|
| 139 |
|
| 140 |
---
|
| 141 |
|
tech_stack.md
CHANGED
|
@@ -2,20 +2,22 @@
|
|
| 2 |
|
| 3 |
## Architecture (Hackathon-Simple)
|
| 4 |
|
| 5 |
-
|
| 6 |
|
| 7 |
```
|
| 8 |
-
βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 9 |
-
β Hugging Face Space (GPU: T4 or A10G)
|
| 10 |
-
β
|
| 11 |
-
β app.py (Gradio +
|
| 12 |
-
β βββ
|
| 13 |
-
β
|
| 14 |
-
β βββ
|
| 15 |
-
β βββ
|
| 16 |
-
β
|
| 17 |
-
β
|
| 18 |
-
βββ
|
|
|
|
|
|
|
| 19 |
```
|
| 20 |
|
| 21 |
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.
|
|
@@ -24,11 +26,12 @@ No database. No external storage. No external LLM API. Stories are flat files. A
|
|
| 24 |
|
| 25 |
| Component | Estimated VRAM | Notes |
|
| 26 |
|---|---|---|
|
| 27 |
-
|
|
| 28 |
-
| Qwen2.5-3B-Instruct (4-bit) | ~2 GB |
|
| 29 |
-
| Whisper-small | ~1 GB | Loaded on demand |
|
|
|
|
| 30 |
| Gradio + PyTorch overhead | ~1β2 GB | Runtime |
|
| 31 |
-
| **Total** | **~
|
| 32 |
|
| 33 |
**Concurrency:** Single-process Gradio serializes concurrent users. The hackathon demo is single-user. For multi-user, consider Gradio queue or separate worker processes.
|
| 34 |
|
|
@@ -53,17 +56,19 @@ No database. No external storage. No external LLM API. Stories are flat files. A
|
|
| 53 |
|
| 54 |
---
|
| 55 |
|
| 56 |
-
## 2. Voice Model (
|
| 57 |
|
| 58 |
| Aspect | Detail |
|
| 59 |
|---|---|
|
| 60 |
-
| Model | `Qwen/
|
| 61 |
-
| Size |
|
| 62 |
-
| Capability | Zero-shot voice cloning
|
| 63 |
-
| Input | Reference audio (β₯5s)
|
| 64 |
-
| Output | WAV audio in cloned voice (24 kHz
|
| 65 |
-
| Latency | ~
|
| 66 |
-
| Optimization | Cache
|
|
|
|
|
|
|
| 67 |
|
| 68 |
---
|
| 69 |
|
|
@@ -85,7 +90,7 @@ No database. No external storage. No external LLM API. Stories are flat files. A
|
|
| 85 |
| Model | `Qwen/Qwen2.5-3B-Instruct` |
|
| 86 |
| Why | Strong small-model instruction following with lower latency and VRAM pressure than an 8B-class model |
|
| 87 |
| Method | Current story position + relevant story passages + strict answer-from-story instruction + child question β short answer |
|
| 88 |
-
| Retrieval |
|
| 89 |
| Output cap | 1β2 child-friendly sentences, typically 40β80 new tokens |
|
| 90 |
| Runtime note | Use 4-bit/8-bit loading on T4; use bf16 or 8-bit on A10G for more headroom |
|
| 91 |
|
|
@@ -172,12 +177,12 @@ All other transitions are illegal. The UI should disable buttons that would trig
|
|
| 172 |
## 9. Local Dev
|
| 173 |
|
| 174 |
```bash
|
| 175 |
-
pip install
|
| 176 |
python app.py
|
| 177 |
# β http://localhost:7860
|
| 178 |
```
|
| 179 |
|
| 180 |
-
No Docker, no DB, no infra setup.
|
| 181 |
|
| 182 |
---
|
| 183 |
|
|
@@ -191,6 +196,10 @@ accelerate
|
|
| 191 |
bitsandbytes
|
| 192 |
soundfile
|
| 193 |
numpy
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
```
|
| 195 |
|
| 196 |
---
|
|
@@ -213,7 +222,7 @@ All in a `static/` folder loaded by gr.Server mount.
|
|
| 213 |
| Area | Critique | Upgrade |
|
| 214 |
|---|---|---|
|
| 215 |
| 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. |
|
| 216 |
-
| GPU fit |
|
| 217 |
-
| Latency |
|
| 218 |
| 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. |
|
| 219 |
| Dependencies | External LLM SDKs and API secrets are no longer aligned with the model choice. | Use local inference dependencies and optional HF authentication only. |
|
|
|
|
| 2 |
|
| 3 |
## Architecture (Hackathon-Simple)
|
| 4 |
|
| 5 |
+
Multi-module Gradio app. Everything runs in one process on a GPU-enabled HF Space.
|
| 6 |
|
| 7 |
```
|
| 8 |
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 9 |
+
β Hugging Face Space (GPU: T4 or A10G) β
|
| 10 |
+
β β
|
| 11 |
+
β app.py (Gradio UI + wiring) β
|
| 12 |
+
β βββ voice_clone.py β
|
| 13 |
+
β β βββ Qwen3-TTS-1.7B (voice clone + TTS) β
|
| 14 |
+
β βββ tts.py (unified TTS: Qwen3 or Supertonic) β
|
| 15 |
+
β β βββ Supertonic TTS (stock voice fallback) β
|
| 16 |
+
β βββ inference.py β
|
| 17 |
+
β β βββ Whisper-small (ASR for child questions) β
|
| 18 |
+
β β βββ Qwen2.5-3B-Instruct (story Q&A) β
|
| 19 |
+
β βββ stories/ (10 .txt files, public domain) β
|
| 20 |
+
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 21 |
```
|
| 22 |
|
| 23 |
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.
|
|
|
|
| 26 |
|
| 27 |
| Component | Estimated VRAM | Notes |
|
| 28 |
|---|---|---|
|
| 29 |
+
| Qwen3-TTS-1.7B (fp16) | ~3.5 GB | Loaded on demand when cloning starts |
|
| 30 |
+
| Qwen2.5-3B-Instruct (4-bit) | ~2 GB | Loaded on demand for Q&A |
|
| 31 |
+
| Whisper-small | ~1 GB | Loaded on demand for voice questions |
|
| 32 |
+
| Supertonic (ONNX) | ~0.3 GB | Loaded on demand as fallback |
|
| 33 |
| Gradio + PyTorch overhead | ~1β2 GB | Runtime |
|
| 34 |
+
| **Total** | **~8β9 GB** | ~7 GB headroom for KV cache and activations |
|
| 35 |
|
| 36 |
**Concurrency:** Single-process Gradio serializes concurrent users. The hackathon demo is single-user. For multi-user, consider Gradio queue or separate worker processes.
|
| 37 |
|
|
|
|
| 56 |
|
| 57 |
---
|
| 58 |
|
| 59 |
+
## 2. Voice Model (Qwen3-TTS-1.7B)
|
| 60 |
|
| 61 |
| Aspect | Detail |
|
| 62 |
|---|---|
|
| 63 |
+
| Model | `Qwen/Qwen3-TTS-12Hz-1.7B-Base` from Hugging Face Hub |
|
| 64 |
+
| Size | 1.7B params β fits on T4 in fp16 (~3.5 GB VRAM) |
|
| 65 |
+
| Capability | Zero-shot voice cloning via speaker embedding extraction + TTS synthesis |
|
| 66 |
+
| Input | Reference audio (β₯5s) for cloning; text + cached voice profile for synthesis |
|
| 67 |
+
| Output | WAV audio in cloned voice (24 kHz) |
|
| 68 |
+
| Latency | ~30s for speaker embedding extraction; ~25β50s per sentence synthesis on T4 |
|
| 69 |
+
| Optimization | Cache voice profile after recording (UUID-keyed server-side dict); generate story audio in sentence-level chunks streamed via background thread |
|
| 70 |
+
| Fallback | Supertonic TTS with stock voices (F1βF5, M1βM5) when no voice profile exists |
|
| 71 |
+
| Module | `voice_clone.py` (model + profile cache), `tts.py` (unified streaming API) |
|
| 72 |
|
| 73 |
---
|
| 74 |
|
|
|
|
| 90 |
| Model | `Qwen/Qwen2.5-3B-Instruct` |
|
| 91 |
| Why | Strong small-model instruction following with lower latency and VRAM pressure than an 8B-class model |
|
| 92 |
| Method | Current story position + relevant story passages + strict answer-from-story instruction + child question β short answer |
|
| 93 |
+
| Retrieval | Keyword overlap + proximity bonus: score each paragraph by shared words with the question plus a bonus for paragraphs near the current playback position; return top-3 as context. Full-story fallback when no context found. |
|
| 94 |
| Output cap | 1β2 child-friendly sentences, typically 40β80 new tokens |
|
| 95 |
| Runtime note | Use 4-bit/8-bit loading on T4; use bf16 or 8-bit on A10G for more headroom |
|
| 96 |
|
|
|
|
| 177 |
## 9. Local Dev
|
| 178 |
|
| 179 |
```bash
|
| 180 |
+
pip install -r requirements.txt
|
| 181 |
python app.py
|
| 182 |
# β http://localhost:7860
|
| 183 |
```
|
| 184 |
|
| 185 |
+
No Docker, no DB, no infra setup. Requires GPU for voice cloning and Q&A inference.
|
| 186 |
|
| 187 |
---
|
| 188 |
|
|
|
|
| 196 |
bitsandbytes
|
| 197 |
soundfile
|
| 198 |
numpy
|
| 199 |
+
supertonic>=1.3.1
|
| 200 |
+
onnxruntime>=1.18.0
|
| 201 |
+
huggingface-hub>=0.23.0
|
| 202 |
+
qwen-tts>=0.1.1
|
| 203 |
```
|
| 204 |
|
| 205 |
---
|
|
|
|
| 222 |
| Area | Critique | Upgrade |
|
| 223 |
|---|---|---|
|
| 224 |
| 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. |
|
| 225 |
+
| GPU fit | Qwen3-TTS-1.7B, Whisper-small, and Qwen2.5-3B-Instruct are a realistic fit for T4 with lazy loading and quantization, but concurrent use can pressure VRAM. | All models lazy-loaded on demand. Quantize Qwen Q&A on T4. Use A10G for demo headroom. |
|
| 226 |
+
| Latency | Qwen3-TTS synthesis takes ~25β50s per sentence, making full live narration impractical. | Cache voice profile after cloning. Stream sentence chunks. Pre-generate next chunk while current plays. Keep Q&A answers to 1β2 sentences. |
|
| 227 |
| 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. |
|
| 228 |
| Dependencies | External LLM SDKs and API secrets are no longer aligned with the model choice. | Use local inference dependencies and optional HF authentication only. |
|