6.8 KiB
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
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:
git clone <repo-url> researchChat
cd researchChat
cp .env.example .env
# .env editieren: DEEPSEEK_API_KEY und APP_PASSWORD setzen
Mit Docker:
docker compose up -d
Mit Podman (Bazzite/Fedora Atomic):
podman compose up -d
Beim ersten Start wird das Image gebaut (npm install + Chromium-Download, dauert ein paar Minuten). 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:
podman compose logs -f # Logs ansehen
podman compose restart # Neustart
podman compose pull # neues Image holen (nach Rebuild)
Alternativ: Direkt mit Node (ohne Container)
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)
[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
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)
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
:Zmarkiert – Docker ignoriert das Flag, dort reicht die Compose-Datei unverändert