00Boobs00 commited on
Commit
50cd51e
·
verified ·
1 Parent(s): d8863ee

Update app.py from anycoder

Browse files
Files changed (1) hide show
  1. app.py +95 -77
app.py CHANGED
@@ -7,6 +7,16 @@ import torch
7
  import random
8
  from PIL import Image
9
  from typing import Iterable
 
 
 
 
 
 
 
 
 
 
10
  from gradio.themes import Soft
11
  from gradio.themes.utils import colors, fonts, sizes
12
 
@@ -94,11 +104,6 @@ if torch.cuda.is_available():
94
  print("Using device:", device)
95
 
96
  # --- Model Loading ---
97
- from diffusers import FlowMatchEulerDiscreteScheduler
98
- from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
99
- from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
100
- from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
101
-
102
  dtype = torch.bfloat16
103
 
104
  pipe = QwenImageEditPlusPipeline.from_pretrained(
@@ -122,11 +127,11 @@ except Exception as e:
122
  MAX_SEED = np.iinfo(np.int32).max
123
 
124
  # --- Dynamic LoRA Configuration ---
125
- # This dictionary defines the available adapters.
126
- # The application uses lazy-loading to download these only when selected.
127
  ADAPTER_SPECS = {
128
  "Cinematic-DSLR": {
129
- "repo": "prithivMLmods/Qwen-Image-Edit-2509-LoRAs-Fast", # Placeholder for base repo structure
130
  "weights": "placeholder_weights.safetensors",
131
  "adapter_name": "cinematic-dslr",
132
  "description": "High-end cinema look with professional color grading."
@@ -155,6 +160,7 @@ ADAPTER_SPECS = {
155
  LOADED_ADAPTERS = set()
156
 
157
  def update_dimensions_on_upload(image):
 
158
  if image is None:
159
  return 1024, 1024
160
 
@@ -169,7 +175,7 @@ def update_dimensions_on_upload(image):
169
  aspect_ratio = original_width / original_height
170
  new_width = int(new_height * aspect_ratio)
171
 
172
- # Ensure dimensions are multiples of 8
173
  new_width = (new_width // 8) * 8
174
  new_height = (new_height // 8) * 8
175
 
@@ -186,6 +192,9 @@ def infer(
186
  steps,
187
  progress=gr.Progress(track_tqdm=True)
188
  ):
 
 
 
189
  # Cleanup memory before starting
190
  gc.collect()
191
  torch.cuda.empty_cache()
@@ -196,17 +205,17 @@ def infer(
196
  # 1. Get Config for Selected Adapter
197
  spec = ADAPTER_SPECS.get(lora_adapter)
198
  if not spec:
199
- raise gr.Error(f"Configuration not found for: {lora_adapter}")
200
-
201
- adapter_name = spec["adapter_name"]
 
 
202
 
203
  # 2. Lazy Loading Logic (Hot Swapping)
204
  # Only loads if not currently in memory to save bandwidth/startup time
205
- if adapter_name not in LOADED_ADAPTERS:
206
  print(f"--- Hot Loading Adapter: {lora_adapter} ---")
207
  try:
208
- # NOTE: Replace this logic with actual HuggingFace Hub calls
209
- # for your specific dynamic endpoints
210
  pipe.load_lora_weights(
211
  spec["repo"],
212
  weight_name=spec["weights"],
@@ -215,15 +224,19 @@ def infer(
215
  LOADED_ADAPTERS.add(adapter_name)
216
  except Exception as e:
217
  # Fallback for demonstration if placeholder weights don't exist
218
- print(f"Info: Could not load placeholder weights for {lora_adapter}: {e}")
219
- # In a real scenario, you might load a default or alert the user
220
- pass
 
221
  else:
222
- print(f"--- Adapter {lora_adapter} already active in memory. ---")
223
 
224
  # 3. Activate the specific adapter
225
- # Unload others by exclusively setting this one to weight 1.0
226
- pipe.set_adapters([adapter_name], adapter_weights=[1.0])
 
 
 
227
 
228
  # 4. Standard Inference Setup
229
  if randomize_seed:
@@ -250,7 +263,7 @@ def infer(
250
  return result, seed
251
 
252
  except Exception as e:
253
- raise e
254
  finally:
255
  # Cleanup
256
  gc.collect()
@@ -258,6 +271,7 @@ def infer(
258
 
259
  @spaces.GPU
260
  def infer_example(input_image, prompt, lora_adapter):
 
261
  if input_image is None:
262
  return None, 0
263
 
@@ -271,60 +285,61 @@ def infer_example(input_image, prompt, lora_adapter):
271
  # Gradio 6 Syntax: gr.Blocks() takes NO parameters. All config goes in demo.launch()
272
 
273
  with gr.Blocks() as demo:
274
- with gr.Column(elem_id="col-container"):
275
- # Header
276
- gr.HTML("""
277
- <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
278
- <h1 style="margin: 0;">Qwen-Image-Edit-2509-LoRAs-Fast</h1>
279
- <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" style="text-decoration: none; color: inherit;">
280
- <small>Built with anycoder</small>
281
- </a>
282
- </div>
283
- """)
284
-
285
- 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.")
286
-
287
- with gr.Row(equal_height=True):
288
- with gr.Column():
289
- input_image = gr.Image(label="Upload Image", type="pil", height=290)
290
-
291
- prompt = gr.Text(
292
- label="Edit Prompt",
293
- show_label=True,
294
- placeholder="e.g., apply cinematic lighting...",
295
- )
296
 
297
- run_button = gr.Button("Edit Image", variant="primary")
298
-
299
- with gr.Column():
300
- output_image = gr.Image(label="Output Image", interactive=False, format="png", height=353)
301
-
302
- with gr.Row():
303
- # Dynamic keys based on the config dict
304
- lora_adapter = gr.Dropdown(
305
- label="Choose Editing Style",
306
- choices=list(ADAPTER_SPECS.keys()),
307
- value="Cinematic-DSLR"
308
- )
309
-
310
- with gr.Accordion("Advanced Settings", open=False):
311
- seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
312
- randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
313
- guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
314
- steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
315
-
316
- gr.Examples(
317
- examples=[
318
- ["examples/1.jpg", "Apply cinematic dslr style.", "Cinematic-DSLR"],
319
- ["examples/5.jpg", "Enhance portrait lighting.", "Portrait-Pro"],
320
- ["examples/4.jpg", "Switch to high key lighting.", "High-Key-Lighting"],
321
- ],
322
- inputs=[input_image, prompt, lora_adapter],
323
- outputs=[output_image, seed],
324
- fn=infer_example,
325
- cache_examples=False,
326
- label="Examples"
327
- )
 
 
 
 
 
 
 
 
 
 
 
 
328
 
329
  # Gradio 6 Event Listeners
330
  run_button.click(
@@ -337,13 +352,16 @@ with gr.Blocks() as demo:
337
  css="""
338
  #col-container {
339
  margin: 0 auto;
340
- max-width: 960px;
 
 
 
341
  }
342
- #main-title h1 {font-size: 2.1em !important;}
343
  """
344
 
345
  if __name__ == "__main__":
346
  # Gradio 6 Launch Syntax
 
347
  demo.queue(max_size=30).launch(
348
  css=css,
349
  theme=orange_red_theme,
 
7
  import random
8
  from PIL import Image
9
  from typing import Iterable
10
+ from diffusers import FlowMatchEulerDiscreteScheduler
11
+
12
+ # --- Custom Local Imports ---
13
+ # Note: Ensure these files (pipeline_qwenimage_edit_plus.py, etc.)
14
+ # are present in the same directory or installed in the environment.
15
+ from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
16
+ from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
17
+ from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
18
+
19
+ # --- Theme Imports ---
20
  from gradio.themes import Soft
21
  from gradio.themes.utils import colors, fonts, sizes
22
 
 
104
  print("Using device:", device)
105
 
106
  # --- Model Loading ---
 
 
 
 
 
107
  dtype = torch.bfloat16
108
 
109
  pipe = QwenImageEditPlusPipeline.from_pretrained(
 
127
  MAX_SEED = np.iinfo(np.int32).max
128
 
129
  # --- Dynamic LoRA Configuration ---
130
+ # These are architectural placeholders. To make the styles work, update 'repo' and 'weights'
131
+ # to point to actual HuggingFace repositories containing valid LoRA weights.
132
  ADAPTER_SPECS = {
133
  "Cinematic-DSLR": {
134
+ "repo": "prithivMLmods/Qwen-Image-Edit-2509-LoRAs-Fast",
135
  "weights": "placeholder_weights.safetensors",
136
  "adapter_name": "cinematic-dslr",
137
  "description": "High-end cinema look with professional color grading."
 
160
  LOADED_ADAPTERS = set()
161
 
162
  def update_dimensions_on_upload(image):
163
+ """Calculates optimal dimensions based on image aspect ratio."""
164
  if image is None:
165
  return 1024, 1024
166
 
 
175
  aspect_ratio = original_width / original_height
176
  new_width = int(new_height * aspect_ratio)
177
 
178
+ # Ensure dimensions are multiples of 8 (standard for diffusion models)
179
  new_width = (new_width // 8) * 8
180
  new_height = (new_height // 8) * 8
181
 
 
192
  steps,
193
  progress=gr.Progress(track_tqdm=True)
194
  ):
195
+ """
196
+ Main inference function with dynamic LoRA hot-loading.
197
+ """
198
  # Cleanup memory before starting
199
  gc.collect()
200
  torch.cuda.empty_cache()
 
205
  # 1. Get Config for Selected Adapter
206
  spec = ADAPTER_SPECS.get(lora_adapter)
207
  if not spec:
208
+ # Fallback to base model if config missing
209
+ print(f"Configuration not found for: {lora_adapter}. Using base model.")
210
+ adapter_name = "base"
211
+ else:
212
+ adapter_name = spec["adapter_name"]
213
 
214
  # 2. Lazy Loading Logic (Hot Swapping)
215
  # Only loads if not currently in memory to save bandwidth/startup time
216
+ if spec and adapter_name not in LOADED_ADAPTERS:
217
  print(f"--- Hot Loading Adapter: {lora_adapter} ---")
218
  try:
 
 
219
  pipe.load_lora_weights(
220
  spec["repo"],
221
  weight_name=spec["weights"],
 
224
  LOADED_ADAPTERS.add(adapter_name)
225
  except Exception as e:
226
  # Fallback for demonstration if placeholder weights don't exist
227
+ print(f"Info: Could not load weights for {lora_adapter}: {e}")
228
+ gr.Warning(f"Could not load specific style weights for '{lora_adapter}'. Using base model instead.")
229
+ # Ensure we don't try to set this adapter if it failed to load
230
+ adapter_name = "base"
231
  else:
232
+ print(f"--- Adapter {lora_adapter} already active in memory or using base model. ---")
233
 
234
  # 3. Activate the specific adapter
235
+ # If 'base' (or fallback), we disable adapters. Otherwise, set the specific one.
236
+ if adapter_name == "base":
237
+ pipe.disable_lora()
238
+ else:
239
+ pipe.set_adapters([adapter_name], adapter_weights=[1.0])
240
 
241
  # 4. Standard Inference Setup
242
  if randomize_seed:
 
263
  return result, seed
264
 
265
  except Exception as e:
266
+ raise gr.Error(f"Error during inference: {e}")
267
  finally:
268
  # Cleanup
269
  gc.collect()
 
271
 
272
  @spaces.GPU
273
  def infer_example(input_image, prompt, lora_adapter):
274
+ """Helper function for Gradio Examples."""
275
  if input_image is None:
276
  return None, 0
277
 
 
285
  # Gradio 6 Syntax: gr.Blocks() takes NO parameters. All config goes in demo.launch()
286
 
287
  with gr.Blocks() as demo:
288
+ gr.HTML("""
289
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
290
+ <h1 style="margin: 0;">Qwen-Image-Edit-2509-LoRAs-Fast</h1>
291
+ </div>
292
+ """)
293
+
294
+ gr.Markdown(
295
+ "Perform diverse image edits using specialized [LoRA](https://huggingface.co/models?other=base_model:adapter:Qwen/Qwen-Image-Edit-2509) "
296
+ "adapters for the [Qwen-Image-Edit](https://huggingface.co/Qwen/Qwen-Image-Edit-2509) model. "
297
+ "This demo features **dynamic hot-loading**, downloading LoRA weights only when you select them."
298
+ )
 
 
 
 
 
 
 
 
 
 
 
299
 
300
+ with gr.Row(equal_height=True):
301
+ with gr.Column():
302
+ input_image = gr.Image(label="Upload Image", type="pil", height=290)
303
+
304
+ prompt = gr.Text(
305
+ label="Edit Prompt",
306
+ show_label=True,
307
+ placeholder="e.g., apply cinematic lighting...",
308
+ lines=2
309
+ )
310
+
311
+ run_button = gr.Button("Edit Image", variant="primary", size="lg")
312
+
313
+ with gr.Column():
314
+ output_image = gr.Image(label="Output Image", interactive=False, format="png", height=353)
315
+
316
+ with gr.Row():
317
+ # Dynamic keys based on the config dict
318
+ lora_adapter = gr.Dropdown(
319
+ label="Choose Editing Style",
320
+ choices=list(ADAPTER_SPECS.keys()),
321
+ value="Cinematic-DSLR",
322
+ info="Select a style to hot-load"
323
+ )
324
+
325
+ with gr.Accordion("Advanced Settings", open=False):
326
+ seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
327
+ randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
328
+ guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
329
+ steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
330
+
331
+ gr.Examples(
332
+ examples=[
333
+ ["examples/1.jpg", "Apply cinematic dslr style.", "Cinematic-DSLR"],
334
+ ["examples/5.jpg", "Enhance portrait lighting.", "Portrait-Pro"],
335
+ ["examples/4.jpg", "Switch to high key lighting.", "High-Key-Lighting"],
336
+ ],
337
+ inputs=[input_image, prompt, lora_adapter],
338
+ outputs=[output_image, seed],
339
+ fn=infer_example,
340
+ cache_examples=False,
341
+ label="Examples"
342
+ )
343
 
344
  # Gradio 6 Event Listeners
345
  run_button.click(
 
352
  css="""
353
  #col-container {
354
  margin: 0 auto;
355
+ max-width: 1000px;
356
+ }
357
+ .gradio-container {
358
+ font-family: 'Outfit', sans-serif !important;
359
  }
 
360
  """
361
 
362
  if __name__ == "__main__":
363
  # Gradio 6 Launch Syntax
364
+ # All app-level parameters (theme, css, footer_links) go here.
365
  demo.queue(max_size=30).launch(
366
  css=css,
367
  theme=orange_red_theme,