[Unit] Description=whisper.cpp STT server "%i" (CPU-only) — OpenAI-compatible /v1/audio/transcriptions Documentation=file:///home/anon/.config/whisper/README.md After=network-online.target Wants=network-online.target [Service] User=anon Group=anon WorkingDirectory=/ # TEMPLATE UNIT — one file, N instances. `systemctl start whisper@small` reads its model/port/language # from ~/.config/whisper/small.env. Deliberately not N copies of this unit: the --tmp-dir bug below had # to be found once and fixed once, and that only holds if there is exactly one ExecStart in the repo. EnvironmentFile=/home/anon/.config/whisper/%i.env # whisper-server's --tmp-dir defaults to "." — with WorkingDirectory=/ that means it tries to write # uploads and ffmpeg output into the filesystem root, and every request dies with # {"error":"FFmpeg conversion failed."} (yes, even plain wav: --convert pipes everything to ffmpeg) # RuntimeDirectory= creates /run/whisper-, owned by this user, wiped on stop. Per-instance so # two servers can never collide on a temp filename. RuntimeDirectory=whisper-%i RuntimeDirectoryMode=0700 # # ⚠⚠ --no-gpu IS LOAD-BEARING. The GPU on this box drives the display AND holds a 13-15 GB chat model; # ROCm does not OOM cleanly, it spills to GTT and freezes the whole PC. Whisper is CPU-only BY # DESIGN (same rule as the Qwen3-Embedding preset): 0 VRAM means it can never stack into an # overcommit, and it never evicts / gets evicted by the router. Do not remove. # --convert shells out to ffmpeg (webm/opus/ogg -> 16 kHz wav). This is the whole reason the Open WebUI # mic button works — the browser records opus, whisper.cpp reads wav. # --inference-path puts the route exactly where OWUI posts (--request-path defaults to empty), so a # client's base URL is http://192.168.0.204:/v1 . ExecStart=/usr/bin/whisper-server \ --model ${WHISPER_MODEL} \ --host 0.0.0.0 --port ${WHISPER_PORT} \ --inference-path /v1/audio/transcriptions \ --convert \ --tmp-dir /run/whisper-%i \ --no-gpu \ --threads 6 \ --language ${WHISPER_LANG} Restart=always RestartSec=2 # Yield to the llama.cpp router: its CPU-offloaded MoE experts (n-cpu-moe) want the same 6 cores. Nice=5 StandardOutput=journal StandardError=journal [Install] WantedBy=multi-user.target