Files
nico b740ce1316 DeepSeek V4.1 Flash: native Bilderkennung, GLM/OpenRouter entfernt
- deepseek-flash als einziges Modell mit Vision, Preise aktualisiert
- OpenRouter/GLM samt Code, Config und Env-Variablen entfernt
- Legacy-Modell-IDs in Sessions werden automatisch migriert
- browse lädt Produktbilder lokal nach dashboards/ (Dedupe + Cleanup)
- Vision-Prompt: Workflow für visuelle Produktsuche, max. ~5 Screenshots
2026-10-05 12:55:31 +02:00

7.3 KiB
Raw Permalink Blame History

Research Agent – Web-Chat-Oberfläche

Browser-Chatoberfläche für den Research-Agent: DeepSeek V4.1 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
  • 📷 Bild-Upload & Vision: Fotos analysieren, ähnliche Produkte finden und mit lokal gespeicherten Bildern ins Dashboard einbetten
  • 🔔 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-flash
THINKING nein enabled (Standard) oder disabled
DEEPSEEK_BASE_URL nein Für Tests/Proxies überschreibbar
LOGIN_MAX_ATTEMPTS nein Fehlversuche pro IP vor Sperre (Standard 5)
LOGIN_LOCK_MINUTES nein Sperrdauer nach Fehlversuchen (Standard 5)

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). Alternativ ist das fertige Image in der Gitea-Registry gepusht:

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:

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.1 Flash kostet ~$0,30/M Input- (Cache-Miss) und ~$1,20/M Output-Token (Peak; Off-Peak halb so teuer) – 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