# FLUX.1-dev Bildgenerierung — Architektur & Stand

Ergaenzung des ARIA-Agent-Stacks um native Text-to-Image-Generierung via
FLUX.1-dev auf der Gamebox. Folgt dem **gleichen Pattern wie f5tts / whisper**:
ein eigener Container auf dem Gaming-PC, der sich selbst per WebSocket zum
RVS verbindet und auf seinen Request-Typ lauscht.

## Pipeline

```
Stefan / App
     │ Chat-Nachricht ("mal mir einen Sonnenuntergang ueberm Hangar")
     ▼
aria-bridge ── send_to_core ──▶  aria-brain
                                       │ chooses tool: flux_generate(prompt=..., width=..., ...)
                                       │ POST /internal/flux-generate
                                       ▼
                              aria-bridge (VM)
                                       │ pushes  {type: "flux_request",
                                       │           payload: {requestId, prompt, ...}}
                                       │ via RVS-Broadcast
                                       ▼
                                    RVS
                                       │ fanout
                                       ▼
                              flux-bridge (Gamebox)
                                       │ FluxPipeline.from_pretrained(...)
                                       │ pipeline(prompt, width, height, steps, guidance).images[0]
                                       │ PIL → PNG → base64
                                       │ {type: "flux_response", payload: {state:"done",
                                       │   requestId, base64, mimeType, ...}}
                                       ▼
                                    RVS
                                       │
                                       ▼
                              aria-bridge (VM)
                                       │ _pending_flux[requestId].set_result(payload)
                                       │ base64-decode → /shared/uploads/aria_generated_<ts>.png
                                       │ HTTP 200 zurueck an Brain mit {path, sizeBytes, ...}
                                       ▼
                              aria-brain
                                       │ Tool-Result + Hint: "schreib [FILE: {path}] in deine Antwort"
                                       │ Final-Reply: "Hier dein Bild:\n[FILE: /shared/uploads/aria_generated_<ts>.png]"
                                       ▼
                              aria-bridge
                                       │ _FILE_MARKER_RE → file_from_aria-Event
                                       │ Marker bleibt im Chat-Text fuer Hist; App rendert das Bild inline
                                       ▼
                                  App + Diagnostic
```

## Komponenten

### 1. `flux/bridge.py` (neu) — flux-bridge Container

- `FluxPipeline` (diffusers) mit `enable_model_cpu_offload()` als Default,
  damit FLUX.1-dev (~24 GB on disk, ~12 B params) auf einer RTX 3060
  (12 GB VRAM) ueberhaupt laeuft.
- Lazy-Load: Modell wird beim ersten `flux_request` (oder im Initial-Load)
  geladen, `service_status: "flux", state: "loading" | "ready" | "error"`
  wird via RVS broadcastet → Diagnostic-Badge zeigt's an.
- Single-Worker-Queue (`_flux_queue`) — GPU darf nicht parallel rendern,
  sonst OOM oder Crash.
- Progress-Ping: `flux_response {state: "rendering"}` direkt nach
  Queue-Pickup, damit die aria-bridge weiss "Auftrag angekommen", auch
  wenn der eigentliche Render 60s braucht.
- Caps:
  - `width`/`height`: 256 .. `FLUX_MAX_DIM` (Default 1536), gesnappt auf
    Vielfache von 64.
  - `steps`: 1 .. `FLUX_MAX_STEPS` (Default 50).
  - `guidance_scale`: 0.0 .. 20.0.
  - `prompt`: max 2000 chars.
- Env-Switches:
  - `FLUX_MODEL` — Default `black-forest-labs/FLUX.1-dev` (non-commercial).
    Alt: `FLUX.1-schnell` (Apache-2.0, 4 Steps, deutlich schneller).
  - `FLUX_OFFLOAD` — `model` (default), `sequential` (sparsamer, langsamer)
    oder `none` (alles auf GPU; nur fuer >=24 GB VRAM-Karten).
  - `FLUX_DTYPE` — `bfloat16` (default) oder `float16`.
  - `HF_TOKEN` — FLUX.1-dev braucht HuggingFace-Login.

### 2. `flux/docker-compose.yml` — eigener Stack

Bewusst NICHT mit in `xtts/docker-compose.yml` gepackt: FLUX kann auch
separat laufen (z.B. spaeter auf einer 4090, waehrend die 3060 weiter
TTS+STT bedient). Eigener Compose, eigene `.env.example`, eigenes
`hf-cache/`-Volume.

- GPU-Reservation analog zu f5tts/whisper.
- Volume `./hf-cache:/root/.cache/huggingface` — wenn flux auf der
  gleichen Maschine wie xtts laeuft kann man `../xtts/hf-cache`
  symlinken, dann ist der Modell-Cache geteilt.
- Restart `unless-stopped`.

### 3. `rvs/server.js` — Allowlist erweitert

