openfree commited on
Commit
a87b19e
ยท
verified ยท
1 Parent(s): 40c5d1c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +228 -317
app.py CHANGED
@@ -127,108 +127,36 @@ def inference(
127
  error_img = Image.new('RGB', (width, height), color='red')
128
  return error_img, seed, load_generated_images()
129
 
130
- ###############################################################################
131
- # 2. ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ์ฒ˜๋ฆฌ ํ•จ์ˆ˜ ์ถ”๊ฐ€
132
- ###############################################################################
133
-
134
- def process_uploaded_image(
135
- image,
136
- prompt: str,
137
- seed: int,
138
- randomize_seed: bool,
139
- guidance_scale: float,
140
- num_inference_steps: int,
141
- lora_scale: float,
142
- progress: gr.Progress = gr.Progress(track_tqdm=True),
143
- ):
144
- """
145
- ์—…๋กœ๋“œ๋œ ์ด๋ฏธ์ง€๋ฅผ ์ง€๋ธŒ๋ฆฌ ์Šคํƒ€์ผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜
146
- """
147
- if image is None:
148
- return None, seed, load_generated_images()
149
-
150
- if randomize_seed:
151
- seed = random.randint(0, MAX_SEED)
152
- generator = torch.Generator(device=device).manual_seed(seed)
153
-
154
- try:
155
- # ์ด๋ฏธ์ง€ ์ „์ฒ˜๋ฆฌ
156
- if isinstance(image, np.ndarray):
157
- image_pil = Image.fromarray(image)
158
- else:
159
- image_pil = image
160
-
161
- # ์ด๋ฏธ์ง€ ํฌ๊ธฐ ์กฐ์ • (์›๋ณธ ๋น„์œจ ์œ ์ง€)
162
- width, height = image_pil.size
163
- max_size = 768
164
- if width > height:
165
- if width > max_size:
166
- ratio = max_size / width
167
- new_width = max_size
168
- new_height = int(height * ratio)
169
- else:
170
- if height > max_size:
171
- ratio = max_size / height
172
- new_height = max_size
173
- new_width = int(width * ratio)
174
-
175
- if width > max_size or height > max_size:
176
- image_pil = image_pil.resize((new_width, new_height), Image.LANCZOS)
177
-
178
- # ํ”„๋กฌํ”„ํŠธ๊ฐ€ ๋น„์–ด์žˆ๋Š” ๊ฒฝ์šฐ ๊ธฐ๋ณธ ํ”„๋กฌํ”„ํŠธ ์‚ฌ์šฉ
179
- if not prompt or prompt.strip() == "":
180
- prompt = "cat style artwork, high quality, detailed"
181
- elif "cat" not in prompt.lower() and "studio cat" not in prompt.lower():
182
- prompt = f"cat style {prompt}, high quality, detailed"
183
-
184
- # ์ด๋ฏธ์ง€ ์ƒ์„ฑ (img2img)
185
- # ์ฐธ๊ณ : ์‹ค์ œ FLUX ๋ชจ๋ธ์ด img2img๋ฅผ ์ง€์›ํ•˜๋Š”์ง€์— ๋”ฐ๋ผ ์ด ๋ถ€๋ถ„์€ ์กฐ์ • ํ•„์š”
186
- image = pipeline(
187
- prompt=prompt,
188
- image=image_pil, # ์ด๋ฏธ์ง€ ์ž…๋ ฅ
189
- guidance_scale=guidance_scale,
190
- num_inference_steps=num_inference_steps,
191
- generator=generator,
192
- joint_attention_kwargs={"scale": lora_scale},
193
- strength=0.75, # ์ ์šฉ ๊ฐ•๋„ (0: ์›๋ณธ ์œ ์ง€, 1: ์™„์ „ํžˆ ์ƒˆ๋กœ ์ƒ์„ฑ)
194
- ).images[0]
195
-
196
- filepath = save_generated_image(image, f"Uploaded image with prompt: {prompt}")
197
- return image, seed, load_generated_images()
198
-
199
- except Exception as e:
200
- logging.error(f"Error during image processing: {e}")
201
- return image, seed, load_generated_images()
202
-
203
-
204
  ###############################################################################
205
  # 3. Gradio UI
206
  ###############################################################################
207
 
208
  examples = [
209
- "cat style futuristic stormtrooper with glossy white armor and a sleek helmet, standing heroically on a lush alien planet, vibrant flowers blooming around, soft sunlight illuminating the scene, a gentle breeze rustling the leaves. The armor reflects the pink and purple hues of the alien sunset, creating an ethereal glow around the figure. [trigger]",
210
- "cat style wonder woman, she saying \"hello\" in 'speech bubble', her blue costume shining under the sun, surrounded by floating islands with waterfalls, magical sparkles in the air. [trigger]",
211
- "cat style ancient forest guardian robot, covered in moss and flowering vines, sitting peacefully in a crystal-clear lake. Its gentle eyes glow with soft blue light, while bioluminescent dragonflies dance around its weathered metal frame. Ancient tech symbols on its surface pulse with a gentle rhythm. [trigger]",
212
- "cat style superhero girl saying \"I will protect you\" in a 'speech bubble', her cape flowing in the wind as she stands on a rooftop at sunset, with city lights beginning to twinkle below. [trigger]",
213
- "cat style cyber-shrine maiden with flowing holographic robes, performing a ritual dance among floating lanterns and digital cherry blossoms. Her traditional headdress emits soft light patterns, while spirit-like AI constructs swirl around her in elegant patterns. The scene is set in a modern shrine with both ancient wood and sleek chrome elements. [trigger]",
214
- "cat style robot farmer saying \"Harvest time!\" in 'speech bubble', tending to floating rice paddies in the sky, wearing a traditional straw hat with advanced sensors, surrounded by flying fish that leave trails of sparkles. [trigger]"
215
  ]
216
 
217
  css = """
218
  :root {
219
- --primary-color: #6a92cc;
220
- --primary-hover: #557ab8;
221
- --secondary-color: #f4c062;
222
- --background-color: #f7f9fc;
 
223
  --panel-background: #ffffff;
224
- --text-color: #333333;
225
- --border-radius: 12px;
226
- --shadow: 0 4px 12px rgba(0,0,0,0.08);
227
  --font-main: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;
228
  }
229
  body {
230
  background-color: var(--background-color);
231
  font-family: var(--font-main);
 
232
  }
233
  .gradio-container {
234
  margin: 0 auto;
@@ -236,29 +164,57 @@ body {
236
  }
237
  .main-header {
238
  text-align: center;
239
- padding: 2rem 1rem 1rem;
240
- background: linear-gradient(90deg, #6a92cc 0%, #8f7fc8 100%);
241
  color: white;
242
  margin-bottom: 2rem;
243
  border-radius: var(--border-radius);
244
  box-shadow: var(--shadow);
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  }
246
  .main-header h1 {
247
- font-size: 2.5rem;
248
  margin-bottom: 0.5rem;
249
- font-weight: 700;
250
- text-shadow: 0 2px 4px rgba(0,0,0,0.2);
 
251
  }
252
  .main-header p {
253
- font-size: 1rem;
254
- margin-bottom: 0.5rem;
 
 
 
 
 
 
 
 
 
 
255
  opacity: 0.9;
 
 
 
256
  }
257
  .main-header a {
258
- color: var(--secondary-color);
259
  text-decoration: none;
260
  font-weight: 600;
261
  transition: all 0.2s ease;
 
262
  }
263
  .main-header a:hover {
264
  text-decoration: underline;
@@ -266,51 +222,62 @@ body {
266
  }
267
  .container {
268
  background-color: var(--panel-background);
269
- padding: 1.5rem;
270
  border-radius: var(--border-radius);
271
  box-shadow: var(--shadow);
272
- margin-bottom: 1.5rem;
 
273
  }
274
  button.primary {
275
  background: var(--primary-color) !important;
 
276
  border: none !important;
277
  color: white !important;
278
- padding: 10px 20px !important;
279
- border-radius: 8px !important;
280
  font-weight: 600 !important;
281
- box-shadow: 0 2px 5px rgba(0,0,0,0.1) !important;
282
- transition: all 0.2s ease !important;
 
 
283
  }
284
  button.primary:hover {
285
- background: var(--primary-hover) !important;
286
- transform: translateY(-2px) !important;
287
- box-shadow: 0 4px 8px rgba(0,0,0,0.15) !important;
288
  }
289
  button.secondary {
290
  background: white !important;
291
- border: 1px solid #ddd !important;
292
- color: var(--text-color) !important;
293
- padding: 10px 20px !important;
294
- border-radius: 8px !important;
295
  font-weight: 500 !important;
296
- box-shadow: 0 2px 5px rgba(0,0,0,0.05) !important;
297
- transition: all 0.2s ease !important;
298
  }
299
  button.secondary:hover {
300
- background: #f5f5f5 !important;
301
  transform: translateY(-2px) !important;
 
302
  }
303
  .gr-box {
304
  border-radius: var(--border-radius) !important;
305
- border: 1px solid #e0e0e0 !important;
306
  }
307
  .gr-panel {
308
  border-radius: var(--border-radius) !important;
309
  }
310
  .gr-input {
311
- border-radius: 8px !important;
312
- border: 1px solid #ddd !important;
313
  padding: 12px !important;
 
 
 
 
 
 
314
  }
315
  .gr-form {
316
  border-radius: var(--border-radius) !important;
@@ -319,17 +286,21 @@ button.secondary:hover {
319
  .gr-accordion {
320
  border-radius: var(--border-radius) !important;
321
  overflow: hidden !important;
 
322
  }
323
  .gr-button {
324
- border-radius: 8px !important;
325
  }
326
  .gallery-item {
327
  border-radius: var(--border-radius) !important;
328
  transition: all 0.3s ease !important;
 
 
329
  }
330
  .gallery-item:hover {
331
- transform: scale(1.02) !important;
332
- box-shadow: 0 6px 15px rgba(0,0,0,0.1) !important;
 
333
  }
334
  .tabs {
335
  border-radius: var(--border-radius) !important;
@@ -340,60 +311,66 @@ footer {
340
  }
341
  .settings-accordion legend span {
342
  font-weight: 600 !important;
 
343
  }
344
  .example-prompt {
345
- font-size: 0.9rem;
346
- color: #555;
347
- padding: 8px;
348
- background: #f5f7fa;
349
- border-radius: 6px;
350
- border-left: 3px solid var(--primary-color);
351
- margin-bottom: 8px;
352
  cursor: pointer;
353
- transition: all 0.2s;
 
354
  }
355
  .example-prompt:hover {
356
- background: #eef2f8;
 
 
357
  }
358
  .status-generating {
359
- color: #ffa200;
360
- font-weight: 500;
361
  display: flex;
362
  align-items: center;
363
  gap: 8px;
 
364
  }
365
  .status-generating::before {
366
  content: "";
367
  display: inline-block;
368
- width: 12px;
369
- height: 12px;
370
  border-radius: 50%;
371
- background-color: #ffa200;
372
  animation: pulse 1.5s infinite;
373
  }
374
  .status-complete {
375
- color: #00c853;
376
- font-weight: 500;
377
  display: flex;
378
  align-items: center;
379
  gap: 8px;
 
380
  }
381
  .status-complete::before {
382
  content: "";
383
  display: inline-block;
384
- width: 12px;
385
- height: 12px;
386
  border-radius: 50%;
387
- background-color: #00c853;
388
  }
389
  @keyframes pulse {
390
- 0% { opacity: 0.6; }
391
- 50% { opacity: 1; }
392
- 100% { opacity: 0.6; }
393
  }
394
  .gr-accordion-title {
395
  font-weight: 600 !important;
396
- color: var(--text-color) !important;
397
  }
398
  .tabs button {
399
  font-weight: 500 !important;
@@ -402,15 +379,16 @@ footer {
402
  .tabs button.selected {
403
  font-weight: 600 !important;
404
  color: var(--primary-color) !important;
405
- background: rgba(106, 146, 204, 0.1) !important;
406
  }
407
  .gr-slider-container {
408
  padding: 10px 0 !important;
409
  }
410
  .gr-prose h3 {
411
- font-weight: 600 !important;
412
  color: var(--primary-color) !important;
413
  margin-bottom: 1rem !important;
 
414
  }
415
  .tab-nav {
416
  margin-bottom: 1rem !important;
@@ -418,157 +396,128 @@ footer {
418
  border-radius: var(--border-radius) !important;
419
  overflow: hidden !important;
420
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
421
  """
422
 
423
  with gr.Blocks(css=css, analytics_enabled=False, theme="soft") as demo:
424
  with gr.Column():
425
  gr.HTML('''
426
  <div class="main-header">
427
- <h1>โœจ FLUX cat LoRA Generator โœจ</h1>
 
 
428
  <p>Community: <a href="https://discord.gg/openfreeai" target="_blank">https://discord.gg/openfreeai</a></p>
429
  </div>
430
  ''')
431
 
432
- with gr.Tabs() as mode_tabs:
433
- # ํ…์ŠคํŠธ-์ด๋ฏธ์ง€ ์ƒ์„ฑ ํƒญ
434
- with gr.TabItem("Text-to-Image") as text_to_image_tab:
435
- with gr.Row():
436
- with gr.Column(scale=3):
437
- with gr.Group(elem_classes="container"):
438
- prompt = gr.Textbox(
439
- label="Enter your imagination",
440
- placeholder="Describe your cat-style image here...",
441
- lines=3
442
- )
443
-
444
- with gr.Row():
445
- run_button = gr.Button("โœจ Generate Image", elem_classes="primary")
446
- clear_button = gr.Button("Clear", elem_classes="secondary")
447
-
448
- with gr.Accordion("Advanced Settings", open=False, elem_classes="settings-accordion"):
449
- with gr.Row():
450
- seed = gr.Slider(
451
- label="Seed",
452
- minimum=0,
453
- maximum=MAX_SEED,
454
- step=1,
455
- value=42,
456
- )
457
- randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
458
- with gr.Row():
459
- width = gr.Slider(
460
- label="Width",
461
- minimum=256,
462
- maximum=MAX_IMAGE_SIZE,
463
- step=32,
464
- value=1024,
465
- )
466
- height = gr.Slider(
467
- label="Height",
468
- minimum=256,
469
- maximum=MAX_IMAGE_SIZE,
470
- step=32,
471
- value=768,
472
- )
473
- with gr.Row():
474
- guidance_scale = gr.Slider(
475
- label="Guidance scale",
476
- minimum=0.0,
477
- maximum=10.0,
478
- step=0.1,
479
- value=3.5,
480
- )
481
- with gr.Row():
482
- num_inference_steps = gr.Slider(
483
- label="Steps",
484
- minimum=1,
485
- maximum=50,
486
- step=1,
487
- value=30,
488
- )
489
- lora_scale = gr.Slider(
490
- label="LoRA scale",
491
- minimum=0.0,
492
- maximum=1.0,
493
- step=0.1,
494
- value=1.0,
495
- )
496
 
497
- with gr.Group(elem_classes="container"):
498
- gr.Markdown("### โœจ Example Prompts")
499
- examples_html = '\n'.join([f'<div class="example-prompt">{ex}</div>' for ex in examples])
500
- example_container = gr.HTML(examples_html)
501
-
502
- with gr.Column(scale=4):
503
- with gr.Group(elem_classes="container"):
504
- generation_status = gr.HTML('<div class="status-complete">Ready to generate</div>')
505
- result = gr.Image(label="Generated Image", elem_id="result-image")
506
- seed_text = gr.Number(label="Used Seed", value=42)
507
-
508
- # ์ด๋ฏธ์ง€-์ด๋ฏธ์ง€ ๋ณ€ํ™˜ ํƒญ
509
- with gr.TabItem("Image-to-Image") as image_to_image_tab:
510
- with gr.Row():
511
- with gr.Column(scale=3):
512
- with gr.Group(elem_classes="container"):
513
- upload_image = gr.Image(
514
- label="Upload your image",
515
- type="pil",
516
- elem_id="upload-image"
517
- )
518
- img2img_prompt = gr.Textbox(
519
- label="Optional: Describe additional details",
520
- placeholder="Add details or leave empty for default cat style...",
521
- lines=2
522
- )
523
-
524
  with gr.Row():
525
- process_button = gr.Button("๐ŸŽจ Process Image", elem_classes="primary")
526
- clear_img_button = gr.Button("Clear", elem_classes="secondary")
527
-
528
- with gr.Accordion("Advanced Settings", open=False, elem_classes="settings-accordion"):
529
- with gr.Row():
530
- img2img_seed = gr.Slider(
531
- label="Seed",
532
- minimum=0,
533
- maximum=MAX_SEED,
534
- step=1,
535
- value=42,
536
- )
537
- img2img_random_seed = gr.Checkbox(label="Randomize seed", value=True)
538
- with gr.Row():
539
- img2img_guidance_scale = gr.Slider(
540
- label="Guidance scale",
541
- minimum=0.0,
542
- maximum=10.0,
543
- step=0.1,
544
- value=3.5,
545
- )
546
- with gr.Row():
547
- img2img_steps = gr.Slider(
548
- label="Steps",
549
- minimum=1,
550
- maximum=50,
551
- step=1,
552
- value=30,
553
- )
554
- img2img_lora_scale = gr.Slider(
555
- label="LoRA scale",
556
- minimum=0.0,
557
- maximum=1.0,
558
- step=0.1,
559
- value=1.0,
560
- )
 
 
 
 
 
 
 
 
 
 
561
 
562
- with gr.Column(scale=4):
563
- with gr.Group(elem_classes="container"):
564
- img2img_status = gr.HTML('<div class="status-complete">Ready to process</div>')
565
- img2img_result = gr.Image(label="Processed Image", elem_id="img2img-result")
566
- img2img_seed_text = gr.Number(label="Used Seed", value=42)
 
 
 
 
 
567
 
568
  with gr.Group(elem_classes="container"):
569
  with gr.Tabs(elem_classes="tabs") as gallery_tabs:
570
- with gr.TabItem("Gallery"):
571
- gallery_header = gr.Markdown("### ๐Ÿ–ผ๏ธ Your Generated Masterpieces")
572
  with gr.Row():
573
  refresh_btn = gr.Button("๐Ÿ”„ Refresh Gallery", elem_classes="secondary")
574
  generated_gallery = gr.Gallery(
@@ -588,20 +537,11 @@ with gr.Blocks(css=css, analytics_enabled=False, theme="soft") as demo:
588
  def clear_output():
589
  return "", gr.update(value=None), seed, '<div class="status-complete">Ready to generate</div>'
590
 
591
- def clear_img2img_output():
592
- return None, "", img2img_seed, '<div class="status-complete">Ready to process</div>', None
593
-
594
  def before_generate():
595
- return '<div class="status-generating">Generating image...</div>'
596
-
597
- def before_process_image():
598
- return '<div class="status-generating">Processing image...</div>'
599
 
600
  def after_generate(image, seed_num, gallery):
601
- return image, seed_num, gallery, '<div class="status-complete">Generation complete!</div>'
602
-
603
- def after_process_image(image, seed_num, gallery):
604
- return image, seed_num, gallery, '<div class="status-complete">Processing complete!</div>'
605
 
606
  ###########################################################################
607
  # Gradio Event Wiring
@@ -665,35 +605,6 @@ with gr.Blocks(css=css, analytics_enabled=False, theme="soft") as demo:
665
  outputs=[result, seed_text, generated_gallery, generation_status],
666
  )
667
 
668
- # ์ด๋ฏธ์ง€-์ด๋ฏธ์ง€ ๋ณ€ํ™˜ ์ด๋ฒคํŠธ
669
- clear_img_button.click(
670
- fn=clear_img2img_output,
671
- inputs=None,
672
- outputs=[upload_image, img2img_prompt, img2img_seed_text, img2img_status, img2img_result]
673
- )
674
-
675
- process_button.click(
676
- fn=before_process_image,
677
- inputs=None,
678
- outputs=img2img_status,
679
- ).then(
680
- fn=process_uploaded_image,
681
- inputs=[
682
- upload_image,
683
- img2img_prompt,
684
- img2img_seed,
685
- img2img_random_seed,
686
- img2img_guidance_scale,
687
- img2img_steps,
688
- img2img_lora_scale,
689
- ],
690
- outputs=[img2img_result, img2img_seed_text, generated_gallery],
691
- ).then(
692
- fn=after_process_image,
693
- inputs=[img2img_result, img2img_seed_text, generated_gallery],
694
- outputs=[img2img_result, img2img_seed_text, generated_gallery, img2img_status],
695
- )
696
-
697
  # JS๋กœ ์˜ˆ์‹œ prompt ํด๋ฆญ ์‹œ ์ž๋™ ์ฑ„์šฐ๊ธฐ
698
  gr.HTML("""
699
  <script>
 
127
  error_img = Image.new('RGB', (width, height), color='red')
128
  return error_img, seed, load_generated_images()
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  ###############################################################################
131
  # 3. Gradio UI
132
  ###############################################################################
133
 
134
  examples = [
135
+ "cat style cosmic explorer with starry fur, floating in a nebula of vibrant pink and purple clouds, mystical glowing eyes, surrounded by tiny planets and cosmic dust. Extremely detailed, artistic masterpiece. [trigger]",
136
+ "cat style samurai warrior with ornate armor decorated with cherry blossoms, sitting in meditation under a moonlit waterfall, katana resting beside, glowing spiritual aura, ultra-detailed metallic reflections. [trigger]",
137
+ "cat style magical librarian in an ancient floating library, surrounded by flying books with glowing runes, wearing wizards robes with star patterns, soft magical lighting, shelves extending to infinity, detailed bookbindings. [trigger]",
138
+ "cat style royal empress with jeweled crown and elaborate golden silk robes, sitting on a throne made of jade and cherry blossoms, palace backdrop with ornate architecture, atmospheric lighting, ultra-detailed embroidery patterns. [trigger]",
139
+ "cat style mystical forest guardian, fur intertwined with vines and flowers, ancient moss-covered stone artifacts floating around, emerald glowing eyes, sunbeams filtering through dense canopy, magical particles in the air, studio quality. [trigger]",
140
+ "cat style space astronaut on an alien planet, exploring crystal caves with bioluminescent plants, helmet reflecting the colorful surroundings, paw prints leaving glowing marks, scientific equipment, cinematic lighting, highly detailed suit. [trigger]"
141
  ]
142
 
143
  css = """
144
  :root {
145
+ --primary-color: #ff7e5f;
146
+ --primary-hover: #ff6347;
147
+ --secondary-color: #feb47b;
148
+ --tertiary-color: #ffead0;
149
+ --background-color: #f9f4f0;
150
  --panel-background: #ffffff;
151
+ --text-color: #4a3933;
152
+ --border-radius: 16px;
153
+ --shadow: 0 8px 24px rgba(255, 126, 95, 0.12);
154
  --font-main: 'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;
155
  }
156
  body {
157
  background-color: var(--background-color);
158
  font-family: var(--font-main);
159
+ color: var(--text-color);
160
  }
161
  .gradio-container {
162
  margin: 0 auto;
 
164
  }
165
  .main-header {
166
  text-align: center;
167
+ padding: 2.5rem 1.5rem 1.5rem;
168
+ background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
169
  color: white;
170
  margin-bottom: 2rem;
171
  border-radius: var(--border-radius);
172
  box-shadow: var(--shadow);
173
+ position: relative;
174
+ overflow: hidden;
175
+ }
176
+ .main-header::before {
177
+ content: "";
178
+ position: absolute;
179
+ top: 0;
180
+ left: 0;
181
+ right: 0;
182
+ bottom: 0;
183
+ background: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><path d="M44,98.1c0.1-17.7,7.2-31.9,18.9-43.5c7.5-7.3,16.5-12,26.5-15c29.9-8.8,59.7,4.9,73.2,33.2c8.1,17,7.1,34.2-0.7,51c-8.3,17.8-22.4,29.5-41.4,34.7c-18.5,5-36.1,1.4-51.7-9.8C51.7,136.6,43.9,118.9,44,98.1z M172.8,96.6c0-14.2-2.3-27.1-8.3-39.1c-12.7-25.4-33.9-37.7-61.8-37C74.2,21.1,50.8,46.9,46,75.5c-4.7,28.4,8.5,59.6,45.2,72.7c15.5,5.6,31.2,5.3,46.5-0.8C162.6,138.1,172.9,119.4,172.8,96.6z" fill="rgba(255,255,255,0.05)"/><path d="M117.3,75.5c-0.5-4.7-0.4-9.8-2.9-14c-7.3-12.3-30.9-12.8-37.4,2.1c-2.5,5.8-1.2,12.2-1.8,18.3c-0.2,1.1-0.1,2.3-0.6,3.2c-2.2,5-4.3,10.1-2.5,15.7c0.1,0.3,0.2,0.6,0.2,0.9c0.5,4.2-0.5,7.1-5.5,8c-1.7,0.3-3.3,1-4.9,1.5c0.4,2.6,0.6,5.2,1.3,7.8c0.7,2.6,2.5,5.2,1.5,8.1c-0.5,1.4-2.9,2.7-4.4,2.7c-12.9-0.2-12.5,7.2-13.5,15.9c-0.9,7.9-2,14.4,7.1,19.5c1.7,1,2.1,4.5,2.3,6.9c0.7,9.3,7.1,14.4,15.6,16c4.4,0.8,9.1,1.9,13.5,1.1c5.5-1,9-9.6,7.7-19.2c-0.6-4.6,0.4-8.2,4.9-10.2c1.8-0.8,3.9-1.3,5.8-1.4c6-0.2,12.1-0.3,18.1-0.5c8.8-0.2,16.5-3.4,22.1-10.3c8.3-10.1,17.6-15.1,30.9-11.1c0.6,0.2,1.3,0.1,2.5,0.2c-0.4-9.3-1.4-18.3-10.8-22.7c-2.8-1.3-5.9-2.6-7.9-4.8c-9.3-10.5-18.2-21.3-27.5-31.8c-4.9-5.5-10.4-10.4-15.8-15.5c-2.7-2.5-6.9-4.4-6.3-8.8c0.6-4.4,5.2-5.1,8.8-5.9c6.3-1.4,12-3.7,11.4-11.4c-0.5-5.2-5.5-10.4-11.7-9.8c-3.2,0.3-6.4,0.8-9.6,1.5c-10,2.5-11.8,12.1-17.5,19c-1.5,1.7-2.5,4.4-6,2.9c-3.1-1.3-6.4-3.1-6.3-7c0.1-4.1,3.7-5.7,6.9-7.2c10.3-5,18.2-12.2,19.6-24.2c0.3-2.5,0.9-4.9-0.7-7.2c-1.2-1.7-2.7-3.1-4.2-4.6c-0.6-0.6-1.5-1.1-2.3-1.1c-6.8,0-11.5,5.4-16.9,7c-0.1-0.3-0.3-0.5-0.4-0.8c5.2-4.6,10.5-9.1,16.7-14.5c-1.6-2.2-2.9-5.1-5.1-6.5c-1.4-0.9-5.6,0.1-7.1,1.7c-5.3,5.6-10.2,11.5-14.3,18.9c-1.1-1.3-1.3-2.2-1.8-2.2c-6.9,0.7-13.7,1.4-20.6,2.3c-2.2,0.3-5.7,1.5-6.2,3c-0.9,2.8,0.5,6.3,1.3,9.5c2.4,0.8,4.9,1.5,7.3,2.2c10.1,2.5,16.9,13.6,14.8,24.2c-1.9,9.6-9.3,15.6-19.1,15.4c-2.6-0.1-5.1-1.2-7.6-1.9c-3.2-0.9-6.5-2.3-9.6-2.1c-3.8,0.2-4.8,4.3-4.9,8c-0.2,5.2,3.1,6.6,7.1,6.9c6.9,0.5,13.9,0.5,20.8,1c6.1,0.4,10.8,3.7,14.7,8.1C112.6,69.5,115,72.4,117.3,75.5z M94.5,100.5c0.2,13.8,11.7,25,25.6,24.8c13.9-0.1,25.1-11.3,25.1-25c0-14-11.3-25.3-25.2-25.3C106.1,75.1,94.3,86.7,94.5,100.5z" fill="rgba(255,255,255,0.08)"/></svg>') no-repeat center center;
184
+ background-size: 180px;
185
+ opacity: 0.5;
186
  }
187
  .main-header h1 {
188
+ font-size: 3rem;
189
  margin-bottom: 0.5rem;
190
+ font-weight: 800;
191
+ text-shadow: 0 2px 5px rgba(0,0,0,0.2);
192
+ position: relative;
193
  }
194
  .main-header p {
195
+ font-size: 1.1rem;
196
+ margin: 1rem 0;
197
+ opacity: 0.95;
198
+ position: relative;
199
+ font-weight: 500;
200
+ max-width: 800px;
201
+ margin-left: auto;
202
+ margin-right: auto;
203
+ line-height: 1.6;
204
+ }
205
+ .main-header .tribute {
206
+ font-style: italic;
207
  opacity: 0.9;
208
+ font-size: 1rem;
209
+ margin-top: 1rem;
210
+ position: relative;
211
  }
212
  .main-header a {
213
+ color: var(--tertiary-color);
214
  text-decoration: none;
215
  font-weight: 600;
216
  transition: all 0.2s ease;
217
+ position: relative;
218
  }
219
  .main-header a:hover {
220
  text-decoration: underline;
 
222
  }
223
  .container {
224
  background-color: var(--panel-background);
225
+ padding: 2rem;
226
  border-radius: var(--border-radius);
227
  box-shadow: var(--shadow);
228
+ margin-bottom: 2rem;
229
+ border: 1px solid rgba(255, 126, 95, 0.1);
230
  }
231
  button.primary {
232
  background: var(--primary-color) !important;
233
+ background: linear-gradient(90deg, var(--primary-color) 0%, var(--secondary-color) 100%) !important;
234
  border: none !important;
235
  color: white !important;
236
+ padding: 12px 24px !important;
237
+ border-radius: 12px !important;
238
  font-weight: 600 !important;
239
+ box-shadow: 0 4px 10px rgba(255, 126, 95, 0.3) !important;
240
+ transition: all 0.3s ease !important;
241
+ font-size: 1.05rem !important;
242
+ letter-spacing: 0.5px !important;
243
  }
244
  button.primary:hover {
245
+ background: linear-gradient(90deg, var(--primary-hover) 0%, var(--secondary-color) 100%) !important;
246
+ transform: translateY(-3px) !important;
247
+ box-shadow: 0 6px 15px rgba(255, 126, 95, 0.4) !important;
248
  }
249
  button.secondary {
250
  background: white !important;
251
+ border: 1px solid rgba(255, 126, 95, 0.3) !important;
252
+ color: var(--primary-color) !important;
253
+ padding: 12px 24px !important;
254
+ border-radius: 12px !important;
255
  font-weight: 500 !important;
256
+ box-shadow: 0 2px 5px rgba(255, 126, 95, 0.1) !important;
257
+ transition: all 0.3s ease !important;
258
  }
259
  button.secondary:hover {
260
+ background: rgba(255, 126, 95, 0.05) !important;
261
  transform: translateY(-2px) !important;
262
+ box-shadow: 0 4px 8px rgba(255, 126, 95, 0.15) !important;
263
  }
264
  .gr-box {
265
  border-radius: var(--border-radius) !important;
266
+ border: 1px solid rgba(255, 126, 95, 0.2) !important;
267
  }
268
  .gr-panel {
269
  border-radius: var(--border-radius) !important;
270
  }
271
  .gr-input {
272
+ border-radius: 12px !important;
273
+ border: 1px solid rgba(255, 126, 95, 0.3) !important;
274
  padding: 12px !important;
275
+ transition: all 0.3s ease !important;
276
+ font-size: 1rem !important;
277
+ }
278
+ .gr-input:focus {
279
+ border-color: var(--primary-color) !important;
280
+ box-shadow: 0 0 0 2px rgba(255, 126, 95, 0.2) !important;
281
  }
282
  .gr-form {
283
  border-radius: var(--border-radius) !important;
 
286
  .gr-accordion {
287
  border-radius: var(--border-radius) !important;
288
  overflow: hidden !important;
289
+ border: 1px solid rgba(255, 126, 95, 0.15) !important;
290
  }
291
  .gr-button {
292
+ border-radius: 12px !important;
293
  }
294
  .gallery-item {
295
  border-radius: var(--border-radius) !important;
296
  transition: all 0.3s ease !important;
297
+ overflow: hidden !important;
298
+ border: 3px solid transparent !important;
299
  }
300
  .gallery-item:hover {
301
+ transform: scale(1.03) !important;
302
+ box-shadow: 0 8px 20px rgba(255, 126, 95, 0.2) !important;
303
+ border: 3px solid var(--primary-color) !important;
304
  }
305
  .tabs {
306
  border-radius: var(--border-radius) !important;
 
311
  }
312
  .settings-accordion legend span {
313
  font-weight: 600 !important;
314
+ color: var(--primary-color) !important;
315
  }
316
  .example-prompt {
317
+ font-size: 0.95rem;
318
+ color: var(--text-color);
319
+ padding: 12px 16px;
320
+ background: linear-gradient(to right, rgba(255, 126, 95, 0.05), rgba(254, 180, 123, 0.1));
321
+ border-radius: 12px;
322
+ border-left: 4px solid var(--primary-color);
323
+ margin-bottom: 12px;
324
  cursor: pointer;
325
+ transition: all 0.3s;
326
+ box-shadow: 0 2px 5px rgba(255, 126, 95, 0.05);
327
  }
328
  .example-prompt:hover {
329
+ background: linear-gradient(to right, rgba(255, 126, 95, 0.1), rgba(254, 180, 123, 0.15));
330
+ transform: translateX(5px);
331
+ box-shadow: 0 3px 8px rgba(255, 126, 95, 0.1);
332
  }
333
  .status-generating {
334
+ color: var(--secondary-color);
335
+ font-weight: 600;
336
  display: flex;
337
  align-items: center;
338
  gap: 8px;
339
+ font-size: 1.05rem;
340
  }
341
  .status-generating::before {
342
  content: "";
343
  display: inline-block;
344
+ width: 14px;
345
+ height: 14px;
346
  border-radius: 50%;
347
+ background-color: var(--secondary-color);
348
  animation: pulse 1.5s infinite;
349
  }
350
  .status-complete {
351
+ color: #4caf50;
352
+ font-weight: 600;
353
  display: flex;
354
  align-items: center;
355
  gap: 8px;
356
+ font-size: 1.05rem;
357
  }
358
  .status-complete::before {
359
  content: "";
360
  display: inline-block;
361
+ width: 14px;
362
+ height: 14px;
363
  border-radius: 50%;
364
+ background-color: #4caf50;
365
  }
366
  @keyframes pulse {
367
+ 0% { opacity: 0.6; transform: scale(0.9); }
368
+ 50% { opacity: 1; transform: scale(1.1); }
369
+ 100% { opacity: 0.6; transform: scale(0.9); }
370
  }
371
  .gr-accordion-title {
372
  font-weight: 600 !important;
373
+ color: var(--primary-color) !important;
374
  }
375
  .tabs button {
376
  font-weight: 500 !important;
 
379
  .tabs button.selected {
380
  font-weight: 600 !important;
381
  color: var(--primary-color) !important;
382
+ background: rgba(255, 126, 95, 0.1) !important;
383
  }
384
  .gr-slider-container {
385
  padding: 10px 0 !important;
386
  }
387
  .gr-prose h3 {
388
+ font-weight: 700 !important;
389
  color: var(--primary-color) !important;
390
  margin-bottom: 1rem !important;
391
+ font-size: 1.2rem !important;
392
  }
393
  .tab-nav {
394
  margin-bottom: 1rem !important;
 
396
  border-radius: var(--border-radius) !important;
397
  overflow: hidden !important;
398
  }
399
+ .gr-slider-thumb {
400
+ background: var(--primary-color) !important;
401
+ }
402
+ .gr-slider-track {
403
+ background: linear-gradient(90deg, var(--primary-color) 0%, var(--secondary-color) 100%) !important;
404
+ }
405
+ .cat-icon {
406
+ display: inline-block;
407
+ font-size: 1.8em;
408
+ margin-right: 0.3em;
409
+ vertical-align: middle;
410
+ }
411
+ .gr-gallery {
412
+ display: grid !important;
413
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)) !important;
414
+ gap: 16px !important;
415
+ padding: 16px !important;
416
+ }
417
+ #result-image .gr-image-viewer {
418
+ border-radius: var(--border-radius);
419
+ overflow: hidden;
420
+ box-shadow: 0 5px 15px rgba(255, 126, 95, 0.1);
421
+ transition: all 0.3s ease;
422
+ }
423
+ #result-image .gr-image-viewer:hover {
424
+ box-shadow: 0 8px 25px rgba(255, 126, 95, 0.2);
425
+ }
426
+ .gr-padded {
427
+ padding: 0 !important;
428
+ }
429
  """
430
 
431
  with gr.Blocks(css=css, analytics_enabled=False, theme="soft") as demo:
432
  with gr.Column():
433
  gr.HTML('''
434
  <div class="main-header">
435
+ <h1><span class="cat-icon">๐Ÿฑโœจ</span> FLUX Cat LoRA Generator</h1>
436
+ <p>Generate beautiful cat-styled images with this specialized LoRA model. Simply enter your prompt and watch the magic happen!</p>
437
+ <p class="tribute">This project is a tribute to the first-ever "cat" LoRA model on Hugging Face, honoring its pioneering contribution to stylized AI image generation.</p>
438
  <p>Community: <a href="https://discord.gg/openfreeai" target="_blank">https://discord.gg/openfreeai</a></p>
439
  </div>
440
  ''')
441
 
442
+ # Text-to-Image tab only (removed Image-to-Image tab)
443
+ with gr.Column():
444
+ with gr.Row():
445
+ with gr.Column(scale=3):
446
+ with gr.Group(elem_classes="container"):
447
+ prompt = gr.Textbox(
448
+ label="Enter your imagination",
449
+ placeholder="Describe your cat-style image here... (e.g., 'cat style majestic warrior with armor')",
450
+ lines=3
451
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
452
 
453
+ with gr.Row():
454
+ run_button = gr.Button("โœจ Generate Purrfect Image", elem_classes="primary")
455
+ clear_button = gr.Button("Clear", elem_classes="secondary")
456
+
457
+ with gr.Accordion("Advanced Settings", open=False, elem_classes="settings-accordion"):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  with gr.Row():
459
+ seed = gr.Slider(
460
+ label="Seed",
461
+ minimum=0,
462
+ maximum=MAX_SEED,
463
+ step=1,
464
+ value=42,
465
+ )
466
+ randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
467
+ with gr.Row():
468
+ width = gr.Slider(
469
+ label="Width",
470
+ minimum=256,
471
+ maximum=MAX_IMAGE_SIZE,
472
+ step=32,
473
+ value=1024,
474
+ )
475
+ height = gr.Slider(
476
+ label="Height",
477
+ minimum=256,
478
+ maximum=MAX_IMAGE_SIZE,
479
+ step=32,
480
+ value=768,
481
+ )
482
+ with gr.Row():
483
+ guidance_scale = gr.Slider(
484
+ label="Guidance scale",
485
+ minimum=0.0,
486
+ maximum=10.0,
487
+ step=0.1,
488
+ value=3.5,
489
+ )
490
+ with gr.Row():
491
+ num_inference_steps = gr.Slider(
492
+ label="Steps",
493
+ minimum=1,
494
+ maximum=50,
495
+ step=1,
496
+ value=30,
497
+ )
498
+ lora_scale = gr.Slider(
499
+ label="LoRA scale",
500
+ minimum=0.0,
501
+ maximum=1.0,
502
+ step=0.1,
503
+ value=1.0,
504
+ )
505
 
506
+ with gr.Group(elem_classes="container"):
507
+ gr.Markdown("### โœจ Inspirational Cat Prompts")
508
+ examples_html = '\n'.join([f'<div class="example-prompt">{ex}</div>' for ex in examples])
509
+ example_container = gr.HTML(examples_html)
510
+
511
+ with gr.Column(scale=4):
512
+ with gr.Group(elem_classes="container"):
513
+ generation_status = gr.HTML('<div class="status-complete">Ready to generate</div>')
514
+ result = gr.Image(label="Generated Cat Image", elem_id="result-image")
515
+ seed_text = gr.Number(label="Used Seed", value=42)
516
 
517
  with gr.Group(elem_classes="container"):
518
  with gr.Tabs(elem_classes="tabs") as gallery_tabs:
519
+ with gr.TabItem("Cat Gallery"):
520
+ gallery_header = gr.Markdown("### ๐Ÿ–ผ๏ธ Your Cat-tastic Creations")
521
  with gr.Row():
522
  refresh_btn = gr.Button("๐Ÿ”„ Refresh Gallery", elem_classes="secondary")
523
  generated_gallery = gr.Gallery(
 
537
  def clear_output():
538
  return "", gr.update(value=None), seed, '<div class="status-complete">Ready to generate</div>'
539
 
 
 
 
540
  def before_generate():
541
+ return '<div class="status-generating">Creating cat masterpiece...</div>'
 
 
 
542
 
543
  def after_generate(image, seed_num, gallery):
544
+ return image, seed_num, gallery, '<div class="status-complete">Meow-gnificent creation complete!</div>'
 
 
 
545
 
546
  ###########################################################################
547
  # Gradio Event Wiring
 
605
  outputs=[result, seed_text, generated_gallery, generation_status],
606
  )
607
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
608
  # JS๋กœ ์˜ˆ์‹œ prompt ํด๋ฆญ ์‹œ ์ž๋™ ์ฑ„์šฐ๊ธฐ
609
  gr.HTML("""
610
  <script>