Provision OpenWebUI workspace model presets
This commit is contained in:
+1
-1
@@ -470,7 +470,7 @@ services:
|
|||||||
- ./platform/openwebui/theme/loader.js:/app/build/static/loader.js:ro
|
- ./platform/openwebui/theme/loader.js:/app/build/static/loader.js:ro
|
||||||
environment:
|
environment:
|
||||||
WEBUI_SECRET_KEY: "${WEBUI_SECRET_KEY:?WEBUI_SECRET_KEY is required}"
|
WEBUI_SECRET_KEY: "${WEBUI_SECRET_KEY:?WEBUI_SECRET_KEY is required}"
|
||||||
DEFAULT_MODELS: qwen-medium
|
DEFAULT_MODELS: mikeai-medium
|
||||||
OLLAMA_BASE_URL: ""
|
OLLAMA_BASE_URL: ""
|
||||||
OPENAI_API_BASE_URLS: http://router:8081/v1
|
OPENAI_API_BASE_URLS: http://router:8081/v1
|
||||||
OPENAI_API_KEYS: "${ROUTER_API_KEY:?ROUTER_API_KEY is required}"
|
OPENAI_API_KEYS: "${ROUTER_API_KEY:?ROUTER_API_KEY is required}"
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
|
|||||||
- [ ] llama.cpp entspricht dem festgelegten Commit
|
- [ ] llama.cpp entspricht dem festgelegten Commit
|
||||||
- [ ] Modelldateien stimmen mit SHA256 überein
|
- [ ] Modelldateien stimmen mit SHA256 überein
|
||||||
- [ ] Fast startet mit 76.800 Kontext
|
- [ ] Fast startet mit 76.800 Kontext
|
||||||
- [ ] Medium startet mit 94.208 Kontext
|
- [ ] Medium startet mit 160.000 Kontext und ist Standard
|
||||||
- [ ] Long startet mit 131.072 Kontext
|
- [ ] Large startet mit 192.000 Kontext
|
||||||
|
- [ ] Ultra startet mit 262.144 Kontext und bleibt text-only
|
||||||
- [ ] GPU-/CPU-Verteilung entspricht den Profilen
|
- [ ] GPU-/CPU-Verteilung entspricht den Profilen
|
||||||
- [ ] Fast erreicht den festgelegten Geschwindigkeitstoleranzbereich
|
- [ ] Fast erreicht den festgelegten Geschwindigkeitstoleranzbereich
|
||||||
- [ ] MTP funktioniert und verursacht keine Qualitätsregression
|
- [ ] MTP funktioniert und verursacht keine Qualitätsregression
|
||||||
@@ -36,7 +37,7 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
|
|||||||
- [ ] geschützte Endpunkte liefern ohne Key 401
|
- [ ] geschützte Endpunkte liefern ohne Key 401
|
||||||
- [ ] Router-Key erscheint weder im Upstream noch im Journal
|
- [ ] Router-Key erscheint weder im Upstream noch im Journal
|
||||||
- [ ] `/status` meldet den richtigen Upstream
|
- [ ] `/status` meldet den richtigen Upstream
|
||||||
- [ ] `/v1/models` liefert drei virtuelle Modelle
|
- [ ] `/v1/models` liefert vier virtuelle Modelle
|
||||||
- [ ] `/fast`, `/medium`, `/large` und `/ultra` wechseln zuverlässig
|
- [ ] `/fast`, `/medium`, `/large` und `/ultra` wechseln zuverlässig
|
||||||
- [ ] automatischer Wechsel über virtuellen Modellnamen funktioniert
|
- [ ] automatischer Wechsel über virtuellen Modellnamen funktioniert
|
||||||
- [ ] paralleler Wechsel wird sauber gesperrt
|
- [ ] paralleler Wechsel wird sauber gesperrt
|
||||||
@@ -49,6 +50,11 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
|
|||||||
|
|
||||||
## Phase D – Web und MCP
|
## Phase D – Web und MCP
|
||||||
|
|
||||||
|
- [ ] OpenWebUI zeigt nur die vier MikeAI-Arbeitsbereichsmodelle
|
||||||
|
- [ ] rohe `qwen-*`-Routermodelle sind ausgeblendet
|
||||||
|
- [ ] Medium ist die gespeicherte Standardauswahl
|
||||||
|
- [ ] Filter und Quick Actions sind allen vier Presets zugeordnet
|
||||||
|
|
||||||
- [ ] SearXNG und TinySearch gesund
|
- [ ] SearXNG und TinySearch gesund
|
||||||
- [ ] Websuche liefert kompakte, quellengebundene Ergebnisse
|
- [ ] Websuche liefert kompakte, quellengebundene Ergebnisse
|
||||||
- [ ] GitHub- und Hugging-Face-Routing geprüft
|
- [ ] GitHub- und Hugging-Face-Routing geprüft
|
||||||
@@ -86,7 +92,8 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
|
|||||||
|
|
||||||
## Phase G – Fachlicher Benchmark
|
## Phase G – Fachlicher Benchmark
|
||||||
|
|
||||||
Der gespeicherte Standardbenchmark wird mindestens mit Fast und Long ausgeführt:
|
Der gespeicherte Standardbenchmark wird mindestens mit Fast und Medium sowie
|
||||||
|
für Kontextgrenzen zusätzlich mit Large und Ultra ausgeführt:
|
||||||
|
|
||||||
- Home-Assistant-Automatisierung analysieren
|
- Home-Assistant-Automatisierung analysieren
|
||||||
- Logs lesen und Fehlerursache begründen
|
- Logs lesen und Fehlerursache begründen
|
||||||
|
|||||||
+17
-5
@@ -95,6 +95,18 @@ Zusätzlich prüfen: Uni-LAN sieht keine KI-Ports; Heimnetz erreicht beide;
|
|||||||
gestopptes WireGuard lässt KI-Container nicht ins Internet; jeder Profilwechsel
|
gestopptes WireGuard lässt KI-Container nicht ins Internet; jeder Profilwechsel
|
||||||
startet exakt einen llama-Container; Text, Tool Call, Bild und Sprachausgabe funktionieren.
|
startet exakt einen llama-Container; Text, Tool Call, Bild und Sprachausgabe funktionieren.
|
||||||
|
|
||||||
|
Nach dem ersten Anlegen des OpenWebUI-Administrators werden Filter, Quick
|
||||||
|
Actions und die vier Arbeitsbereichsmodelle reproduzierbar eingespielt:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo /opt/mike-ai/stack/platform/openwebui/install-filters.sh
|
||||||
|
sudo /opt/mike-ai/stack/platform/openwebui/install-models.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Danach sind nur die vier benannten MikeAI-Presets sichtbar; die rohen
|
||||||
|
Router-Aliase sind ausgeblendet und Medium ist die Standardauswahl. Beide
|
||||||
|
Skripte sichern die OpenWebUI-Datenbank vor jeder Änderung.
|
||||||
|
|
||||||
## Werkzeug-Container
|
## Werkzeug-Container
|
||||||
|
|
||||||
Der Installer startet Websuche automatisch in einem privaten Docker-Netz.
|
Der Installer startet Websuche automatisch in einem privaten Docker-Netz.
|
||||||
@@ -122,11 +134,11 @@ Kein MCP-Port wird auf dem Host veröffentlicht. Externe Clients wie Hermes
|
|||||||
benötigen später den authentifizierten WireGuard-Gateway und dürfen nicht
|
benötigen später den authentifizierten WireGuard-Gateway und dürfen nicht
|
||||||
direkt auf das interne Werkzeugnetz zugreifen.
|
direkt auf das interne Werkzeugnetz zugreifen.
|
||||||
|
|
||||||
Die öffentliche Standardkonfiguration nutzt `UD-IQ4_XS`. Das bislang schnellste
|
Die Standardkonfiguration lädt IQ4-MIX für Fast und IQ4_XS Pure für Medium,
|
||||||
Referenzprofil nutzt dagegen die lokal vorhandene `IQ4-MIX`-Datei. Für eine
|
Large und Ultra aus den dokumentierten Hugging-Face-Repositories. URLs,
|
||||||
bitgenaue Migration diese Datei anhand der in `CURRENT_REFERENCE.md`
|
Dateinamen und SHA256 stehen vollständig in `config/install.env.example`.
|
||||||
dokumentierten SHA256 in das Modellverzeichnis kopieren und die drei
|
Der Installer lädt jede identische Datei nur einmal und löscht vorhandene
|
||||||
`*_MODEL_FILE`-Werte anpassen. Der Installer löscht vorhandene Modelle nicht.
|
Modelle nicht.
|
||||||
|
|
||||||
Open-WebUI-Daten liegen in einem Docker-Volume und müssen separat gesichert
|
Open-WebUI-Daten liegen in einem Docker-Volume und müssen separat gesichert
|
||||||
werden. Geheimnisse und Chatdaten gehören nie in Git.
|
werden. Geheimnisse und Chatdaten gehören nie in Git.
|
||||||
|
|||||||
@@ -29,6 +29,22 @@ einer vorherigen Datenbanksicherung installiert beziehungsweise aktualisiert:
|
|||||||
sudo /opt/mike-ai/stack/platform/openwebui/install-filters.sh
|
sudo /opt/mike-ai/stack/platform/openwebui/install-filters.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Die sichtbaren Arbeitsbereichsmodelle und die versteckten Router-Aliase werden
|
||||||
|
separat und ebenfalls mit vorheriger Datenbanksicherung installiert:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo /opt/mike-ai/stack/platform/openwebui/install-models.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Dadurch erscheinen ausschließlich `MikeAI · Fast`, `MikeAI · Medium`,
|
||||||
|
`MikeAI · Large` und `MikeAI · Ultra`. Medium ist die Standardauswahl. Alle
|
||||||
|
vier erhalten die geprüften Filter und Quick Actions sowie Piper-Stimme
|
||||||
|
`alloy`. Vision ist nur bei Fast, Medium und Large aktiviert; Ultra bleibt
|
||||||
|
bewusst text-only. Bildgenerierung wird erst als Fähigkeit freigeschaltet,
|
||||||
|
wenn ein echter Generator-Worker im Stack aktiv ist. Websuche und Codewerkzeuge
|
||||||
|
bleiben verfügbar, werden aber nicht automatisch jeder Nachricht beigelegt,
|
||||||
|
damit Werkzeugschemas den Kontext nicht unnötig füllen.
|
||||||
|
|
||||||
Bei mehreren Administratoren muss der gewünschte Eigentümer explizit über
|
Bei mehreren Administratoren muss der gewünschte Eigentümer explizit über
|
||||||
`OPENWEBUI_FILTER_OWNER_ID` gesetzt werden. Das Skript liest oder verändert
|
`OPENWEBUI_FILTER_OWNER_ID` gesetzt werden. Das Skript liest oder verändert
|
||||||
keine Chats. Es deaktiviert zugleich global die automatisch erzeugten
|
keine Chats. Es deaktiviert zugleich global die automatisch erzeugten
|
||||||
|
|||||||
@@ -15,7 +15,10 @@ und einer bewussten Aktualisierung dieser Datei.
|
|||||||
|
|
||||||
- Medium ist nach Neuinstallation und bewusstem Plattformstart das aktive
|
- Medium ist nach Neuinstallation und bewusstem Plattformstart das aktive
|
||||||
Standardprofil.
|
Standardprofil.
|
||||||
- Open WebUI erhält `qwen-medium` als Standardmodell.
|
- Open WebUI erhält `mikeai-medium` als Standardmodell.
|
||||||
|
- Im OpenWebUI-Arbeitsbereich ist dieses auf `qwen-medium` basierende Preset
|
||||||
|
`mikeai-medium` die sichtbare Standardauswahl; die vier rohen `qwen-*`-Aliase
|
||||||
|
bleiben ausgeblendet.
|
||||||
- Ein explizit gewähltes anderes Modell löst den zugehörigen Containerwechsel
|
- Ein explizit gewähltes anderes Modell löst den zugehörigen Containerwechsel
|
||||||
aus; es ist immer nur ein Inferenzcontainer aktiv.
|
aus; es ist immer nur ein Inferenzcontainer aktiv.
|
||||||
- Ultra reserviert den verfügbaren Speicher für nativen 256K-Textkontext und
|
- Ultra reserviert den verfügbaren Speicher für nativen 256K-Textkontext und
|
||||||
@@ -30,4 +33,3 @@ und einer bewussten Aktualisierung dieser Datei.
|
|||||||
- Large 192K: Pure 86:14 mit MTP3, 75,28 Tok/s.
|
- Large 192K: Pure 86:14 mit MTP3, 75,28 Tok/s.
|
||||||
- Ultra 256K: Pure 80:20 mit MTP2, 68,19 Tok/s; 220.190 Tokens
|
- Ultra 256K: Pure 80:20 mit MTP2, 68,19 Tok/s; 220.190 Tokens
|
||||||
erfolgreich verarbeitet und Sentinel korrekt wiedergefunden.
|
erfolgreich verarbeitet und Sentinel korrekt wiedergefunden.
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,218 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
umask 077
|
||||||
|
|
||||||
|
CONTAINER=${OPENWEBUI_CONTAINER:-mike-ai-open-webui}
|
||||||
|
VOLUME=${OPENWEBUI_VOLUME:-mike-ai_open-webui-data}
|
||||||
|
|
||||||
|
die() { printf 'FEHLER: %s\n' "$*" >&2; exit 1; }
|
||||||
|
[[ $EUID -eq 0 ]] || die "Bitte als root ausführen."
|
||||||
|
|
||||||
|
volume_path=$(docker volume inspect -f '{{.Mountpoint}}' "$VOLUME")
|
||||||
|
db=$volume_path/webui.db
|
||||||
|
[[ -s $db ]] || die "OpenWebUI-Datenbank fehlt: $db"
|
||||||
|
|
||||||
|
was_running=false
|
||||||
|
if [[ $(docker inspect -f '{{.State.Running}}' "$CONTAINER" 2>/dev/null || true) == true ]]; then
|
||||||
|
was_running=true
|
||||||
|
docker stop "$CONTAINER" >/dev/null
|
||||||
|
fi
|
||||||
|
restart_on_exit() {
|
||||||
|
if [[ $was_running == true ]]; then
|
||||||
|
docker start "$CONTAINER" >/dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap restart_on_exit EXIT
|
||||||
|
|
||||||
|
stamp=$(date +%Y%m%d-%H%M%S)
|
||||||
|
backup=$volume_path/webui.db.before-model-install-$stamp
|
||||||
|
cp -a "$db" "$backup"
|
||||||
|
rm -f "$volume_path/webui.db-wal" "$volume_path/webui.db-shm"
|
||||||
|
|
||||||
|
python3 - "$db" "${OPENWEBUI_MODEL_OWNER_ID:-}" <<'PY'
|
||||||
|
import json
|
||||||
|
import sqlite3
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
db, requested_owner = sys.argv[1:]
|
||||||
|
con = sqlite3.connect(db)
|
||||||
|
columns = {row[1] for row in con.execute("pragma table_info(model)")}
|
||||||
|
required = {
|
||||||
|
"id", "user_id", "base_model_id", "name", "params", "meta",
|
||||||
|
"is_active", "updated_at", "created_at",
|
||||||
|
}
|
||||||
|
if not required <= columns:
|
||||||
|
raise SystemExit("Unbekanntes OpenWebUI-Modellschema; keine Änderung vorgenommen.")
|
||||||
|
|
||||||
|
owner = requested_owner
|
||||||
|
if not owner:
|
||||||
|
row = con.execute(
|
||||||
|
"select user_id from model where id in "
|
||||||
|
"('mikeai-fast','mikeai-medium','mikeai-large','mikeai-ultra',"
|
||||||
|
"'mikeai---fast-72k') order by updated_at desc limit 1"
|
||||||
|
).fetchone()
|
||||||
|
if row:
|
||||||
|
owner = row[0]
|
||||||
|
if not owner:
|
||||||
|
admins = con.execute("select id from user where role='admin'").fetchall()
|
||||||
|
if len(admins) != 1:
|
||||||
|
raise SystemExit(
|
||||||
|
"Modelleigentümer ist nicht eindeutig; OPENWEBUI_MODEL_OWNER_ID setzen."
|
||||||
|
)
|
||||||
|
owner = admins[0][0]
|
||||||
|
|
||||||
|
now = int(time.time())
|
||||||
|
filter_ids = [
|
||||||
|
"reasoning_default_off",
|
||||||
|
"thinking",
|
||||||
|
"stability_guard",
|
||||||
|
"secret_redaction",
|
||||||
|
"local_performance_metrics",
|
||||||
|
]
|
||||||
|
|
||||||
|
def capabilities(vision: bool) -> dict:
|
||||||
|
return {
|
||||||
|
"file_context": True,
|
||||||
|
"vision": vision,
|
||||||
|
"file_upload": True,
|
||||||
|
"web_search": True,
|
||||||
|
"image_generation": False,
|
||||||
|
"code_interpreter": True,
|
||||||
|
"terminal": True,
|
||||||
|
"citations": True,
|
||||||
|
"status_updates": True,
|
||||||
|
"memory": True,
|
||||||
|
"builtin_tools": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
profiles = [
|
||||||
|
{
|
||||||
|
"id": "mikeai-fast",
|
||||||
|
"base": "qwen-fast",
|
||||||
|
"name": "MikeAI · Fast · 76K",
|
||||||
|
"description": (
|
||||||
|
"Schnelles Alltags- und Agentenprofil: Qwen3.8-27B IQ4-MIX, "
|
||||||
|
"76.800 Token, RTX 5080, MTP2 und Bildanalyse."
|
||||||
|
),
|
||||||
|
"vision": True,
|
||||||
|
"tags": ["MikeAI", "Schnell", "Vision"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mikeai-medium",
|
||||||
|
"base": "qwen-medium",
|
||||||
|
"name": "MikeAI · Medium · 160K · Standard",
|
||||||
|
"description": (
|
||||||
|
"Verbindliches Standardprofil: Qwen3.8-27B IQ4_XS Pure, "
|
||||||
|
"160.000 Token, RTX 5080 + RTX 3060 (90:10), MTP3 und Bildanalyse."
|
||||||
|
),
|
||||||
|
"vision": True,
|
||||||
|
"tags": ["MikeAI", "Standard", "Vision"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mikeai-large",
|
||||||
|
"base": "qwen-large",
|
||||||
|
"name": "MikeAI · Large · 192K",
|
||||||
|
"description": (
|
||||||
|
"Großes Agenten- und MCP-Profil: Qwen3.8-27B IQ4_XS Pure, "
|
||||||
|
"192.000 Token, RTX 5080 + RTX 3060 (86:14), MTP3 und Bildanalyse."
|
||||||
|
),
|
||||||
|
"vision": True,
|
||||||
|
"tags": ["MikeAI", "Großer Kontext", "Vision"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "mikeai-ultra",
|
||||||
|
"base": "qwen-ultra",
|
||||||
|
"name": "MikeAI · Ultra · 256K · Text",
|
||||||
|
"description": (
|
||||||
|
"Maximaler Textkontext: Qwen3.8-27B IQ4_XS Pure, 262.144 Token, "
|
||||||
|
"RTX 5080 + RTX 3060 (80:20), MTP2; bewusst ohne Bildanalyse."
|
||||||
|
),
|
||||||
|
"vision": False,
|
||||||
|
"tags": ["MikeAI", "Maximaler Kontext", "Nur Text"],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"temperature": 0.2,
|
||||||
|
"top_p": 0.8,
|
||||||
|
"top_k": 20,
|
||||||
|
"max_tokens": 32768,
|
||||||
|
}
|
||||||
|
|
||||||
|
def upsert(model_id, base_model_id, name, model_params, meta, active=True):
|
||||||
|
existing = con.execute(
|
||||||
|
"select created_at from model where id=?", (model_id,)
|
||||||
|
).fetchone()
|
||||||
|
created_at = existing[0] if existing else now
|
||||||
|
con.execute(
|
||||||
|
"""
|
||||||
|
insert into model
|
||||||
|
(id,user_id,base_model_id,name,params,meta,is_active,updated_at,created_at)
|
||||||
|
values (?,?,?,?,?,?,?,?,?)
|
||||||
|
on conflict(id) do update set
|
||||||
|
user_id=excluded.user_id,
|
||||||
|
base_model_id=excluded.base_model_id,
|
||||||
|
name=excluded.name,
|
||||||
|
params=excluded.params,
|
||||||
|
meta=excluded.meta,
|
||||||
|
is_active=excluded.is_active,
|
||||||
|
updated_at=excluded.updated_at
|
||||||
|
""",
|
||||||
|
(
|
||||||
|
model_id, owner, base_model_id, name,
|
||||||
|
json.dumps(model_params, ensure_ascii=False),
|
||||||
|
json.dumps(meta, ensure_ascii=False),
|
||||||
|
active, now, created_at,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
with con:
|
||||||
|
# Hide the raw router aliases while keeping them resolvable as bases for
|
||||||
|
# the user-facing workspace presets.
|
||||||
|
for raw_id in ("qwen-fast", "qwen-medium", "qwen-large", "qwen-ultra"):
|
||||||
|
upsert(
|
||||||
|
raw_id, None, raw_id, {},
|
||||||
|
{
|
||||||
|
"description": "Interner Router-Alias; bitte das zugehörige MikeAI-Profil verwenden.",
|
||||||
|
"hidden": True,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
for profile in profiles:
|
||||||
|
meta = {
|
||||||
|
"profile_image_url": "/static/favicon.png",
|
||||||
|
"description": profile["description"],
|
||||||
|
"capabilities": capabilities(profile["vision"]),
|
||||||
|
"knowledge": None,
|
||||||
|
"suggestion_prompts": None,
|
||||||
|
"tags": [{"name": tag} for tag in profile["tags"]],
|
||||||
|
# Features remain available but are not forced on every request;
|
||||||
|
# this avoids needlessly injecting large tool schemas.
|
||||||
|
"defaultFeatureIds": [],
|
||||||
|
"filterIds": filter_ids,
|
||||||
|
"actionIds": ["quick_actions"],
|
||||||
|
"tts": {"voice": "alloy"},
|
||||||
|
"hidden": False,
|
||||||
|
}
|
||||||
|
upsert(
|
||||||
|
profile["id"], profile["base"], profile["name"], params, meta
|
||||||
|
)
|
||||||
|
|
||||||
|
# Exact legacy entries from the experimental 72K/Long setup. The database
|
||||||
|
# backup above makes the cleanup fully recoverable.
|
||||||
|
con.execute(
|
||||||
|
"delete from model where id in ('mikeai---fast-72k','qwen-long')"
|
||||||
|
)
|
||||||
|
con.execute(
|
||||||
|
"""
|
||||||
|
insert into config (key,value,updated_at) values (?,?,?)
|
||||||
|
on conflict(key) do update set value=excluded.value, updated_at=excluded.updated_at
|
||||||
|
""",
|
||||||
|
("ui.default_models", json.dumps("mikeai-medium"), now),
|
||||||
|
)
|
||||||
|
|
||||||
|
print("OpenWebUI-Modelle installiert: Fast, Medium (Standard), Large, Ultra")
|
||||||
|
PY
|
||||||
|
|
||||||
|
printf 'Datenbanksicherung: %s\n' "$backup"
|
||||||
Reference in New Issue
Block a user