alexander00001 commited on
Commit
64214fe
·
verified ·
1 Parent(s): 384dd80

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +153 -96
app.py CHANGED
@@ -29,37 +29,47 @@ except ImportError:
29
  print("⚠️ Compel not available - using standard prompt processing")
30
 
31
  # ===== 优化后的配置 =====
 
32
  STYLE_KEYWORDS = {
33
- "None": {"prefix": "", "suffix": ""},
 
 
 
 
 
 
 
 
 
 
 
34
  "Realistic": {
35
- "prefix": "(RAW photo:1.3), (photorealistic:1.4), (hyperrealistic:1.3), 8k uhd, (ultra realistic skin texture:1.2), cinematic lighting, vibrant colors, masterpiece, realistic skin texture, detailed anatomy, professional photography",
36
- "suffix": "sharp focus, (everything in focus:1.3), (no bokeh:1.2), realistic skin texture, subsurface scattering, detailed anatomy, (perfect anatomy:1.2), detailed face, detailed background, lifelike, professional photography, realistic proportions, (detailed face:1.1), natural pose, expressive eyes, 8k resolution"
37
  },
38
  "Anime": {
39
- "prefix": "(anime style:1.3), (anime artwork:1.2), vibrant, key visual, studio anime, highly detailed anime",
40
- "suffix": "cel shading, clean linework, vibrant anime colors, detailed anime eyes, smooth anime skin, perfect anime proportions, manga illustration"
41
- },
42
- "Comic": {
43
- "prefix": "(comic book art:1.3), (graphic novel:1.2), bold inking, comic art style",
44
- "suffix": "bold outlines, halftone dots, pop art colors, dynamic panel, graphic illustration, cel shading, comic book style"
45
  },
46
- "Watercolor": {
47
- "prefix": "(watercolor painting:1.3), (watercolor art:1.2), soft edges, delicate washes, artistic",
48
- "suffix": "soft gradients, pastel colors, paper texture, artistic brush strokes, traditional watercolor, hand-painted"
49
  }
50
  }
51
 
52
- QUALITY_TAGS = "masterpiece, best quality, high resolution, detailed"
 
53
 
54
- # 🔧 正:使用正确的模型名称
55
- FIXED_MODEL = "votepurchase/pornmasterPro_noobV3VAE"
 
56
 
57
- # 🔧 修正:使用正确的 LoRA 配置
58
  LORA_CONFIGS = [
59
  {
60
- "repo_id": "OedoSoldier/detail-tweaker-lora",
61
- "weight_name": "add_detail.safetensors",
62
- "adapter_name": "detail_tweaker",
63
  "scale": 0.8
64
  }
65
  ]
@@ -74,7 +84,7 @@ device = None
74
  model_loaded = False
75
 
76
  def initialize_model():
77
- """优化的模型初始化 - 修复设备不一致问题"""
78
  global pipeline, compel_processor, device, model_loaded
79
 
80
  if model_loaded and pipeline is not None:
@@ -85,25 +95,34 @@ def initialize_model():
85
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
86
  print(f"🖥️ Using device: {device}")
87
 
88
- print(f"📦 Loading model: {FIXED_MODEL}")
 
 
 
 
 
 
 
 
 
89
 
90
- # 基础模型加载
91
- pipeline = StableDiffusionXLPipeline.from_pretrained(
92
- FIXED_MODEL,
 
 
93
  torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
94
- variant="fp16" if torch.cuda.is_available() else None,
95
  use_safetensors=True,
96
  safety_checker=None,
97
  requires_safety_checker=False
98
  )
99
 
100
- # 优化调度器
101
  pipeline.scheduler = EulerDiscreteScheduler.from_config(
102
  pipeline.scheduler.config,
103
  timestep_spacing="trailing"
104
  )
105
 
106
- # 先移到设备
107
  pipeline = pipeline.to(device)
108
 
109
  # 加载 LoRA
@@ -113,53 +132,46 @@ def initialize_model():
113
 
114
  for lora_config in LORA_CONFIGS:
115
  try:
116
- print(f" Loading: {lora_config['repo_id']}/{lora_config['weight_name']}")
117
  pipeline.load_lora_weights(
118
  lora_config["repo_id"],
119
  weight_name=lora_config["weight_name"],
120
  adapter_name=lora_config["adapter_name"]
121
  )
122
-
123
- # 🔧 关键修复: 确保 LoRA 权重在正确的设备上
124
- if hasattr(pipeline, 'unet') and hasattr(pipeline.unet, 'to'):
125
- pipeline.unet.to(device)
126
-
127
  adapter_names.append(lora_config["adapter_name"])
128
  adapter_scales.append(lora_config.get("scale", 0.8))
129
- print(f" ✅ LoRA loaded: {lora_config['adapter_name']} (scale: {lora_config.get('scale', 0.8)})")
130
  except Exception as lora_error:
131
- print(f" ⚠️ Failed to load LoRA {lora_config['adapter_name']}: {lora_error}")
132
- print(traceback.format_exc())
133
 
134
  # 设置 LoRA 强度
135
  if adapter_names:
136
  try:
137
  pipeline.set_adapters(adapter_names, adapter_weights=adapter_scales)
138
  print(f"✅ LoRA adapters activated with scales: {adapter_scales}")
139
-
140
- # 🔧 再次确保所有组件在同一设备
141
- pipeline.to(device)
142
  except Exception as e:
143
  print(f"⚠️ Failed to set adapter scales: {e}")
144
 
145
- # GPU优化
146
  if torch.cuda.is_available():
147
  try:
 
148
  pipeline.enable_vae_slicing()
