import gradio as gr import numpy as np import random import torch import requests from PIL import Image from io import BytesIO import time # TODO: PNGinfo追加, 使用データの展開(コピーボタン) MAX_SEED = np.iinfo(np.int32).max MAX_IMAGE_SIZE = 1344 model_url = { "ImageUltra":"https://api.stability.ai/v2beta/stable-image/generate/ultra", "ImageCore":"https://api.stability.ai/v2beta/stable-image/generate/core", "StableDiffusion3": "https://api.stability.ai/v2beta/stable-image/generate/sd3"} service_url = { "Conservative_Upscale":"https://api.stability.ai/v2beta/stable-image/upscale/conservative", "Creative_Upscale":"https://api.stability.ai/v2beta/stable-image/upscale/creative", "Erase":"https://api.stability.ai/v2beta/stable-image/edit/erase", "Inpaint":"https://api.stability.ai/v2beta/stable-image/edit/inpaint", "Outpaint":"https://api.stability.ai/v2beta/stable-image/edit/outpaint", "SR":"https://api.stability.ai/v2beta/stable-image/edit/search-and-replace", "RMBG":"https://api.stability.ai/v2beta/stable-image/edit/remove-background", "Sketch":"https://api.stability.ai/v2beta/stable-image/control/sketch", "Structure":"https://api.stability.ai/v2beta/stable-image/control/structure" } def bytes_to_image(image): image = BytesIO(image) image = Image.open(image).convert('RGB') return image def image_to_bytes(image): byte_io = BytesIO() image.save(byte_io, format='PNG') byte_data = byte_io.getvalue() return byte_data def send_request(url, api_key, file,data): response = requests.post( url, headers={ "Authorization": f"Bearer {api_key}", "Accept": "image/*" }, files=file, data=data, ) return response def generate(prompt, negative_prompt, seed, mode, submode, input_image, mask, CNstrength, search_prompt, op_left, op_right, op_up, op_down, randomize_seed, aspect, model, sd3_model, preset, api_key): if randomize_seed: seed = 0 file = {} data = { "prompt": prompt, "negative_prompt": negative_prompt, "output_format": "png", "seed": seed, "aspect_ratio": aspect } if input_image is not None: file["image"] = image_to_bytes(input_image) if mask is not None: file["mask"] = image_to_bytes(mask) if mode == "Generate": file["none"] = "" if model == "ImageUltra": url = model_url[model] elif model == "ImageCore": url = model_url[model] data["style_preset"] = preset elif model == "StableDiffusion3": url = model_url[model] data["model"] = sd3_model else: raise ValueError("Invalid model type") elif mode == "Upscale": if submode == "Conservative": url = service_url["Conservative_Upscale"] elif submode == "Creative": url = service_url["Creative_Upscale"] elif mode == "Edit": if submode == "Erase": url = service_url["Erase"] elif submode == "Inpaint": url = service_url["Inpaint"] elif submode == "Outpaint": url = service_url["Outpaint"] data["left"] = op_left data["right"] = op_right data["up"] = op_up data["down"] = op_down elif submode == "Search and Replace": url = service_url["SR"] data["search_prompt"] = search_prompt elif submode == "Remove Background": url = service_url["RMBG"] elif mode == "Control": data["control_strength"] = CNstrength if submode == "Sketch": url = service_url["Sketch"] elif submode == "Structure": url = service_url["Structure"] response = send_request(url, api_key, file, data) if response.status_code == 200: if mode == "Upscale" and submode == "Creative": generation_id = response.json().get("id") if not generation_id: raise Exception("No generation ID returned for creative upscale") # Polling for the result result_url = f"https://api.stability.ai/v2beta/stable-image/upscale/creative/result/{generation_id}" while True: result_response = requests.get( result_url, headers={ 'accept': "image/*", 'authorization': f"Bearer {api_key}" } ) if result_response.status_code == 202: print("Generation in-progress, try again in 10 seconds.") time.sleep(10) elif result_response.status_code == 200: print("Generation complete!") image = result_response.content image = bytes_to_image(image) copy_filed_value = f"prompt:{prompt}, negative:{negative_prompt}, mode:{mode}, submode:{submode}" return image, seed, copy_filed_value else: raise Exception(str(result_response.json())) else: image = response.content image = bytes_to_image(image) copy_filed_value = f"prompt:{prompt}, negative:{negative_prompt}, mode:{mode}, submode:{submode}" return image, seed, copy_filed_value else: raise Exception(str(response.json())) examples = [ "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k", "An astronaut riding a green horse", "A delicious ceviche cheesecake slice", ] css=""" #col-container { margin: 0 auto; max-width: 50vw; } """ def update_mode(mode): submode_update = gr.update(choices=["None"], visible=False) image_label_update = gr.update(visible=False) img_input_update = gr.update(visible=False) mask_update = gr.update(visible=False) if mode == "Generate": submode_update = gr.update(visible=False) elif mode == "Upscale": submode_update = gr.update(choices=["Conservative", "Creative"],value="Conservative" ,visible=True) img_input_update = gr.update(visible=True) image_label_update = gr.update(visible=True) elif mode == "Edit": submode_update = gr.update(choices=["Erase", "Inpaint", "Outpaint", "Search and Replace", "Remove Background"],value="Erase", visible=True) img_input_update = gr.update(visible=True) image_label_update = gr.update(visible=True) elif mode == "Control": submode_update = gr.update(choices=["Sketch", "Structure"],value="Sketch", visible=True) img_input_update = gr.update(visible=True) image_label_update = gr.update(visible=True) return submode_update, img_input_update, mask_update, image_label_update def update_submode(submode): mask = gr.update(visible=False) outpaint = gr.update(visible=False) cn = gr.update(visible=False) search_prompt = gr.update(visible=False) if submode in ["Erase", "Inpaint"]: mask = gr.update(visible=True) else: if submode == "Outpaint": outpaint = gr.update(visible=True) elif submode == "Control": cn = gr.update(visible=True) elif submode == "Search and Replace": search_prompt = gr.update(visible=True) return mask, outpaint, cn, search_prompt with gr.Blocks(css=css) as demo: with gr.Column(elem_id="col-container"): gr.Markdown(f""" # Demo Stable Image API Learn more about the [Stable Diffusion 3 series](https://stability.ai/news/stable-diffusion-3). Try on [Stability AI API](https://platform.stability.ai/docs/api-reference#tag/Generate/paths/~1v2beta~1stable-image~1generate~1sd3/post), [Stable Assistant](https://stability.ai/stable-assistant), or on Discord via [Stable Artisan](https://stability.ai/stable-artisan). Run locally with [ComfyUI](https://github.com/comfyanonymous/ComfyUI) or [diffusers](https://github.com/huggingface/diffusers) """) with gr.Row(): api_key = gr.Text(label="API Key", type="password", placeholder="Enter your API key", max_lines=1, container=False) with gr.Row(): model = gr.Dropdown(label="Model", choices=["ImageUltra", "ImageCore", "StableDiffusion3"], value="ImageUltra") mode = gr.Dropdown(label="Mode", choices=["Generate", "Upscale", "Edit", "Control"], value="Generate") submode = gr.Dropdown(label="Submode", choices=["None"], visible=False, value="None") with gr.Row(): with gr.Column(): prompt = gr.Text( label="Prompt", show_label=False, max_lines=1, placeholder="Enter your prompt", container=False, ) search_prompt = gr.Text( label="search prompt", visible=False, show_label=False, max_lines=1, placeholder="Enter a search prompt", ) run_button = gr.Button("Run", scale=0) with gr.Row(): with gr.Column(): image_label = gr.Markdown(value = "input image",visible=False) image = gr.Image(type='pil',label="img input", width="20vw", height="20vw",show_label=True,visible=False, interactive=True, container=False) with gr.Column(visible=False) as mask: mask_label = gr.Markdown(value="input mask") mask_input = gr.Image(type='pil',label="mask", width="20vw", height="20vw", show_label=True, interactive=True, container=False) with gr.Row(): result = gr.Image(label="Result", width="20vw", height="20%") with gr.Accordion("Advanced Settings", open=False): negative_prompt = gr.Text( label="Negative prompt", max_lines=1, placeholder="Enter a negative prompt", ) seed = gr.Slider( label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0, ) CN_strength = gr.Slider(label="Control Strength", minimum=0, maximum=1, step=0.01, value=0.5, visible=False) randomize_seed = gr.Checkbox(label="Randomize seed", value=True) with gr.Row(): aspect = gr.Radio(choices=["1:1", "16:9", "21:9", "2:3", "3:2", "4:5", "5:4", "9:16", "9:21"], label="Aspect raito", value="1:1") style_preset = gr.Radio(choices=["3d-model", "analog-film", "anime", "cinematic", "comic-book", "digital-art", "enhance", "fantasy-art", "isometric", "line-art", "low-poly", "modeling-compound", "neon-punk", "origami", "photographic", "pixel-art", "tile-texture"], label="Style_preset", value="anime", info="This parameter is only available for ImageCore model.") sd3_model = gr.Dropdown(label="SD3 Model Size", choices=["sd3-medium", "sd3-large", "sd3-large-turbo"], value="sd3-medium") with gr.Row(visible=False) as outpaint_scale: paint = gr.Markdown(value = "Outpain Scale") op_left = gr.Slider(label="left", minimum=0, maximum=2000, step=4, value=200) op_right = gr.Slider(label="right", minimum=0, maximum=2000, step=4, value=200) op_up = gr.Slider(label="up", minimum=0, maximum=2000, step=4, value=200) op_down = gr.Slider(label="down", minimum=0, maximum=2000, step=4, value=200) gr.Examples( examples=examples, inputs=[prompt] ) copy_filed = gr.TextArea( value="", label="Copy Field", max_lines=1, placeholder="Copy the field", show_copy_button=True, container=False) gr.on( triggers=[run_button.click, prompt.submit, negative_prompt.submit], fn=generate, inputs=[prompt, negative_prompt, seed, mode, submode, image, mask_input, CN_strength, search_prompt, op_left, op_right, op_up, op_down, randomize_seed, aspect, model, sd3_model, style_preset, api_key], outputs=[result, seed, copy_filed] ) mode.change(fn=update_mode, inputs=mode, outputs=[submode, image, mask, image_label]) submode.change(fn=update_submode, inputs=submode, outputs=[mask,outpaint_scale,CN_strength,search_prompt]) demo.launch()