Spaces:
Running on Zero
Running on Zero
| import os | |
| # Neutralize torch.compile decorators inside mmdit.py (not supported on ZeroGPU | |
| # forked workers) and reduce allocator fragmentation for the 13B DiT. | |
| os.environ.setdefault("TORCHDYNAMO_DISABLE", "1") | |
| os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True") | |
| import random | |
| import spaces # noqa: E402 MUST come before torch / CUDA-touching imports | |
| import torch # noqa: E402 | |
| import gradio as gr # noqa: E402 | |
| from huggingface_hub import hf_hub_download # noqa: E402 | |
| from pipeline import DepthLoRAPipeline # noqa: E402 | |
| MAX_SEED = 2**31 - 1 | |
| # --------------------------------------------------------------------- loading | |
| # Turbo base (8-step, no CFG) — the author's recommended fast configuration. | |
| # Krea-2 base checkpoint (~26GB) + depth-control LoRA + Qwen3-VL-4B text encoder | |
| # + Qwen-Image VAE + Depth-Anything-V2-Large. Loaded once at module scope so | |
| # ZeroGPU packs the weights and streams them to VRAM on the first GPU call. | |
| print("Resolving Krea-2-Turbo base checkpoint...") | |
| BASE_CKPT = os.path.realpath(hf_hub_download("krea/Krea-2-Turbo", "turbo.safetensors")) | |
| LORA_CKPT = os.path.realpath( | |
| hf_hub_download("Patil/Krea-2-depth-controlnet", "depth-control-lora.safetensors") | |
| ) | |
| print("Building DepthLoRAPipeline (13B DiT + Qwen3-VL-4B + VAE + DepthAnything)...") | |
| pipe = DepthLoRAPipeline(BASE_CKPT, LORA_CKPT, device="cuda") | |
| print("Pipeline ready.") | |
| # --------------------------------------------------------------------- inference | |
| def generate( | |
| image, | |
| prompt: str = "", | |
| steps: int = 8, | |
| lora_scale: float = 1.0, | |
| seed: int = 0, | |
| randomize_seed: bool = True, | |
| progress=gr.Progress(track_tqdm=True), | |
| ): | |
| """Generate a new image that keeps the 3D structure of an input image. | |
| Extracts a depth map from the input image with Depth-Anything-V2 and | |
| generates a new image following the same depth/composition but with the | |
| content and style described by the prompt (Krea-2-Turbo, 8-step). | |
| Args: | |
| image: The input image whose depth/structure is preserved. | |
| prompt: What to generate. Leave empty for depth-only generation. | |
| steps: Number of sampling steps (8 recommended for Turbo). | |
| lora_scale: Control strength. <1.0 relaxes structure adherence. | |
| seed: RNG seed for reproducibility. | |
| randomize_seed: If True, pick a random seed each run. | |
| Returns: | |
| A tuple of (generated image, extracted depth map, used seed). | |
| """ | |
| if image is None: | |
| raise gr.Error("Please provide an input image.") | |
| if randomize_seed: | |
| seed = random.randint(0, MAX_SEED) | |
| seed = int(seed) | |
| # Turbo config: cfg=0.0, mu=1.15. lora_scale is applied to the loaded LoRA | |
| # layers in place (they were built with scale=1.0), so scale the effective | |
| # weight by mutating each LoRALinear's scale before the run. | |
| from pipeline import LoRALinear | |
| for module in pipe.model.modules(): | |
| if isinstance(module, LoRALinear): | |
| module.scale = (64 / 64) * float(lora_scale) | |
| out, depth = pipe( | |
| image, | |
| prompt=prompt or "", | |
| steps=int(steps), | |
| cfg=0.0, | |
| mu=1.15, | |
| seed=seed, | |
| ) | |
| return out, depth, seed | |
| # --------------------------------------------------------------------- UI | |
| CSS = """ | |
| #col-container { max-width: 1200px; margin: 0 auto; } | |
| .dark .gradio-container { color: var(--body-text-color); } | |
| """ | |
| with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo: | |
| with gr.Column(elem_id="col-container"): | |
| gr.Markdown( | |
| """ | |
| # Krea-2 Depth ControlNet-LoRA | |
| Give it any image and a prompt — it extracts the depth map with | |
| **Depth-Anything-V2** and generates a new image with the **same 3D | |
| structure and composition**, but whatever content and style you ask | |
| for. Powered by [Krea-2-Turbo](https://huggingface.co/krea/Krea-2-Turbo) | |
| (8-step) + the | |
| [depth-control LoRA](https://huggingface.co/Patil/Krea-2-depth-controlnet). | |
| *Best with photos / renders that have real perspective. Flat 2D | |
| illustrations give weak control. Empty prompt = depth-only generation.* | |
| """ | |
| ) | |
| with gr.Row(): | |
| with gr.Column(): | |
| image = gr.Image(label="Input image (depth source)", type="pil") | |
| prompt = gr.Textbox( | |
| label="Prompt", | |
| placeholder="a futuristic spaceship interior, cinematic lighting", | |
| lines=2, | |
| ) | |
| run = gr.Button("Generate", variant="primary") | |
| with gr.Accordion("Advanced settings", open=False): | |
| steps = gr.Slider( | |
| 4, 16, value=8, step=1, label="Sampling steps" | |
| ) | |
| lora_scale = gr.Slider( | |
| 0.3, | |
| 1.4, | |
| value=1.0, | |
| step=0.05, | |
| label="Control strength (LoRA scale)", | |
| ) | |
| randomize_seed = gr.Checkbox( | |
| label="Randomize seed", value=True | |
| ) | |
| seed = gr.Slider( | |
| 0, MAX_SEED, value=0, step=1, label="Seed" | |
| ) | |
| with gr.Column(): | |
| output = gr.Image(label="Generated image") | |
| depth_out = gr.Image(label="Extracted depth map") | |
| gr.Examples( | |
| examples=[ | |
| ["examples/dog.jpg", "a majestic lion, golden hour, photorealistic"], | |
| [ | |
| "examples/landscape.jpg", | |
| "an alien planet landscape, purple sky, sci-fi", | |
| ], | |
| [ | |
| "examples/man_beach.jpg", | |
| "an astronaut on the moon, cinematic lighting", | |
| ], | |
| [ | |
| "examples/tent.jpg", | |
| "a cozy cabin in a snowy forest at dusk", | |
| ], | |
| ], | |
| inputs=[image, prompt], | |
| outputs=[output, depth_out, seed], | |
| fn=generate, | |
| cache_examples=True, | |
| cache_mode="lazy", | |
| ) | |
| run.click( | |
| fn=generate, | |
| inputs=[image, prompt, steps, lora_scale, seed, randomize_seed], | |
| outputs=[output, depth_out, seed], | |
| api_name="generate", | |
| ) | |
| if __name__ == "__main__": | |
| demo.launch(mcp_server=True) | |