#!/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 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 [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"