Spaces:
Running
Running
| import os | |
| import random | |
| import numpy as np | |
| import gradio as gr | |
| # --- Hugging Face Spaces ๋ฐ์ฝ๋ ์ดํฐ(์์ด๋ ๋์ํ๋๋ก ๋์ฒด) --- | |
| try: | |
| import spaces | |
| GPU_DECORATOR = spaces.GPU | |
| except Exception: | |
| def GPU_DECORATOR(*args, **kwargs): | |
| def _wrap(fn): | |
| return fn | |
| return _wrap | |
| import torch | |
| from diffusers import DiffusionPipeline | |
| # ----------------------- | |
| # ์ฅ์น/์ ๋ฐ๋ ์๋ ์ ํ | |
| # ----------------------- | |
| def select_device_dtype(): | |
| if torch.cuda.is_available(): | |
| device = "cuda" | |
| dtype = torch.bfloat16 if torch.cuda.is_bf16_supported() else torch.float16 | |
| else: | |
| device = "cpu" | |
| dtype = torch.float32 | |
| return device, dtype | |
| device, dtype = select_device_dtype() | |
| if device == "cuda": | |
| torch.backends.cuda.matmul.allow_tf32 = True | |
| # ์ ํ๊ฐ | |
| MAX_SEED = np.iinfo(np.uint32).max | |
| MAX_SIDE = 2048 | |
| MAX_TOTAL_PIXELS = 2_359_296 # ํด์๋ ์ด ํฝ์ ๊ฐ๋(์ฝ 2.36MP) | |
| # ----------------------- | |
| # ๋ชจ๋ธ ๋ก๋ (FLUX.1-schnell) | |
| # ----------------------- | |
| MODEL_ID = "black-forest-labs/FLUX.1-schnell" | |
| pipe = DiffusionPipeline.from_pretrained(MODEL_ID, torch_dtype=dtype).to(device) | |
| if hasattr(pipe, "enable_vae_slicing"): | |
| pipe.enable_vae_slicing() | |
| if hasattr(pipe, "enable_vae_tiling"): | |
| pipe.enable_vae_tiling() | |
| # ----------------------- | |
| # ์ ํธ | |
| # ----------------------- | |
| def _clamp_hw(width: int, height: int): | |
| width = int(max(256, min(int(width), MAX_SIDE))) | |
| height = int(max(256, min(int(height), MAX_SIDE))) | |
| if width * height > MAX_TOTAL_PIXELS: | |
| scale = (MAX_TOTAL_PIXELS / (width * height)) ** 0.5 | |
| width = int((width * scale) // 32 * 32) | |
| height = int((height * scale) // 32 * 32) | |
| width = max(256, min(width, MAX_SIDE)) | |
| height = max(256, min(height, MAX_SIDE)) | |
| return width, height | |
| def _validate_params(prompt: str, steps: int, guidance: float): | |
| if not prompt or not prompt.strip(): | |
| raise ValueError("ํ๋กฌํํธ๊ฐ ๋น์ด ์์ต๋๋ค. ๋ด์ฉ์ ์ ๋ ฅํด ์ฃผ์ธ์.") | |
| if not (1 <= steps <= 50): | |
| raise ValueError("์ถ๋ก ์คํ ์ 1~50 ๋ฒ์์ฌ์ผ ํฉ๋๋ค.") | |
| if not (0.0 <= guidance <= 20.0): | |
| raise ValueError("๊ฐ์ด๋์ค ์ค์ผ์ผ์ 0.0~20.0 ๋ฒ์์ฌ์ผ ํฉ๋๋ค.") | |
| # ----------------------- | |
| # ์์ฑ ํจ์ | |
| # ----------------------- | |
| def generate_image(prompt, seed, randomize_seed, width, height, steps, guidance_scale, progress=gr.Progress(track_tqdm=True)): | |
| try: | |
| prompt = prompt.strip() | |
| _validate_params(prompt, steps, guidance_scale) | |
| if randomize_seed: | |
| seed = random.randint(0, MAX_SEED) | |
| generator = torch.Generator(device=device).manual_seed(int(seed)) | |
| width, height = _clamp_hw(width, height) | |
| progress(0.1, desc="์ด๊ธฐํ ์คโฆ") | |
| if device == "cuda": | |
| autocast_ctx = torch.autocast(device_type="cuda", dtype=dtype) | |
| elif device == "cpu": | |
| autocast_ctx = torch.autocast(device_type="cpu", dtype=dtype) if dtype != torch.float32 else torch.no_grad() | |
| else: | |
| autocast_ctx = torch.no_grad() | |
| with autocast_ctx: | |
| progress(0.4, desc="์ด๋ฏธ์ง ์์ฑ ์คโฆ") | |
| out = pipe( | |
| prompt=prompt, | |
| width=int(width), | |
| height=int(height), | |
| num_inference_steps=int(steps), | |
| generator=generator, | |
| guidance_scale=float(guidance_scale) | |
| ) | |
| image = out.images[0] | |
| progress(1.0, desc="์๋ฃ") | |
| return image, int(seed) | |
| except Exception as e: | |
| gr.Error(f"์์ฑ ์ค ์ค๋ฅ: {type(e).__name__}: {e}") | |
| return None, int(seed) | |
| def set_prompt(example_text): | |
| return example_text | |
| # ----------------------- | |
| # ํ๊ธ ์์ ํ๋กฌํํธ | |
| # ----------------------- | |
| example_prompts = { | |
| "์ ํ ๋์์ธ": [ | |
| """์ฌ๋ฆญํ ์ธ๋์คํธ๋ฆฌ์ผ ์คํ์ผ์ ์ปคํผ๋จธ์ ์ปจ์ ์ค์ผ์น: | |
| - ๊ณก์ ํ ๋ฉํ ๋ฐ๋, ๋ฒ ์ ค ์ต์ํ | |
| - ์ค์ ์ฉ ํฐ์น์คํฌ๋ฆฐ ํจ๋ | |
| - ๋ชจ๋ํ ๋งคํธ ๋ธ๋ ๋ง๊ฐ | |
| - ์๊ทธ๋ฆผ(์ค์ผ์น) ์ปจ์ ์ํธ ์คํ์ผ""" | |
| ], | |
| "๋ง์ธ๋๋งต": [ | |
| """์๊ทธ๋ฆผ ์คํ์ผ์ ๋ค์ฑ๋ก์ด ๋ง์ธ๋๋งต, ๊ต์ก์ฉ, ์๋๊ฐ ์๋ ์๊ฐ, ๋ช ํํ ๊ณ์ธต ๊ตฌ์กฐ, ํฉ๊ธ๋น ๋ ์ด์์. | |
| KNOWLEDGE | |
| โโโ ACQUISITION [๋ฒ๊ฐ๊ฐ ์น ๋ ~60px] | |
| โ โโโ READING [๋น๋๋ ํผ์น ์ฑ ] | |
| โ โโโ PRACTICE [๊ณต๊ตฌ ์์ด์ฝ] | |
| โ โโโ OBSERVATION [ํ๋๊ฒฝ ๋ ๋] | |
| โโโ PROCESSING [๊ธฐ์ด ๋คํธ์ํฌ ~50px] | |
| โ โโโ ANALYSIS [์์น ๊ทธ๋ํ] | |
| โ โโโ SYNTHESIS [ํผ์ฆ ์กฐ๊ฐ] | |
| โโโ RETENTION [๋ฉ๋ชจ๋ฆฌ ์นฉ ~45px] | |
| โ โโโ SHORT-TERM [๋ฒ์ฉ์] | |
| โ โโโ LONG-TERM [๊ฒฌ๊ณ ํ ์์นด์ด๋ธ] | |
| โโโ APPLICATION | |
| โโโ CREATION [ํ๋ ํธ] | |
| โโโ INNOVATION [๋ณ์๋ฆฌ ์ ๊ตฌ]""" | |
| ], | |
| "๋ชฉ์ ": [ | |
| """์๊ทธ๋ฆผ ์์ด์ดํ๋ ์ ์คํ์ผ์ ๋ชจ๋ฐ์ผ ๋ฑ ํน ์ฑ ๋ชฉ์ : | |
| - ๋ก๊ณ ๊ฐ ์๋ ํ์ดํ ํ๋ฉด | |
| - ๋ก๊ทธ์ธ(์์ด๋, ๋น๋ฐ๋ฒํธ, ๋ก๊ทธ์ธ ๋ฒํผ) | |
| - ๋์๋ณด๋ 3๊ฐ ์น์ (์์ก, ๊ฑฐ๋๋ด์ญ, ๋น ๋ฅธ ์คํ) | |
| - ํ๋จ ๋ด๋น๊ฒ์ด์ (ํ, ์ด์ฒด, ํ๋กํ)""" | |
| ], | |
| "์ธํฌ๊ทธ๋ํฝ": [ | |
| """๋๊ธฐ์ ์ฐ์ฐจ๋ณด๊ณ ์์ฉ ํ๋ซ ์คํ์ผ ์ธํฌ๊ทธ๋ํฝ: | |
| - ์ ๋ชฉ: "Global Renewable Energy Trends 2025" | |
| - ๋ถ์ : "์์ฅ์ ์ ์จ๊ณผ ์ฑ์ฅ๋ถ์" | |
| - ์๊ฐ ์์: | |
| - ์ง์ญ๋ณ ํ์๊ดยทํ๋ ฅยท์๋ ฅ ์์ฐ๋ ๋ง๋๊ทธ๋ํ | |
| - ์๋์ง ๋น์ค ํ์ด์ฐจํธ: ํ์๊ด(45%)ยทํ๋ ฅ(30%)ยท์๋ ฅ(25%) | |
| - ์ฐ๋๋ณ ์ฑ์ฅ ์ถ์ธ์ | |
| - ์์ด์ฝ: ๋ฏธ๋๋ฉ ํ์, ํ๋ ฅ ํฐ๋น, ๋ฌผ๋ฐฉ์ธ | |
| - ๋ ์ด์์: ๊ทธ๋ฆฌ๋ ๊ธฐ๋ฐ, ํ์คํ ํฌ์ธํธ, ํ์ดํธ ์คํ์ด์ค ์ถฉ๋ถ | |
| - ์ฃผ์: KPI ํต์ฌ ์์น ๋ฐ ์ ๋ง ์ฝ์์""" | |
| ], | |
| "๋ค์ด์ด๊ทธ๋จ": [ | |
| """์๋ํฌ์๋ ๋น์ฆ๋์ค ์ํฌํ๋ก ๋ค์ด์ด๊ทธ๋จ(์๊ทธ๋ฆผ, ๊ต์ก์ ยท์ ๋ฌธ์ ): | |
| - ์ ๋ชฉ: "ํตํฉ ๋น์ฆ๋์ค ํ๋ก์ธ์ค" | |
| - ๊ตฌ์ฑ: | |
| - ์์ฅ๋ถ์(์ฐจํธ, ๊ฒฝ์์ ๋งต) | |
| - ์ ๋ต์๋ฆฝ(๋ธ๋ ์ธ์คํ ๋ฐ ํด๋ผ์ฐ๋, ํต์ฌ ํฌ์ปค์ค) | |
| - ์ ํ์ค๊ณ(์ค์ผ์น, ํผ๋๋ฐฑ ๋ฃจํ) | |
| - ๊ตฌํ(ํ์๋ผ์ธ ๋ง์ปค, ๋ฆฌ์์ค ์์ด์ฝ) | |
| - ์ถ์ ํ ๋ฆฌ๋ทฐ(์งํ, ์ง์ ๊ฐ์ ) | |
| - ๋ช ํํ ๋ฐฉํฅ ํ์ดํ, ์์์ผ๋ก ๋จ๊ณ ๊ตฌ๋ถ""" | |
| ], | |
| "ํ๋ก์ฐ์ฐจํธ": [ | |
| """์๊ทธ๋ฆผ ์คํ์ผ ํ๋ก์ฐ์ฐจํธ, ์ ๋ช ํ ์, ๋ฏธ๋๋ฉ ์์ด์ฝ. | |
| BUSINESS WORKFLOW | |
| โโโ ์์ [์ด๋ก ๋ฒํผ ~40px] | |
| โ โโโ ์๊ตฌ์ฌํญ ์์ง [ํด๋ ์์ด์ฝ] | |
| โ โโโ ๋ฐ์ดํฐ ๋ถ์ [์ฐจํธ ์์ด์ฝ] | |
| โโโ ๊ตฌํ [์ฝ๋ฉ ์ฌ๋ณผ ~50px] | |
| โ โโโ ํ๋ก ํธ์๋ [๋ธ๋ผ์ฐ์ ์์ด์ฝ] | |
| โ โโโ ๋ฐฑ์๋ [์๋ฒ ์์ด์ฝ] | |
| โโโ ํ ์คํธ & ํตํฉ [๊ธฐ์ด ์์ด์ฝ ~45px] | |
| โโโ ๋ฐฐํฌ | |
| โโโ ์ข ๋ฃ [์ฒด์ปค๊ธฐ ๊น๋ฐ ~40px]""" | |
| ] | |
| } | |
| # ----------------------- | |
| # Gradio UI (ํ๊ตญ์ด) | |
| # ----------------------- | |
| css = """ | |
| * { box-sizing: border-box; } | |
| body { | |
| background: linear-gradient(135deg, #667eea, #764ba2); | |
| font-family: 'Pretendard', 'Apple SD Gothic Neo', 'Noto Sans KR', 'Helvetica Neue', Arial, sans-serif; | |
| color: #333; margin: 0; padding: 0; | |
| } | |
| .gradio-container { | |
| background: rgba(255, 255, 255, 0.95); | |
| border-radius: 15px; | |
| padding: 30px 40px; | |
| box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3); | |
| margin: 40px auto; | |
| width: 1200px; | |
| overflow: visible !important; | |
| } | |
| .sidebar { | |
| background: rgba(255, 255, 255, 0.98); | |
| border-radius: 10px; | |
| padding: 20px; | |
| box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2); | |
| position: relative; z-index: 10; | |
| overflow: visible !important; | |
| } | |
| button, .btn { | |
| background: linear-gradient(90deg, #ff8a00, #e52e71); | |
| border: none; color: #fff; | |
| padding: 12px 24px; text-transform: uppercase; | |
| font-weight: bold; letter-spacing: 1px; | |
| border-radius: 5px; cursor: pointer; | |
| transition: transform 0.2s ease-in-out; | |
| } | |
| button:hover, .btn:hover { transform: scale(1.05); } | |
| .example-accordion { width: 100% !important; max-width: 100% !important; } | |
| .example-accordion button { width: auto !important; white-space: normal !important; } | |
| """ | |
| with gr.Blocks(css=css, title="์ํฌํ๋ก ์บ๋ฒ์ค") as demo: | |
| gr.Markdown( | |
| """ | |
| <div style="text-align:center;"> | |
| <h1>์ํฌํ๋ก ์บ๋ฒ์ค</h1> | |
| <p>์ฌ๋ฌ ํญ์์ ๋น์ฆ๋์ค์ ํ์ํ ๋์์ธ ์ปจ์ ๊ณผ ์ํฌํ๋ก ๋ค์ด์ด๊ทธ๋จ์ ์์ฑํด ๋ณด์ธ์.</p> | |
| <p><strong>์ปค๋ฎค๋ํฐ:</strong> <a href="https://discord.gg/openfreeai" target="_blank">https://discord.gg/openfreeai</a></p> | |
| </div> | |
| """ | |
| ) | |
| gr.HTML( | |
| """<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fginigen-Workflow-Canvas.hf.space"> | |
| <img src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fginigen-Workflow-Canvas.hf.space&countColor=%23263759" alt="๋ฐฉ๋ฌธ์ ๋ฐฐ์ง"/> | |
| </a>""" | |
| ) | |
| with gr.Row(): | |
| # ์ผ์ชฝ ์ฌ์ด๋๋ฐ: ๊ณตํต ํ๋ผ๋ฏธํฐ | |
| with gr.Column(scale=2, elem_classes="sidebar"): | |
| gr.Markdown("### ์์ฑ ํ๋ผ๋ฏธํฐ") | |
| size_preset = gr.Dropdown( | |
| label="ํด์๋ ํ๋ฆฌ์ ", | |
| choices=[ | |
| "1024x1024", "1536x1024", "1024x1536", | |
| "1344x1344", "1536x1536", "1920x1080", "1080x1920" | |
| ], | |
| value="1024x1024" | |
| ) | |
| width_slider = gr.Slider(label="๊ฐ๋ก ํด์๋(px)", minimum=256, maximum=MAX_SIDE, step=32, value=1024) | |
| height_slider = gr.Slider(label="์ธ๋ก ํด์๋(px)", minimum=256, maximum=MAX_SIDE, step=32, value=1024) | |
| def apply_preset(preset): | |
| w, h = map(int, preset.split("x")) | |
| w, h = _clamp_hw(w, h) | |
| return w, h | |
| size_preset.change(fn=apply_preset, inputs=size_preset, outputs=[width_slider, height_slider]) | |
| seed_slider = gr.Slider(label="์๋(Seed)", minimum=0, maximum=int(MAX_SEED), step=1, value=42) | |
| randomize_seed = gr.Checkbox(label="์๋ ๋๋ค", value=True) | |
| def toggle_seed(disable): | |
| return gr.update(interactive=not disable) | |
| randomize_seed.change(fn=toggle_seed, inputs=randomize_seed, outputs=seed_slider) | |
| steps_slider = gr.Slider(label="์ถ๋ก ์คํ ", minimum=1, maximum=50, step=1, value=20) | |
| guidance_slider = gr.Slider(label="๊ฐ์ด๋์ค ์ค์ผ์ผ", minimum=0.0, maximum=20.0, step=0.5, value=7.5) | |
| # ๋ฉ์ธ: ํญ UI | |
| with gr.Column(scale=8): | |
| with gr.Tabs(): | |
| def build_tab(tab_title, ex_key, placeholder_text): | |
| with gr.Tab(tab_title): | |
| tb = gr.Textbox( | |
| label=f"{tab_title} ํ๋กฌํํธ", | |
| placeholder=placeholder_text, | |
| lines=5, | |
| value=example_prompts[ex_key][0] | |
| ) | |
| btn = gr.Button(f"{tab_title} ์์ฑ") | |
| img = gr.Image(label=f"{tab_title} ๊ฒฐ๊ณผ", type="pil", value=None, height=512) | |
| with gr.Accordion("์์ ํ๋กฌํํธ", open=True, elem_classes="example-accordion"): | |
| for ex in example_prompts[ex_key]: | |
| gr.Button(ex, variant="secondary").click( | |
| fn=lambda ex=ex: set_prompt(ex), | |
| outputs=tb | |
| ) | |
| btn.click( | |
| fn=generate_image, | |
| inputs=[tb, seed_slider, randomize_seed, width_slider, height_slider, steps_slider, guidance_slider], | |
| outputs=[img, seed_slider] | |
| ) | |
| build_tab("์ ํ ๋์์ธ", "์ ํ ๋์์ธ", "์ ํ ๋์์ธ ์ปจ์ ์ ์ ๋ ฅํ์ธ์โฆ") | |
| build_tab("๋ง์ธ๋๋งต", "๋ง์ธ๋๋งต", "๋ง์ธ๋๋งต ์ค๋ช ์ ์ ๋ ฅํ์ธ์โฆ") | |
| build_tab("๋ชฉ์ ", "๋ชฉ์ ", "์ฑ/์น ๋ชฉ์ ์ค๋ช ์ ์ ๋ ฅํ์ธ์โฆ") | |
| build_tab("์ธํฌ๊ทธ๋ํฝ", "์ธํฌ๊ทธ๋ํฝ", "์ธํฌ๊ทธ๋ํฝ ์ค๋ช ์ ์ ๋ ฅํ์ธ์โฆ") | |
| build_tab("๋ค์ด์ด๊ทธ๋จ", "๋ค์ด์ด๊ทธ๋จ", "๋ค์ด์ด๊ทธ๋จ ์ค๋ช ์ ์ ๋ ฅํ์ธ์โฆ") | |
| build_tab("ํ๋ก์ฐ์ฐจํธ", "ํ๋ก์ฐ์ฐจํธ", "ํ๋ก์ฐ์ฐจํธ ์ค๋ช ์ ์ ๋ ฅํ์ธ์โฆ") | |
| if __name__ == "__main__": | |
| demo.queue(concurrency_count=2, max_size=32) | |
| demo.launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| share=False, | |
| show_error=True, | |
| debug=True | |
| ) | |