feat: Imagen Image-to-Image — Referenzbild als rawBytes übergeben

- _imagen_generate akzeptiert image_base64 (str|None)
- Multipart-Parser extrahiert hochgeladenes Bild als Base64
- rawBytes im Instance-Feld für Image-to-Image-Modus
- Duplicate import base64 as b64 entfernt
- Getestet: Text-to-Image + Image-to-Image funktionieren
This commit is contained in:
Hermes Agent
2026-06-23 08:30:48 +02:00
parent 53efc2f93b
commit 23a4bff254
+22 -6
View File
@@ -95,21 +95,32 @@ def _get_imagen_key() -> str:
def _imagen_generate( def _imagen_generate(
prompt: str, prompt: str,
image_urls: list, image_base64: str | None,
aspect_ratio: str, aspect_ratio: str,
resolution: str resolution: str
) -> dict: ) -> dict:
"""Google Imagen aufrufen — synchron, liefert Base64-Bild direkt zurück.""" """Google Imagen aufrufen — synchron, liefert Base64-Bild direkt zurück.
Args:
prompt: Text-Prompt für die Bildgenerierung.
image_base64: Optionales Referenzbild als Base64 (Image-to-Image).
aspect_ratio: Seitenverhältnis (z.B. "16:9").
resolution: Auflösung ("1K", "2K", "4K").
"""
key = _get_imagen_key() key = _get_imagen_key()
if not key: if not key:
return {"error": "Kein Google Imagen API-Key"} return {"error": "Kein Google Imagen API-Key"}
instance = {"prompt": prompt}
if image_base64:
instance["rawBytes"] = image_base64
body = json.dumps({ body = json.dumps({
"instances": [{"prompt": prompt}], "instances": [instance],
"parameters": { "parameters": {
"sampleCount": 1, "sampleCount": 1,
"aspectRatio": aspect_ratio, "aspectRatio": aspect_ratio,
"sampleImageSize": IMAGEN_SIZE_MAP.get(resolution, "2048x2048"), "sampleImageSize": IMAGEN_SIZE_MAP.get(resolution, "2K"),
} }
}).encode() }).encode()
@@ -975,6 +986,8 @@ h1{color:#c0392b;}p{color:#888;}</style></head>
def _handle_image_generate(self): def _handle_image_generate(self):
"""Bildgenerierung via Google Imagen (synchron, Base64→JPEG).""" """Bildgenerierung via Google Imagen (synchron, Base64→JPEG)."""
import base64 as b64
content_type = self.headers.get("Content-Type", "") content_type = self.headers.get("Content-Type", "")
if "multipart/form-data" not in content_type: if "multipart/form-data" not in content_type:
self._json_reply(400, {"ok": False, "error": "Expected multipart/form-data"}) self._json_reply(400, {"ok": False, "error": "Expected multipart/form-data"})
@@ -993,6 +1006,7 @@ h1{color:#c0392b;}p{color:#888;}</style></head>
prompt = "" prompt = ""
aspect_ratio = "16:9" aspect_ratio = "16:9"
resolution = "1K" resolution = "1K"
image_base64 = None
for part in parts: for part in parts:
if b"Content-Disposition" not in part: if b"Content-Disposition" not in part:
@@ -1009,13 +1023,16 @@ h1{color:#c0392b;}p{color:#888;}</style></head>
aspect_ratio = content.decode("utf-8", errors="ignore") aspect_ratio = content.decode("utf-8", errors="ignore")
elif 'name="resolution"' in headers_raw: elif 'name="resolution"' in headers_raw:
resolution = content.decode("utf-8", errors="ignore") resolution = content.decode("utf-8", errors="ignore")
elif 'name="image"' in headers_raw and len(content) > 100:
# Referenzbild als Base64 für Image-to-Image
image_base64 = b64.b64encode(content).decode()
if not prompt: if not prompt:
self._json_reply(400, {"ok": False, "error": "Prompt fehlt"}) self._json_reply(400, {"ok": False, "error": "Prompt fehlt"})
return return
# Google Imagen aufrufen (synchron!) # Google Imagen aufrufen (synchron!)
result = _imagen_generate(prompt, [], aspect_ratio, resolution) result = _imagen_generate(prompt, image_base64, aspect_ratio, resolution)
if "error" in result: if "error" in result:
self._json_reply(500, {"ok": False, "error": result["error"]}) self._json_reply(500, {"ok": False, "error": result["error"]})
return return
@@ -1031,7 +1048,6 @@ h1{color:#c0392b;}p{color:#888;}</style></head>
self._json_reply(500, {"ok": False, "error": "Leeres Base64-Bild"}) self._json_reply(500, {"ok": False, "error": "Leeres Base64-Bild"})
return return
import base64 as b64
img_bytes = b64.b64decode(b64_data) img_bytes = b64.b64decode(b64_data)
# Im media-Ordner speichern (wie normale Uploads) # Im media-Ordner speichern (wie normale Uploads)