Files
ARIA-AGENT/xtts/bootstrap.sh
T
duffyduckandClaude Opus 5.5 9be14eef5e fix(diagnostic): Karten kommen im Browser an, lokales Modell springt nicht zurueck
1. "Die LLM-Box meldet noch keine Karten": die Box schickte die Karten-
   Belegung, aber workerList() im Diagnostic-Server gibt nur eine feste
   Feldliste an den Browser — slots stand nicht drauf. Meine UI-Tests haben
   die Flotte direkt im Browser gesetzt und sind an genau dieser Stelle
   vorbeigelaufen. Jetzt Ende-zu-Ende getestet: echter Diagnostic-Server +
   RVS + Box-Meldung → Browser (per DevTools-Protokoll gelesen).

2. Lokales Modell sprang auf "Qwen3 8B" zurueck: die Auswahl wurde gespeichert,
   aber die Seite behielt intern das alte Modell und stellte das Dropdown beim
   naechsten Lebenszeichen der Box (10 s) darauf zurueck. Dazu wie gewuenscht
   umgebaut: nur Modelle, die im Cluster geladen sind, jedes einmal, ohne
   Karte. Ist das gewaehlte gerade nirgends geladen: "(offline)" — geht
   automatisch weiter, sobald eine Box es hat. Nichts da: "kein Modell
   verfuegbar". Waehrend die Auswahl offen ist, wird nicht umgebaut.

3. "Bereit", aber Karte leer: der llm-adapter meldet pro Karte den belegten
   VRAM. Laeuft ein Modell "ready" und die Karte bleibt unter 400 MB, rechnet
   llama.cpp auf der CPU (Treiber zu alt fuer das CUDA im Image) — das sagt
   llama.cpp nicht nach aussen. Diagnostic zeigt es jetzt in Flotte,
   LLM-Karten und Modell-Auswahl ("laeuft auf der CPU").

4. bootstrap.sh: der normale Lauf meldete "✓ Treiber aktiv", auch wenn er fuer
   das LLM zu alt ist. Jetzt Warnung mit Version und dem Befehl
   (--upgrade-driver), wenn das LLM-Profil aktiv ist.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 02:11:02 +02:00

