03-oct: superguardado automático
This commit is contained in:
108
scripts/voz_mensaje.py
Normal file
108
scripts/voz_mensaje.py
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""voz_mensaje.py — Enrutador de voz para los mensajes del asistente (OpenCode).
|
||||||
|
|
||||||
|
Genera y reproduce un mensaje hablado con VoiceStudio (http://127.0.0.1:3900)
|
||||||
|
eligiendo el perfil de voz segun el TIPO de mensaje:
|
||||||
|
|
||||||
|
default -> Carolina (10466680) Mensajes trascendentes de OpenCode (por defecto)
|
||||||
|
biblioteca -> Juanjo (4f18d2df) Mensajes de la biblioteca Prolongo
|
||||||
|
critico -> Abuelo (9f83c527) Mensajes importantes / criticos
|
||||||
|
|
||||||
|
Uso:
|
||||||
|
python voz_mensaje.py "texto a decir" [--tipo default|biblioteca|critico]
|
||||||
|
[--idioma es] [--no-play]
|
||||||
|
|
||||||
|
Proyecto: INFRAESTRUCTURA. Perfiles de voz locales de VoiceStudio.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
BASE = os.environ.get("VOICESTUDIO_BASE", "http://127.0.0.1:3900")
|
||||||
|
|
||||||
|
# tipo -> (profile_id, nombre)
|
||||||
|
PROFILES = {
|
||||||
|
"default": ("10466680", "Carolina"),
|
||||||
|
"biblioteca": ("4f18d2df", "Juanjo"),
|
||||||
|
"critico": ("9f83c527", "Abuelo"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _get_profile(pid: str) -> dict:
|
||||||
|
"""Metadatos del perfil (para reutilizar su ref_text al generar)."""
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(f"{BASE}/profiles/{pid}", timeout=30) as r:
|
||||||
|
return json.loads(r.read())
|
||||||
|
except Exception:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def generar(texto: str, tipo: str = "default", idioma: str = "es") -> str:
|
||||||
|
"""Sintetiza `texto` con el perfil del `tipo` y devuelve la ruta del WAV."""
|
||||||
|
pid, nombre = PROFILES.get(tipo, PROFILES["default"])
|
||||||
|
prof = _get_profile(pid)
|
||||||
|
|
||||||
|
campos = {
|
||||||
|
"text": texto,
|
||||||
|
"language": idioma,
|
||||||
|
"profile_id": pid,
|
||||||
|
"stream": "false",
|
||||||
|
}
|
||||||
|
# Los perfiles clone necesitan su transcripcion de referencia para generar.
|
||||||
|
if prof.get("ref_text"):
|
||||||
|
campos["ref_text"] = prof["ref_text"]
|
||||||
|
|
||||||
|
data = urllib.parse.urlencode(campos).encode()
|
||||||
|
req = urllib.request.Request(
|
||||||
|
f"{BASE}/generate", data=data,
|
||||||
|
headers={"Content-Type": "application/x-www-form-urlencoded"},
|
||||||
|
)
|
||||||
|
with urllib.request.urlopen(req, timeout=300) as r:
|
||||||
|
wav = r.read()
|
||||||
|
|
||||||
|
out_dir = os.path.join(os.path.expanduser("~"), "Documents", "voz_mensajes")
|
||||||
|
os.makedirs(out_dir, exist_ok=True)
|
||||||
|
out = os.path.join(out_dir, f"msg_{tipo}.wav")
|
||||||
|
with open(out, "wb") as f:
|
||||||
|
f.write(wav)
|
||||||
|
print(f"[voz_mensaje] {nombre} ({tipo}) -> {out}")
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def reproducir(path: str) -> None:
|
||||||
|
"""Reproduce el WAV de forma sincrona (Windows)."""
|
||||||
|
import winsound
|
||||||
|
winsound.PlaySound(path, winsound.SND_FILENAME)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
ap = argparse.ArgumentParser(description="Enrutador de voz para mensajes del asistente.")
|
||||||
|
ap.add_argument("texto", help="Texto a decir")
|
||||||
|
ap.add_argument("--tipo", choices=list(PROFILES), default="default")
|
||||||
|
ap.add_argument("--idioma", default="es")
|
||||||
|
ap.add_argument("--no-play", action="store_true", help="Solo generar, no reproducir")
|
||||||
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
path = generar(args.texto, args.tipo, args.idioma)
|
||||||
|
except Exception as e: # noqa: BLE001
|
||||||
|
print(f"[voz_mensaje] ERROR: {e}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
if not args.no_play:
|
||||||
|
try:
|
||||||
|
reproducir(path)
|
||||||
|
except Exception as e: # noqa: BLE001
|
||||||
|
print(f"[voz_mensaje] ERROR reproduciendo: {e}", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
Reference in New Issue
Block a user