Add dual-GPU FLUX 9B image pipeline

This commit is contained in:
Mikei386
2026-09-07 15:42:45 +02:00
parent 61aa20cb52
commit 1844551534
19 changed files with 945 additions and 51 deletions
+12 -10
View File
@@ -20,13 +20,13 @@ Kommandos: POST /fast, /medium, /beta1, /large, /ultra,
/uncensored
GET /status (Zustand)
Bildgenerierung und Editing (FLUX.2-klein-4B):
Bildgenerierung und Editing (FLUX.2 Klein 9B FP8 beta):
POST /v1/images/generations (OpenAI-kompatibel)
POST /v1/images/edits (lokal, Referenzbilder)
GET /images (Liste)
GET /images/<datei> (PNG-Download)
Sprachausgabe (XTTS-v2, multilingual, CPU-only):
Sprachausgabe (Qwen3-TTS auf RTX 3060, Piper als CPU-Fallback):
POST /v1/audio/speech (OpenAI-kompatibel)
GET /v1/audio/voices (verfügbare Stimmen)
@@ -40,7 +40,8 @@ Der Router leitet /v1/audio/speech und /v1/audio/transcriptions
per HTTP an die Worker weiter.
Der Router agiert als Modell-Orchestrator: vor der Generierung wird
llama.cpp gestoppt, der Bild-Worker lädt FLUX.2, generiert/bearbeitet und entlädt
llama.cpp und Qwen3-TTS gestoppt, der Bild-Worker lädt FLUX.2 und den
Text-Encoder auf getrennte GPUs, generiert/bearbeitet und entlädt
das Modell wieder; danach wird das vorherige Qwen-Profil wiederher-
gestellt und erst dann geantwortet (try/finally – Qwen wird auch bei
Fehlgeschlagener Generierung wiederhergestellt).
@@ -126,7 +127,7 @@ DEFAULT_REASONING_EFFORT = os.environ.get(
GLOBAL_SYSTEM_POLICY_FILE = os.environ.get(
"GLOBAL_SYSTEM_POLICY_FILE", "").strip()
# --- Bildgenerierung und Referenzbild-Bearbeitung (FLUX.2 Klein 4B) ---
# --- Bildgenerierung und Referenzbild-Bearbeitung (FLUX.2 Klein 9B FP8) ---
LLAMA_SERVICE = os.environ.get("LLAMA_SERVICE", "mike-ai-llama-ui.service")
SYSTEMCTL_BIN = os.environ.get("SYSTEMCTL_BIN", "systemctl")
IMAGE_WORKER = os.environ.get(
@@ -135,7 +136,8 @@ IMAGE_PYTHON = os.environ.get(
"IMAGE_PYTHON", "/opt/mike-ai/ai-profile-router/venv/bin/python")
IMAGE_WORKER_URL = os.environ.get("IMAGE_WORKER_URL", "").rstrip("/")
IMAGE_WORKER_TOKEN = os.environ.get("IMAGE_WORKER_TOKEN", "").strip()
IMAGE_MODEL_NAME = os.environ.get("IMAGE_MODEL_NAME", "FLUX.2-klein-4B")
IMAGE_MODEL_NAME = os.environ.get(
"IMAGE_MODEL_NAME", "FLUX.2-klein-9B-fp8-beta")
IMAGE_DIR = os.environ.get(
"IMAGE_DIR", "/opt/mike-ai/ai-profile-router/images")
IMAGE_WORKER_LOG = os.environ.get(
@@ -163,7 +165,7 @@ IMAGE_SIZES = {
"1920x1088": (1920, 1088),
"1088x1920": (1088, 1920),
}
# Das destillierte FLUX.2-klein-4B ist auf vier Schritte ausgelegt.
# Das destillierte FLUX.2 Klein 9B ist auf vier Schritte ausgelegt.
IMAGE_QUALITY = {"standard": 4, "high": 4}
IMAGE_DEFAULT_QUALITY = "standard"
IMAGE_MAX_N = 4
@@ -765,7 +767,7 @@ def switch_profile(profile: str, implicit: bool = False) -> None:
# ---------------------------------------------------------------------------
# Bildgenerierung und Editing (FLUX.2-klein-4B)
# Bildgenerierung und Editing (FLUX.2 Klein 9B FP8)
# ---------------------------------------------------------------------------
class _Worker:
@@ -1874,7 +1876,7 @@ class Handler(BaseHTTPRequestHandler):
return
steps = data.get("steps", IMAGE_QUALITY[quality])
if not isinstance(steps, int) or isinstance(steps, bool) or steps != 4:
self._send_error(400, "FLUX.2-klein-4B erfordert 'steps'=4",
self._send_error(400, f"{IMAGE_MODEL_NAME} erfordert 'steps'=4",
"invalid_request_error", "invalid_steps")
return
guidance = data.get("guidance", 1.0)
@@ -1885,7 +1887,7 @@ class Handler(BaseHTTPRequestHandler):
"invalid_request_error", "invalid_guidance")
return
if guidance != 1.0:
self._send_error(400, "FLUX.2-klein-4B erfordert 'guidance'=1.0",
self._send_error(400, f"{IMAGE_MODEL_NAME} erfordert 'guidance'=1.0",
"invalid_request_error", "invalid_guidance")
return
@@ -1986,7 +1988,7 @@ class Handler(BaseHTTPRequestHandler):
self.end_headers()
self.wfile.write(data)
# ---------- Sprachausgabe (XTTS-v2) ----------
# ---------- Sprachausgabe (Qwen3-TTS mit Piper-Fallback) ----------
def _speech(self) -> None:
try: