aboutsummaryrefslogtreecommitdiff
path: root/backends/__init__.py
diff options
context:
space:
mode:
Diffstat (limited to 'backends/__init__.py')
-rw-r--r--backends/__init__.py41
1 files changed, 34 insertions, 7 deletions
diff --git a/backends/__init__.py b/backends/__init__.py
index 629551e..6a23ab7 100644
--- a/backends/__init__.py
+++ b/backends/__init__.py
@@ -5,8 +5,15 @@ its setup wizard, its status detection, and the launch command it prints
once configured. This package aggregates them into a single registry so
``audiobook.py``'s TUI hub and future tools can iterate backends without
hardcoding their names: ``backends.detect_all()`` reports which are set
-up (and whether their server is currently running), and
-``backends.REGISTRY`` drives the hub's setup/configure menus.
+up (and whether their server is currently running), and the registry
+drives the hub's setup/configure menus.
+
+The registry is built lazily on the first call to ``get``/``detect_all``/
+``detect`` (not at package import time), because the backend modules pull
+in ``converter.tts`` and its third-party dependencies, which are only
+available inside the managed venv that ``audiobook.py`` bootstraps before
+importing them. ``backends.envs`` is imported during that bootstrap, so
+importing this package must stay cheap and dependency-free.
Adding a backend: create ``backends/<name>.py`` exposing
``detect() -> BackendStatus``, ``run_tui() -> int`` and
@@ -15,11 +22,26 @@ Adding a backend: create ``backends/<name>.py`` exposing
automatically.
"""
+import shlex
from dataclasses import dataclass, field
from typing import Callable, List, Optional
@dataclass
+class ServerSpec:
+ """One launchable server process for a backend.
+
+ A backend may expose more than one server (qwen runs CustomVoice and Base
+ on separate ports). ARGV is the exact command line the hub spawns (using
+ the managed venv's absolute binaries, so no shell activation is needed);
+ URL is the endpoint ``common.server_running`` probes to decide readiness.
+ """
+ name: str
+ url: str
+ argv: List[str]
+
+
+@dataclass
class BackendStatus:
"""How far a backend is set up, plus the command to start it.
@@ -29,8 +51,10 @@ class BackendStatus:
points at the right port). RUNNING means an external server is
currently accepting connections on the configured port (probed by
``backends.common.server_running``). DETAILS are short status lines for
- the hub. LAUNCH_HINT is the exact command the user runs to start the
- server.
+ the hub. LAUNCH_HINT is the human-readable command(s) the user runs to
+ start the server, derived from SERVERS by ``format_launch_hint``.
+ SERVERS is the machine-usable list of server processes the hub can
+ start/stop (empty when the backend is not yet configured).
"""
key: str
label: str
@@ -39,6 +63,7 @@ class BackendStatus:
running: bool = False
details: List[str] = field(default_factory=list)
launch_hint: str = ""
+ servers: List[ServerSpec] = field(default_factory=list)
@property
def ready(self) -> bool:
@@ -46,6 +71,11 @@ class BackendStatus:
return self.installed and self.configured
+def format_launch_hint(servers: List[ServerSpec]) -> str:
+ """Join a backend's server argvs into a copy-pasteable launch hint."""
+ return " ; ".join(shlex.join(s.argv) for s in servers)
+
+
@dataclass
class ConfigureAction:
"""A per-backend "configure" menu entry (e.g. "New server.json")."""
@@ -114,6 +144,3 @@ def detect(key: str) -> Optional[BackendStatus]:
"""Detect a single backend by key."""
info = get(key)
return info.detect() if info is not None else None
-
-
-_build_registry()