Better voices

This commit is contained in:
Andras Schmelczer 2026-07-15 22:42:27 +01:00
parent df02ffd9c0
commit 362b96b8ee
3 changed files with 145 additions and 21 deletions

View file

@ -47,6 +47,7 @@ import urllib.request
import wave
from dataclasses import dataclass
from pathlib import Path
from typing import Any
DEFAULT_SERVER = "http://host.docker.internal:8004"
@ -163,7 +164,7 @@ def _post(url: str, payload: dict, timeout: float) -> bytes:
return response.read()
def _get_json(url: str, timeout: float) -> dict:
def _get_json(url: str, timeout: float) -> Any:
with urllib.request.urlopen(url, timeout=timeout) as response:
return json.loads(response.read())
@ -438,14 +439,26 @@ def check_voice_exists(server: str, voice: str) -> None:
/tts does reject an unknown predefined voice, but this names the mistake
and lists the alternatives instead of surfacing a server stack trace.
Ask /get_predefined_voices, NOT /v1/audio/voices. The latter looks right but
answers a different, wider list (it also carries reference clips and the
bundled sample pack) and it lags behind uploads: on 2026-07-15 it omitted
French-F.wav and Hungarian-F.wav while /tts synthesized both happily. So it
fails a perfectly good voice and blames the storyboard. The filenames from
/get_predefined_voices are exactly the `predefined_voice_id` vocabulary.
"""
try:
voices = _get_json(f"{server}/v1/audio/voices", INFO_TIMEOUT_S).get("voices", [])
listed = _get_json(f"{server}/get_predefined_voices", INFO_TIMEOUT_S)
except (urllib.error.URLError, OSError, json.JSONDecodeError):
return # Non-fatal: /tts still validates the name.
voices = sorted(
str(entry["filename"])
for entry in listed
if isinstance(entry, dict) and entry.get("filename")
)
if voices and voice not in voices:
raise SystemExit(
f"[synth] unknown predefined voice {voice!r}. Available: {', '.join(sorted(voices))}"
f"[synth] unknown predefined voice {voice!r}. Available: {', '.join(voices)}"
)