7e53dcfed3
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>
181 lines
8.4 KiB
Markdown
181 lines
8.4 KiB
Markdown
# 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.
|