85 lines
3.9 KiB
Markdown
85 lines
3.9 KiB
Markdown
---
|
|
name: speech-synthesis
|
|
description: >
|
|
Text-to-speech with Kokoro-82M (open weights, runs on CPU): synthesize WAV
|
|
files with a female or male voice, choose British/American English and other
|
|
languages, blend voices, set the speed, batch long texts, and play or embed
|
|
the result. Use for any TTS, voice-over, audiobook, speaking assistant or
|
|
"read this aloud" task.
|
|
---
|
|
|
|
# Speech synthesis with Kokoro
|
|
|
|
Kokoro-82M is a small, fast TTS model (Apache 2.0; ~330 MB download once).
|
|
Use the ready-made script [tts.py](./tts.py) - copy it into the project
|
|
(`cp <skill-dir>/tts.py .`) or import `synthesize()` from it.
|
|
|
|
## Setup
|
|
```
|
|
pip install kokoro soundfile # torch comes with it; first run downloads the weights
|
|
apt install espeak-ng / brew install espeak-ng # only for non-English languages
|
|
```
|
|
Python 3.10-3.12 recommended. CPU is fine: ~1 s of audio per 0.1-0.3 s compute.
|
|
A GPU is used automatically if torch sees one.
|
|
|
|
## Female and male voice - the two calls that matter
|
|
```python
|
|
from kokoro import KPipeline
|
|
import soundfile as sf, numpy as np
|
|
|
|
pipeline = KPipeline(lang_code='a') # 'a' American English, 'b' British English
|
|
|
|
# feminine voice
|
|
audio = np.concatenate([a for _, _, a in pipeline("Good morning! The report is ready.", voice='af_heart')])
|
|
sf.write('female.wav', audio, 24000)
|
|
|
|
# masculine voice
|
|
audio = np.concatenate([a for _, _, a in pipeline("Good morning! The report is ready.", voice='am_michael')])
|
|
sf.write('male.wav', audio, 24000)
|
|
```
|
|
`pipeline(text, voice=..., speed=1.0)` is a generator: one `(graphemes,
|
|
phonemes, audio)` item per chunk (chunks split at newlines by default). Audio
|
|
is a float32 array at **24 kHz**. Voices: `af_*`/`am_*` American female/male,
|
|
`bf_*`/`bm_*` British. Good defaults: `af_heart` (F), `am_michael` (M),
|
|
`bf_emma` (F, British), `bm_george` (M, British). `python tts.py --list-voices`
|
|
prints all.
|
|
|
|
## Script
|
|
```
|
|
python tts.py "Hello there." --out hello.wav # af_heart (female)
|
|
python tts.py "Hello there." --voice am_michael --out hello_m.wav
|
|
python tts.py --file chapter.txt --voice bf_emma --lang b --speed 0.9 --out chapter.wav
|
|
python tts.py "Blend." --voice af_heart,am_michael --out blend.wav # average of two voices
|
|
```
|
|
`synthesize(text, voice, lang, speed) -> (samples, 24000)` splits at blank
|
|
lines and sentence ends, inserts 250 ms pauses and concatenates - no length limit.
|
|
|
|
## Languages
|
|
Kokoro-82M v1.0: `a` American English, `b` British English, `e` Spanish,
|
|
`f` French, `h` Hindi, `i` Italian, `j` Japanese, `p` Brazilian Portuguese,
|
|
`z` Mandarin (`pip install misaki[ja]` / `misaki[zh]` for j/z). **No German.**
|
|
For German use Piper (`pip install piper-tts`, voice `de_DE-thorsten-medium`)
|
|
and say so in the summary instead of feeding German text to an English voice.
|
|
|
|
## Using the audio
|
|
- Play: `pip install sounddevice` then `sd.play(samples, 24000); sd.wait()`,
|
|
or `python tts.py ... --play`.
|
|
- MP3/OGG: write WAV, convert with `ffmpeg -i out.wav -b:a 96k out.mp3`.
|
|
- Web page: serve the WAV and use `<audio controls src="out.wav">`; for an
|
|
in-browser TTS without Python see kokoro-js (`kokoro-js` npm, WebGPU/WASM).
|
|
- Verify: check the duration (`len(samples)/24000`) is plausible for the text
|
|
(~2.5 words/s) and that `np.abs(samples).max() > 0.05` (not silence); for a
|
|
listening check write a short sample and tell the user the file name.
|
|
|
|
## Pitfalls
|
|
- First run is slow (weight download + model load); keep ONE `KPipeline` per
|
|
language and reuse it (`tts.py` caches it).
|
|
- Text with no sentence punctuation is spoken as one breathless chunk - add
|
|
periods or newlines.
|
|
- Numbers, dates and abbreviations are read as written; expand them in the
|
|
text ("3 km" -> "three kilometres") for clean output.
|
|
- Empty audio / `None` in the generator: the chunk was empty or unpronounceable
|
|
(only symbols). Skip it, don't crash.
|
|
- `numpy` must be < 2.0 for current kokoro releases (`pip install "numpy<2"` if
|
|
the import fails).
|