149
  pipeline.enable_vae_tiling()
150
 
 
151
  try:
152
  pipeline.enable_xformers_memory_efficient_attention()
153
  print("✅ xFormers enabled")
154
  except:
155
  print("⚠️ xFormers not available, using default attention")
156
 
 
157
  print("ℹ️ Skipping torch.compile for ZeroGPU compatibility")
158
 
159
  except Exception as opt_error:
160
  print(f"⚠️ Optimization warning: {opt_error}")
161
 
162
- # 初始化Compel
163
  if COMPEL_AVAILABLE:
164
  try:
165
  compel_processor = Compel(
@@ -174,14 +186,8 @@ def initialize_model():
174
  print(f"⚠️ Compel initialization failed: {compel_error}")
175
  compel_processor = None
176
 
177
- # 🔧 最终设备检查
178
- print(f"🔍 Final device check:")
179
- print(f" - UNet device: {next(pipeline.unet.parameters()).device}")
180
- print(f" - VAE device: {next(pipeline.vae.parameters()).device}")
181
- print(f" - Text Encoder device: {next(pipeline.text_encoder.parameters()).device}")
182
-
183
  model_loaded = True
184
- print("✅ Model initialization complete")
185
  return True
186
 
187
  except Exception as e:
@@ -191,11 +197,14 @@ def initialize_model():
191
  return False
192
 
193
  def enhance_prompt(prompt: str, style: str) -> str:
194
- """优化的提示词增强"""
195
  if not prompt or prompt.strip() == "":
196
  return ""
197
 
 
198
  style_config = STYLE_KEYWORDS.get(style, STYLE_KEYWORDS["None"])
 
 
199
  parts = []
200
 
201
  if style_config["prefix"]:
@@ -217,20 +226,22 @@ def enhance_prompt(prompt: str, style: str) -> str:
217
  return enhanced
218
 
219
  def build_negative_prompt(style: str, custom_negative: str = "") -> str:
220
- """根据风格构建负面提示词"""
221
- base_negative = "(low quality:1.4), (worst quality:1.4), (bad anatomy:1.3), (bad hands:1.2), blurry, watermark, text, error, cropped, jpeg artifacts, ugly, duplicate, deformed"
 
222
 
 
223
  style_negatives = {
224
- "Realistic": ", (cartoon:1.3), (anime:1.3), (3d render:1.2), (illustration:1.2), (painting:1.2), (drawing:1.2), (art:1.2), (sketch:1.2), artificial, unrealistic",
225
- "Anime": ", (realistic:1.3), (photorealistic:1.3), (photo:1.2), (3d:1.2), (hyperrealistic:1.2)",
226
- "Comic": ", (realistic:1.2), (photorealistic:1.2), (blurry lines:1.2), (soft edges:1.2)",
227
- "Watercolor": ", (digital art:1.2), (sharp edges:1.2), (vector art:1.2), (3d:1.2)"
228
  }
229
 
230
  negative = base_negative
231
  if style in style_negatives:
232
  negative += style_negatives[style]
233
 
 
234
  if custom_negative.strip():
235
  negative += f", {custom_negative.strip()}"
236
 
@@ -242,6 +253,7 @@ def process_with_compel(prompt, negative_prompt):
242
  return None, None
243
 
244
  try:
 
245
  conditioning, pooled = compel_processor([prompt, negative_prompt])
246
  print("✅ Long prompt processed with Compel")
247
  return conditioning, pooled
@@ -258,10 +270,13 @@ def apply_spaces_decorator(func):
258
  def create_metadata_content(prompt, enhanced_prompt, seed, steps, cfg_scale, width, height, style):
259
  """创建元数据"""
260
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
 
 
261
  lora_info = ", ".join([f"{lora['adapter_name']}({lora.get('scale', 1.0)})" for lora in LORA_CONFIGS])
262
 
263
  return f"""Generated Image Metadata
264
  ======================
 
265
  Timestamp: {timestamp}
266
  Original Prompt: {prompt}
267
  Enhanced Prompt: {enhanced_prompt}
@@ -270,22 +285,25 @@ Steps: {steps}
270
  CFG Scale: {cfg_scale}
271
  Dimensions: {width}x{height}
272
  Style: {style}
273
- LoRA: {lora_info}
274
  """
275
 
276
  def cleanup_pipeline():
277
- """清理 pipeline 状态"""
278
  global pipeline
279
 
280
  if pipeline is None:
281
  return
282
 
283
  try:
 
284
  if torch.cuda.is_available():
285
  torch.cuda.empty_cache()
286
  torch.cuda.ipc_collect()
287
 
 
288
  if hasattr(pipeline, 'unet'):
 
289
  if hasattr(pipeline.unet, 'set_attn_processor'):
290
  try:
291
  from diffusers.models.attention_processor import AttnProcessor
@@ -293,6 +311,7 @@ def cleanup_pipeline():
293
  except:
294
  pass
295
 
 
296
  if hasattr(pipeline, 'vae'):
297
  pipeline.vae.to('cpu')
298
  pipeline.vae.to(device)
@@ -304,30 +323,38 @@ def cleanup_pipeline():
304
 
305
  @apply_spaces_decorator
306
  def generate_image(prompt: str, style: str, negative_prompt: str = "",
307
- steps: int = 25, cfg_scale: float = 7.0,
308
- seed: int = -1, width: int = 1024, height: int = 1024,
309
  progress=gr.Progress()):
310
- """图像生成主函数"""
311
 
 
312
  if not prompt or prompt.strip() == "":
313
  return None, "", "❌ Please enter a prompt"
314
 
315
  progress(0.05, desc="Initializing...")
316
 
 
317
  if not initialize_model():
318
  return None, "", "❌ Failed to load model"
319
 
 
320
  cleanup_pipeline()
321
 
322
  progress(0.1, desc="Processing prompt...")
323
 
324
  try:
 
325
  if seed == -1:
326
  seed = random.randint(0, np.iinfo(np.int32).max)
327
 
 
328
  generator = torch.Generator(device).manual_seed(seed)
329
 
 
330
  enhanced_prompt = enhance_prompt(prompt, style)
 
 
331
  final_negative = build_negative_prompt(style, negative_prompt)
332
 
333
  print(f"🔧 Generation params: seed={seed}, steps={steps}, cfg={cfg_scale}, size={width}x{height}")
@@ -335,6 +362,7 @@ def generate_image(prompt: str, style: str, negative_prompt: str = "",
335
 
336
  progress(0.2, desc="Generating image...")
337
 
 
338
  prompt_length = len(enhanced_prompt.split())
339
  use_compel = prompt_length > 50 and compel_processor is not None
340
 
@@ -343,6 +371,7 @@ def generate_image(prompt: str, style: str, negative_prompt: str = "",
343
  conditioning, pooled = process_with_compel(enhanced_prompt, final_negative)
344
 
345
  if conditioning is not None:
 
346
  result = pipeline(
347
  prompt_embeds=conditioning[0:1],
348
  pooled_prompt_embeds=pooled[0:1],
@@ -356,6 +385,7 @@ def generate_image(prompt: str, style: str, negative_prompt: str = "",
356
  output_type="pil"
357
  ).images[0]
358
  else:
 
359
  print("⚠️ Falling back to standard generation")
360
  result = pipeline(
361
  prompt=enhanced_prompt,
@@ -368,6 +398,7 @@ def generate_image(prompt: str, style: str, negative_prompt: str = "",
368
  output_type="pil"
369
  ).images[0]
370
  else:
 
371
  print(f"📝 Standard generation ({prompt_length} words)")
372
  result = pipeline(
373
  prompt=enhanced_prompt,
@@ -382,12 +413,14 @@ def generate_image(prompt: str, style: str, negative_prompt: str = "",
382
 
383
  progress(0.95, desc="Finalizing...")
384
 
 
385
  if not isinstance(result, Image.Image):
386
  if isinstance(result, np.ndarray):
387
  if result.dtype != np.uint8:
388
  result = (result * 255).astype(np.uint8)
389
  result = Image.fromarray(result)
390
 
 
391
  metadata = create_metadata_content(
392
  prompt, enhanced_prompt, seed, steps, cfg_scale,
393
  width, height, style
@@ -395,6 +428,7 @@ def generate_image(prompt: str, style: str, negative_prompt: str = "",
395
 
396
  generation_info = f"Style: {style} | Seed: {seed} | Size: {width}×{height} | Steps: {steps} | CFG: {cfg_scale}"
397
 
 
398
  if torch.cuda.is_available():
399
  torch.cuda.empty_cache()
400
 
@@ -408,6 +442,7 @@ def generate_image(prompt: str, style: str, negative_prompt: str = "",
408
  print(f"❌ Generation error: {error_msg}")
409
  print(traceback.format_exc())
410
 
 
411
  try:
412
  cleanup_pipeline()
413
  except:
@@ -421,17 +456,17 @@ css = """
421
  max-width: 100% !important;
422
  margin: 0 !important;
423
  padding: 0 !important;
424
- background: linear-gradient(135deg, #e6a4f2 0%, #1197e4 100%) !important;
425
  min-height: 100vh !important;
426
  font-family: 'Segoe UI', Arial, sans-serif !important;
427
  }
428
 
429
  .main-content {
430
- background: rgba(255, 255, 255, 0.9) !important;
431
  border-radius: 20px !important;
432
  padding: 20px !important;
433
  margin: 15px !important;
434
- box-shadow: 0 10px 25px rgba(255, 255, 255, 0.2) !important;
435
  min-height: calc(100vh - 30px) !important;
436
  color: #3e3e3e !important;
437
  backdrop-filter: blur(10px) !important;
@@ -439,7 +474,7 @@ css = """
439
 
440
  .title {
441
  text-align: center !important;
442
- background: linear-gradient(45deg, #bb6ded, #08676b) !important;
443
  -webkit-background-clip: text !important;
444
  -webkit-text-fill-color: transparent !important;
445
  background-clip: text !important;
@@ -449,7 +484,7 @@ css = """
449
  }
450
 
451
  .warning-box {
452
- background: linear-gradient(45deg, #bb6ded, #08676b) !important;
453
  color: white !important;
454
  padding: 8px !important;
455
  border-radius: 8px !important;
@@ -459,9 +494,21 @@ css = """
459
  font-size: 14px !important;
460
  }
461
 
 
 
 
 
 
 
 
 
 
 
 
 
462
  .prompt-box textarea, .prompt-box input {
463
  border-radius: 10px !important;
464
- border: 2px solid #bb6ded !important;
465
  padding: 15px !important;
466
  font-size: 18px !important;
467
  background: linear-gradient(135deg, rgba(245, 243, 255, 0.9), rgba(237, 233, 254, 0.9)) !important;
@@ -469,8 +516,8 @@ css = """
469
  }
470
 
471
  .prompt-box textarea:focus, .prompt-box input:focus {
472
- border-color: #08676b !important;
473
- box-shadow: 0 0 15px rgba(77, 8, 161, 0.3) !important;
474
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 249, 250, 0.95)) !important;
475
  }
476
 
@@ -479,7 +526,7 @@ css = """
479
  border-radius: 12px !important;
480
  padding: 15px !important;
481
  margin-bottom: 8px !important;
482
- border: 2px solid rgba(187, 109, 237, 0.3) !important;
483
  backdrop-filter: blur(5px) !important;
484
  }
485
 
@@ -490,20 +537,20 @@ css = """
490
  }
491
 
492
  .controls-section input[type="radio"] {
493
- accent-color: #bb6ded !important;
494
  }
495
 
496
  .controls-section input[type="number"],
497
  .controls-section input[type="range"] {
498
  background: rgba(255, 255, 255, 0.9) !important;
499
- border: 1px solid #bb6ded !important;
500
  border-radius: 6px !important;
501
  padding: 8px !important;
502
  color: #2d2d2d !important;
503
  }
504
 
505
  .generate-btn {
506
- background: linear-gradient(45deg, #bb6ded, #08676b) !important;
507
  color: white !important;
508
  border: none !important;
509
  padding: 15px 25px !important;
@@ -519,7 +566,7 @@ css = """
519
 
520
  .generate-btn:hover {
521
  transform: translateY(-2px) !important;
522
- box-shadow: 0 8px 25px rgba(187, 109, 237, 0.5) !important;
523
  }
524
 
525
  .image-output {
@@ -527,31 +574,31 @@ css = """
527
  overflow: hidden !important;
528
  max-width: 100% !important;
529
  max-height: 70vh !important;
530
- border: 3px solid #08676b !important;
531
  box-shadow: 0 8px 20px rgba(0,0,0,0.15) !important;
532
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(248, 249, 250, 0.9)) !important;
533
  }
534
 
535
  .image-info {
536
- background: linear-gradient(135deg, rgba(248, 249, 250, 0.2), rgba(233, 236, 239, 0.9)) !important;
537
  border-radius: 8px !important;
538
  padding: 12px !important;
539
  margin-top: 10px !important;
540
  font-size: 12px !important;
541
  color: #495057 !important;
542
- border: 2px solid rgba(187, 109, 237, 0.2) !important;
543
  backdrop-filter: blur(5px) !important;
544
  }
545
 
546
  .metadata-box {
547
- background: linear-gradient(135deg, rgba(248, 249, 250, 0.2), rgba(233, 236, 239, 0.9)) !important;
548
  border-radius: 8px !important;
549
  padding: 15px !important;
550
  margin-top: 15px !important;
551
  font-family: 'Courier New', monospace !important;
552
  font-size: 12px !important;
553
  color: #495057 !important;
554
- border: 2px solid rgba(187, 109, 237, 0.2) !important;
555
  backdrop-filter: blur(5px) !important;
556
  white-space: pre-wrap !important;
557
  overflow-y: auto !important;
@@ -571,16 +618,17 @@ css = """
571
 
572
  # ===== 创建UI =====
573
  def create_interface():
574
- with gr.Blocks(css=css, title="Adult NSFW AI Image Generator") as interface:
575
  with gr.Column(elem_classes=["main-content"]):
576
- gr.HTML('<div class="title">Adult NSFW AI Image Generator</div>')
 
577
  gr.HTML('<div class="warning-box">⚠️ 18+ CONTENT WARNING ⚠️</div>')
578
 
579
  with gr.Row():
580
  with gr.Column(scale=2):
581
  prompt_input = gr.Textbox(
582
- label="Detailed Prompt",
583
- placeholder="Enter your detailed prompt here...",
584
  lines=15,
585
  elem_classes=["prompt-box"]
586
  )
@@ -597,7 +645,7 @@ def create_interface():
597
  style_input = gr.Radio(
598
  label="Style Preset",
599
  choices=list(STYLE_KEYWORDS.keys()),
600
- value="Realistic"
601
  )
602
 
603
  with gr.Group(elem_classes=["controls-section"]):
@@ -612,8 +660,9 @@ def create_interface():
612
  label="Width",
613
  minimum=512,
614
  maximum=2048,
615
- value=1024,
616
- step=64
 
617
  )
618
 
619
  with gr.Group(elem_classes=["controls-section"]):
@@ -621,8 +670,9 @@ def create_interface():
621
  label="Height",
622
  minimum=512,
623
  maximum=2048,
624
- value=1024,
625
- step=64
 
626
  )
627
 
628
  with gr.Group(elem_classes=["controls-section"]):
@@ -630,16 +680,18 @@ def create_interface():
630
  label="Steps",
631
  minimum=10,
632
  maximum=50,
633
- value=25,
634
- step=1
 
635
  )
636
 
637
  cfg_input = gr.Slider(
638
  label="CFG Scale",
639
  minimum=1.0,
640
  maximum=15.0,
641
- value=7.0,
642
- step=0.1
 
643
  )
644
 
645
  generate_button = gr.Button(
@@ -721,21 +773,26 @@ def create_interface():
721
  ],
722
  show_progress=True
723
  )
724
-
725
- return interface
726
 
727
  # ===== 启动应用 =====
728
  if __name__ == "__main__":
729
  print("\n" + "="*50)
730
- print("🚀 Starting NSFW Image Generator")
731
  print("="*50)
732
- print(f"📦 Model: {FIXED_MODEL}")
 
733
  print(f"🖥️ Device: {'CUDA' if torch.cuda.is_available() else 'CPU'}")
734
  print(f"⚡ ZeroGPU: {'Enabled' if SPACES_AVAILABLE else 'Disabled'}")
735
  print(f"📝 Compel: {'Available' if COMPEL_AVAILABLE else 'Not Available'}")
736
- print(f"🎨 LoRA: detail-tweaker-lora (scale: {LORA_CONFIGS[0].get('scale', 0.8)})")
 
737
  print("="*50 + "\n")
738
 
 
 
 
739
  app = create_interface()
740
  app.queue(max_size=10, default_concurrency_limit=2)
741
 
 
29
  print("⚠️ Compel not available - using standard prompt processing")
30
 
31
  # ===== 优化后的配置 =====
32
+ # Kageillustrious风格核心关键词 - 使用Danbooru标签风格
33
  STYLE_KEYWORDS = {
34
+ "None": {
35
+ "prefix": "",
36
+ "suffix": ""
37
+ },
38
+ "Standard Quality": {
39
+ "prefix": "masterpiece, best quality, amazing quality, very aesthetic, absurdres",
40
+ "suffix": ""
41
+ },
42
+ "High Detail": {
43
+ "prefix": "masterpiece, best quality, amazing quality, very aesthetic, high resolution, ultra-detailed, absurdres, newest, colorful, rim light, backlit, highest detailed",
44
+ "suffix": ""
45
+ },
46
  "Realistic": {
47
+ "prefix": "masterpiece, best quality, amazing quality, very aesthetic, absurdres, (photorealistic:1.3), (realistic:1.4), detailed skin texture, cinematic lighting",
48
+ "suffix": "sharp focus, detailed anatomy, realistic proportions, detailed face, natural pose, expressive eyes, 8k resolution"
49
  },
50
  "Anime": {
51
+ "prefix": "masterpiece, best quality, amazing quality, very aesthetic, absurdres, anime style, vibrant colors, detailed anime",
52
+ "suffix": "cel shading, clean linework, vibrant anime colors, detailed anime eyes, smooth anime skin"
 
 
 
 
53
  },
54
+ "Artistic": {
55
+ "prefix": "masterpiece, best quality, amazing quality, very aesthetic, absurdres, artistic, illustration, detailed artwork",
56
+ "suffix": "vibrant colors, expressive, detailed composition, artistic rendering"
57
  }
58
  }
59
 
60
+ # 通用质量增强词
61
+ QUALITY_TAGS = "very awa"
62
 
63
+ # 修改为Kageillustrious模型 - 使用from_single_file加载
64
+ FIXED_MODEL_REPO = "PutiLeslie/kageillustrious_v60NLXLVersion"
65
+ FIXED_MODEL_FILE = "kageillustrious_v60NLXLVersion.safetensors"
66
 
67
+ # LoRA 配置 - 保留原有的LoRA(可能需要测试兼容性)
68
  LORA_CONFIGS = [
69
  {
70
+ "repo_id": "artificialguybr/LogoRedmond-LogoLoraForSDXL-V2",
71
+ "weight_name": "LogoRedAF.safetensors",
72
+ "adapter_name": "logo_lora",
73
  "scale": 0.8
74
  }
75
  ]
 
84
  model_loaded = False
85
 
86
  def initialize_model():
87
+ """优化的模型初始化 - 使用from_single_file加载Kageillustrious"""
88
  global pipeline, compel_processor, device, model_loaded
89
 
90
  if model_loaded and pipeline is not None:
 
95
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
96
  print(f"🖥️ Using device: {device}")
97
 
98
+ print(f"📦 Loading Kageillustrious model from: {FIXED_MODEL_REPO}")
99
+
100
+ # 使用from_single_file加载单个safetensors文件
101
+ from huggingface_hub import hf_hub_download
102
+
103
+ # 下载模型文件
104
+ model_path = hf_hub_download(
105
+ repo_id=FIXED_MODEL_REPO,
106
+ filename=FIXED_MODEL_FILE
107
+ )
108
 
109
+ print(f"📥 Model downloaded to: {model_path}")
110
+
111
+ # 使用from_single_file加载
112
+ pipeline = StableDiffusionXLPipeline.from_single_file(
113
+ model_path,
114
  torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32,
 
115
  use_safetensors=True,
116
  safety_checker=None,
117
  requires_safety_checker=False
118
  )
119
 
120
+ # 优化调度器 - 使用Euler适合Illustrious系列
121
  pipeline.scheduler = EulerDiscreteScheduler.from_config(
122
  pipeline.scheduler.config,
123
  timestep_spacing="trailing"
124
  )
125
 
 
126
  pipeline = pipeline.to(device)
127
 
128
  # 加载 LoRA
 
132
 
133
  for lora_config in LORA_CONFIGS:
134
  try:
 
135
  pipeline.load_lora_weights(
136
  lora_config["repo_id"],
137
  weight_name=lora_config["weight_name"],
138
  adapter_name=lora_config["adapter_name"]
139
  )
 
 
 
 
 
140
  adapter_names.append(lora_config["adapter_name"])
141
  adapter_scales.append(lora_config.get("scale", 0.8))
142
+ print(f"✅ LoRA loaded: {lora_config['adapter_name']} (scale: {lora_config.get('scale', 0.8)})")
143
  except Exception as lora_error:
144
+ print(f"⚠️ Failed to load LoRA {lora_config['adapter_name']}: {lora_error}")
 
145
 
146
  # 设置 LoRA 强度
147
  if adapter_names:
148
  try:
149
  pipeline.set_adapters(adapter_names, adapter_weights=adapter_scales)
150
  print(f"✅ LoRA adapters activated with scales: {adapter_scales}")
 
 
 
151
  except Exception as e:
152
  print(f"⚠️ Failed to set adapter scales: {e}")
153
 
154
+ # GPU优化 - 适配ZeroGPU环境
155
  if torch.cuda.is_available():
156
  try:
157
+ # VAE优化
158
  pipeline.enable_vae_slicing()
159
  pipeline.enable_vae_tiling()
160
 
161
+ # 尝试启用xformers
162
  try:
163
  pipeline.enable_xformers_memory_efficient_attention()
164
  print("✅ xFormers enabled")
165
  except:
166
  print("⚠️ xFormers not available, using default attention")
167
 
168
+ # 不使用torch.compile,因为它在ZeroGPU环境中不稳定
169
  print("ℹ️ Skipping torch.compile for ZeroGPU compatibility")
170
 
171
  except Exception as opt_error:
172
  print(f"⚠️ Optimization warning: {opt_error}")
173
 
174
+ # 初始化Compel用于长提示词
175
  if COMPEL_AVAILABLE:
176
  try:
177
  compel_processor = Compel(
 
186
  print(f"⚠️ Compel initialization failed: {compel_error}")
187
  compel_processor = None
188
 
 
 
 
 
 
 
189
  model_loaded = True
190
+ print("✅ Kageillustrious model initialization complete")
191
  return True
192
 
193
  except Exception as e:
 
197
  return False
198
 
199
  def enhance_prompt(prompt: str, style: str) -> str:
200
+ """优化的提示词增强 - 适配Kageillustrious的Danbooru标签风格"""
201
  if not prompt or prompt.strip() == "":
202
  return ""
203
 
204
+ # 获取风格关键词
205
  style_config = STYLE_KEYWORDS.get(style, STYLE_KEYWORDS["None"])
206
+
207
+ # 组合顺序:风格前缀 → 用户提示词 → 风格后缀 → 质量标签
208
  parts = []
209
 
210
  if style_config["prefix"]:
 
226
  return enhanced
227
 
228
  def build_negative_prompt(style: str, custom_negative: str = "") -> str:
229
+ """根据风格构建负面提示词 - 适配Illustrious系列"""
230
+ # Illustrious系列推荐的负面提示词
231
+ base_negative = "lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry"
232
 
233
+ # 风格特定的负面词
234
  style_negatives = {
235
+ "Realistic": ", (cartoon:1.3), (anime:1.3), (3d render:1.2), (illustration:1.2)",
236
+ "Anime": ", (realistic:1.3), (photorealistic:1.3), (photo:1.2)",
237
+ "Artistic": ", (photo:1.2), (photorealistic:1.2)"
 
238
  }
239
 
240
  negative = base_negative
241
  if style in style_negatives:
242
  negative += style_negatives[style]
243
 
244
+ # 添加用户自定义负面词
245
  if custom_negative.strip():
246
  negative += f", {custom_negative.strip()}"
247
 
 
253
  return None, None
254
 
255
  try:
256
+ # Compel会自动处理超过77 tokens的提示词
257
  conditioning, pooled = compel_processor([prompt, negative_prompt])
258
  print("✅ Long prompt processed with Compel")
259
  return conditioning, pooled
 
270
  def create_metadata_content(prompt, enhanced_prompt, seed, steps, cfg_scale, width, height, style):
271
  """创建元数据"""
272
  timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
273
+
274
+ # 获取 LoRA 信息
275
  lora_info = ", ".join([f"{lora['adapter_name']}({lora.get('scale', 1.0)})" for lora in LORA_CONFIGS])
276
 
277
  return f"""Generated Image Metadata
278
  ======================
279
+ Model: Kageillustrious v6.0NL XL
280
  Timestamp: {timestamp}
281
  Original Prompt: {prompt}
282
  Enhanced Prompt: {enhanced_prompt}
 
285
  CFG Scale: {cfg_scale}
286
  Dimensions: {width}x{height}
287
  Style: {style}
288
+ LoRA: {lora_info if lora_info else "None"}
289
  """
290
 
291
  def cleanup_pipeline():
292
+ """清理 pipeline 状态,防止污染"""
293
  global pipeline
294
 
295
  if pipeline is None:
296
  return
297
 
298
  try:
299
+ # 清理 CUDA 缓存
300
  if torch.cuda.is_available():
301
  torch.cuda.empty_cache()
302
  torch.cuda.ipc_collect()
303
 
304
+ # 清理 pipeline 的内部缓存
305
  if hasattr(pipeline, 'unet'):
306
+ # 清空 UNet 的注意力缓存
307
  if hasattr(pipeline.unet, 'set_attn_processor'):
308
  try:
309
  from diffusers.models.attention_processor import AttnProcessor
 
311
  except:
312
  pass
313
 
314
+ # 清理 VAE 缓存
315
  if hasattr(pipeline, 'vae'):
316
  pipeline.vae.to('cpu')
317
  pipeline.vae.to(device)
 
323
 
324
  @apply_spaces_decorator
325
  def generate_image(prompt: str, style: str, negative_prompt: str = "",
326
+ steps: int = 20, cfg_scale: float = 6.0,
327
+ seed: int = -1, width: int = 896, height: int = 1152,
328
  progress=gr.Progress()):
329
+ """图像生成主函数 - 使用Kageillustrious推荐参数"""
330
 
331
+ # 验证输入
332
  if not prompt or prompt.strip() == "":
333
  return None, "", "❌ Please enter a prompt"
334
 
335
  progress(0.05, desc="Initializing...")
336
 
337
+ # 初始化模型
338
  if not initialize_model():
339
  return None, "", "❌ Failed to load model"
340
 
341
+ # 清理之前的状态
342
  cleanup_pipeline()
343
 
344
  progress(0.1, desc="Processing prompt...")
345
 
346
  try:
347
+ # 处理seed
348
  if seed == -1:
349
  seed = random.randint(0, np.iinfo(np.int32).max)
350
 
351
+ # 重要:为每次生成创建新的 generator,避免状态污染
352
  generator = torch.Generator(device).manual_seed(seed)
353
 
354
+ # 增强提示词
355
  enhanced_prompt = enhance_prompt(prompt, style)
356
+
357
+ # 构建负面提示词
358
  final_negative = build_negative_prompt(style, negative_prompt)
359
 
360
  print(f"🔧 Generation params: seed={seed}, steps={steps}, cfg={cfg_scale}, size={width}x{height}")
 
362
 
363
  progress(0.2, desc="Generating image...")
364
 
365
+ # 检查提示词长度并决定是否使用Compel
366
  prompt_length = len(enhanced_prompt.split())
367
  use_compel = prompt_length > 50 and compel_processor is not None
368
 
 
371
  conditioning, pooled = process_with_compel(enhanced_prompt, final_negative)
372
 
373
  if conditioning is not None:
374
+ # 使用embeddings生成
375
  result = pipeline(
376
  prompt_embeds=conditioning[0:1],
377
  pooled_prompt_embeds=pooled[0:1],
 
385
  output_type="pil"
386
  ).images[0]
387
  else:
388
+ # Compel失败,回退到普通模式
389
  print("⚠️ Falling back to standard generation")
390
  result = pipeline(
391
  prompt=enhanced_prompt,
 
398
  output_type="pil"
399
  ).images[0]
400
  else:
401
+ # 标准生成
402
  print(f"📝 Standard generation ({prompt_length} words)")
403
  result = pipeline(
404
  prompt=enhanced_prompt,
 
413
 
414
  progress(0.95, desc="Finalizing...")
415
 
416
+ # 确保结果是PIL Image
417
  if not isinstance(result, Image.Image):
418
  if isinstance(result, np.ndarray):
419
  if result.dtype != np.uint8:
420
  result = (result * 255).astype(np.uint8)
421
  result = Image.fromarray(result)
422
 
423
+ # 创建元数据
424
  metadata = create_metadata_content(
425
  prompt, enhanced_prompt, seed, steps, cfg_scale,
426
  width, height, style
 
428
 
429
  generation_info = f"Style: {style} | Seed: {seed} | Size: {width}×{height} | Steps: {steps} | CFG: {cfg_scale}"
430
 
431
+ # 生成后立即清理
432
  if torch.cuda.is_available():
433
  torch.cuda.empty_cache()
434
 
 
442
  print(f"❌ Generation error: {error_msg}")
443
  print(traceback.format_exc())
444
 
445
+ # 错误后也要清理
446
  try:
447
  cleanup_pipeline()
448
  except:
 
456
  max-width: 100% !important;
457
  margin: 0 !important;
458
  padding: 0 !important;
459
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
460
  min-height: 100vh !important;
461
  font-family: 'Segoe UI', Arial, sans-serif !important;
462
  }
463
 
464
  .main-content {
465
+ background: rgba(255, 255, 255, 0.95) !important;
466
  border-radius: 20px !important;
467
  padding: 20px !important;
468
  margin: 15px !important;
469
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2) !important;
470
  min-height: calc(100vh - 30px) !important;
471
  color: #3e3e3e !important;
472
  backdrop-filter: blur(10px) !important;
 
474
 
475
  .title {
476
  text-align: center !important;
477
+ background: linear-gradient(45deg, #667eea, #764ba2) !important;
478
  -webkit-background-clip: text !important;
479
  -webkit-text-fill-color: transparent !important;
480
  background-clip: text !important;
 
484
  }
485
 
486
  .warning-box {
487
+ background: linear-gradient(45deg, #667eea, #764ba2) !important;
488
  color: white !important;
489
  padding: 8px !important;
490
  border-radius: 8px !important;
 
494
  font-size: 14px !important;
495
  }
496
 
497
+ .model-info {
498
+ background: linear-gradient(135deg, rgba(102, 126, 234, 0.1), rgba(118, 75, 162, 0.1)) !important;
499
+ color: #764ba2 !important;
500
+ padding: 10px !important;
501
+ border-radius: 8px !important;
502
+ margin-bottom: 15px !important;
503
+ text-align: center !important;
504
+ font-weight: 600 !important;
505
+ font-size: 13px !important;
506
+ border: 2px solid rgba(118, 75, 162, 0.3) !important;
507
+ }
508
+
509
  .prompt-box textarea, .prompt-box input {
510
  border-radius: 10px !important;
511
+ border: 2px solid #667eea !important;
512
  padding: 15px !important;
513
  font-size: 18px !important;
514
  background: linear-gradient(135deg, rgba(245, 243, 255, 0.9), rgba(237, 233, 254, 0.9)) !important;
 
516
  }
517
 
518
  .prompt-box textarea:focus, .prompt-box input:focus {
519
+ border-color: #764ba2 !important;
520
+ box-shadow: 0 0 15px rgba(118, 75, 162, 0.3) !important;
521
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 249, 250, 0.95)) !important;
522
  }
523
 
 
526
  border-radius: 12px !important;
527
  padding: 15px !important;
528
  margin-bottom: 8px !important;
529
+ border: 2px solid rgba(102, 126, 234, 0.3) !important;
530
  backdrop-filter: blur(5px) !important;
531
  }
532
 
 
537
  }
538
 
539
  .controls-section input[type="radio"] {
540
+ accent-color: #667eea !important;
541
  }
542
 
543
  .controls-section input[type="number"],
544
  .controls-section input[type="range"] {
545
  background: rgba(255, 255, 255, 0.9) !important;
546
+ border: 1px solid #667eea !important;
547
  border-radius: 6px !important;
548
  padding: 8px !important;
549
  color: #2d2d2d !important;
550
  }
551
 
552
  .generate-btn {
553
+ background: linear-gradient(45deg, #667eea, #764ba2) !important;
554
  color: white !important;
555
  border: none !important;
556
  padding: 15px 25px !important;
 
566
 
567
  .generate-btn:hover {
568
  transform: translateY(-2px) !important;
569
+ box-shadow: 0 8px 25px rgba(102, 126, 234, 0.5) !important;
570
  }
571
 
572
  .image-output {
 
574
  overflow: hidden !important;
575
  max-width: 100% !important;
576
  max-height: 70vh !important;
577
+ border: 3px solid #764ba2 !important;
578
  box-shadow: 0 8px 20px rgba(0,0,0,0.15) !important;
579
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(248, 249, 250, 0.9)) !important;
580
  }
581
 
582
  .image-info {
583
+ background: linear-gradient(135deg, rgba(248, 249, 250, 0.9), rgba(233, 236, 239, 0.9)) !important;
584
  border-radius: 8px !important;
585
  padding: 12px !important;
586
  margin-top: 10px !important;
587
  font-size: 12px !important;
588
  color: #495057 !important;
589
+ border: 2px solid rgba(102, 126, 234, 0.2) !important;
590
  backdrop-filter: blur(5px) !important;
591
  }
592
 
593
  .metadata-box {
594
+ background: linear-gradient(135deg, rgba(248, 249, 250, 0.9), rgba(233, 236, 239, 0.9)) !important;
595
  border-radius: 8px !important;
596
  padding: 15px !important;
597
  margin-top: 15px !important;
598
  font-family: 'Courier New', monospace !important;
599
  font-size: 12px !important;
600
  color: #495057 !important;
601
+ border: 2px solid rgba(102, 126, 234, 0.2) !important;
602
  backdrop-filter: blur(5px) !important;
603
  white-space: pre-wrap !important;
604
  overflow-y: auto !important;
 
618
 
619
  # ===== 创建UI =====
620
  def create_interface():
621
+ with gr.Blocks(css=css, title="Kageillustrious AI Image Generator") as interface:
622
  with gr.Column(elem_classes=["main-content"]):
623
+ gr.HTML('<div class="title">🎨 Kageillustrious AI Image Generator</div>')
624
+ gr.HTML('<div class="model-info">📦 Model: Kageillustrious v6.0NL XL (Illustrious-based SDXL)</div>')
625
  gr.HTML('<div class="warning-box">⚠️ 18+ CONTENT WARNING ⚠️</div>')
626
 
627
  with gr.Row():
628
  with gr.Column(scale=2):
629
  prompt_input = gr.Textbox(
630
+ label="Detailed Prompt (Use Danbooru tags style)",
631
+ placeholder="1girl, solo, long hair, blue eyes, detailed face, beautiful...",
632
  lines=15,
633
  elem_classes=["prompt-box"]
634
  )
 
645
  style_input = gr.Radio(
646
  label="Style Preset",
647
  choices=list(STYLE_KEYWORDS.keys()),
648
+ value="Standard Quality"
649
  )
650
 
651
  with gr.Group(elem_classes=["controls-section"]):
 
660
  label="Width",
661
  minimum=512,
662
  maximum=2048,
663
+ value=896,
664
+ step=64,
665
+ info="Recommended: 896"
666
  )
667
 
668
  with gr.Group(elem_classes=["controls-section"]):
 
670
  label="Height",
671
  minimum=512,
672
  maximum=2048,
673
+ value=1152,
674
+ step=64,
675
+ info="Recommended: 1152"
676
  )
677
 
678
  with gr.Group(elem_classes=["controls-section"]):
 
680
  label="Steps",
681
  minimum=10,
682
  maximum=50,
683
+ value=20,
684
+ step=1,
685
+ info="Recommended: 20"
686
  )
687
 
688
  cfg_input = gr.Slider(
689
  label="CFG Scale",
690
  minimum=1.0,
691
  maximum=15.0,
692
+ value=6.0,
693
+ step=0.1,
694
+ info="Recommended: 6.0"
695
  )
696
 
697
  generate_button = gr.Button(
 
773
  ],
774
  show_progress=True
775
  )
776
+
777
+ return interface
778
 
779
  # ===== 启动应用 =====
780
  if __name__ == "__main__":
781
  print("\n" + "="*50)
782
+ print("🚀 Starting Kageillustrious Image Generator")
783
  print("="*50)
784
+ print(f"📦 Model: {FIXED_MODEL_REPO}")
785
+ print(f"📄 Model File: {FIXED_MODEL_FILE}")
786
  print(f"🖥️ Device: {'CUDA' if torch.cuda.is_available() else 'CPU'}")
787
  print(f"⚡ ZeroGPU: {'Enabled' if SPACES_AVAILABLE else 'Disabled'}")
788
  print(f"📝 Compel: {'Available' if COMPEL_AVAILABLE else 'Not Available'}")
789
+ if LORA_CONFIGS:
790
+ print(f"🎨 LoRA: LogoRedmond-LogoLoraForSDXL-V2 (scale: {LORA_CONFIGS[0].get('scale', 0.8)})")
791
  print("="*50 + "\n")
792
 
793
+ # 不预加载模型,让ZeroGPU按需分配
794
+ # 这样可以避免GPU分配冲突
795
+
796
  app = create_interface()
797
  app.queue(max_size=10, default_concurrency_limit=2)
798