Spaces:
Running on Zero
Running on Zero
| import os | |
| os.environ.setdefault("VF_HF_ATTN_IMPL", "sdpa") | |
| import spaces | |
| import torch | |
| import gradio as gr | |
| import random | |
| from mage_flow import MageFlowPipeline | |
| from mage_flow.models.modules._attn_backend import set_attn_backend | |
| MODEL_ID = "microsoft/Mage-Flow-Base" | |
| pipe = MageFlowPipeline.from_pretrained(MODEL_ID, device="cuda") | |
| # Override the attention backend to SDPA after model load — the model's | |
| # __init__ resets it to "flash2" (the default attn_type), but flash_attn | |
| # is not available on ZeroGPU. SDPA is torch-native and works everywhere. | |
| set_attn_backend("sdpa") | |
| def _estimate_duration(prompt, negative_prompt, height, width, steps, cfg, seed, *args, **kwargs): | |
| """Estimate GPU time needed based on steps and resolution. | |
| Measured: ~15s for 30 steps at 1024x1024 with SDPA backend + content screening. | |
| """ | |
| pixels = height * width | |
| base = 20 # content screening + text encoding overhead | |
| step_time = 0.5 if pixels <= 1024 * 1024 else 1.0 | |
| return min(300, base + int(steps * step_time)) | |
| def generate( | |
| prompt: str, | |
| negative_prompt: str = "", | |
| height: int = 1024, | |
| width: int = 1024, | |
| steps: int = 30, | |
| cfg: float = 5.0, | |
| seed: int = 42, | |
| randomize_seed: bool = False, | |
| ): | |
| """Generate an image from a text prompt using Mage-Flow-Base. | |
| Args: | |
| prompt: Text description of the image to generate. | |
| negative_prompt: What to avoid in the generated image. | |
| height: Output image height (512-2048, multiple of 16). | |
| width: Output image width (512-2048, multiple of 16). | |
| steps: Number of denoising steps (more = higher quality, slower). | |
| cfg: Classifier-free guidance scale (higher = more prompt adherence). | |
| seed: Random seed for reproducibility. | |
| randomize_seed: If True, use a random seed each time. | |
| """ | |
| if randomize_seed: | |
| seed = random.randint(0, 2**32 - 1) | |
| seed = int(seed) | |
| height = max(512, min(2048, int(height) // 16 * 16)) | |
| width = max(512, min(2048, int(width) // 16 * 16)) | |
| neg = negative_prompt.strip() if negative_prompt else " " | |
| result = pipe.generate( | |
| [prompt], | |
| neg_prompts=[neg], | |
| seeds=[seed], | |
| steps=int(steps), | |
| cfg=float(cfg), | |
| heights=[height], | |
| widths=[width], | |
| ) | |
| return result[0], seed | |
| CSS = """ | |
| #col-container { max-width: 1100px; margin: 0 auto; } | |
| .dark .gradio-container { color: var(--body-text-color); } | |
| """ | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# 🎨 Mage-Flow-Base Text-to-Image") | |
| gr.Markdown( | |
| "Generate images with [microsoft/Mage-Flow-Base](https://huggingface.co/microsoft/Mage-Flow-Base), " | |
| "a 4.1B parameter native-resolution MMDiT model. Supports any resolution from 512 to 2048." | |
| ) | |
| with gr.Column(elem_id="col-container"): | |
| with gr.Row(): | |
| prompt = gr.Textbox( | |
| label="Prompt", | |
| placeholder="Describe the image you want to generate...", | |
| show_label=False, | |
| container=False, | |
| scale=4, | |
| ) | |
| run_btn = gr.Button("Generate", variant="primary", scale=1) | |
| output = gr.Image(label="Generated Image", show_label=False, height=512) | |
| with gr.Accordion("Advanced settings", open=False): | |
| negative_prompt = gr.Textbox( | |
| label="Negative prompt", | |
| placeholder="What to avoid...", | |
| value="", | |
| ) | |
| with gr.Row(): | |
| height = gr.Slider( | |
| label="Height", minimum=512, maximum=2048, step=16, value=1024 | |
| ) | |
| width = gr.Slider( | |
| label="Width", minimum=512, maximum=2048, step=16, value=1024 | |
| ) | |
| with gr.Row(): | |
| steps = gr.Slider( | |
| label="Steps", minimum=1, maximum=100, step=1, value=30 | |
| ) | |
| cfg = gr.Slider( | |
| label="CFG scale", minimum=1.0, maximum=20.0, step=0.1, value=5.0 | |
| ) | |
| with gr.Row(): | |
| seed = gr.Number(label="Seed", value=42, precision=0) | |
| randomize_seed = gr.Checkbox(label="Randomize seed", value=True) | |
| gr.Examples( | |
| examples=[ | |
| ["A close-up portrait of an elderly African man with deep wrinkles, wearing a traditional hat, soft natural lighting, ultra realistic."], | |
| ["An immersive close-up of a steaming bowl of Sichuan mapo tofu over jasmine rice served on a hand-thrown ceramic plate, finished with a wedge of citrus. Surface oils catch a tiny specular highlight. Shot with a Hasselblad H6D-100c, ambient window light, the kind of image that makes the viewer hungry."], | |
| ["the Salar de Uyuni mirror surface captured at high noon, with intimate stillness permeating the air. dew beads on every blade of grass. National Geographic editorial, cinematic depth, fine-grained natural texture."], | |
| ["A serene Japanese garden with a red wooden bridge over a koi pond, cherry blossoms floating on still water, morning mist, photorealistic."], | |
| ], | |
| inputs=[prompt], | |
| outputs=[output, seed], | |
| fn=generate, | |
| cache_examples=True, | |
| cache_mode="lazy", | |
| ) | |
| run_btn.click( | |
| fn=generate, | |
| inputs=[prompt, negative_prompt, height, width, steps, cfg, seed, randomize_seed], | |
| outputs=[output, seed], | |
| api_name="generate", | |
| ) | |
| demo.launch(mcp_server=True, theme=gr.themes.Citrus(), css=CSS) |