# 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_.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_.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_.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: ]` 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_.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.