aboutsummaryrefslogtreecommitdiff
path: root/app/backends
diff options
context:
space:
mode:
Diffstat (limited to 'app/backends')
-rw-r--r--app/backends/__init__.py9
-rwxr-xr-xapp/backends/audiocpp.py11
-rwxr-xr-xapp/backends/faster.py9
-rw-r--r--app/backends/qwen.py22
-rw-r--r--app/backends/servers.py16
5 files changed, 51 insertions, 16 deletions
diff --git a/app/backends/__init__.py b/app/backends/__init__.py
index ed772d4..9facd13 100644
--- a/app/backends/__init__.py
+++ b/app/backends/__init__.py
@@ -55,6 +55,13 @@ class BackendStatus:
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).
+
+ MANAGED says a running server was started by this tool: ``servers``
+ contains a spec whose pid file still names a live process (see
+ ``servers.manages``); when RUNNING but not MANAGED the hub tags the
+ status "[remote]". RUNNING_MODELS names which of a multi-server
+ backend's models answered (qwen: "Base" and/or "CustomVoice"), shown
+ in parentheses in the hub's status table.
"""
key: str
label: str
@@ -64,6 +71,8 @@ class BackendStatus:
details: List[str] = field(default_factory=list)
launch_hint: str = ""
servers: List[ServerSpec] = field(default_factory=list)
+ managed: bool = False
+ running_models: List[str] = field(default_factory=list)
@property
def ready(self) -> bool:
diff --git a/app/backends/audiocpp.py b/app/backends/audiocpp.py
index 2368ce7..673d344 100755
--- a/app/backends/audiocpp.py
+++ b/app/backends/audiocpp.py
@@ -47,6 +47,7 @@ from backends import (
ServerSpec,
common,
format_launch_hint,
+ servers,
)
from backends.common import (
APP_DIR,
@@ -1712,11 +1713,11 @@ def detect() -> BackendStatus:
details.append("not built — run setup to build audiocpp_server")
server_json = checkout / "server.json"
configured = server_json.exists()
- servers: List[ServerSpec] = []
+ specs: List[ServerSpec] = []
if configured:
details.append(f"config: {server_json}")
if built:
- servers = [ServerSpec(
+ specs = [ServerSpec(
"audiocpp", config.AUDIOCPP_API_URL,
[str(binary), "--config", str(server_json)])]
else:
@@ -1724,12 +1725,12 @@ def detect() -> BackendStatus:
f"audiocpp_server --config {server_json}")
else:
details.append("no server.json — run setup to configure models")
- if servers:
- launch = format_launch_hint(servers)
+ if specs:
+ launch = format_launch_hint(specs)
return BackendStatus("audiocpp", "audio.cpp", installed=built,
configured=configured, running=running,
details=details, launch_hint=launch,
- servers=servers)
+ servers=specs, managed=servers.manages(specs))
configure_actions: List[ConfigureAction] = [
diff --git a/app/backends/faster.py b/app/backends/faster.py
index 0d34a0f..77b9c8a 100755
--- a/app/backends/faster.py
+++ b/app/backends/faster.py
@@ -31,6 +31,7 @@ from backends import (
common,
envs,
format_launch_hint,
+ servers,
)
from backends.common import (
APP_DIR,
@@ -356,18 +357,18 @@ def detect() -> BackendStatus:
details.append(f"voices: {voices_json}" if voices_json.exists() else
"no voices.json — run setup to create one")
launch = ""
- servers: List[ServerSpec] = []
+ specs: List[ServerSpec] = []
if cloned and voices_json.exists():
argv = [str(envs.env_python()),
str(_checkout() / "examples" / "openai_server.py"),
"--voices", str(voices_json), "--port", str(_config_port())]
- servers = [ServerSpec("faster", config.FASTER_API_URL, argv)]
- launch = format_launch_hint(servers)
+ specs = [ServerSpec("faster", config.FASTER_API_URL, argv)]
+ launch = format_launch_hint(specs)
return BackendStatus("faster", "faster-qwen3-tts",
installed=installed and cloned,
configured=configured, running=running,
details=details, launch_hint=launch,
- servers=servers)
+ servers=specs, managed=servers.manages(specs))
def _run_voices_only_tui() -> int:
diff --git a/app/backends/qwen.py b/app/backends/qwen.py
index 21280a0..64f3996 100644
--- a/app/backends/qwen.py
+++ b/app/backends/qwen.py
@@ -27,6 +27,7 @@ from backends import (
common,
envs,
format_launch_hint,
+ servers,
)
from converter import config
from ui import tui
@@ -215,10 +216,15 @@ def detect() -> BackendStatus:
installed = _is_installed()
custom_port = _config_port(config.QWEN_API_URL, DEFAULT_CUSTOM_PORT)
clone_port = _config_port(config.CLONE_API_URL, DEFAULT_CLONE_PORT)
- # Running when either server is up — CustomVoice (speaker mode) or Base
- # (voice clone) each suffice for a conversion on their own.
- running = (common.server_running(config.QWEN_API_URL)
- or common.server_running(config.CLONE_API_URL))
+ # Probe each port separately: whichever answers names the running
+ # model — CustomVoice (speaker mode) or Base (voice clone); either
+ # suffices for a conversion on its own.
+ custom_up = common.server_running(config.QWEN_API_URL)
+ clone_up = common.server_running(config.CLONE_API_URL)
+ running = custom_up or clone_up
+ running_models = [name for name, up in
+ (("Base", clone_up), ("CustomVoice", custom_up))
+ if up]
details: List[str] = []
details.append("pip: installed" if installed else
"not installed — run setup to pip install qwen-tts")
@@ -226,7 +232,7 @@ def detect() -> BackendStatus:
details.append(f"Base (clone) port: {clone_port}")
details.append(f"speaker: {config.SPEAKER}")
demo = str(envs.env_script("qwen-tts-demo"))
- servers = [
+ specs = [
ServerSpec("qwen-custom", config.QWEN_API_URL,
[demo, QWEN_CUSTOMVOICE_MODEL, "--ip", "127.0.0.1",
"--port", str(custom_port)]),
@@ -237,8 +243,10 @@ def detect() -> BackendStatus:
return BackendStatus("qwen", "qwen-tts",
installed=installed, configured=installed,
running=running, details=details,
- launch_hint=format_launch_hint(servers),
- servers=servers)
+ launch_hint=format_launch_hint(specs),
+ servers=specs,
+ managed=servers.manages(specs),
+ running_models=running_models)
configure_actions: List[ConfigureAction] = [
diff --git a/app/backends/servers.py b/app/backends/servers.py
index a5a6829..63f37ce 100644
--- a/app/backends/servers.py
+++ b/app/backends/servers.py
@@ -233,6 +233,22 @@ def stop(name: str) -> bool:
return killed
+def manages(specs) -> bool:
+ """True when any SPEC in the list was started (and is kept alive) by us.
+
+ A server counts as ours when ``start`` recorded a pid file for it and
+ that pid is still alive — the same ownership rule ``stop`` applies
+ before refusing ("not started by this tool"). Used by the backends'
+ ``detect()`` so the hub's status table can tag an up server as
+ "[remote]" when it was launched outside this tool.
+ """
+ for spec in specs:
+ pid = pid_for(spec.name)
+ if pid is not None and _pid_alive(pid):
+ return True
+ return False
+
+
def pid_for(name: str):
"""Return the recorded pid for NAME, or None when no pid file exists."""
pid_file = _pid_path(name)