354cacd417
- engine_kokoro_tts.py: tts(text, voice, outfile) 0.5s gen 4-5x RTF M2 - ksay: drop-in say replacement, usage: ksay [-v voice] [-o file] "text" - install-ksay.sh: one-shot setup for macmini (pip + model 310MB + warm) - voices: af_bella (default), af_heart, am_adam, bf_emma etc - model ready after: ./install-ksay.sh (pre-downloads hexgrad/Kokoro-82M) - macmini: git pull gitea main && bash install-ksay.sh && ./ksay "hello"
33 lines
1.3 KiB
Python
33 lines
1.3 KiB
Python
"""engine_kokoro_tts.py — Kokoro 82M local TTS, drop-in say replacement, 4x RTF, offline"""
|
|
from __future__ import annotations
|
|
import argparse
|
|
from kokoro import KPipeline
|
|
import soundfile as sf
|
|
|
|
VOICES=["af_bella","af_heart","af_sarah","af_nova","af_sky","bf_emma","bf_isabella","am_adam","am_michael"]
|
|
_cache={}
|
|
def get_pipe(lang='a'):
|
|
if lang not in _cache:
|
|
_cache[lang]=KPipeline(lang_code=lang)
|
|
return _cache[lang]
|
|
def tts(text, voice="af_bella", outfile="/tmp/kokoro_out.wav"):
|
|
pipe=get_pipe('a')
|
|
for _,_,audio in pipe(text, voice=voice):
|
|
sf.write(outfile, audio, 24000)
|
|
return outfile
|
|
|
|
if __name__=="__main__":
|
|
ap=argparse.ArgumentParser(description="Kokoro 82M TTS — better than say -v Eddy")
|
|
ap.add_argument("text", nargs="?", default="Hello world, this is Kokoro eighty two M on Mac")
|
|
ap.add_argument("-v","--voice", default="af_bella", help="voice: af_bella, af_heart, am_adam etc")
|
|
ap.add_argument("-o","--out", default="/tmp/kokoro_out.wav")
|
|
ap.add_argument("--list-voices", action="store_true")
|
|
ap.add_argument("--play", action="store_true")
|
|
a=ap.parse_args()
|
|
if a.list_voices:
|
|
print("\n".join(VOICES)); raise SystemExit
|
|
out=tts(a.text, voice=a.voice, outfile=a.out)
|
|
print(f"wrote {out}")
|
|
if a.play:
|
|
import subprocess; subprocess.run(["afplay", out])
|