""" Gradio UI für AI Image Generator - Mit Mock-Funktionen für CPU-Testing """ import gradio as gr from PIL import Image, ImageDraw import random import time # ==================== KONSTANTEN ==================== MAX_IMAGE_SIZE = 4096 # Maximale Bildgröße für Verarbeitung # ==================== MOCK-FUNKTIONEN ==================== def mock_text_to_image(prompt, model_id, steps, guidance_scale, progress=None): """Mock für Text-zu-Bild: Erzeugt einfaches Farbbild""" print(f"📝 Mock text_to_image aufgerufen: '{prompt[:50]}...'") if progress: for i in range(10): time.sleep(0.05) progress((i+1)/10, desc="Mock-Generierung läuft...") colors = ["lightblue", "lightgreen", "lavender", "peachpuff"] img = Image.new('RGB', (512, 512), color=random.choice(colors)) draw = ImageDraw.Draw(img) text = f"Mock: {prompt[:30]}..." if len(prompt) > 30 else f"Mock: {prompt}" draw.text((50, 256), text, fill="black") status = f"✅ Mock: '{prompt[:30]}...' würde mit {model_id} generiert (Steps: {steps}, CFG: {guidance_scale})" return img, status def mock_img_to_image(image, prompt, neg_prompt, strength, steps, guidance_scale, mode, bbox_x1, bbox_y1, bbox_x2, bbox_y2, progress=None): """Mock für Bild-zu-Bild: Fügt Rahmen und Text hinzu""" print(f"🎨 Mock img_to_image aufgerufen: Modus={mode}, Prompt='{prompt[:30]}...'") if not image: return None, None, None, None, None if progress: for i in range(10): time.sleep(0.05) progress((i+1)/10, desc=f"Mock-{mode} läuft...") img = image.copy().convert("RGB") draw = ImageDraw.Draw(img) colors = { "environment_change": "green", "focus_change": "orange", "face_only_change": "red" } border_color = colors.get(mode, "blue") draw.rectangle([20, 20, img.width-20, img.height-20], outline=border_color, width=10) if all(v is not None for v in [bbox_x1, bbox_y1, bbox_x2, bbox_y2]): x1, y1 = min(bbox_x1, bbox_x2), min(bbox_y1, bbox_y2) x2, y2 = max(bbox_x1, bbox_x2), max(bbox_y1, bbox_y2) draw.rectangle([x1, y1, x2, y2], outline="yellow", width=5) draw.text((x1+5, y1+5), f"{mode}", fill="white") draw.text((30, 30), f"Mock: {mode}", fill=border_color) draw.text((30, 60), f"Strength: {strength}", fill="black") mask_preview = Image.new('RGB', (256, 256), color='gray') controlnet_map = Image.new('RGB', (256, 256), color='darkblue') canny_map = Image.new('RGB', (256, 256), color='black') status = f"✅ Mock: {mode} angewendet (Strength: {strength}, Steps: {steps})" print(status) return img, mask_preview, mask_preview, controlnet_map, canny_map def sort_coordinates(x1, y1, x2, y2): """Sortiert Koordinaten, so dass x1 <= x2 und y1 <= y2""" sorted_x1 = min(x1, x2) sorted_x2 = max(x1, x2) sorted_y1 = min(y1, y2) sorted_y2 = max(y1, y2) return sorted_x1, sorted_y1, sorted_x2, sorted_y2 def create_preview_image(image, bbox_coords, mode): """Vorschau mit dynamischer Rahmendicke""" if image is None: return None preview = image.copy() draw = ImageDraw.Draw(preview) if mode == "environment_change": border_color = (0, 255, 0, 180) mode_text = "UMGEBUNG ÄNDERN" box_color = (255, 255, 0, 200) text_bg_color = (0, 128, 0, 160) elif mode == "focus_change": border_color = (255, 165, 0, 180) mode_text = "FOCUS VERÄNDERN" box_color = (255, 0, 0, 200) text_bg_color = (255, 140, 0, 160) elif mode == "face_only_change": border_color = (255, 0, 0, 180) mode_text = "NUR BEREICH" box_color = (255, 0, 0, 200) text_bg_color = (128, 0, 0, 160) else: border_color = (128, 128, 128, 180) mode_text = "UNBEKANNT" box_color = (128, 128, 128, 200) text_bg_color = (64, 64, 64, 160) border_width = max(8, image.width // 200) box_width = max(3, image.width // 400) draw.rectangle([0, 0, preview.width-1, preview.height-1], outline=border_color, width=border_width) if bbox_coords and all(coord is not None for coord in bbox_coords): x1, y1, x2, y2 = sort_coordinates(*bbox_coords) x1 = max(0, min(x1, preview.width-1)) y1 = max(0, min(y1, preview.height-1)) x2 = max(0, min(x2, preview.width-1)) y2 = max(0, min(y2, preview.height-1)) if x2 > x1 and y2 > y1: draw.rectangle([x1, y1, x2, y2], outline=box_color, width=box_width) text_color = (255, 255, 255) text_y = max(0, y1 - 25) try: from PIL import ImageFont font_size = max(12, image.width // 50) font = ImageFont.truetype("arial.ttf", font_size) text_bbox = draw.textbbox((x1, text_y), mode_text, font=font) draw.rectangle([text_bbox[0]-5, text_bbox[1]-2, text_bbox[2]+5, text_bbox[3]+2], fill=text_bg_color) draw.text((x1, text_y), mode_text, fill=text_color, font=font) except: text_bbox = draw.textbbox((x1, text_y), mode_text) draw.rectangle([text_bbox[0]-5, text_bbox[1]-2, text_bbox[2]+5, text_bbox[3]+2], fill=text_bg_color) draw.text((x1, text_y), mode_text, fill=text_color) return preview def mock_update_live_preview(image, bbox_x1, bbox_y1, bbox_x2, bbox_y2, mode): """Mock für Live-Vorschau MIT dynamischen Rahmen""" if not image: return None bbox_coords = sort_coordinates(bbox_x1, bbox_y1, bbox_x2, bbox_y2) return create_preview_image(image, bbox_coords, mode) def mock_process_image_upload(image): """Mock für Bild-Upload: Setzt BBox in der Mitte""" if not image: return None, 100, 100, 300, 300 # x1, y1, x2, y2 w, h = image.size bbox_size = min(w, h) * 0.3 x1 = (w - bbox_size) / 2 y1 = (h - bbox_size) / 4 x2 = x1 + bbox_size y2 = y1 + bbox_size * 1.2 print(f"📐 Bildgröße erkannt: {w}x{h} -> BBox: {int(x1)}-{int(x2)}, {int(y1)}-{int(y2)}") preview = mock_update_live_preview(image, x1, y1, x2, y2, "environment_change") return preview, int(x1), int(y1), int(x2), int(y2) # x1, y1, x2, y2 def mock_update_slider_for_image(image): """KORRIGIERT: Slider-Update mit getrennten Maxima für Breite und Höhe""" if not image: return ( gr.update(maximum=MAX_IMAGE_SIZE), gr.update(maximum=MAX_IMAGE_SIZE), gr.update(maximum=MAX_IMAGE_SIZE), gr.update(maximum=MAX_IMAGE_SIZE) ) w, h = image.size max_x = min(w, MAX_IMAGE_SIZE) max_y = min(h, MAX_IMAGE_SIZE) print(f"📐 Slider-Maxima gesetzt: X={max_x}, Y={max_y} (Bild: {w}x{h})") return ( gr.update(maximum=max_x), # bbox_x1: linke Kante max = Bildbreite gr.update(maximum=max_y), # bbox_y1: obere Kante max = Bildhöhe gr.update(maximum=max_x), # bbox_x2: rechte Kante max = Bildbreite gr.update(maximum=max_y), # bbox_y2: untere Kante max = Bildhöhe ) def mock_update_model_settings(model_id): configs = { "runwayml/stable-diffusion-v1-5": (35, 7.5, "🏠 SD 1.5 Mock"), "SG161222/Realistic_Vision_V6.0_B1_noVAE": (40, 7.0, "👤 Realistic Vision Mock") } steps, cfg, msg = configs.get(model_id, (35, 7.5, "Standard Mock")) # WICHTIG: Die dritte Rückgabe muss der HTML-String für die Info-Box sein. info_html = f"
{msg}
Mock-Einstellungen: {steps} Steps, CFG {cfg}
" return steps, cfg, info_html def mock_update_info(mode): """Mock für Prompt-Info-Update - ALTE TEXTE WIEDERHERGESTELLT""" if mode == "environment_change": return ( "`[STIL-MOTIV],[UMGEBUNG],[PERSPEKTIVE],[DETAILS],[QUALITÄT],[BELEUCHTUNG]`", "`[GESICHTER/ANATOMIE], [FEHLER], [QUALITÄT], [UNERWÜNSCHTES]`" ) elif mode == "focus_change": return ( "`[GESICHTSBESCHREIBUNG], [KLEIDUNG], [POSITION], [DETAILS], [STIL]`", "`[DEFORMIERT], [UNSCHÄRFE], [ANATOMIEFEHLER], [UNERWÜNSCHTES]`" ) else: return ( "`[STIL/KOPFART],[HAARFARBE],[AUGEN],[GESICHTSAUSDRUCK],[DETAILS],[BELEUCHTUNG]`", "`[UNREALISTISCH], [ASYMETRISCH], [FEHLER], [UNERWÜNSCHTES]`" ) # ==================== UI-DEFINITION ==================== def main_ui(): """Haupt-UI-Funktion (angepasst für 3 Modi)""" with gr.Blocks( title="AI Image Generator - Mock Version", theme=gr.themes.Base(), css=""" /* ===== INFO-BOXEN MIT GRÖßEREM TEXT ===== */ .info-box { background: #f8fafc; padding: 4px 4px; border-radius: 4px; border: none; margin-bottom: 3px; font-size: 12px; line-height: 1.3; height: 40px;