prithivMLmods commited on
Commit
6091fe1
·
verified ·
1 Parent(s): c6f8f53

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +253 -139
app.py CHANGED
@@ -9,11 +9,20 @@ import spaces
9
  import torch
10
  from diffusers import StableDiffusionXLPipeline, EulerAncestralDiscreteScheduler
11
 
12
- DESCRIPTIONz= """## SDXL-LoRA-DLC ⚡
13
  """
14
 
 
 
 
 
 
15
  def save_image(img):
16
- unique_name = str(uuid.uuid4()) + ".png"
 
 
 
 
17
  img.save(unique_name)
18
  return unique_name
19
 
@@ -23,14 +32,16 @@ def randomize_seed_fn(seed: int, randomize_seed: bool) -> int:
23
  return seed
24
 
25
  MAX_SEED = np.iinfo(np.int32).max
 
26
 
27
  if not torch.cuda.is_available():
28
  DESCRIPTIONz += "\n<p>⚠️Running on CPU, This may not work on CPU. If it runs for an extended time or if you encounter errors, try running it on a GPU by duplicating the space using @spaces.GPU(). +import spaces.📍</p>"
 
 
 
 
29
 
30
- USE_TORCH_COMPILE = 0
31
- ENABLE_CPU_OFFLOAD = 0
32
-
33
- if torch.cuda.is_available():
34
  pipe = StableDiffusionXLPipeline.from_pretrained(
35
  "SG161222/RealVisXL_V4.0_Lightning",
36
  torch_dtype=torch.float16,
@@ -52,12 +63,21 @@ if torch.cuda.is_available():
52
  "Canes Cars (realistic/futurecars)🚘": ("prithivMLmods/Canes-Cars-Model-LoRA", "Canes-Cars-Model-LoRA.safetensors", "car"),
53
  "Pencil Art (characteristic/creative)✏️": ("prithivMLmods/Canopus-Pencil-Art-LoRA", "Canopus-Pencil-Art-LoRA.safetensors", "Pencil Art"),
54
  "Art Minimalistic (paint/semireal)🎨": ("prithivMLmods/Canopus-Art-Medium-LoRA", "Canopus-Art-Medium-LoRA.safetensors", "mdm"),
55
-
56
  }
57
 
58
- for model_name, weight_name, adapter_name in LORA_OPTIONS.values():
59
- pipe.load_lora_weights(model_name, weight_name=weight_name, adapter_name=adapter_name)
60
- pipe.to("cuda")
 
 
 
 
 
 
 
 
 
 
61
 
