aboutsummaryrefslogtreecommitdiff
path: root/app/backends/audiocpp/build.py
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-27 17:03:57 -0400
committerhistoria <historiavg@proton.me>2026-08-27 17:03:57 -0400
commitcef2352a5e81b272d067c2c02eb9588e54edfcfd (patch)
tree83af416a82d9e854f44b6f3207eb8ea648b0896d /app/backends/audiocpp/build.py
parent6527240aa69a08f06e36e796818721abeec9f592 (diff)
downloadtts-audiobook-generator-cef2352a5e81b272d067c2c02eb9588e54edfcfd.tar.gz
feat: automatic updates added to configure backend menu
Diffstat (limited to 'app/backends/audiocpp/build.py')
-rw-r--r--app/backends/audiocpp/build.py114
1 files changed, 112 insertions, 2 deletions
diff --git a/app/backends/audiocpp/build.py b/app/backends/audiocpp/build.py
index e63a799..b850859 100644
--- a/app/backends/audiocpp/build.py
+++ b/app/backends/audiocpp/build.py
@@ -11,8 +11,8 @@ from typing import List, Optional
from backends import common, servers
from backends.common import APP_DIR
-from .catalog import _BACKEND_TOKEN_RE
-from .constants import AUDIOCPP_DIR_NAME, PATCH_DIR
+from .catalog import _BACKEND_TOKEN_RE, detect_backend, load_server_config
+from .constants import AUDIOCPP_DIR_NAME, BACKENDS, PATCH_DIR
def uninstall(*, emit=None, cancel=None) -> int:
"""Remove the audio.cpp backend entirely: stop its server, delete the checkout.
@@ -47,6 +47,116 @@ def uninstall(*, emit=None, cancel=None) -> int:
return 0
+def update(*, emit=None, cancel=None) -> int:
+ """Update the audio.cpp backend: refresh the checkout, rebuild if stale.
+
+ A managed server that is running is stopped first (best-effort): it
+ serves the binary whose sources are being replaced. Phases: stop
+ server / git update / rebuild — CANCEL is honored between phases only,
+ so a started phase always completes. The git update is a fetch plus
+ hard reset to origin's HEAD (see ``common.git_update``): everything
+ that matters lives untracked in the checkout (models, build trees,
+ server.json) and survives, while the vendored-ggml patch edit is
+ intentionally wiped — the rebuild re-applies it (the patch step is
+ idempotent and fails loudly when upstream re-shaped the file).
+
+ The rebuild target is the backend recorded in server.json, else the
+ one detected from existing build directories; when neither names one
+ (nothing was ever built) the update stops after the checkout refresh
+ — 'Build audio.cpp server' handles a first build. The rebuild itself
+ runs when the sources changed (HEAD moved) or the on-disk binary is
+ missing or older than HEAD's commit time — the latter heals an
+ interrupted (cancelled or failed) earlier rebuild, which leaves the
+ previous binary in place against already-updated sources. An
+ up-to-date checkout with a fresh binary costs one fetch. Returns the
+ exit code (130 when cancelled before a remaining phase).
+ """
+ # Only stop when a pid file exists: without one this tool never
+ # started the server, so the "not started by this tool" notice would
+ # be uninstall-time noise.
+ if servers.pid_for("audiocpp") is not None:
+ servers.stop("audiocpp")
+ if common.cancel_requested(cancel):
+ return 130
+ checkout = find_local_checkout()
+ if checkout is None:
+ print("[INFO] No audio.cpp checkout to update.")
+ return 0
+ head_before = common.git_head(checkout)
+ rc = common.git_update(checkout, emit=emit, cancel=cancel)
+ if rc != 0:
+ print(f"[WARNING] checkout update failed (exit {rc}); update "
+ f"manually: git -C {checkout} pull")
+ return rc
+ head_after = common.git_head(checkout)
+ if common.cancel_requested(cancel):
+ return 130
+ backend = _rebuild_backend(checkout)
+ if backend is None:
+ print("[INFO] audiocpp_server was never built for a known "
+ "backend; skipping the rebuild. 'Build audio.cpp server' "
+ "builds one.")
+ return 0
+ binary = built_server_binary(checkout, backend)
+ if not _rebuild_needed(checkout, binary,
+ moved=head_after not in (None, head_before)):
+ print(f"[OK] {checkout} is already at origin's HEAD with an "
+ "up-to-date audiocpp_server.")
+ return 0
+ if head_after in (None, head_before):
+ print(f"[INFO] audiocpp_server on disk is older than the "
+ f"checked-out sources (earlier build interrupted?); "
+ f"rebuilding for {backend}.")
+ else:
+ print(f"[OK] Updated {checkout} to {head_after[:12]}; rebuilding "
+ f"audiocpp_server for {backend}.")
+ build_rc = build_audiocpp(checkout, backend, emit=emit, cancel=cancel)
+ if build_rc != 0:
+ print(f"[WARNING] rebuild exited with code {build_rc}; see the "
+ "messages above (the build log under app/logs/ has the "
+ "full output). The binary on disk is now older than the "
+ "checked-out sources; re-running 'Update backends' will "
+ "retry the rebuild.")
+ else:
+ print("[OK] rebuild complete.")
+ return build_rc
+
+
+def _rebuild_needed(checkout: Path, binary: Optional[Path],
+ *, moved: bool) -> bool:
+ """True when audiocpp_server must be (re)built after an update.
+
+ True when the checkout moved, the binary is missing, its age cannot
+ be compared (no commit time), or it predates HEAD's commit — the
+ last case is what a cancelled or failed earlier rebuild leaves
+ behind (old binary, already-updated sources).
+ """
+ if moved or binary is None:
+ return True
+ commit_time = common.git_commit_time(checkout)
+ if commit_time is None:
+ return True
+ try:
+ return binary.stat().st_mtime <= commit_time
+ except OSError:
+ return True
+
+
+def _rebuild_backend(checkout: Path) -> Optional[str]:
+ """The inference backend to rebuild for after an update, or None.
+
+ server.json's recorded backend wins (it is what the managed server
+ launches); an existing build directory's token is the fallback for a
+ checkout that was built but never configured. None means neither
+ names a valid backend — there is no binary to keep fresh.
+ """
+ server_config = load_server_config(checkout / "server.json") or {}
+ recorded = server_config.get("backend")
+ if recorded in BACKENDS:
+ return recorded
+ return detect_backend(checkout)
+
+
def find_local_checkout() -> Optional[Path]:
"""Return the managed audio.cpp checkout at ``app/audio.cpp``.