| import logging | |
| import gradio as gr | |
| import numpy as np | |
| import cv2 | |
| import os | |
| import base64 | |
| from try_on_diffusion_client import TryOnDiffusionClient | |
| LOG_LEVEL = logging.INFO | |
| LOG_FORMAT = "%(asctime)s %(thread)-8s %(name)-16s %(levelname)-8s %(message)s" | |
| LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" | |
| EXAMPLE_PATH = os.path.join(os.path.dirname(__file__), "examples") | |
| API_URL = os.getenv("TRY_ON_DIFFUSION_DEMO_API_URL", "http://localhost:8000") | |
| API_KEY = os.getenv("TRY_ON_DIFFUSION_DEMO_API_KEY", "") | |
| SHOW_RAPIDAPI_LINK = os.getenv("TRY_ON_DIFFUSION_DEMO_SHOW_RAPIDAPI_LINK", "1") == "1" | |
| CONCURRENCY_LIMIT = int(os.getenv("TRY_ON_DIFFUSION_DEMO_CONCURRENCY_LIMIT", "2")) | |
| logging.basicConfig(level=LOG_LEVEL, format=LOG_FORMAT, datefmt=LOG_DATE_FORMAT) | |
| client = TryOnDiffusionClient(base_url=API_URL, api_key=API_KEY) | |
| def get_image_base64(file_name: str) -> str: | |
| _, ext = os.path.splitext(file_name.lower()) | |
| content_type = "image/jpeg" | |
| if ext == ".png": | |
| content_type = "image/png" | |
| elif ext == ".webp": | |
| content_type = "image/webp" | |
| elif ext == ".gif": | |
| content_type = "image/gif" | |
| with open(file_name, "rb") as f: | |
| return f"data:{content_type};base64," + base64.b64encode(f.read()).decode("utf-8") | |
| def get_examples(example_dir: str) -> list[str]: | |
| file_list = [f for f in os.listdir(os.path.join(EXAMPLE_PATH, example_dir)) if f.endswith(".jpg")] | |
| file_list.sort() | |
| return [os.path.join(EXAMPLE_PATH, example_dir, f) for f in file_list] | |
| def try_on( | |
| clothing_image: np.ndarray = None, | |
| clothing_prompt: str = None, | |
| avatar_image: np.ndarray = None, | |
| avatar_prompt: str = None, | |
| avatar_sex: str = None, | |
| background_image: np.ndarray = None, | |
| background_prompt: str = None, | |
| seed: int = -1, | |
| ) -> tuple: | |
| result = client.try_on_file( | |
| clothing_image=cv2.cvtColor(clothing_image, cv2.COLOR_RGB2BGR) if clothing_image is not None else None, | |
| clothing_prompt=clothing_prompt, | |
| avatar_image=cv2.cvtColor(avatar_image, cv2.COLOR_RGB2BGR) if avatar_image is not None else None, | |
| avatar_prompt=avatar_prompt, | |
| avatar_sex=avatar_sex if avatar_sex in ["male", "female"] else None, | |
| background_image=cv2.cvtColor(background_image, cv2.COLOR_RGB2BGR) if background_image is not None else None, | |
| background_prompt=background_prompt, | |
| seed=seed, | |
| ) | |
| if result.status_code == 200: | |
| return cv2.cvtColor(result.image, cv2.COLOR_BGR2RGB), f"<h3>Success</h3><p>Seed: {result.seed}</p>" | |
| else: | |
| error_message = f"<h3>Error {result.status_code}</h3>" | |
| if result.error_details is not None: | |
| error_message += f"<p>{result.error_details}</p>" | |
| return None, error_message | |
| with gr.Blocks(theme=gr.themes.Soft(), delete_cache=(3600, 3600)) as app: | |
| gr.HTML( | |
| f""" | |
| <div style="width: 100%; background-color: #001537; border-radius: 10px; padding-left: 10px"> | |
| <a href="https://texelmoda.com/" target="_blank"> | |
| <img src="{get_image_base64("images/logo.png")}" title="Texel.Moda" alt="Texel.Moda" style="float: left; margin-right: 10px; margin-left: -10px; border-radius: 10px; max-height: 50px;"/> | |
| </a> | |
| <h1 style="margin: 0; margin-right: 10px; line-height: 50px; color: #8cecd5; text-transform: uppercase">Virtual Try-On Diffusion</h1> | |
| </div> | |
| <br/> | |
| <p> | |
| Virtual Try-On Diffusion [VTON-D] by <a href="https://texelmoda.com/" target="_blank">Texel.Moda</a> is a | |
| custom diffusion-based pipeline for fast and flexible multi-modal virtual try-on. | |
| Clothing, avatar and background can be specified by reference images or text prompts allowing for clothing | |
| transfer, avatar replacement, fashion image generation and other virtual try-on related tasks. | |
| """ | |
| ) | |
| if SHOW_RAPIDAPI_LINK: | |
| gr.Button( | |
| value="Check out the API @ RapidAPI.com", | |
| link="https://rapidapi.com/texelmoda-texelmoda-apis/api/try-on-diffusion", | |
| icon="https://files.readme.io/9336831-small-rapid-logo-favicon.png", | |
| ) | |
| gr.HTML( | |
| """ | |
| <center> | |
| <a href="https://huggingface.co/spaces/texelmoda/try-on-diffusion/blob/main/docs/API.md">API Documentation</a> | |
| </center> | |
| """ | |
| ) | |
| gr.HTML("</p>") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.HTML( | |
| """ | |
| <h2>Clothing</h2> | |
| <p> | |
| Clothing may be specified with a reference image or a text prompt. | |
| For more exotic use cases image and prompt can be also used together. | |
| If both image and prompt are empty the model will generate random clothing. | |
| <br/><br/> | |
| </p> | |
| """ | |
| ) | |
| with gr.Tab("Image"): | |
| clothing_image = gr.Image(label="Clothing Image", sources=["upload"], type="numpy") | |
| clothing_image_examples = gr.Examples( | |
| inputs=clothing_image, examples_per_page=18, examples=get_examples("clothing") | |
| ) | |
| with gr.Tab("Prompt"): | |
| clothing_prompt = gr.TextArea( | |
| label="Clothing Prompt", | |
| info='Compel weighting <a href="https://github.com/damian0815/compel/blob/main/doc/syntax.md">syntax</a> is supported.', | |
| ) | |
| clothing_prompt_examples = gr.Examples( | |
| inputs=clothing_prompt, | |
| examples_per_page=8, | |
| examples=[ | |
| "a sheer blue sleeveless mini dress", | |
| "a beige woolen sweater and white pleated skirt", | |
| "a black leather jacket and dark blue slim-fit jeans", | |
| "a floral pattern blouse and leggings", | |
| "a paisley pattern purple shirt and beige chinos", | |
| "a striped white and blue polo shirt and blue jeans", | |
| "a colorful t-shirt and black shorts", | |
| "a checked pattern shirt and dark blue cargo pants", | |
| ], | |
| ) | |
| with gr.Column(): | |
| gr.HTML( | |
| """ | |
| <h2>Avatar</h2> | |
| <p> | |
| Avatar may be specified with a subject photo or a text prompt. | |
| Latter can be used, for example, to replace person while preserving clothing. | |
| For more exotic use cases image and prompt can be also used together. | |
| If both image and prompt are empty the model will generate random avatars. | |
| </p> | |
| """ | |
| ) | |
| with gr.Tab("Image"): | |
| avatar_image = gr.Image(label="Avatar Image", sources=["upload"], type="numpy") | |
| avatar_image_examples = gr.Examples( | |
| inputs=avatar_image, | |
| examples_per_page=18, | |
| examples=get_examples("avatar"), | |
| ) | |
| with gr.Tab("Prompt"): | |
| avatar_prompt = gr.TextArea( | |
| label="Avatar Prompt", | |
| info='Compel weighting <a href="https://github.com/damian0815/compel/blob/main/doc/syntax.md">syntax</a> is supported.', | |
| ) | |
| avatar_prompt_examples = gr.Examples( | |
| inputs=avatar_prompt, | |
| examples_per_page=8, | |
| examples=[ | |
| "a beautiful blond girl with long hair", | |
| "a cute redhead girl with freckles", | |
| "a plus size female model wearing sunglasses", | |
| "a woman with dark hair and blue eyes", | |
| "a fit man with dark beard and blue eyes", | |
| "a young blond man posing for a photo", | |
| "a gentleman with beard and mustache", | |
| "a plus size man walking", | |
| ], | |
| ) | |
| avatar_sex = gr.Dropdown( | |
| label="Avatar Sex", | |
| choices=[("Auto", ""), ("Male", "male"), ("Female", "female")], | |
| value="", | |
| info="Avatar sex selector can be used to enforce a specific sex of the avatar.", | |
| ) | |
| with gr.Column(): | |
| gr.HTML( | |
| """ | |
| <h2>Background</h2> | |
| <p> | |
| Replacing the background is optional. | |
| Resulting background may be specified with a reference image or a text prompt. | |
| If omitted the original avatar background will be preserved. | |
| <br/><br/><br/> | |
| </p> | |
| """ | |
| ) | |
| with gr.Tab("Image"): | |
| background_image = gr.Image(label="Background Image", sources=["upload"], type="numpy") | |
| background_image_examples = gr.Examples( | |
| inputs=background_image, examples_per_page=18, examples=get_examples("background") | |
| ) | |
| with gr.Tab("Prompt"): | |
| background_prompt = gr.TextArea( | |
| label="Background Prompt", | |
| info='Compel weighting <a href="https://github.com/damian0815/compel/blob/main/doc/syntax.md">syntax</a> is supported.', | |
| ) | |
| background_prompt_examples = gr.Examples( | |
| inputs=background_prompt, | |
| examples_per_page=8, | |
| examples=[ | |
| "in an autumn park", | |
| "in front of a brick wall", | |
| "near an old tree", | |
| "on a busy city street", | |
| "in front of a staircase", | |
| "on an ocean beach with palm trees", | |
| "in a shopping mall", | |
| "in a modern office", | |
| ], | |
| ) | |
| with gr.Column(): | |
| gr.HTML( | |
| """ | |
| <h2>Generation</h2> | |
| """ | |
| ) | |
| seed = gr.Number( | |
| label="Seed", | |
| value=-1, | |
| minimum=-1, | |
| info="Seed used for generation, specify -1 for random seed for each generation.", | |
| ) | |
| generate_button = gr.Button(value="Generate", variant="primary") | |
| result_image = gr.Image(label="Result", show_share_button=False, format="jpeg") | |
| result_details = gr.HTML(label="Details") | |
| generate_button.click( | |
| fn=try_on, | |
| inputs=[ | |
| clothing_image, | |
| clothing_prompt, | |
| avatar_image, | |
| avatar_prompt, | |
| avatar_sex, | |
| background_image, | |
| background_prompt, | |
| seed, | |
| ], | |
| outputs=[result_image, result_details], | |
| api_name=False, | |
| concurrency_limit=CONCURRENCY_LIMIT, | |
| ) | |
| app.title = "Virtual Try-On Diffusion by Texel.Moda" | |
| if __name__ == "__main__": | |
| app.queue(api_open=False).launch(show_api=False, ssr_mode=False) | |