Spaces:
Runtime error
Runtime error
Download app.py from NotRIK/ZImage-Img2Img: direct link, hf CLI and curl.
- Browser
- Download file 10.8 kB
-
https://huggingface.co/spaces/NotRIK/ZImage-Img2Img/resolve/main/app.py
- Command line
-
hf download hf://spaces/NotRIK/ZImage-Img2Img/app.py
-
curl -L -o app.py https://huggingface.co/spaces/NotRIK/ZImage-Img2Img/resolve/main/app.py
10.8 kB
| import random | |
| import gradio as gr | |
| import spaces | |
| import torch | |
| from PIL import Image | |
| from diffusers import ZImageImg2ImgPipeline | |
| # ============================================================ | |
| # CONFIG | |
| # ============================================================ | |
| MODEL_ID = "Tongyi-MAI/Z-Image-Turbo" | |
| # IMPORTANT: | |
| # Z-Image strength=1.0 essentially ignores the input image. | |
| # We intentionally cap the UI at 0.85 for better editing behavior. | |
| MIN_STRENGTH = 0.15 | |
| MAX_STRENGTH = 0.85 | |
| DEFAULT_STRENGTH = 0.55 | |
| NUM_INFERENCE_STEPS = 8 | |
| GUIDANCE_SCALE = 0.0 | |
| MAX_IMAGE_SIZE = 1024 | |
| GPU_DURATION = 180 | |
| # ============================================================ | |
| # MODEL | |
| # ============================================================ | |
| print( | |
| "Loading Z-Image-Turbo...", | |
| flush=True, | |
| ) | |
| pipe = ZImageImg2ImgPipeline.from_pretrained( | |
| MODEL_ID, | |
| torch_dtype=torch.bfloat16, | |
| ) | |
| pipe.to("cuda") | |
| pipe.set_progress_bar_config( | |
| disable=True | |
| ) | |
| print( | |
| "Z-Image-Turbo loaded successfully.", | |
| flush=True, | |
| ) | |
| # ============================================================ | |
| # IMAGE PREPARATION | |
| # ============================================================ | |
| def prepare_image( | |
| image: Image.Image, | |
| ) -> Image.Image: | |
| if image is None: | |
| raise ValueError( | |
| "Please upload an image." | |
| ) | |
| image = image.convert("RGB") | |
| width, height = image.size | |
| if width < 64 or height < 64: | |
| raise ValueError( | |
| "Image must be at least 64Γ64 pixels." | |
| ) | |
| # Keep the original aspect ratio. | |
| scale = min( | |
| MAX_IMAGE_SIZE / width, | |
| MAX_IMAGE_SIZE / height, | |
| 1.0, | |
| ) | |
| new_width = int(width * scale) | |
| new_height = int(height * scale) | |
| # Z-Image works with dimensions divisible by 8. | |
| new_width = max( | |
| 64, | |
| (new_width // 8) * 8, | |
| ) | |
| new_height = max( | |
| 64, | |
| (new_height // 8) * 8, | |
| ) | |
| if ( | |
| new_width != image.width | |
| or new_height != image.height | |
| ): | |
| image = image.resize( | |
| (new_width, new_height), | |
| Image.Resampling.LANCZOS, | |
| ) | |
| return image | |
| # ============================================================ | |
| # PROMPT HANDLING | |
| # ============================================================ | |
| def build_edit_prompt( | |
| prompt: str, | |
| strength: float, | |
| ) -> str: | |
| prompt = prompt.strip() | |
| # Lower strength = stronger preservation. | |
| if strength <= 0.35: | |
| prefix = ( | |
| "Edit the provided image while preserving " | |
| "the original subject, identity, composition, " | |
| "camera angle, pose, framing, and overall " | |
| "structure. Make only the requested visual " | |
| "changes. " | |
| ) | |
| elif strength <= 0.60: | |
| prefix = ( | |
| "Transform the provided image according to " | |
| "the request while preserving the main subject, " | |
| "recognizable identity, composition, and " | |
| "important visual structure. " | |
| ) | |
| else: | |
| prefix = ( | |
| "Creatively transform the provided image " | |
| "according to the request while keeping the " | |
| "main subject and important visual identity " | |
| "recognizable. Do not completely replace the " | |
| "original concept unless explicitly requested. " | |
| ) | |
| return prefix + prompt | |
| # ============================================================ | |
| # GENERATION | |
| # ============================================================ | |
| def generate( | |
| image, | |
| prompt, | |
| strength, | |
| seed, | |
| ): | |
| if image is None: | |
| raise gr.Error( | |
| "Please upload an image first." | |
| ) | |
| if not prompt or not prompt.strip(): | |
| raise gr.Error( | |
| "Please enter a transformation prompt." | |
| ) | |
| # -------------------------------------------------------- | |
| # Strength | |
| # -------------------------------------------------------- | |
| try: | |
| strength = float(strength) | |
| except Exception: | |
| raise gr.Error( | |
| "Invalid transformation strength." | |
| ) | |
| strength = max( | |
| MIN_STRENGTH, | |
| min( | |
| MAX_STRENGTH, | |
| strength, | |
| ), | |
| ) | |
| # -------------------------------------------------------- | |
| # Seed | |
| # -------------------------------------------------------- | |
| try: | |
| seed = int(seed) | |
| except Exception: | |
| seed = -1 | |
| if seed < 0: | |
| seed = random.SystemRandom().randint( | |
| 0, | |
| 2**32 - 1, | |
| ) | |
| # -------------------------------------------------------- | |
| # Generation | |
| # -------------------------------------------------------- | |
| try: | |
| image = prepare_image(image) | |
| final_prompt = build_edit_prompt( | |
| prompt, | |
| strength, | |
| ) | |
| generator = torch.Generator( | |
| device="cuda" | |
| ).manual_seed(seed) | |
| print( | |
| "Generation started | " | |
| f"seed={seed} | " | |
| f"strength={strength}", | |
| flush=True, | |
| ) | |
| print( | |
| f"Prompt: {final_prompt}", | |
| flush=True, | |
| ) | |
| with torch.inference_mode(): | |
| result = pipe( | |
| prompt=final_prompt, | |
| image=image, | |
| strength=strength, | |
| num_inference_steps=NUM_INFERENCE_STEPS, | |
| guidance_scale=GUIDANCE_SCALE, | |
| generator=generator, | |
| ) | |
| output = result.images[0] | |
| print( | |
| "Generation complete | " | |
| f"seed={seed}", | |
| flush=True, | |
| ) | |
| return output, seed | |
| except torch.cuda.OutOfMemoryError: | |
| if torch.cuda.is_available(): | |
| torch.cuda.empty_cache() | |
| raise gr.Error( | |
| "GPU memory was insufficient. " | |
| "Try a smaller input image." | |
| ) | |
| except Exception as exc: | |
| print( | |
| "Generation error:", | |
| repr(exc), | |
| flush=True, | |
| ) | |
| if torch.cuda.is_available(): | |
| torch.cuda.empty_cache() | |
| raise gr.Error( | |
| f"Generation failed: {exc}" | |
| ) | |
| # ============================================================ | |
| # UI | |
| # ============================================================ | |
| CSS = """ | |
| #title { | |
| text-align: center; | |
| } | |
| #subtitle { | |
| text-align: center; | |
| opacity: 0.7; | |
| } | |
| .generate-btn { | |
| min-height: 52px; | |
| font-size: 18px !important; | |
| font-weight: 600 !important; | |
| } | |
| .strength-info { | |
| text-align: center; | |
| opacity: 0.7; | |
| font-size: 13px; | |
| } | |
| """ | |
| with gr.Blocks( | |
| title="IMAGINE β Z-Image Image to Image", | |
| css=CSS, | |
| ) as demo: | |
| gr.Markdown( | |
| "# IMAGINE", | |
| elem_id="title", | |
| ) | |
| gr.Markdown( | |
| "Z-Image-Turbo Image Transformation", | |
| elem_id="subtitle", | |
| ) | |
| with gr.Row(): | |
| # ==================================================== | |
| # INPUT | |
| # ==================================================== | |
| with gr.Column(): | |
| input_image = gr.Image( | |
| type="pil", | |
| label="Upload Image", | |
| ) | |
| prompt = gr.Textbox( | |
| label="Transformation Prompt", | |
| placeholder=( | |
| "Example: Change the clothes to " | |
| "a black formal suit while keeping " | |
| "the person's face and pose." | |
| ), | |
| lines=4, | |
| ) | |
| strength = gr.Slider( | |
| minimum=MIN_STRENGTH, | |
| maximum=MAX_STRENGTH, | |
| value=DEFAULT_STRENGTH, | |
| step=0.05, | |
| label="Transformation Strength", | |
| info=( | |
| "Lower = preserve more β’ " | |
| "Higher = transform more" | |
| ), | |
| ) | |
| gr.Markdown( | |
| "Preserve βββββββββ Balanced βββββββββ Transform", | |
| elem_classes="strength-info", | |
| ) | |
| seed = gr.Number( | |
| value=-1, | |
| precision=0, | |
| label="Seed", | |
| info="-1 = random", | |
| ) | |
| generate_button = gr.Button( | |
| "Generate Image", | |
| variant="primary", | |
| elem_classes="generate-btn", | |
| ) | |
| # ==================================================== | |
| # OUTPUT | |
| # ==================================================== | |
| with gr.Column(): | |
| output_image = gr.Image( | |
| type="pil", | |
| label="Generated Image", | |
| ) | |
| output_seed = gr.Number( | |
| label="Used Seed", | |
| interactive=False, | |
| ) | |
| # ======================================================== | |
| # EXAMPLES | |
| # ======================================================== | |
| gr.Examples( | |
| examples=[ | |
| [ | |
| ( | |
| "Change the lighting to warm golden " | |
| "hour lighting while keeping the " | |
| "same person, face, pose, background " | |
| "and composition." | |
| ), | |
| 0.30, | |
| -1, | |
| ], | |
| [ | |
| ( | |
| "Change the person's clothing to a " | |
| "premium black formal outfit while " | |
| "keeping the same face, pose and " | |
| "composition." | |
| ), | |
| 0.50, | |
| -1, | |
| ], | |
| [ | |
| ( | |
| "Transform this scene into a cinematic " | |
| "fantasy environment while keeping " | |
| "the main subject recognizable." | |
| ), | |
| 0.70, | |
| -1, | |
| ], | |
| ], | |
| inputs=[ | |
| prompt, | |
| strength, | |
| seed, | |
| ], | |
| ) | |
| # ======================================================== | |
| # API | |
| # ======================================================== | |
| generate_button.click( | |
| fn=generate, | |
| inputs=[ | |
| input_image, | |
| prompt, | |
| strength, | |
| seed, | |
| ], | |
| outputs=[ | |
| output_image, | |
| output_seed, | |
| ], | |
| api_name="generate", | |
| ) | |
| # ============================================================ | |
| # LAUNCH | |
| # ============================================================ | |
| if __name__ == "__main__": | |
| demo.queue( | |
| max_size=20, | |
| default_concurrency_limit=1, | |
| ).launch( | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| ) |