straylight: local Whisper ASR and Qwen3.8-Flash-Next uncensored
whisper.cpp large-v3-turbo on :11435 (CPU, OpenAI transcriptions path) so ASR does not take GTT from llama-server. Flash-Next is the cygnal IQ4_XS-NGQ4 GGUF (~98 GB, gfx1151), qwen4exp, mmproj pinned; unload Laguna before loading.
This commit is contained in:
@@ -76,6 +76,18 @@ let
|
||||
[qwen3.8-27b-uncensored]
|
||||
hf-repo = huihui-ai/Huihui-Qwen3.8-27B-abliterated-GGUF:Q4_K_L
|
||||
dedup-cache-models = true
|
||||
|
||||
; Qwen3.8-Flash-Next (~177B / 6B active, qwen4exp), orcarouter-abliterated,
|
||||
; cygnal IQ4_XS-NGQ4 GGUF (~98 GB) measured on gfx1151. Needs ~99 GB GTT
|
||||
; plus KV: unload Laguna first. 32k ctx / 1 slot so it fits beside the
|
||||
; 104 GiB TTM cap. mmproj is explicit; hf-repo alone misses it in router mode.
|
||||
[qwen3.8-flash-next-uncensored]
|
||||
hf-repo = cygnal/Qwen3.8-Flash-Next-Uncensored-IQ4XS-NGQ4-GGUF
|
||||
hf-file = Qwen3.8-Flash-Next-Uncensored-IQ4XS-NGQ4.gguf
|
||||
mmproj-url = https://huggingface.co/cygnal/Qwen3.8-Flash-Next-Uncensored-IQ4XS-NGQ4-GGUF/resolve/main/mmproj-Qwen3.8-Flash-Next-Uncensored-BF16.gguf
|
||||
parallel = 1
|
||||
ctx-size = 32768
|
||||
dedup-cache-models = true
|
||||
'';
|
||||
# `llama-models` shows what the router has resident; `llama-unload` frees every loaded
|
||||
# model (e.g. before a gaming session), or just the ones named on the command line.
|
||||
@@ -112,6 +124,25 @@ let
|
||||
'';
|
||||
llamaModelsCmd = pkgs.writeShellScriptBin "llama-models" "exec ${pkgs.python3}/bin/python3 ${llamaCtl} list \"$@\"";
|
||||
llamaUnloadCmd = pkgs.writeShellScriptBin "llama-unload" "exec ${pkgs.python3}/bin/python3 ${llamaCtl} unload \"$@\"";
|
||||
# CPU whisper.cpp: keep GTT for llama-server. large-v3-turbo is ~1.5 GB.
|
||||
whisperCpp = pkgsUnstable.whisper-cpp.override { withFFmpegSupport = true; };
|
||||
whisperModel = "/var/lib/whisper-server/models/ggml-large-v3-turbo.bin";
|
||||
whisperFetch = pkgs.writeShellScript "whisper-fetch-model" ''
|
||||
set -eu
|
||||
D=/var/lib/whisper-server/models
|
||||
mkdir -p "$D"
|
||||
F=${whisperModel}
|
||||
if [ ! -s "$F" ]; then
|
||||
echo "fetching whisper large-v3-turbo"
|
||||
${pkgs.curl}/bin/curl -L --retry 20 --retry-delay 10 --retry-all-errors \
|
||||
-o "$F.part" \
|
||||
https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-large-v3-turbo.bin
|
||||
mv "$F.part" "$F"
|
||||
fi
|
||||
'';
|
||||
whisperTranscribe = pkgs.writeShellScriptBin "whisper-transcribe" ''
|
||||
exec ${whisperCpp}/bin/whisper-cli -m ${whisperModel} --language auto -f "$@"
|
||||
'';
|
||||
in
|
||||
{
|
||||
imports = [
|
||||
@@ -168,6 +199,43 @@ in
|
||||
TimeoutStartSec = "600";
|
||||
};
|
||||
};
|
||||
|
||||
# Local ASR: OpenAI-compatible /v1/audio/transcriptions on 11435.
|
||||
# CPU-only so it does not contend with llama-server for GTT.
|
||||
users.users.whisper-server = {
|
||||
isSystemUser = true;
|
||||
group = "whisper-server";
|
||||
home = "/var/lib/whisper-server";
|
||||
};
|
||||
users.groups.whisper-server = {};
|
||||
systemd.services.whisper-server = {
|
||||
description = "whisper.cpp transcription server";
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
after = [ "network-online.target" ];
|
||||
wants = [ "network-online.target" ];
|
||||
serviceConfig = {
|
||||
ExecStartPre = whisperFetch;
|
||||
ExecStart = ''
|
||||
${whisperCpp}/bin/whisper-server \
|
||||
--model ${whisperModel} \
|
||||
--host 0.0.0.0 \
|
||||
--port 11435 \
|
||||
--inference-path /v1/audio/transcriptions \
|
||||
--language auto \
|
||||
--convert \
|
||||
--threads 8 \
|
||||
--no-gpu
|
||||
'';
|
||||
User = "whisper-server";
|
||||
Group = "whisper-server";
|
||||
StateDirectory = "whisper-server";
|
||||
WorkingDirectory = "/var/lib/whisper-server";
|
||||
Restart = "on-failure";
|
||||
RestartSec = "10s";
|
||||
TimeoutStartSec = "600";
|
||||
};
|
||||
};
|
||||
|
||||
# straylight is the unikernel host. The shared mcp.nix locks the agent
|
||||
# down with PrivateDevices=true, which hides /dev/kvm and /dev/net/tun.
|
||||
# Relax that here (only on straylight) so the agent can boot Nanos
|
||||
@@ -222,6 +290,8 @@ in
|
||||
inputs.herdr.packages.x86_64-linux.default
|
||||
llamaModelsCmd
|
||||
llamaUnloadCmd
|
||||
whisperTranscribe
|
||||
whisperCpp
|
||||
];
|
||||
|
||||
services.open-webui = {
|
||||
@@ -236,6 +306,9 @@ in
|
||||
OPENAI_API_BASE_URLS = "http://127.0.0.1:11434/v1";
|
||||
OPENAI_API_KEYS = "none";
|
||||
ENABLE_OLLAMA_API = "False";
|
||||
AUDIO_STT_ENGINE = "openai";
|
||||
AUDIO_STT_OPENAI_API_BASE_URL = "http://127.0.0.1:11435/v1";
|
||||
AUDIO_STT_OPENAI_API_KEY = "none";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -243,7 +316,7 @@ in
|
||||
networking.firewall.allowedTCPPorts = [ 53 443 8080 8443 9443 9444 9555 ];
|
||||
networking.firewall.allowedUDPPorts = [ 53 ];
|
||||
# llama.cpp OpenAI-compatible API: tailnet only (localhost is always allowed).
|
||||
networking.firewall.interfaces.tailscale0.allowedTCPPorts = [ 11434 ];
|
||||
networking.firewall.interfaces.tailscale0.allowedTCPPorts = [ 11434 11435 ];
|
||||
|
||||
# DNS: MCNS for internal zones, public resolvers as fallback.
|
||||
networking.nameservers = [
|
||||
|
||||
Reference in New Issue
Block a user