feat(scripts): fold model downloads into update.sh, skip if already present
Today's embedding-server crash-loop (missing nomic-embed-text GGUF) was a manual step nobody ran. update.sh now runs both downloader profiles itself, every time, before bringing services up -- no separate command to remember. - docker-compose.yml: downloader/downloader-embedding commands gain a `test -f ... && skip || curl ...` guard, so re-running update.sh never re-downloads an existing model file. - scripts/update.sh: runs both profiles after image pull/build, before service recreation. - scripts/download-model.sh removed -- folded in, redundant standalone script. - README.md / docs/memory-knowledgebase.md updated accordingly. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018WHfjWrSEcGhCoeu6dQfDa
This commit is contained in:
@@ -7,11 +7,10 @@ See the wayfinder map ([issue #1](https://git.arthurerlich.de/haylan/LLM-Server/
|
|||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./scripts/download-model.sh
|
|
||||||
./scripts/update.sh
|
./scripts/update.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
`update.sh` creates `.env` from `.env.example` if missing, fills in every secret and per-workload virtual key it can generate itself (random secrets via `openssl`, `OPENWEBUI_LITELLM_KEY`/`LITELLM_PGVECTOR_EMBEDDING_KEY` minted through LiteLLM's own `/key/generate` API, `SEARXNG_LAN_IP` resolved from `search.home` on this host), then pulls/builds/brings up the whole stack. Safe to re-run any time — it only fills in what's still blank and only recreates what changed. See [`docs/proxy-key-onboarding.md`](docs/proxy-key-onboarding.md) if a key mint fails and needs doing by hand.
|
`update.sh` creates `.env` from `.env.example` if missing, fills in every secret and per-workload virtual key it can generate itself (random secrets via `openssl`, `OPENWEBUI_LITELLM_KEY`/`LITELLM_PGVECTOR_EMBEDDING_KEY` minted through LiteLLM's own `/key/generate` API, `SEARXNG_LAN_IP` resolved from `search.home` on this host), downloads both model GGUFs into the `models` volume if they're not there yet, then pulls/builds/brings up the whole stack. Safe to re-run any time — it only fills in what's still blank, skips models already downloaded, and only recreates what changed. See [`docs/proxy-key-onboarding.md`](docs/proxy-key-onboarding.md) if a key mint fails and needs doing by hand.
|
||||||
|
|
||||||
- Open WebUI: `http://<this-machine>:3000` locally, or `ai.home` / `ai.haylan.ch` once routed through Nginx Proxy Manager — see [`docs/network-access.md`](docs/network-access.md). First signup becomes the admin account (`WEBUI_AUTH` is on).
|
- Open WebUI: `http://<this-machine>:3000` locally, or `ai.home` / `ai.haylan.ch` once routed through Nginx Proxy Manager — see [`docs/network-access.md`](docs/network-access.md). First signup becomes the admin account (`WEBUI_AUTH` is on).
|
||||||
- llama.cpp's own API is internal-only now — everything routes through the AI proxy below.
|
- llama.cpp's own API is internal-only now — everything routes through the AI proxy below.
|
||||||
|
|||||||
+10
-3
@@ -66,8 +66,10 @@ services:
|
|||||||
networks: [ai-stack]
|
networks: [ai-stack]
|
||||||
|
|
||||||
# ponytail: one-off downloader, not a standing service — run via
|
# ponytail: one-off downloader, not a standing service — run via
|
||||||
# `docker compose --profile tools run --rm downloader` (see scripts/download-model.sh).
|
# `docker compose --profile tools run --rm downloader`. Folded into
|
||||||
# Keeps the model file inside the named `models` volume instead of a host bind-mount.
|
# scripts/update.sh, which runs this every time; the `test -f` guard is
|
||||||
|
# what makes that safe to re-run without re-downloading. Keeps the model
|
||||||
|
# file inside the named `models` volume instead of a host bind-mount.
|
||||||
downloader:
|
downloader:
|
||||||
image: curlimages/curl:latest
|
image: curlimages/curl:latest
|
||||||
profiles: ["tools"]
|
profiles: ["tools"]
|
||||||
@@ -79,11 +81,14 @@ services:
|
|||||||
entrypoint: ["sh", "-c"]
|
entrypoint: ["sh", "-c"]
|
||||||
command:
|
command:
|
||||||
- >
|
- >
|
||||||
|
test -f /models/${LLAMA_MODEL_FILE:-Qwen3.8-27B-UD-Q4_K_XL.gguf} &&
|
||||||
|
echo "already downloaded, skipping" ||
|
||||||
curl -L --fail --create-dirs -o /models/${LLAMA_MODEL_FILE:-Qwen3.8-27B-UD-Q4_K_XL.gguf}
|
curl -L --fail --create-dirs -o /models/${LLAMA_MODEL_FILE:-Qwen3.8-27B-UD-Q4_K_XL.gguf}
|
||||||
https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/resolve/main/${LLAMA_MODEL_FILE:-Qwen3.8-27B-UD-Q4_K_XL.gguf}
|
https://huggingface.co/unsloth/Qwen3.8-27B-GGUF/resolve/main/${LLAMA_MODEL_FILE:-Qwen3.8-27B-UD-Q4_K_XL.gguf}
|
||||||
|
|
||||||
# ponytail: same one-off pattern as `downloader`, for the embedding model —
|
# ponytail: same one-off pattern as `downloader`, for the embedding model —
|
||||||
# run via `docker compose --profile tools run --rm downloader-embedding`.
|
# run via `docker compose --profile tools run --rm downloader-embedding`,
|
||||||
|
# also folded into scripts/update.sh.
|
||||||
downloader-embedding:
|
downloader-embedding:
|
||||||
image: curlimages/curl:latest
|
image: curlimages/curl:latest
|
||||||
profiles: ["tools"]
|
profiles: ["tools"]
|
||||||
@@ -93,6 +98,8 @@ services:
|
|||||||
entrypoint: ["sh", "-c"]
|
entrypoint: ["sh", "-c"]
|
||||||
command:
|
command:
|
||||||
- >
|
- >
|
||||||
|
test -f /models/${EMBEDDING_MODEL_FILE:-nomic-embed-text-v1.5.Q8_0.gguf} &&
|
||||||
|
echo "already downloaded, skipping" ||
|
||||||
curl -L --fail --create-dirs -o /models/${EMBEDDING_MODEL_FILE:-nomic-embed-text-v1.5.Q8_0.gguf}
|
curl -L --fail --create-dirs -o /models/${EMBEDDING_MODEL_FILE:-nomic-embed-text-v1.5.Q8_0.gguf}
|
||||||
https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF/resolve/main/${EMBEDDING_MODEL_FILE:-nomic-embed-text-v1.5.Q8_0.gguf}
|
https://huggingface.co/nomic-ai/nomic-embed-text-v1.5-GGUF/resolve/main/${EMBEDDING_MODEL_FILE:-nomic-embed-text-v1.5.Q8_0.gguf}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ New pieces:
|
|||||||
|
|
||||||
### First-time setup
|
### First-time setup
|
||||||
|
|
||||||
|
`./scripts/update.sh` fetches the embedding model automatically (skips it if already downloaded). To do it by hand instead:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose --profile tools run --rm downloader-embedding # fetch the embedding model
|
docker compose --profile tools run --rm downloader-embedding # fetch the embedding model
|
||||||
docker compose up -d embedding-server pgvector-db litellm-pgvector
|
docker compose up -d embedding-server pgvector-db litellm-pgvector
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# Downloads the model GGUF straight into the `models` named volume via a
|
|
||||||
# one-off container — no huggingface-cli or host bind-mount needed.
|
|
||||||
#
|
|
||||||
# ponytail: hardcodes the one model this stack is built for (see the
|
|
||||||
# `downloader` service in docker-compose.yml for the actual URL/filename).
|
|
||||||
# Set LLAMA_MODEL_FILE in .env first if you're using a different quant.
|
|
||||||
set -euo pipefail
|
|
||||||
cd "$(dirname "$0")/.."
|
|
||||||
|
|
||||||
docker compose --profile tools run --rm downloader
|
|
||||||
echo "Model downloaded into the 'models' volume."
|
|
||||||
@@ -63,6 +63,10 @@ docker compose pull --ignore-buildable
|
|||||||
echo "==> rebuilding local-build services"
|
echo "==> rebuilding local-build services"
|
||||||
docker compose build --pull
|
docker compose build --pull
|
||||||
|
|
||||||
|
echo "==> ensuring models are downloaded (skips already-present files)"
|
||||||
|
docker compose --profile tools run --rm downloader
|
||||||
|
docker compose --profile tools run --rm downloader-embedding
|
||||||
|
|
||||||
echo "==> bringing up litellm (needed to mint virtual keys below)"
|
echo "==> bringing up litellm (needed to mint virtual keys below)"
|
||||||
docker compose up -d --wait litellm-db litellm
|
docker compose up -d --wait litellm-db litellm
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user