diff --git a/scripts/podx-tools.sh b/scripts/podx-tools.sh index 90be100..123acd1 100755 --- a/scripts/podx-tools.sh +++ b/scripts/podx-tools.sh @@ -101,66 +101,63 @@ _require() { fi } -_kb_id_by_name() { +_owui_get_kb_list() { + _require "OPENWEBUI_API_KEY" "$OPENWEBUI_API_KEY" + _require "OPENWEBUI_URL" "$OPENWEBUI_URL" + local url; url="$(_owui_url)/api/v1/knowledge/list" + curl -sS -H "Authorization: Bearer $OPENWEBUI_API_KEY" "$url" +} + +_kb_create() { local kb_name="$1" _require "OPENWEBUI_API_KEY" "$OPENWEBUI_API_KEY" _require "OPENWEBUI_URL" "$OPENWEBUI_URL" - local url - url="$(_owui_url)/api/v1/knowledge/list" + curl -sS -X POST \ + -H "Authorization: Bearer $OPENWEBUI_API_KEY" \ + -H "Content-Type: application/json" \ + -d "{\"name\":\"$kb_name\",\"description\":\"Created by podx-tools\"}" \ + "$(_owui_url)/api/v1/knowledge/create" +} - # Fetch list once - local body tmp_code - body="$(_mktemp)"; tmp_code="$(_mktemp)" - curl -sS -H "Authorization: Bearer $OPENWEBUI_API_KEY" \ - -w "%{http_code}" --output "$body" "$url" >"$tmp_code" || true - local http_code; http_code="$(cat "$tmp_code" 2>/dev/null || echo 0)"; rm -f "$tmp_code" - - # If non-200, return empty - if [ "$http_code" != "200" ]; then - rm -f "$body"; echo ""; return - fi - - # Parse with python: prefer exact name match; if multiple, choose by latest updated_at; else try substring match - local id - id="$(python3 - "$kb_name" <"$body" 2>/dev/null <<'PY' +_kb_id_by_name() { + local kb_name="$1" + local json; json="$(_owui_get_kb_list)" + # Normalize to a flat list and choose the most recently updated match + python3 - "$kb_name" <<'PY' || true import sys, json name = sys.argv[1] +raw = sys.stdin.read().strip() +if not raw: + sys.exit(0) try: - data = json.load(sys.stdin) + d = json.loads(raw) except Exception: - print("") sys.exit(0) +if isinstance(d, dict) and "data" in d and isinstance(d["data"], list): + items = d["data"] +elif isinstance(d, list): + items = d +else: + items = [] -# Normalize to list -if not isinstance(data, list): - print("") - sys.exit(0) +def ts(kb): + for key in ("updated_at", "created_at"): + v = kb.get(key) + if isinstance(v, (int, float)): + return int(v) + return 0 -candidates = [kb for kb in data if (kb.get('name') or '') == name] -# If nothing exact, try substring (case-insensitive) -if not candidates: - lname = name.lower() - candidates = [kb for kb in data if lname in (kb.get('name') or '').lower()] - -if not candidates: - print("") - sys.exit(0) - -# Choose the one with the newest updated_at (numeric seconds); fall back to created_at; else first. -from operator import itemgetter - -def ts(kb, key): - try: - return int(kb.get(key) or 0) - except Exception: - return 0 - -best = sorted(candidates, key=lambda kb: (ts(kb,'updated_at'), ts(kb,'created_at')), reverse=True)[0] -print(best.get('id','')) +exact = sorted([kb for kb in items if kb.get("name") == name], key=ts, reverse=True) +if exact: + print(exact[0].get("id", ""), end=""); sys.exit(0) +iexact = sorted([kb for kb in items if isinstance(kb.get("name"), str) and kb["name"].lower() == name.lower()], key=ts, reverse=True) +if iexact: + print(iexact[0].get("id", ""), end=""); sys.exit(0) +sub = sorted([kb for kb in items if isinstance(kb.get("name"), str) and name.lower() in kb["name"].lower()], key=ts, reverse=True) +if sub: + print(sub[0].get("id", ""), end=""); sys.exit(0) +print("", end="") PY -)" - rm -f "$body" - echo "$id" } _help() { @@ -179,12 +176,11 @@ Meilisearch: OpenWebUI: owui-health # check API health (200) owui-kbs # list knowledge bases - owui-kbs-raw # list knowledge bases raw JSON (debug) - owui-kb-debug "" # debug KB id resolution owui-kb-id "" # print the KB UUID by exact name owui-upload # upload a file, prints file_id owui-attach "" # upload + attach to KB - owui-kb-files "" # list files in KB + owui-kb-create "" # create a KB (prints JSON with id) + owui-kbs-raw # raw JSON from /knowledge/list owui-batch-attach "" # attach all files matching glob Examples: @@ -284,24 +280,14 @@ print(f\"Indexed {n} document(s).\")" ;; owui-kbs-raw) - _require "OPENWEBUI_URL" "$OPENWEBUI_URL" - _require "OPENWEBUI_API_KEY" "$OPENWEBUI_API_KEY" - curl -sS -H "Authorization: Bearer $OPENWEBUI_API_KEY" \ - "$(_owui_url)/api/v1/knowledge/list" + _owui_get_kb_list | ppjson ;; - owui-kb-debug) + owui-kb-create) shift || true name="${1:-}" - if [ -z "$name" ]; then echo "Usage: owui-kb-debug \"\"" >&2; exit 1; fi - _require "OPENWEBUI_URL" "$OPENWEBUI_URL" - _require "OPENWEBUI_API_KEY" "$OPENWEBUI_API_KEY" - echo "[debug] Resolved KB URL: $(_owui_url)" - echo "[debug] Looking for KB name: $name" - echo "[debug] Listing KBs (pretty):" - curl -sS -H "Authorization: Bearer $OPENWEBUI_API_KEY" \ - "$(_owui_url)/api/v1/knowledge/list" | ppjson - echo "[debug] Resolved KB id: $(_kb_id_by_name "$name")" + if [ -z "$name" ]; then echo "Usage: owui-kb-create \"\"" >&2; exit 1; fi + _kb_create "$name" | ppjson ;; owui-kb-id) @@ -375,7 +361,8 @@ print(f\"Indexed {n} document(s).\")" echo "[owui] attaching to KB: $kb_name (id: $KB_ID)" if [ -z "$KB_ID" ]; then echo "KB '$kb_name' not found (or ambiguous)." >&2 - echo "Tip: run './scripts/podx-tools.sh owui-kb-debug \"$kb_name\"' to inspect the KB list and resolved id." >&2 + echo "Tip: run './scripts/podx-tools.sh owui-kb-debug \"$kb_name\"' or create one:" >&2 + echo " ./scripts/podx-tools.sh owui-kb-create \"$kb_name\"" >&2 exit 1 fi @@ -425,6 +412,21 @@ print(f\"Indexed {n} document(s).\")" "$(_owui_url)/api/v1/knowledge/$KB_ID/files" | ppjson ;; + owui-kb-debug) + shift || true + name="${1:-}" + if [ -z "$name" ]; then echo "Usage: owui-kb-debug \"\"" >&2; exit 1; fi + echo "[owui] base URL: $(_owui_url)" + echo "[owui] KBs returned:" + _owui_get_kb_list | ppjson + id="$(_kb_id_by_name "$name")" + if [ -n "$id" ]; then + echo "[owui] resolved id for \"$name\": $id" + else + echo "[owui] could not resolve an id for \"$name\"" >&2 + fi + ;; + owui-batch-attach) shift || true kb_name="${1:-}"; glob_pat="${2:-}"