diff --git a/BEDIENUNGSANLEITUNG.md b/BEDIENUNGSANLEITUNG.md index cb9fccf..f86ed80 100644 --- a/BEDIENUNGSANLEITUNG.md +++ b/BEDIENUNGSANLEITUNG.md @@ -15,9 +15,10 @@ siehe [`CLAUDE.md`](CLAUDE.md). 5. [Stimmklonung](#5-stimmklonung) 6. [Modelle und Provider verwalten](#6-modelle-und-provider-verwalten) 7. [Dienste starten/stoppen](#7-dienste-startenstoppen) -8. [Suche über Chunks (Search/Ask)](#8-suche-über-chunks-searchask) -9. [Die API in eigenen Programmen nutzen](#9-die-api-in-eigenen-programmen-nutzen) -10. [Troubleshooting](#10-troubleshooting) +8. [Updates einspielen](#8-updates-einspielen) +9. [Suche über Chunks (Search/Ask)](#9-suche-über-chunks-searchask) +10. [Die API in eigenen Programmen nutzen](#10-die-api-in-eigenen-programmen-nutzen) +11. [Troubleshooting](#11-troubleshooting) --- @@ -256,7 +257,54 @@ ollama ps # aktuell geladene Modelle + GPU/CPU-Verteilung --- -## 8. Suche über Chunks (Search/Ask) +## 8. Updates einspielen + +Open Notebook läuft hier auf einer **festgenagelten Version** (Digest-Pin in +`docker-compose.yml`). Weder ein Start noch ein Reboot tauscht die Anwendung unbemerkt aus — Sie +bekommen immer genau den Stand, der zuletzt geprüft wurde. + +**Beim Sitzungsstart** (ändert nichts, dauert Sekunden): + +```bash +./scripts/check_updates.sh +``` + +Ausgabe entweder „Du laeufst auf dem aktuellen Release. Nichts zu tun." oder ein Hinweis auf ein +neues Image. + +**Update einspielen:** + +```bash +./scripts/update_stack.sh +``` + +Das Skript sichert zuerst Datenbank und Notebook-Daten nach `backups//`, stellt dann +auf das neue Image um, startet den Stack und fährt einen **Rauchtest** (API, Sprachausgabe, +Spracherkennung, YouTube-Import, alle lokalen Anpassungen). Schlägt der fehl, wird **automatisch +zurückgerollt** — Daten und Konfiguration landen wieder auf dem alten Stand. + +Läuft alles, committen Sie den neuen Stand: + +```bash +git add docker-compose.yml && git commit -m "Update auf " +``` + +**Warum nicht einfach immer die neueste Version?** Ein Update verändert das Datenbankschema, und +eine ältere Version kann eine bereits migrierte Datenbank in der Regel nicht mehr lesen — ohne +Sicherung wäre ein misslungenes Update also eine Einbahnstraße. Außerdem hängen die Anpassungen +dieser Installation (Podcast-Vorlagen, YouTube-Sprachen, TTS-Einstellungen) an Interna der +Anwendung und können durch ein Update **still** kaputtgehen, ohne dass etwas abstürzt. Genau +deshalb der Rauchtest. + +Ihn können Sie auch jederzeit einzeln laufen lassen, etwa wenn sich etwas seltsam verhält: + +```bash +./scripts/smoke_test.sh +``` + +--- + +## 9. Suche über Chunks (Search/Ask) Jedes Dokument wird beim Hochladen automatisch in feste, überlappende Textabschnitte ("Chunks", ~400 Tokens) zerlegt und eingebettet — **nicht** kapitelweise, sondern rein @@ -300,7 +348,7 @@ weil nur die relevanten Chunks statt des ganzen Dokuments verarbeitet werden. --- -## 9. Die API in eigenen Programmen nutzen +## 10. Die API in eigenen Programmen nutzen Die REST-API ist eine ganz normale JSON-über-HTTP-API **ohne Authentifizierung** — kein API-Key nötig, da nur `127.0.0.1` gebunden (jeder lokale Prozess auf diesem Rechner hat Zugriff, aber @@ -361,7 +409,7 @@ Spezifisches nötig, kein SDK erforderlich. --- -## 10. Troubleshooting +## 11. Troubleshooting ### „Chat gibt keine Antwort" (leere Antwort, kein Fehler) diff --git a/CLAUDE.md b/CLAUDE.md index 4d8b223..aac3bc6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## What this repo is -This is a local Docker Compose deployment of [Open Notebook](https://github.com/lfnovo/open-notebook) (upstream image `lfnovo/open_notebook`), not a clone of its source. There is no application source code here — only deployment config (`docker-compose.yml`, `.env`, `.gitignore`). Application bugs/features belong upstream; this repo only concerns itself with how the stack is run locally. +This is a local Docker Compose deployment of [Open Notebook](https://github.com/lfnovo/open-notebook) (upstream image `lfnovo/open_notebook`), not a clone of its source. The application's own code is **not** here and its bugs/features belong upstream — this repo only concerns itself with how the stack is run locally. + +What *is* here, beyond `docker-compose.yml`/`.env`: + +- `services/` — our own source: the TTS/STT wrapper servers (Open Notebook has no local TTS/STT provider) plus their systemd units. +- `scripts/` — setup, maintenance and update tooling (see Commands below). +- `prompts/podcast/`, `config/content_core.yaml` — **overlays** bind-mounted over files inside the image, to fix upstream behaviour we can't configure otherwise (podcast language/reliability, YouTube caption languages). These are the fragile part: they can silently rot when the image is updated, which is what `scripts/smoke_test.sh` exists to catch. ## Commands @@ -71,7 +77,7 @@ check. Two services, defined in `docker-compose.yml`: - **surrealdb** (`surrealdb/surrealdb:v2`) — the database, RocksDB-backed, bound to `127.0.0.1:8000` only (local debugging access, e.g. `surreal sql`). Credentials come from `SURREAL_USER`/`SURREAL_PASSWORD` (default `root`/`root` if unset in `.env`) and are shared with the `open_notebook` service so they stay in sync. -- **open_notebook** (`lfnovo/open_notebook:v1-latest`) — bundles the web UI (port 8502) and REST API (port 5055) in one image, both bound to `127.0.0.1` only. Connects to `surrealdb` over the internal compose network (`ws://surrealdb:8000/rpc`). +- **open_notebook** (`lfnovo/open_notebook:v1-latest`, digest-pinned — see *Image versioning*) — bundles the web UI (port 8502) and REST API (port 5055) in one image, both bound to `127.0.0.1` only. Connects to `surrealdb` over the internal compose network (`ws://surrealdb:8000/rpc`). Data persists in `./surreal_data` and `./notebook_data` (bind mounts, gitignored). @@ -130,8 +136,9 @@ dialogue segment), `outline.json` and `transcript.json`, is never touched, and n Failed and `/retry`-replaced runs leak a directory too (the retry writes a *new* episode row with a new uuid dir; the old one loses its DB entry and just stays). Upstream this would be roughly `shutil.rmtree(audio_path.parent.parent)` in that handler. We deliberately do **not** patch it here by -bind-mounting a modified router — that would fork app logic into a deployment repo and silently rot -against `pull_policy: always`. Instead: `scripts/prune_podcast_data.py` (dry-run by default, `--yes` to +bind-mounting a modified router — that would fork app logic into a deployment repo and rot against +image updates (the same trap the existing overlays already carry). Instead: +`scripts/prune_podcast_data.py` (dry-run by default, `--yes` to apply) reconciles the episode list from the API against the directories on disk and removes orphans plus the `clips/` of completed episodes. Two guards matter — it aborts if any job is `running`/`pending` (a running job has no `audio_file` yet, so its directory is indistinguishable from an orphan) and it diff --git a/README.md b/README.md index cfe0839..4dcdbf7 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,8 @@ Der `open_notebook`-Container erreicht Ollama und die TTS/STT-Wrapper über in Schritt 2) - **`ufw`** (falls als Firewall aktiv) — Standardrichtlinie „deny incoming“ wird vorausgesetzt - **`openssl`**, **`ffmpeg`**, **`curl`**, **`python3`** +- **`yt-dlp`** — nur für `scripts/add_video_source.py` (Videos ohne Untertitel); der übrige Stack + läuft auch ohne --- @@ -80,11 +82,14 @@ chmod 600 .env ### 2.3 Container starten ```bash -docker compose pull docker compose up -d docker compose ps # beide Container sollten "Up" sein ``` +Die Images sind in `docker-compose.yml` auf einen **Digest gepinnt** (`pull_policy: missing`) — +`up -d` lädt sie beim ersten Mal und danach nie wieder unbemerkt eine andere Version. Aktualisiert +wird bewusst, siehe [Abschnitt 4](#4-updates). + Web-UI: `http://localhost:8502` · REST-API: `http://localhost:5055` (beide nur `127.0.0.1`). ### 2.4 Firewall öffnen für TTS/STT @@ -123,7 +128,7 @@ journalctl --user -u open-notebook-tts -f Für Stimmklonung mindestens eine Referenz-WAV in `services/voices/default.wav` ablegen (z. B. Symlink auf eine eigene Sprachaufnahme, 10–30s, WAV) — siehe -[`BEDIENUNGSANLEITUNG.md`](BEDIENUNGSANLEITUNG.md#stimmklonung). +[`BEDIENUNGSANLEITUNG.md`](BEDIENUNGSANLEITUNG.md#5-stimmklonung). ### 2.6 KI-Provider und Modelle registrieren @@ -161,6 +166,12 @@ curl -s http://127.0.0.1:8901/health # Chatterbox TTS curl -s http://127.0.0.1:8902/health # faster-whisper STT ``` +Gründlicher — prüft API, TTS, STT, YouTube-Extraktion und alle lokalen Anpassungen auf einmal: + +```bash +./scripts/smoke_test.sh +``` + UI öffnen (`http://localhost:8502`), ein Notebook anlegen, eine Quelle hinzufügen und chatten — siehe [`BEDIENUNGSANLEITUNG.md`](BEDIENUNGSANLEITUNG.md) für die weitere Bedienung. @@ -194,7 +205,7 @@ Ersteinrichtung bzw. nach Änderungen an den Unit-Dateien nötig. --- -## 3a. Updates +## 4. Updates Die Images sind **auf einen Digest gepinnt** — es läuft immer genau der Stand, der im Repo steht. Weder ein `docker compose up -d` noch ein Reboot tauscht die Anwendung unbemerkt aus. @@ -223,7 +234,7 @@ typischerweise Wochen voraus, aber unveröffentlicht. Wer den will, müsste selb --- -## 4. Verzeichnisstruktur +## 5. Verzeichnisstruktur ``` open-notebook/ @@ -256,7 +267,7 @@ open-notebook/ --- -## 5. Bekannte Stolpersteine +## 6. Bekannte Stolpersteine Kurzreferenz — Details jeweils in [`CLAUDE.md`](CLAUDE.md): @@ -297,4 +308,4 @@ Kurzreferenz — Details jeweils in [`CLAUDE.md`](CLAUDE.md): Vorlagen enthalten zusätzlich `/no_think`, damit `qwen3.5:27b` bei langem Quellinhalt nicht durch überlange Reasoning-Blöcke ungültiges JSON liefert. Änderst du die Vorlagen, danach `docker compose up -d --force-recreate open_notebook`. Details: - [`BEDIENUNGSANLEITUNG.md`](BEDIENUNGSANLEITUNG.md#10-troubleshooting) und [`CLAUDE.md`](CLAUDE.md). + [`BEDIENUNGSANLEITUNG.md`](BEDIENUNGSANLEITUNG.md#11-troubleshooting) und [`CLAUDE.md`](CLAUDE.md).