Make OpenWebUI reasoning filter order reproducible
This commit is contained in:
1 parent
bf90698b99
commit
9a40758c7f
7 files changed
+220
No files matched your search
@@ -0,0 +1,24 @@
|
||||
"""
|
||||
title: Reasoning Default Off
|
||||
author: Mike
|
||||
version: 1.0.1
|
||||
description: Forces llama.cpp reasoning off by default.
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Filter:
|
||||
class Valves(BaseModel):
|
||||
# OpenWebUI runs lower priorities first. This default must precede the
|
||||
# optional Thinking override.
|
||||
priority: int = 10
|
||||
|
||||
def __init__(self):
|
||||
self.valves = self.Valves()
|
||||
self.toggle = False
|
||||
|
||||
async def inlet(self, body: dict, **kwargs) -> dict:
|
||||
body["reasoning_effort"] = "none"
|
||||
body["thinking_budget_tokens"] = 0
|
||||
return body
|
||||
@@ -0,0 +1,57 @@
|
||||
"""
|
||||
title: Thinking
|
||||
author: Mike
|
||||
version: 2.0.1
|
||||
description: Optional Qwen3.8 reasoning override - Low / Medium / High.
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from typing import Literal
|
||||
from urllib.parse import quote
|
||||
|
||||
|
||||
class Filter:
|
||||
class Valves(BaseModel):
|
||||
# Runs after Reasoning Default Off and may deliberately override it.
|
||||
priority: int = 20
|
||||
|
||||
class UserValves(BaseModel):
|
||||
level: Literal["Low", "Medium", "High"] = Field(
|
||||
default="Low",
|
||||
description="Thinking depth",
|
||||
)
|
||||
|
||||
def __init__(self):
|
||||
self.valves = self.Valves()
|
||||
self.toggle = True
|
||||
svg = """
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<text x="16" y="23" text-anchor="middle" font-size="24">🧠</text>
|
||||
</svg>
|
||||
"""
|
||||
self.icon = "data:image/svg+xml," + quote(svg)
|
||||
|
||||
async def inlet(
|
||||
self,
|
||||
body: dict,
|
||||
__user__: dict = None,
|
||||
**kwargs,
|
||||
) -> dict:
|
||||
level = "Low"
|
||||
if __user__ and __user__.get("valves") is not None:
|
||||
valves = __user__["valves"]
|
||||
if isinstance(valves, dict):
|
||||
level = valves.get("level", "Low")
|
||||
else:
|
||||
level = getattr(valves, "level", "Low")
|
||||
|
||||
if level == "Low":
|
||||
body["reasoning_effort"] = "low"
|
||||
body["thinking_budget_tokens"] = 512
|
||||
elif level == "Medium":
|
||||
body["reasoning_effort"] = "medium"
|
||||
body["thinking_budget_tokens"] = 3072
|
||||
elif level == "High":
|
||||
body["reasoning_effort"] = "xhigh"
|
||||
body["thinking_budget_tokens"] = 8192
|
||||
return body
|
||||
Executable
+108
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
umask 077
|
||||
|
||||
CONTAINER=${OPENWEBUI_CONTAINER:-mike-ai-open-webui}
|
||||
VOLUME=${OPENWEBUI_VOLUME:-mike-ai_open-webui-data}
|
||||
FILTER_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/filters" && pwd)
|
||||
|
||||
die() { printf 'FEHLER: %s\n' "$*" >&2; exit 1; }
|
||||
[[ $EUID -eq 0 ]] || die "Bitte als root ausführen."
|
||||
for file in reasoning_default_off.py thinking.py; do
|
||||
[[ -s $FILTER_DIR/$file ]] || die "Filterdatei fehlt: $file"
|
||||
done
|
||||
|
||||
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-filter-install-$stamp
|
||||
cp -a "$db" "$backup"
|
||||
rm -f "$volume_path/webui.db-wal" "$volume_path/webui.db-shm"
|
||||
|
||||
python3 - "$db" "$FILTER_DIR" "${OPENWEBUI_FILTER_OWNER_ID:-}" <<'PY'
|
||||
import json
|
||||
import pathlib
|
||||
import sqlite3
|
||||
import sys
|
||||
import time
|
||||
|
||||
db, filter_dir, requested_owner = sys.argv[1:]
|
||||
con = sqlite3.connect(db)
|
||||
columns = {row[1] for row in con.execute("pragma table_info(function)")}
|
||||
required = {
|
||||
"id", "user_id", "name", "type", "content", "meta", "valves",
|
||||
"is_active", "is_global", "updated_at", "created_at",
|
||||
}
|
||||
if not required <= columns:
|
||||
raise SystemExit("Unbekanntes OpenWebUI-Function-Schema; keine Änderung vorgenommen.")
|
||||
|
||||
owner = requested_owner
|
||||
if not owner:
|
||||
existing = con.execute(
|
||||
"select user_id from function where id in (?, ?) order by id limit 1",
|
||||
("reasoning_default_off", "thinking"),
|
||||
).fetchone()
|
||||
if existing:
|
||||
owner = existing[0]
|
||||
if not owner:
|
||||
admins = con.execute("select id from user where role='admin'").fetchall()
|
||||
if len(admins) != 1:
|
||||
raise SystemExit(
|
||||
"Filter-Eigentümer ist nicht eindeutig; OPENWEBUI_FILTER_OWNER_ID setzen."
|
||||
)
|
||||
owner = admins[0][0]
|
||||
|
||||
now = int(time.time())
|
||||
filters = [
|
||||
("reasoning_default_off", "Reasoning Default Off", 10),
|
||||
("thinking", "Thinking", 20),
|
||||
]
|
||||
with con:
|
||||
for function_id, name, priority in filters:
|
||||
content = pathlib.Path(filter_dir, f"{function_id}.py").read_text()
|
||||
con.execute(
|
||||
"""
|
||||
insert into function
|
||||
(id,user_id,name,type,content,meta,valves,is_active,is_global,updated_at,created_at)
|
||||
values (?,?,?,?,?,?,?,?,?,?,?)
|
||||
on conflict(id) do update set
|
||||
name=excluded.name,
|
||||
type=excluded.type,
|
||||
content=excluded.content,
|
||||
valves=excluded.valves,
|
||||
is_active=excluded.is_active,
|
||||
is_global=excluded.is_global,
|
||||
updated_at=excluded.updated_at
|
||||
""",
|
||||
(
|
||||
function_id, owner, name, "filter", content, "{}",
|
||||
json.dumps({"priority": priority}), True, True, now, now,
|
||||
),
|
||||
)
|
||||
print("OpenWebUI-Filter installiert: Default Off=10, Thinking=20")
|
||||
PY
|
||||
|
||||
if [[ $was_running == true ]]; then
|
||||
docker start "$CONTAINER" >/dev/null
|
||||
deadline=$((SECONDS + 180))
|
||||
until [[ $(docker inspect -f '{{.State.Health.Status}}' "$CONTAINER" 2>/dev/null || true) == healthy ]]; do
|
||||
(( SECONDS < deadline )) || die "$CONTAINER wurde nicht rechtzeitig gesund."
|
||||
sleep 3
|
||||
done
|
||||
fi
|
||||
trap - EXIT
|
||||
printf 'Datenbanksicherung: %s\n' "$backup"
|
||||
Reference in new issue
Block a user