diff options
| author | historia <historiavg@proton.me> | 2026-08-26 02:25:55 -0400 |
|---|---|---|
| committer | historia <historiavg@proton.me> | 2026-08-26 02:25:55 -0400 |
| commit | 8b5c8697740ff415cf7f1d03c9fb5a8c8851d420 (patch) | |
| tree | 28c0323c54c896af5f89fb34b89a62e0fe0df291 /app/backends/audiocpp/remote.py | |
| parent | acbd9ff2c91182d96c57ffb57bee6e9b3fcbcbd4 (diff) | |
| download | tts-audiobook-generator-8b5c8697740ff415cf7f1d03c9fb5a8c8851d420.tar.gz | |
refactor: audiocpp.py setup flow
Diffstat (limited to 'app/backends/audiocpp/remote.py')
| -rw-r--r-- | app/backends/audiocpp/remote.py | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/app/backends/audiocpp/remote.py b/app/backends/audiocpp/remote.py new file mode 100644 index 0000000..42b3872 --- /dev/null +++ b/app/backends/audiocpp/remote.py @@ -0,0 +1,59 @@ +"""Query a running audiocpp_server for its models and voices.""" + +import json +import urllib.request +from typing import Dict, List, Optional + +from .constants import FALLBACK_PORT + +def fetch_server_models(api_url: str) -> Optional[List[Dict[str, str]]]: + """List a running audiocpp_server's model entries via GET /v1/models. + + Returns ``[{id, family, task}, ...]`` — the same shape the converter's + client resolves at startup — or None when URL does not answer with a + valid document (wrong server, still starting, older audio.cpp). Used by + the hub to drive the convert menus against a remote server that has no + local server.json describing it. + """ + try: + with urllib.request.urlopen( + f"{api_url.rstrip('/')}/v1/models", timeout=10) as response: + payload = json.loads(response.read().decode("utf-8")) + except (OSError, ValueError): + # URLError/HTTPError/socket errors are OSErrors; a non-JSON body is + # a ValueError. Anything else means "not an audiocpp_server". + return None + entries = payload.get("data") if isinstance(payload, dict) else None + models: List[Dict[str, str]] = [] + for entry in entries or []: + if isinstance(entry, dict) and entry.get("id"): + models.append({ + "id": str(entry["id"]), + "family": str(entry.get("family") or ""), + "task": str(entry.get("task") or ""), + }) + return models + + +def fetch_server_voices(api_url: str, model_id: str) -> Optional[List[str]]: + """List a running audiocpp_server's voices for MODEL_ID. + + Queries ``GET /v1/audio/voices?model=<id>`` — the endpoint the converter + validates ``--voice`` against — and returns its voice-name list, or None + when the server cannot be queried. Lets the hub offer a remote server's + voices without reading its configuration locally. + """ + query = urllib.parse.urlencode({"model": model_id}) + try: + with urllib.request.urlopen( + f"{api_url.rstrip('/')}/v1/audio/voices?{query}", + timeout=10) as response: + payload = json.loads(response.read().decode("utf-8")) + except (OSError, ValueError): + return None + voices = payload.get("voices") if isinstance(payload, dict) else None + if not isinstance(voices, list): + return None + return [str(voice) for voice in voices] + + |
