import os import random import gradio as gr import numpy as np from dotenv import load_dotenv from gradio_client import Client from PIL import Image # Load environment variables load_dotenv() # Client configuration HF_TOKEN = os.getenv("HF_TOKEN") # --- UI Constants and Helpers --- MAX_SEED = np.iinfo(np.int32).max def create_prompt(params): """ Generate a prompt string for sending to the client Args: params (dict): Dictionary of parameters used for prompt generation - label (str): Comma-separated button texts, will be split into array of 4 labels - detail (str): Design details - shape (str): Button shape - layout (str): Layout arrangement - background (str): Background setting Returns: str: Complete prompt string for image generation """ label_str = params.get("label", "Button") detail = params.get("detail", "") shape = params.get("shape", "rounded") layout = params.get("layout", "horizontal_3") background = params.get("background", "natural") # Split labels by comma, take up to number of positions labels = [l.strip() for l in label_str.split(",") if l.strip()] if labels: # If there are labels, repeat to up to 4 while len(labels) < 4: labels.extend(labels) layout_config = { "horizontal_3": { "positions": ["top", "middle", "bottom"], "desc": "3 horizontal rows: top, middle, bottom", }, "vertical_2": { "positions": [ "left middle-valign small text", "right middle-valign small text", ], "desc": "2 vertical tall buttons arranged side by side, vertical rectangular shape, 2 columns layout, horizontal text, small text orientation is horizontal", }, "box_2x2": { "positions": ["left-top", "right-top", "left-bottom", "right-bottom"], "desc": "2x2 grid: left-top, right-top, left-bottom, right-bottom", }, } shape_descriptions = { "box": "box shape", "rounded": "rounded corners", "oval": "oval shape", "free": "organic freeform shape", } config = layout_config.get(layout, layout_config["horizontal_3"]) positions = config["positions"] layout_desc = config["desc"] shape_desc = shape_descriptions.get(shape, "rounded corners") base_prompt = ( f"Create {len(positions)} {detail} button designs in a 1024x1024 image.\n" ) base_prompt += f"Arranged in {layout_desc}.\n" base_prompt += f"{shape_desc.capitalize()}.\n" if detail: base_prompt += f"{detail.capitalize()} aesthetic: detailed visual elements and color palette.\n" # Describe each button with position and label for i, pos in enumerate(positions): if i < len(labels): base_prompt += f'{pos} button: "{labels[i]}".\n' else: base_prompt += f"{pos} button: empty text rectangle.\n" base_prompt += "Each button is a different design variation exploring the theme.\n" if background == "natural": base_prompt += "Natural background with subtle textures and ambient lighting.\n" elif background == "white": base_prompt += "plain white only background.\n" elif background == "black": base_prompt += "plain black only background.\n" else: base_prompt += "Clean background with proper lighting.\n" base_prompt += "Ultra HD, 4K, cinematic composition" return base_prompt def call_client( prompt, seed, randomize_seed, aspect_ratio, num_inference_steps, hf_token=None ): """ Call the gradio client for image generation Args: prompt (str): Prompt text for image generation seed (int): Random seed value randomize_seed (bool): Whether to randomize the seed aspect_ratio (str): Image aspect ratio (e.g., "1:1", "16:9", "4:3") num_inference_steps (int): Number of inference steps (4-28) Returns: tuple: (image, seed, error) - Image object, used seed, error message """ try: # Map aspect_ratio to resolution resolution_map = { "1:1": "1024x1024 ( 1:1 )", "16:9": "1280x720 ( 16:9 )", "9:16": "720x1280 ( 9:16 )", } resolution = resolution_map.get(aspect_ratio, "1024x1024 ( 1:1 )") client = Client("Tongyi-MAI/Z-Image-Turbo", hf_token=hf_token) result = client.predict( prompt=prompt, resolution=resolution, seed=seed, steps=num_inference_steps, shift=3.0, random_seed=randomize_seed, gallery_images=[], api_name="/generate", ) # Assume result is PIL Image return result, seed, None except Exception as e: return None, seed, str(e) # --- Main Inference Logic --- # Define outside Blocks or define within Blocks to pass to Examples def run_inference_engine( label, detail, shape, layout, background, seed, randomize_seed, aspect_ratio, guidance_scale, num_inference_steps, request: gr.Request, ): """ generate UI button images Args: label (str): Text to display on the button,allow empty detail (str): Detailed design prompt shape (str): Button shape ("box", "rounded", "oval", "free") layout (str): Layout arrangement ("horizontal_3:3x1", "vertical_2:1x2", "box_2x2:2x2") background (str): Background setting ("natural", "white", "black") seed (int): Random seed value randomize_seed (bool): Whether to randomize the seed aspect_ratio (str): Image aspect ratio (use 1:1) guidance_scale (float): Guidance scale (use 1),no need to change num_inference_steps (int): Number of inference steps (use 8),no need to change Yields: tuple: (image, seed, status_message) - Generated image, used seed, status message """ hf_token = HF_TOKEN if request: if hasattr(request, "headers"): if hasattr(request.headers, "authorization"): hf_token = request.headers.authorization hf_token = hf_token.replace("Bearer", "").strip() # print(hf_token) yield None, seed, "Generating..." prompt_params = { "label": label, "detail": detail, "shape": shape, "layout": layout, "background": background, } prompt = create_prompt(prompt_params) # Debug: Print the generated prompt # print(f"Generated prompt: {prompt}") if randomize_seed: seed = random.randint(0, MAX_SEED) image, generated_seed, error = call_client( prompt, seed, randomize_seed, aspect_ratio, num_inference_steps, hf_token ) if image is None: gr.Warning(f"Error: {error}") yield None, generated_seed, f"Error: {error}" else: # Convert image to WebP format original_image = image[0][0]["image"] yield (original_image, generated_seed, "") # --- UI Customization --- css = """ body { font-family: 'Helvetica Neue', Arial, sans-serif; } #col-container { max-width: 1200px; margin: 0 auto; padding: 20px; } h1 { text-align: center; font-weight: 800; color: #333; margin-bottom: 0.5em; } .subtitle { text-align: center; color: #666; margin-bottom: 2em; } .generate-btn { background: linear-gradient(90deg, #6366f1 0%, #a855f7 100%) !important; border: none !important; color: white !important; font-weight: bold !important; font-size: 1.2em !important; padding: 20px !important; border-radius: 12px !important; transition: all 0.3s ease; height: 100% !important; min-height: 100px; } .generate-btn:hover { transform: translateY(-2px); box-shadow: 0 5px 15px rgba(99, 102, 241, 0.4); } .examples-container table { font-size: 0.85em !important; margin-bottom: 0 !important; } .examples-container td { padding: 4px 8px !important; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 150px; } .examples-container label { font-weight: bold; color: #555; margin-bottom: 5px; display: block; } #result-gallery { border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,0.1); border: 1px solid #eee; } .input-group { background: #f9fafb; padding: 15px; border-radius: 10px; border: 1px solid #e5e7eb; margin-bottom: 15px; } """ theme = gr.themes.Soft(primary_hue="indigo", secondary_hue="slate", radius_size="md") # Examples data example_data = [ [ "Start,Option,Exit", "Neon glowing cyberpunk, blue/purple gradient", "box", "horizontal_3", "black", "examples/start.webp", ], [ "Buy", "Luxury gold texture, minimal elegant, serif", "rounded", "vertical_2", "white", "examples/buy.webp", ], [ "RPG,R,P,G", "Wood texture, steel rim, fantasy game style", "free", "box_2x2", "natural", "examples/rpg.webp", ], [ "Submit", "Modern flat design, blue gradient, clean minimal style", "rounded", "horizontal_3", "white", None, ], ] with gr.Blocks(css=css, theme=theme, title="UI Button Generator MCP") as demo: gr.Markdown("# 🎨 AI UI Button Generator") gr.Markdown( "
UI button material and design concept generation tool using Z-Image-Turbo(Zero-GPU)
Web and MCP without Header-Authorization,only few time you can try zero-gpu