HAL1993 commited on
Commit
dbc1c64
·
verified ·
1 Parent(s): cdf1c70

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +132 -113
app.py CHANGED
@@ -8,11 +8,7 @@ from PIL import Image
8
  from typing import Iterable
9
  from gradio.themes import Soft
10
  from gradio.themes.utils import colors, fonts, sizes
11
- from huggingface_hub import snapshot_download
12
 
13
- # --------------------------
14
- # Theme Setup
15
- # --------------------------
16
  colors.steel_blue = colors.Color(
17
  name="steel_blue",
18
  c50="#EBF3F8",
@@ -81,127 +77,129 @@ class SteelBlueTheme(Soft):
81
 
82
  steel_blue_theme = SteelBlueTheme()
83
 
84
- # --------------------------
85
- # Device Setup
86
- # --------------------------
87
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
88
- dtype = torch.bfloat16 if torch.cuda.is_available() else torch.float32
89
 
90
- print("Using device:", device)
91
-
92
- # --------------------------
93
- # Automatic download paths
94
- # --------------------------
95
- MODEL_DIR = "./models/Qwen-Image-Edit-2509"
96
- TRANSFORMER_DIR = "./models/Qwen-Image-Edit-Rapid-AIO/transformer"
97
- LORA_DIRS = {
98
- "anime": "./loras/anime",
99
- "multiple-angles": "./loras/multiple-angles",
100
- "light-restoration": "./loras/light-restoration",
101
- "relight": "./loras/relight",
102
- "multi-angle-lighting": "./loras/multi-angle-lighting",
103
- "edit-skin": "./loras/edit-skin",
104
- "next-scene": "./loras/next-scene",
105
- "upscale-image": "./loras/upscale-image",
106
- }
107
 
108
- LORA_WEIGHTS = {
109
- "anime": "Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors",
110
- "multiple-angles": "镜头转换.safetensors",
111
- "light-restoration": "移除光影.safetensors",
112
- "relight": "Qwen-Edit-Relight.safetensors",
113
- "multi-angle-lighting": "多角度灯光-251116.safetensors",
114
- "edit-skin": "qwen-edit-skin_1.1_000002750.safetensors",
115
- "next-scene": "next-scene_lora-v2-3000.safetensors",
116
- "upscale-image": "qwen-edit-enhance_64-v3_000001000.safetensors",
117
- }
118
-
119
- # Function to download repos if missing
120
- from huggingface_hub import snapshot_download
121
-
122
- def ensure_model(repo_id, local_dir):
123
- if not os.path.exists(local_dir):
124
- print(f"Downloading {repo_id} to {local_dir}...")
125
- snapshot_download(repo_id=repo_id, local_dir=local_dir)
126
- else:
127
- print(f"{local_dir} already exists.")
128
-
129
- # Download main model and transformer
130
- ensure_model("Qwen/Qwen-Image-Edit-2509", MODEL_DIR)
131
- ensure_model("linoyts/Qwen-Image-Edit-Rapid-AIO", TRANSFORMER_DIR)
132
-
133
- # Download all LoRAs
134
- ensure_model("autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime", LORA_DIRS["anime"])
135
- ensure_model("dx8152/Qwen-Edit-2509-Multiple-angles", LORA_DIRS["multiple-angles"])
136
- ensure_model("dx8152/Qwen-Image-Edit-2509-Light_restoration", LORA_DIRS["light-restoration"])
137
- ensure_model("dx8152/Qwen-Edit-2509-Relight", LORA_DIRS["relight"])
138
- ensure_model("dx8152/Qwen-Edit-2509-Multi-Angle-Lighting", LORA_DIRS["multi-angle-lighting"])
139
- ensure_model("tlennon-ie/qwen-edit-skin", LORA_DIRS["edit-skin"])
140
- ensure_model("lovis93/next-scene-qwen-image-lora-2509", LORA_DIRS["next-scene"])
141
- ensure_model("vafipas663/Qwen-Edit-2509-Upscale-LoRA", LORA_DIRS["upscale-image"])
142
 
143
- # --------------------------
144
- # Import pipeline after ensuring downloads
145
- # --------------------------
146
  from diffusers import FlowMatchEulerDiscreteScheduler
147
  from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
148
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
149
  from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
150
 
151
- # --------------------------
152
- # Pipeline setup
153
- # --------------------------
154
  pipe = QwenImageEditPlusPipeline.from_pretrained(
155
- MODEL_DIR,
156
  transformer=QwenImageTransformer2DModel.from_pretrained(
157
- TRANSFORMER_DIR,
158
  subfolder='transformer',
159
  torch_dtype=dtype,
160
- device_map='cuda' if torch.cuda.is_available() else None
161
  ),
162
  torch_dtype=dtype
163
  ).to(device)
164
 
165
- # Load LoRAs locally
166
- for adapter, lora_path in LORA_DIRS.items():
167
- pipe.load_lora_weights(lora_path, weight_name=LORA_WEIGHTS[adapter], adapter_name=adapter)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
  pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
170
-
171
- # --------------------------
172
- # Misc constants
173
- # --------------------------
174
  MAX_SEED = np.iinfo(np.int32).max
175
 
176
- # --------------------------
177
- # Helper functions
178
- # --------------------------
179
  def update_dimensions_on_upload(image):
180
  if image is None:
181
  return 1024, 1024
182
- w, h = image.size
183
- if w > h:
184
- new_w = 1024
185
- new_h = int(1024 * h / w)
 
 
 
186
  else:
187
- new_h = 1024
188
- new_w = int(1024 * w / h)
189
- return (new_w // 8) * 8, (new_h // 8) * 8
 
 
 
 
 
 
190
 
191
  @spaces.GPU(duration=30)
192
- def infer(input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps, progress=gr.Progress(track_tqdm=True)):
 
 
 
 
 
 
 
 
 
193
  if input_image is None:
194
  raise gr.Error("Please upload an image to edit.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  if randomize_seed:
196
  seed = random.randint(0, MAX_SEED)
 
197
  generator = torch.Generator(device=device).manual_seed(seed)
198
  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"
 
199
  original_image = input_image.convert("RGB")
 
 
200
  width, height = update_dimensions_on_upload(original_image)
201
 
202
- # Set the adapter
203
- pipe.set_adapters([lora_adapter.lower().replace("-", "_")], adapter_weights=[1.0])
204
-
205
  result = pipe(
206
  image=original_image,
207
  prompt=prompt,
@@ -212,54 +210,75 @@ def infer(input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scal
212
  generator=generator,
213
  true_cfg_scale=guidance_scale,
214
  ).images[0]
 
215
  return result, seed
216
 
217
  @spaces.GPU(duration=30)
218
  def infer_example(input_image, prompt, lora_adapter):
219
- return infer(input_image, prompt, lora_adapter, 0, True, 1.0, 4)
 
 
 
 
 
220
 
221
- # --------------------------
222
- # Gradio interface
223
- # --------------------------
224
  css="""
225
- #col-container {margin:0 auto; max-width:960px;}
226
- #main-title h1 {font-size:2.1em !important;}
 
 
 
227
  """
228
 
229
  with gr.Blocks() as demo:
230
  with gr.Column(elem_id="col-container"):
231
  gr.Markdown("# **Qwen-Image-Edit-2509-LoRAs-Fast**", elem_id="main-title")
232
  gr.Markdown("Perform diverse image edits using specialized [LoRA](https://huggingface.co/models?other=base_model:adapter:Qwen/Qwen-Image-Edit-2509) adapters for the [Qwen-Image-Edit](https://huggingface.co/Qwen/Qwen-Image-Edit-2509) model.")
 
233
  with gr.Row(equal_height=True):
234
  with gr.Column():
235
  input_image = gr.Image(label="Upload Image", type="pil", height=290)
236
- prompt = gr.Text(label="Edit Prompt", show_label=True, placeholder="e.g., transform into anime..")
 
 
 
 
 
 
237
  run_button = gr.Button("Edit Image", variant="primary")
 
238
  with gr.Column():
239
  output_image = gr.Image(label="Output Image", interactive=False, format="png", height=353)
240
- lora_adapter = gr.Dropdown(
241
- label="Choose Editing Style",
242
- choices=list(LORA_DIRS.keys()),
243
- value="anime"
244
- )
 
 
245
  with gr.Accordion("Advanced Settings", open=False, visible=False):
246
  seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
247
  randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
248
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
249
  steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
250
-
251
  gr.Examples(
252
  examples=[
253
- ["examples/1.jpg", "Transform into anime.", "anime"],
254
- ["examples/5.jpg", "Remove shadows and relight the image using soft lighting.", "light-restoration"],
255
- ["examples/4.jpg", "Use a subtle golden-hour filter with smooth light diffusion.", "relight"],
256
- ["examples/2.jpeg", "Rotate the camera 45 degrees to the left.", "multiple-angles"],
257
- ["examples/7.jpg", "Light source from the Right Rear", "multi-angle-lighting"],
258
- ["examples/10.jpeg", "Upscale the image.", "upscale-image"],
259
- ["examples/7.jpg", "Light source from the Below", "multi-angle-lighting"],
260
- ["examples/2.jpeg", "Switch the camera to a top-down right corner view.", "multiple-angles"],
261
- ["examples/9.jpg", "The camera moves slightly forward as sunlight breaks through the clouds, casting a soft glow around the character's silhouette in the mist. Realistic cinematic style, atmospheric depth.", "next-scene"],
262
- ["examples/8.jpg", "Make the subjects skin details more prominent and natural.", "edit-skin"],
 
 
 
 
 
263
  ],
264
  inputs=[input_image, prompt, lora_adapter],
265
  outputs=[output_image, seed],
@@ -275,4 +294,4 @@ with gr.Blocks() as demo:
275
  )
276
 
277
  if __name__ == "__main__":
278
- demo.queue(max_size=30).launch(css=css, theme=steel_blue_theme, mcp_server=True, ssr_mode=False, show_error=True)
 
8
  from typing import Iterable
9
  from gradio.themes import Soft
10
  from gradio.themes.utils import colors, fonts, sizes
 
11
 
 
 
 
12
  colors.steel_blue = colors.Color(
13
  name="steel_blue",
14
  c50="#EBF3F8",
 
77
 
78
  steel_blue_theme = SteelBlueTheme()
79
 
 
 
 
80
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
81
 
82
+ print("CUDA_VISIBLE_DEVICES=", os.environ.get("CUDA_VISIBLE_DEVICES"))
83
+ print("torch.__version__ =", torch.__version__)
84
+ print("torch.version.cuda =", torch.version.cuda)
85
+ print("cuda available:", torch.cuda.is_available())
86
+ print("cuda device count:", torch.cuda.device_count())
87
+ if torch.cuda.is_available():
88
+ print("current device:", torch.cuda.current_device())
89
+ print("device name:", torch.cuda.get_device_name(torch.cuda.current_device()))
 
 
 
 
 
 
 
 
 
90
 
91
+ print("Using device:", device)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
 
 
 
93
  from diffusers import FlowMatchEulerDiscreteScheduler
94
  from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
95
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
96
  from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
97
 
98
+ dtype = torch.bfloat16
99
+ device = "cuda" if torch.cuda.is_available() else "cpu"
100
+
101
  pipe = QwenImageEditPlusPipeline.from_pretrained(
102
+ "Qwen/Qwen-Image-Edit-2509",
103
  transformer=QwenImageTransformer2DModel.from_pretrained(
104
+ "linoyts/Qwen-Image-Edit-Rapid-AIO", # [transformer weights extracted from: Phr00t/Qwen-Image-Edit-Rapid-AIO]
105
  subfolder='transformer',
106
  torch_dtype=dtype,
107
+ device_map='cuda'
108
  ),
109
  torch_dtype=dtype
110
  ).to(device)
111
 
112
+ pipe.load_lora_weights("autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime",
113
+ weight_name="Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors",
114
+ adapter_name="anime")
115
+ pipe.load_lora_weights("dx8152/Qwen-Edit-2509-Multiple-angles",
116
+ weight_name="镜头转换.safetensors",
117
+ adapter_name="multiple-angles")
118
+ pipe.load_lora_weights("dx8152/Qwen-Image-Edit-2509-Light_restoration",
119
+ weight_name="移除光影.safetensors",
120
+ adapter_name="light-restoration")
121
+ pipe.load_lora_weights("dx8152/Qwen-Image-Edit-2509-Relight",
122
+ weight_name="Qwen-Edit-Relight.safetensors",
123
+ adapter_name="relight")
124
+ pipe.load_lora_weights("dx8152/Qwen-Edit-2509-Multi-Angle-Lighting",
125
+ weight_name="多角度灯光-251116.safetensors",
126
+ adapter_name="multi-angle-lighting")
127
+ pipe.load_lora_weights("tlennon-ie/qwen-edit-skin",
128
+ weight_name="qwen-edit-skin_1.1_000002750.safetensors",
129
+ adapter_name="edit-skin")
130
+ pipe.load_lora_weights("lovis93/next-scene-qwen-image-lora-2509",
131
+ weight_name="next-scene_lora-v2-3000.safetensors",
132
+ adapter_name="next-scene")
133
+ pipe.load_lora_weights("vafipas663/Qwen-Edit-2509-Upscale-LoRA",
134
+ weight_name="qwen-edit-enhance_64-v3_000001000.safetensors",
135
+ adapter_name="upscale-image")
136
 
137
  pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
 
 
 
 
138
  MAX_SEED = np.iinfo(np.int32).max
139
 
 
 
 
140
  def update_dimensions_on_upload(image):
141
  if image is None:
142
  return 1024, 1024
143
+
144
+ original_width, original_height = image.size
145
+
146
+ if original_width > original_height:
147
+ new_width = 1024
148
+ aspect_ratio = original_height / original_width
149
+ new_height = int(new_width * aspect_ratio)
150
  else:
151
+ new_height = 1024
152
+ aspect_ratio = original_width / original_height
153
+ new_width = int(new_height * aspect_ratio)
154
+
155
+ # Ensure dimensions are multiples of 8
156
+ new_width = (new_width // 8) * 8
157
+ new_height = (new_height // 8) * 8
158
+
159
+ return new_width, new_height
160
 
161
  @spaces.GPU(duration=30)
162
+ def infer(
163
+ input_image,
164
+ prompt,
165
+ lora_adapter,
166
+ seed,
167
+ randomize_seed,
168
+ guidance_scale,
169
+ steps,
170
+ progress=gr.Progress(track_tqdm=True)
171
+ ):
172
  if input_image is None:
173
  raise gr.Error("Please upload an image to edit.")
174
+
175
+ if lora_adapter == "Photo-to-Anime":
176
+ pipe.set_adapters(["anime"], adapter_weights=[1.0])
177
+ elif lora_adapter == "Multiple-Angles":
178
+ pipe.set_adapters(["multiple-angles"], adapter_weights=[1.0])
179
+ elif lora_adapter == "Light-Restoration":
180
+ pipe.set_adapters(["light-restoration"], adapter_weights=[1.0])
181
+ elif lora_adapter == "Relight":
182
+ pipe.set_adapters(["relight"], adapter_weights=[1.0])
183
+ elif lora_adapter == "Multi-Angle-Lighting":
184
+ pipe.set_adapters(["multi-angle-lighting"], adapter_weights=[1.0])
185
+ elif lora_adapter == "Edit-Skin":
186
+ pipe.set_adapters(["edit-skin"], adapter_weights=[1.0])
187
+ elif lora_adapter == "Next-Scene":
188
+ pipe.set_adapters(["next-scene"], adapter_weights=[1.0])
189
+ elif lora_adapter == "Upscale-Image":
190
+ pipe.set_adapters(["upscale-image"], adapter_weights=[1.0])
191
+
192
  if randomize_seed:
193
  seed = random.randint(0, MAX_SEED)
194
+
195
  generator = torch.Generator(device=device).manual_seed(seed)
196
  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"
197
+
198
  original_image = input_image.convert("RGB")
199
+
200
+ # Use the new function to update dimensions
201
  width, height = update_dimensions_on_upload(original_image)
202
 
 
 
 
203
  result = pipe(
204
  image=original_image,
205
  prompt=prompt,
 
210
  generator=generator,
211
  true_cfg_scale=guidance_scale,
212
  ).images[0]
213
+
214
  return result, seed
215
 
216
  @spaces.GPU(duration=30)
217
  def infer_example(input_image, prompt, lora_adapter):
218
+ input_pil = input_image.convert("RGB")
219
+ guidance_scale = 1.0
220
+ steps = 4
221
+ result, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps)
222
+ return result, seed
223
+
224
 
 
 
 
225
  css="""
226
+ #col-container {
227
+ margin: 0 auto;
228
+ max-width: 960px;
229
+ }
230
+ #main-title h1 {font-size: 2.1em !important;}
231
  """
232
 
233
  with gr.Blocks() as demo:
234
  with gr.Column(elem_id="col-container"):
235
  gr.Markdown("# **Qwen-Image-Edit-2509-LoRAs-Fast**", elem_id="main-title")
236
  gr.Markdown("Perform diverse image edits using specialized [LoRA](https://huggingface.co/models?other=base_model:adapter:Qwen/Qwen-Image-Edit-2509) adapters for the [Qwen-Image-Edit](https://huggingface.co/Qwen/Qwen-Image-Edit-2509) model.")
237
+
238
  with gr.Row(equal_height=True):
239
  with gr.Column():
240
  input_image = gr.Image(label="Upload Image", type="pil", height=290)
241
+
242
+ prompt = gr.Text(
243
+ label="Edit Prompt",
244
+ show_label=True,
245
+ placeholder="e.g., transform into anime..",
246
+ )
247
+
248
  run_button = gr.Button("Edit Image", variant="primary")
249
+
250
  with gr.Column():
251
  output_image = gr.Image(label="Output Image", interactive=False, format="png", height=353)
252
+
253
+ with gr.Row():
254
+ lora_adapter = gr.Dropdown(
255
+ label="Choose Editing Style",
256
+ choices=["Photo-to-Anime", "Multiple-Angles", "Light-Restoration", "Multi-Angle-Lighting", "Upscale-Image", "Relight", "Next-Scene", "Edit-Skin"],
257
+ value="Photo-to-Anime"
258
+ )
259
  with gr.Accordion("Advanced Settings", open=False, visible=False):
260
  seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
261
  randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
262
  guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
263
  steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
264
+
265
  gr.Examples(
266
  examples=[
267
+ ["examples/1.jpg", "Transform into anime.", "Photo-to-Anime"],
268
+ ["examples/5.jpg", "Remove shadows and relight the image using soft lighting.", "Light-Restoration"],
269
+ ["examples/4.jpg", "Use a subtle golden-hour filter with smooth light diffusion.", "Relight"],
270
+ ["examples/2.jpeg", "Rotate the camera 45 degrees to the left.", "Multiple-Angles"],
271
+ ["examples/7.jpg", "Light source from the Right Rear", "Multi-Angle-Lighting"],
272
+ ["examples/10.jpeg", "Upscale the image.", "Upscale-Image"],
273
+ ["examples/7.jpg", "Light source from the Below", "Multi-Angle-Lighting"],
274
+ ["examples/2.jpeg", "Switch the camera to a top-down right corner view.", "Multiple-Angles"],
275
+ ["examples/9.jpg", "The camera moves slightly forward as sunlight breaks through the clouds, casting a soft glow around the character's silhouette in the mist. Realistic cinematic style, atmospheric depth.", "Next-Scene"],
276
+ ["examples/8.jpg", "Make the subjects skin details more prominent and natural.", "Edit-Skin"],
277
+ ["examples/6.jpg", "Switch the camera to a bottom-up view.", "Multiple-Angles"],
278
+ ["examples/6.jpg", "Rotate the camera 180 degrees upside down.", "Multiple-Angles"],
279
+ ["examples/4.jpg", "Rotate the camera 45 degrees to the right.", "Multiple-Angles"],
280
+ ["examples/4.jpg", "Switch the camera to a top-down view.", "Multiple-Angles"],
281
+ ["examples/4.jpg", "Switch the camera to a wide-angle lens.", "Multiple-Angles"],
282
  ],
283
  inputs=[input_image, prompt, lora_adapter],
284
  outputs=[output_image, seed],
 
294
  )
295
 
296
  if __name__ == "__main__":
297
+ demo.queue(max_size=30).launch(css=css, theme=steel_blue_theme, mcp_server=True, ssr_mode=False, show_error=True)