76 lines
2.9 KiB
Bash
Executable File
76 lines
2.9 KiB
Bash
Executable File
#!/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
|