import spaces import torch from diffusers import FluxPipeline import gradio as gr import random import numpy as np import os if torch.cuda.is_available(): device = "cuda" print("GPU를 사용합니다") else: device = "cpu" print("CPU를 사용합니다") HF_TOKEN = os.getenv("HF_TOKEN") MAX_SEED = np.iinfo(np.int32).max CACHE_EXAMPLES = torch.cuda.is_available() and os.getenv("CACHE_EXAMPLES", "0") == "1" pipe = FluxPipeline.from_pretrained("black-forest-labs/FLUX.1-dev", torch_dtype=torch.bfloat16) pipe.to(device) @spaces.GPU(duration=160) def generate_image(prompt, num_inference_steps, height, width, guidance_scale, seed, num_images_per_prompt, progress=gr.Progress(track_tqdm=True)): if seed is None or seed == 0: seed = random.randint(1, MAX_SEED) generator = torch.Generator().manual_seed(seed) with torch.inference_mode(): output = pipe( prompt=prompt, num_inference_steps=num_inference_steps, height=height, width=width, guidance_scale=guidance_scale, generator=generator, num_images_per_prompt=num_images_per_prompt ).images return output def random_seed(): return random.randint(1, MAX_SEED) def create_random_seed(): new_seed = random_seed() return [gr.Number.update(value=new_seed), f"현재 시드: {new_seed}"] examples = [ ["A cat holding a sign that says hello world"], ["a tiny astronaut hatching from an egg on the moon"], ["An astronaut on mars in a futuristic cyborg suit"], ] css = """ .gradio-container { max-width: 1400px !important; margin: auto; } .image-container img { max-height: 600px !important; } .image-slider { height: 600px !important; max-height: 600px !important; } h1 { text-align: center; font-family: 'Pretendard', sans-serif; color: #EA580C; font-size: 2.5rem; font-weight: 700; margin-bottom: 1.5rem; text-shadow: 0 2px 4px rgba(0,0,0,0.1); } .subtitle { text-align: center; color: #4B5563; font-size: 1.1rem; margin-bottom: 2rem; font-family: 'Pretendard', sans-serif; } .gr-button-primary { background-color: #F97316 !important; border: none !important; box-shadow: 0 2px 4px rgba(234, 88, 12, 0.2) !important; } .gr-button-primary:hover { background-color: #EA580C !important; transform: translateY(-1px); box-shadow: 0 4px 6px rgba(234, 88, 12, 0.25) !important; } .footer-content { text-align: center; margin-top: 3rem; padding: 2rem; background: linear-gradient(to bottom, #FFF7ED, white); border-radius: 12px; font-family: 'Pretendard', sans-serif; } .footer-content a { color: #EA580C; text-decoration: none; font-weight: 500; transition: all 0.2s; } .footer-content a:hover { color: #C2410C; } .visit-button { background-color: #EA580C; color: white !important; padding: 12px 24px; border-radius: 8px; font-weight: 600; text-decoration: none; display: inline-block; transition: all 0.3s; margin-top: 1rem; box-shadow: 0 2px 4px rgba(234, 88, 12, 0.2); font-size: 1.1rem; } .visit-button:hover { background-color: #C2410C; transform: translateY(-2px); box-shadow: 0 4px 6px rgba(234, 88, 12, 0.25); color: white !important; } .container-wrapper { background: white; border-radius: 16px; padding: 2rem; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); } .image-container { border-radius: 12px; overflow: hidden; border: 2px solid #F3F4F6; } .seed-button { background-color: #F3F4F6 !important; color: #374151 !important; border: 1px solid #E5E7EB !important; border-radius: 8px !important; padding: 8px 16px !important; font-size: 0.9rem !important; font-weight: 500 !important; transition: all 0.2s ease-in-out !important; } .seed-button:hover { background-color: #E5E7EB !important; transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); } .seed-text { font-family: 'Pretendard', sans-serif; color: #4B5563; font-size: 0.9rem; margin: 0; line-height: 2.5; font-weight: 500; } """ with gr.Blocks( theme=gr.themes.Soft( primary_hue=gr.themes.Color( c50="#FFF7ED", c100="#FFEDD5", c200="#FED7AA", c300="#FDBA74", c400="#FB923C", c500="#F97316", c600="#EA580C", c700="#C2410C", c800="#9A3412", c900="#7C2D12", c950="#431407", ), secondary_hue="zinc", neutral_hue="zinc", font=("Pretendard", "sans-serif") ), css=css ) as demo: with gr.Row(): with gr.Column(): gr.HTML( """

끝장AI FLUX.1 이미지 생성기

강력한 AI 기술로 당신의 상상을 현실로 만들어보세요
""" ) with gr.Group(elem_classes="container-wrapper"): with gr.Column(): prompt = gr.Textbox( label="프롬프트", info="원하는 이미지를 설명해주세요", placeholder="고양이..." ) run_button = gr.Button("생성하기", variant="primary") result = gr.Gallery( label="생성된 AI 이미지", elem_id="gallery", elem_classes="image-container" ) with gr.Accordion("고급 설정", open=False): with gr.Row(): num_inference_steps = gr.Slider( label="추론 단계 수", info="이미지의 디노이징 단계 수입니다. 더 많은 단계는 더 높은 품질의 이미지를 생성하지만 시간이 더 걸립니다", minimum=1, maximum=50, value=25, step=1, interactive=True, show_label=True, container=True, randomize=False ) guidance_scale = gr.Slider( label="가이던스 스케일", info="텍스트 프롬프트를 얼마나 충실히 따를지 제어합니다. 높은 값은 입력 텍스트에 더 가깝게 생성됩니다", minimum=0.0, maximum=7.0, value=3.5, step=0.1, interactive=True, show_label=True, container=True, randomize=False ) with gr.Row(): width = gr.Slider( label="너비", info="이미지의 너비", minimum=256, maximum=1024, step=32, value=1024, interactive=True, show_label=True, container=True, randomize=False ) height = gr.Slider( label="높이", info="이미지의 높이", minimum=256, maximum=1024, step=32, value=1024, interactive=True, show_label=True, container=True, randomize=False ) with gr.Row(): seed = gr.Slider( label="시드", info="생성 프로세스를 시작하는 시작점입니다. 무작위는 0을 입력하세요", value=42, minimum=0, maximum=MAX_SEED, step=1 ) num_images_per_prompt = gr.Slider( label="프롬프트당 이미지 수", info="설정된 값으로 생성할 이미지의 수", minimum=1, maximum=4, step=1, value=2 ) gr.Examples( examples=examples, fn=generate_image, inputs=[prompt, num_inference_steps, height, width, guidance_scale, seed, num_images_per_prompt], outputs=[result], cache_examples=CACHE_EXAMPLES ) seed_button.click( fn=create_random_seed, outputs=[seed, seed_text] ) gr.on( triggers=[ prompt.submit, run_button.click, ], fn=generate_image, inputs=[prompt, num_inference_steps, height, width, guidance_scale, seed, num_images_per_prompt], outputs=[result], ) gr.HTML( """ """ ) demo.queue().launch(share=False)