Astridkraft commited on
Commit
c6191da
·
verified ·
1 Parent(s): d77ef69

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -60
app.py CHANGED
@@ -2,7 +2,7 @@
2
  #und deutlich besserem Prompt-Verständnis - (Änderung Architektur).
3
  #Eine deutsche Alternative zur Umsetzung von Text-Bild zu Bild ist Flux - mit einer völlig anderen Architektur als SD!
4
  import gradio as gr
5
- from diffusers import StableDiffusionPipeline, StableDiffusionImg2ImgPipeline, StableDiffusionXLPipeline
6
  from diffusers import StableDiffusionInpaintPipeline
7
  from controlnet_module import controlnet_processor
8
  import torch
@@ -12,12 +12,10 @@ import os
12
  import tempfile
13
  import random
14
 
15
-
16
-
17
  # === OPTIMIERTE EINSTELLUNGEN ===
18
  device = "cuda" if torch.cuda.is_available() else "cpu"
19
  torch_dtype = torch.float16 if device == "cuda" else torch.float32
20
- IMG_SIZE = 1024 # SDXL verwendet 1024x1024 statt 512x512
21
 
22
  print(f"Running on: {device}")
23
 
@@ -65,21 +63,44 @@ pipe_img2img = None
65
  def load_txt2img():
66
  global pipe_txt2img
67
  if pipe_txt2img is None:
68
- print("Loading SDXL Text-to-Image model...")
69
- pipe_txt2img = StableDiffusionXLPipeline.from_pretrained(
70
- "stabilityai/stable-diffusion-xl-base-1.0",
71
- torch_dtype=torch_dtype,
72
- add_watermarker=False,
73
- ).to(device)
74
-
75
- from diffusers import DPMSolverMultistepScheduler
76
- pipe_txt2img.scheduler = DPMSolverMultistepScheduler.from_config(
77
- pipe_txt2img.scheduler.config,
78
- use_karras_sigmas=True, # Noch bessere Qualität
79
- use_safetensors=True,
80
- algorithm_type="sde-dpmsolver++"
81
- )
82
- pipe_txt2img.enable_attention_slicing()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  return pipe_txt2img
84
 
85
  def load_img2img():
@@ -89,15 +110,13 @@ def load_img2img():
89
  try:
90
  pipe_img2img = StableDiffusionInpaintPipeline.from_pretrained(
91
  "runwayml/stable-diffusion-inpainting",
92
- #"stabilityai/stable-diffusion-2-inpainting", # Neues Modell
93
  torch_dtype=torch_dtype,
94
- #use_safetensors=True, # Erzwinge .safetensors
95
- allow_pickle=False, # Verhindere unsichere Serialisierung
96
  safety_checker=None,
97
- #clean_up_tokenization_spaces=False #benötigt neue Transformer-Version
98
  ).to(device)
99
  except Exception as e:
100
- print(f"Fehler beim Laden des Modells: {e}")
101
  raise
102
 
103
 
@@ -111,7 +130,8 @@ def load_img2img():
111
 
112
  pipe_img2img.enable_attention_slicing()
113
  pipe_img2img.enable_vae_tiling()
114
- pipe_img2img.vae_slicing = True
 
115
 
116
  return pipe_img2img
117
 
@@ -126,7 +146,7 @@ class TextToImageProgressCallback:
126
  """Neue Callback-Signatur für diffusers >= 1.0.0"""
127
  self.current_step = step + 1
128
  progress_percent = (step / self.total_steps) * 100
129
- self.progress(progress_percent / 100, desc="Generierung läuft - CPU benötigt bis zu 20 Minuten!")
130
  return callback_kwargs
131
 
132
  class ImageToImageProgressCallback:
@@ -152,7 +172,7 @@ class ImageToImageProgressCallback:
152
  print(f"🎯 INTERNE STEP-AUSGABE: Strength {self.strength} → {self.actual_total_steps} tatsächliche Denoising-Schritte")
153
 
