Eigener Compose-Stack im /flux Verzeichnis (kann auf separater Maschine laufen). aria-bridge routet flux_request via RVS, ARIA referenziert das fertige PNG im Reply mit [FILE: ...]-Marker. Brain-Tool flux_generate mit Caps fuer steps/dimension. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.4 KiB
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) mitenable_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— Defaultblack-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) odernone(alles auf GPU; nur fuer >=24 GB VRAM-Karten).FLUX_DTYPE—bfloat16(default) oderfloat16.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-cachesymlinken, 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 vonservice_statusUpdates 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:- UUID + Future
flux_requestbroadcastenasyncio.wait_for(future, timeout=...)- base64 →
/shared/uploads/aria_generated_<ts>.png - dict mit
{ok, path, sizeBytes, width, height, steps, guidance, seed, model, renderSeconds}
- HTTP-Endpoint
POST /internal/flux-generateim internen Listener (Port 8090). Validiert prompt + clamps, ruft_flux_generate, gibt Result als JSON zurueck.
5. aria-brain/agent.py — META-Tool flux_generate
{
"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}anhttp://aria-bridge:8090/internal/flux-generate(urllib, 1200 s Timeout — der erste Render kann den 24 GB Modell-Download triggern). - Bei
ok=truegibt 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_TOKENim.envsetzen oder im Containerhuggingface-cli loginmachen, 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) oderFLUX.1-pro(API only) wechseln. Stefan kann das ueberFLUX_MODELin der.envumstellen. - VRAM: 12 GB (3060) reichen NUR mit
enable_model_cpu_offload. Bei Out-of-Memory in den Logs aufFLUX_OFFLOAD=sequentialswitchen (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.