FLUX-Animations / app.py
fantaxy's picture
Update app.py
8d07ced verified
raw
history blame
9.45 kB
import gradio as gr
import numpy as np
import torch
import spaces
from diffusers import FluxPipeline, FluxTransformer2DModel
from diffusers.utils import export_to_gif
from huggingface_hub import hf_hub_download
from PIL import Image
import uuid
import random
device = "cuda" if torch.cuda.is_available() else "cpu"
if torch.cuda.is_available():
torch_dtype = torch.bfloat16
else:
torch_dtype = torch.float32
# ํŒŒ์ดํ”„๋ผ์ธ ์ดˆ๊ธฐํ™” ์ˆ˜์ •
pipe = FluxPipeline.from_pretrained(
"black-forest-labs/FLUX.1-dev",
torch_dtype=torch_dtype,
use_safetensors=True
).to(device)
MAX_SEED = np.iinfo(np.int32).max
def split_image(input_image, num_splits=8):
width = input_image.width
height = input_image.height
split_width = width // num_splits
output_images = []
for i in range(num_splits):
left = i * split_width
right = (i + 1) * split_width
box = (left, 0, right, height)
split = input_image.crop(box)
# ์ด๋ฏธ์ง€ ํ’ˆ์งˆ ๊ฐœ์„ ์„ ์œ„ํ•œ ์ฒ˜๋ฆฌ
split = split.convert('RGB')
output_images.append(split)
return output_images
@spaces.GPU
def infer(prompt, seed=1, randomize_seed=False, num_inference_steps=20, progress=gr.Progress(track_tqdm=True)):
progress(0, desc="Starting...")
prompt_template = f"A single clear frame of {prompt}. The scene should show only one moment of the action, high quality, detailed, centered composition."
if randomize_seed:
seed = random.randint(0, MAX_SEED)
frames = []
total_frames = 8
# ์ง„ํ–‰ ์ƒํ™ฉ์„ ๋” ์„ธ๋ฐ€ํ•˜๊ฒŒ ํ‘œ์‹œ
for i in range(total_frames):
current_progress = (i / total_frames) * 0.8
progress(current_progress, desc=f"๐ŸŽจ Generating frame {i+1}/{total_frames}")
frame_prompt = f"{prompt_template} Frame {i+1} of sequence."
frame_seed = seed + i
generator = torch.Generator().manual_seed(frame_seed)
# ๊ฐ ํ”„๋ ˆ์ž„์˜ ์ƒ์„ฑ ๋‹จ๊ณ„๋„ ํ‘œ์‹œ
for step in range(num_inference_steps):
step_progress = current_progress + (step / num_inference_steps) * (0.8 / total_frames)
progress(step_progress, desc=f"Frame {i+1}/{total_frames} - Step {step+1}/{num_inference_steps}")
frame = pipe(
prompt=frame_prompt,
num_inference_steps=num_inference_steps,
num_images_per_prompt=1,
generator=generator,
height=320,
width=320,
guidance_scale=7.5,
).images[0]
frames.append(frame)
progress((i + 1) / total_frames * 0.8, desc=f"โœ… Completed frame {i+1}/{total_frames}")
progress(0.9, desc="๐ŸŽฌ Creating GIF...")
gif_name = f"{uuid.uuid4().hex}-flux.gif"
export_to_gif(frames, gif_name, fps=8)
total_width = 320 * total_frames
preview_image = Image.new('RGB', (total_width, 320))
for i, frame in enumerate(frames):
preview_image.paste(frame, (i * 320, 0))
progress(1.0, desc="โœจ Done!")
return gif_name, preview_image, seed
def create_preview_image(frames):
"""ํ”„๋ ˆ์ž„๋“ค์„ ๊ฐ€๋กœ๋กœ ์—ฐ๊ฒฐํ•˜์—ฌ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์ด๋ฏธ์ง€ ์ƒ์„ฑ"""
total_width = sum(frame.width for frame in frames)
max_height = max(frame.height for frame in frames)
preview = Image.new('RGB', (total_width, max_height))
x_offset = 0
for frame in frames:
preview.paste(frame, (x_offset, 0))
x_offset += frame.width
return preview
examples = [
"a red panda in mid-backflip",
"an astronaut floating in space",
"a butterfly spreading its wings",
"a robot arm painting with a brush",
"a dragon egg with cracks appearing",
"a person stepping through a glowing portal",
"a mermaid swimming underwater",
"a steampunk clock gear turning",
"a flower bud slowly opening",
"a wizard with magical energy swirling"
]
css = """
... (์ด์ „ CSS์™€ ๋™์ผ)
/* Examples ์˜์—ญ ์Šคํƒ€์ผ ์™„์ „ ์žฌ์ •์˜ */
.gr-examples-parent {
background: transparent !important;
}
.gr-examples-parent > div {
background: transparent !important;
}
.gr-examples {
background: transparent !important;
}
.gr-examples * {
background: transparent !important;
}
.gr-samples-table {
background: transparent !important;
}
.gr-samples-table > div {
background: transparent !important;
}
.gr-samples-table button {
background: transparent !important;
border: none !important;
box-shadow: none !important;
}
.gr-samples-table button:hover {
background: rgba(0,0,0,0.05) !important;
}
div[class*="examples"] {
background: transparent !important;
}
/* ํ”„๋กœ๊ทธ๋ ˆ์Šค ๋ฐ” ์Šคํƒ€์ผ ๊ฐ•ํ™” */
.progress-bar {
background-color: #f0f0f0;
border-radius: 10px;
padding: 5px;
margin: 15px 0;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.progress-bar-fill {
background: linear-gradient(45deg, #FF6B6B, #4ECDC4);
height: 25px;
border-radius: 7px;
transition: width 0.3s ease-out;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.progress-text {
color: black;
font-weight: 600;
margin-bottom: 8px;
font-size: 1.1em;
}
/* ์ง„ํ–‰ ์ƒํƒœ ํ…์ŠคํŠธ ์Šคํƒ€์ผ */
.progress-label {
display: block;
text-align: center;
margin-top: 5px;
color: #666;
font-size: 0.9em;
}
"""
def create_snow_effect():
# CSS ์Šคํƒ€์ผ ์ •์˜
snow_css = """
@keyframes snowfall {
0% {
transform: translateY(-10vh) translateX(0);
opacity: 1;
}
100% {
transform: translateY(100vh) translateX(100px);
opacity: 0.3;
}
}
.snowflake {
position: fixed;
color: white;
font-size: 1.5em;
user-select: none;
z-index: 1000;
pointer-events: none;
animation: snowfall linear infinite;
}
"""
# JavaScript ์ฝ”๋“œ ์ •์˜
snow_js = """
function createSnowflake() {
const snowflake = document.createElement('div');
snowflake.innerHTML = 'โ„';
snowflake.className = 'snowflake';
snowflake.style.left = Math.random() * 100 + 'vw';
snowflake.style.animationDuration = Math.random() * 3 + 2 + 's';
snowflake.style.opacity = Math.random();
document.body.appendChild(snowflake);
setTimeout(() => {
snowflake.remove();
}, 5000);
}
setInterval(createSnowflake, 200);
"""
# CSS์™€ JavaScript๋ฅผ ๊ฒฐํ•ฉํ•œ HTML
snow_html = f"""
<style>
{snow_css}
</style>
<script>
{snow_js}
</script>
"""
return gr.HTML(snow_html)
with gr.Blocks(theme="soft", css=css) as demo:
gr.HTML("""
<div style="text-align: center; max-width: 800px; margin: 0 auto;">
<h1 style="font-size: 3rem; font-weight: 700; margin-bottom: 1rem;">
FLUX Animation Creator
</h1>
<p style="font-size: 1.2rem; color: #666; margin-bottom: 2rem;">
Create amazing animated GIFs with AI - Just describe what you want to see!
</p>
</div>
""")
create_snow_effect()
with gr.Column(elem_id="col-container"):
with gr.Row():
prompt = gr.Text(
label="Your Animation Prompt",
show_label=True,
max_lines=1,
placeholder="Describe the animation you want to create...",
container=True,
elem_id="prompt-input"
)
run_button = gr.Button("โœจ Generate", scale=0, variant="primary")
result = gr.Image(
label="Generated Animation",
show_label=True,
elem_id="main-output",
height=500
)
with gr.Row():
result_full = gr.Image(
label="Preview",
elem_id="preview-output",
height=200
)
strip_image = gr.Image(
label="Animation Strip",
elem_id="strip-output",
height=150
)
with gr.Accordion("Advanced Settings", open=False):
seed = gr.Slider(
label="Seed",
minimum=0,
maximum=MAX_SEED,
step=1,
value=0,
)
randomize_seed = gr.Checkbox(label="Randomize seed", value=True)
num_inference_steps = gr.Slider(
label="Number of inference steps",
minimum=1,
maximum=25,
step=1,
value=20,
)
gr.Examples(
examples=examples,
inputs=[prompt],
outputs=[result, result_full, seed],
fn=infer,
cache_examples=True,
label="Click on any example to try it out"
)
gr.on(
triggers=[run_button.click, prompt.submit],
fn=infer,
inputs=[prompt, seed, randomize_seed, num_inference_steps],
outputs=[result, result_full, seed]
)
demo.theme = gr.themes.Default().set(
body_text_color="black",
block_label_text_color="black",
block_title_text_color="black",
body_text_color_subdued="black",
background_fill_primary="white"
)
demo.queue().launch()