TTS¶
Source: tts/
Pronunciation backend: provider contract, gTTS implementation, content-addressed
MP3 cache, live-set phrase collection, and TtsService. Cache layout and GC
rules are in Data and storage.
Playback stays on App session (speak); the language and
auto-speak used for a set are its effective overrides, with
TTS preferences as the app default. Screens must not
construct Audio or GttsProvider.
Provider¶
TTS provider contract and error types.
UI and TtsService depend only on TtsProvider. Swap GttsProvider
for ElevenLabs or OpenAI later without changing cache or playback.
TtsError ¶
TtsNetworkError ¶
TtsProvider ¶
Bases: ABC
Backend that turns text into MP3 bytes.
name and voice are part of the on-disk cache key so a later
provider does not replay audio generated by an older one.
Source code in src/learning_app/tts/provider.py
synthesize
abstractmethod
async
¶
Return MP3 bytes for text spoken in language.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Already-normalized phrase to speak. |
required |
language
|
str
|
IETF language tag such as |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
MP3 audio bytes. |
Raises:
| Type | Description |
|---|---|
TtsNetworkError
|
The remote service could not be reached. |
TtsError
|
Synthesis failed for another reason. |
Source code in src/learning_app/tts/provider.py
gTTS implementation of TtsProvider (Google Translate unofficial TTS).
GttsProvider ¶
Bases: TtsProvider
Generate MP3 audio through the gTTS library.
Calls are offloaded with asyncio.to_thread so Flet handlers stay
responsive. lang_check is disabled to avoid an extra network round
trip per word.
Source code in src/learning_app/tts/gtts_provider.py
synthesize
async
¶
Return MP3 bytes from gTTS in a worker thread.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Normalized phrase to speak. |
required |
language
|
str
|
IETF language tag accepted by gTTS (for example |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
MP3 audio bytes. |
Raises:
| Type | Description |
|---|---|
TtsNetworkError
|
The Translate endpoint failed or timed out. |
TtsError
|
gTTS rejected the input or returned empty audio. |
Source code in src/learning_app/tts/gtts_provider.py
Cache and texts¶
Content-addressed MP3 cache for generated pronunciation audio.
TtsCache ¶
Store MP3 files keyed by provider, voice, language, and text.
Files live under FilePathManager.get_tts_cache_dir(). Each object is
<hash[:2]>/<hash>.mp3 plus a JSON sidecar used by garbage collection
so recordings stay while some set still speaks that phrase in that language.
Source code in src/learning_app/tts/cache.py
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 | |
make_key
staticmethod
¶
Return a hex digest for the cache object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
str
|
Provider id such as |
required |
language
|
str
|
IETF language tag. |
required |
text
|
str
|
Phrase to speak (will be normalized). |
required |
voice
|
str
|
Optional voice id; empty for providers without voices. |
''
|
Returns:
| Type | Description |
|---|---|
str
|
SHA-256 hex digest used as the filename stem. |
Source code in src/learning_app/tts/cache.py
get_path ¶
Return the MP3 path when a non-empty file and sidecar exist.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
Digest from |
required |
Returns:
| Type | Description |
|---|---|
Path | None
|
Path to the MP3, or |
Source code in src/learning_app/tts/cache.py
put ¶
Write MP3 bytes and a sidecar describing the phrase.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key
|
str
|
Digest from |
required |
data
|
bytes
|
MP3 bytes. |
required |
text
|
str
|
Normalized phrase stored for garbage collection. |
required |
language
|
str
|
IETF language tag. |
required |
provider
|
str
|
Provider id that produced |
required |
voice
|
str
|
Optional voice id. |
''
|
Returns:
| Type | Description |
|---|---|
Path
|
Path to the written MP3. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
Source code in src/learning_app/tts/cache.py
garbage_collect ¶
Delete recordings whose phrase and language are no longer live.
Provider and voice are ignored: if a set still speaks that phrase in that language, every cached rendering of the pair is kept. A recording in another language is removed even when the same spelling remains.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
live_texts
|
Iterable[tuple[str, str]]
|
|
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of MP3 files removed. |
Source code in src/learning_app/tts/cache.py
Normalize phrases and collect live set texts for TTS cache GC.
normalize_text ¶
Strip and collapse whitespace so cache keys stay stable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Raw cell value from a learning set. |
required |
Returns:
| Type | Description |
|---|---|
str
|
Normalized phrase, or an empty string when nothing remains. |
Source code in src/learning_app/tts/texts.py
speakable_phrases ¶
Split a cell on / and return each normalized member.
Empty members are dropped. Order is preserved and duplicates are removed.
A cell such as go/goes/went becomes three phrases. A cell without
slashes is a one-item list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Raw cell value from a learning set. |
required |
Returns:
| Type | Description |
|---|---|
list[str]
|
Distinct normalized phrases to synthesize and keep in the TTS cache. |
Source code in src/learning_app/tts/texts.py
collect_speakable_texts ¶
Return phrases still spoken, paired with each set's TTS language.
Statistics columns and empty cells are ignored. Unreadable set files are
skipped so GC can still run after a partial catalog failure. The language
is the set's tts_language override, or the app language when that
cell is empty. The same spelling in two languages yields two pairs.
Returns:
| Type | Description |
|---|---|
set[tuple[str, str]]
|
Distinct |
set[tuple[str, str]]
|
|
Source code in src/learning_app/tts/texts.py
Service¶
Orchestrate TTS cache lookup, synthesis, and garbage collection.
TtsService ¶
Resolve a phrase to a cached MP3 path, generating it when missing.
One service instance should be reused for the app session. Playback stays outside this class so a later UI layer can feed the path into Flet Audio.
Source code in src/learning_app/tts/service.py
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 | |
resolve_path
async
¶
Return the MP3 path for text, synthesizing on a cache miss.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Phrase to speak. Whitespace is normalized. |
required |
language
|
str
|
IETF language tag passed to the provider. |
required |
Returns:
| Type | Description |
|---|---|
Path
|
Path to the MP3 on disk. |
Raises:
| Type | Description |
|---|---|
TtsError
|
|
Source code in src/learning_app/tts/service.py
resolve_paths
async
¶
Return an MP3 path for every slash-separated member of text.
go/goes/went yields three cached files so the UI can play each
form in order. Members share the cache with the same phrase in other
cells.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Cell value, possibly containing |
required |
language
|
str
|
IETF language tag passed to the provider. |
required |
Returns:
| Type | Description |
|---|---|
list[Path]
|
Paths in speak order, one per distinct member. |
Raises:
| Type | Description |
|---|---|
TtsError
|
|
Source code in src/learning_app/tts/service.py
get_mp3_bytes
async
¶
Return MP3 bytes for text, using the cache when possible.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
Phrase to speak. |
required |
language
|
str
|
IETF language tag. |
required |
Returns:
| Type | Description |
|---|---|
bytes
|
MP3 audio bytes. |
Source code in src/learning_app/tts/service.py
garbage_collect ¶
Remove cached audio for phrase/language pairs no set still speaks.
Returns:
| Type | Description |
|---|---|
int
|
Number of MP3 files removed. |
garbage_collect_tts_cache ¶
garbage_collect_tts_cache(
cache: TtsCache | None = None,
) -> int
Remove cached MP3s whose phrase and language no longer appear in any set.
Uses the default app TTS directory when cache is omitted. Safe to call
after deleting or rewriting set content. Do not call after progress-only
saves.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cache
|
TtsCache | None
|
Cache to prune. |
None
|
Returns:
| Type | Description |
|---|---|
int
|
Number of MP3 files removed. |