154
  progress_percent = (step / self.actual_total_steps) * 100
155
- self.progress(progress_percent / 100, desc="Generierung läuft - CPU benötigt bis zu 20 Minuten!")
156
  return callback_kwargs
157
 
158
  # === NEUE FUNKTIONEN FÜR DIE FEATURES ===
@@ -239,9 +259,7 @@ def text_to_image(prompt, steps, guidance_scale, progress=gr.Progress()):
239
  print(f"Starting generation for: {prompt}")
240
  start_time = time.time()
241
 
242
- # Statusmeldung anzeigen
243
- progress(0, desc="Generierung läuft - CPU benötigt bis zu 20 Minuten!")
244
-
245
  pipe = load_txt2img()
246
 
247
  # ZUFÄLLIGER SEED für Variation
@@ -249,28 +267,27 @@ def text_to_image(prompt, steps, guidance_scale, progress=gr.Progress()):
249
  generator = torch.Generator(device=device).manual_seed(seed)
250
  print(f"Using seed: {seed}")
251
 
252
- # NEUE Callback-Implementierung
253
  callback = TextToImageProgressCallback(progress, steps)
254
 
 
255
  image = pipe(
256
  prompt=prompt,
257
- height=IMG_SIZE,
258
- width=IMG_SIZE,
259
  num_inference_steps=int(steps),
260
  guidance_scale=guidance_scale,
261
  generator=generator,
262
- callback_on_step_end=callback, # NEUE Parameter-Name
263
- callback_on_step_end_tensor_inputs=[], # Keine zusätzlichen Tensor-Inputs
264
  ).images[0]
265
 
266
  end_time = time.time()
267
  print(f"Bild generiert in {end_time - start_time:.2f} Sekunden")
268
 
269
- # Robuste Zwischenspeicherung
270
  return image
271
 
272
  except Exception as e:
273
- print(f"Fehler: {e}")
274
  import traceback
275
  traceback.print_exc()
276
  return None