340 lines
16 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# ARIA KI-Box (gpubox) Bootstrap — frisches Debian Trixie → startklarer
# GPU-Satelliten-Host fuer den xtts-Stack (Voxtral/Whisper STT, F5-TTS, lokales LLM).
#
# Ablauf nach `git clone`:
# cd ARIA-AGENT/xtts
# sudo ./bootstrap.sh # richtet Treiber + Docker + NVIDIA-Toolkit ein
# # (falls Treiber frisch installiert: einmal `sudo reboot`, dann Script erneut)
# sudo ./bootstrap.sh --up # dazu: xtts-Stack (Whisper+F5+LLM) hochziehen
#
# Optionen:
# --up am Ende den xtts-Stack starten (Default-Profil, OHNE voxtral)
# --upgrade-driver NVIDIA-Treiber aus NVIDIAs eigener Paketquelle fuer Debian 13
# (Debian selbst hat max. 550 = CUDA 12.4 — zu alt fuer die
# aktuellen llama.cpp/llama-swap-Images, die CUDA 12.8/12.9
# brauchen; ohne Upgrade rechnet das LLM still auf der CPU).
# Spielt erst durch, zeigt den Plan, fragt nach. Danach REBOOT.
# Default-Bootstrap laesst den Treiber unangetastet.
# --yes bei --upgrade-driver nicht nachfragen
# --token <TOK> RVS_TOKEN in xtts/.env eintragen (alternativ: env RVS_TOKEN=...)
# --rvs-host <H> RVS_HOST setzen (Default aus .env.example)
#
# IDEMPOTENT: bereits erledigte Schritte werden uebersprungen. Nach dem
# Treiber-Reboot einfach nochmal ausfuehren — der Rest laeuft dann durch.
#
set -euo pipefail
# ── CLI ──
DO_UP=0
DO_UPGRADE_DRIVER=0
ASSUME_YES=0
RVS_TOKEN_ARG="${RVS_TOKEN:-}"
RVS_HOST_ARG="${RVS_HOST:-}"
while [[ $# -gt 0 ]]; do
case "$1" in
--up) DO_UP=1; shift ;;
--upgrade-driver) DO_UPGRADE_DRIVER=1; shift ;;
--yes|-y) ASSUME_YES=1; shift ;;
--token) RVS_TOKEN_ARG="${2:-}"; shift 2 ;;
--rvs-host) RVS_HOST_ARG="${2:-}"; shift 2 ;;
-h|--help) grep '^#' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;;
*) echo "Unbekannte Option: $1"; exit 1 ;;
esac
done
# ── Log-Helfer ──
c_g="\033[1;32m"; c_y="\033[1;33m"; c_r="\033[1;31m"; c_b="\033[1;34m"; c_0="\033[0m"
STEP=0
step() { STEP=$((STEP+1)); echo -e "\n${c_b}[${STEP}] $*${c_0}"; }
ok() { echo -e " ${c_g}✓${c_0} $*"; }
warn() { echo -e " ${c_y}!${c_0} $*"; }
die() { echo -e "${c_r}✗ $*${c_0}" >&2; exit 1; }
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
XTTS_DIR="$REPO_ROOT/xtts"
# ── Preflight ──
[[ "$(id -u)" -eq 0 ]] || die "Bitte als root ausfuehren (sudo ./bootstrap.sh)."
command -v apt-get >/dev/null || die "Kein apt-get — dieses Script ist fuer Debian/Trixie."
export DEBIAN_FRONTEND=noninteractive
echo -e "${c_b}=== ARIA KI-Box Bootstrap ===${c_0}"
echo "Repo: $REPO_ROOT"
echo "xtts: $XTTS_DIR"
# ── 1. Basis-Pakete ──
step "Basis-Pakete"
apt-get update -qq
apt-get install -y -qq ca-certificates curl gnupg git lsb-release >/dev/null
ok "ca-certificates, curl, gnupg, git"
# ── 2. non-free Repos aktivieren (Trixie deb822 + Legacy) ──
step "APT-Komponenten (contrib non-free non-free-firmware)"
# Ergaenzt die drei Komponenten in JEDER Components:-Zeile einer deb822-Datei —
# pro Zeile nur was fehlt, reihenfolge-robust, idempotent. Die Adressen pruefen
# ganze Woerter (non-free-firmware zaehlt NICHT als non-free).
add_components() {
sed -i -E '/^[Cc]omponents:/{
/(^|[[:space:]])contrib([[:space:]]|$)/!s/$/ contrib/
/(^|[[:space:]])non-free([[:space:]]|$)/!s/$/ non-free/
/(^|[[:space:]])non-free-firmware([[:space:]]|$)/!s/$/ non-free-firmware/
}' "$1"
}
ENABLED_ANY=0
shopt -s nullglob
for f in /etc/apt/sources.list.d/*.sources; do
grep -qE '^[Cc]omponents:' "$f" || continue
b="$(md5sum "$f")"; add_components "$f"; a="$(md5sum "$f")"
if [[ "$b" != "$a" ]]; then ENABLED_ANY=1; ok "aktualisiert: $(basename "$f")"; fi
done
shopt -u nullglob
# Legacy /etc/apt/sources.list (deb-Zeilen)
if [[ -f /etc/apt/sources.list ]] && grep -qE '^deb ' /etc/apt/sources.list; then
if ! grep -qE '^deb .*[[:space:]]non-free([[:space:]]|$)' /etc/apt/sources.list; then
sed -i -E '/^deb .*debian/ s/$/ contrib non-free non-free-firmware/' /etc/apt/sources.list
ENABLED_ANY=1; ok "aktualisiert: sources.list"
fi
fi
[[ $ENABLED_ANY -eq 0 ]] && ok "non-free schon aktiv"
apt-get update -qq # immer neu einlesen, damit der Kandidat sicher da ist
# ── 2b. (opt-in) Treiber-Upgrade ueber NVIDIAs Paketquelle fuer Debian 13 ──
# Debian (auch trixie-backports) hat hoechstens 550 = CUDA 12.4. Die aktuellen
# llama.cpp-/llama-swap-Images brauchen CUDA 12.8/12.9 → mit 550 meldet
# llama.cpp "failed to initialize CUDA … forward compatibility …", findet keine
# Karte und rechnet STILL auf der CPU ("ready" meldet es trotzdem).
# NVIDIAs Quelle hat die Pakete unter denselben Namen, nur neuer — apt
# aktualisiert an Ort und Stelle. Alte Debian-Teilpakete (nvidia-driver-bin,
# nvidia-alternative, …) sind in den neuen aufgegangen und werden entfernt.
# Das Container-Toolkit bleibt unberuehrt — ohne es saehe kein Container die GPU,
# darum bricht das Script ab, falls apt es anfassen wollte.
# NUR mit --upgrade-driver, damit ein laufendes Setup nicht ungewollt angefasst wird.
NV_REPO="https://developer.download.nvidia.com/compute/cuda/repos/debian13/x86_64"
MIN_DRIVER_MAJOR=575 # CUDA 12.9 braucht mindestens Treiber 575
if [[ "$DO_UPGRADE_DRIVER" -eq 1 ]]; then
step "NVIDIA-Treiber-Upgrade (NVIDIAs Paketquelle fuer Debian 13)"
CUR="$(nvidia-smi --query-gpu=driver_version --format=csv,noheader 2>/dev/null | head -1 || true)"
if [[ -z "$CUR" ]]; then CUR="$(dpkg-query -W -f='${Version}' nvidia-driver 2>/dev/null || true)"; fi
CUR_MAJOR="${CUR%%.*}"
if [[ "$CUR_MAJOR" =~ ^[0-9]+$ && "$CUR_MAJOR" -ge "$MIN_DRIVER_MAJOR" ]]; then
ok "Treiber ${CUR} ist neu genug (>= ${MIN_DRIVER_MAJOR}) — nichts zu tun"
else
ok "aktuell: ${CUR:-kein Treiber} — Ziel: >= ${MIN_DRIVER_MAJOR}"
KEYRING_NEW=0
if ! dpkg -s cuda-keyring >/dev/null 2>&1; then
curl -fsSL "$NV_REPO/cuda-keyring_1.1-1_all.deb" -o /tmp/cuda-keyring.deb \
|| die "NVIDIA-Paketquelle nicht erreichbar ($NV_REPO)"
dpkg -i /tmp/cuda-keyring.deb >/dev/null && KEYRING_NEW=1
ok "NVIDIA-Paketquelle eingetragen"
fi
undo_keyring() { [[ "$KEYRING_NEW" -eq 1 ]] && dpkg -r cuda-keyring >/dev/null 2>&1 && apt-get update -qq || true; }
apt-get update -qq
apt-get install -y -qq linux-headers-amd64 >/dev/null 2>&1 || true
apt-get install -y -qq "linux-headers-$(uname -r)" >/dev/null 2>&1 || true
NV_PKGS="nvidia-driver nvidia-kernel-dkms nvidia-smi libcuda1"
for p in nvidia-persistenced nvidia-modprobe; do
if dpkg -s "$p" >/dev/null 2>&1; then NV_PKGS="$NV_PKGS $p"; fi
done
# Erst durchspielen — aendert nichts.
if ! SIM="$(apt-get -s install -y $NV_PKGS 2>&1)"; then
echo "$SIM" | grep -E "^E:|Kollidiert|Hängt ab|Depends|Conflicts" | head -15 || true
undo_keyring
die "apt findet keinen sauberen Weg — NICHTS geaendert (Quelle wieder entfernt)."
fi
if echo "$SIM" | grep -qE '^(Remv|Inst) (nvidia-container|libnvidia-container)'; then
undo_keyring
die "Das Upgrade wuerde das NVIDIA-Container-Toolkit anfassen — abgebrochen, NICHTS geaendert."
fi
NEWV="$(echo "$SIM" | sed -nE 's/^Inst nvidia-driver (\[[^]]*\] )?\(([^ ]+).*/\2/p' | head -1 || true)"
echo
echo -e " Plan: Treiber ${CUR:-?} → ${c_g}${NEWV:-?}${c_0}"
echo "$SIM" | grep -E "^[0-9]+ (aktualisiert|upgraded)" | head -1 | sed 's/^/ /' || true
REMV="$(echo "$SIM" | sed -nE 's/^Remv ([^ ]+).*/\1/p' | paste -sd' ' || true)"
if [[ -n "$REMV" ]]; then echo " entfernt (in den neuen Paketen aufgegangen): $REMV"; fi
echo " Container-Toolkit: bleibt unberuehrt"
echo " Danach ist ein REBOOT noetig (neues Kernelmodul)."
if [[ "$ASSUME_YES" -ne 1 && -t 0 ]]; then
read -r -p " Jetzt ausfuehren? [j/N] " ans
if [[ ! "$ans" =~ ^[jJyY] ]]; then
undo_keyring
die "Abgebrochen — NICHTS geaendert."
fi
fi
apt-get install -y $NV_PKGS
dkms autoinstall >/dev/null 2>&1 || true
GOT="$(dpkg-query -W -f='${Version}' nvidia-driver 2>/dev/null || echo '?')"
[[ "${GOT%%.*}" =~ ^[0-9]+$ && "${GOT%%.*}" -ge "$MIN_DRIVER_MAJOR" ]] \
|| die "Installiert ist ${GOT} — erwartet >= ${MIN_DRIVER_MAJOR}. Bitte Ausgabe oben pruefen."
if dkms status 2>/dev/null | grep -q "$(uname -r).*installed"; then
ok "Kernelmodul fuer $(uname -r) gebaut"
else
warn "Kernelmodul fuer $(uname -r) nicht als gebaut gemeldet — nach dem Reboot 'nvidia-smi' pruefen"
fi
ok "nvidia-driver ${GOT} installiert"
echo
echo -e "${c_y}==> REBOOT noetig, damit der neue Treiber laedt:${c_0}"
echo -e "${c_y} sudo reboot${c_0}"
echo -e "${c_y} danach: nvidia-smi (zeigt ${GOT%%-*} und eine CUDA-Version >= 12.9)${c_0}"
echo -e "${c_y} und: cd xtts && docker compose up -d${c_0}"
exit 0
fi
fi
# ── 3. NVIDIA-Treiber ──
step "NVIDIA-Treiber"
if nvidia-smi >/dev/null 2>&1; then
DRV="$(nvidia-smi --query-gpu=driver_version --format=csv,noheader 2>/dev/null | head -1 || true)"
ok "Treiber ${DRV} aktiv: $(nvidia-smi --query-gpu=name --format=csv,noheader | paste -sd', ')"
DRIVER_ACTIVE=1
# Fuer das lokale LLM zu alt? Dann laeuft es still auf der CPU — das soll man
# hier sehen, nicht erst an einer leeren Karte in nvidia-smi.
PROFILES="$(grep -E '^COMPOSE_PROFILES=' "$XTTS_DIR/.env" 2>/dev/null | cut -d= -f2- || true)"
if [[ "${DRV%%.*}" =~ ^[0-9]+$ && "${DRV%%.*}" -lt "$MIN_DRIVER_MAJOR" && ( -z "$PROFILES" || "$PROFILES" == *llm* ) ]]; then
warn "Treiber ${DRV} ist zu alt fuer das lokale LLM (braucht >= ${MIN_DRIVER_MAJOR})."
warn " Folge: llama.cpp findet keine Karte und rechnet auf der CPU."
warn " Abhilfe: sudo ./bootstrap.sh --upgrade-driver (zeigt erst den Plan, fragt nach)"
fi
else
if dpkg -l | grep -q '^ii nvidia-driver '; then
warn "Treiber installiert, aber nvidia-smi antwortet nicht → REBOOT noetig."
DRIVER_ACTIVE=0
else
# KEIN separater Kandidaten-Check — die apt-cache-Ausgabe ist locale-/pipe-
# fragil (hat faelschlich "kein Kandidat" gemeldet). Der Install IST der Test:
# direkt installieren; schlaegt er fehl, einmal volles apt-get update + Retry,
# dann erst mit Diagnose abbrechen.
# Kernel-Header ZUERST — sonst ueberspringt DKMS den Modulbau ("No kernel
# headers were found") und nvidia-smi kann spaeter nicht mit dem Treiber reden.
warn "Kernel-Header + nvidia-driver installieren (DKMS-Build, dauert)…"
apt-get install -y linux-headers-amd64 || true
apt-get install -y "linux-headers-$(uname -r)" || true
if ! apt-get install -y nvidia-driver firmware-misc-nonfree; then
warn "Install fehlgeschlagen — volles 'apt-get update' + zweiter Versuch…"
apt-get update
if ! apt-get install -y nvidia-driver firmware-misc-nonfree; then
echo
warn "nvidia-driver liess sich nicht installieren. Aktive Quellen:"
grep -rhE '^[Cc]omponents:' /etc/apt/sources.list.d/*.sources 2>/dev/null | sed 's/^/ /' || true
grep -E '^deb ' /etc/apt/sources.list 2>/dev/null | sed 's/^/ /' || true
die "Pruefe 'apt-cache policy nvidia-driver' + Netz/non-free."
fi
fi
# Falls nvidia-kernel-dkms schon (ohne Header) installiert war: Modul jetzt bauen.
dkms autoinstall >/dev/null 2>&1 || true
ok "nvidia-driver + Kernel-Modul installiert"
DRIVER_ACTIVE=0
fi
fi
# ── 4. Docker Engine + Compose-Plugin ──
step "Docker"
if command -v docker >/dev/null 2>&1; then
ok "Docker vorhanden: $(docker --version)"
else
warn "Installiere Docker (offizielles get.docker.com)…"
curl -fsSL https://get.docker.com | sh >/dev/null
systemctl enable --now docker >/dev/null 2>&1 || true
ok "Docker installiert: $(docker --version)"
fi
if docker compose version >/dev/null 2>&1; then
ok "Compose-Plugin: $(docker compose version | head -1)"
else
warn "Compose-Plugin fehlt — installiere docker-compose-plugin…"
apt-get install -y -qq docker-compose-plugin >/dev/null || \
warn "Konnte docker-compose-plugin nicht via apt holen — get.docker.com bringt es normalerweise mit."
fi
# ── 5. NVIDIA Container Toolkit ──
step "NVIDIA Container Toolkit"
NCT_LIST="/etc/apt/sources.list.d/nvidia-container-toolkit.list"
NCT_KEY="/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg"
if ! dpkg -l | grep -q '^ii nvidia-container-toolkit '; then
[[ -f "$NCT_KEY" ]] || curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey \
| gpg --dearmor -o "$NCT_KEY"
if [[ ! -f "$NCT_LIST" ]]; then
curl -fsSL https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list \
| sed "s#deb https://#deb [signed-by=${NCT_KEY}] https://#g" > "$NCT_LIST"
fi
apt-get update -qq
apt-get install -y -qq nvidia-container-toolkit >/dev/null
ok "nvidia-container-toolkit installiert"
else
ok "nvidia-container-toolkit vorhanden"
fi
# Docker-Runtime auf NVIDIA konfigurieren (idempotent)
if ! grep -q '"nvidia"' /etc/docker/daemon.json 2>/dev/null; then
nvidia-ctk runtime configure --runtime=docker >/dev/null
systemctl restart docker
ok "Docker-Runtime auf NVIDIA konfiguriert + Docker neugestartet"
else
ok "Docker-Runtime bereits NVIDIA-konfiguriert"
fi
# ── 6. xtts/.env vorbereiten ──
step "xtts/.env"
if [[ -f "$XTTS_DIR/.env" ]]; then
ok ".env existiert bereits (unangetastet)"
else
cp "$XTTS_DIR/.env.example" "$XTTS_DIR/.env"
ok ".env aus .env.example erstellt"
fi
if [[ -n "$RVS_TOKEN_ARG" ]]; then
sed -i -E "s#^RVS_TOKEN=.*#RVS_TOKEN=${RVS_TOKEN_ARG}#" "$XTTS_DIR/.env"
ok "RVS_TOKEN eingetragen"
fi
if [[ -n "$RVS_HOST_ARG" ]]; then
sed -i -E "s#^RVS_HOST=.*#RVS_HOST=${RVS_HOST_ARG}#" "$XTTS_DIR/.env"
ok "RVS_HOST=${RVS_HOST_ARG} eingetragen"
fi
if grep -q '^RVS_TOKEN=dein_token_hier' "$XTTS_DIR/.env"; then
warn "RVS_TOKEN ist noch der Platzhalter — vor dem Start setzen:"
warn " nano $XTTS_DIR/.env (oder: sudo ./bootstrap.sh --token <TOKEN>)"
fi
warn "Stimm-Daten (nicht in git): falls von der alten Box noch vorhanden, xtts/voice-id/"
warn " + xtts/voices/ herkopieren. Sonst egal — in der App neu anlegen:"
warn " Sprache neu enrollen (Speaker-ID, sonst fail-open) + F5-Referenz neu hochladen."
# ── 7. GPU-im-Container verifizieren ──
step "GPU-im-Container Test"
if [[ "${DRIVER_ACTIVE:-0}" -eq 1 ]]; then
if docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi >/dev/null 2>&1; then
ok "Docker sieht die GPU — KI-Box ist einsatzbereit."
GPU_READY=1
else
warn "Host-Treiber ok, aber Container sieht die GPU nicht — Toolkit/Runtime pruefen."
GPU_READY=0
fi
else
warn "Treiber noch nicht aktiv → Test uebersprungen."
echo
echo -e "${c_y}==> REBOOT noetig, dann Script erneut ausfuehren:${c_0}"
echo -e "${c_y} sudo reboot && (nach dem Boot) sudo ./bootstrap.sh${c_0}"
exit 0
fi
# ── 8. Optional: xtts-Stack hochziehen ──
if [[ $DO_UP -eq 1 && "${GPU_READY:-0}" -eq 1 ]]; then
step "xtts-Stack starten (Default-Profil: Whisper + F5 + LLM — OHNE voxtral)"
warn "Erster Start laedt Modelle (mehrere GB via HuggingFace) — kann dauern."
( cd "$XTTS_DIR" && docker compose up -d --build )
ok "Stack laeuft. Logs: docker logs -f aria-whisper-bridge"
echo
echo " voxtral (STT via Voxtral) braucht >=16 GB VRAM → erst mit der 24-GB-Karte:"
echo " cd $XTTS_DIR && docker compose stop whisper-bridge && docker compose --profile voxtral up -d --build"
fi
# ── Abschluss ──
echo
echo -e "${c_g}=== Fertig. KI-Box startklar. ===${c_0}"
if [[ $DO_UP -eq 0 ]]; then
echo "Naechster Schritt — Stack starten:"
echo " cd $XTTS_DIR && docker compose up -d --build"
echo "oder direkt: sudo ./bootstrap.sh --up"
fi