Spaces:
Running
on
Zero
Running
on
Zero
Update app.py
Browse files
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
|
210 |
-
"cat style
|
211 |
-
"cat style
|
212 |
-
"cat style
|
213 |
-
"cat style
|
214 |
-
"cat style
|
215 |
]
|
216 |
|
217 |
css = """
|
218 |
:root {
|
219 |
-
--primary-color: #
|
220 |
-
--primary-hover: #
|
221 |
-
--secondary-color: #
|
222 |
-
--
|
|
|
223 |
--panel-background: #ffffff;
|
224 |
-
--text-color: #
|
225 |
-
--border-radius:
|
226 |
-
--shadow: 0
|
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:
|
240 |
-
background: linear-gradient(
|
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:
|
248 |
margin-bottom: 0.5rem;
|
249 |
-
font-weight:
|
250 |
-
text-shadow: 0 2px
|
|
|
251 |
}
|
252 |
.main-header p {
|
253 |
-
font-size: 1rem;
|
254 |
-
margin
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
255 |
opacity: 0.9;
|
|
|
|
|
|
|
256 |
}
|
257 |
.main-header a {
|
258 |
-
color: var(--
|
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:
|
270 |
border-radius: var(--border-radius);
|
271 |
box-shadow: var(--shadow);
|
272 |
-
margin-bottom:
|
|
|
273 |
}
|
274 |
button.primary {
|
275 |
background: var(--primary-color) !important;
|
|
|
276 |
border: none !important;
|
277 |
color: white !important;
|
278 |
-
padding:
|
279 |
-
border-radius:
|
280 |
font-weight: 600 !important;
|
281 |
-
box-shadow: 0
|
282 |
-
transition: all 0.
|
|
|
|
|
283 |
}
|
284 |
button.primary:hover {
|
285 |
-
background: var(--primary-hover) !important;
|
286 |
-
transform: translateY(-
|
287 |
-
box-shadow: 0
|
288 |
}
|
289 |
button.secondary {
|
290 |
background: white !important;
|
291 |
-
border: 1px solid
|
292 |
-
color: var(--
|
293 |
-
padding:
|
294 |
-
border-radius:
|
295 |
font-weight: 500 !important;
|
296 |
-
box-shadow: 0 2px 5px rgba(
|
297 |
-
transition: all 0.
|
298 |
}
|
299 |
button.secondary:hover {
|
300 |
-
background:
|
301 |
transform: translateY(-2px) !important;
|
|
|
302 |
}
|
303 |
.gr-box {
|
304 |
border-radius: var(--border-radius) !important;
|
305 |
-
border: 1px solid
|
306 |
}
|
307 |
.gr-panel {
|
308 |
border-radius: var(--border-radius) !important;
|
309 |
}
|
310 |
.gr-input {
|
311 |
-
border-radius:
|
312 |
-
border: 1px solid
|
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:
|
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.
|
332 |
-
box-shadow: 0
|
|
|
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.
|
346 |
-
color:
|
347 |
-
padding:
|
348 |
-
background:
|
349 |
-
border-radius:
|
350 |
-
border-left:
|
351 |
-
margin-bottom:
|
352 |
cursor: pointer;
|
353 |
-
transition: all 0.
|
|
|
354 |
}
|
355 |
.example-prompt:hover {
|
356 |
-
background:
|
|
|
|
|
357 |
}
|
358 |
.status-generating {
|
359 |
-
color:
|
360 |
-
font-weight:
|
361 |
display: flex;
|
362 |
align-items: center;
|
363 |
gap: 8px;
|
|
|
364 |
}
|
365 |
.status-generating::before {
|
366 |
content: "";
|
367 |
display: inline-block;
|
368 |
-
width:
|
369 |
-
height:
|
370 |
border-radius: 50%;
|
371 |
-
background-color:
|
372 |
animation: pulse 1.5s infinite;
|
373 |
}
|
374 |
.status-complete {
|
375 |
-
color: #
|
376 |
-
font-weight:
|
377 |
display: flex;
|
378 |
align-items: center;
|
379 |
gap: 8px;
|
|
|
380 |
}
|
381 |
.status-complete::before {
|
382 |
content: "";
|
383 |
display: inline-block;
|
384 |
-
width:
|
385 |
-
height:
|
386 |
border-radius: 50%;
|
387 |
-
background-color: #
|
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(--
|
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(
|
406 |
}
|
407 |
.gr-slider-container {
|
408 |
padding: 10px 0 !important;
|
409 |
}
|
410 |
.gr-prose h3 {
|
411 |
-
font-weight:
|
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
|
|
|
|
|
428 |
<p>Community: <a href="https://discord.gg/openfreeai" target="_blank">https://discord.gg/openfreeai</a></p>
|
429 |
</div>
|
430 |
''')
|
431 |
|
432 |
-
|
433 |
-
|
434 |
-
with gr.
|
435 |
-
with gr.
|
436 |
-
with gr.
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
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.
|
498 |
-
gr.
|
499 |
-
|
500 |
-
|
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 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
561 |
|
562 |
-
with gr.
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
|
|
|
|
|
|
|
|
|
|
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
|
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">
|
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">
|
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>
|