harumaa commited on
Commit
ccb13e6
ยท
verified ยท
1 Parent(s): 2199812

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +48 -36
app.py CHANGED
@@ -10,7 +10,6 @@ from PIL import Image
10
  from pathlib import Path
11
  from diffusers import StableDiffusionXLPipeline, EulerAncestralDiscreteScheduler
12
  from huggingface_hub import hf_hub_download
13
- from transformers import CLIPVisionModelWithProjection
14
  from compel import Compel, ReturnedEmbeddingsType
15
 
16
  # --- Configuration ---
@@ -50,6 +49,11 @@ UPSCALER_URL = os.environ.get("UPSCALER_URL", "https://huggingface.co/spaces/har
50
  _char_cache = {}
51
 
52
  # --- Helper Functions ---
 
 
 
 
 
53
  def auto_res(input_image):
54
  if input_image is None:
55
  return gr.update(value=1024), gr.update(value=1024), gr.update(value="No image โ€” using default 1024 x 1024"), gr.update(value=None)
@@ -93,13 +97,6 @@ def encode_prompts(pipe, prompt, neg):
93
  # --- Preloading Logic ---
94
  def download_and_load_all():
95
  print("๐Ÿš€ [Startup] Initializing Character Studio pre-load...")
96
-
97
- print("โš™๏ธ [Pipeline] Loading ViT-H Image Encoder for IP-Adapter...")
98
- image_encoder = CLIPVisionModelWithProjection.from_pretrained(
99
- "h94/IP-Adapter",
100
- subfolder="models/image_encoder",
101
- torch_dtype=torch.float16
102
- )
103
 
104
  for model_name in CIVITAI_MODELS.keys():
105
  try:
@@ -116,19 +113,19 @@ def download_and_load_all():
116
  )
117
 
118
  if model_name not in _char_cache:
119
- print(f"โš™๏ธ [Pipeline] Building {model_name} with IP-Adapter...")
120
  pipe = StableDiffusionXLPipeline.from_single_file(
121
  str(dest),
122
  torch_dtype=torch.float16,
123
- use_safetensors=True,
124
- image_encoder=image_encoder
125
  )
126
  pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config)
127
 
 
128
  pipe.load_ip_adapter(
129
  "h94/IP-Adapter",
130
  subfolder="sdxl_models",
131
- weight_name="ip-adapter-plus_sdxl_vit-h.safetensors"
132
  )
133
  _char_cache[model_name] = pipe
134
 
@@ -140,6 +137,10 @@ def download_and_load_all():
140
  # --- Inference ---
141
  @spaces.GPU(duration=60)
142
  def generate_gpu(model_name, ref_img, prompt, neg, seed, randomize, w, h, ip_scale, cfg, steps, progress=gr.Progress(track_tqdm=False)):
 
 
 
 
143
  if randomize: seed = random.randint(0, MAX_SEED)
144
  yield None, seed, gr.update(value="Waiting for GPU..."), gr.update(visible=False, value=None)
145
 
