194 lines
6.9 KiB
Markdown
194 lines
6.9 KiB
Markdown
# Research Agent – Web-Chat-Oberfläche
|
||
|
||
Browser-Chatoberfläche für den Research-Agent: DeepSeek v4 Flash recherchiert per Playwright im
|
||
Internet, verifiziert alle Links und generiert HTML-Dashboards – ohne dass Opencode lokal laufen muss.
|
||
|
||
## Funktionen
|
||
|
||
- 💬 Chat-Oberfläche mit Live-Fortschritt (SSE): Suchen, Seitenbesuche, Link-Verifizierung in Echtzeit
|
||
- 🔎 Volle Research-Funktion: DuckDuckGo-Suche, Seiten lesen, Links verifizieren, HTML-Dashboard generieren
|
||
- 🔔 Web-Push-Benachrichtigung, wenn die Recherche fertig ist (auch wenn der Browser zu ist)
|
||
- 📱 PWA: installierbar auf Desktop & Handy (Chrome/Android; iOS 16.4+ für Push)
|
||
- 👤 Eine gemeinsame Anmeldung (Name + Passwort), Sessions sind dem Namen zugeordnet
|
||
- 🔗 Sessions als read-only Teil-Link ohne Login teilbar
|
||
- 📦 SQLite-Speicherung, keine externe Datenbank nötig
|
||
|
||
## Setup
|
||
|
||
```bash
|
||
cd webapp
|
||
npm install
|
||
cp .env.example .env
|
||
# .env editieren: DEEPSEEK_API_KEY und APP_PASSWORD setzen (Pflicht)
|
||
npx playwright install chromium # falls Chromium fehlt
|
||
npm start # läuft auf Port 3000
|
||
```
|
||
|
||
Fehlende Werte wie `SESSION_SECRET` und die VAPID-Keys werden beim ersten Start automatisch
|
||
erzeugt und in die `.env` geschrieben.
|
||
|
||
## Konfiguration (.env)
|
||
|
||
| Variable | Pflicht | Beschreibung |
|
||
|---|---|---|
|
||
| `DEEPSEEK_API_KEY` | ja | Key von https://platform.deepseek.com/api_keys |
|
||
| `APP_PASSWORD` | ja | Gemeinsames Login-Passwort |
|
||
| `PORT` | nein | Standard 3000 |
|
||
| `MODEL` | nein | Standard `deepseek-v4-flash` |
|
||
| `THINKING` | nein | `enabled` (Standard) oder `disabled` |
|
||
| `DEEPSEEK_BASE_URL` | nein | Für Tests/Proxies überschreibbar |
|
||
|
||
## Deployment mit Docker/Podman (empfohlen)
|
||
|
||
Alles läuft in einem Container (Node + Playwright-Chromium). Auf dem Server reicht:
|
||
|
||
```bash
|
||
git clone <repo-url> researchChat
|
||
cd researchChat
|
||
cp .env.example .env
|
||
# .env editieren: DEEPSEEK_API_KEY und APP_PASSWORD setzen
|
||
```
|
||
|
||
**Mit Docker:**
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
|
||
**Mit Podman (Bazzite/Fedora Atomic):**
|
||
```bash
|
||
podman compose up -d
|
||
```
|
||
|
||
Beim ersten Start wird das Image gebaut (npm install + Chromium-Download, dauert ein paar Minuten).
|
||
Alternativ ist das fertige Image in der Gitea-Registry gepusht:
|
||
|
||
```bash
|
||
podman compose pull # fertiges Image aus der Registry holen
|
||
podman compose up -d
|
||
```
|
||
|
||
Danach läuft die App auf Port 3000. Daten bleiben über die Volumes erhalten:
|
||
|
||
| Host-Verzeichnis | Inhalt |
|
||
|---|---|
|
||
| `./data/` | SQLite-Datenbank (Sessions, Nachrichten, Push-Abos) |
|
||
| `./dashboards/` | Generierte HTML-Dashboards |
|
||
| `./.env` | Konfiguration (generierte Secrets werden ergänzt) |
|
||
|
||
Nützliche Befehle:
|
||
```bash
|
||
podman compose logs -f # Logs ansehen
|
||
podman compose restart # Neustart
|
||
podman compose pull # neues Image holen (nach Rebuild)
|
||
```
|
||
|
||
## Alternativ: Direkt mit Node (ohne Container)
|
||
|
||
```bash
|
||
npm install
|
||
npx playwright install --with-deps chromium # Chromium + Systemdeps
|
||
npm start
|
||
```
|
||
|
||
## Optional: NGINX davor (Reverse Proxy + IP-Prüfung + HTTPS)
|
||
|
||
### systemd-Unit (`/etc/systemd/system/research-web.service`, falls ohne Docker)
|
||
|
||
```ini
|
||
[Unit]
|
||
Description=Research Agent WebApp
|
||
After=network.target
|
||
|
||
[Service]
|
||
WorkingDirectory=/var/home/nico/dev/researchChat
|
||
ExecStart=/usr/bin/node server.js
|
||
Restart=always
|
||
RestartSec=3
|
||
Environment=NODE_ENV=production
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
```bash
|
||
sudo systemctl enable --now research-web
|
||
```
|
||
|
||
**Mit Docker/Podman** entfällt die systemd-Unit — `restart: unless-stopped` in der
|
||
docker-compose.yaml übernimmt das. Der NGINX-Block bleibt der gleiche:
|
||
|
||
### NGINX (Reverse Proxy + IP-Prüfung + HTTPS)
|
||
|
||
```nginx
|
||
server {
|
||
listen 443 ssl;
|
||
server_name research.deinedomain.de;
|
||
|
||
# SSL-Zertifikat (certbot --nginx)
|
||
ssl_certificate /etc/letsencrypt/live/research.deinedomain.de/fullchain.pem;
|
||
ssl_certificate_key /etc/letsencrypt/live/research.deinedomain.de/privkey.pem;
|
||
|
||
# IP-Prüfung: nur deine IPs kommen rein
|
||
allow 123.45.67.89; # deine Heim-IP
|
||
allow 10.0.0.0/8; # ggf. Heimnetz/VPN
|
||
# deny all; # Kommentar entfernen, wenn IP-Check aktiv sein soll
|
||
# (für /share/ entfernen, damit Teil-Links extern funktionieren)
|
||
|
||
location / {
|
||
proxy_pass http://localhost:3000;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_set_header Upgrade $http_upgrade; # SSE/EventSource
|
||
proxy_set_header Connection "upgrade";
|
||
proxy_buffering off; # wichtig für Live-Streaming
|
||
proxy_read_timeout 3600s;
|
||
proxy_send_timeout 3600s;
|
||
}
|
||
}
|
||
```
|
||
|
||
Tipp: Möchte man Teil-Links (`/share/...`) auch für Personen außerhalb der eigenen IP
|
||
freigeben, kann man die `allow/deny`-Regeln nur für `location /share/` weglassen
|
||
(und `location /` mit deny schützen) – die Teil-Ansicht ist read-only und benötigt keinen Login.
|
||
|
||
## Teilen
|
||
|
||
In jeder Session gibt es „🔗 Teilen-Link kopieren“. Der Link zeigt den Chat-Verlauf und das
|
||
Dashboard read-only, ganz ohne Login.
|
||
|
||
## Projektstruktur
|
||
|
||
```
|
||
researchChat/
|
||
├── Dockerfile # Node + Playwright-Chromium im Container
|
||
├── docker-compose.yaml # Ein-Befehl-Deployment (Docker & Podman)
|
||
├── server.js # Express-App: Auth, APIs, SSE, Web Push, statische Dateien
|
||
├── lib/
|
||
│ ├── config.js # .env-Laden, Secret/VAPID-Autogenerierung
|
||
│ ├── db.js # SQLite (node:sqlite, keine nativen Module)
|
||
│ ├── tools.js # Playwright-Tools: search, browse, verify, save_dashboard
|
||
│ ├── research.js # DeepSeek Tool-Calling-Loop (Agent)
|
||
│ └── queue.js # FIFO-Job-Queue (1 Recherche gleichzeitig)
|
||
├── public/ # Frontend (Vanilla JS + Tailwind CDN)
|
||
│ ├── index.html # Chat-UI
|
||
│ ├── login.html # Anmeldung
|
||
│ ├── share.html # Read-only Teil-Ansicht
|
||
│ ├── app.js
|
||
│ ├── sw.js # Service Worker (Push + Notifications)
|
||
│ └── manifest.json # PWA-Manifest
|
||
├── dashboards/ # generierte HTML-Dashboards (Host-Volume)
|
||
├── data/research.db # SQLite-Datenbank (Host-Volume)
|
||
└── scripts/make-icons.js
|
||
```
|
||
|
||
## Hinweise
|
||
|
||
- Recherchen dauern mehrere Minuten – die Fortschrittsleiste zeigt den aktuellen Schritt
|
||
- Nur **eine** Recherche läuft gleichzeitig; weitere Anfragen zeigen „Recherche läuft…“
|
||
- DuckDuckGo blockiert nach ~4-5 Suchen: Der Agent wechselt automatisch auf Fallback-Suchmaschinen
|
||
- Der Browser-Context bleibt pro Server-Lauf erhalten (weniger CAPTCHAs durch stabile Session-Cookies)
|
||
- API-Kosten: DeepSeek v4 Flash kostet ~$0,44/M Input- und ~$0,66/M Output-Token – eine Recherche kostet Cent-Beträge
|
||
- Auf SELinux-Systemen (Bazzite/Fedora Atomic) sind die Volume-Mounts mit `:Z` markiert – Docker ignoriert das Flag, dort reicht die Compose-Datei unverändert
|