import tempfile import spaces import gradio as gr import torch from diffusers import ZImagePipeline import os from pathlib import Path import hashlib import re from datetime import datetime # Load the model directly at startup print("Loading Z-Image Turbo model...") print("This may take a few minutes on first run while the model downloads...") # Directory where images will be stored IMAGE_DIR = Path("generated_images") IMAGE_DIR.mkdir(exist_ok=True) # Load the pipeline with optimal settings pipe = ZImagePipeline.from_pretrained( "Tongyi-MAI/Z-Image-Turbo", torch_dtype=torch.bfloat16, low_cpu_mem_usage=False, ) # Move to GPU if available device = "cuda" if torch.cuda.is_available() else "cpu" pipe.to(device) print(f"Model loaded on {device}") print("Model loaded successfully!") def prompt_hash(prompt: str) -> str: """Create a stable hash from the prompt.""" return hashlib.sha256(prompt.strip().encode("utf-8")).hexdigest()[:16] def clean_prompt(prompt: str, max_len=40): """Make a readable safe filename part from prompt.""" safe = re.sub(r"[^a-zA-Z0-9_-]", "_", prompt.strip()) return safe[:max_len] def build_filename(prompt: str) -> Path: """Build deterministic filename from prompt hash.""" h = prompt_hash(prompt) readable = clean_prompt(prompt) return IMAGE_DIR / f"{readable}_{h}.png" @spaces.GPU() def generate_image( prompt, progress=gr.Progress(track_tqdm=True) ): """ Generate an image using Z-Image Turbo model. Args: prompt: Text description of the desired image Returns: Generated PIL Image """ global pipe if pipe is None: raise gr.Error("Model failed to load on startup. Please restart the application.") if not prompt.strip(): raise gr.Error("Please enter a prompt to generate an image.") # Determine device device = "cuda" if torch.cuda.is_available() else "cpu" # Set random seed for reproducibility generator = torch.Generator(device).manual_seed(42) # Generate the image with optimal settings progress(0.1, desc="Generating image...") try: result = pipe( prompt=prompt, negative_prompt=None, height=1024, width=1024, num_inference_steps=9, guidance_scale=0.0, generator=generator, ) image = result.images[0] # Build permanent filename from prompt file_path = build_filename(prompt) # If already generated → reuse it if file_path.exists(): print("Using cached image:", file_path) progress(1.0, desc="Loaded from cache!") return str(file_path) # Save new file image.save(file_path, format="PNG") progress(1.0, desc="Saved!") return str(file_path) except Exception as e: raise gr.Error(f"Generation failed: {str(e)}") # Apple-style CSS apple_css = """ /* Global Styles */ .gradio-container { max-width: 980px !important; margin: 0 auto !important; padding: 48px 20px !important; font-family: -apple-system, BlinkMacSystemFont, 'Inter', 'Segoe UI', 'Roboto', sans-serif !important; } /* Header */ .header-container { text-align: center; margin-bottom: 48px; } .main-title { font-size: 56px !important; font-weight: 600 !important; letter-spacing: -0.02em !important; line-height: 1.07 !important; color: #1d1d1f !important; margin: 0 0 12px 0 !important; } .subtitle { font-size: 21px !important; font-weight: 400 !important; line-height: 1.38 !important; color: #6e6e73 !important; margin: 0 0 24px 0 !important; } .attribution-link { display: inline-block; font-size: 14px !important; color: #0071e3 !important; text-decoration: none !important; font-weight: 400 !important; transition: color 0.2s ease !important; } .attribution-link:hover { color: #0077ed !important; text-decoration: underline !important; } /* Input Section */ .input-section { background: #ffffff; border-radius: 18px; padding: 32px; margin-bottom: 24px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); } /* Textbox */ textarea { font-size: 17px !important; line-height: 1.47 !important; border-radius: 12px !important; border: 1px solid #d2d2d7 !important; padding: 12px 16px !important; transition: all 0.2s ease !important; background: #ffffff !important; font-family: -apple-system, BlinkMacSystemFont, 'Inter', sans-serif !important; } textarea:focus { border-color: #0071e3 !important; box-shadow: 0 0 0 4px rgba(0, 113, 227, 0.15) !important; outline: none !important; } textarea::placeholder { color: #86868b !important; } /* Button */ button.primary { font-size: 17px !important; font-weight: 400 !important; padding: 12px 32px !important; border-radius: 980px !important; background: #0071e3 !important; border: none !important; color: #ffffff !important; min-height: 44px !important; transition: all 0.2s ease !important; letter-spacing: -0.01em !important; cursor: pointer !important; } button.primary:hover { background: #0077ed !important; transform: scale(1.02) !important; } button.primary:active { transform: scale(0.98) !important; } /* Output Section */ .output-section { background: #ffffff; border-radius: 18px; padding: 32px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08); overflow: hidden; } .output-section img { border-radius: 12px !important; width: 100% !important; height: auto !important; } /* Footer */ .footer-text { text-align: center; margin-top: 48px; font-size: 14px !important; color: #86868b !important; line-height: 1.43 !important; } /* Progress */ .progress-bar { background: #0071e3 !important; border-radius: 4px !important; } /* Dark Mode */ .dark .main-title { color: #f5f5f7 !important; } .dark .subtitle { color: #a1a1a6 !important; } .dark .input-section, .dark .output-section { background: #1d1d1f; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4); } .dark textarea { background: #1d1d1f !important; border-color: #424245 !important; color: #f5f5f7 !important; } .dark textarea::placeholder { color: #86868b !important; } /* Responsive */ @media (max-width: 734px) { .main-title { font-size: 40px !important; } .subtitle { font-size: 19px !important; } .gradio-container { padding: 32px 16px !important; } .input-section, .output-section { padding: 24px !important; } } /* Remove default Gradio styling */ .contain { padding: 0 !important; } """ # Create the interface with gr.Blocks( title="Z-Image Turbo", fill_height=False, ) as demo: # Header gr.HTML("""
Text2PNG - i made it save as PNG to make this work with google docs (in progress).
Built with anycoder