aboutsummaryrefslogtreecommitdiff
path: root/app/converter/tts.py
diff options
context:
space:
mode:
authorhistoria <historiavg@proton.me>2026-08-24 14:13:06 -0400
committerhistoria <historiavg@proton.me>2026-08-24 14:13:06 -0400
commite7a3d65f68659d17f37b79e8bfefea19d7ac0648 (patch)
tree2c6d65391e2160ffb800eb237d5e25f842771a3e /app/converter/tts.py
parentdff790664389d60d16729092a58d9c0dc490a953 (diff)
downloadtts-audiobook-generator-e7a3d65f68659d17f37b79e8bfefea19d7ac0648.tar.gz
feat: audio.cpp unloads model before converting
Diffstat (limited to 'app/converter/tts.py')
-rw-r--r--app/converter/tts.py29
1 files changed, 29 insertions, 0 deletions
diff --git a/app/converter/tts.py b/app/converter/tts.py
index 842cc0c..a90dbbe 100644
--- a/app/converter/tts.py
+++ b/app/converter/tts.py
@@ -914,6 +914,35 @@ class AudioCppTTSClient(_BaseTTSClient):
print(f"[INFO] Sending instruction with every request: {self.instructions}")
print("[INFO] Its effect (style, emotion, delivery) depends on the "
"model family; models without instruction support ignore it.")
+ self._unload_server_models()
+
+ def _unload_server_models(self) -> None:
+ """Ask the server to unload every loaded model before generating.
+
+ Lazy-loaded entries stay resident until the server exits (unless its
+ max_loaded_models setting bounds residency), so switching between
+ configured models across runs can exhaust device memory. Unloading
+ first frees those leftovers; this run's model reloads transparently
+ on its first request. Failures only warn: an older server without
+ the endpoint, or a busy one, must not block a working setup.
+ """
+ request = urllib.request.Request(
+ f"{self.api_url}/v1/tasks/unload_all_models", data=b"",
+ method="POST", headers={"Content-Type": "application/json"})
+ try:
+ with urllib.request.urlopen(request, timeout=10) as response:
+ payload = json.loads(response.read().decode("utf-8"))
+ except Exception as exc:
+ print(f"[WARNING] Could not unload previously loaded models at "
+ f"{self.api_url}: {exc}")
+ return
+ unloaded = [entry for entry in (payload.get("unloaded") or [])
+ if isinstance(entry, str)]
+ if unloaded:
+ print(f"[OK] Unloaded {len(unloaded)} model(s) from server memory: "
+ f"{', '.join(unloaded)}")
+ else:
+ logger.debug("No loaded audio.cpp models to unload at %s", self.api_url)
def _get_json(self, path: str, timeout: int = 10) -> Dict[str, Any]:
"""GET a JSON document from the server."""