| import torch |
| import gradio as gr |
| from diffusers import DiffusionPipeline |
| import diffusers |
| import numpy as np |
| import random |
| import os |
| import shutil |
| import gc |
| from pathlib import Path |
|
|
| |
| |
| |
| def clean_huggingface_cache(): |
| """Clean HuggingFace cache to free up disk space""" |
| cache_dir = Path.home() / ".cache" / "huggingface" / "hub" |
| freed_space = 0 |
| |
| if cache_dir.exists(): |
| print("π§Ή Cleaning HuggingFace cache...") |
| for item in cache_dir.iterdir(): |
| if item.is_dir(): |
| try: |
| size = sum(f.stat().st_size for f in item.rglob('*') if f.is_file()) |
| shutil.rmtree(item) |
| freed_space += size |
| print(f" Removed: {item.name} ({size / 1e9:.2f} GB)") |
| except Exception as e: |
| print(f" Skip {item.name}: {e}") |
| print(f"β
Freed {freed_space / 1e9:.2f} GB of disk space!") |
| else: |
| print("β οΈ Cache directory not found") |
| |
| |
| gc.collect() |
| torch.cuda.empty_cache() if torch.cuda.is_available() else None |
| return freed_space |
|
|
| def clean_temp_files(): |
| """Clean temporary Gradio files""" |
| temp_dirs = [ |
| Path("/tmp/gradio"), |
| Path.home() / ".gradio" / "cached_examples", |
| Path.home() / ".gradio" / "file_cache" |
| ] |
| |
| freed = 0 |
| for temp_dir in temp_dirs: |
| if temp_dir.exists(): |
| try: |
| size = sum(f.stat().st_size for f in temp_dir.rglob('*') if f.is_file()) |
| shutil.rmtree(temp_dir) |
| freed += size |
| print(f"π§Ή Cleaned: {temp_dir} ({size / 1e6:.2f} MB)") |
| temp_dir.mkdir(parents=True, exist_ok=True) |
| except Exception as e: |
| print(f"β οΈ Could not clean {temp_dir}: {e}") |
| return freed |
|
|
| |
| |
| |
| |
| cpu_cores = os.cpu_count() |
| torch.set_num_threads(cpu_cores) |
| torch.set_num_interop_threads(cpu_cores // 2) |
|
|
| |
| torch.set_flush_denormal(True) |
|
|
| |
| TORCH_DTYPE = torch.float32 |
|
|
| |
| torch.set_grad_enabled(False) |
|
|
| |
| os.environ["OMP_NUM_THREADS"] = str(cpu_cores) |
| os.environ["MKL_NUM_THREADS"] = str(cpu_cores) |
|
|
| |
| |
| |
| MAX_SEED = np.iinfo(np.int32).max |
|
|
| |
| |
| |
| prompt_examples = [ |
| "The shy college girl, with glasses and a tight plaid skirt, nervously approaches her professor", |
| "Her skirt rose a little higher with each gentle push, a soft blush spreading across her cheeks", |
| "a girl in a school uniform having her skirt pulled up by a boy", |
| "Moody mature anime scene of two lovers under neon rain, sensual atmosphere", |
| "Moody mature anime scene of two lovers kissing under neon rain", |
| "The girl sits on the boy's lap by the window, his hands resting on her waist", |
| "A girl with long, black hair is sleeping on her desk in the classroom", |
| "Her elegant silk gown swayed gracefully as she approached him", |
| "A woman in a business suit having her skirt lifted by a man", |
| "The older woman sits on the man's lap by the fireplace", |
| "A woman with glasses, lying on the bed in just her bra, spreads her legs wide", |
| "A soft focus on the girl's face, eyes closed, biting her lip", |
| "A woman in a blue hanbok sits on a wooden floor, gazing out of a window", |
| "The couple in a wooden outdoor bath share an intimate moment", |
| "A steamy shower scene, the twins embrace under warm water", |
| "The teacher pins the student against the blackboard, her skirt hiked up", |
| "After hours, the girl rides the teacher on the classroom floor", |
| "The secretary unzips her boss's shirt in the supply closet", |
| "The secretary leans back on the boss's desk, her legs wrapped around his waist", |
| "On the living room couch, one twin sits astride her sister's lap", |
| ] |
|
|
| |
| |
| |
| def get_device(): |
| if torch.cuda.is_available(): |
| print("β
CUDA GPU detected! Using GPU for ultra-fast inference.") |
| return "cuda", torch.bfloat16 |
| elif torch.backends.mps.is_available(): |
| print("β
Apple MPS detected! Using MPS acceleration.") |
| return "mps", torch.float32 |
| else: |
| print("β οΈ No GPU detected. Running on CPU with max optimizations...") |
| print(f" Using {cpu_cores} CPU cores for parallel processing!") |
| return "cpu", torch.float32 |
|
|
| device, dtype = get_device() |
|
|
| |
| |
| |
| def get_cache_size(): |
| cache_dir = Path.home() / ".cache" / "huggingface" / "hub" |
| if cache_dir.exists(): |
| total = sum(f.stat().st_size for f in cache_dir.rglob('*') if f.is_file()) |
| return total / 1e9 |
| return 0 |
|
|
| print(f"π¦ Current HuggingFace cache size: {get_cache_size():.2f} GB") |
|
|
| |
| |
| |
| print("π Loading Z-Image-Turbo pipeline (optimized for speed)...") |
| diffusers.utils.logging.set_verbosity_error() |
|
|
| |
| pipe = DiffusionPipeline.from_pretrained( |
| "Tongyi-MAI/Z-Image-Turbo", |
| torch_dtype=dtype, |
| low_cpu_mem_usage=True, |
| use_safetensors=True, |
| ) |
|
|
| |
| pipe.to(device) |
|
|
| |
| if device == "cpu": |
| try: |
| pipe.enable_attention_slicing() |
| print("β
Attention slicing enabled - memory efficient") |
| except: |
| pass |
| |
| |
| try: |
| pipe.enable_model_cpu_offload() |
| print("β
Model CPU offload enabled") |
| except: |
| pass |
|
|
| print(f"β
Pipeline loaded on: {device}") |
| print(f"π¦ Cache size after loading: {get_cache_size():.2f} GB") |
|
|
| |
| |
| |
| def get_random_prompt(): |
| return random.choice(prompt_examples) |
|
|
| |
| |
| |
| def generate_image(prompt, height, width, num_inference_steps, seed, randomize_seed, num_images): |
| if not prompt: |
| raise gr.Error("Please enter a prompt.") |
|
|
| if randomize_seed: |
| seed = random.randint(0, 2**32 - 1) |
|
|
| num_images = min(max(1, int(num_images)), 4) |
| |
| |
| if height * width > 1024 * 1024: |
| actual_steps = min(num_inference_steps, 6) |
| if actual_steps < num_inference_steps: |
| print(f"β‘ Auto-reduced steps from {num_inference_steps} to {actual_steps} for high resolution") |
| else: |
| actual_steps = num_inference_steps |
|
|
| generator = torch.Generator(device=device).manual_seed(int(seed)) |
|
|
| print(f"π¨ Generating {num_images} image(s) - Steps: {actual_steps}") |
|
|
| |
| result = pipe( |
| prompt=prompt, |
| height=int(height), |
| width=int(width), |
| num_inference_steps=actual_steps, |
| guidance_scale=0.0, |
| generator=generator, |
| max_sequence_length=1024, |
| num_images_per_prompt=num_images, |
| output_type="pil", |
| ) |
|
|
| print(f"β
Done! Generated {len(result.images)} image(s)") |
| |
| |
| gc.collect() |
| |
| return result.images, seed |
|
|
| |
| |
| |
| def clean_all_cache(): |
| hf_freed = clean_huggingface_cache() |
| temp_freed = clean_temp_files() |
| total_freed = hf_freed + temp_freed |
| |
| status = f"π§Ή Cleaned {total_freed / 1e9:.2f} GB total! (HF: {hf_freed / 1e9:.2f} GB, Temp: {temp_freed / 1e6:.2f} MB)" |
| print(status) |
| return status, f"Current cache: {get_cache_size():.2f} GB" |
|
|
| |
| |
| |
| css = """ |
| @import url('https://fonts.googleapis.com/css2?family=Bangers&family=Comic+Neue:wght@400;700&display=swap'); |
| |
| .gradio-container { |
| background-color: #FEF9C3 !important; |
| background-image: radial-gradient(#1F2937 1px, transparent 1px) !important; |
| background-size: 20px 20px !important; |
| min-height: 100vh !important; |
| } |
| |
| .huggingface-space-header, #space-header, .space-header, [class*="space-header"], |
| .svelte-1ed2p3z, .space-header-badge, .header-badge, [data-testid="space-header"], |
| footer, .footer, .gradio-container footer, .built-with, [class*="footer"] { |
| display: none !important; |
| visibility: hidden !important; |
| height: 0 !important; |
| } |
| |
| .header-text h1 { |
| font-family: 'Bangers', cursive !important; |
| color: #1F2937 !important; |
| font-size: 3.5rem !important; |
| text-align: center !important; |
| margin-bottom: 0.5rem !important; |
| text-shadow: 4px 4px 0px #FACC15, 6px 6px 0px #1F2937 !important; |
| } |
| |
| .subtitle { |
| text-align: center !important; |
| font-family: 'Comic Neue', cursive !important; |
| font-size: 1.2rem !important; |
| color: #1F2937 !important; |
| font-weight: 700 !important; |
| } |
| |
| .warning-box { |
| background: #FEF3C7 !important; |
| border: 3px solid #F59E0B !important; |
| border-radius: 8px !important; |
| padding: 12px 20px !important; |
| margin: 10px auto 20px auto !important; |
| max-width: 800px !important; |
| box-shadow: 4px 4px 0px #1F2937 !important; |
| } |
| |
| .gr-panel, .gr-box, .block { |
| background: #FFFFFF !important; |
| border: 3px solid #1F2937 !important; |
| border-radius: 8px !important; |
| box-shadow: 6px 6px 0px #1F2937 !important; |
| } |
| |
| .gr-button-primary, button.primary { |
| background: #3B82F6 !important; |
| border: 3px solid #1F2937 !important; |
| border-radius: 8px !important; |
| color: #FFFFFF !important; |
| font-family: 'Bangers', cursive !important; |
| font-size: 1.3rem !important; |
| padding: 14px 28px !important; |
| box-shadow: 5px 5px 0px #1F2937 !important; |
| } |
| |
| .gr-button-primary:hover, button.primary:hover { |
| background: #2563EB !important; |
| transform: translate(-2px, -2px) !important; |
| box-shadow: 7px 7px 0px #1F2937 !important; |
| } |
| |
| .gr-button-secondary, .random-btn, .clean-btn { |
| background: #EF4444 !important; |
| border: 3px solid #1F2937 !important; |
| border-radius: 8px !important; |
| color: #FFFFFF !important; |
| font-family: 'Bangers', cursive !important; |
| font-size: 1.1rem !important; |
| box-shadow: 4px 4px 0px #1F2937 !important; |
| } |
| |
| .gr-button-secondary:hover, .random-btn:hover, .clean-btn:hover { |
| background: #DC2626 !important; |
| transform: translate(-2px, -2px) !important; |
| box-shadow: 6px 6px 0px #1F2937 !important; |
| } |
| |
| .clean-btn { |
| background: #10B981 !important; |
| } |
| |
| .clean-btn:hover { |
| background: #059669 !important; |
| } |
| |
| .gr-gallery { |
| border: 4px solid #1F2937 !important; |
| border-radius: 8px !important; |
| box-shadow: 8px 8px 0px #1F2937 !important; |
| background: #FFFFFF !important; |
| } |
| |
| textarea, input[type="text"], input[type="number"] { |
| background: #FFFFFF !important; |
| border: 3px solid #1F2937 !important; |
| border-radius: 8px !important; |
| font-family: 'Comic Neue', cursive !important; |
| font-weight: 700 !important; |
| } |
| |
| ::-webkit-scrollbar { width: 12px; } |
| ::-webkit-scrollbar-track { background: #FEF9C3; border: 2px solid #1F2937; } |
| ::-webkit-scrollbar-thumb { background: #3B82F6; border: 2px solid #1F2937; } |
| """ |
|
|
| |
| |
| |
| with gr.Blocks(css=css, title="Z-Image-Turbo - Fast AI Image Generator") as demo: |
| |
| cache_status = gr.Textbox(label="π¦ Cache Status", value=f"Cache size: {get_cache_size():.2f} GB", interactive=False) |
| |
| |
| gr.HTML(""" |
| <div style="text-align: center; margin: 20px 0 10px 0;"> |
| <a href="https://www.humangen.ai" target="_blank"> |
| <img src="https://img.shields.io/static/v1?label=π HOME&message=HUMANGEN.AI&color=0000ff&labelColor=ffcc00&style=for-the-badge" alt="HOME"> |
| </a> |
| </div> |
| """) |
| |
| |
| gr.Markdown("# πΌοΈ Zimage Turbo β¨", elem_classes="header-text") |
| gr.Markdown('<p class="subtitle">π¨ Powered by Z-Image-Turbo - Fast Text-to-Image π</p>') |
| |
| |
| gr.HTML(""" |
| <div class="warning-box"> |
| <p>β‘ FAST MODE: 8 steps default for quick generation | π‘ Lower resolution = faster generation</p> |
| </div> |
| """) |
| |
| with gr.Row(equal_height=False): |
| with gr.Column(scale=1, min_width=350): |
| prompt_input = gr.Textbox(label="βοΈ Prompt", placeholder="Describe your image...", lines=4) |
| |
| with gr.Row(): |
| generate_button = gr.Button("β¨ GENERATE! π¨", variant="primary", size="lg") |
| clean_cache_button = gr.Button("π§Ή CLEAN CACHE", elem_classes="clean-btn", size="sm") |
| |
| with gr.Row(): |
| height_input = gr.Slider(512, 2048, 768, step=64, label="π Height") |
| width_input = gr.Slider(512, 2048, 768, step=64, label="π Width") |
| |
| num_images_input = gr.Slider(1, 4, 1, step=1, label="πΌοΈ Number of Images") |
|
|
| with gr.Accordion("β‘ Speed Settings", open=False): |
| steps_slider = gr.Slider(1, 30, 8, step=1, label="π Inference Steps (lower = faster)") |
| seed_input = gr.Slider(0, MAX_SEED, 42, step=1, label="π± Seed") |
| randomize_seed_checkbox = gr.Checkbox(label="π² Randomize Seed", value=True) |
| |
| random_button = gr.Button("π² RANDOM PROMPT!", variant="secondary", elem_classes="random-btn") |
| used_seed_output = gr.Number(label="π± Seed Used", interactive=False) |
|
|
| with gr.Column(scale=1, min_width=350): |
| output_gallery = gr.Gallery(label="π¨ Generated Images", height=550, columns=2, object_fit="contain") |
| gr.Markdown('<p style="text-align: center;">π‘ Click to enlarge | Right-click to save</p>') |
|
|
| |
| random_button.click(fn=get_random_prompt, outputs=[prompt_input]) |
| |
| generate_button.click( |
| fn=generate_image, |
| inputs=[prompt_input, height_input, width_input, steps_slider, seed_input, randomize_seed_checkbox, num_images_input], |
| outputs=[output_gallery, used_seed_output], |
| ) |
| |
| clean_cache_button.click( |
| fn=clean_all_cache, |
| outputs=[cache_status, cache_status], |
| ) |
|
|
| if __name__ == "__main__": |
| demo.queue().launch(server_name="0.0.0.0", server_port=7860) |