# Bedienungsanleitung — Open Notebook (lokales Deployment) Diese Anleitung deckt die **tägliche Benutzung** ab. Installation/Neuaufbau: siehe [`README.md`](README.md). Technische Hintergründe und Architektur: siehe [`CLAUDE.md`](CLAUDE.md). --- ## Inhalt 1. [Zugriff](#1-zugriff) 2. [Notebooks und Quellen](#2-notebooks-und-quellen) 3. [Chat: die drei Kontext-Modi](#3-chat-die-drei-kontext-modi) 4. [Podcasts erzeugen](#4-podcasts-erzeugen) 5. [Stimmklonung](#5-stimmklonung) 6. [Modelle und Provider verwalten](#6-modelle-und-provider-verwalten) 7. [Dienste starten/stoppen](#7-dienste-startenstoppen) 8. [Troubleshooting](#8-troubleshooting) --- ## 1. Zugriff - **Web-Oberfläche:** `http://localhost:8502` - **REST-API** (für Automatisierung/Skripte): `http://localhost:5055`, Doku unter `http://localhost:5055/docs` Beide sind nur von diesem Rechner aus erreichbar (`127.0.0.1`), nicht aus dem Netzwerk. --- ## 2. Notebooks und Quellen Ein **Notebook** bündelt Quellen, Notizen, Chats und Podcasts zu einem Thema. Neues Notebook über „+ New Notebook" in der UI anlegen. ### Quellen hinzufügen Unterstützt: hochgeladene Dateien (PDF, EPUB, TXT, DOCX, …), URLs, eingefügter Text. **Wie lang darf eine Datei sein?** Es gibt kein hartes Limit für Upload/Verarbeitung — auch sehr große PDFs/EPUBs werden vollständig extrahiert und in Textabschnitte („Chunks") zerlegt, die für die Suche eingebettet werden. Eine Längenbegrenzung greift nur, wenn eine Quelle im **„Volltext"-Kontextmodus** (siehe Abschnitt 3) oder für eine **Transformation** verwendet wird — dort geht der komplette Text in einem Stück an das Sprachmodell. Praktischer Richtwert bei `qwen3.5:27b` (98.304 Tokens Kontext, siehe Abschnitt 6): grob **180–350 Buchseiten**, abhängig von Textdichte. Wichtig: Die **Datei­größe in MB sagt nichts über die Textmenge aus** — ein gescanntes PDF mit vielen Bildern kann riesig sein, aber nach der Texterkennung kaum Inhalt liefern. ### Verarbeitungsstatus prüfen Nach dem Hochladen läuft die Verarbeitung (Extraktion → Chunking → Embedding) im Hintergrund. Bei großen Dateien kann das ein bis mehrere Minuten dauern. Status ist in der UI an der Quelle sichtbar; per API: `GET /api/sources/{source_id}/status`. --- ## 3. Chat: die drei Kontext-Modi Beim Chatten mit einem Notebook lässt sich pro Quelle einstellen, wie viel davon in den Chat-Kontext einfließt (Buttons/Auswahl in der UI, z. B. als Sammel-Aktion für alle Quellen): | UI-Option | Bedeutung | Geschwindigkeit | |---|---|---| | **Alle aus dem Kontext ausschließen** | Quelle wird ignoriert | – | | **Alle aufnehmen (nur Erkenntnisse)** | Nutzt die generierten „Insights" (Zusammenfassungen) der Quelle | schnell (Sekunden) | | **Alle aufnehmen (vollständiger Inhalt)** | Kompletter Text der Quelle geht an das Sprachmodell | langsam bei langen Dokumenten (bis zu einigen Minuten) | ### Wichtig: „nur Erkenntnisse" braucht vorher eine Transformation Der Modus „nur Erkenntnisse" ist **nur dann nützlich, wenn für die Quelle bereits eine Zusammenfassung („Insight") erzeugt wurde**. Ohne das liefert er praktisch nichts (nur Titel/ Metadaten). Eine Zusammenfassung erzeugen: - In der UI: bei der Quelle eine Transformation anwenden, z. B. **„Simple Summary"** (für die meisten Fälle passend) oder „Dense Summary", „Key Insights", „Table of Contents". - Per API: ```bash curl -X POST http://127.0.0.1:5055/api/sources/{source_id}/insights \ -H "Content-Type: application/json" \ -d '{"transformation_id": ""}' ``` - Bei langen Dokumenten (z. B. ein ganzes Buch) dauert das einmalig **einige Minuten** (die gesamte Quelle wird einmal durchs Sprachmodell geschickt) — danach ist „nur Erkenntnisse" aber dauerhaft schnell nutzbar. ### Faustregel - **Normale Fragen, Überblick, grobe Zusammenhänge** → „nur Erkenntnisse" (nach einmaliger Zusammenfassung) - **Sehr spezifische Detailfrage** (z. B. exaktes Zitat aus einem bestimmten Kapitel), die in der Zusammenfassung fehlen könnte → „vollständiger Inhalt", dafür Geduld bei langen Quellen - **Quelle für die aktuelle Frage irrelevant** → ausschließen (spart Zeit bei mehreren Quellen) Für gezielte Detailsuche über viele/lange Quellen gibt es außerdem eine separate **Such-/Ask-Funktion**, die per Embedding-Ähnlichkeitssuche automatisch nur die relevanten Textstellen findet, statt ganze Dokumente einzubeziehen — meist die schnellste und treffsicherste Option für Detailfragen in langen Werken. --- ## 4. Podcasts erzeugen Open Notebook kann aus Notebook-Inhalten automatisch einen Podcast (Dialog zwischen ein oder mehreren Sprechern) erzeugen — Text via Sprachmodell, Audio via TTS (hier: lokal, Chatterbox). 1. **Episode-Profil** wählen (bestimmt Sprecherzahl/-rollen, Anzahl Segmente, Textmodell): `solo_expert` (1 Sprecher), `tech_discussion` (2 Sprecher), `business_analysis` (3 Sprecher). 2. Notebook/Quelle als Grundlage angeben. 3. Generierung starten — läuft asynchron (Outline → Transkript → Sprachsynthese pro Segment). Bei mehreren Sprechern und langen Transkripten realistisch **mehrere Minuten**, da jedes Dialogsegment einzeln per TTS synthetisiert wird. 4. Fertige Episode in der UI abspielbar/herunterladbar. Alle Episode-/Sprecherprofile sind bereits auf lokale Modelle (`qwen3.5:27b` für Text, Chatterbox für Sprache) umgestellt — keine zusätzlichen Kosten. --- ## 5. Stimmklonung Die TTS-Wrapper (`services/tts_server.py`) unterstützt Stimmklonung: Referenz-WAV rein, Stimme raus. Aktuell hinterlegte Stimmen: `default` (eigene Stimme), `male_thorsten` und `female_kerstin` (offen lizenzierte, synthetische Piper-Stimmen — bewusst **keine** ungefragt geklonten echten Personen, siehe [`CLAUDE.md`](CLAUDE.md)). ### Eine weitere Stimme hinzufügen 1. Referenz-Aufnahme besorgen: **10–30 Sekunden**, eine Person, saubere Aufnahme, WAV-Format. Rechtlich sauber ist entweder eine eigene Aufnahme, eine Aufnahme mit ausdrücklicher Zustimmung der Person, oder eine offen für diesen Zweck lizenzierte Stimme (z. B. weitere [Piper-Stimmen](https://huggingface.co/rhasspy/piper-voices)). 2. Datei nach `services/voices/.wav` legen (z. B. `services/voices/elena.wav`). 3. TTS-Server neu starten (Stimmen werden nur beim Start eingelesen): ```bash pkill -f "python tts_server.py" ./scripts/start_services.sh ``` 4. Prüfen: `curl http://127.0.0.1:8901/health` sollte `` in der `voices`-Liste zeigen. 5. In einem Sprecherprofil (Podcast) den betreffenden Sprecher auf `voice_id: ""` setzen, z. B. per API: ```bash curl -X PUT http://127.0.0.1:5055/api/speaker-profiles/{id} \ -H "Content-Type: application/json" -d '{... "speakers": [{"name": "Elena", ..., "voice_id": "elena"}], ...}' ``` Mit Piper lässt sich auch selbst eine Referenz-Stimme synthetisieren (statt eine echte Aufnahme zu verwenden): ```bash echo "Ein Beispielsatz auf Deutsch." | piper --model .onnx --output_file services/voices/.wav ``` Weitere deutsche Piper-Stimmen: `huggingface.co/rhasspy/piper-voices/tree/main/de/de_DE` (Lizenz jeweils im `MODEL_CARD` prüfen). --- ## 6. Modelle und Provider verwalten Übersicht unter **Settings → AI Providers / Models** in der UI, oder per API: ```bash curl http://127.0.0.1:5055/api/models | python3 -m json.tool # alle registrierten Modelle curl http://127.0.0.1:5055/api/models/defaults | python3 -m json.tool # aktuelle Standardmodelle ``` ### Standardmodelle ändern Sieben Rollen lassen sich unabhängig belegen: Chat, Transformation, großer Kontext, Embedding, Tools, Text-to-Speech, Speech-to-Text. ```bash curl -X PUT http://127.0.0.1:5055/api/models/defaults \ -H "Content-Type: application/json" \ -d '{"default_tools_model": ""}' ``` Der Endpunkt aktualisiert nur die tatsächlich mitgeschickten Felder — nicht angegebene Felder bleiben unverändert, es muss also nicht der komplette Satz aller sieben Modelle mitgeschickt werden. ### Kostenübersicht der aktuell registrierten Modelle | Modell | Provider | Kosten | |---|---|---| | `qwen3.5:27b` | Ollama (lokal) | 0 € (Standard für Chat/Tools/großer Kontext) | | `nomic-embed-text` | Ollama (lokal) | 0 € (Standard-Embedding) | | `qwen3-coder-30b-128k` | Ollama (lokal) | 0 € (optional, für Coding-Aufgaben) | | Chatterbox TTS / faster-whisper | lokal | 0 € | | `anthropic/claude-sonnet-5` | OpenRouter | ~2$/10$ pro Mio. Tokens (Prompt/Antwort) | | `qwen/qwen3-max` | OpenRouter | ~0,78$/3,90$ pro Mio. Tokens — günstigere Cloud-Alternative | | `google/gemini-3.5-flash` | OpenRouter | ~1,50$/9$ pro Mio. Tokens — 1M Tokens Kontext | Weitere OpenRouter-Modelle lassen sich jederzeit über `POST /api/models` registrieren (`provider: "openrouter"`) — aktuelle Preise: `https://openrouter.ai/api/v1/models`. --- ## 7. Dienste starten/stoppen ```bash # Open Notebook (Docker) docker compose up -d docker compose down # TTS/STT (lokale Hintergrundprozesse, nicht in Docker) ./scripts/start_services.sh pkill -f "python tts_server.py" pkill -f "python stt_server.py" ``` Ollama selbst läuft als systemd-Dienst und muss normalerweise nicht manuell verwaltet werden: ```bash systemctl status ollama ollama ps # aktuell geladene Modelle + GPU/CPU-Verteilung ``` --- ## 8. Troubleshooting ### „Chat gibt keine Antwort" (leere Antwort, kein Fehler) Meist ein zu kleiner Kontext (`num_ctx`) am Ollama-Chat-Credential — siehe README, Abschnitt 2.6. Prüfen: ```bash curl -s http://127.0.0.1:5055/api/credentials | python3 -c " import json,sys for c in json.load(sys.stdin): if c['provider']=='ollama': print(c['name'], c['num_ctx'])" ``` Sollte `98304` (oder höher, dann ggf. auf GPU-Auslastung achten) zeigen, nicht `None`/`null`. ### Quelle hängt beim Verarbeiten / Einbetten fest (Endlos-Retry) Meist Ressourcen-Engpass beim Embedding-Modell (GPU voll, Modell läuft teilweise auf CPU, Timeout). Prüfen: ```bash ollama ps # PROCESSOR-Spalte: sollte "100% GPU" zeigen, nicht "xx%/yy% CPU/GPU" ``` Falls CPU-Anteil: Embedding-Modell ist zu groß für den freien GPU-Speicher. Standardmäßig ist hier das kleine `nomic-embed-text` (274 MB) konfiguriert, das läuft normalerweise problemlos komplett auf der GPU. ### Antwort dauert sehr lange (mehrere Minuten) Meist normal bei „vollständiger Inhalt"-Modus auf langen Dokumenten (siehe Abschnitt 3) — das Sprachmodell muss den kompletten Text lesen. Für Detailfragen auf lange Sicht besser die Such-/Ask-Funktion oder „nur Erkenntnisse" nach einer Zusammenfassung nutzen. ### TTS/STT vom Container aus nicht erreichbar ```bash docker compose exec open_notebook curl -sf http://host.docker.internal:8901/health ``` Bei Timeout: `ufw`-Regeln fehlen (siehe README 2.4) oder die Server laufen nicht (`./scripts/start_services.sh`). ### Podcast-Profil zeigt „Einrichtung erforderlich" Das Episode- oder Sprecherprofil verweist auf ein Modell ohne konfiguriertes Credential (z. B. nach einem Reset auf die mitgelieferten OpenAI-Standardprofile). Modell-IDs über `PUT /api/episode-profiles/{id}` (`outline_llm`, `transcript_llm`) bzw. `PUT /api/speaker-profiles/{id}` (`voice_model`) auf registrierte lokale/OpenRouter-Modelle umstellen — siehe `scripts/setup_models.sh` für die IDs der Standardmodelle. ### Podcast wird auf Englisch statt Deutsch erzeugt Das verwendete Episode-Profil hat kein `language`-Feld gesetzt — ohne Angabe generiert das Sprachmodell standardmäßig auf Englisch, unabhängig von der Sprache der Quelle. Prüfen und korrigieren: ```bash curl -s http://127.0.0.1:5055/api/episode-profiles | python3 -c \ "import json,sys; [print(p['name'], p['language']) for p in json.load(sys.stdin)]" ``` Fehlt `de`, per `PUT /api/episode-profiles/{id}` (vollständiger Body nötig, siehe oben) `"language": "de"` ergänzen. Die drei mitgelieferten Profile (`business_analysis`, `solo_expert`, `tech_discussion`) sind bereits korrigiert; bei neu angelegten eigenen Profilen selbst daran denken. ### Weitere technische Details Siehe [`CLAUDE.md`](CLAUDE.md) — dort stehen alle bisher aufgetretenen Probleme mit exakter Ursache (Codestellen, Bibliotheks-Bugs) dokumentiert.