From fd70cae4b756a37544e7ae1969f669376c2148be Mon Sep 17 00:00:00 2001 From: Silberengel Date: Wed, 15 Apr 2026 22:37:23 +0200 Subject: [PATCH] bug-fixes --- .env.development | 6 +++ .gitignore | 1 + PROXY_SETUP.md | 2 +- docker-compose.dev.yml | 31 +++++++++---- docker-compose.prod.yml | 64 ++++++++++++++++++++++++++- docker-compose.yml | 26 +++++++---- package.json | 7 ++- scripts/dev-all-local.sh | 13 ++++++ scripts/ensure-libretranslate-dirs.sh | 10 +++++ scripts/stack-remote.sh | 14 ++++++ scripts/start-local-ancillary.sh | 6 +-- 11 files changed, 156 insertions(+), 24 deletions(-) create mode 100644 .env.development create mode 100644 scripts/dev-all-local.sh create mode 100755 scripts/ensure-libretranslate-dirs.sh create mode 100644 scripts/stack-remote.sh diff --git a/.env.development b/.env.development new file mode 100644 index 00000000..b14b7e0e --- /dev/null +++ b/.env.development @@ -0,0 +1,6 @@ +# Picked up automatically by `vite` / `npm run dev` / `npm run dev:all` (development mode only). +# Paths are same-origin; vite.config.ts proxies them to Docker (see npm run dev:all). +VITE_PROXY_SERVER=/sites +VITE_READ_ALOUD_TTS_URL=/api/piper-tts +VITE_LANGUAGE_TOOL_URL=/api/languagetool +VITE_TRANSLATE_URL=/api/translate diff --git a/.gitignore b/.gitignore index e32ba63c..51a2cc45 100644 --- a/.gitignore +++ b/.gitignore @@ -34,4 +34,5 @@ public/.og-image.raster.svg .venv-i18n .local-piper-data +.local-libretranslate scripts/i18n-overrides/.gaps diff --git a/PROXY_SETUP.md b/PROXY_SETUP.md index f4215801..f5f9ffb1 100644 --- a/PROXY_SETUP.md +++ b/PROXY_SETUP.md @@ -187,7 +187,7 @@ VITE_TRANSLATE_URL=/api/translate **Production:** `docker compose -f docker-compose.prod.yml --profile editor-tools up -d languagetool libretranslate` publishes **127.0.0.1:8010** and **127.0.0.1:5000** (loopback-only). Proxy those paths from Apache/nginx to the SPA origin, and bake the client with `LANGUAGE_TOOL_URL=/api/languagetool` and `TRANSLATE_URL=/api/translate` when running `./scripts/build-and-push-prod.sh`. -**Notes:** LanguageTool’s JVM image often needs **~1–2 GiB** RAM. LibreTranslate may **download models** on first start (can take several minutes). +**Notes:** LanguageTool’s JVM image often needs **~1–2 GiB** RAM. LibreTranslate **does not listen on port 5000 until models are ready**; without **`LT_LOAD_ONLY`** it may pull **many gigabytes** first, so the Vite proxy can show **`ECONNRESET` on `/translate`** while booting. Compose sets **`LT_LOAD_ONLY=en,de`** by default (override with **`LT_LOAD_ONLY`**). Models are stored under **`.local-libretranslate/share`** and **`.local-libretranslate/cache`** (gitignored) with **bind mounts** so they survive **`docker compose down`**, image updates, and container recreate. **`scripts/ensure-libretranslate-dirs.sh`** (run automatically by **`npm run dev:all`**, **`npm run stack:remote`**, **`npm run docker:editor-tools`**, etc.) creates those dirs and **`chown`s them to UID 1032** via a short **Alpine** container so the LibreTranslate user can write. If you start **`libretranslate` by hand**, run **`npm run docker:prep-libretranslate`** once first. First download can still take **several minutes**; use **`docker logs -f jumble-libretranslate`** until **`curl http://127.0.0.1:5000/languages`** returns JSON. ## LibreTranslate (same-origin `/api/translate`) diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index e545fc43..c2609e31 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -12,17 +12,22 @@ services: networks: - jumble - proxy-server: - image: ghcr.io/danvergara/jumble-proxy-server:latest - environment: - - ALLOW_ORIGIN=${JUMBLE_SOCIAL_URL:-http://localhost:8089} - - JUMBLE_PROXY_GITHUB_TOKEN=${JUMBLE_PROXY_GITHUB_TOKEN:-} - - ENABLE_PPROF=true - - PORT=8080 + # Link / OG preview — silberengel/wikistr (override: OG_PROXY_IMAGE). + og-proxy: + image: ${OG_PROXY_IMAGE:-silberengel/wikistr:latest-og-proxy} + container_name: jumble-og-proxy ports: - - "8090:8080" + - '127.0.0.1:8090:8090' + environment: + PROXY_PORT: '8090' + PROXY_ALLOW_ORIGIN: ${OG_PROXY_ALLOW_ORIGIN:-http://localhost:5173} + PROXY_TIMEOUT_MS: '30000' + PROXY_MAX_BODY_BYTES: '5242880' + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 'true' + PUPPETEER_EXECUTABLE_PATH: /usr/bin/chromium-browser networks: - jumble + restart: unless-stopped nostr-relay: image: scsibug/nostr-rs-relay:latest @@ -56,6 +61,13 @@ services: container_name: jumble-libretranslate ports: - '5000:5000' + # Without LT_LOAD_ONLY the image downloads many GB of models before binding :5000 — Vite then gets ECONNRESET on /translate. + tty: true + environment: + LT_LOAD_ONLY: ${LT_LOAD_ONLY:-en,de} + volumes: + - ./.local-libretranslate/share:/home/libretranslate/.local/share + - ./.local-libretranslate/cache:/home/libretranslate/.local/cache networks: - jumble restart: unless-stopped @@ -63,7 +75,7 @@ services: # Wyoming Piper + HTTP bridge (read-aloud). Profile local-tts — matches vite /api/piper-tts → :9876, Wyoming :10200. # Mount voices under ./.local-piper-data/voices (see PROXY_SETUP.md) or use your existing piper-data path. piper-wyoming: - image: silberengel/wyoming-piper:latest + image: ${WYOMING_PIPER_IMAGE:-silberengel/wyoming-piper:latest} profiles: ['local-tts'] container_name: jumble-piper-wyoming command: @@ -81,6 +93,7 @@ services: - jumble restart: unless-stopped + # No Hub image required — built from this repo. (Avoid silberengel/imwald-piper-tts-proxy:latest here until it exists on Docker Hub.) piper-tts-proxy: profiles: ['local-tts'] container_name: jumble-piper-tts-proxy diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 687bc510..e7e1ca27 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -1,5 +1,6 @@ # Minimal compose for running the published image (e.g. on remote server). -# Usage: docker compose -f docker-compose.prod.yml pull && docker compose -f docker-compose.prod.yml up -d +# Full stack (jumble + NIP-66 + og-proxy + Piper + LanguageTool + LibreTranslate): npm run stack:remote +# Usage (app only): docker compose -f docker-compose.prod.yml pull && docker compose -f docker-compose.prod.yml up -d # # Apache (unchanged on your host) should keep (order: specific paths before catch-all /): # ProxyPass /sites/ http://127.0.0.1:8090/sites/ @@ -83,8 +84,69 @@ services: container_name: imwald-libretranslate ports: - '127.0.0.1:5000:5000' + tty: true + environment: + LT_LOAD_ONLY: ${LT_LOAD_ONLY:-en,de} + volumes: + - ./.local-libretranslate/share:/home/libretranslate/.local/share + - ./.local-libretranslate/cache:/home/libretranslate/.local/cache restart: unless-stopped deploy: resources: limits: memory: 2048M + + # --- profile `stack`: OG proxy + Piper (Apache → 8090 / 9876). One command: npm run stack:remote --- + # First-party images: silberengel/* (override with OG_PROXY_IMAGE / WYOMING_PIPER_IMAGE / PIPER_HTTP_PROXY_IMAGE). + og-proxy: + image: ${OG_PROXY_IMAGE:-silberengel/wikistr:latest-og-proxy} + profiles: ['stack'] + container_name: og-proxy + ports: + - '127.0.0.1:8090:8090' + environment: + PROXY_PORT: '8090' + PROXY_ALLOW_ORIGIN: ${OG_PROXY_ALLOW_ORIGIN:-https://jumble.imwald.eu} + PROXY_TIMEOUT_MS: '30000' + PROXY_MAX_BODY_BYTES: '5242880' + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 'true' + PUPPETEER_EXECUTABLE_PATH: /usr/bin/chromium-browser + restart: unless-stopped + + piper-wyoming: + image: ${WYOMING_PIPER_IMAGE:-silberengel/wyoming-piper:latest} + profiles: ['stack'] + container_name: piper-tts + command: + - --voice + - en_US-lessac-medium + - --uri + - tcp://0.0.0.0:10200 + - --data-dir + - /data + volumes: + - piper-stack-data:/data + expose: + - '10200' + restart: unless-stopped + + piper-tts-proxy: + profiles: ['stack'] + container_name: imwald-piper-tts-proxy + build: + context: . + dockerfile: services/piper-tts-proxy/Dockerfile + image: ${PIPER_HTTP_PROXY_IMAGE:-silberengel/imwald-piper-tts-proxy:latest} + environment: + NODE_ENV: production + PORT: '9876' + PIPER_TTS_HOST: piper-wyoming + PIPER_TTS_PORT: '10200' + ports: + - '127.0.0.1:9876:9876' + depends_on: + - piper-wyoming + restart: unless-stopped + +volumes: + piper-stack-data: diff --git a/docker-compose.yml b/docker-compose.yml index 0f3904a8..de496714 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,17 +12,21 @@ services: networks: - jumble - proxy-server: - image: ghcr.io/danvergara/jumble-proxy-server:latest - environment: - - ALLOW_ORIGIN=${JUMBLE_SOCIAL_URL:-http://localhost:8089} - - JUMBLE_PROXY_GITHUB_TOKEN=${JUMBLE_PROXY_GITHUB_TOKEN:-} - - ENABLE_PPROF=true - - PORT=8080 + og-proxy: + image: ${OG_PROXY_IMAGE:-silberengel/wikistr:latest-og-proxy} + container_name: jumble-og-proxy ports: - - "8090:8080" + - '127.0.0.1:8090:8090' + environment: + PROXY_PORT: '8090' + PROXY_ALLOW_ORIGIN: ${OG_PROXY_ALLOW_ORIGIN:-http://localhost:5173} + PROXY_TIMEOUT_MS: '30000' + PROXY_MAX_BODY_BYTES: '5242880' + PUPPETEER_SKIP_CHROMIUM_DOWNLOAD: 'true' + PUPPETEER_EXECUTABLE_PATH: /usr/bin/chromium-browser networks: - jumble + restart: unless-stopped # Optional: same as docker-compose.dev.yml — `docker compose --profile editor-tools up -d languagetool libretranslate` languagetool: @@ -41,6 +45,12 @@ services: container_name: jumble-libretranslate ports: - '5000:5000' + tty: true + environment: + LT_LOAD_ONLY: ${LT_LOAD_ONLY:-en,de} + volumes: + - ./.local-libretranslate/share:/home/libretranslate/.local/share + - ./.local-libretranslate/cache:/home/libretranslate/.local/cache networks: - jumble restart: unless-stopped diff --git a/package.json b/package.json index 79a32429..58468637 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,12 @@ "homepage": "https://github.com/Silberengel/jumble", "scripts": { "dev": "vite --host", + "dev:all": "bash scripts/dev-all-local.sh", + "stack:remote": "bash scripts/stack-remote.sh", "dev:refresh": "rm -rf node_modules/.vite && vite --host", - "docker:editor-tools": "docker compose -f docker-compose.dev.yml --profile editor-tools up -d languagetool libretranslate", - "docker:local-ancillary": "docker compose -f docker-compose.dev.yml --profile editor-tools --profile local-tts up -d languagetool libretranslate piper-wyoming piper-tts-proxy", + "docker:prep-libretranslate": "bash scripts/ensure-libretranslate-dirs.sh", + "docker:editor-tools": "bash scripts/ensure-libretranslate-dirs.sh && docker compose -f docker-compose.dev.yml --profile editor-tools up -d languagetool libretranslate", + "docker:local-ancillary": "bash scripts/ensure-libretranslate-dirs.sh && docker compose -f docker-compose.dev.yml --profile editor-tools --profile local-tts build piper-tts-proxy && docker compose -f docker-compose.dev.yml --profile editor-tools --profile local-tts up -d og-proxy languagetool libretranslate piper-wyoming piper-tts-proxy", "piper-tts-proxy": "cross-env NODE_ENV=development npx --yes tsx services/piper-tts-proxy/http.ts", "build": "tsc -b && vite build", "lint": "eslint .", diff --git a/scripts/dev-all-local.sh b/scripts/dev-all-local.sh new file mode 100644 index 00000000..4829f49f --- /dev/null +++ b/scripts/dev-all-local.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# One local command: Docker backends + Vite (Ctrl+C stops Vite; Docker keeps running). +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" +export OG_PROXY_ALLOW_ORIGIN="${OG_PROXY_ALLOW_ORIGIN:-http://localhost:5173}" +mkdir -p .local-piper-data +bash "$ROOT/scripts/ensure-libretranslate-dirs.sh" +docker compose -f docker-compose.dev.yml --profile editor-tools --profile local-tts build piper-tts-proxy +docker compose -f docker-compose.dev.yml --profile editor-tools --profile local-tts up -d \ + og-proxy languagetool libretranslate piper-wyoming piper-tts-proxy +echo "[dev:all] Jumble=Vite (.env.development → /sites, /api/piper-tts, lab APIs) | og-proxy :8090 | Piper :9876" +exec npm run dev diff --git a/scripts/ensure-libretranslate-dirs.sh b/scripts/ensure-libretranslate-dirs.sh new file mode 100755 index 00000000..454de797 --- /dev/null +++ b/scripts/ensure-libretranslate-dirs.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Host dirs for LibreTranslate bind mounts must be writable by container UID 1032 (see docker-compose*.yml). +# Uses a one-shot Alpine container so you do not need sudo chown on the host. +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +mkdir -p "$ROOT/.local-libretranslate/share" "$ROOT/.local-libretranslate/cache" +docker run --rm \ + -v "$ROOT/.local-libretranslate/share:/s" \ + -v "$ROOT/.local-libretranslate/cache:/c" \ + alpine:3.20 chown -R 1032:1032 /s /c diff --git a/scripts/stack-remote.sh b/scripts/stack-remote.sh new file mode 100644 index 00000000..9f7ed97f --- /dev/null +++ b/scripts/stack-remote.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +# One remote command from repo clone: silberengel/imwald-jumble + nip66 + wikistr og-proxy + wyoming-piper + +# imwald-piper-tts-proxy (built here; push silberengel/imwald-piper-tts-proxy:latest to Hub for pull-only hosts) + +# LanguageTool + LibreTranslate. Apache → 8089 / 8090 / 9876. +set -euo pipefail +ROOT="$(cd "$(dirname "$0")/.." && pwd)" +cd "$ROOT" +bash "$ROOT/scripts/ensure-libretranslate-dirs.sh" +COMPOSE=(docker compose -f docker-compose.prod.yml --profile stack --profile editor-tools) +# Pull Hub images only; piper-tts-proxy is built from this repo (push silberengel/imwald-piper-tts-proxy:latest when ready). +"${COMPOSE[@]}" pull jumble jumble-nip66-monitor og-proxy piper-wyoming languagetool libretranslate +"${COMPOSE[@]}" build piper-tts-proxy +"${COMPOSE[@]}" up -d +echo "[stack:remote] jumble :8089 | og-proxy :8090 | piper HTTP :9876 | LT :8010 | translate :5000" diff --git a/scripts/start-local-ancillary.sh b/scripts/start-local-ancillary.sh index f37f3b2f..bcf53ed5 100644 --- a/scripts/start-local-ancillary.sh +++ b/scripts/start-local-ancillary.sh @@ -1,12 +1,12 @@ #!/usr/bin/env bash -# Start LanguageTool, LibreTranslate, Wyoming Piper, and the Piper HTTP proxy (Docker). -# Run the app separately: npm run dev +# Prefer: npm run dev:all (backends + Vite in one go). +# This script only starts Docker (no Vite): og-proxy, LanguageTool, LibreTranslate, Wyoming Piper, Piper HTTP proxy. # Optional .env.local (Vite): VITE_READ_ALOUD_TTS_URL=/api/piper-tts VITE_LANGUAGE_TOOL_URL=/api/languagetool VITE_TRANSLATE_URL=/api/translate set -euo pipefail cd "$(dirname "$0")/.." mkdir -p .local-piper-data npm run docker:local-ancillary echo -echo "Ancillary stack is up (LanguageTool :8010, LibreTranslate :5000, Piper proxy :9876)." +echo "Ancillary stack is up (og-proxy :8090, LanguageTool :8010, LibreTranslate :5000, Piper HTTP :9876)." echo "Wyoming Piper listens inside Docker only; the HTTP proxy on 127.0.0.1:9876 forwards to it." echo "Next: npm run dev"