fix(aquamarine): socket-activate whisper-asr with FreeBind

At boot whisper-asr could start before the LAN address was configured and
fail with "could not bind on any address". Let whisper-asr.socket bind it
with FreeBind and have uvicorn take fd 3, like the exporters.

Assisted-by: Claude Code (claude-opus-5-5)
This commit is contained in:
Ryan Yin authored and ryan4yin | 二花 committed 2026-11-01 11:55:14 -06:00
1 parent c732f3b9bb
commit 0f5ad1ad10
2 files changed
+12 -6

No files matched your search

+10 -3
View File
@@ -66,17 +66,24 @@ in
{
# vinput on the desktop sends raw PCM here and gets text back; the endpoint is
# the OpenAI transcription API, so any client of that shape works.
# FreeBind: the LAN address may not exist yet at boot.
systemd.sockets.whisper-asr = {
wantedBy = [ "sockets.target" ];
listenStreams = [ "${ipv4}:${toString port}" ];
socketConfig.FreeBind = true;
};
systemd.services.whisper-asr = {
description = "OpenAI-compatible Whisper transcription service (Intel NPU)";
# Start eagerly so the ~70 s NPU compile does not land on the first request.
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
requires = [ "whisper-asr.socket" ];
after = [ "whisper-asr.socket" ];
environment = {
WHISPER_MODEL_DIR = "${whisperModel}";
WHISPER_MODEL_NAME = "whisper-large-v3-turbo";
WHISPER_DEVICE = "NPU";
WHISPER_HOST = ipv4;
WHISPER_PORT = toString port;
# Compiling the graph for the NPU takes ~70 s; cache it so restarts and
# reboots reuse the compiled blob instead of paying that again.
OV_CACHE_DIR = "/var/cache/whisper-asr";
+2 -3
View File
@@ -27,8 +27,6 @@ DEVICE = os.environ.get("WHISPER_DEVICE", "NPU")
# Empty auto-detects the language per request; set it to pin one language.
DEFAULT_LANGUAGE = os.environ.get("WHISPER_LANGUAGE") or ""
CACHE_DIR = os.environ.get("OV_CACHE_DIR", "")
LISTEN_HOST = os.environ.get("WHISPER_HOST", "127.0.0.1")
LISTEN_PORT = int(os.environ.get("WHISPER_PORT", "18080"))
SAMPLE_RATE = 16000
MAX_AUDIO_SECONDS = int(os.environ.get("WHISPER_MAX_AUDIO_SECONDS") or "120")
@@ -197,4 +195,5 @@ async def transcriptions(
if __name__ == "__main__":
uvicorn.run(app, host=LISTEN_HOST, port=LISTEN_PORT, log_level="info")
# Listens on the socket systemd passes in (whisper-asr.socket).
uvicorn.run(app, fd=3, log_level="info")