aboutsummaryrefslogtreecommitdiff
path: root/app/backends/audiocpp/status.py
blob: 9ccf8cc347ead92fe71fc86c181b53e641c04a47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
"""detect() — the BackendStatus report for the hub's backend menu."""

from typing import List, Tuple

from backends import (BackendStatus, ServerSpec, format_launch_hint,
                      probe, servers)
from converter import config
from . import build as _build
from . import models as _models

def detect() -> BackendStatus:
    """Detect how far audio.cpp is set up, plus the command to start it."""
    checkout = _build.find_local_checkout()
    details: List[str] = []
    launch = ""
    if checkout is None:
        # No local checkout: only a remote server can make this usable.
        remote = _detect_remote()
        return BackendStatus("audiocpp", "audio.cpp", installed=False,
                             configured=False, running=remote[0],
                             remote=remote[0], remote_urls=remote[1],
                             details=["not cloned — run setup to clone "
                                      "./app/audio.cpp"])
    details.append(f"checkout: {checkout}")
    binary = _build.find_audiocpp_server_bin(checkout)
    built = binary is not None
    if built:
        details.append(f"built: {binary}")
    else:
        details.append("not built — run setup to build audiocpp_server")
    server_json = checkout / "server.json"
    configured = server_json.exists()
    specs: List[ServerSpec] = []
    missing = _models.missing_model_entries(server_json) if configured else []
    if configured:
        details.append(f"config: {server_json}")
        if missing:
            # The config references model files that are not on disk; a
            # conversion would fail at model-load time, so say so now.
            details.extend(_models.model_install_hints(checkout, missing))
        if built:
            # Spawned from the checkout: audiocpp_server discovers
            # model_specs/<family>.json relative to its working directory.
            specs = [ServerSpec(
                "audiocpp", config.AUDIOCPP_API_URL,
                [str(binary), "--config", str(server_json)],
                cwd=checkout, identity=probe.IDENTITY_AUDIOCPP)]
        else:
            launch = (f"cd {checkout} && ./build/<platform>-<backend>-release"
                      f"/bin/audiocpp_server --config {server_json}")
    else:
        details.append("no server.json — run setup to configure models")
    if specs:
        launch = format_launch_hint(specs)
    managed = servers.manages(specs)
    remote_running, remote_urls = _detect_remote(managed)
    # A more specific "part-way set up" label than unavailable/installed:
    # cloned but never built, or built but not configured.
    partial = ""
    if not built:
        partial = "downloaded (not built)"
    elif not configured:
        partial = "built (not configured)"
    return BackendStatus("audiocpp", "audio.cpp", installed=built,
                         configured=configured,
                         running=managed or remote_running,
                         details=details, launch_hint=launch,
                         servers=specs, managed=managed,
                         remote=remote_running, remote_urls=remote_urls,
                         models_missing=bool(missing), partial=partial)


def _detect_remote(managed: bool = False) -> Tuple[bool, dict]:
    """Detect an externally-run audiocpp_server at the remote URL.

    Returns ``(running, {spec_name: url})``. The remote URL is probed only
    when configured (non-empty); a server answering there is ignored when it
    is this tool's own managed server (remote URL == local URL and our pid is
    still alive) — that instance is already reported as "[local]".
    """
    url = (config.AUDIOCPP_REMOTE_URL or "").strip()
    if not url:
        return False, {}
    if managed and probe.same_endpoint(url, config.AUDIOCPP_API_URL):
        return False, {}
    if probe.identify_server(url) == probe.IDENTITY_AUDIOCPP:
        return True, {"audiocpp": url}
    return False, {}