Spaces:
Runtime error
Runtime error
| """ | |
| Z-Image-Turbo: Ultra-fast AI image generation powered by diffusion models. | |
| A Gradio-based web application for generating images using the Tongyi-MAI/Z-Image-Turbo | |
| model. Features a modern dark UI with purple/violet accent theme. | |
| """ | |
| import torch | |
| import spaces | |
| import gradio as gr | |
| from diffusers import DiffusionPipeline | |
| # ============================================================================= | |
| # CONFIGURATION CONSTANTS | |
| # ============================================================================= | |
| ASPECT_RATIOS = { | |
| "1:1 Square": (1024, 1024), | |
| "16:9 Landscape": (1344, 768), | |
| "9:16 Portrait": (768, 1344), | |
| "4:3 Standard": (1152, 896), | |
| "3:4 Portrait": (896, 1152), | |
| "21:9 Cinematic": (1536, 640), | |
| "Custom": None, | |
| } | |
| EXAMPLE_PROMPTS = [ | |
| ["Young Chinese woman in red Hanfu, intricate embroidery. Impeccable makeup, red floral forehead pattern. Elaborate high bun, golden phoenix headdress, red flowers, beads. Holds round folding fan with lady, trees, bird. Neon lightning-bolt lamp, bright yellow glow, above extended left palm. Soft-lit outdoor night background, silhouetted tiered pagoda, blurred colorful distant lights."], | |
| ["A majestic dragon soaring through clouds at sunset, scales shimmering with iridescent colors, detailed fantasy art style"], | |
| ["Cozy coffee shop interior, warm lighting, rain on windows, plants on shelves, vintage aesthetic, photorealistic"], | |
| ["Astronaut riding a horse on Mars, cinematic lighting, sci-fi concept art, highly detailed"], | |
| ["Portrait of a wise old wizard with a long white beard, holding a glowing crystal staff, magical forest background"], | |
| ["Cyberpunk street scene at night, neon signs reflecting in rain puddles, flying cars overhead, blade runner aesthetic"], | |
| ["Serene Japanese zen garden with cherry blossoms, koi pond, wooden bridge, morning mist, traditional painting style"], | |
| ["Steampunk mechanical owl with brass gears and glowing amber eyes, perched on old leather-bound books, warm candlelight"], | |
| ] | |
| DEFAULT_SETTINGS = { | |
| "height": 1024, | |
| "width": 1024, | |
| "inference_steps": 9, | |
| "guidance_scale": 0.0, | |
| "seed": 42, | |
| } | |
| # ============================================================================= | |
| # THEME CONFIGURATION | |
| # ============================================================================= | |
| def create_theme(): | |
| """Create the modern dark theme with purple/violet accents.""" | |
| return gr.themes.Base( | |
| primary_hue="violet", | |
| secondary_hue="purple", | |
| neutral_hue="slate", | |
| font=gr.themes.GoogleFont("Inter"), | |
| text_size="lg", | |
| spacing_size="md", | |
| radius_size="lg" | |
| ).set( | |
| # Dark mode colors | |
| body_background_fill="*neutral_950", | |
| body_background_fill_dark="*neutral_950", | |
| background_fill_primary="*neutral_900", | |
| background_fill_primary_dark="*neutral_900", | |
| background_fill_secondary="*neutral_800", | |
| background_fill_secondary_dark="*neutral_800", | |
| # Text colors | |
| body_text_color="*neutral_100", | |
| body_text_color_dark="*neutral_100", | |
| body_text_color_subdued="*neutral_400", | |
| body_text_color_subdued_dark="*neutral_400", | |
| # Border styling | |
| border_color_primary="*neutral_700", | |
| border_color_primary_dark="*neutral_700", | |
| block_border_width="1px", | |
| # Button styling | |
| button_primary_background_fill="linear-gradient(135deg, *primary_500 0%, *secondary_600 100%)", | |
| button_primary_background_fill_hover="linear-gradient(135deg, *primary_400 0%, *secondary_500 100%)", | |
| button_primary_text_color="white", | |
| button_primary_border_color="transparent", | |
| # Input styling | |
| input_background_fill="*neutral_800", | |
| input_background_fill_dark="*neutral_800", | |
| input_border_color="*neutral_600", | |
| input_border_color_dark="*neutral_600", | |
| input_border_color_focus="*primary_500", | |
| input_border_color_focus_dark="*primary_500", | |
| # Block styling | |
| block_background_fill="*neutral_900", | |
| block_background_fill_dark="*neutral_900", | |
| block_label_background_fill="*neutral_800", | |
| block_label_text_color="*neutral_200", | |
| block_title_text_weight="600", | |
| block_label_text_weight="500", | |
| # Shadow and depth | |
| shadow_drop="0 4px 20px rgba(0, 0, 0, 0.3)", | |
| shadow_drop_lg="0 8px 40px rgba(0, 0, 0, 0.4)", | |
| ) | |
| # ============================================================================= | |
| # CUSTOM CSS | |
| # ============================================================================= | |
| CUSTOM_CSS = """ | |
| /* ===== ROOT VARIABLES ===== */ | |
| :root { | |
| --accent-primary: #8b5cf6; | |
| --accent-secondary: #a855f7; | |
| --accent-glow: rgba(139, 92, 246, 0.4); | |
| --bg-dark: #0a0a0f; | |
| --bg-card: #111118; | |
| --bg-elevated: #1a1a24; | |
| --text-primary: #f1f5f9; | |
| --text-secondary: #94a3b8; | |
| --text-muted: #64748b; | |
| --border-subtle: rgba(148, 163, 184, 0.1); | |
| --border-hover: rgba(139, 92, 246, 0.3); | |
| --gradient-primary: linear-gradient(135deg, #8b5cf6 0%, #a855f7 50%, #d946ef 100%); | |
| --gradient-hero: linear-gradient(135deg, #0f0f1a 0%, #1a1025 50%, #0f0f1a 100%); | |
| } | |
| /* ===== BASE STYLES ===== */ | |
| .gradio-container { | |
| max-width: 1400px !important; | |
| margin: 0 auto !important; | |
| background: var(--bg-dark) !important; | |
| } | |
| .dark { | |
| --background-fill-primary: var(--bg-dark) !important; | |
| } | |
| /* ===== HERO SECTION ===== */ | |
| .hero-section { | |
| position: relative; | |
| padding: 3rem 2rem; | |
| text-align: center; | |
| overflow: hidden; | |
| border-radius: 20px; | |
| margin-bottom: 2rem; | |
| background: var(--gradient-hero); | |
| } | |
| .hero-background { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: | |
| radial-gradient(ellipse at 20% 50%, rgba(139, 92, 246, 0.15) 0%, transparent 50%), | |
| radial-gradient(ellipse at 80% 50%, rgba(168, 85, 247, 0.15) 0%, transparent 50%), | |
| radial-gradient(ellipse at 50% 100%, rgba(217, 70, 239, 0.1) 0%, transparent 50%); | |
| animation: pulse-glow 8s ease-in-out infinite; | |
| } | |
| @keyframes pulse-glow { | |
| 0%, 100% { opacity: 0.7; } | |
| 50% { opacity: 1; } | |
| } | |
| .hero-content { | |
| position: relative; | |
| z-index: 1; | |
| } | |
| .logo-badge { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| width: 64px; | |
| height: 64px; | |
| background: var(--gradient-primary); | |
| border-radius: 16px; | |
| margin-bottom: 1rem; | |
| box-shadow: 0 8px 32px var(--accent-glow); | |
| } | |
| .logo-icon { | |
| font-size: 2rem; | |
| font-weight: 800; | |
| color: white; | |
| font-family: 'Inter', sans-serif; | |
| } | |
| .hero-title { | |
| font-size: 3rem; | |
| font-weight: 800; | |
| margin: 0.5rem 0; | |
| background: var(--gradient-primary); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| background-clip: text; | |
| letter-spacing: -0.02em; | |
| } | |
| .hero-subtitle { | |
| font-size: 1.1rem; | |
| color: var(--text-secondary); | |
| margin: 0.5rem 0 1.5rem; | |
| font-weight: 400; | |
| } | |
| .hero-stats { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 1.5rem; | |
| padding: 1rem 2rem; | |
| background: rgba(255, 255, 255, 0.03); | |
| border: 1px solid var(--border-subtle); | |
| border-radius: 100px; | |
| backdrop-filter: blur(10px); | |
| } | |
| .stat-item { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| gap: 0.25rem; | |
| } | |
| .stat-value { | |
| font-size: 1.25rem; | |
| font-weight: 700; | |
| color: var(--accent-primary); | |
| } | |
| .stat-label { | |
| font-size: 0.75rem; | |
| color: var(--text-muted); | |
| text-transform: uppercase; | |
| letter-spacing: 0.05em; | |
| } | |
| .stat-divider { | |
| width: 1px; | |
| height: 32px; | |
| background: var(--border-subtle); | |
| } | |
| /* ===== MAIN CONTAINER ===== */ | |
| .main-container { | |
| gap: 2rem !important; | |
| } | |
| /* ===== SECTION HEADERS ===== */ | |
| .section-header { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| font-size: 0.875rem; | |
| font-weight: 600; | |
| color: var(--text-secondary); | |
| text-transform: uppercase; | |
| letter-spacing: 0.08em; | |
| margin-bottom: 0.75rem; | |
| padding-left: 0.25rem; | |
| } | |
| .section-icon { | |
| font-size: 1rem; | |
| color: var(--accent-primary); | |
| } | |
| /* ===== CONTROLS COLUMN ===== */ | |
| .controls-column { | |
| padding: 0 !important; | |
| } | |
| /* ===== PROMPT INPUT ===== */ | |
| .prompt-input textarea { | |
| background: var(--bg-card) !important; | |
| border: 2px solid var(--border-subtle) !important; | |
| border-radius: 16px !important; | |
| padding: 1rem !important; | |
| font-size: 1rem !important; | |
| color: var(--text-primary) !important; | |
| transition: all 0.3s ease !important; | |
| min-height: 120px !important; | |
| } | |
| .prompt-input textarea:focus { | |
| border-color: var(--accent-primary) !important; | |
| box-shadow: 0 0 0 4px var(--accent-glow), 0 4px 20px rgba(0, 0, 0, 0.3) !important; | |
| } | |
| .prompt-input textarea::placeholder { | |
| color: var(--text-muted) !important; | |
| } | |
| /* ===== QUICK ACTIONS ===== */ | |
| .quick-actions { | |
| gap: 0.5rem !important; | |
| margin-top: 0.5rem !important; | |
| margin-bottom: 1.5rem !important; | |
| } | |
| .action-btn { | |
| flex: 1; | |
| } | |
| .action-btn button { | |
| width: 100% !important; | |
| background: var(--bg-elevated) !important; | |
| border: 1px solid var(--border-subtle) !important; | |
| color: var(--text-secondary) !important; | |
| border-radius: 10px !important; | |
| font-size: 0.875rem !important; | |
| padding: 0.5rem 1rem !important; | |
| transition: all 0.2s ease !important; | |
| } | |
| .action-btn button:hover { | |
| background: var(--bg-card) !important; | |
| border-color: var(--border-hover) !important; | |
| color: var(--text-primary) !important; | |
| } | |
| /* ===== ASPECT RATIO SELECTOR ===== */ | |
| .aspect-radio { | |
| margin-bottom: 1rem !important; | |
| } | |
| .aspect-radio .wrap { | |
| display: grid !important; | |
| grid-template-columns: repeat(4, 1fr) !important; | |
| gap: 0.5rem !important; | |
| } | |
| .aspect-radio label { | |
| display: flex !important; | |
| align-items: center !important; | |
| justify-content: center !important; | |
| padding: 0.625rem 0.5rem !important; | |
| background: var(--bg-card) !important; | |
| border: 1px solid var(--border-subtle) !important; | |
| border-radius: 10px !important; | |
| cursor: pointer !important; | |
| transition: all 0.2s ease !important; | |
| font-size: 0.75rem !important; | |
| color: var(--text-secondary) !important; | |
| text-align: center !important; | |
| } | |
| .aspect-radio label:hover { | |
| border-color: var(--border-hover) !important; | |
| background: var(--bg-elevated) !important; | |
| } | |
| .aspect-radio label.selected, | |
| .aspect-radio input:checked + label { | |
| background: var(--accent-primary) !important; | |
| border-color: var(--accent-primary) !important; | |
| color: white !important; | |
| } | |
| /* ===== DIMENSION SLIDERS ===== */ | |
| .dimension-row { | |
| gap: 1rem !important; | |
| margin-bottom: 1rem !important; | |
| } | |
| .dimension-slider { | |
| flex: 1; | |
| } | |
| .dimension-slider input[type="range"] { | |
| accent-color: var(--accent-primary) !important; | |
| } | |
| /* ===== ADVANCED ACCORDION ===== */ | |
| .advanced-accordion { | |
| margin-bottom: 1.5rem !important; | |
| } | |
| .advanced-accordion > .label-wrap { | |
| background: var(--bg-card) !important; | |
| border: 1px solid var(--border-subtle) !important; | |
| border-radius: 12px !important; | |
| padding: 0.75rem 1rem !important; | |
| } | |
| .advanced-accordion .icon { | |
| color: var(--accent-primary) !important; | |
| } | |
| /* ===== GENERATE BUTTON ===== */ | |
| .generate-btn button { | |
| width: 100% !important; | |
| background: var(--gradient-primary) !important; | |
| border: none !important; | |
| border-radius: 14px !important; | |
| padding: 1rem 2rem !important; | |
| font-size: 1.1rem !important; | |
| font-weight: 600 !important; | |
| color: white !important; | |
| cursor: pointer !important; | |
| transition: all 0.3s ease !important; | |
| box-shadow: 0 4px 20px var(--accent-glow) !important; | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .generate-btn button::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: -100%; | |
| width: 100%; | |
| height: 100%; | |
| background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); | |
| transition: left 0.5s ease; | |
| } | |
| .generate-btn button:hover { | |
| transform: translateY(-2px) !important; | |
| box-shadow: 0 8px 32px var(--accent-glow) !important; | |
| } | |
| .generate-btn button:hover::before { | |
| left: 100%; | |
| } | |
| .generate-btn button:active { | |
| transform: translateY(0) !important; | |
| } | |
| /* ===== EXAMPLES GALLERY ===== */ | |
| #examples-gallery { | |
| margin-top: 0.5rem; | |
| } | |
| #examples-gallery .gallery { | |
| display: grid !important; | |
| grid-template-columns: repeat(2, 1fr) !important; | |
| gap: 0.5rem !important; | |
| } | |
| #examples-gallery .gallery button { | |
| background: var(--bg-card) !important; | |
| border: 1px solid var(--border-subtle) !important; | |
| border-radius: 10px !important; | |
| padding: 0.75rem !important; | |
| text-align: left !important; | |
| font-size: 0.75rem !important; | |
| color: var(--text-secondary) !important; | |
| line-height: 1.4 !important; | |
| transition: all 0.2s ease !important; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| display: -webkit-box; | |
| -webkit-line-clamp: 2; | |
| -webkit-box-orient: vertical; | |
| } | |
| #examples-gallery .gallery button:hover { | |
| border-color: var(--border-hover) !important; | |
| color: var(--text-primary) !important; | |
| background: var(--bg-elevated) !important; | |
| } | |
| /* ===== OUTPUT COLUMN ===== */ | |
| .output-column { | |
| background: var(--bg-card) !important; | |
| border-radius: 20px !important; | |
| padding: 1.5rem !important; | |
| border: 1px solid var(--border-subtle) !important; | |
| } | |
| .output-image { | |
| border-radius: 16px !important; | |
| overflow: hidden !important; | |
| background: var(--bg-elevated) !important; | |
| border: 1px solid var(--border-subtle) !important; | |
| } | |
| .output-image img { | |
| border-radius: 16px !important; | |
| } | |
| .output-image .icon-buttons { | |
| background: rgba(0, 0, 0, 0.6) !important; | |
| backdrop-filter: blur(10px) !important; | |
| border-radius: 10px !important; | |
| } | |
| /* ===== IMAGE INFO BAR ===== */ | |
| .image-info-bar { | |
| margin-top: 1rem !important; | |
| padding-top: 1rem !important; | |
| border-top: 1px solid var(--border-subtle) !important; | |
| } | |
| .seed-display input { | |
| background: var(--bg-elevated) !important; | |
| border: 1px solid var(--border-subtle) !important; | |
| border-radius: 8px !important; | |
| color: var(--text-secondary) !important; | |
| font-family: 'JetBrains Mono', monospace !important; | |
| } | |
| /* ===== FOOTER ===== */ | |
| .app-footer { | |
| margin-top: 2rem; | |
| padding: 1.5rem; | |
| border-top: 1px solid var(--border-subtle); | |
| } | |
| .footer-content { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| flex-wrap: wrap; | |
| gap: 1rem; | |
| } | |
| .footer-links { | |
| display: flex; | |
| align-items: center; | |
| gap: 1rem; | |
| flex-wrap: wrap; | |
| } | |
| .footer-link { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.375rem; | |
| color: var(--text-secondary); | |
| text-decoration: none; | |
| font-size: 0.875rem; | |
| transition: color 0.2s ease; | |
| } | |
| .footer-link:hover { | |
| color: var(--accent-primary); | |
| } | |
| .link-icon { | |
| font-size: 1rem; | |
| } | |
| .footer-divider { | |
| color: var(--text-muted); | |
| } | |
| .footer-text { | |
| color: var(--text-muted); | |
| font-size: 0.875rem; | |
| } | |
| .footer-badge { | |
| display: inline-block; | |
| padding: 0.375rem 0.75rem; | |
| background: var(--bg-elevated); | |
| border: 1px solid var(--border-subtle); | |
| border-radius: 100px; | |
| font-size: 0.75rem; | |
| color: var(--text-muted); | |
| } | |
| /* ===== RESPONSIVE DESIGN ===== */ | |
| @media (max-width: 768px) { | |
| .hero-section { | |
| padding: 2rem 1rem; | |
| } | |
| .hero-title { | |
| font-size: 2rem; | |
| } | |
| .hero-subtitle { | |
| font-size: 0.95rem; | |
| } | |
| .hero-stats { | |
| flex-wrap: wrap; | |
| padding: 0.75rem 1rem; | |
| gap: 1rem; | |
| } | |
| .stat-divider { | |
| display: none; | |
| } | |
| .main-container { | |
| flex-direction: column !important; | |
| } | |
| .output-column { | |
| order: -1; | |
| } | |
| .aspect-radio .wrap { | |
| grid-template-columns: repeat(2, 1fr) !important; | |
| } | |
| #examples-gallery .gallery { | |
| grid-template-columns: 1fr !important; | |
| } | |
| .footer-content { | |
| flex-direction: column; | |
| text-align: center; | |
| } | |
| } | |
| /* ===== LOADING STATE ===== */ | |
| .generating .output-image { | |
| position: relative; | |
| } | |
| .generating .output-image::after { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| bottom: 0; | |
| background: linear-gradient( | |
| 90deg, | |
| transparent, | |
| rgba(139, 92, 246, 0.1), | |
| transparent | |
| ); | |
| animation: shimmer 1.5s infinite; | |
| } | |
| @keyframes shimmer { | |
| 0% { transform: translateX(-100%); } | |
| 100% { transform: translateX(100%); } | |
| } | |
| /* ===== SCROLLBAR ===== */ | |
| ::-webkit-scrollbar { | |
| width: 8px; | |
| height: 8px; | |
| } | |
| ::-webkit-scrollbar-track { | |
| background: var(--bg-dark); | |
| } | |
| ::-webkit-scrollbar-thumb { | |
| background: var(--border-subtle); | |
| border-radius: 4px; | |
| } | |
| ::-webkit-scrollbar-thumb:hover { | |
| background: var(--text-muted); | |
| } | |
| /* ===== ANIMATIONS ===== */ | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| .controls-column, .output-column { | |
| animation: fadeIn 0.5s ease-out; | |
| } | |
| .output-column { | |
| animation-delay: 0.1s; | |
| } | |
| """ | |
| # ============================================================================= | |
| # HTML TEMPLATES | |
| # ============================================================================= | |
| HERO_HTML = """ | |
| <div class="hero-section"> | |
| <div class="hero-background"></div> | |
| <div class="hero-content"> | |
| <div class="logo-badge"> | |
| <span class="logo-icon">Z</span> | |
| </div> | |
| <h1 class="hero-title">Z-Image-Turbo</h1> | |
| <p class="hero-subtitle">Ultra-fast AI image generation powered by state-of-the-art diffusion</p> | |
| <div class="hero-stats"> | |
| <div class="stat-item"> | |
| <span class="stat-value">8</span> | |
| <span class="stat-label">DiT Steps</span> | |
| </div> | |
| <div class="stat-divider"></div> | |
| <div class="stat-item"> | |
| <span class="stat-value">2K</span> | |
| <span class="stat-label">Max Resolution</span> | |
| </div> | |
| <div class="stat-divider"></div> | |
| <div class="stat-item"> | |
| <span class="stat-value"><3s</span> | |
| <span class="stat-label">Generation</span> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| FOOTER_HTML = """ | |
| <footer class="app-footer"> | |
| <div class="footer-content"> | |
| <div class="footer-links"> | |
| <a href="https://huggingface.co/Tongyi-MAI/Z-Image-Turbo" target="_blank" class="footer-link"> | |
| <span class="link-icon">🤗</span> Model | |
| </a> | |
| <span class="footer-divider">|</span> | |
| <a href="https://x.com/realmrfakename" target="_blank" class="footer-link"> | |
| <span class="link-icon">👨‍💻</span> @mrfakename | |
| </a> | |
| <span class="footer-divider">|</span> | |
| <span class="footer-text">Redesigned with care</span> | |
| </div> | |
| <div class="footer-badge"> | |
| Apache 2.0 License | |
| </div> | |
| </div> | |
| </footer> | |
| """ | |
| # ============================================================================= | |
| # MODEL INITIALIZATION | |
| # ============================================================================= | |
| def load_pipeline(): | |
| """Load and configure the diffusion pipeline.""" | |
| print("Loading Z-Image-Turbo pipeline...") | |
| pipeline = DiffusionPipeline.from_pretrained( | |
| "Tongyi-MAI/Z-Image-Turbo", | |
| torch_dtype=torch.bfloat16, | |
| low_cpu_mem_usage=False, | |
| ) | |
| pipeline.to("cuda") | |
| print("Pipeline loaded!") | |
| return pipeline | |
| # Initialize pipeline at module level | |
| pipe = load_pipeline() | |
| # ============================================================================= | |
| # CORE FUNCTIONS | |
| # ============================================================================= | |
| def generate_image( | |
| prompt: str, | |
| height: int, | |
| width: int, | |
| num_inference_steps: int, | |
| seed: int, | |
| randomize_seed: bool, | |
| progress=gr.Progress(track_tqdm=True) | |
| ): | |
| """Generate an image from the given prompt. | |
| Args: | |
| prompt: Text description of the image to generate | |
| height: Output image height in pixels | |
| width: Output image width in pixels | |
| num_inference_steps: Number of denoising steps | |
| seed: Random seed for reproducibility | |
| randomize_seed: Whether to use a random seed | |
| progress: Gradio progress tracker | |
| Returns: | |
| Tuple of (generated image, seed used) | |
| """ | |
| if not prompt or prompt.strip() == "": | |
| gr.Warning("Please enter a prompt first!") | |
| return None, None | |
| if randomize_seed: | |
| seed = torch.randint(0, 2**32 - 1, (1,)).item() | |
| generator = torch.Generator("cuda").manual_seed(int(seed)) | |
| image = pipe( | |
| prompt=prompt, | |
| height=int(height), | |
| width=int(width), | |
| num_inference_steps=int(num_inference_steps), | |
| guidance_scale=DEFAULT_SETTINGS["guidance_scale"], | |
| generator=generator, | |
| ).images[0] | |
| return image, seed | |
| def update_dimensions(aspect_ratio: str): | |
| """Update height and width sliders based on selected aspect ratio. | |
| Args: | |
| aspect_ratio: Selected aspect ratio key from ASPECT_RATIOS | |
| Returns: | |
| Tuple of (height slider, width slider) with updated values | |
| """ | |
| if aspect_ratio == "Custom": | |
| return gr.Slider(interactive=True), gr.Slider(interactive=True) | |
| dims = ASPECT_RATIOS.get(aspect_ratio) | |
| if dims: | |
| return ( | |
| gr.Slider(value=dims[1], interactive=False), | |
| gr.Slider(value=dims[0], interactive=False) | |
| ) | |
| return gr.Slider(interactive=True), gr.Slider(interactive=True) | |
| def toggle_seed_visibility(randomize: bool): | |
| """Toggle seed input visibility based on randomize checkbox.""" | |
| return gr.Number(visible=not randomize) | |
| def clear_prompt(): | |
| """Clear the prompt textbox.""" | |
| return "" | |
| def enhance_prompt(prompt_text: str) -> str: | |
| """Add quality enhancement keywords to a prompt. | |
| Args: | |
| prompt_text: Original prompt text | |
| Returns: | |
| Enhanced prompt with quality keywords added | |
| """ | |
| if not prompt_text: | |
| return prompt_text | |
| enhancements = ", highly detailed, professional photography, 8k resolution, cinematic lighting, masterpiece" | |
| enhancement_keywords = ["detailed", "8k", "cinematic", "masterpiece"] | |
| if not any(keyword in prompt_text.lower() for keyword in enhancement_keywords): | |
| return prompt_text + enhancements | |
| return prompt_text | |
| # ============================================================================= | |
| # UI BUILDER | |
| # ============================================================================= | |
| def build_controls_column(): | |
| """Build the left controls column with prompt input and settings.""" | |
| with gr.Column(scale=4, min_width=340, elem_classes="controls-column"): | |
| # Prompt Section | |
| gr.HTML('<div class="section-header"><span class="section-icon">✎</span> Describe Your Vision</div>') | |
| prompt = gr.Textbox( | |
| label="", | |
| placeholder="A mystical forest at twilight, bioluminescent mushrooms glowing softly, ethereal fog weaving between ancient trees...", | |
| lines=4, | |
| max_lines=8, | |
| autofocus=True, | |
| elem_classes="prompt-input", | |
| show_label=False, | |
| ) | |
| # Quick Actions Row | |
| with gr.Row(elem_classes="quick-actions"): | |
| clear_btn = gr.Button("Clear", size="sm", variant="secondary", elem_classes="action-btn") | |
| enhance_btn = gr.Button("Enhance Prompt", size="sm", variant="secondary", elem_classes="action-btn") | |
| # Aspect Ratio Selection | |
| gr.HTML('<div class="section-header"><span class="section-icon">▢</span> Aspect Ratio</div>') | |
| with gr.Row(elem_classes="aspect-ratio-grid"): | |
| aspect_ratio = gr.Radio( | |
| choices=list(ASPECT_RATIOS.keys()), | |
| value="1:1 Square", | |
| label="", | |
| show_label=False, | |
| elem_classes="aspect-radio", | |
| ) | |
| # Dimension Controls | |
| with gr.Row(visible=True, elem_classes="dimension-row"): | |
| height = gr.Slider( | |
| minimum=512, | |
| maximum=2048, | |
| value=DEFAULT_SETTINGS["height"], | |
| step=64, | |
| label="Height", | |
| interactive=False, | |
| elem_classes="dimension-slider" | |
| ) | |
| width = gr.Slider( | |
| minimum=512, | |
| maximum=2048, | |
| value=DEFAULT_SETTINGS["width"], | |
| step=64, | |
| label="Width", | |
| interactive=False, | |
| elem_classes="dimension-slider" | |
| ) | |
| # Advanced Settings | |
| with gr.Accordion("Advanced Settings", open=False, elem_classes="advanced-accordion"): | |
| num_inference_steps = gr.Slider( | |
| minimum=1, | |
| maximum=20, | |
| value=DEFAULT_SETTINGS["inference_steps"], | |
| step=1, | |
| label="Quality Steps", | |
| info="Higher = better quality, slower generation (9 recommended)" | |
| ) | |
| with gr.Row(): | |
| randomize_seed = gr.Checkbox( | |
| label="Random Seed", | |
| value=True, | |
| elem_classes="seed-checkbox" | |
| ) | |
| seed = gr.Number( | |
| label="Seed Value", | |
| value=DEFAULT_SETTINGS["seed"], | |
| precision=0, | |
| visible=False, | |
| elem_classes="seed-input" | |
| ) | |
| # Generate Button | |
| generate_btn = gr.Button( | |
| "Generate Image", | |
| variant="primary", | |
| size="lg", | |
| elem_classes="generate-btn", | |
| ) | |
| # Examples Section | |
| gr.HTML('<div class="section-header"><span class="section-icon">✨</span> Inspiration Gallery</div>') | |
| gr.Examples( | |
| examples=EXAMPLE_PROMPTS, | |
| inputs=[prompt], | |
| label="", | |
| examples_per_page=4, | |
| elem_id="examples-gallery", | |
| ) | |
| return { | |
| "prompt": prompt, | |
| "clear_btn": clear_btn, | |
| "enhance_btn": enhance_btn, | |
| "aspect_ratio": aspect_ratio, | |
| "height": height, | |
| "width": width, | |
| "num_inference_steps": num_inference_steps, | |
| "randomize_seed": randomize_seed, | |
| "seed": seed, | |
| "generate_btn": generate_btn, | |
| } | |
| def build_output_column(): | |
| """Build the right output column with generated image display.""" | |
| with gr.Column(scale=5, min_width=400, elem_classes="output-column"): | |
| gr.HTML('<div class="section-header"><span class="section-icon">🖼</span> Generated Artwork</div>') | |
| output_image = gr.Image( | |
| label="", | |
| type="pil", | |
| show_label=False, | |
| height=580, | |
| elem_classes="output-image", | |
| show_download_button=True, | |
| show_share_button=True, | |
| ) | |
| # Image Info Bar | |
| with gr.Row(elem_classes="image-info-bar"): | |
| used_seed = gr.Number( | |
| label="Seed", | |
| interactive=False, | |
| elem_classes="seed-display", | |
| scale=1, | |
| ) | |
| return { | |
| "output_image": output_image, | |
| "used_seed": used_seed, | |
| } | |
| def create_app(): | |
| """Create and configure the Gradio application.""" | |
| theme = create_theme() | |
| with gr.Blocks(fill_height=True, title="Z-Image-Turbo | AI Image Generator") as demo: | |
| # Hero Header | |
| gr.HTML(HERO_HTML) | |
| with gr.Row(equal_height=False, elem_classes="main-container"): | |
| # Build UI sections | |
| controls = build_controls_column() | |
| outputs = build_output_column() | |
| # Footer | |
| gr.HTML(FOOTER_HTML) | |
| # Wire up event handlers | |
| controls["randomize_seed"].change( | |
| toggle_seed_visibility, | |
| inputs=[controls["randomize_seed"]], | |
| outputs=[controls["seed"]] | |
| ) | |
| controls["aspect_ratio"].change( | |
| update_dimensions, | |
| inputs=[controls["aspect_ratio"]], | |
| outputs=[controls["height"], controls["width"]] | |
| ) | |
| controls["clear_btn"].click( | |
| clear_prompt, | |
| outputs=[controls["prompt"]] | |
| ) | |
| controls["enhance_btn"].click( | |
| enhance_prompt, | |
| inputs=[controls["prompt"]], | |
| outputs=[controls["prompt"]] | |
| ) | |
| # Generation triggers | |
| generation_inputs = [ | |
| controls["prompt"], | |
| controls["height"], | |
| controls["width"], | |
| controls["num_inference_steps"], | |
| controls["seed"], | |
| controls["randomize_seed"], | |
| ] | |
| generation_outputs = [outputs["output_image"], outputs["used_seed"]] | |
| controls["generate_btn"].click( | |
| fn=generate_image, | |
| inputs=generation_inputs, | |
| outputs=generation_outputs, | |
| ) | |
| controls["prompt"].submit( | |
| fn=generate_image, | |
| inputs=generation_inputs, | |
| outputs=generation_outputs, | |
| ) | |
| return demo, theme | |
| # ============================================================================= | |
| # MAIN ENTRY POINT | |
| # ============================================================================= | |
| # Create the application | |
| demo, custom_theme = create_app() | |
| if __name__ == "__main__": | |
| demo.launch( | |
| theme=custom_theme, | |
| css=CUSTOM_CSS, | |
| ) | |