@@ -299,12 +316,10 @@ def img_to_image(image, prompt, neg_prompt, strength, steps, guidance_scale,
299
 
300
  # CONTROLNET-STRENGTH ANPASSEN ABHÄNGIG VOM MODUS
301
  if face_preserve:
302
- # UMGEBUNG BEIBEHALTEN, PERSON ÄNDERN → HOHE STRENGTH FÜR KOMBINIERTE STRATEGIE
303
- controlnet_strength = adj_strength * 0.8 # 80% für kombinierte OpenPose + Canny
304
  print(f"🎯 ControlNet Modus: Umgebung beibehalten (Strength = {controlnet_strength:.3f})")
305
  else:
306
- # PERSON BEIBEHALTEN, UMGEBUNG ÄNDERN → NORMALE STRENGTH FÜR OPENPOSE
307
- controlnet_strength = adj_strength * 0.5 # 50% für OpenPose
308
  print(f"🎯 ControlNet Modus: Person beibehalten (Strength = {controlnet_strength:.3f})")
309
 
310
  controlnet_steps = min(25, int(steps * 0.8))
@@ -324,7 +339,7 @@ def img_to_image(image, prompt, neg_prompt, strength, steps, guidance_scale,
324
  guidance_scale=guidance_scale,
325
  controlnet_strength=controlnet_strength,
326
  progress=progress,
327
- keep_environment=face_preserve # WICHTIG: Parameter hinzugefügt!
328
  )
329
 
330
  print(f"✅ ControlNet Output erhalten: {type(controlnet_output)}")
@@ -335,10 +350,9 @@ def img_to_image(image, prompt, neg_prompt, strength, steps, guidance_scale,
335
  # -------------------------------
336
  progress(0.3, desc="ControlNet abgeschlossen – starte Inpaint...")
337
 
338
- pipe = load_img2img() # ← deine bestehende Funktion
339
 
340
- # inpaint_input ist IMMER das Originalbild (laut neuer ControlNet-Logik)
341
- img_resized = inpaint_input.convert("RGB").resize((512, 512)) # Bleibt bei 512 für Inpaint
342
 
343
  adj_guidance = min(guidance_scale, 12.0)
344
  seed = random.randint(0, 2**32 - 1)
@@ -351,7 +365,7 @@ def img_to_image(image, prompt, neg_prompt, strength, steps, guidance_scale,
351
  mask = None
352
  if bbox_x1 and bbox_y1 and bbox_x2 and bbox_y2:
353
  orig_w, orig_h = image.size
354
- scale_x, scale_y = 512 / orig_w, 512 / orig_h # Skalierung für Inpaint (512px)
355
  bbox_coords = [
356
  int(bbox_x1 * scale_x),
357
  int(bbox_y1 * scale_y),
@@ -398,7 +412,6 @@ def img_to_image(image, prompt, neg_prompt, strength, steps, guidance_scale,
398
  import traceback
399
  traceback.print_exc()
400
  return None
401
-
402
 
403
  def update_bbox_from_image(image):
404
  """Aktualisiert die Bounding-Box-Koordinaten wenn ein Bild hochgeladen wird"""
@@ -480,7 +493,6 @@ def main_ui():
480
  """
481
  ) as demo:
482
 
483
- # --- Hauptanwendungsbereich (zunächst versteckt) ---
484
  with gr.Column(visible=True) as content_area:
485
  with gr.Tab("Text zu Bild"):
486
  gr.Markdown("**Beschreibe dein gewünschtes Bild:**")
@@ -524,7 +536,6 @@ def main_ui():
524
  with gr.Tab("Bild zu Bild"):
525
  gr.Markdown("**Lade ein Bild hoch und beschreibe die gewünschte Veränderung:**")
526
 
527
- # NEUE ANORDNUNG: Eingabebild und Live-Vorschau nebeneinander
528
  with gr.Row():
529
  with gr.Column():
530
  img_input = gr.Image(
@@ -542,7 +553,6 @@ def main_ui():
542
  show_download_button=False
543
  )
544
 
545
- # DARUNTER: Checkbox Gesicht/Person oder Umgebung ändern
546
  with gr.Row():
547
  face_preserve = gr.Checkbox(
548
  label="Schutz",
@@ -550,7 +560,6 @@ def main_ui():
550
  info="🟢 Checkbox AN: Alles AUSSERHALB des gelben Rahmens verändern | 🔴 Checkbox AUS: Nur INNERHALB des gelben Rahmens verändern"
551
  )
552
 
553
- # DARUNTER: Bildelementbereich anpassen
554
  with gr.Row():
555
  gr.Markdown("**Bildelementbereich anpassen**")
556
 
@@ -581,7 +590,6 @@ def main_ui():
581
  info="Untere Kante des Bildelementbereichs"
582
  )
583
 
584
- # DARUNTER: Prompt und Negativ-Prompt
585
  with gr.Row():
586
  with gr.Column():
587
  img_prompt = gr.Textbox(
@@ -598,7 +606,6 @@ def main_ui():
598
  info="Was soll vermieden werden? Unerwünschte Elemente auflisten."
599
  )
600
 
601
- # DARUNTER: Veränderungsstärke, Inferenzschritte, Promptstärke
602
  with gr.Row():
603
  with gr.Column():
604
  strength_slider = gr.Slider(
@@ -628,7 +635,6 @@ def main_ui():
628
  "• **Koordinaten nur bei erkennbaren Verzerrungen anpassen** (Bereiche leicht verschieben)"
629
  )
630
 
631
-
632
  transform_btn = gr.Button("Bild transformieren", variant="primary")
633
 
634
  with gr.Row():
@@ -638,15 +644,12 @@ def main_ui():
638
  type="pil"
639
  )
640
 
641
- # NEUE: Event-Handler für alle Live-Updates
642
- # Bild-Upload: Auto-Koordinaten + Vorschau
643
  img_input.change(
644
  fn=process_image_upload,
645
  inputs=[img_input],
646
  outputs=[preview_output, bbox_x1, bbox_y1, bbox_x2, bbox_y2]
647
  )
648
 
649
- # Live-Updates bei Koordinaten-Änderungen
650
  coordinate_inputs = [img_input, bbox_x1, bbox_y1, bbox_x2, bbox_y2, face_preserve]
651
 
652
  bbox_x1.change(
@@ -673,14 +676,12 @@ def main_ui():
673
  outputs=preview_output
674
  )
675
 
676
- # Live-Update bei Modus-Änderung
677
  face_preserve.change(
678
  fn=update_live_preview,
679
  inputs=coordinate_inputs,
680
  outputs=preview_output
681
  )
682
 
683
- # Transform-Button (UNVERÄNDERT - gibt OUTPUT zurück)
684
  transform_btn.click(
685
  fn=img_to_image,
686
  inputs=[
@@ -697,7 +698,11 @@ def main_ui():
697
 
698
  if __name__ == "__main__":
699
  demo = main_ui()
700
- demo.queue()
 
 
 
 
701
  demo.launch(
702
  server_name="0.0.0.0",
703
  server_port=7860,
 
2
  #und deutlich besserem Prompt-Verständnis - (Änderung Architektur).
3
  #Eine deutsche Alternative zur Umsetzung von Text-Bild zu Bild ist Flux - mit einer völlig anderen Architektur als SD!
4
  import gradio as gr
5
+ from diffusers import StableDiffusionPipeline, StableDiffusionImg2ImgPipeline
6
  from diffusers import StableDiffusionInpaintPipeline
7
  from controlnet_module import controlnet_processor
8
  import torch
 
12
  import tempfile
13
  import random
14
 
 
 
15
  # === OPTIMIERTE EINSTELLUNGEN ===
16
  device = "cuda" if torch.cuda.is_available() else "cpu"
17
  torch_dtype = torch.float16 if device == "cuda" else torch.float32
18
+ IMG_SIZE = 512 # Jetzt 512x512 für Realistic Vision
19
 
20
  print(f"Running on: {device}")
21
 
 
63
  def load_txt2img():
64
  global pipe_txt2img
65
  if pipe_txt2img is None:
66
+ try:
67
+ print("Loading Realistic Vision V6.0 for high-quality 512x512...")
68
+ pipe_txt2img = StableDiffusionPipeline.from_pretrained(
69
+ "SG161222/Realistic_Vision_V6.0_B1",
70
+ torch_dtype=torch_dtype,
71
+ safety_checker=None,
72
+ requires_safety_checker=False,
73
+ add_watermarker=False,
74
+ use_safetensors=True, # Sicherheitsproblem behoben
75
+ variant="fp16" if torch_dtype == torch.float16 else None,
76
+ ).to(device)
77
+
78
+ from diffusers import DPMSolverMultistepScheduler
79
+ pipe_txt2img.scheduler = DPMSolverMultistepScheduler.from_config(
80
+ pipe_txt2img.scheduler.config,
81
+ use_karras_sigmas=True,
82
+ algorithm_type="sde-dpmsolver++"
83
+ )
84
+
85
+ # T4 OPTIMIERUNGEN
86
+ pipe_txt2img.enable_attention_slicing()
87
+ pipe_txt2img.enable_vae_slicing()
88
+ if hasattr(pipe_txt2img, 'vae'):
89
+ pipe_txt2img.vae.enable_slicing()
90
+
91
+ print("✅ Realistic Vision V6.0 erfolgreich geladen")
92
+
93
+ except Exception as e:
94
+ print(f"❌ Fehler beim Laden von Realistic Vision: {e}")
95
+ print("🔄 Fallback auf SD 1.5...")
96
+ # Fallback auf Standard SD 1.5
97
+ pipe_txt2img = StableDiffusionPipeline.from_pretrained(
98
+ "runwayml/stable-diffusion-v1-5",
99
+ torch_dtype=torch_dtype,
100
+ use_safetensors=True,
101
+ ).to(device)
102
+ pipe_txt2img.enable_attention_slicing()
103
+
104
  return pipe_txt2img
105
 
106
  def load_img2img():
 
110
  try:
111
  pipe_img2img = StableDiffusionInpaintPipeline.from_pretrained(
112
  "runwayml/stable-diffusion-inpainting",
 
113
  torch_dtype=torch_dtype,
114
+ use_safetensors=True, # Sicherheitsproblem behoben
115
+ allow_pickle=False,
116
  safety_checker=None,
 
117
  ).to(device)
118
  except Exception as e:
119
+ print(f"Fehler beim Laden des Inpainting-Modells: {e}")
120
  raise
121
 
122
 
 
130
 
131
  pipe_img2img.enable_attention_slicing()
132
  pipe_img2img.enable_vae_tiling()
133
+ if hasattr(pipe_img2img, 'vae_slicing'):
134
+ pipe_img2img.vae_slicing = True
135
 
136
  return pipe_img2img
137
 
 
146
  """Neue Callback-Signatur für diffusers >= 1.0.0"""
147
  self.current_step = step + 1
148
  progress_percent = (step / self.total_steps) * 100
149
+ self.progress(progress_percent / 100, desc="Generierung läuft...")
150
  return callback_kwargs
151
 
152
  class ImageToImageProgressCallback:
 
172
  print(f"🎯 INTERNE STEP-AUSGABE: Strength {self.strength} → {self.actual_total_steps} tatsächliche Denoising-Schritte")
173
 
174
  progress_percent = (step / self.actual_total_steps) * 100
175
+ self.progress(progress_percent / 100, desc="Generierung läuft...")
176
  return callback_kwargs
177
 
178
  # === NEUE FUNKTIONEN FÜR DIE FEATURES ===
 
259
  print(f"Starting generation for: {prompt}")
260
  start_time = time.time()
261
 
262
+ progress(0, desc="Lade Modell...")
 
 
263
  pipe = load_txt2img()
264
 
265
  # ZUFÄLLIGER SEED für Variation
 
267
  generator = torch.Generator(device=device).manual_seed(seed)
268
  print(f"Using seed: {seed}")
269
 
 
270
  callback = TextToImageProgressCallback(progress, steps)
271
 
272
+ # NEUE: 512x512 für Realistic Vision
273
  image = pipe(
274
  prompt=prompt,
275
+ height=512, # ← 512 statt IMG_SIZE (1024)
276
+ width=512, # ← 512 statt IMG_SIZE (1024)
277
  num_inference_steps=int(steps),
278
  guidance_scale=guidance_scale,
279
  generator=generator,
280
+ callback_on_step_end=callback,
281
+ callback_on_step_end_tensor_inputs=[],
282
  ).images[0]
283
 
284
  end_time = time.time()
285
  print(f"Bild generiert in {end_time - start_time:.2f} Sekunden")
286
 
 
287
  return image
288
 
289
  except Exception as e:
290
+ print(f"Fehler in text_to_image: {e}")
291
  import traceback
292
  traceback.print_exc()
293
  return None
 
316
 
317
  # CONTROLNET-STRENGTH ANPASSEN ABHÄNGIG VOM MODUS
318
  if face_preserve:
319
+ controlnet_strength = adj_strength * 0.8
 
320
  print(f"🎯 ControlNet Modus: Umgebung beibehalten (Strength = {controlnet_strength:.3f})")
321
  else:
322
+ controlnet_strength = adj_strength * 0.5
 
323
  print(f"🎯 ControlNet Modus: Person beibehalten (Strength = {controlnet_strength:.3f})")
324
 
325
  controlnet_steps = min(25, int(steps * 0.8))
 
339
  guidance_scale=guidance_scale,
340
  controlnet_strength=controlnet_strength,
341
  progress=progress,
342
+ keep_environment=face_preserve
343
  )
344
 
345
  print(f"✅ ControlNet Output erhalten: {type(controlnet_output)}")
 
350
  # -------------------------------
351
  progress(0.3, desc="ControlNet abgeschlossen – starte Inpaint...")
352
 
353
+ pipe = load_img2img()
354
 
355
+ img_resized = inpaint_input.convert("RGB").resize((512, 512))
 
356
 
357
  adj_guidance = min(guidance_scale, 12.0)
358
  seed = random.randint(0, 2**32 - 1)
 
365
  mask = None
366
  if bbox_x1 and bbox_y1 and bbox_x2 and bbox_y2:
367
  orig_w, orig_h = image.size
368
+ scale_x, scale_y = 512 / orig_w, 512 / orig_h
369
  bbox_coords = [
370
  int(bbox_x1 * scale_x),
371
  int(bbox_y1 * scale_y),
 
412
  import traceback
413
  traceback.print_exc()
414
  return None
 
415
 
416
  def update_bbox_from_image(image):
417
  """Aktualisiert die Bounding-Box-Koordinaten wenn ein Bild hochgeladen wird"""
 
493
  """
494
  ) as demo:
495
 
 
496
  with gr.Column(visible=True) as content_area:
497
  with gr.Tab("Text zu Bild"):
498
  gr.Markdown("**Beschreibe dein gewünschtes Bild:**")
 
536
  with gr.Tab("Bild zu Bild"):
537
  gr.Markdown("**Lade ein Bild hoch und beschreibe die gewünschte Veränderung:**")
538
 
 
539
  with gr.Row():
540
  with gr.Column():
541
  img_input = gr.Image(
 
553
  show_download_button=False
554
  )
555
 
 
556
  with gr.Row():
557
  face_preserve = gr.Checkbox(
558
  label="Schutz",
 
560
  info="🟢 Checkbox AN: Alles AUSSERHALB des gelben Rahmens verändern | 🔴 Checkbox AUS: Nur INNERHALB des gelben Rahmens verändern"
561
  )
562
 
 
563
  with gr.Row():
564
  gr.Markdown("**Bildelementbereich anpassen**")
565
 
 
590
  info="Untere Kante des Bildelementbereichs"
591
  )
592
 
 
593
  with gr.Row():
594
  with gr.Column():
595
  img_prompt = gr.Textbox(
 
606
  info="Was soll vermieden werden? Unerwünschte Elemente auflisten."
607
  )
608
 
 
609
  with gr.Row():
610
  with gr.Column():
611
  strength_slider = gr.Slider(
 
635
  "• **Koordinaten nur bei erkennbaren Verzerrungen anpassen** (Bereiche leicht verschieben)"
636
  )
637
 
 
638
  transform_btn = gr.Button("Bild transformieren", variant="primary")
639
 
640
  with gr.Row():
 
644
  type="pil"
645
  )
646
 
 
 
647
  img_input.change(
648
  fn=process_image_upload,
649
  inputs=[img_input],
650
  outputs=[preview_output, bbox_x1, bbox_y1, bbox_x2, bbox_y2]
651
  )
652
 
 
653
  coordinate_inputs = [img_input, bbox_x1, bbox_y1, bbox_x2, bbox_y2, face_preserve]
654
 
655
  bbox_x1.change(
 
676
  outputs=preview_output
677
  )
678
 
 
679
  face_preserve.change(
680
  fn=update_live_preview,
681
  inputs=coordinate_inputs,
682
  outputs=preview_output
683
  )
684
 
 
685
  transform_btn.click(
686
  fn=img_to_image,
687
  inputs=[
 
698
 
699
  if __name__ == "__main__":
700
  demo = main_ui()
701
+ # OPTIMIERTE WARTESCHLANGE FÜR T4
702
+ demo.queue(
703
+ max_size=3, # Max 3 Anfragen in Warteschlange
704
+ concurrency_count=1 # Nur 1 Generation gleichzeitig
705
+ )
706
  demo.launch(
707
  server_name="0.0.0.0",
708
  server_port=7860,