jcode/skills/speech-synthesis/SKILL.md

3.9 KiB

name description
speech-synthesis 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 - 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

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).