83 lines
3.1 KiB
Python
83 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
tts_eval.py — Genera la MISMA frase de feadulta con varias voces/modelos TTS para
|
|
compararlas (evaluación de voz, issue #76). Incluye:
|
|
- edge-tts Ximena (referencia, gratis, ya la usamos) — siempre.
|
|
- Modelos premium vía Hugging Face Inference Providers (consume crédito HF) — opcional.
|
|
|
|
Objetivo: ELEGIR voz. Para producción en masa NO se usa HF (sale caro); el modelo
|
|
abierto ganador se corre en LOCAL (RTX 5060 Ti) gratis. Ver análisis en #76.
|
|
|
|
Uso:
|
|
# Solo la referencia local (gratis):
|
|
python3 scripts/tts_eval.py
|
|
# Con modelos HF (necesita token; gasta unos céntimos del crédito):
|
|
HF_TOKEN=hf_xxx python3 scripts/tts_eval.py --hf
|
|
|
|
Salida: ./tts-eval/<nombre>.mp3 (escúchalos y elige).
|
|
"""
|
|
from __future__ import annotations
|
|
import argparse, os, subprocess, sys
|
|
from pathlib import Path
|
|
|
|
SAMPLE = (
|
|
"Bienvenido a Fe Adulta. La humanidad abriga una esperanza: verse liberada de la "
|
|
"esclavitud y alcanzar la libertad de los hijos de Dios. Una fe adulta es una fe "
|
|
"personal, valiente, sin miedos infantiles. Detente un instante y respira."
|
|
)
|
|
OUT = Path(__file__).resolve().parent.parent / "tts-eval"
|
|
EDGE = os.path.expanduser("~/.hermes/hermes-agent/venv/bin/edge-tts")
|
|
|
|
# Candidatos vía HF Inference Providers (provider, model). Verifica disponibilidad en la
|
|
# pestaña "Inference Providers" de cada modelo en huggingface.co — el routing cambia.
|
|
HF_CANDIDATES = [
|
|
("fal-ai", "fal-ai/f5-tts"),
|
|
("fal-ai", "fal-ai/chatterbox/text-to-speech"),
|
|
("hf-inference", "myshell-ai/MeloTTS-Spanish"),
|
|
]
|
|
|
|
|
|
def edge_samples():
|
|
OUT.mkdir(exist_ok=True)
|
|
for voz in ("es-ES-XimenaNeural", "es-ES-ElviraNeural", "es-MX-JorgeNeural"):
|
|
dst = OUT / f"edge-{voz}.mp3"
|
|
print(f"edge-tts {voz} ...", flush=True)
|
|
subprocess.run([EDGE, "--voice", voz, "--text", SAMPLE, "--write-media", str(dst)],
|
|
capture_output=True)
|
|
print(f" -> {OUT}")
|
|
|
|
|
|
def hf_samples():
|
|
try:
|
|
from huggingface_hub import InferenceClient
|
|
except ImportError:
|
|
sys.exit("Falta huggingface_hub: pip install huggingface_hub")
|
|
token = os.environ.get("HF_TOKEN")
|
|
if not token:
|
|
sys.exit("Define HF_TOKEN para usar --hf")
|
|
OUT.mkdir(exist_ok=True)
|
|
for provider, model in HF_CANDIDATES:
|
|
name = model.replace("/", "_")
|
|
try:
|
|
client = InferenceClient(provider=provider, api_key=token)
|
|
audio = client.text_to_speech(SAMPLE, model=model)
|
|
dst = OUT / f"hf-{name}.mp3"
|
|
dst.write_bytes(audio)
|
|
print(f"OK {provider}:{model} -> {dst.name}")
|
|
except Exception as exc: # noqa: BLE001
|
|
print(f"FALLO {provider}:{model} -> {exc}")
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--hf", action="store_true", help="También generar con modelos HF (gasta crédito).")
|
|
args = ap.parse_args()
|
|
edge_samples()
|
|
if args.hf:
|
|
hf_samples()
|
|
print("\nEscucha los .mp3 en", OUT, "y elige. Para producción: correr el modelo abierto ganador en local.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|