| 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) |
|
|