632 lines
30 KiB
Markdown
632 lines
30 KiB
Markdown
# Neural Hunt — V2.8 RIFT Task-Style Collection
|
||
|
||
|
||
|
||
> **V2.8 RIFT Task-Styles:** RIFT-Identität und Rendering-Stil sind jetzt sauber getrennt. `/data/artifacts/_collection/character_anchor.png` ist ein globaler, neutraler Identity-Lock für den Waschbären RIFT und kann im Admin-Tab **ARTIFACT** einmalig manuell erzeugt und geprüft werden. Jeder Task kann im Admin-Tab **TASK ACTIONS** ein eigenes JPEG-/PNG-Style-Referenzbild erhalten; Nutzer sehen dieses Stylebild bereits in der Task-Auswahl und wählen damit indirekt die gewünschte NFT-Art. Bei jeder RIFT-Karte sendet Neural Hunt **Image 1 = Character Anchor** und **Image 2 = Task Style Reference** an die Images Edit API. Ohne eigenen Task-Style bleibt `internal/artifact/assets/style_reference.jpg` nur noch der Default-Fallback. Folge-Tasks erben ihren Style. `medium` bleibt Standard und die OpenAI-Usage-/Kosten-KPIs aus V2.7 bleiben erhalten.
|
||
|
||
|
||
> **V2.5.2 Hotfix:** Der 3-Sekunden-Telemetrie-Poll hat in V2.5.1 den kompletten Control-Plane-DOM neu aufgebaut. Dadurch wurden native `<select>`-Dropdowns geschlossen und Cursor-/Scrollzustände in Eingabefeldern zerstört, obwohl die Werte über Drafts erhalten blieben. V2.5.2 trennt Telemetrie-Refresh und Formular-Rendering: Overview, Performance, Taskliste und Map aktualisieren sich weiterhin live, die Formular-Controls werden aber nur noch bei explizitem Tab-/Taskwechsel oder nach einer Admin-Aktion neu aufgebaut. Offene Dropdowns und laufende Eingaben bleiben damit stabil.
|
||
|
||
> **V2.5.1 Hotfix:** Ein WebSocket-Heartbeat-Fehler in V2.5 konnte Browser-Verbindungen sehr regelmäßig nach ungefähr 90 Sekunden beenden. Der Server hatte zwar eine Pong-Deadline gesetzt, aber nur ein JSON-`ping` statt eines echten WebSocket-Control-Pings gesendet. Danach fehlte die Presence-Lease und der nächste Tipp erhielt HTTP 409, bis F5 eine neue Verbindung öffnete. V2.5.1 sendet echte Ping-Frames, schützt Reconnects mit generationsgebundenen Presence-Leases und verbindet Browser/Shell automatisch neu. HTTP-409-Antworten besitzen zusätzlich maschinenlesbare Fehlercodes und werden clientseitig selbstständig resynchronisiert.
|
||
|
||
> **V2.5:** Nutzer wählen ihren Task auf einer eigenen Landing-Page und können jederzeit wechseln. Jeder Task besitzt eigene NFT-Prompt-Anweisungen, Anzeigename und Beschreibung; sein Folge-Task erbt diese Konfiguration. Admin-Formulare behalten ungespeicherte Eingaben auch bei Auto-Refresh und Browser-Reload. Zusätzlich gibt es mit `cmd/client` einen vollwertigen signierten Shell-Client für unbeaufsichtigten Betrieb.
|
||
>
|
||
> Die **V2.4-SCALE-Architektur** bleibt erhalten: Verlierende Tipps bleiben im RAM, Map-Updates werden gebatcht, WebSockets schreiben asynchron und Map-Snapshots sind serverseitig begrenzt. Bitte weiterhin in ein **neues/leeres Verzeichnis** entpacken.
|
||
|
||
|
||
Neural Hunt ist eine eigenständige Go-Webanwendung für das beschriebene soziale Wahrscheinlichkeitsexperiment. Sie benötigt für den Normalbetrieb **nur das Go-Binary und SQLite über `modernc.org/sqlite`**. Es gibt kein PostgreSQL, Redis, S3/MinIO und keinen separaten Frontend-Build.
|
||
|
||
Die Weboberfläche liegt unter `internal/webui/dist/` und wird mit `//go:embed` in das Binary eingebettet. Der Server lädt beim lokalen Start automatisch eine vorhandene `.env` (bereits gesetzte Prozess-Umgebungsvariablen haben Vorrang), daher reicht `go run ./cmd/server` für Backend, Client-UI, Admin-UI und öffentliches Echtzeit-Leaderboard.
|
||
|
||
## Schnellstart
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
# JWT_SECRET, ADMIN_PASSWORD und OPENAI_API_KEY setzen.
|
||
# ARTIFACT_MODEL nur ändern, wenn du bewusst ein anderes GPT-Image-Modell nutzen willst.
|
||
|
||
go run ./cmd/server
|
||
```
|
||
|
||
oder:
|
||
|
||
```bash
|
||
docker compose up --build
|
||
```
|
||
|
||
Danach:
|
||
|
||
- Client: `http://localhost:8080/`
|
||
- Echtzeit-Leaderboard: `http://localhost:8080/leaderboard`
|
||
- Admin: `http://localhost:8080/admin`
|
||
|
||
|
||
## V2.5: Task-Landing-Page und Task-Serien
|
||
|
||
Der Browser startet nach der Anmeldung nicht mehr stillschweigend in einem zufällig zugewiesenen Task. Stattdessen erscheint eine responsive **Task-Landing-Page** mit allen aktiven Tasks. Jede Karte zeigt Anzeigename, Beschreibung, Zahlenraum, Teilnehmerzahl, eigenen Score/Rank und Pause-Status. Ein Klick wählt den Task aus; über **TASKS** kann der Client die laufende Session sauber verlassen und später auf einen anderen aktiven Task wechseln.
|
||
|
||
Die Auswahl wird serverseitig in SQLite an die kryptografische Client-ID gebunden. Wird dieselbe Identität exportiert und auf einem anderen Gerät importiert, bleibt damit auch die zuletzt gewählte Task-Serie erhalten. Die Regel **eine Identity = eine aktive WebSocket-Verbindung** gilt weiterhin.
|
||
|
||
Wenn ein Task gewonnen oder administrativ geschlossen wird, erzeugt Neural Hunt genau einen Folge-Task. Dieser erbt vom Vorgänger:
|
||
|
||
- Zahlenraum (`range_bits`),
|
||
- task-spezifisches Server- und Client-Tippintervall,
|
||
- Anzeigename,
|
||
- Landing-Page-Beschreibung,
|
||
- NFT-Prompt-Anweisungen,
|
||
- task-spezifischen Negative Prompt,
|
||
- NFT-Style-Referenz.
|
||
|
||
`paused` wird absichtlich nicht vererbt: Ein neuer Folge-Task startet aktiv. Bestehende Client-Auswahlen des Vorgängers werden atomar auf den Folge-Task verschoben.
|
||
|
||
### Task-spezifische NFT-Prompts
|
||
|
||
Im Admin-Tab **TASK** besitzt jeder Task jetzt einen eigenen Bereich **TASK-KONFIGURATION & NFT-PROMPT**. Der globale Artifact-Prompt bleibt die stilistische Basis; die Task-Anweisungen werden anschließend angefügt. Damit kann beispielsweise eine Serie ihren eigenen visuellen Stil oder ihr eigenes Motiv erhalten, ohne die globale Provider-Konfiguration zu verändern.
|
||
|
||
Beispiel für einen Task:
|
||
|
||
```text
|
||
Anzeigename: Aurora Vault
|
||
Beschreibung: 48-Bit-Raum, Gewinner erhält die Aurora-Serie.
|
||
|
||
NFT-Prompt-Anweisungen:
|
||
Create a crystalline aurora data-vault, radial neural filaments,
|
||
no readable words, emphasize the winner as a singular luminous core.
|
||
|
||
Negative Prompt:
|
||
text, watermark, logo, duplicated core, low detail
|
||
```
|
||
|
||
Der Folge-Task übernimmt diese Werte automatisch. OpenAI verwendet die positiven Task-Anweisungen zusammen mit dem globalen Prompt; ComfyUI und A1111 erhalten zusätzlich den kombinierten globalen + task-spezifischen Negative Prompt.
|
||
|
||
### Admin-Entwürfe überleben Refresh
|
||
|
||
Die dynamischen Admin-Formulare speichern ungespeicherte Eingaben lokal als Draft. Das betrifft Runtime-/Artifact-Settings, Task-Konfiguration und die Felder für geplante Aktionen. Der 3-Sekunden-Auto-Refresh und ein normaler Browser-Reload überschreiben diese Eingaben nicht mehr. Nach erfolgreichem Speichern wird nur der zugehörige Draft-Bereich gelöscht.
|
||
|
||
## Shell-Client
|
||
|
||
`cmd/client` ist ein eigenständiger Neural-Hunt-Client ohne Browser. Er verwendet dieselbe P-256-Identität, dieselbe Challenge/Login-Signatur, denselben deterministischen Guess und denselben WebSocket-Presence-Mechanismus wie die Weboberfläche.
|
||
|
||
Interaktiv starten:
|
||
|
||
```bash
|
||
go run ./cmd/client -url http://127.0.0.1:8080
|
||
```
|
||
|
||
Beim ersten Start wird standardmäßig `~/.neuralhunt/identity.json` mit Dateirechten `0600` erzeugt. Danach zeigt die Shell eine Task-Auswahl ähnlich der Browser-Landing-Page.
|
||
|
||
Wichtige Befehle:
|
||
|
||
```text
|
||
tasks aktive Tasks + eigener Score/Rank
|
||
use <nr|id|name> Task wechseln
|
||
status aktueller Task, Score, Rank, Sequence, Wins
|
||
map [n] textuelles TARGET FIELD nach Nähe-Zonen
|
||
leaderboard [n] Echtzeit-Leaderboard abrufen
|
||
leaderboard watch Leaderboard alle 5 Sekunden anzeigen
|
||
leaderboard stop Watch beenden
|
||
nfts [n] Winner-Artefakte mit Wasserzeichen-URLs
|
||
nft get <task-id> <datei> öffentliche Wasserzeichen-Preview speichern
|
||
identity Client-ID + lokale Identity-Datei
|
||
identity export <datei> browser-kompatibler verschlüsselter Export
|
||
quit
|
||
```
|
||
|
||
Für `tmux`, `screen`, systemd oder einen Server ohne Vordergrund-Browser:
|
||
|
||
```bash
|
||
go run ./cmd/client \
|
||
-url https://hunt.example.org \
|
||
-non-interactive \
|
||
-task "Aurora Vault" \
|
||
-max-nodes 250
|
||
```
|
||
|
||
Im Non-Interactive-Modus bleibt der WebSocket offen, sendet automatisch im vom Task vorgegebenen Intervall signierte Tipps und folgt einem abgeschlossenen Task automatisch auf dessen Nachfolger. `SIGINT`/`SIGTERM` beendet sauber.
|
||
|
||
Für eine feste Binary:
|
||
|
||
```bash
|
||
go build -trimpath -o neuralhunt-client ./cmd/client
|
||
./neuralhunt-client -url https://hunt.example.org -non-interactive -task "Aurora Vault"
|
||
```
|
||
|
||
Ein minimales systemd-Beispiel:
|
||
|
||
```ini
|
||
[Unit]
|
||
Description=Neural Hunt Shell Client
|
||
After=network-online.target
|
||
|
||
[Service]
|
||
ExecStart=/opt/neuralhunt/neuralhunt-client -url https://hunt.example.org -non-interactive -task "Aurora Vault"
|
||
Environment=NEURALHUNT_IDENTITY=/var/lib/neuralhunt-client/identity.json
|
||
Restart=on-failure
|
||
RestartSec=5
|
||
User=neuralhunt
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
```
|
||
|
||
### Browser-Identität im Terminal verwenden
|
||
|
||
Die Browseroberfläche exportiert die Identität verschlüsselt mit PBKDF2-HMAC-SHA256 (250.000 Iterationen) + AES-256-GCM. Der Shell-Client versteht exakt dieses Format:
|
||
|
||
```bash
|
||
export NEURALHUNT_IDENTITY_PASSPHRASE='ein-langes-passwort'
|
||
go run ./cmd/client \
|
||
-import ./neuralhunt-identity-abc123.json \
|
||
-identity ~/.neuralhunt/identity.json
|
||
```
|
||
|
||
Um die Terminal-Identity wieder browser-kompatibel zu exportieren:
|
||
|
||
```bash
|
||
export NEURALHUNT_IDENTITY_PASSPHRASE='ein-langes-passwort'
|
||
go run ./cmd/client \
|
||
-identity ~/.neuralhunt/identity.json \
|
||
-export ./neuralhunt-browser-import.json
|
||
```
|
||
|
||
**Nicht dieselbe Identity gleichzeitig im Browser und im Shell-Client verbinden.** Das ist absichtlich durch die Single-Connection-Regel gesperrt. Unterschiedliche Identities dürfen natürlich vom selben Rechner bzw. derselben IP verbunden sein.
|
||
|
||
Unterstützte Shell-Parameter:
|
||
|
||
```text
|
||
-url Server-URL (oder NEURALHUNT_URL)
|
||
-identity persistente Raw-Identity (oder NEURALHUNT_IDENTITY)
|
||
-task Start-Task per Nummer, ID-Präfix oder Anzeigename
|
||
-max-nodes Größe des lokalen Target-Field-Working-Sets
|
||
-non-interactive unbeaufsichtigter Betrieb
|
||
-quiet weniger Konsolenausgabe
|
||
-import Browser-/Terminal-Identity importieren
|
||
-export verschlüsselten Browser-Export schreiben und beenden
|
||
-passphrase Import/Export-Passphrase; bevorzugt ENV verwenden
|
||
```
|
||
|
||
## Faire signierte Tipps
|
||
|
||
Der Browser darf den Tipp nicht frei wählen. Die Zahl ist deterministisch:
|
||
|
||
```text
|
||
SHA-256(task_id | public_seed | client_id | sequence) mod 2^range_bits
|
||
```
|
||
|
||
Danach signiert der Browser:
|
||
|
||
```text
|
||
guess|task_id|sequence|guess
|
||
```
|
||
|
||
mit seinem persistenten P-256-Schlüssel. Der Server berechnet den erwarteten Guess erneut und prüft die Signatur. Standardmäßig akzeptiert der Server höchstens einen Tipp alle 10 Sekunden; der Browser sendet alle 11 Sekunden.
|
||
|
||
Falsche Roh-Tipps und deren Signaturen werden **nicht gespeichert**. In V2.4 erzeugt ein akzeptierter Tipp, der den persönlichen Best-Score nicht verbessert, sogar **gar keinen SQLite-Write und gar kein WebSocket-Map-Event**. `next_seq`, Rate-Limit, Guess-Zähler und Bestwert liegen auf dem Hotpath im RAM. Erst eine Score-Verbesserung checkpointet den aggregierten Zustand in SQLite; beim Gewinner bleiben zusätzlich der korrekte Guess und dessen Signatur erhalten.
|
||
|
||
## TARGET FIELD — lesbare 3D-Nähe
|
||
|
||
Die vorherige Visualisierung hatte ein grundsätzliches Wahrnehmungsproblem: Eine echte 3D-Kugel um den Task kann in der 2D-Projektion einen weit entfernten Punkt scheinbar direkt neben dem Task zeigen, wenn er entlang der Kameratiefe liegt. Damit war „wer ist wirklich näher?“ trotz korrekter Daten nicht zuverlässig ablesbar.
|
||
|
||
V2.3 verwendet deshalb standardmäßig ein **3D-TARGET-FIELD mit unverzerrter Score-Ebene**. Der Score bestimmt ausschließlich den sichtbaren Orbitalradius; die Client-ID bestimmt nur den Winkel. Die dritte Dimension wird über Tiefensortierung, Perspektivgröße, Helligkeit und Vorder-/Rückseiten-Cues codiert, verschiebt den Node aber nicht radial. Dadurch kann Kameratiefe die Nähe nicht mehr optisch umkehren. Die Ringe und Nodes benutzen exakt dieselbe Radiusfunktion:
|
||
|
||
```text
|
||
kleinerer Ringradius = höherer Score = näher am Task
|
||
```
|
||
|
||
Die Wahrnehmungsfunktion ist bewusst im Bereich 90–100 gedehnt:
|
||
|
||
```text
|
||
field radius = 0.045 + 0.955 * (1 - score/100)^0.38
|
||
```
|
||
|
||
Damit sind z. B. 90, 95, 99 und 99.9 noch klar getrennt. Zusätzlich:
|
||
|
||
- Score-Ringe bei `0 / 25 / 50 / 75 / 90 / 95 / 99+`,
|
||
- Vorder-/Rückseite der Ringe mit unterschiedlicher Intensität als 3D-Tiefencue,
|
||
- Top-10 und eigene ID mit Score-Label,
|
||
- eigene ID mit weißem Doppelring,
|
||
- Kandidaten ab 95 mit zusätzlichem Nähe-Ring,
|
||
- Hover zeigt Score, Rank und eine verständliche Distanzzone,
|
||
- `TARGET RADAR` zeigt die besten Kandidaten zusätzlich numerisch,
|
||
- `TARGET FIELD` kann weiterhin auf `RAW 3D` umgeschaltet werden, um die serverseitigen Rohkoordinaten zu inspizieren.
|
||
|
||
### Keine erfundenen Synapsen mehr
|
||
|
||
Die alte Option `SYNAPSEN` verband Clients pseudozufällig miteinander. Dafür gibt es im Experiment keine fachliche Beziehung und die Linien erzeugten nur visuelles Rauschen. Diese Darstellung wurde entfernt.
|
||
|
||
`SIGNALWEGE` zeichnen jetzt nur noch **Client → Task**:
|
||
|
||
- nur Top-Kandidaten und der eigene Client erhalten einen Pfad,
|
||
- höhere Scores machen den Pfad deutlicher,
|
||
- unter 90 werden Pfade gestrichelt,
|
||
- wenn ein Client seinen Best-Score verbessert, laufen drei kurze Signalimpulse entlang genau dieses Pfades zum Task,
|
||
- es gibt keine zufälligen Ambient-Partikel und keine Client-zu-Client-Kanten mehr.
|
||
|
||
Der gleiche Renderer wird im Admin-Bereich verwendet.
|
||
|
||
## Mobile-Modus
|
||
|
||
Neural Hunt aktiviert auf kleinen Displays bzw. Geräten mit grobem Pointer automatisch einen Mobile-Modus. Er kann über den Button **MOBILE** auch manuell an- und ausgeschaltet werden; die Auswahl wird im Browser gespeichert.
|
||
|
||
Im Client reduziert Mobile Mode die Renderlast automatisch (ECO, weniger Nodes, keine optionalen Signalwege/Labels), zeigt Rank/Score/Countdown kompakt im Header und bietet eine einklappbare Detailkarte. Die 3D-Steuerung wird auf die wichtigsten Touch-Aktionen reduziert.
|
||
|
||
Im Admin-Bereich gibt es auf Mobile drei klare Ansichten **MAP / TASKS / CONTROL**, damit Task-Liste und Control Plane nicht mehr durch Responsive-CSS verschwinden. Das Leaderboard wechselt auf Karten statt horizontaler Tabellen.
|
||
|
||
## Öffentliches Echtzeit-Leaderboard
|
||
|
||
`/leaderboard` ist eine eigene, nicht authentifizierungspflichtige Ansicht. Sie bietet:
|
||
|
||
- Live-Ranking nach aktuellem Score,
|
||
- All-Time-Ranking nach Wins / Best Score,
|
||
- Online/Offline-Indikator,
|
||
- Best Score, Wins, Tippanzahl und Unlocks,
|
||
- Client-ID-Suche,
|
||
- WebSocket-getriggerte Aktualisierung bei neuen Punkten, Task-Änderungen und Task-Abschlüssen.
|
||
|
||
Zusätzlich zeigt das Leaderboard eine Gewinner-Galerie. Die öffentliche API liefert **keine Original-Artifact-URI**, sondern nur eine Wasserzeichen-Vorschau. Für PNG/JPEG/GIF wird das Wasserzeichen serverseitig in eine neue PNG-Vorschau gerastert; lokale SVG-Artefakte erhalten eine sichtbare, wiederholte SVG-Wasserzeichenebene.
|
||
|
||
Die Originaldatei und das Manifest sind nur noch über authentifizierte Admin-Endpunkte erreichbar. Der frühere öffentliche `/artifacts/*`-File-Server wurde entfernt.
|
||
|
||
API:
|
||
|
||
```text
|
||
GET /api/public/leaderboard?mode=live&limit=500
|
||
GET /api/public/leaderboard?mode=alltime&limit=500
|
||
GET /api/public/artifacts?limit=96
|
||
GET /api/public/artifacts/{task_id}/preview
|
||
WS /api/leaderboard/ws
|
||
|
||
# nur Admin-JWT
|
||
GET /api/admin/tasks/{task_id}/artifact
|
||
GET /api/admin/tasks/{task_id}/manifest
|
||
```
|
||
|
||
## Admin: planbare Task-Aktionen
|
||
|
||
Jeder Task besitzt jetzt einen persistierten Aktionsplan/Audit-Log. Aktionen können **sofort** oder für einen Zeitpunkt in der Zukunft geplant werden. Ein 1-Sekunden-Scheduler führt fällige Aktionen aus.
|
||
|
||
Unterstützt sind:
|
||
|
||
- `set_range_bits` — Zahlenraum eines laufenden Tasks ändern,
|
||
- `set_intervals` — Tippintervalle pro Task überschreiben,
|
||
- `clear_intervals` — wieder globale Defaults verwenden,
|
||
- `pause` — Tippabgaben pausieren,
|
||
- `resume` — fortsetzen,
|
||
- `reroll` — neues Secret + neuer Public Seed, Scores/Sequenzen zurücksetzen,
|
||
- `close` — Task beenden und Ersatz-Task sicherstellen,
|
||
- `regenerate_artifact` — Gewinnerbild erneut in die Queue legen.
|
||
|
||
Damit lassen sich z. B. Difficulty-Ramps planen:
|
||
|
||
```text
|
||
20:00 24 Bit
|
||
20:15 28 Bit
|
||
20:30 32 Bit
|
||
20:45 pause
|
||
20:50 resume
|
||
```
|
||
|
||
### Zahlenraum live ändern
|
||
|
||
Es gibt zwei Modi:
|
||
|
||
**preserve**
|
||
|
||
- das geheime Ziel und der Public Seed bleiben bestehen,
|
||
- Sequenzen bleiben bestehen,
|
||
- Scores werden auf den neuen Bit-Denominator re-skaliert,
|
||
- die räumlichen Positionen werden neu berechnet,
|
||
- Verkleinern ist nur möglich, wenn das bestehende Secret in den neuen Zahlenraum passt.
|
||
|
||
**reroll**
|
||
|
||
- neues Secret,
|
||
- neuer Public Seed,
|
||
- Score/Position/Sequenz werden zurückgesetzt,
|
||
- kumulative Tippanzahl bleibt erhalten.
|
||
|
||
Die Clients empfangen `task_changed` via WebSocket und laden `range_bits`, Seed, Revision und Intervalle neu. Ein Browser verwendet deshalb nach einer Live-Änderung nicht versehentlich die alte Bitzahl.
|
||
|
||
## KI-/NFT-artige Gewinnerbilder
|
||
|
||
Ein abgeschlossenes Gewinnerbild ist ein **NFT-artiges digitales Artefakt**, aber noch kein Blockchain-NFT. Neural Hunt mintet nichts on-chain. Es erzeugt Bild + Manifest mit eindeutiger ID und kryptografischen Bindungen.
|
||
|
||
Das Manifest enthält u. a.:
|
||
|
||
```text
|
||
artifact_id
|
||
artifact_preset
|
||
task_id
|
||
task_range_bits
|
||
winner_client_id
|
||
winner_public_jwk
|
||
winning_guess
|
||
winner_guess_signature
|
||
raw_art_sha256
|
||
image_sha256
|
||
prompt_sha256
|
||
collection_character
|
||
collection_traits
|
||
layout
|
||
provider
|
||
provider_meta
|
||
```
|
||
|
||
Wichtig: Die Gewinner-Signatur authentifiziert den erfolgreichen Guess. Sie ist keine nachträgliche Signatur der vom Bildprovider erzeugten Pixel. Das erzeugte Bild wird stattdessen per `image_sha256` an das Server-Manifest gebunden.
|
||
|
||
### Provider
|
||
|
||
Das Standard-Preset `raccoon_full_art_v1` ist im Admin-Tab **ARTIFACT** bewusst auf OpenAI + Character-Anchor-Workflow vorkonfiguriert; dort muss normalerweise nur das Bildmodell geändert werden. Die älteren Provider `local`, `comfyui`, `a1111` und `auto` bleiben für `artifact_preset=legacy` kompatibel.
|
||
|
||
Provider-Secrets und Provider-URLs bleiben absichtlich ENV-only und werden nicht an den Browser ausgeliefert. Das Dashboard zeigt für OpenAI nur, ob der API-Key vorhanden ist, und ob der kanonische Character Anchor bereits erzeugt wurde.
|
||
|
||
### 1. Local
|
||
|
||
Kein externer Dienst. Erzeugt ein deterministisches SVG wie bisher.
|
||
|
||
```env
|
||
ARTIFACT_PROVIDER=local
|
||
```
|
||
|
||
### 2. OpenAI Images API — RIFT Collection (Standard)
|
||
|
||
Für das neue Full-Art-Preset reichen im Normalfall genau zwei Werte:
|
||
|
||
```env
|
||
ARTIFACT_MODEL=gpt-image-2
|
||
OPENAI_API_KEY=...
|
||
```
|
||
|
||
`OPENAI_BASE_URL` kann optional überschrieben werden; standardmäßig wird `https://api.openai.com` verwendet. Provider, Portrait-Größe (`1024x1536`), Quality (`medium`) und das Collection-Preset sind bereits als Defaults hinterlegt. Eine mit älteren Projektversionen ausgelieferte lokale 1024×1024-Artifact-Konfiguration wird beim ersten Start einmalig auf das neue Preset migriert.
|
||
|
||
Die RIFT-Quality wird außerdem einmalig von einem früheren `high`-Default auf `medium` migriert. Eine später bewusst gesetzte `high`-Einstellung wird durch diese Migration nicht erneut überschrieben.
|
||
|
||
Ablauf:
|
||
|
||
1. Im Admin-Tab **ARTIFACT** kann `/data/artifacts/_collection/character_anchor.png` einmalig manuell erzeugt werden. Der Anchor entsteht nur aus dem neutralen RIFT-Masterprompt und enthält bewusst **keinen Task-Style**. Ist beim ersten Gewinner noch kein Anchor vorhanden, erzeugt der Worker ihn weiterhin automatisch als Sicherheits-Fallback.
|
||
2. Im Admin-Tab **TASK ACTIONS** kann jeder Task ein eigenes JPEG-/PNG-Stylebild erhalten. Es wird content-addressed unter `data/artifacts/_styles/<sha256>.<ext>` gespeichert und über `tasks.nft_style_reference` dem Task zugeordnet. Ein Folge-Task erbt dieselbe Style-Referenz. Ohne Custom-Style wird das eingebettete `internal/artifact/assets/style_reference.jpg` als Default verwendet.
|
||
3. Für jede RIFT-Karte sendet Neural Hunt zwei Bildinputs an `/v1/images/edits`: **Image 1 = globaler Character Anchor (Identität)** und **Image 2 = Task Style Reference (Rendering-Look)**. Der Prompt weist das Modell explizit an, Gesicht/Fell/Proportionen aus Image 1 und Rendering-Technik/Material/Licht/Farbverhalten aus Image 2 zu übernehmen. Der Kartenprompt erzwingt dabei bewusst keinen festen 3D-Look mehr: ein Task-Style darf z. B. 3D-Cartoon, Cel-Shading, Comic, malerisch, Watercolor-artig, Clay/Toy, Low-Poly oder Retro-Game sein, solange RIFT als Charakter erkennbar und die Ausgabe nicht fotorealistisch bleibt.
|
||
4. `internal/artifact/collection.go` wählt deterministisch Theme, Outfit, Accessoires, Szene, Mood, Pose, Atmosphäre, Rarity und Akzentfarben. Task-spezifische kreative Vorgaben und Ausschlüsse bleiben optionale Overrides.
|
||
5. Das generierte PNG wird als `art.png` gespeichert. `internal/artifact/card.go` baut daraus anschließend das finale `image.svg` im Format 1024×1536. Die KI muss daher keine Karten-Typografie oder UI exakt rendern.
|
||
6. Das Manifest bindet sowohl Roh-Art als auch fertige Karte per SHA-256 und speichert Collection-Traits sowie die verwendete Task-Style-Referenz/Provider-Metadaten.
|
||
|
||
Der Character Anchor ist absichtlich global und wird im Admin nach Erstellung als **LOCKED** behandelt. Ein Wechsel des NFT-Stils erfolgt deshalb nicht mehr durch Austausch des Anchors, sondern durch ein anderes Style-Referenzbild am jeweiligen Task. Das eingebettete `style_reference.jpg` muss dafür nicht neu kompiliert oder ausgetauscht werden.
|
||
|
||
### OpenAI-Nutzung und Kosten
|
||
|
||
Jeder erfolgreiche OpenAI-Bildaufruf (Character-Anchor und Gewinnerkarte) wird lokal in `artifact_api_usage` protokolliert. Wenn OpenAI im Images-Response die Usage-Felder liefert, speichert Neural Hunt die gemeldeten Text-/Bild-Input-Tokens sowie Output-/Total-Tokens und berechnet daraus eine lokale USD-Kostenschätzung. Die Preisbasis ist im Datensatz fixiert, damit historische Werte reproduzierbar bleiben; unbekannte Modelle werden weiter protokolliert, aber ohne erfundene Kostenschätzung.
|
||
|
||
Im Adminbereich zeigt **OPENAI NUTZUNG & KOSTEN** die Kosten des heutigen lokalen Kalendertags, den durchschnittlichen Preis pro fertiger Gewinnerkarte und die hochgerechneten Kosten pro 1.000 Karten sowie die letzten API-Aufrufe. Character-Anchor-Aufrufe zählen zu den heutigen API-Kosten, werden aber bewusst nicht in den Karten-Durchschnitt eingerechnet. Die USD-Werte sind eine aus den Provider-Tokens berechnete Standardpreis-Schätzung (ohne separat ausgewiesenen Cached-Input-Rabatt) und keine Rechnungs-/Billing-Abstimmung; dafür ist kein zusätzlicher OpenAI-Admin-Key nötig. Die Rohdaten sind zusätzlich über `GET /api/admin/artifact/usage` verfügbar.
|
||
|
||
### 3. ComfyUI
|
||
|
||
```env
|
||
ARTIFACT_PROVIDER=comfyui
|
||
COMFYUI_URL=http://127.0.0.1:8188
|
||
COMFYUI_WORKFLOW_PATH=/absolute/path/workflow-api.json
|
||
ARTIFACT_MODEL=your-checkpoint.safetensors
|
||
```
|
||
|
||
Der Workflow muss im **API-Format** vorliegen. Neural Hunt ersetzt rekursiv folgende String-Platzhalter:
|
||
|
||
```text
|
||
{{PROMPT}}
|
||
{{NEGATIVE_PROMPT}}
|
||
{{SEED}}
|
||
{{WIDTH}}
|
||
{{HEIGHT}}
|
||
{{STEPS}}
|
||
{{MODEL}}
|
||
```
|
||
|
||
Beispiel in einem KSampler-/Text-Encode-Input:
|
||
|
||
```json
|
||
{
|
||
"text": "{{PROMPT}}",
|
||
"seed": "{{SEED}}",
|
||
"steps": "{{STEPS}}"
|
||
}
|
||
```
|
||
|
||
Der Worker sendet den Workflow an `/prompt`, pollt `/history/{prompt_id}` und lädt das erste gefundene Ergebnis über `/view`.
|
||
|
||
### 4. AUTOMATIC1111
|
||
|
||
A1111 muss mit API gestartet werden, z. B. `--api`. Optional ist `--api-auth user:pass` möglich.
|
||
|
||
```env
|
||
ARTIFACT_PROVIDER=a1111
|
||
A1111_URL=http://127.0.0.1:7860
|
||
A1111_USER=
|
||
A1111_PASSWORD=
|
||
ARTIFACT_MODEL=my-checkpoint.safetensors
|
||
ARTIFACT_STEPS=28
|
||
A1111_CFG_SCALE=7
|
||
```
|
||
|
||
Neural Hunt verwendet `/sdapi/v1/txt2img`, übernimmt das Base64-Ergebnis und speichert es lokal. Ist `ARTIFACT_MODEL` kein `gpt-image-*`-Name, wird es für A1111 als `sd_model_checkpoint` pro Request gesetzt.
|
||
|
||
### 5. Auto
|
||
|
||
```env
|
||
ARTIFACT_PROVIDER=auto
|
||
```
|
||
|
||
Reihenfolge:
|
||
|
||
```text
|
||
OpenAI (wenn Key gesetzt)
|
||
→ ComfyUI (wenn URL + Workflow gesetzt)
|
||
→ A1111 (wenn URL gesetzt)
|
||
→ lokales SVG
|
||
```
|
||
|
||
Fehler der fehlgeschlagenen Provider werden im Manifest des lokalen Fallbacks vermerkt.
|
||
|
||
### Docker + lokale ComfyUI/A1111-Instanz
|
||
|
||
`docker-compose.yml` enthält `host.docker.internal:host-gateway`. Dadurch kann der App-Container unter Linux/Windows/macOS typischerweise einen Bildserver auf dem Docker-Host erreichen:
|
||
|
||
```env
|
||
COMFYUI_URL=http://host.docker.internal:8188
|
||
A1111_URL=http://host.docker.internal:7860
|
||
```
|
||
|
||
Ein ComfyUI-Workflow, den der Container lesen soll, muss zusätzlich in den Container gemountet bzw. unter `/data` abgelegt werden.
|
||
|
||
## Architektur
|
||
|
||
```text
|
||
Browser
|
||
├─ Client UI + P-256 Identity
|
||
├─ /leaderboard
|
||
└─ Admin Control Plane
|
||
│ HTTP / WS
|
||
▼
|
||
+------------------------------------------+
|
||
| Go Binary |
|
||
| auth | tasks | scheduler | WS | artifact |
|
||
+--------------------+---------------------+
|
||
│
|
||
modernc.org/sqlite
|
||
/data/neuralhunt.db
|
||
│
|
||
└─ /data/artifacts/
|
||
└─ artifact_<id>/
|
||
├─ image.png|svg
|
||
└─ manifest.json
|
||
|
||
Optional nur für Bildgenerierung:
|
||
OpenAI API ODER ComfyUI ODER A1111
|
||
```
|
||
|
||
## V2.4 Scale-Architektur
|
||
|
||
Die Standalone-Edition bleibt bewusst **ein Go-Prozess auf einem Host**. Dafür ist der heiße Pfad jetzt konsequent aus SQLite herausgezogen:
|
||
|
||
```text
|
||
normaler falscher Guess
|
||
-> JWT / Signatur / deterministischen Guess prüfen
|
||
-> Sequence + Rate Limit + GuessCount im RAM
|
||
-> Score berechnen
|
||
-> schlechter als Bestwert
|
||
-> Antwort false
|
||
|
||
SQLite writes: 0
|
||
Map events: 0
|
||
```
|
||
|
||
Nur Registrierung, erstmaliger Task-Punkt, Score-Verbesserungen, Gewinner, Unlocks, Admin-/Task-Änderungen und Artefakte werden dauerhaft geschrieben. Presence (`eine ID = eine aktive Verbindung`) liegt ebenfalls im Prozess und verursacht keine regelmäßigen SQLite-Lease-Writes mehr. Die alte Tabelle `presence_leases` kann aus Kompatibilitätsgründen in bestehenden Datenbanken vorhanden bleiben, wird aber vom V2.4-Hotpath nicht genutzt.
|
||
|
||
### Gebatchte WebSockets
|
||
|
||
Verbesserungen werden pro Task und Client koalesziert und alle **250 ms** als ein `points`-Frame gesendet. Jeder Socket hat eine bounded Outbound-Queue; ein langsamer Browser blockiert daher niemals einen Guess-Request. Ist seine Queue voll, darf ein transienter Map-Frame verworfen werden. Der persistierte Zustand bleibt maßgeblich.
|
||
|
||
### Server-seitig begrenzte Map-Snapshots
|
||
|
||
Der Browser lädt nicht mehr pauschal 50.000 Nodes. `max_nodes` wird an den WebSocket übergeben; der Server liefert höchstens `3 × max_nodes` Overscan (hart gedeckelt auf 10.000) und garantiert, dass die eigene Node enthalten ist. Nachfolgende Events werden clientseitig ebenfalls auf dieses Overscan-Budget gekürzt. Das vorhandene LOD arbeitet nur noch auf diesem begrenzten Working Set.
|
||
|
||
### Performance-Telemetrie
|
||
|
||
`GET /api/admin/performance` liefert live u. a. `Guess/s`, `Improvements/s`, `SQLite Writes/s`, verworfene Requests, WebSocket Frames/s, WebSocket Bytes/s, Queue-Drops, Goroutines und Heap. Diese Werte erscheinen zusätzlich im Admin-Dashboard.
|
||
|
||
### Lastgenerator
|
||
|
||
Der integrierte Lastgenerator erzeugt echte P-256-Identitäten, führt Challenge/Login aus, öffnet WebSockets und sendet deterministische signierte Tipps:
|
||
|
||
```bash
|
||
go run ./cmd/loadtest \
|
||
-url http://127.0.0.1:8080 \
|
||
-clients 10000 \
|
||
-ramp 60s \
|
||
-duration 5m \
|
||
-max-nodes 250
|
||
```
|
||
|
||
Für einen realen 10k-Test sollten Server und Lastgenerator nach Möglichkeit auf getrennten Hosts laufen. Die erreichbare Obergrenze hängt von CPU, RAM, TLS, Dateideskriptoren und Netzwerk ab; V2.4 setzt **10.000 gleichzeitige Clients als Lasttest-Ziel**, nicht als hardwareunabhängige Garantie.
|
||
|
||
## SQLite und Skalierungsgrenze
|
||
|
||
SQLite läuft mit Foreign Keys, WAL, `busy_timeout` und kurzen Transaktionen. Weil normale falsche Tipps SQLite nicht mehr berühren, ist die Single-Writer-Eigenschaft deutlich weniger dominant. Für echtes Multi-Host-Horizontal-Scaling wäre trotzdem wieder eine gemeinsame Koordinations-/Datenbankschicht nötig.
|
||
|
||
## Mehrere lokale Test-Clients
|
||
|
||
Die IP-Adresse ist nicht Teil der Identität. Mehrere Clients auf `127.0.0.1` funktionieren. Sie brauchen lediglich unterschiedliche Browser-Identitäten, z. B. normales Fenster + Inkognito oder getrennte Browserprofile.
|
||
|
||
Zwei Tabs desselben Profils teilen `localStorage` und damit dieselbe ID. Pro ID ist weiterhin nur eine aktive Client-WebSocket-Verbindung erlaubt.
|
||
|
||
## Persistenz / Backup
|
||
|
||
Relevant sind:
|
||
|
||
```text
|
||
/data/neuralhunt.db
|
||
/data/artifacts/
|
||
```
|
||
|
||
In SQLite liegen u. a.:
|
||
|
||
```text
|
||
clients
|
||
tasks
|
||
task_points
|
||
settings
|
||
presence_leases
|
||
task_actions
|
||
```
|
||
|
||
## API-Überblick
|
||
|
||
User:
|
||
|
||
```text
|
||
POST /api/auth/challenge
|
||
POST /api/auth/login
|
||
GET /api/tasks/current
|
||
POST /api/tasks/{id}/guess
|
||
GET /api/tasks/{id}/points
|
||
GET /api/me
|
||
GET /api/leaderboard
|
||
GET /api/ws
|
||
```
|
||
|
||
Public:
|
||
|
||
```text
|
||
GET /api/public/leaderboard
|
||
WS /api/leaderboard/ws
|
||
```
|
||
|
||
Admin:
|
||
|
||
```text
|
||
POST /api/admin/login
|
||
GET /api/admin/overview
|
||
GET /api/admin/performance
|
||
GET /api/admin/settings
|
||
PUT /api/admin/settings
|
||
GET /api/admin/tasks
|
||
GET /api/admin/tasks/{id}/points
|
||
GET /api/admin/tasks/{id}/actions
|
||
POST /api/admin/tasks/{id}/actions
|
||
POST /api/admin/actions/{id}/cancel
|
||
GET /api/admin/artifact/providers
|
||
POST /api/admin/tasks/{id}/close
|
||
POST /api/admin/tasks/ensure
|
||
```
|
||
|
||
## Produktions-Hinweise
|
||
|
||
- TLS erzwingen.
|
||
- `JWT_SECRET` und Admin-Passwort ändern.
|
||
- `CheckOrigin` für WebSockets auf eine Origin-Allowlist begrenzen.
|
||
- `/data` sichern und freien Speicher überwachen.
|
||
- API-Keys nur als ENV/Secret injizieren, niemals in Runtime-Settings speichern.
|
||
- Bei ComfyUI/A1111 nur vertrauenswürdige lokale/netzinterne Instanzen konfigurieren.
|
||
- Datenschutz-/Einwilligungstexte für das soziale Experiment ergänzen.
|
||
|
||
## V2.9: lokaler RIFT-Pipeline-Test
|
||
|
||
Im Adminbereich unter **TASK ACTIONS** kann für den ausgewählten Task eine komplette lokale Testkarte erzeugt werden. Der Test verwendet den vorhandenen `character_anchor.png` als Mock-Character-Artwork und die Style-Referenz des Tasks als Hintergrund, führt die deterministische Trait-Auswahl, das programmatische Kartenlayout und das Schreiben der Testdateien aus, ruft aber **keine externe Bild-API** auf. Die Dateien landen unter `data/artifacts/_test/<task-id>/`; der echte Task- und Artifact-Status bleibt unverändert.
|