Files
AI-Profile-Router/deploy/install.sh
2026-08-30 10:07:40 +02:00

179 lines
6.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# AI Profile Router – Installation/Update auf dem Zielsystem.
# Wird als root auf dem Zielsystem ausgeführt (per SSH, vgl. deploy.sh).
# Erwartet ai_profile_router.py, image_worker.py, xtts_worker.py,
# mike-ai-profile-router.service und mike-ai-xtts.service im selben
# Verzeichnis wie dieses Skript.
set -euo pipefail
DIR="$(cd "$(dirname "$0")" && pwd)"
INSTALL_DIR=/opt/mike-ai/ai-profile-router
SERVICE=mike-ai-profile-router.service
XTTS_SERVICE=mike-ai-xtts.service
WHISPER_SERVICE=mike-ai-whisper.service
OLD_SERVICE=mike-ai-local-llm-router.service
OLD_DIR=/opt/mike-ai/local-llm-router
BACKUP_DIR=/opt/mike-ai/.backup-ai-profile-router-$(date +%Y%m%d-%H%M%S)
VENV="$INSTALL_DIR/venv"
MODEL_DIR=/opt/mike-ai/models/FLUX.2-klein-4B
IMAGE_DIR="$INSTALL_DIR/images"
XTTS_VENV=/opt/mike-ai/xtts/venv
XTTS_CACHE=/opt/mike-ai/xtts/.cache
echo "== AI Profile Router: Installation/Update =="
# --- 1. Bestehenden (alten) Router entfernen, mit Backup -------------------
if [ -f "/etc/systemd/system/${OLD_SERVICE}" ]; then
echo "-- Entferne alten Router ${OLD_SERVICE} (Backup: ${BACKUP_DIR})"
mkdir -p "$BACKUP_DIR"
systemctl stop "$OLD_SERVICE" 2>/dev/null || true
systemctl disable "$OLD_SERVICE" 2>/dev/null || true
mv "/etc/systemd/system/${OLD_SERVICE}" "$BACKUP_DIR/"
if [ -d "$OLD_DIR" ]; then
mv "$OLD_DIR" "$BACKUP_DIR/local-llm-router"
fi
else
echo "-- Kein alter Router gefunden"
fi
# --- 2. Neue Dateien installieren -------------------------------------------
mkdir -p "$INSTALL_DIR" "$IMAGE_DIR"
install -d -m 0700 /etc/mike-ai /var/lib/mike-ai-profile-router
install -m 0755 "$DIR/ai_profile_router.py" "$INSTALL_DIR/ai_profile_router.py"
install -m 0644 "$DIR/router_support.py" "$INSTALL_DIR/router_support.py"
install -m 0644 "$DIR/router_profiles.json" /etc/mike-ai/router-profiles.json
install -m 0755 "$DIR/image_worker.py" "$INSTALL_DIR/image_worker.py"
install -m 0755 "$DIR/xtts_worker.py" "$INSTALL_DIR/xtts_worker.py"
install -m 0755 "$DIR/stt_worker.py" "$INSTALL_DIR/stt_worker.py"
install -m 0644 "$DIR/${SERVICE}" "/etc/systemd/system/${SERVICE}"
install -m 0644 "$DIR/${XTTS_SERVICE}" "/etc/systemd/system/${XTTS_SERVICE}"
install -m 0644 "$DIR/${WHISPER_SERVICE}" "/etc/systemd/system/${WHISPER_SERVICE}"
# Eigener Router-Key. Er wird niemals in Git oder ins Installationslog geschrieben.
if [ ! -s /etc/mike-ai/router-api-key ]; then
umask 077
python3 -c 'import secrets; print(secrets.token_urlsafe(48))' \
> /etc/mike-ai/router-api-key
fi
chmod 0600 /etc/mike-ai/router-api-key
# --- 3. Python-Venv mit Bild-Abhängigkeiten ---------------------------------
if [ ! -x "$VENV/bin/python" ]; then
echo "-- Erstelle Python-Venv in $VENV"
python3 -m venv "$VENV"
fi
echo "-- Installiere festgeschriebene Bild-Abhängigkeiten"
"$VENV/bin/pip" install --quiet --upgrade pip
"$VENV/bin/pip" install --quiet torch==2.11.0+cu128 \
--index-url https://download.pytorch.org/whl/cu128
"$VENV/bin/pip" install --quiet -r "$DIR/requirements-image.lock"
# --- 4. FLUX-Modell (nur wenn noch nicht vorhanden) --------------------------
if [ -f "$MODEL_DIR/model_index.json" ]; then
echo "-- FLUX-Modell vorhanden: $MODEL_DIR"
else
echo "-- Lade FLUX.2-klein-4B nach $MODEL_DIR (kann dauern)"
"$VENV/bin/python" - <<'PY'
import os
from huggingface_hub import snapshot_download
snapshot_download(
repo_id="black-forest-labs/FLUX.2-klein-4B",
revision="e7b7dc27f91deacad38e78976d1f2b499d76a294",
local_dir="/opt/mike-ai/models/FLUX.2-klein-4B",
local_dir_use_symlinks=False,
)
print("Modell-Download abgeschlossen")
PY
fi
# --- 5. TTS (XTTS-v2) ----------------------------------------------------------
# XTTS-Venv (Python 3.11 via uv + CPU-only torch + Coqui TTS)
if [ ! -x "$XTTS_VENV/bin/python" ]; then
echo "-- Erstelle XTTS-Venv in $XTTS_VENV (Python 3.11 via uv)"
mkdir -p "$XTTS_VENV"
# uv installieren (falls noch nicht vorhanden)
if ! command -v uv >/dev/null 2>&1; then
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
fi
uv venv --python 3.11 "$XTTS_VENV"
"$XTTS_VENV/bin/pip" install --quiet --upgrade pip
echo "-- Installiere CPU-only torch"
"$XTTS_VENV/bin/pip" install --quiet torch==2.11.0+cpu torchaudio==2.11.0+cpu \
--index-url https://download.pytorch.org/whl/cpu
echo "-- Installiere Coqui TTS + Abhängigkeiten"
"$XTTS_VENV/bin/pip" install --quiet -r "$DIR/requirements-xtts.lock"
# PyTorch 2.6+ weights_only-Patch für Coqui TTS
echo "-- Wende weights_only-Patch für Coqui TTS an"
"$XTTS_VENV/bin/python" - <<'PY'
import os
patch_file = os.path.expanduser("/opt/mike-ai/xtts/venv/lib/python3.11/site-packages/TTS/utils/io.py")
with open(patch_file, 'r') as f:
content = f.read()
if 'weights_only=False' not in content:
content = content.replace(
'return torch.load(f, map_location=map_location, **kwargs)',
'return torch.load(f, map_location=map_location, weights_only=False, **kwargs)'
)
with open(patch_file, 'w') as f:
f.write(content)
print("Patch angewendet")
else:
print("Patch bereits vorhanden")
PY
fi
# XTTS-v2-Modell (nur wenn noch nicht vorhanden)
if [ ! -d "$XTTS_CACHE/hub/models--coqui--tts_models--multilingual--multi-dataset--xtts_v2" ]; then
echo "-- Lade XTTS-v2-Modell (kann dauern, ~1.9 GB)"
"$XTTS_VENV/bin/python" - <<'PY'
import os
os.environ["HF_HOME"] = "/opt/mike-ai/xtts/.cache"
from TTS.api import TTS
tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2")
print("Modell geladen")
PY
fi
# --- 6. Services aktivieren und starten ---------------------------------------
systemctl daemon-reload
systemctl enable "$SERVICE" "$XTTS_SERVICE" "$WHISPER_SERVICE"
systemctl restart "$XTTS_SERVICE"
systemctl restart "$WHISPER_SERVICE"
systemctl restart "$SERVICE"
# --- 7. Verifikation ----------------------------------------------------------
sleep 1
if ! systemctl is-active --quiet "$SERVICE"; then
echo "-- FEHLER: Router-Service läuft nicht" >&2
journalctl -u "$SERVICE" -n 20 --no-pager >&2
exit 1
fi
echo "-- Router-Service läuft"
if ! systemctl is-active --quiet "$XTTS_SERVICE"; then
echo "-- FEHLER: XTTS-Service läuft nicht" >&2
journalctl -u "$XTTS_SERVICE" -n 20 --no-pager >&2
exit 1
fi
echo "-- XTTS-Service läuft"
if ! systemctl is-active --quiet "$WHISPER_SERVICE"; then
echo "-- FEHLER: Whisper-Service läuft nicht" >&2
journalctl -u "$WHISPER_SERVICE" -n 20 --no-pager >&2
exit 1
fi
echo "-- Whisper-Service läuft"
python3 - <<'PY'
import json
import pathlib
import urllib.request
key = pathlib.Path("/etc/mike-ai/router-api-key").read_text().strip()
request = urllib.request.Request(
"http://127.0.0.1:8081/status",
headers={"Authorization": f"Bearer {key}"})
with urllib.request.urlopen(request, timeout=10) as response:
print(json.dumps(json.load(response), indent=2))
PY
echo "-- Router-API-Key liegt ausschließlich in /etc/mike-ai/router-api-key"
echo "== Fertig =="