tts_local operator: text→speech via Kokoro-82M on MLX (character voice templates)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
26c4cfd099
commit
f6626f0a06
19
server/operators/tts_local/manifest.json
Normal file
19
server/operators/tts_local/manifest.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"id": "tts_local",
|
||||
"name": "Speak (local, Kokoro)",
|
||||
"category": "audio",
|
||||
"description": "Text → speech WAV entirely on this Mac via Kokoro-82M on MLX (Apache 2.0, ungated, ~350MB first download). ~50 built-in voices spanning male/female US/UK = instant character voice templates. Faster than realtime, no API cost, no cloud.",
|
||||
"accepts": [],
|
||||
"produces": ["audio"],
|
||||
"resources": "gpu",
|
||||
"entry": "run.py",
|
||||
"python": "venvs/kokoro/bin/python",
|
||||
"params_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"text": {"type": "string", "default": "", "description": "The line to speak"},
|
||||
"voice": {"type": "string", "default": "af_heart", "description": "Kokoro voice id (af_/am_ = US female/male, bf_/bm_ = UK): af_heart, af_bella, af_nicole, am_adam, am_michael, am_onyx, bf_emma, bf_isabella, bm_george, bm_lewis, ..."},
|
||||
"speed": {"type": "number", "default": 1.0, "minimum": 0.5, "maximum": 2.0, "description": "Speaking rate"}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
server/operators/tts_local/run.py
Normal file
43
server/operators/tts_local/run.py
Normal file
@ -0,0 +1,43 @@
|
||||
import argparse
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
ap = argparse.ArgumentParser()
|
||||
ap.add_argument("--input", action="append", default=[])
|
||||
ap.add_argument("--outdir", required=True)
|
||||
ap.add_argument("--params", default="{}")
|
||||
a = ap.parse_args()
|
||||
p = json.loads(a.params)
|
||||
|
||||
text = (p.get("text") or "").strip()
|
||||
if not text:
|
||||
print("ERROR: text is required")
|
||||
sys.exit(1)
|
||||
|
||||
voice = p.get("voice", "af_heart")
|
||||
speed = float(p.get("speed", 1.0))
|
||||
outdir = Path(a.outdir)
|
||||
|
||||
cmd = [
|
||||
sys.executable, "-m", "mlx_audio.tts.generate",
|
||||
"--model", "prince-canuma/Kokoro-82M",
|
||||
"--text", text,
|
||||
"--voice", voice,
|
||||
"--speed", str(speed),
|
||||
"--file_prefix", str(outdir / f"tts_{voice}"),
|
||||
]
|
||||
t0 = time.time()
|
||||
r = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if r.stdout:
|
||||
print(r.stdout[-2000:])
|
||||
if r.stderr:
|
||||
print(r.stderr[-2000:], file=sys.stderr)
|
||||
|
||||
wavs = sorted(outdir.glob("*.wav"))
|
||||
if r.returncode != 0 or not wavs:
|
||||
print("ERROR: kokoro generation failed")
|
||||
sys.exit(1)
|
||||
print(f"done in {time.time() - t0:.1f}s: {', '.join(w.name for w in wavs)}")
|
||||
Loading…
Reference in New Issue
Block a user