feat(flux): Modell-Wahl per Diagnostic + raw/switch-Keywords + Download-Hinweis

Diagnostic-Einstellungen fuer FLUX:
- Default-Modell (dev | schnell) — wird via RVS gepusht, flux-bridge
  hot-swappt die Pipeline aus dem HF-Cache (~15-30s)
- Raw-Keyword (Default 'flux') — Pipe-Modus, Brain leitet Stefans Text
  1:1 als prompt durch, kein Rewriting/Beautify
- Switch-Keyword (Default 'fix') — zwingt das ANDERE Modell als Default

Brain-Tool flux_generate um model + raw erweitert, System-Prompt-Block
mit den aktuellen Diagnostic-Settings + Whisper-Toleranz-Hinweis.

Kein eager Bootstrap-Load: flux-bridge wartet auf config oder ersten
Request. Bei erstem HF-Download zeigt Banner "laedt erstmalig runter"
mit Pfeil-Icon, Toast in der App wenn fertig.

FLUX_MODEL aus der .env entfernt (Steuerung jetzt komplett ueber
Diagnostic). HF_TOKEN-Kommentar erklaert warum trotz lokaler Inference
noetig (HF Gate-Mechanismus fuer FLUX.1-dev).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-16 23:11:22 +02:00
parent 7e53dcfed3
commit 2d348aeec7
8 changed files with 440 additions and 72 deletions
+29 -6
View File
@@ -487,6 +487,7 @@ class ARIABridge:
self.tts_enabled = True
self.xtts_voice = ""
self._f5tts_config: dict = {}
self._flux_config: dict = {}
vc: dict = {}
# Gespeicherte Voice-Config laden
try:
@@ -503,9 +504,14 @@ class ARIABridge:
"f5ttsCfgStrength", "f5ttsNfeStep"):
if k in vc:
self._f5tts_config[k] = vc[k]
logger.info("Voice-Config geladen: tts=%s voice=%s f5tts=%s",
# FLUX-Felder (Default-Modell + Keywords) gleicher Mechanismus
for k in ("fluxDefaultModel", "fluxKeywordRaw", "fluxKeywordSwitch"):
if k in vc:
self._flux_config[k] = vc[k]
logger.info("Voice-Config geladen: tts=%s voice=%s f5tts=%s flux=%s",
self.tts_enabled, self.xtts_voice or "default",
self._f5tts_config or "defaults")
self._f5tts_config or "defaults",
self._flux_config or "defaults")
except Exception as e:
logger.warning("Voice-Config laden fehlgeschlagen: %s", e)
# Whisper-Modell: Config hat Vorrang, dann env/Default (medium)
@@ -1238,6 +1244,7 @@ class ARIABridge:
"whisperModel": self.stt_engine.model_size,
}
payload.update(getattr(self, "_f5tts_config", {}) or {})
payload.update(getattr(self, "_flux_config", {}) or {})
await self._send_to_rvs({
"type": "config",
"payload": payload,
@@ -1776,6 +1783,15 @@ class ARIABridge:
self._f5tts_config = {}
self._f5tts_config[k] = payload[k]
changed = True
# FLUX-Felder: gleiche Logik wie F5-TTS. flux-bridge applied
# fluxDefaultModel selbst (Pipeline-Swap). Keywords nutzt Brain
# via /shared/config/voice_config.json.
for k in ("fluxDefaultModel", "fluxKeywordRaw", "fluxKeywordSwitch"):
if k in payload:
if not hasattr(self, "_flux_config"):
self._flux_config = {}
self._flux_config[k] = payload[k]
changed = True
# Persistent speichern in Shared Volume
if changed:
try:
@@ -1786,6 +1802,7 @@ class ARIABridge:
"whisperModel": self.stt_engine.model_size,
}
config_data.update(getattr(self, "_f5tts_config", {}))
config_data.update(getattr(self, "_flux_config", {}))
with open("/shared/config/voice_config.json", "w") as f:
json.dump(config_data, f, indent=2)
logger.info("[rvs] Voice-Config gespeichert: %s", config_data)
@@ -2553,7 +2570,7 @@ class ARIABridge:
async def _flux_generate(self, prompt: str, width: int, height: int,
steps: Optional[int], guidance: Optional[float],
seed: Optional[int]) -> dict:
seed: Optional[int], model: Optional[str] = None) -> dict:
"""Schickt einen flux_request an die flux-bridge, wartet auf das fertige
PNG, speichert es nach /shared/uploads/aria_generated_<ts>.png.
@@ -2578,9 +2595,13 @@ class ARIABridge:
req_payload["guidance_scale"] = guidance
if seed is not None:
req_payload["seed"] = seed
if model:
# 'dev' | 'schnell' — flux-bridge mappt das auf HF-IDs.
# Ohne Angabe nimmt die flux-bridge ihren konfigurierten Default.
req_payload["model"] = model
logger.info("[rvs] flux_request → flux-bridge (id=%s, %dx%d, steps=%s, prompt=%r)",
request_id[:8], width, height, steps, prompt[:60])
logger.info("[rvs] flux_request → flux-bridge (id=%s, %dx%d, steps=%s, model=%s, prompt=%r)",
request_id[:8], width, height, steps, model or "default", prompt[:60])
ok = await self._send_to_rvs({
"type": "flux_request",
"payload": req_payload,
@@ -2897,10 +2918,12 @@ class ARIABridge:
steps = int(steps_raw) if isinstance(steps_raw, (int, float)) else None
guidance = float(guidance_raw) if isinstance(guidance_raw, (int, float)) else None
seed = int(seed_raw) if isinstance(seed_raw, (int, float)) else None
model_raw = data.get("model")
model = model_raw.strip() if isinstance(model_raw, str) and model_raw.strip() in ("dev", "schnell") else None
result = await self._flux_generate(
prompt=prompt, width=width, height=height,
steps=steps, guidance=guidance, seed=seed,
steps=steps, guidance=guidance, seed=seed, model=model,
)
status = 200 if result.get("ok") else 502
await _send_response(writer, status, result)