#!/usr/bin/env bash # Stoppt den LocalAI-Stack bzw. gibt den VRAM frei. # # ./scripts/stop.sh Container stoppen (bleiben auch nach Reboot aus) # ./scripts/stop.sh --unload nur alle Modelle entladen, Container laufen weiter # ./scripts/stop.sh --down Container stoppen und entfernen (Modelle/Daten bleiben) set -euo pipefail cd "$(dirname "$(readlink -f "$0")")/.." MODE=stop while [[ $# -gt 0 ]]; do case "$1" in --unload) MODE=unload ;; --down) MODE=down ;; -h|--help) sed -n '2,6p' "$0" | sed 's/^# \{0,1\}//'; exit 0 ;; *) echo "Unbekannte Option: $1" >&2; exit 2 ;; esac shift done if [[ -t 1 ]]; then B=$'\e[1m'; G=$'\e[32m'; Y=$'\e[33m'; R=$'\e[31m'; N=$'\e[0m'; else B= G= Y= R= N=; fi ok() { echo "${G}✔${N} $*"; } warn() { echo "${Y}!${N} $*"; } die() { echo "${R}✘${N} $*" >&2; exit 1; } step() { echo; echo "${B}== $*${N}"; } command -v docker >/dev/null || die "docker nicht installiert" docker info >/dev/null 2>&1 || die "Docker-Daemon läuft nicht oder keine Rechte (Gruppe 'docker'?)" BACKEND_PORT=8080 [[ -f .env ]] && BACKEND_PORT=$(set -a; . ./.env; echo "${BACKEND_PORT:-8080}") running=$(docker compose ps --status running -q 2>/dev/null | wc -l) # ------------------------------------------------------------- Entladen # vor dem Stoppen entladen, damit llama-swap die Server sauber beendet if [[ "$running" -gt 0 ]] && curl -fsS -m 2 "http://127.0.0.1:$BACKEND_PORT/health" >/dev/null 2>&1; then step "Entlade Modelle" loaded=$(curl -s -m 5 "http://127.0.0.1:$BACKEND_PORT/running" \ | python3 -c 'import sys,json; print(", ".join(m["model"] for m in json.load(sys.stdin)["running"]) or "-")' 2>/dev/null || echo "?") echo " geladen: $loaded" if curl -fsS -m 60 -o /dev/null "http://127.0.0.1:$BACKEND_PORT/unload"; then ok "Modelle entladen" else warn "Entladen über llama-swap fehlgeschlagen" fi elif [[ "$MODE" == unload ]]; then die "llama-swap läuft nicht – nichts zu entladen" fi # --------------------------------------------------------------- Stoppen case "$MODE" in stop) step "Stoppe Container" docker compose stop ok "Stack gestoppt – Neustart mit ./scripts/start.sh" ;; down) step "Stoppe und entferne Container" docker compose down --remove-orphans ok "Stack entfernt – Neustart mit ./scripts/start.sh" ;; unload) warn "Container laufen weiter – Autocomplete/Embeddings werden beim nächsten Request neu geladen" ;; esac # ------------------------------------------------------------------ Status step "Status" docker compose ps -a --format '{{.Service}}: {{.Status}}' | sed 's/^/ /' [[ "$(docker compose ps -a -q | wc -l)" -eq 0 ]] && echo " keine Container" command -v rocm-smi >/dev/null && rocm-smi --showmeminfo vram 2>/dev/null \ | awk '/GPU\[0\].*Total Memory/{t=$NF} /GPU\[0\].*Used Memory/{u=$NF} END{if(t) printf " VRAM: %.1f / %.1f GB\n", u/1e9, t/1e9}' true