Consolidates and extends the curl patterns already scattered across other sections into one reference point, notes the API requires no auth (loopback- only), and points to the interactive /docs Swagger UI as the best starting point for exploring endpoints not yet covered here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
401 lines
17 KiB
Markdown
401 lines
17 KiB
Markdown
# 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. [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)
|
||
|
||
---
|
||
|
||
## 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 **Dateigröß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": "<id aus GET /api/transformations>"}'
|
||
```
|
||
- 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/<name>.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 `<name>` in der `voices`-Liste zeigen.
|
||
5. In einem Sprecherprofil (Podcast) den betreffenden Sprecher auf `voice_id: "<name>"` 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 <stimme>.onnx --output_file services/voices/<name>.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": "<model_id>"}'
|
||
```
|
||
|
||
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. 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
|
||
größenbasiert (siehe Abschnitt 2). Um gezielt in diesen Chunks zu suchen, gibt es zwei
|
||
API-Endpunkte (in der UI vermutlich unter einem eigenen Menüpunkt wie „Search"/„Ask" mit
|
||
Lupen-Symbol, getrennt von „Mit Notebook chatten" — die genaue Beschriftung war ohne
|
||
Browser-Zugriff nicht zu verifizieren):
|
||
|
||
### Einfache Suche — schnell, liefert Roh-Textstellen
|
||
|
||
```bash
|
||
curl -s -X POST http://127.0.0.1:5055/api/search \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"query": "Suchbegriff", "type": "vector", "limit": 5}'
|
||
```
|
||
|
||
Liefert die ähnlichsten Chunks per Embedding-Vergleich samt Ähnlichkeits-Score (0–1), ohne
|
||
KI-Interpretation — am schnellsten, aber du musst die Antwort selbst zusammensetzen.
|
||
|
||
### „Ask" — durchsuchen und direkt beantworten lassen
|
||
|
||
Die smartere Variante: Die KI zerlegt die Frage selbst in mehrere gezielte Suchanfragen,
|
||
durchsucht die Chunks für jede getrennt und fasst alles zu einer einzigen, mit
|
||
Quellenverweisen (`[source:...]`) belegten Antwort zusammen. Getestet mit „Wie kam Wallenstein
|
||
ums Leben?" — Ergebnis war eine vollständige, korrekt zitierte Antwort in ca. 3 Minuten
|
||
(mehrere LLM-Aufrufe hintereinander: Suchstrategie → Einzelantworten → Zusammenfassung).
|
||
|
||
```bash
|
||
MODEL_ID=$(curl -s http://127.0.0.1:5055/api/models/defaults | python3 -c "import json,sys; print(json.load(sys.stdin)['default_chat_model'])")
|
||
curl -N -X POST http://127.0.0.1:5055/api/search/ask \
|
||
-H "Content-Type: application/json" \
|
||
-d "{\"question\": \"Deine Frage\", \"strategy_model\": \"$MODEL_ID\", \"answer_model\": \"$MODEL_ID\", \"final_answer_model\": \"$MODEL_ID\"}"
|
||
```
|
||
|
||
Antwort kommt als Server-Sent-Events-Stream (`data: {...}`-Zeilen, kein einzelnes JSON-Objekt);
|
||
das letzte `"type": "complete"`-Event enthält die finale Antwort im Feld `final_answer`.
|
||
|
||
**Wann was nutzen:** Für gezielte Detailfragen über lange/viele Quellen ist „Ask" meist
|
||
treffsicherer und dabei noch schneller als der „vollständiger Inhalt"-Chat-Modus (Abschnitt 3),
|
||
weil nur die relevanten Chunks statt des ganzen Dokuments verarbeitet werden.
|
||
|
||
---
|
||
|
||
## 9. 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
|
||
niemand aus dem Netzwerk). Funktioniert mit jeder Sprache, die HTTP kann.
|
||
|
||
**Bester Startpunkt:** `http://127.0.0.1:5055/docs` — interaktive Swagger-UI mit allen
|
||
Endpunkten, Schemas und einer „Try it out"-Funktion zum direkten Ausprobieren im Browser.
|
||
Rohes OpenAPI-Schema: `http://127.0.0.1:5055/openapi.json`.
|
||
|
||
### Mit curl
|
||
|
||
```bash
|
||
# Notebooks auflisten
|
||
curl -s http://127.0.0.1:5055/api/notebooks | python3 -m json.tool
|
||
|
||
# Neues Notebook anlegen
|
||
curl -s -X POST http://127.0.0.1:5055/api/notebooks \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"name": "Mein Notebook", "description": "..."}'
|
||
|
||
# Text-Quelle hinzufügen (multipart, nicht JSON)
|
||
curl -s -X POST http://127.0.0.1:5055/api/sources \
|
||
-F "type=text" -F "notebook_id=notebook:xxx" -F "title=..." \
|
||
-F "content=..." -F "embed=true"
|
||
|
||
# Chat-Session erstellen + Nachricht senden
|
||
curl -s -X POST http://127.0.0.1:5055/api/chat/sessions \
|
||
-H "Content-Type: application/json" -d '{"notebook_id": "notebook:xxx"}'
|
||
curl -s -X POST http://127.0.0.1:5055/api/chat/execute \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"session_id": "chat_session:xxx", "message": "...", "context": {}}'
|
||
```
|
||
|
||
Weitere Beispiele (Quellen-Insights, Podcast-Generierung, Modell-/Provider-Verwaltung,
|
||
Chunk-Suche) stehen bereits in den jeweiligen Abschnitten dieser Anleitung.
|
||
|
||
### Aus Python
|
||
|
||
```python
|
||
import requests
|
||
|
||
BASE = "http://127.0.0.1:5055/api"
|
||
|
||
notebooks = requests.get(f"{BASE}/notebooks").json()
|
||
|
||
session = requests.post(f"{BASE}/chat/sessions",
|
||
json={"notebook_id": notebooks[0]["id"]}).json()
|
||
answer = requests.post(f"{BASE}/chat/execute", json={
|
||
"session_id": session["id"],
|
||
"message": "Wovon handelt das Buch?",
|
||
"context": {},
|
||
}).json()
|
||
print(answer["messages"][-1]["content"])
|
||
```
|
||
|
||
Genauso mit JavaScript (`fetch`), Go, oder jeder anderen Sprache — nichts Open-Notebook-
|
||
Spezifisches nötig, kein SDK erforderlich.
|
||
|
||
---
|
||
|
||
## 10. 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.
|