sabannna commited on
Commit
f5dfd8d
·
verified ·
1 Parent(s): 5ff3fe3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +236 -97
app.py CHANGED
@@ -16,7 +16,7 @@ from huggingface_hub import HfApi
16
  # Girdilerin kaydedileceği dataset
17
  INPUT_DATASET_ID = "tyndreus/image-edit-logs"
18
  # Çıktıların kaydedileceği dataset (Bunu oluşturduğunuzdan emin olun)
19
- OUTPUT_DATASET_ID = "tyndreus/output"
20
  # ---------------
21
 
22
  colors.steel_blue = colors.Color(
@@ -87,8 +87,6 @@ class SteelBlueTheme(Soft):
87
 
88
  steel_blue_theme = SteelBlueTheme()
89
 
90
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
91
-
92
  from diffusers import FlowMatchEulerDiscreteScheduler
93
  from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
94
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
@@ -100,137 +98,216 @@ device = "cuda" if torch.cuda.is_available() else "cpu"
100
  pipe = QwenImageEditPlusPipeline.from_pretrained(
101
  "Qwen/Qwen-Image-Edit-2509",
102
  transformer=QwenImageTransformer2DModel.from_pretrained(
103
- "linoyts/Qwen-Image-Edit-Rapid-AIO",
104
- subfolder='transformer',
105
  torch_dtype=dtype,
106
- device_map='cuda'
107
  ),
108
- torch_dtype=dtype
109
  ).to(device)
110
 
111
- pipe.load_lora_weights("autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime", weight_name="Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors", adapter_name="anime")
112
- pipe.load_lora_weights("dx8152/Qwen-Edit-2509-Multiple-angles", weight_name="镜头转换.safetensors", adapter_name="multiple-angles")
113
- pipe.load_lora_weights("dx8152/Qwen-Image-Edit-2509-Light_restoration", weight_name="移除光影.safetensors", adapter_name="light-restoration")
114
- pipe.load_lora_weights("dx8152/Qwen-Image-Edit-2509-Relight", weight_name="Qwen-Edit-Relight.safetensors", adapter_name="relight")
115
- pipe.load_lora_weights("dx8152/Qwen-Edit-2509-Multi-Angle-Lighting", weight_name="多角度灯光-251116.safetensors", adapter_name="multi-angle-lighting")
116
- pipe.load_lora_weights("tlennon-ie/qwen-edit-skin", weight_name="qwen-edit-skin_1.1_000002750.safetensors", adapter_name="edit-skin")
117
- pipe.load_lora_weights("lovis93/next-scene-qwen-image-lora-2509", weight_name="next-scene_lora-v2-3000.safetensors", adapter_name="next-scene")
118
- pipe.load_lora_weights("vafipas663/Qwen-Edit-2509-Upscale-LoRA", weight_name="qwen-edit-enhance_64-v3_000001000.safetensors", adapter_name="upscale-image")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
 
120
  pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
 
121
  MAX_SEED = np.iinfo(np.int32).max
122
 
123
- def update_dimensions_on_upload(image):
124
- if image is None: return 1024, 1024
 
 
 
 
 
 
125
  original_width, original_height = image.size
126
  if original_width > original_height:
127
- new_width = 1024
128
  aspect_ratio = original_height / original_width
129
  new_height = int(new_width * aspect_ratio)
130
  else:
131
- new_height = 1024
132
  aspect_ratio = original_width / original_height
133
  new_width = int(new_height * aspect_ratio)
134
- new_width = (new_width // 8) * 8
135
- new_height = (new_height // 8) * 8
136
- return new_width, new_height
137
 
138
  # --- HUB'A YÜKLEME YAPAN ORTAK FONKSİYON ---
139
  def upload_image_to_hub(image, dataset_id, folder_prefix="images"):
140
  try:
141
- # Token kontrolü
142
  hf_token = os.environ.get("HF_TOKEN")
143
  if not hf_token:
144
- print(f"Fail")
145
  return
146
 
147
  api = HfApi(token=hf_token)
148
-
149
- # Dosya ismi oluşturma
150
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
151
  unique_id = str(uuid.uuid4())[:8]
152
  filename = f"{folder_prefix}_{timestamp}_{unique_id}.png"
153
-
154
- # Geçici olarak diske kaydet
155
  temp_path = f"/tmp/{filename}"
156
  image.save(temp_path)
157
-
158
- # Dataset'e yükle
159
  api.upload_file(
160
  path_or_fileobj=temp_path,
161
- path_in_repo=f"{folder_prefix}/{filename}",
162
  repo_id=dataset_id,
163
- repo_type="dataset"
164
  )
165
-
166
- # Geçici dosyayı sil
167
  os.remove(temp_path)
168
- print(f"Success")
169
-
170
  except Exception as e:
171
  print(f"Yükleme hatası ({dataset_id}): {e}")
172
  # -------------------------------------------
173
 
174
- @spaces.GPU(duration=30)
175
- def infer(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
176
  input_image,
177
- prompt,
 
 
178
  lora_adapter,
 
 
 
179
  seed,
180
  randomize_seed,
181
  guidance_scale,
182
  steps,
183
- progress=gr.Progress(track_tqdm=True)
184
  ):
185
  if input_image is None:
186
  raise gr.Error("Please upload an image to edit.")
187
 
188
- # 1. GİRDİ RESMİNİ KAYDET (INPUT)
189
  upload_image_to_hub(input_image, INPUT_DATASET_ID, folder_prefix="inputs")
190
 
191
- if lora_adapter == "Photo-to-Anime": pipe.set_adapters(["anime"], adapter_weights=[1.0])
192
- elif lora_adapter == "Multiple-Angles": pipe.set_adapters(["multiple-angles"], adapter_weights=[1.0])
193
- elif lora_adapter == "Light-Restoration": pipe.set_adapters(["light-restoration"], adapter_weights=[1.0])
194
- elif lora_adapter == "Relight": pipe.set_adapters(["relight"], adapter_weights=[1.0])
195
- elif lora_adapter == "Multi-Angle-Lighting": pipe.set_adapters(["multi-angle-lighting"], adapter_weights=[1.0])
196
- elif lora_adapter == "Edit-Skin": pipe.set_adapters(["edit-skin"], adapter_weights=[1.0])
197
- elif lora_adapter == "Next-Scene": pipe.set_adapters(["next-scene"], adapter_weights=[1.0])
198
- elif lora_adapter == "Upscale-Image": pipe.set_adapters(["upscale-image"], adapter_weights=[1.0])
199
-
200
- if randomize_seed: seed = random.randint(0, MAX_SEED)
201
 
202
- generator = torch.Generator(device=device).manual_seed(seed)
203
- negative_prompt = "worst quality, low quality, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, jpeg artifacts, signature, watermark, username, blurry"
 
 
 
 
 
 
 
 
 
 
 
 
204
 
205
  original_image = input_image.convert("RGB")
206
- width, height = update_dimensions_on_upload(original_image)
207
-
208
- result = pipe(
209
- image=original_image,
210
- prompt=prompt,
211
- negative_prompt=negative_prompt,
212
- height=height,
213
- width=width,
214
- num_inference_steps=steps,
215
- generator=generator,
216
- true_cfg_scale=guidance_scale,
217
- ).images[0]
218
-
219
- # 2. ÇIKTI RESMİNİ KAYDET (OUTPUT)
220
- # Burada 'generated' adında bir klasör ön eki ve OUTPUT_DATASET_ID kullanıyoruz
221
- upload_image_to_hub(result, OUTPUT_DATASET_ID, folder_prefix="generated")
222
-
223
- return result, seed
224
-
225
- @spaces.GPU(duration=30)
226
- def infer_example(input_image, prompt, lora_adapter):
227
- input_pil = input_image.convert("RGB")
228
- guidance_scale = 1.0
229
- steps = 4
230
- result, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps)
231
- return result, seed
232
-
233
- css="""
 
 
234
  #col-container {
235
  margin: 0 auto;
236
  max-width: 960px;
@@ -246,28 +323,90 @@ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
246
  with gr.Row(equal_height=True):
247
  with gr.Column():
248
  input_image = gr.Image(label="Upload Image", type="pil", height=290)
249
- prompt = gr.Text(label="Edit Prompt", show_label=True, placeholder="e.g., transform into anime..")
250
- run_button = gr.Button("Edit Image", variant="primary")
251
 
252
- with gr.Column():
253
- output_image = gr.Image(label="Output Image", interactive=False, format="png", height=350)
 
 
 
254
  with gr.Row():
255
- lora_adapter = gr.Dropdown(
256
- label="Choose Editing Style",
257
- choices=["Photo-to-Anime", "Multiple-Angles", "Light-Restoration", "Multi-Angle-Lighting", "Upscale-Image", "Relight", "Next-Scene", "Edit-Skin"],
258
- value="Photo-to-Anime"
259
- )
260
- with gr.Accordion("Advanced Settings", open=False, visible=False):
261
- seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
262
- randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
264
  steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
265
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  run_button.click(
267
- fn=infer,
268
- inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps],
269
- outputs=[output_image, seed]
 
 
 
 
 
 
270
  )
271
 
272
  if __name__ == "__main__":
273
- demo.queue(max_size=30).launch(mcp_server=True, ssr_mode=False, show_error=True)
 
16
  # Girdilerin kaydedileceği dataset
17
  INPUT_DATASET_ID = "tyndreus/image-edit-logs"
18
  # Çıktıların kaydedileceği dataset (Bunu oluşturduğunuzdan emin olun)
19
+ OUTPUT_DATASET_ID = "tyndreus/output"
20
  # ---------------
21
 
22
  colors.steel_blue = colors.Color(
 
87
 
88
  steel_blue_theme = SteelBlueTheme()
89
 
 
 
90
  from diffusers import FlowMatchEulerDiscreteScheduler
91
  from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
92
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
 
98
  pipe = QwenImageEditPlusPipeline.from_pretrained(
99
  "Qwen/Qwen-Image-Edit-2509",
100
  transformer=QwenImageTransformer2DModel.from_pretrained(
101
+ "linoyts/Qwen-Image-Edit-Rapid-AIO",
102
+ subfolder="transformer",
103
  torch_dtype=dtype,
104
+ device_map="cuda" if torch.cuda.is_available() else None,
105
  ),
106
+ torch_dtype=dtype,
107
  ).to(device)
108
 
109
+ pipe.load_lora_weights("autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime",
110
+ weight_name="Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors",
111
+ adapter_name="anime")
112
+ pipe.load_lora_weights("dx8152/Qwen-Edit-2509-Multiple-angles",
113
+ weight_name="镜头转换.safetensors",
114
+ adapter_name="multiple-angles")
115
+ pipe.load_lora_weights("dx8152/Qwen-Image-Edit-2509-Light_restoration",
116
+ weight_name="移除光影.safetensors",
117
+ adapter_name="light-restoration")
118
+ pipe.load_lora_weights("dx8152/Qwen-Image-Edit-2509-Relight",
119
+ weight_name="Qwen-Edit-Relight.safetensors",
120
+ adapter_name="relight")
121
+ pipe.load_lora_weights("dx8152/Qwen-Edit-2509-Multi-Angle-Lighting",
122
+ weight_name="多角度灯光-251116.safetensors",
123
+ adapter_name="multi-angle-lighting")
124
+ pipe.load_lora_weights("tlennon-ie/qwen-edit-skin",
125
+ weight_name="qwen-edit-skin_1.1_000002750.safetensors",
126
+ adapter_name="edit-skin")
127
+ pipe.load_lora_weights("lovis93/next-scene-qwen-image-lora-2509",
128
+ weight_name="next-scene_lora-v2-3000.safetensors",
129
+ adapter_name="next-scene")
130
+ pipe.load_lora_weights("vafipas663/Qwen-Edit-2509-Upscale-LoRA",
131
+ weight_name="qwen-edit-enhance_64-v3_000001000.safetensors",
132
+ adapter_name="upscale-image")
133
 
134
  pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
135
+
136
  MAX_SEED = np.iinfo(np.int32).max
137
 
138
+ def _round8(x: int) -> int:
139
+ x = int(x)
140
+ return max(8, (x // 8) * 8)
141
+
142
+ def update_dimensions_on_upload(image: Image.Image, max_side: int = 1024):
143
+ """Keep aspect ratio; fit the long side to max_side; round down to multiple of 8."""
144
+ if image is None:
145
+ return 1024, 1024
146
  original_width, original_height = image.size
147
  if original_width > original_height:
148
+ new_width = max_side
149
  aspect_ratio = original_height / original_width
150
  new_height = int(new_width * aspect_ratio)
151
  else:
152
+ new_height = max_side
153
  aspect_ratio = original_width / original_height
154
  new_width = int(new_height * aspect_ratio)
155
+ return _round8(new_width), _round8(new_height)
 
 
156
 
157
  # --- HUB'A YÜKLEME YAPAN ORTAK FONKSİYON ---
158
  def upload_image_to_hub(image, dataset_id, folder_prefix="images"):
159
  try:
 
160
  hf_token = os.environ.get("HF_TOKEN")
161
  if not hf_token:
162
+ print("Fail")
163
  return
164
 
165
  api = HfApi(token=hf_token)
166
+
 
167
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
168
  unique_id = str(uuid.uuid4())[:8]
169
  filename = f"{folder_prefix}_{timestamp}_{unique_id}.png"
170
+
 
171
  temp_path = f"/tmp/{filename}"
172
  image.save(temp_path)
173
+
 
174
  api.upload_file(
175
  path_or_fileobj=temp_path,
176
+ path_in_repo=f"{folder_prefix}/{filename}",
177
  repo_id=dataset_id,
178
+ repo_type="dataset",
179
  )
180
+
 
181
  os.remove(temp_path)
182
+ print("Success")
183
+
184
  except Exception as e:
185
  print(f"Yükleme hatası ({dataset_id}): {e}")
186
  # -------------------------------------------
187
 
188
+ SIZE_PRESETS = [
189
+ "Auto (fit long side to 1024)",
190
+ "1024 x 1024 (Square)",
191
+ "1024 x 768 (Landscape)",
192
+ "768 x 1024 (Portrait)",
193
+ "512 x 512 (Fast)",
194
+ "Custom (use sliders)",
195
+ ]
196
+
197
+ def apply_size_preset(preset, image, cur_w, cur_h):
198
+ if preset == "Auto (fit long side to 1024)":
199
+ if image is None:
200
+ return 1024, 1024
201
+ img = image.convert("RGB")
202
+ w, h = update_dimensions_on_upload(img, max_side=1024)
203
+ return w, h
204
+ if preset == "1024 x 1024 (Square)":
205
+ return 1024, 1024
206
+ if preset == "1024 x 768 (Landscape)":
207
+ return 1024, 768
208
+ if preset == "768 x 1024 (Portrait)":
209
+ return 768, 1024
210
+ if preset == "512 x 512 (Fast)":
211
+ return 512, 512
212
+ # Custom: keep current slider values
213
+ return _round8(cur_w), _round8(cur_h)
214
+
215
+ def set_adapter(lora_adapter: str):
216
+ if lora_adapter == "Photo-to-Anime":
217
+ pipe.set_adapters(["anime"], adapter_weights=[1.0])
218
+ elif lora_adapter == "Multiple-Angles":
219
+ pipe.set_adapters(["multiple-angles"], adapter_weights=[1.0])
220
+ elif lora_adapter == "Light-Restoration":
221
+ pipe.set_adapters(["light-restoration"], adapter_weights=[1.0])
222
+ elif lora_adapter == "Relight":
223
+ pipe.set_adapters(["relight"], adapter_weights=[1.0])
224
+ elif lora_adapter == "Multi-Angle-Lighting":
225
+ pipe.set_adapters(["multi-angle-lighting"], adapter_weights=[1.0])
226
+ elif lora_adapter == "Edit-Skin":
227
+ pipe.set_adapters(["edit-skin"], adapter_weights=[1.0])
228
+ elif lora_adapter == "Next-Scene":
229
+ pipe.set_adapters(["next-scene"], adapter_weights=[1.0])
230
+ elif lora_adapter == "Upscale-Image":
231
+ pipe.set_adapters(["upscale-image"], adapter_weights=[1.0])
232
+
233
+ @spaces.GPU(duration=60)
234
+ def infer_6pack(
235
  input_image,
236
+ prompt1,
237
+ prompt2,
238
+ prompt3,
239
  lora_adapter,
240
+ size_preset,
241
+ width,
242
+ height,
243
  seed,
244
  randomize_seed,
245
  guidance_scale,
246
  steps,
247
+ progress=gr.Progress(track_tqdm=True),
248
  ):
249
  if input_image is None:
250
  raise gr.Error("Please upload an image to edit.")
251
 
252
+ # 1) Upload input
253
  upload_image_to_hub(input_image, INPUT_DATASET_ID, folder_prefix="inputs")
254
 
255
+ # Adapter
256
+ set_adapter(lora_adapter)
257
+
258
+ # Dimensions
259
+ width = _round8(width)
260
+ height = _round8(height)
261
+
262
+ # Prompts (3)
263
+ prompts = [prompt1, prompt2, prompt3]
 
264
 
265
+ # Seeds (2 per prompt => 6)
266
+ seeds = []
267
+ if randomize_seed:
268
+ for _ in range(6):
269
+ seeds.append(random.randint(0, MAX_SEED))
270
+ else:
271
+ base = int(seed)
272
+ for i in range(6):
273
+ seeds.append((base + i) % MAX_SEED)
274
+
275
+ negative_prompt = (
276
+ "worst quality, low quality, bad anatomy, bad hands, text, error, missing fingers, "
277
+ "extra digit, fewer digits, cropped, jpeg artifacts, signature, watermark, username, blurry"
278
+ )
279
 
280
  original_image = input_image.convert("RGB")
281
+
282
+ outputs = []
283
+ seed_idx = 0
284
+ for p_i, p in enumerate(prompts):
285
+ for v in range(2):
286
+ s = seeds[seed_idx]
287
+ seed_idx += 1
288
+
289
+ generator = torch.Generator(device=device).manual_seed(int(s))
290
+ result = pipe(
291
+ image=original_image,
292
+ prompt=p,
293
+ negative_prompt=negative_prompt,
294
+ height=height,
295
+ width=width,
296
+ num_inference_steps=int(steps),
297
+ generator=generator,
298
+ true_cfg_scale=float(guidance_scale),
299
+ ).images[0]
300
+
301
+ # 2) Upload each output
302
+ upload_image_to_hub(result, OUTPUT_DATASET_ID, folder_prefix="generated")
303
+
304
+ caption = f"prompt{p_i+1} var{v+1} | seed={s} | {width}x{height}"
305
+ outputs.append((result, caption))
306
+
307
+ seeds_text = "\n".join([f"{i+1}: {s}" for i, s in enumerate(seeds)])
308
+ return outputs, seeds_text
309
+
310
+ css = """
311
  #col-container {
312
  margin: 0 auto;
313
  max-width: 960px;
 
323
  with gr.Row(equal_height=True):
324
  with gr.Column():
325
  input_image = gr.Image(label="Upload Image", type="pil", height=290)
 
 
326
 
327
+ size_preset = gr.Dropdown(
328
+ label="Image Size Preset",
329
+ choices=SIZE_PRESETS,
330
+ value="Auto (fit long side to 1024)",
331
+ )
332
  with gr.Row():
333
+ width = gr.Slider(label="Width", minimum=256, maximum=2048, step=8, value=1024)
334
+ height = gr.Slider(label="Height", minimum=256, maximum=2048, step=8, value=1024)
335
+
336
+ prompt1 = gr.Text(
337
+ label="Prompt 1 (standing pose)",
338
+ placeholder="e.g., ...",
339
+ value="make this girl to another standing pose",
340
+ )
341
+ prompt2 = gr.Text(
342
+ label="Prompt 2 (sitting pose)",
343
+ placeholder="e.g., ...",
344
+ value="make this girl to another sitting pose",
345
+ )
346
+ prompt3 = gr.Text(
347
+ label="Prompt 3 (standing pose + hand sign)",
348
+ placeholder="e.g., ...",
349
+ value="make this girl to another standing pose with hand sign",
350
+ )
351
+
352
+ run_button = gr.Button("Generate 6 Images (3 prompts x 2 seeds)", variant="primary")
353
+
354
+ with gr.Column():
355
+ output_gallery = gr.Gallery(
356
+ label="Outputs (3 x 2 = 6)",
357
+ columns=3,
358
+ rows=2,
359
+ height=380,
360
+ preview=True,
361
+ )
362
+
363
+ lora_adapter = gr.Dropdown(
364
+ label="Choose Editing Style",
365
+ choices=[
366
+ "Photo-to-Anime",
367
+ "Multiple-Angles",
368
+ "Light-Restoration",
369
+ "Multi-Angle-Lighting",
370
+ "Upscale-Image",
371
+ "Relight",
372
+ "Next-Scene",
373
+ "Edit-Skin",
374
+ ],
375
+ value="Next-Scene", # ★ デフォルトを Next-Scene に
376
+ )
377
+
378
+ with gr.Accordion("Advanced Settings", open=False, visible=True):
379
+ seed = gr.Slider(label="Base Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
380
+ randomize_seed = gr.Checkbox(label="Randomize Seeds (6 images)", value=True)
381
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
382
  steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
383
 
384
+ seeds_box = gr.Textbox(label="Used Seeds (1..6)", lines=6)
385
+
386
+ # Preset changes update sliders
387
+ size_preset.change(
388
+ fn=apply_size_preset,
389
+ inputs=[size_preset, input_image, width, height],
390
+ outputs=[width, height],
391
+ )
392
+ # New upload + Auto preset should re-fit
393
+ input_image.change(
394
+ fn=apply_size_preset,
395
+ inputs=[size_preset, input_image, width, height],
396
+ outputs=[width, height],
397
+ )
398
+
399
  run_button.click(
400
+ fn=infer_6pack,
401
+ inputs=[
402
+ input_image,
403
+ prompt1, prompt2, prompt3,
404
+ lora_adapter,
405
+ size_preset, width, height,
406
+ seed, randomize_seed, guidance_scale, steps,
407
+ ],
408
+ outputs=[output_gallery, seeds_box],
409
  )
410
 
411
  if __name__ == "__main__":
412
+ demo.queue(max_size=30).launch(mcp_server=True, ssr_mode=False, show_error=True)