@@ -148,25 +149,34 @@ def generate_gpu(model_name, ref_img, prompt, neg, seed, randomize, w, h, ip_sca
148
  yield None, seed, gr.update(value=f"Model {model_name} not loaded."), gr.update(visible=False)
149
  return
150
 
151
- # 1. FIX THE VAE UPCAST BUG PERMANENTLY
152
- pipe.to("cuda")
153
- pipe.vae.to(dtype=torch.float16, non_blocking=True)
 
 
 
 
154
 
155
- pipe.set_ip_adapter_scale(float(ip_scale))
156
- generator = torch.Generator("cuda").manual_seed(seed)
157
-
158
- yield None, seed, gr.update(value=f"Generating {w}x{h}..."), gr.update(visible=False)
159
-
160
- # 2. AUTO-ENHANCE PROMPT FOR ILLUSTRIOUS/REALMIX
161
- # This prevents the model from generating random noise when given short prompts like "running"
162
- final_prompt = prompt
163
- if "masterpiece" not in final_prompt.lower():
164
- final_prompt = f"{prompt}, 1girl, solo, masterpiece, best quality, very aesthetic, absurdres"
165
 
166
- def cb(p, i, t, kw): progress((i+1)/steps, desc=f"Step {i+1}/{steps}"); return kw
 
 
167
 
168
- try:
169
- cond, pool, ncond, npool = encode_prompts(pipe, final_prompt, neg)
 
 
 
 
 
 
170
  image = pipe(
171
  prompt_embeds=cond,
172
  pooled_prompt_embeds=pool,
@@ -181,12 +191,14 @@ def generate_gpu(model_name, ref_img, prompt, neg, seed, randomize, w, h, ip_sca
181
  callback_on_step_end=cb
182
  ).images[0]
183
 
184
- except RuntimeError as e:
185
- torch.cuda.empty_cache()
186
- yield None, seed, gr.update(value=f"Error: {str(e)[:120]}"), gr.update(visible=False)
187
- return
188
 
189
- yield image, seed, gr.update(value="Done!"), gr.update(visible=False)
 
 
 
 
 
190
 
191
  # --- UI Setup ---
192
  def build_css(accent="#7c3aed"):
@@ -229,7 +241,7 @@ with gr.Blocks(title="Character Lab", css=build_css(DEFAULT_ACCENT), theme=gr.th
229
  <a href="{UPSCALER_URL}" target="_blank">Upscaler</a>
230
  </div>
231
  ''')
232
- gr.Markdown("# Character Lab\n**Maintain character consistency using IP-Adapter Plus.**")
233
 
234
  gr.HTML("<p class='lbl'>Select Model</p>")
235
  with gr.Row():
@@ -262,8 +274,8 @@ with gr.Blocks(title="Character Lab", css=build_css(DEFAULT_ACCENT), theme=gr.th
262
  with gr.Accordion("Advanced Settings", open=False):
263
  ch_neg = gr.Text(label="Negative Prompt", max_lines=2, value="lowres, bad anatomy, bad hands, text, watermark, worst quality")
264
 
265
- # 3. LOWERED DEFAULT IP SCALE TO PREVENT DEEP-FRYING ANIME MODELS
266
- ch_ip_scale = gr.Slider(label="Consistency Strength (IP-Scale)", minimum=0.1, maximum=1.2, step=0.05, value=0.55)
267
 
268
  with gr.Row():
269
  ch_seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
 
10
  from pathlib import Path
11
  from diffusers import StableDiffusionXLPipeline, EulerAncestralDiscreteScheduler
12
  from huggingface_hub import hf_hub_download
 
13
  from compel import Compel, ReturnedEmbeddingsType
14
 
15
  # --- Configuration ---
 
49
  _char_cache = {}
50
 
51
  # --- Helper Functions ---
52
+ def fix_vae_dtype(vae, dtype=torch.float16):
53
+ vae = vae.to(dtype=dtype)
54
+ vae.config.force_upcast = False
55
+ return vae
56
+
57
  def auto_res(input_image):
58
  if input_image is None:
59
  return gr.update(value=1024), gr.update(value=1024), gr.update(value="No image โ€” using default 1024 x 1024"), gr.update(value=None)
 
97
  # --- Preloading Logic ---
98
  def download_and_load_all():
99
  print("๐Ÿš€ [Startup] Initializing Character Studio pre-load...")
 
 
 
 
 
 
 
100
 
101
  for model_name in CIVITAI_MODELS.keys():
102
  try:
 
113
  )
114
 
115
  if model_name not in _char_cache:
116
+ print(f"โš™๏ธ [Pipeline] Building {model_name} with Standard IP-Adapter...")
117
  pipe = StableDiffusionXLPipeline.from_single_file(
118
  str(dest),
119
  torch_dtype=torch.float16,
120
+ use_safetensors=True
 
121
  )
122
  pipe.scheduler = EulerAncestralDiscreteScheduler.from_config(pipe.scheduler.config)
123
 
124
+ # SWITCH TO STANDARD IP-ADAPTER: Much better for Anime styles
125
  pipe.load_ip_adapter(
126
  "h94/IP-Adapter",
127
  subfolder="sdxl_models",
128
+ weight_name="ip-adapter_sdxl.safetensors"
129
  )
130
  _char_cache[model_name] = pipe
131
 
 
137
  # --- Inference ---
138
  @spaces.GPU(duration=60)
139
  def generate_gpu(model_name, ref_img, prompt, neg, seed, randomize, w, h, ip_scale, cfg, steps, progress=gr.Progress(track_tqdm=False)):
140
+ if ref_img is None:
141
+ yield None, seed, gr.update(value="โš ๏ธ Error: Please upload a Character Reference image first!"), gr.update(visible=False)
142
+ return
143
+
144
  if randomize: seed = random.randint(0, MAX_SEED)
145
  yield None, seed, gr.update(value="Waiting for GPU..."), gr.update(visible=False, value=None)
146
 
 
149
  yield None, seed, gr.update(value=f"Model {model_name} not loaded."), gr.update(visible=False)
150
  return
151
 
152
+ try:
153
+ # 1. GPU Prep & VAE Lock (Fixes distorted colors)
154
+ pipe.to("cuda")
155
+ pipe.vae = fix_vae_dtype(pipe.vae)
156
+
157
+ # 2. Disable the SDXL Watermarker (Prevents anime deep-frying)
158
+ pipe.watermark = None
159
 
160
+ pipe.set_ip_adapter_scale(float(ip_scale))
161
+ generator = torch.Generator("cuda").manual_seed(seed)
162
+
163
+ # 3. Auto-enhance Prompt
164
+ final_prompt = prompt or ""
165
+ if "masterpiece" not in final_prompt.lower():
166
+ final_prompt = f"{final_prompt}, 1girl, solo, masterpiece, best quality, very aesthetic, absurdres"
 
 
 
167
 
168
+ # 4. Auto-enhance Negative Prompt
169
+ base_neg = "lowres, (bad), text, error, missing, extra, worst quality, jpeg artifacts, bad anatomy, watermark, unfinished, displeasing, oldest, early, signature, extra digits, fewer digits, bad hands"
170
+ final_neg = f"{neg}, {base_neg}" if neg else base_neg
171
 
172
+ yield None, seed, gr.update(value=f"Generating {w}x{h}..."), gr.update(visible=False)
173
+
174
+ def cb(p, i, t, kw):
175
+ progress((i+1)/steps, desc=f"Step {i+1}/{steps}")
176
+ return kw
177
+
178
+ cond, pool, ncond, npool = encode_prompts(pipe, final_prompt, final_neg)
179
+
180
  image = pipe(
181
  prompt_embeds=cond,
182
  pooled_prompt_embeds=pool,
 
191
  callback_on_step_end=cb
192
  ).images[0]
193
 
194
+ yield image, seed, gr.update(value="โœ… Done!"), gr.update(visible=True)
 
 
 
195
 
196
+ except Exception as e:
197
+ import traceback
198
+ traceback.print_exc()
199
+ torch.cuda.empty_cache()
200
+ yield None, seed, gr.update(value=f"โŒ Crash: {str(e)[:150]}"), gr.update(visible=False)
201
+
202
 
203
  # --- UI Setup ---
204
  def build_css(accent="#7c3aed"):
 
241
  <a href="{UPSCALER_URL}" target="_blank">Upscaler</a>
242
  </div>
243
  ''')
244
+ gr.Markdown("# Character Lab\n**Maintain character consistency using Standard IP-Adapter.**")
245
 
246
  gr.HTML("<p class='lbl'>Select Model</p>")
247
  with gr.Row():
 
274
  with gr.Accordion("Advanced Settings", open=False):
275
  ch_neg = gr.Text(label="Negative Prompt", max_lines=2, value="lowres, bad anatomy, bad hands, text, watermark, worst quality")
276
 
277
+ # Reset to a balanced default scale since Standard IP-Adapter is gentler
278
+ ch_ip_scale = gr.Slider(label="Consistency Strength (IP-Scale)", minimum=0.1, maximum=1.2, step=0.05, value=0.65)
279
 
280
  with gr.Row():
281
  ch_seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)