Neue Typen: `flux_request`, `flux_response` (auch wenn das Initial-Load-
broadcast `service_status` bereits zugelassen war).

### 4. `bridge/aria_bridge.py`

- `self._pending_flux: dict[str, asyncio.Future]` — request_id → future.
- `self._remote_flux_ready: bool` — wird von `service_status` Updates
  gefuellt; steuert den HTTP-Timeout (240 s wenn ready, 900 s waehrend
  des allerersten Modell-Downloads).
- `flux_response`-Handler: Progress-Ping (`state == "rendering"`) bleibt
  no-op auf der Future; `state == "done"` setzt die Future, Error setzt
  `{"error": ...}`.
- `_flux_generate(prompt, width, height, steps, guidance, seed)` — Helper:
  1. UUID + Future
  2. `flux_request` broadcasten
  3. `asyncio.wait_for(future, timeout=...)`
  4. base64 → `/shared/uploads/aria_generated_<ts>.png`
  5. dict mit `{ok, path, sizeBytes, width, height, steps, guidance, seed, model, renderSeconds}`
- HTTP-Endpoint `POST /internal/flux-generate` im internen Listener
  (Port 8090). Validiert prompt + clamps, ruft `_flux_generate`, gibt
  Result als JSON zurueck.

### 5. `aria-brain/agent.py` — META-Tool `flux_generate`

```jsonc
{
  "name": "flux_generate",
  "parameters": {
    "prompt": "string (englischer Prompt — FLUX liefert auf EN besser)",
    "width":  "integer (256..1536, default 1024)",
    "height": "integer (256..1536, default 1024)",
    "steps":  "integer (1..50, default 28)",
    "guidance_scale": "number (default 3.5)",
    "seed":   "integer (optional)"
  }
}
```

Dispatcher:
- POSTet `{prompt, width, height, steps, guidance_scale, seed}` an
  `http://aria-bridge:8090/internal/flux-generate` (urllib, 1200 s Timeout
  — der erste Render kann den 24 GB Modell-Download triggern).
- Bei `ok=true` gibt das Tool den **Pfad** + Render-Stats zurueck und
  weist Claude explizit an: *"Schreibe `[FILE: <path>]` in deine
  Antwort an Stefan, dann zeigt die App das Bild inline."*
- Brain ueberlegt sich den Begleittext selber und packt den Marker an
  passende Stelle.

### 6. `diagnostic/index.html` — Status-Badge

Label `flux: 'FLUX Image-Gen'` zum bestehenden `updateServiceStatus()`-Switch
hinzugefuegt — kein neuer Code, gleicher Banner-Mechanismus wie F5-TTS /
Whisper.

## File-Lifecycle

Generierte Bilder leben unter `/shared/uploads/aria_generated_<ts>.png`
(gleicher Folder wie User-Uploads). Damit:
- `[FILE: ...]`-Marker funktioniert (Bridge erlaubt nur Pfade unter
  `/shared/uploads/`).
- File-Manager-Endpoints in Diagnostic (Liste/Loeschen/Zip) sehen sie
  ohne Sonderbehandlung.
- Memory-Anhaenge: ARIA kann ein generiertes Bild im selben Turn an
  einen Memory-Eintrag haengen (`memory_save(attach_paths=[path])`).

## Bekannte Stolpersteine

- **HF-Login**: FLUX.1-dev ist gated. Vor erstem Start `HF_TOKEN` im
  `.env` setzen oder im Container `huggingface-cli login` machen, sonst
  403 beim ersten Download.
- **Erster Render dauert lang**: 24 GB Modell laden + CUDA-Warmup → 5-10
  min realistisch. Brain-HTTP-Timeout ist 1200 s, RVS-Future-Timeout
  900 s (loading-Modus). Stefan sollte beim ersten "Mal mir was"-Request
  ein bisschen Geduld haben — danach sind Renders ~30-90 s.
- **Lizenz**: FLUX.1-dev ist *non-commercial* (FLUX.1 Dev Non-Commercial
  License). Fuer kommerzielle Nutzung muss man auf `FLUX.1-schnell`
  (Apache-2.0) oder `FLUX.1-pro` (API only) wechseln. Stefan kann das
  ueber `FLUX_MODEL` in der `.env` umstellen.
- **VRAM**: 12 GB (3060) reichen NUR mit `enable_model_cpu_offload`. Bei
  Out-of-Memory in den Logs auf `FLUX_OFFLOAD=sequential` switchen
  (deutlich langsamer, aber peak-VRAM ~6 GB).
- **Parallele Calls**: Single-Worker-Queue in der flux-bridge — ein
  zweiter `flux_generate`-Tool-Call von Brain wartet, bis der erste fertig
  ist. In der Praxis kein Problem, weil Stefan eh nicht zwei Bilder
  gleichzeitig macht.
