minhahwang Copilot commited on
Commit
e308c53
Β·
1 Parent(s): 215fff0

docs: update all docs to reflect Qwen3-TTS architecture

Browse files

Update 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>

Files changed (5) hide show
  1. README.md +11 -6
  2. SPEC.md +11 -7
  3. mission.md +3 -3
  4. sprint.md +14 -8
  5. 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. Voice representation is computed and cached. | QWEN-TTS-0.6B |
35
- | **Listen** | Story plays in the cloned voice as interruptible paragraph chunks. | QWEN-TTS-0.6B |
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 + QWEN-TTS-0.6B |
38
  | **Resume** | Story continues from where it left off. | Cached chunks |
39
 
40
  ## Models
41
 
42
  | Model | Role | Size |
43
  |---|---|---|
44
- | [QWEN-TTS-0.6B](https://huggingface.co/Qwen/Qwen-TTS-0.6B) | Voice cloning + TTS | 0.6B params |
 
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 gradio transformers torch accelerate bitsandbytes soundfile numpy
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. Voice representation is computed and cached. | QWEN-TTS-0.6B |
24
- | **Listen** | Story plays in the cloned voice as interruptible paragraph chunks. | QWEN-TTS-0.6B |
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 + QWEN-TTS-0.6B |
27
  | **Resume** | Story continues from where it left off. | Cached chunks |
28
 
29
  ## Models
30
 
31
  | Model | Role | Size |
32
  |---|---|---|
33
- | [QWEN-TTS-0.6B](https://huggingface.co/Qwen/Qwen-TTS-0.6B) | Voice cloning + TTS | 0.6B params |
 
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 gradio transformers torch accelerate bitsandbytes soundfile numpy
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** β€” QWEN-TTS-0.6B streams paragraph-sized chunks in the cloned voice
34
- 3. **Voice Q&A during narration** β€” child taps Ask, narration pauses, Qwen2.5-3B-Instruct answers from the story context, then QWEN-TTS-0.6B speaks the answer in the cloned voice
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
- | QWEN-TTS-0.6B doesn't clone well | Fall back to longer reference audio (30s+); or use CosyVoice as backup model |
78
- | GPU OOM with TTS + Whisper + Qwen + Gradio | Use 4-bit/8-bit Qwen loading on T4; prefer A10G for the live demo; load Whisper only on demand; use `whisper-tiny` if needed |
79
- | HF Space cold start too slow | Use persistent Space (not sleep); preload model in `app.py` global scope |
 
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 (all logic)
 
 
 
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 samples held in memory/session
127
  - **No auth** β€” open access for hackathon judges
128
- - **Interruptible chunked streaming** β€” play paragraph chunks quickly, pause on Ask, answer, then resume from the saved story position
 
 
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
- - **Single `app.py`** β€” keep it simple, refactor later
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
- Single Python file 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 + gr.Server) β”‚
12
- β”‚ β”œβ”€β”€ UI: Stitch-styled tabs/cards β”‚
13
- β”‚ β”œβ”€β”€ QWEN-TTS-0.6B (voice clone + chunks) β”‚
14
- β”‚ β”œβ”€β”€ Whisper-small (ASR for child questions) β”‚
15
- β”‚ └── Qwen2.5-3B-Instruct (story Q&A) β”‚
16
- β”‚ β”‚
17
- β”‚ stories/ (3–5 .txt files, public domain) β”‚
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
- | QWEN-TTS-0.6B | ~1.2 GB | Always loaded |
28
- | Qwen2.5-3B-Instruct (4-bit) | ~2 GB | Always loaded |
29
- | Whisper-small | ~1 GB | Loaded on demand |
 
30
  | Gradio + PyTorch overhead | ~1–2 GB | Runtime |
31
- | **Total** | **~5–6 GB** | ~10 GB headroom for KV cache and activations |
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 (QWEN-TTS-0.6B)
57
 
58
  | Aspect | Detail |
59
  |---|---|
60
- | Model | `Qwen/Qwen-TTS-0.6B` from Hugging Face Hub |
61
- | Size | 0.6B params β€” fits comfortably on T4 (16GB VRAM) |
62
- | Capability | Zero-shot voice cloning + TTS from text chunks |
63
- | Input | Reference audio (β‰₯5s) + target text |
64
- | Output | WAV audio in cloned voice (24 kHz, 16-bit, mono) |
65
- | Latency | ~3–5s for a paragraph on T4 |
66
- | Optimization | Cache the voice representation after recording; generate story audio in interruptible paragraph chunks |
 
 
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 | 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. |
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 gradio transformers torch accelerate bitsandbytes soundfile numpy
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 | 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. |
217
- | 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. |
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. |