import random import gradio as gr import numpy as np import torch import spaces from diffusers import FluxPipeline from PIL import Image from diffusers.utils import export_to_gif from transformers import pipeline # ------------------------- # Configuration constants # ------------------------- FRAMES = 4 # number of stills laid out horizontally DEFAULT_HEIGHT = 256 # per‑frame size (px) DEFAULT_FPS = 8 # smoother playback than the original 4 fps MAX_SEED = np.iinfo(np.int32).max # ------------------------- # Model initialisation # ------------------------- device = "cuda" if torch.cuda.is_available() else "cpu" pipe = ( FluxPipeline.from_pretrained( "black-forest-labs/FLUX.1-dev", torch_dtype=torch.float16, # slightly higher precision than bfloat16 for crisper output ) .to(device) ) # English is the primary UI language, but Korean prompts are still accepted & translated. translator = pipeline("translation", model="Helsinki-NLP/opus-mt-ko-en") # ------------------------- # Helper functions # ------------------------- def split_image(input_image: Image.Image, frame_size: int) -> list[Image.Image]: """Cut a wide strip into equal square frames.""" return [ input_image.crop((i * frame_size, 0, (i + 1) * frame_size, frame_size)) for i in range(FRAMES) ] def translate_to_english(text: str) -> str: """Translate Korean text to English if necessary.""" return translator(text)[0]["translation_text"] @spaces.GPU() def predict( prompt: str, seed: int = 42, randomize_seed: bool = False, guidance_scale: float = 7.0, num_inference_steps: int = 40, height: int = DEFAULT_HEIGHT, fps: int = DEFAULT_FPS, progress: gr.Progress = gr.Progress(track_tqdm=True), ): # 1) Language handling if any("\u3131" <= ch <= "\u318E" or "\uAC00" <= ch <= "\uD7A3" for ch in prompt): prompt = translate_to_english(prompt) # 2) Prompt template prompt_template = ( f"A side-by-side {FRAMES} frame image showing consecutive stills from a looped gif moving left to right. " f"The gif is of {prompt}." ) # 3) Seed control if randomize_seed: seed = random.randint(0, MAX_SEED) width = FRAMES * height # maintain square frames # 4) Generation image = pipe( prompt=prompt_template, guidance_scale=guidance_scale, num_inference_steps=num_inference_steps, num_images_per_prompt=1, generator=torch.Generator(device).manual_seed(seed), height=height, width=width, ).images[0] # 5) Assemble gif gif_path = export_to_gif(split_image(image, height), "flux.gif", fps=fps) return gif_path, image, seed # ------------------------- # Interface # ------------------------- css = """ #col-container {max-width: 820px; margin: 0 auto;} footer {visibility: hidden;} """ examples = [ "cat lazily swinging its paws in mid-air", "panda shaking its hips", "flower blooming in timelapse", ] with gr.Blocks(theme="soft", css=css) as demo: gr.Markdown("