open_notebook/scripts/setup_models.sh

137 lines
5.4 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
# Registriert Ollama + OpenRouter + lokale TTS/STT-Wrapper als AI-Provider in
# Open Notebook und setzt sinnvolle Standardmodelle. Für einen frischen Stack
# gedacht (siehe README.md) — prüft vor dem Anlegen jeweils, ob Credential/
# Modell mit demselben Namen schon existiert, ist also im Wesentlichen
# wiederholbar, aber nicht für abweichende Konfigurationen gedacht.
set -euo pipefail
API="http://127.0.0.1:5055/api"
echo "Warte auf Open Notebook API..."
until curl -sf "${API}/models/providers" >/dev/null 2>&1; do sleep 2; done
# --- Hilfsfunktionen -------------------------------------------------------
credential_id_by_name() {
curl -s "${API}/credentials" | python3 -c "
import json, sys
name = sys.argv[1]
for c in json.load(sys.stdin):
if c['name'] == name:
print(c['id']); break
" "$1"
}
model_id_by_name() {
curl -s "${API}/models" | python3 -c "
import json, sys
name = sys.argv[1]
for m in json.load(sys.stdin):
if m['name'] == name:
print(m['id']); break
" "$1"
}
ensure_credential() {
# ensure_credential <name> <json-payload>
local name="$1" payload="$2" id
id=$(credential_id_by_name "$name")
if [ -n "$id" ]; then
echo "Credential '$name' existiert bereits ($id)" >&2
echo "$id"
return
fi
id=$(curl -s -X POST "${API}/credentials" -H "Content-Type: application/json" -d "$payload" \
| python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")
echo "Credential '$name' angelegt ($id)" >&2
echo "$id"
}
ensure_model() {
# ensure_model <name> <provider> <type> [credential_id]
local name="$1" provider="$2" type="$3" cred="${4:-}" id
id=$(model_id_by_name "$name")
if [ -n "$id" ]; then
echo "Modell '$name' existiert bereits ($id)" >&2
echo "$id"
return
fi
local cred_json="null"
[ -n "$cred" ] && cred_json="\"$cred\""
id=$(curl -s -X POST "${API}/models" -H "Content-Type: application/json" \
-d "{\"name\": \"$name\", \"provider\": \"$provider\", \"type\": \"$type\", \"credential\": ${cred_json}}" \
| python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")
echo "Modell '$name' ($type) angelegt ($id)" >&2
echo "$id"
}
# --- 1. OpenRouter: API-Key aus Environment in die DB migrieren -----------
echo "== OpenRouter =="
curl -s -X POST "${API}/credentials/migrate-from-env" >/dev/null
echo "OPENROUTER_API_KEY aus Environment migriert (falls gesetzt)"
# --- 2. Ollama-Credential (Chat/Embedding), num_ctx=98304 -----------------
# 98304 ist der größte Kontext, der bei qwen3.5:27b auf dieser Hardware noch
# vollständig auf einer GPU bleibt (100% GPU laut `ollama ps`) — 131072
# spillt auf die CPU und macht Antworten 5-6x langsamer. Ohne num_ctx
# begrenzt esperanto Ollama-Chat-Aufrufe fest auf 8192 Tokens.
echo "== Ollama (Chat + Embedding) =="
OLLAMA_CRED=$(ensure_credential "Ollama (local)" '{
"name": "Ollama (local)",
"provider": "ollama",
"modalities": ["language", "embedding"],
"base_url": "http://host.docker.internal:11434",
"num_ctx": 98304
}')
QWEN_CHAT=$(ensure_model "qwen3.5:27b" "ollama" "language" "$OLLAMA_CRED")
QWEN_CODER=$(ensure_model "qwen3-coder-30b-128k:latest" "ollama" "language" "$OLLAMA_CRED")
NOMIC_EMBED=$(ensure_model "nomic-embed-text" "ollama" "embedding" "$OLLAMA_CRED")
# --- 3. OpenRouter-Sprachmodelle (kuratiert, nicht alle ~400) --------------
echo "== OpenRouter Sprachmodelle =="
CLAUDE_SONNET=$(ensure_model "anthropic/claude-sonnet-5" "openrouter" "language")
QWEN_MAX=$(ensure_model "qwen/qwen3-max" "openrouter" "language")
GEMINI_FLASH=$(ensure_model "google/gemini-3.5-flash" "openrouter" "language")
# --- 4. Lokale TTS/STT-Wrapper (siehe services/) --------------------------
echo "== Lokales TTS (Chatterbox) =="
TTS_CRED=$(ensure_credential "Chatterbox TTS (local)" '{
"name": "Chatterbox TTS (local)",
"provider": "openai_compatible",
"modalities": ["text_to_speech"],
"base_url": "http://host.docker.internal:8901",
"api_key": "not-required"
}')
TTS_MODEL=$(ensure_model "chatterbox-tts" "openai_compatible" "text_to_speech" "$TTS_CRED")
echo "== Lokales STT (faster-whisper) =="
STT_CRED=$(ensure_credential "faster-whisper STT (local)" '{
"name": "faster-whisper STT (local)",
"provider": "openai_compatible",
"modalities": ["speech_to_text"],
"base_url": "http://host.docker.internal:8902",
"api_key": "not-required"
}')
STT_MODEL=$(ensure_model "faster-whisper-large-v3" "openai_compatible" "speech_to_text" "$STT_CRED")
# --- 5. Standardmodelle setzen ---------------------------------------------
# Alles lokal/kostenlos außer Tools-Modell optional auf ein OpenRouter-Modell
# umstellbar (siehe BEDIENUNGSANLEITUNG.md, Abschnitt "Modelle wechseln").
echo "== Standardmodelle setzen =="
curl -s -X PUT "${API}/models/defaults" -H "Content-Type: application/json" -d "{
\"default_chat_model\": \"$QWEN_CHAT\",
\"default_transformation_model\": \"$QWEN_CHAT\",
\"large_context_model\": \"$QWEN_CHAT\",
\"default_embedding_model\": \"$NOMIC_EMBED\",
\"default_tools_model\": \"$QWEN_CHAT\",
\"default_text_to_speech_model\": \"$TTS_MODEL\",
\"default_speech_to_text_model\": \"$STT_MODEL\"
}" | python3 -m json.tool
echo
echo "Fertig. Registrierte, aber nicht als Standard gesetzte Zusatzmodelle:"
echo " - qwen3-coder-30b-128k:latest ($QWEN_CODER) — für reine Coding-Aufgaben"
echo " - anthropic/claude-sonnet-5 ($CLAUDE_SONNET), qwen/qwen3-max ($QWEN_MAX), google/gemini-3.5-flash ($GEMINI_FLASH) — OpenRouter-Alternativen"