62
  style_list = [
63
  {
@@ -88,14 +108,11 @@ DEFAULT_STYLE_NAME = "3840 x 2160"
88
  STYLE_NAMES = list(styles.keys())
89
 
90
  def apply_style(style_name: str, positive: str, negative: str = "") -> Tuple[str, str]:
91
- if style_name in styles:
92
- p, n = styles.get(style_name, styles[DEFAULT_STYLE_NAME])
93
- else:
94
- p, n = styles[DEFAULT_STYLE_NAME]
95
 
96
  if not negative:
97
  negative = ""
98
- return p.replace("{prompt}", positive), n + negative
99
 
100
  @spaces.GPU(duration=180, enable_queue=True)
101
  def generate(
@@ -111,142 +128,197 @@ def generate(
111
  lora_model: str = "Realism (face/character)👦🏻",
112
  progress=gr.Progress(track_tqdm=True),
113
  ):
 
 
 
114
  seed = int(randomize_seed_fn(seed, randomize_seed))
115
 
116
- positive_prompt, effective_negative_prompt = apply_style(style_name, prompt, negative_prompt)
 
 
 
 
 
 
 
 
 
 
 
117
 
118
- if not use_negative_prompt:
119
- effective_negative_prompt = "" # type: ignore
 
 
 
 
120
 
121
  model_name, weight_name, adapter_name = LORA_OPTIONS[lora_model]
122
- pipe.set_adapters(adapter_name)
123
-
124
- images = pipe(
125
- prompt=positive_prompt,
126
- negative_prompt=effective_negative_prompt,
127
- width=width,
128
- height=height,
129
- guidance_scale=guidance_scale,
130
- num_inference_steps=20,
131
- num_images_per_prompt=1,
132
- cross_attention_kwargs={"scale": 0.65},
133
- output_type="pil",
134
- ).images
135
- image_paths = [save_image(img) for img in images]
136
- return image_paths, seed
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
  examples = [
139
- "Realism: Man in the style of dark beige and brown, uhd image, youthful protagonists, nonrepresentational ",
140
- "Pixar: A young man with light brown wavy hair and light brown eyes sitting in an armchair and looking directly at the camera, pixar style, disney pixar, office background, ultra detailed, 1 man",
141
- "Hoodie: Front view, capture a urban style, Superman Hoodie, technical materials, fabric small point label on text Blue theory, the design is minimal, with a raised collar, fabric is a Light yellow, low angle to capture the Hoodies form and detailing, f/5.6 to focus on the hoodies craftsmanship, solid grey background, studio light setting, with batman logo in the chest region of the t-shirt",
142
  ]
143
 
144
  css = '''
145
- .gradio-container{max-width: 545px !important}
146
  h1{text-align:center}
147
- footer {
148
- visibility: hidden
149
- }
150
  '''
151
- def load_predefined_images():
152
-
153
- predefined_images = [
154
-
155
- "assets/1.png",
156
- "assets/2.png",
157
- "assets/3.png",
158
- "assets/4.png",
159
- "assets/5.png",
160
- "assets/6.png",
161
- "assets/7.png",
162
- "assets/8.png",
163
- "assets/9.png",
164
 
165
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  return predefined_images
167
 
168
- with gr.Blocks(css=css) as demo:
 
 
169
  gr.Markdown(DESCRIPTIONz)
 
 
 
 
 
 
 
 
 
 
 
 
170
  with gr.Row():
171
- with gr.Column(scale=1):
172
- with gr.Row():
173
- prompt = gr.Text(
174
- show_label=False,
175
- max_lines=1,
176
- placeholder="Enter your prompt",
177
- container=False,
178
- )
179
- run_button = gr.Button("Run", scale=0, variant="primary")
180
-
181
- with gr.Accordion("Advanced options", open=False, visible=False):
182
- use_negative_prompt = gr.Checkbox(label="Use negative prompt", value=True)
183
- negative_prompt = gr.Text(
184
- label="Negative prompt",
185
- lines=4,
186
- max_lines=6,
187
- value="(deformed, distorted, disfigured:1.3), poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, (mutated hands and fingers:1.4), disconnected limbs, mutation, mutated, ugly, disgusting, blurry, amputation",
188
- placeholder="Enter a negative prompt",
189
- visible=True,
190
  )
191
- seed = gr.Slider(
192
- label="Seed",
193
- minimum=0,
194
- maximum=MAX_SEED,
195
- step=1,
196
- value=0,
197
- visible=True
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  )
199
- randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
200
 
201
- with gr.Row(visible=True):
202
  width = gr.Slider(
203
  label="Width",
204
  minimum=512,
205
- maximum=2048,
206
- step=8,
207
  value=1024,
208
  )
209
  height = gr.Slider(
210
  label="Height",
211
  minimum=512,
212
- maximum=2048,
213
- step=8,
214
  value=1024,
215
  )
216
-
217
- with gr.Row():
218
  guidance_scale = gr.Slider(
219
- label="Guidance Scale",
220
- minimum=0.1,
221
- maximum=20.0,
222
  step=0.1,
223
  value=3.0,
224
  )
225
 
226
- style_selection = gr.Radio(
227
- show_label=True,
228
- container=True,
229
- interactive=True,
230
- choices=STYLE_NAMES,
231
- value=DEFAULT_STYLE_NAME,
232
- label="Quality Style",
233
- )
234
-
235
- with gr.Row(visible=True):
236
- model_choice = gr.Dropdown(
237
- label="LoRA Selection",
238
- choices=list(LORA_OPTIONS.keys()),
239
- value="Realism (face/character)👦🏻"
240
- )
241
-
242
- gr.Examples(
243
- examples=examples,
244
- inputs=prompt,
245
- outputs=[result, seed],
246
- fn=generate,
247
- cache_examples=False,
248
- )
249
 
 
250
  use_negative_prompt.change(
251
  fn=lambda x: gr.update(visible=x),
252
  inputs=use_negative_prompt,
@@ -254,33 +326,75 @@ with gr.Blocks(css=css) as demo:
254
  api_name=False,
255
  )
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  gr.on(
258
- triggers=[
259
- prompt.submit,
260
- negative_prompt.submit,
261
- run_button.click,
262
- ],
263
  fn=generate,
264
- inputs=[
265
- prompt,
266
- negative_prompt,
267
- use_negative_prompt,
268
- seed,
269
- width,
270
- height,
271
- guidance_scale,
272
- randomize_seed,
273
- style_selection,
274
- model_choice,
275
- ],
276
- outputs=[result, seed],
277
- api_name="run",
278
  )
279
 
 
 
280
 
281
- with gr.Column(scale=3):
282
- gr.Markdown("### Image Gallery")
283
- predefined_gallery = gr.Gallery(label="Image Gallery", columns=3, show_label=False, value=load_predefined_images())
284
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285
  if __name__ == "__main__":
286
- demo.queue(max_size=30).launch()
 
9
  import torch
10
  from diffusers import StableDiffusionXLPipeline, EulerAncestralDiscreteScheduler
11
 
12
+ DESCRIPTIONz = """## SDXL-LoRA-DLC ⚡
13
  """
14
 
15
+ # Ensure assets directory exists if needed for predefined images
16
+ if not os.path.exists("assets"):
17
+ print("Warning: 'assets' directory not found. Predefined gallery might be empty.")
18
+ # Optionally create it: os.makedirs("assets")
19
+
20
  def save_image(img):
21
+ # Ensure an 'outputs' directory exists to save generated images (optional, good practice)
22
+ output_dir = "outputs"
23
+ if not os.path.exists(output_dir):
24
+ os.makedirs(output_dir)
25
+ unique_name = os.path.join(output_dir, str(uuid.uuid4()) + ".png")
26
  img.save(unique_name)
27
  return unique_name
28
 
 
32
  return seed
33
 
34
  MAX_SEED = np.iinfo(np.int32).max
35
+ pipe = None # Initialize pipe to None
36
 
37
  if not torch.cuda.is_available():
38
  DESCRIPTIONz += "\n<p>⚠️Running on CPU, This may not work on CPU. If it runs for an extended time or if you encounter errors, try running it on a GPU by duplicating the space using @spaces.GPU(). +import spaces.📍</p>"
39
+ # Optionally, you could add a placeholder or disable functionality here
40
+ else:
41
+ USE_TORCH_COMPILE = False # Set to False as 0 is not standard boolean
42
+ ENABLE_CPU_OFFLOAD = False # Set to False as 0 is not standard boolean
43
 
44
+ # Moved pipe initialization inside the CUDA check
 
 
 
45
  pipe = StableDiffusionXLPipeline.from_pretrained(
46
  "SG161222/RealVisXL_V4.0_Lightning",
47
  torch_dtype=torch.float16,
 
63
  "Canes Cars (realistic/futurecars)🚘": ("prithivMLmods/Canes-Cars-Model-LoRA", "Canes-Cars-Model-LoRA.safetensors", "car"),
64
  "Pencil Art (characteristic/creative)✏️": ("prithivMLmods/Canopus-Pencil-Art-LoRA", "Canopus-Pencil-Art-LoRA.safetensors", "Pencil Art"),
65
  "Art Minimalistic (paint/semireal)🎨": ("prithivMLmods/Canopus-Art-Medium-LoRA", "Canopus-Art-Medium-LoRA.safetensors", "mdm"),
 
66
  }
67
 
68
+ # Load LoRAs only if pipe is initialized
69
+ if pipe:
70
+ for model_name, weight_name, adapter_name in LORA_OPTIONS.values():
71
+ try:
72
+ pipe.load_lora_weights(model_name, weight_name=weight_name, adapter_name=adapter_name)
73
+ print(f"Loaded LoRA: {adapter_name}")
74
+ except Exception as e:
75
+ print(f"Warning: Could not load LoRA {adapter_name} from {model_name}. Error: {e}")
76
+ pipe.to("cuda")
77
+ print("Pipeline and LoRAs loaded to CUDA.")
78
+ else:
79
+ print("Pipeline not initialized (likely no CUDA available).")
80
+
81
 
82
  style_list = [
83
  {
 
108
  STYLE_NAMES = list(styles.keys())
109
 
110
  def apply_style(style_name: str, positive: str, negative: str = "") -> Tuple[str, str]:
111
+ p, n = styles.get(style_name, styles[DEFAULT_STYLE_NAME]) # Use .get for safety
 
 
 
112
 
113
  if not negative:
114
  negative = ""
115
+ return p.replace("{prompt}", positive), n + " " + negative # Add space for clarity
116
 
117
  @spaces.GPU(duration=180, enable_queue=True)
118
  def generate(
 
128
  lora_model: str = "Realism (face/character)👦🏻",
129
  progress=gr.Progress(track_tqdm=True),
130
  ):
131
+ if pipe is None:
132
+ raise gr.Error("Pipeline not initialized. Check if CUDA is available and drivers are installed.")
133
+
134
  seed = int(randomize_seed_fn(seed, randomize_seed))
135
 
136
+ # Apply style first
137
+ positive_prompt, base_negative_prompt = apply_style(style_name, prompt, negative_prompt if use_negative_prompt else "")
138
+
139
+ # If user explicitly provided a negative prompt and wants to use it, append it
140
+ # (apply_style already incorporates the style's negative prompt)
141
+ # This logic might need adjustment depending on desired behavior: replace or append?
142
+ # Current: Style neg prompt + user neg prompt
143
+ effective_negative_prompt = base_negative_prompt
144
+ if use_negative_prompt and negative_prompt:
145
+ # Check if the negative prompt from apply_style is already there to avoid duplication
146
+ if not negative_prompt in effective_negative_prompt:
147
+ effective_negative_prompt = (effective_negative_prompt + " " + negative_prompt).strip()
148
 
149
+
150
+ # Ensure LoRA selection is valid
151
+ if lora_model not in LORA_OPTIONS:
152
+ print(f"Warning: Invalid LoRA selection '{lora_model}'. Using default or first available.")
153
+ # Fallback logic could be added here, e.g., use the first key
154
+ lora_model = next(iter(LORA_OPTIONS)) # Get the first key as a fallback
155
 
156
  model_name, weight_name, adapter_name = LORA_OPTIONS[lora_model]
157
+
158
+ try:
159
+ print(f"Setting adapter: {adapter_name}")
160
+ pipe.set_adapters(adapter_name)
161
+ # Optional: Add LoRA scale if needed, often done via cross_attention_kwargs
162
+ # Example: cross_attention_kwargs={"scale": lora_scale}
163
+ # Note: RealVisXL Lightning might not need explicit scale adjustments like older models.
164
+ # Using 0.65 as hardcoded before. Keeping it.
165
+ lora_scale = 0.65
166
+
167
+ print(f"Generating with prompt: '{positive_prompt}'")
168
+ print(f"Negative prompt: '{effective_negative_prompt}'")
169
+ print(f"Seed: {seed}, W: {width}, H: {height}, Scale: {guidance_scale}, Steps: 20")
170
+
171
+ images = pipe(
172
+ prompt=positive_prompt,
173
+ negative_prompt=effective_negative_prompt,
174
+ width=width,
175
+ height=height,
176
+ guidance_scale=guidance_scale,
177
+ num_inference_steps=20, # Lightning models use fewer steps
178
+ num_images_per_prompt=1,
179
+ generator=torch.Generator("cuda").manual_seed(seed), # Ensure reproducibility
180
+ cross_attention_kwargs={"scale": lora_scale}, # Apply LoRA scale if needed
181
+ output_type="pil",
182
+ ).images
183
+
184
+ image_paths = [save_image(img) for img in images]
185
+ print(f"Generated {len(image_paths)} image(s).")
186
+ return image_paths, seed
187
+
188
+ except Exception as e:
189
+ print(f"Error during generation: {e}")
190
+ # Raise a Gradio error to display it in the UI
191
+ import traceback
192
+ traceback.print_exc()
193
+ raise gr.Error(f"Generation failed: {e}")
194
+
195
 
196
  examples = [
197
+ ["Realism: Man in the style of dark beige and brown, uhd image, youthful protagonists, nonrepresentational"],
198
+ ["Pixar: A young man with light brown wavy hair and light brown eyes sitting in an armchair and looking directly at the camera, pixar style, disney pixar, office background, ultra detailed, 1 man"],
199
+ ["Hoodie: Front view, capture a urban style, Superman Hoodie, technical materials, fabric small point label on text Blue theory, the design is minimal, with a raised collar, fabric is a Light yellow, low angle to capture the Hoodies form and detailing, f/5.6 to focus on the hoodies craftsmanship, solid grey background, studio light setting, with batman logo in the chest region of the t-shirt"],
200
  ]
201
 
202
  css = '''
203
+ .gradio-container{max-width: 780px !important; margin: auto;}
204
  h1{text-align:center}
205
+ #gallery { min-height: 400px; }
206
+ footer { display: none !important; visibility: hidden !important; }
 
207
  '''
 
 
 
 
 
 
 
 
 
 
 
 
 
208
 
209
+ def load_predefined_images():
210
+ predefined_images = []
211
+ asset_dir = "assets"
212
+ if os.path.exists(asset_dir):
213
+ valid_extensions = {".png", ".jpg", ".jpeg", ".webp"}
214
+ try:
215
+ for i in range(1, 10): # Try loading 1.png to 9.png
216
+ for ext in valid_extensions:
217
+ img_path = os.path.join(asset_dir, f"{i}{ext}")
218
+ if os.path.exists(img_path):
219
+ predefined_images.append(img_path)
220
+ break # Found image for this number, move to next
221
+ except Exception as e:
222
+ print(f"Error loading predefined images: {e}")
223
+ if not predefined_images:
224
+ print("No predefined images found in assets folder (e.g., assets/1.png, assets/2.jpg).")
225
  return predefined_images
226
 
227
+
228
+ # --- Gradio UI Definition ---
229
+ with gr.Blocks(css=css, theme=gr.themes.Soft()) as demo:
230
  gr.Markdown(DESCRIPTIONz)
231
+
232
+ # Define the output gallery component first
233
+ result_gallery = gr.Gallery(
234
+ label="Generated Images",
235
+ show_label=False,
236
+ elem_id="gallery", # For CSS styling
237
+ columns=1, # Adjust as needed
238
+ height="auto"
239
+ )
240
+ # Define the output seed component
241
+ output_seed = gr.State(value=0) # Use gr.State for non-displayed outputs or values needing persistence
242
+
243
  with gr.Row():
244
+ prompt = gr.Textbox(
245
+ label="Prompt",
246
+ show_label=False,
247
+ max_lines=2,
248
+ placeholder="Enter your prompt here...",
249
+ container=False,
250
+ scale=7 # Give more space to prompt
251
+ )
252
+ run_button = gr.Button("Generate", scale=1, variant="primary")
253
+
254
+ with gr.Row():
255
+ model_choice = gr.Dropdown(
256
+ label="LoRA Selection",
257
+ choices=list(LORA_OPTIONS.keys()),
258
+ value="Realism (face/character)👦🏻", # Default selection
259
+ scale=3
 
 
 
260
  )
261
+ style_selection = gr.Radio(
262
+ show_label=False, # Label provided by Row context or Accordion
263
+ container=True,
264
+ interactive=True,
265
+ choices=STYLE_NAMES,
266
+ value=DEFAULT_STYLE_NAME,
267
+ label="Quality Style",
268
+ scale=2
269
+ )
270
+
271
+
272
+ with gr.Accordion("Advanced options", open=False):
273
+ with gr.Row():
274
+ use_negative_prompt = gr.Checkbox(label="Use Negative Prompt", value=True, scale=1)
275
+ randomize_seed = gr.Checkbox(label="Randomize Seed", value=True, scale=1)
276
+ seed = gr.Slider(
277
+ label="Seed",
278
+ minimum=0,
279
+ maximum=MAX_SEED,
280
+ step=1,
281
+ value=0, # Initial value
282
+ visible=True, # Controlled by randomize_seed logic later if needed
283
+ scale=3
284
+ )
285
+
286
+
287
+ negative_prompt = gr.Textbox(
288
+ label="Negative Prompt",
289
+ lines=2,
290
+ max_lines=4,
291
+ value="(deformed, distorted, disfigured:1.3), poorly drawn, bad anatomy, wrong anatomy, extra limb, missing limb, floating limbs, (mutated hands and fingers:1.4), disconnected limbs, mutation, mutated, ugly, disgusting, blurry, amputation",
292
+ placeholder="Enter things to avoid...",
293
+ visible=True, # Controlled by use_negative_prompt checkbox
294
  )
 
295
 
296
+ with gr.Row():
297
  width = gr.Slider(
298
  label="Width",
299
  minimum=512,
300
+ maximum=1536, # Adjusted max for typical SDXL usage
301
+ step=64, # Step by 64 for common resolutions
302
  value=1024,
303
  )
304
  height = gr.Slider(
305
  label="Height",
306
  minimum=512,
307
+ maximum=1536, # Adjusted max
308
+ step=64, # Step by 64
309
  value=1024,
310
  )
 
 
311
  guidance_scale = gr.Slider(
312
+ label="Guidance Scale (CFG)",
313
+ minimum=1.0, # Usually start CFG from 1
314
+ maximum=10.0, # Lightning models often use low CFG
315
  step=0.1,
316
  value=3.0,
317
  )
318
 
319
+ # --- Event Listeners ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
 
321
+ # Toggle negative prompt visibility
322
  use_negative_prompt.change(
323
  fn=lambda x: gr.update(visible=x),
324
  inputs=use_negative_prompt,
 
326
  api_name=False,
327
  )
328
 
329
+ # Toggle seed slider visibility based on randomize checkbox
330
+ # def toggle_seed_visibility(randomize):
331
+ # return gr.update(interactive=not randomize)
332
+ # randomize_seed.change(
333
+ # fn=toggle_seed_visibility,
334
+ # inputs=randomize_seed,
335
+ # outputs=seed,
336
+ # api_name=False
337
+ # )
338
+
339
+ # --- Image Generation Trigger ---
340
+ inputs = [
341
+ prompt,
342
+ negative_prompt,
343
+ use_negative_prompt,
344
+ seed,
345
+ width,
346
+ height,
347
+ guidance_scale,
348
+ randomize_seed,
349
+ style_selection,
350
+ model_choice,
351
+ ]
352
+ # Define outputs using the created components
353
+ outputs = [
354
+ result_gallery, # The gallery to display images
355
+ output_seed # The state to hold the used seed
356
+ ]
357
+
358
+ # Connect the generate function to the button click and prompt submit
359
  gr.on(
360
+ triggers=[run_button.click, prompt.submit],
 
 
 
 
361
  fn=generate,
362
+ inputs=inputs,
363
+ outputs=outputs,
364
+ api_name="run" # Keep API name if needed
 
 
 
 
 
 
 
 
 
 
 
365
  )
366
 
367
+ # Update the seed slider display when a new seed is generated and returned via output_seed
368
+ output_seed.change(fn=lambda x: x, inputs=output_seed, outputs=seed, api_name=False)
369
 
370
+
371
+ # --- Examples ---
372
+ gr.Examples(
373
+ examples=examples,
374
+ inputs=[prompt], # Only prompt needed for examples
375
+ outputs=[result_gallery, output_seed], # Update example outputs as well
376
+ fn=generate, # Function to run when example is clicked
377
+ cache_examples=os.getenv("CACHE_EXAMPLES", "False").lower() == "true" # Cache examples in Spaces
378
+ )
379
+
380
+ # --- Predefined Image Gallery (Static) ---
381
+ with gr.Column(): # Use column for better layout control if needed
382
+ gr.Markdown("### Example Gallery (Predefined)")
383
+ try:
384
+ predefined_gallery_images = load_predefined_images()
385
+ if predefined_gallery_images:
386
+ predefined_gallery = gr.Gallery(
387
+ label="Predefined Images",
388
+ value=predefined_gallery_images,
389
+ columns=3,
390
+ show_label=False
391
+ )
392
+ else:
393
+ gr.Markdown("_(No predefined images found in 'assets' folder)_")
394
+ except Exception as e:
395
+ gr.Markdown(f"_Error loading predefined gallery: {e}_")
396
+
397
+
398
+ # --- Launch the App ---
399
  if __name__ == "__main__":
400
+ demo.queue(max_size=20).launch(debug=True) # Add debug=True for more detailed logs