Remove ineffective photo restoration pipeline

This commit is contained in:
Mikei386
2026-09-08 09:40:43 +02:00
parent f82dc081c9
commit e82e0340e4
9 changed files with 17 additions and 552 deletions
+12 -120
View File
@@ -138,16 +138,6 @@ 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-9B-fp8-beta")
RESTORATION_WORKER_URL = os.environ.get(
"RESTORATION_WORKER_URL", "").rstrip("/")
RESTORATION_WORKER_TOKEN = os.environ.get(
"RESTORATION_WORKER_TOKEN", IMAGE_WORKER_TOKEN).strip()
RESTORATION_MODEL_NAME = os.environ.get(
"RESTORATION_MODEL_NAME", "HYPIR-SD2")
RESTORATION_CHAT_MODEL = os.environ.get(
"RESTORATION_CHAT_MODEL", "restauration").strip()
RESTORATION_CHAT_PROFILE = os.environ.get(
"RESTORATION_CHAT_PROFILE", "fast").strip()
IMAGE_DIR = os.environ.get(
"IMAGE_DIR", "/opt/mike-ai/ai-profile-router/images")
IMAGE_WORKER_LOG = os.environ.get(
@@ -225,12 +215,6 @@ VIRTUAL_MODELS = {
(EXPECTED_MODELS.get(name) or f"qwen-{name}"): name
for name in PROFILES
}
if RESTORATION_CHAT_PROFILE not in PROFILES:
raise ConfigurationError(
f"RESTORATION_CHAT_PROFILE ist unbekannt: {RESTORATION_CHAT_PROFILE!r}")
if not RESTORATION_CHAT_MODEL or RESTORATION_CHAT_MODEL in VIRTUAL_MODELS:
raise ConfigurationError("RESTORATION_CHAT_MODEL fehlt oder kollidiert")
VIRTUAL_MODELS[RESTORATION_CHAT_MODEL] = RESTORATION_CHAT_PROFILE
log = logging.getLogger("ai-profile-router")
AUTH: AuthPolicy | None = None
@@ -874,23 +858,16 @@ class _Worker:
RUNTIME.clear_worker("image")
def _worker(model: str = IMAGE_MODEL_NAME) -> _Worker:
def _worker() -> _Worker:
"""Worker-Instanz liefern (startet bei Bedarf)."""
img = STATE.image
if not img.worker or not img.worker.alive():
if img.worker:
img.worker.stop()
if model == RESTORATION_MODEL_NAME:
if not RESTORATION_WORKER_URL:
raise RuntimeError("Restaurations-Worker ist nicht konfiguriert")
img.worker = _RemoteWorker(
kind="restore", url=RESTORATION_WORKER_URL,
token=RESTORATION_WORKER_TOKEN, endpoint="/restore")
else:
img.worker = (_RemoteWorker(kind="image", url=IMAGE_WORKER_URL,
token=IMAGE_WORKER_TOKEN,
endpoint="/generate")
if IMAGE_WORKER_URL else _Worker())
img.worker = (_RemoteWorker(kind="image", url=IMAGE_WORKER_URL,
token=IMAGE_WORKER_TOKEN,
endpoint="/generate")
if IMAGE_WORKER_URL else _Worker())
img.worker.start()
return img.worker
@@ -1046,7 +1023,6 @@ def generate_image(prompt: str, width: int, height: int, steps: int,
quality: str = "standard",
source_files: list[str] | None = None,
model: str = IMAGE_MODEL_NAME,
restore_options: dict | None = None,
) -> tuple[list[str], str | None]:
"""Orchestriert die Bildgenerierung inkl. Qwen-Hotswap.
@@ -1091,7 +1067,7 @@ def generate_image(prompt: str, width: int, height: int, steps: int,
# 2) Worker starten (Modell wird beim ersten generate geladen).
img.phase = "loading-image"
worker = _worker(model)
worker = _worker()
# 3) Generieren.
for i in range(n):
@@ -1110,7 +1086,6 @@ def generate_image(prompt: str, width: int, height: int, steps: int,
"output": output,
"source_files": source_files or [],
}
worker_payload.update(restore_options or {})
resp = worker.request(worker_payload, timeout=IMAGE_GEN_TIMEOUT)
if resp.get("status") != "ok":
raise RuntimeError(
@@ -1129,8 +1104,7 @@ def generate_image(prompt: str, width: int, height: int, steps: int,
"steps": steps,
"guidance": guidance,
"quality": quality,
"mode": ("image-restoration" if model == RESTORATION_MODEL_NAME
else "image-edit" if source_files else "text-to-image"),
"mode": ("image-edit" if source_files else "text-to-image"),
"reference_images": len(source_files or []),
"seconds": resp.get("seconds"),
"model": model,
@@ -1383,39 +1357,6 @@ def _inject_global_system_policy(data: dict, path: str) -> dict:
return data
def _inject_restoration_system_policy(data: dict, path: str) -> dict:
"""Make the explicitly selected restoration model use the image tool."""
policy = (
"Photo-restoration mode is selected. When the user supplies an image, "
"use the image generation/editing tool exactly once with that source "
"image and the user's requested restoration. Preserve identity, "
"anatomy, pose, composition and objects unless the user explicitly "
"asks for a creative change. Do not attempt restoration with Python, "
"PIL, OpenCV or shell tools."
)
if path == "/v1/chat/completions":
messages = data.get("messages")
if isinstance(messages, list):
# Qwen's chat template permits exactly one system message and it
# must be the first message. The global router policy may already
# have created that message, so extend it instead of inserting a
# second system message in front of it.
if (messages and isinstance(messages[0], dict)
and messages[0].get("role") == "system"
and isinstance(messages[0].get("content"), str)):
existing = messages[0]["content"]
if policy not in existing:
messages[0]["content"] = f"{policy}\n\n{existing}"
else:
messages.insert(0, {"role": "system", "content": policy})
elif path == "/v1/responses":
instructions = data.get("instructions")
data["instructions"] = (
f"{policy}\n\n{instructions}"
if isinstance(instructions, str) and instructions else policy)
return data
def _normalize_llamacpp_reasoning(data: dict) -> dict:
"""Mappt OpenAI/Hermes-Reasoning auf llama.cpp-Template-Parameter.
@@ -1768,15 +1709,6 @@ class Handler(BaseHTTPRequestHandler):
}
for name, ctx in PROFILES.items()
]
models.append({
"id": RESTORATION_CHAT_MODEL,
"object": "model",
"created": 0,
"owned_by": "ai-profile-router",
"context_length": PROFILES[RESTORATION_CHAT_PROFILE],
"context_window": PROFILES[RESTORATION_CHAT_PROFILE],
"purpose": "image-restoration",
})
if REVIEW_UPSTREAM_URL:
models.append({
"id": REVIEW_MODEL_NAME,
@@ -1932,17 +1864,11 @@ class Handler(BaseHTTPRequestHandler):
return
model = data.get("model", IMAGE_MODEL_NAME)
if model not in {IMAGE_MODEL_NAME, RESTORATION_MODEL_NAME}:
if model != IMAGE_MODEL_NAME:
self._send_error(
400, f"unbekanntes Bildmodell: {model!r}",
"invalid_request_error", "invalid_model")
return
restoring = model == RESTORATION_MODEL_NAME
if restoring and len(source_files) != 1:
self._send_error(
400, f"{RESTORATION_MODEL_NAME} benötigt genau ein Referenzbild",
"invalid_request_error", "missing_image")
return
# Größe
size = data.get("size", "1024x1024")
@@ -1960,11 +1886,6 @@ class Handler(BaseHTTPRequestHandler):
self._send_error(400, f"'n' muss eine Ganzzahl 1..{IMAGE_MAX_N} sein",
"invalid_request_error", "invalid_n")
return
if restoring and n != 1:
self._send_error(400, "Bildrestaurierung unterstützt nur 'n'=1",
"invalid_request_error", "invalid_n")
return
# Qualität / Schritte / Guidance
quality = data.get("quality", IMAGE_DEFAULT_QUALITY)
if quality not in IMAGE_QUALITY:
@@ -1973,9 +1894,8 @@ class Handler(BaseHTTPRequestHandler):
"invalid_request_error", "invalid_quality")
return
steps = data.get("steps", IMAGE_QUALITY[quality])
if (not restoring and
(not isinstance(steps, int) or isinstance(steps, bool)
or steps != 4)):
if (not isinstance(steps, int) or isinstance(steps, bool)
or steps != 4):
self._send_error(400, f"{IMAGE_MODEL_NAME} erfordert 'steps'=4",
"invalid_request_error", "invalid_steps")
return
@@ -1986,35 +1906,11 @@ class Handler(BaseHTTPRequestHandler):
self._send_error(400, "'guidance' muss eine Zahl sein",
"invalid_request_error", "invalid_guidance")
return
if not restoring and guidance != 1.0:
if guidance != 1.0:
self._send_error(400, f"{IMAGE_MODEL_NAME} erfordert 'guidance'=1.0",
"invalid_request_error", "invalid_guidance")
return
restore_options: dict = {}
if restoring:
try:
upscale = int(data.get("upscale", 1))
patch_size = int(data.get("patch_size", 512))
stride = int(data.get("stride", 256))
except (TypeError, ValueError):
self._send_error(400, "ungültige Restaurationsparameter",
"invalid_request_error", "invalid_restore_options")
return
if upscale not in (1, 2, 4):
self._send_error(400, "'upscale' muss 1, 2 oder 4 sein",
"invalid_request_error", "invalid_upscale")
return
if patch_size not in (512, 768, 1024) or not 0 < stride <= patch_size:
self._send_error(400, "ungültige patch_size/stride-Kombination",
"invalid_request_error", "invalid_tiling")
return
restore_options = {
"upscale": upscale,
"patch_size": patch_size,
"stride": stride,
}
seed = data.get("seed")
if seed is not None:
try:
@@ -2039,7 +1935,7 @@ class Handler(BaseHTTPRequestHandler):
try:
results, warning = generate_image(
prompt.strip(), width, height, steps, guidance, seed, n,
quality, source_files, model, restore_options)
quality, source_files, model)
except (ValueError, RuntimeError) as e:
self._send_error(503, str(e), "server_error", "image_generation_failed")
return
@@ -2463,7 +2359,6 @@ class Handler(BaseHTTPRequestHandler):
data = None
requested_profile: str | None = None
requested_review = False
requested_restoration = False
# Virtuelles Modell erkennen. Umschalten und Chat-Lease werden weiter
# unten atomar unter dem zentralen Orchestrierungs-Lock ausgeführt.
if body is not None and self.path.startswith("/v1/"):
@@ -2477,7 +2372,6 @@ class Handler(BaseHTTPRequestHandler):
requested_review = True
elif isinstance(model, str) and model in VIRTUAL_MODELS:
requested_profile = VIRTUAL_MODELS[model]
requested_restoration = model == RESTORATION_CHAT_MODEL
elif isinstance(model, str) and model.startswith("qwen-"):
# qwen-* ist der Namensraum des Routers
self._send_error(400, f"unbekanntes virtuelles Modell: {model}",
@@ -2487,8 +2381,6 @@ class Handler(BaseHTTPRequestHandler):
if path in {"/v1/chat/completions", "/v1/responses"}:
try:
data = _inject_global_system_policy(data, path)
if requested_restoration:
data = _inject_restoration_system_policy(data, path)
except ValueError as exc:
self._send_error(500, str(exc), "server_error",
"system_policy_unavailable")