import spaces
import os
from stablepy.diffusers_vanilla.style_prompt_config import STYLE_NAMES
import re
from stablepy import (
    CONTROLNET_MODEL_IDS,
    VALID_TASKS,
    T2I_PREPROCESSOR_NAME,
    FLASH_LORA,
    SCHEDULER_CONFIG_MAP,
    scheduler_names,
    IP_ADAPTER_MODELS,
    IP_ADAPTERS_SD,
    IP_ADAPTERS_SDXL,
    REPO_IMAGE_ENCODER,
    ALL_PROMPT_WEIGHT_OPTIONS,
    SD15_TASKS,
    SDXL_TASKS,
)
from config import (
    DEFAULT_STEPS,
    DEFAULT_CFG,
    MINIMUM_IMAGE_NUMBER,
    MAXIMUM_IMAGE_NUMBER,
    DEFAULT_NEGATIVE_PROMPT,
    DEFAULT_POSITIVE_PROMPT,
    task_stablepy
)
from models.vae import VAE_LIST as download_vae
from models.checkpoints import CHECKPOINT_LIST as download_model
from models.loras import LORA_LIST as download_lora
from models.format_models import FORMAT_MODELS as load_diffusers_format_model
from models.upscaler import upscaler_dict_gui
from models.controlnet import preprocessor_controlnet
from models.embeds import download_embeds
from examples.examples import example_prompts
from utils.download_utils import download_things
from utils.model_utils import get_model_list
import gradio as gr
import logging
from utils.string_utils import extract_parameters
from stablepy import logger
import diffusers
import warnings
from gui import GuiSD

# LOAD ALL ENV TOKEN
CIVITAI_API_KEY: str = os.environ.get("CIVITAI_API_KEY")
hf_token: str = os.environ.get("HF_TOKEN")

task_model_list = list(task_stablepy.keys())

# [Create directories]
directory_models: str = 'models'
os.makedirs(
    directory_models,
    exist_ok=True
)
directory_loras: str = 'loras'
os.makedirs(
    directory_loras,
    exist_ok=True
)
directory_vaes: str = 'vaes'
os.makedirs(
    directory_vaes,
    exist_ok=True
)
directory_embeds: str = 'embedings'
os.makedirs(
    directory_embeds,
    exist_ok=True
)

# Download stuffs
for url in [url.strip() for url in download_model.split(',')]:
    if not os.path.exists(f"./models/{url.split('/')[-1]}"):
        download_things(
            directory_models,
            url,
            hf_token,
            CIVITAI_API_KEY
        )

for url in [url.strip() for url in download_vae.split(',')]:
    if not os.path.exists(f"./vaes/{url.split('/')[-1]}"):
        download_things(
            directory_vaes,
            url,
            hf_token,
            CIVITAI_API_KEY
        )

for url in [url.strip() for url in download_lora.split(',')]:
    if not os.path.exists(f"./loras/{url.split('/')[-1]}"):
        download_things(
            directory_loras,
            url,
            hf_token,
            CIVITAI_API_KEY
        )

for url_embed in download_embeds:
    if not os.path.exists(f"./embedings/{url_embed.split('/')[-1]}"):
        download_things(
            directory_embeds,
            url_embed,
            hf_token,
            CIVITAI_API_KEY
        )

# Build list models
embed_list: list = get_model_list(directory_embeds)
model_list: list = get_model_list(directory_models)
model_list: list = load_diffusers_format_model + model_list
lora_model_list: list = get_model_list(directory_loras)
lora_model_list.insert(0, "None")
vae_model_list: list = get_model_list(directory_vaes)
vae_model_list.insert(0, "None")


def get_my_lora(link_url) -> tuple:
    for __url in [_url.strip() for _url in link_url.split(',')]:
        if not os.path.exists(f"./loras/{__url.split('/')[-1]}"):
            download_things(
                directory_loras,
                __url,
                hf_token,
                CIVITAI_API_KEY
            )

    new_lora_model_list: list = get_model_list(directory_loras)
    new_lora_model_list.insert(0, "None")

    return gr.update(
        choices=new_lora_model_list
    ), gr.update(
        choices=new_lora_model_list
    ), gr.update(
        choices=new_lora_model_list
    ), gr.update(
        choices=new_lora_model_list
    ), gr.update(
        choices=new_lora_model_list
    )


print('\033[33m🏁 Download and listing of valid models completed.\033[0m')

#######################
# GUI
#######################
logging.getLogger("diffusers").setLevel(logging.ERROR)

diffusers.utils.logging.set_verbosity(40)

warnings.filterwarnings(
    action="ignore",
    category=FutureWarning,
    module="diffusers"
)
warnings.filterwarnings(
    action="ignore",
    category=UserWarning,
    module="diffusers"
)
warnings.filterwarnings(
    action="ignore",
    category=FutureWarning,
    module="transformers"
)

logger.setLevel(logging.DEBUG)

# init GuiSD
SD_GEN: GuiSD = GuiSD(
    model_list=model_list,
    task_stablepy=task_stablepy,
    lora_model_list=lora_model_list,
    embed_list=embed_list,
)

with open("app.css", "r") as f:
    CSS: str = f.read()

sdxl_task = [k for k, v in task_stablepy.items() if v in SDXL_TASKS]
sd_task = [k for k, v in task_stablepy.items() if v in SD15_TASKS]


def update_task_options(
        model_name: str,
        task_name: str):
    """
    :param model_name:
    :param task_name:
    :return:
    """
    if model_name in model_list:
        if "xl" in model_name.lower():
            new_choices = sdxl_task
        else:
            new_choices = sd_task

        if task_name not in new_choices:
            task_name = "txt2img"

        return gr.update(
            value=task_name,
            choices=new_choices
        )
    else:
        return gr.update(
            value=task_name,
            choices=task_model_list
        )


# APP
with gr.Blocks(css=CSS) as app:
    gr.Markdown("# 🧩 (Ivan) DiffuseCraft")
    with gr.Tab("Generation"):
        with gr.Row():
            with gr.Column(scale=2):
                task_gui = gr.Dropdown(
                    label="Task",
                    choices=sdxl_task,
                    value=task_model_list[0],
                )
                model_name_gui = gr.Dropdown(
                    label="Model",
                    choices=model_list,
                    value="models/animaPencilXL_v500.safetensors" or model_list[0],
                    allow_custom_value=True
                )
                prompt_gui = gr.Textbox(
                    lines=5,
                    placeholder="Enter Positive prompt",
                    label="Positive Prompt",
                    value=DEFAULT_POSITIVE_PROMPT
                )
                neg_prompt_gui = gr.Textbox(
                    lines=3,
                    placeholder="Enter Negative prompt",
                    label="Negative prompt",
                    value=DEFAULT_NEGATIVE_PROMPT
                )
                with gr.Row(equal_height=False):
                    set_params_gui = gr.Button(value="↙️")
                    clear_prompt_gui = gr.Button(value="🗑️")
                    set_random_seed = gr.Button(value="🎲")

                generate_button = gr.Button(
                    value="GENERATE",
                    variant="primary"
                )

                model_name_gui.change(
                    update_task_options,
                    [model_name_gui, task_gui],
                    [task_gui],
                )

                load_model_gui = gr.HTML()

                result_images = gr.Gallery(
                    label="Generated images",
                    show_label=False,
                    elem_id="gallery",
                    columns=[2],
                    rows=[2],
                    object_fit="contain",
                    # height="auto",
                    interactive=False,
                    preview=False,
                    selected_index=50,
                )

                actual_task_info = gr.HTML()

            with gr.Column(scale=1):
                steps_gui = gr.Slider(
                    minimum=1,
                    maximum=100,
                    step=1,
                    value=DEFAULT_STEPS,
                    label="Steps"
                )
                cfg_gui = gr.Slider(
                    minimum=0,
                    maximum=30,
                    step=0.5,
                    value=DEFAULT_CFG,
                    label="CFG"
                )
                sampler_gui = gr.Dropdown(
                    label="Sampler",
                    choices=scheduler_names,
                    value="DPM++ 2M Karras"
                )
                img_width_gui = gr.Slider(
                    minimum=64,
                    maximum=4096,
                    step=8,
                    value=1024,
                    label="Img Width"
                )
                img_height_gui = gr.Slider(
                    minimum=64,
                    maximum=4096,
                    step=8,
                    value=1024,
                    label="Img Height"
                )
                seed_gui = gr.Number(
                    minimum=-1,
                    maximum=9999999999,
                    value=-1,
                    label="Seed"
                )
                with gr.Row():
                    clip_skip_gui = gr.Checkbox(
                        value=False,
                        label="Layer 2 Clip Skip"
                    )
                    free_u_gui = gr.Checkbox(
                        value=True,
                        label="FreeU"
                    )

                with gr.Row(equal_height=False):

                    def run_set_params_gui(base_prompt):
                        valid_receptors: dict = {  # default values
                            "prompt": gr.update(value=base_prompt),
                            "neg_prompt": gr.update(value=""),
                            "Steps": gr.update(value=30),
                            "width": gr.update(value=1024),
                            "height": gr.update(value=1024),
                            "Seed": gr.update(value=-1),
                            "Sampler": gr.update(value="Euler a"),
                            "scale": gr.update(value=7.5),  # cfg
                            "skip": gr.update(value=True),
                        }
                        valid_keys = list(valid_receptors.keys())

                        parameters: dict = extract_parameters(base_prompt)
                        for key, val in parameters.items():
                            if key in valid_keys:
                                if key == "Sampler":
                                    if val not in scheduler_names:
                                        continue
                                elif key == "skip":
                                    if int(val) >= 2:
                                        val = True
                                if key == "prompt":
                                    if ">" in val and "<" in val:
                                        val = re.sub(r'<[^>]+>', '', val)
                                        print("Removed LoRA written in the prompt")
                                if key in ["prompt", "neg_prompt"]:
                                    val = val.strip()
                                if key in ["Steps", "width", "height", "Seed"]:
                                    val = int(val)
                                if key == "scale":
                                    val = float(val)
                                if key == "Seed":
                                    continue
                                valid_receptors[key] = gr.update(value=val)
                        return [value for value in valid_receptors.values()]


                    set_params_gui.click(
                        run_set_params_gui, [prompt_gui], [
                            prompt_gui,
                            neg_prompt_gui,
                            steps_gui,
                            img_width_gui,
                            img_height_gui,
                            seed_gui,
                            sampler_gui,
                            cfg_gui,
                            clip_skip_gui,
                        ],
                    )


                    def run_clear_prompt_gui():
                        return gr.update(value=""), gr.update(value="")


                    clear_prompt_gui.click(
                        run_clear_prompt_gui, [], [prompt_gui, neg_prompt_gui]
                    )


                    def run_set_random_seed():
                        return -1


                    set_random_seed.click(
                        run_set_random_seed, [], seed_gui
                    )

                num_images_gui = gr.Slider(
                    minimum=MINIMUM_IMAGE_NUMBER,
                    maximum=MAXIMUM_IMAGE_NUMBER,
                    step=1,
                    value=1,
                    label="Images"
                )

                prompt_s_options = [
                    ("Classic format: (word:weight)", "Classic"),
                    ("Compel format: (word)weight", "Compel"),
                    ("Classic-original format: (word:weight)", "Classic-original"),
                    ("Classic-no_norm format: (word:weight)", "Classic-no_norm"),
                    ("Classic-ignore", "Classic-ignore"),
                    ("None", "None"),
                ]

                prompt_syntax_gui = gr.Dropdown(
                    label="Prompt Syntax",
                    choices=prompt_s_options,
                    value=prompt_s_options[0][1]
                )

                vae_model_gui = gr.Dropdown(
                    label="VAE Model",
                    choices=vae_model_list,
                    value=vae_model_list[1]
                )

                with gr.Accordion(
                        "Hires fix",
                        open=False,
                        visible=True):

                    upscaler_keys = list(upscaler_dict_gui.keys())

                    upscaler_model_path_gui = gr.Dropdown(
                        label="Upscaler",
                        choices=upscaler_keys,
                        value=upscaler_keys[0]
                    )
                    upscaler_increases_size_gui = gr.Slider(
                        minimum=1.1,
                        maximum=6.,
                        step=0.1,
                        value=1.4,
                        label="Upscale by"
                    )

                    esrgan_tile_gui = gr.Slider(
                        minimum=0,
                        value=100,
                        maximum=500,
                        step=1,
                        label="ESRGAN Tile"
                    )
                    esrgan_tile_overlap_gui = gr.Slider(
                        minimum=1,
                        maximum=200,
                        step=1,
                        value=10,
                        label="ESRGAN Tile Overlap"
                    )
                    hires_steps_gui = gr.Slider(
                        minimum=0,
                        value=30,
                        maximum=100,
                        step=1,
                        label="Hires Steps"
                    )
                    hires_denoising_strength_gui = gr.Slider(
                        minimum=0.1,
                        maximum=1.0,
                        step=0.01,
                        value=0.55,
                        label="Hires Denoising Strength"
                    )
                    hires_sampler_gui = gr.Dropdown(
                        label="Hires Sampler",
                        choices=["Use same sampler"] + scheduler_names[:-1],
                        value="Use same sampler"
                    )
                    hires_prompt_gui = gr.Textbox(
                        label="Hires Prompt",
                        placeholder="Main prompt will be use",
                        lines=3
                    )
                    hires_negative_prompt_gui = gr.Textbox(
                        label="Hires Negative Prompt",
                        placeholder="Main negative prompt will be use",
                        lines=3
                    )

                with gr.Accordion("LoRA", open=False, visible=True):
                    lora1_gui = gr.Dropdown(
                        label="Lora1",
                        choices=lora_model_list
                    )
                    lora_scale_1_gui = gr.Slider(
                        minimum=-2,
                        maximum=2,
                        step=0.01,
                        value=0.33,
                        label="Lora Scale 1"
                    )
                    lora2_gui = gr.Dropdown(
                        label="Lora2",
                        choices=lora_model_list
                    )
                    lora_scale_2_gui = gr.Slider(
                        minimum=-2,
                        maximum=2,
                        step=0.01,
                        value=0.33,
                        label="Lora Scale 2"
                    )
                    lora3_gui = gr.Dropdown(
                        label="Lora3",
                        choices=lora_model_list
                    )
                    lora_scale_3_gui = gr.Slider(
                        minimum=-2,
                        maximum=2,
                        step=0.01,
                        value=0.33,
                        label="Lora Scale 3"
                    )
                    lora4_gui = gr.Dropdown(
                        label="Lora4",
                        choices=lora_model_list
                    )
                    lora_scale_4_gui = gr.Slider(
                        minimum=-2,
                        maximum=2,
                        step=0.01,
                        value=0.33,
                        label="Lora Scale 4"
                    )
                    lora5_gui = gr.Dropdown(
                        label="Lora5",
                        choices=lora_model_list
                    )
                    lora_scale_5_gui = gr.Slider(
                        minimum=-2,
                        maximum=2,
                        step=0.01,
                        value=0.33,
                        label="Lora Scale 5"
                    )

                    with gr.Accordion(
                            "From URL",
                            open=False,
                            visible=True):
                        text_lora = gr.Textbox(
                            label="URL",
                            placeholder="http://...my_lora_url.safetensors",
                            lines=1
                        )
                        button_lora = gr.Button("Get and update lists of LoRAs")
                        button_lora.click(
                            get_my_lora,
                            [text_lora],
                            [
                                lora1_gui,
                                lora2_gui,
                                lora3_gui,
                                lora4_gui,
                                lora5_gui
                            ]
                        )

                with gr.Accordion(
                        "IP-Adapter",
                        open=False,
                        visible=True):  # IP-Adapter
                    IP_MODELS = sorted(
                        list(
                            set(
                                IP_ADAPTERS_SD + IP_ADAPTERS_SDXL
                            )
                        )
                    )
                    MODE_IP_OPTIONS = [
                        "original",
                        "style",
                        "layout",
                        "style+layout"
                    ]

                    with gr.Accordion("IP-Adapter 1", open=False, visible=True):
                        image_ip1 = gr.Image(
                            label="IP Image",
                            type="filepath"
                        )
                        mask_ip1 = gr.Image(
                            label="IP Mask",
                            type="filepath"
                        )
                        model_ip1 = gr.Dropdown(
                            value="plus_face",
                            label="Model",
                            choices=IP_MODELS
                        )
                        mode_ip1 = gr.Dropdown(
                            value="original",
                            label="Mode",
                            choices=MODE_IP_OPTIONS
                        )
                        scale_ip1 = gr.Slider(
                            minimum=0.,
                            maximum=2.,
                            step=0.01,
                            value=0.7,
                            label="Scale"
                        )

                    with gr.Accordion("IP-Adapter 2", open=False, visible=True):
                        image_ip2 = gr.Image(
                            label="IP Image",
                            type="filepath"
                        )
                        mask_ip2 = gr.Image(
                            label="IP Mask (optional)",
                            type="filepath"
                        )
                        model_ip2 = gr.Dropdown(
                            value="base",
                            label="Model",
                            choices=IP_MODELS
                        )
                        mode_ip2 = gr.Dropdown(
                            value="style",
                            label="Mode",
                            choices=MODE_IP_OPTIONS
                        )
                        scale_ip2 = gr.Slider(
                            minimum=0.,
                            maximum=2.,
                            step=0.01,
                            value=0.7,
                            label="Scale"
                        )

                with gr.Accordion(
                        "ControlNet / Img2img / Inpaint",
                        open=False,
                        visible=True):
                    image_control = gr.Image(
                        label="Image ControlNet/Inpaint/Img2img",
                        type="filepath"
                    )
                    image_mask_gui = gr.Image(
                        label="Image Mask",
                        type="filepath"
                    )
                    strength_gui = gr.Slider(
                        minimum=0.01,
                        maximum=1.0,
                        step=0.01,
                        value=0.55,
                        label="Strength",
                        info="This option adjusts the level of changes for img2img and inpainting."
                    )
                    image_resolution_gui = gr.Slider(
                        minimum=64,
                        maximum=2048,
                        step=64, value=1024,
                        label="Image Resolution"
                    )
                    preprocessor_name_gui = gr.Dropdown(
                        label="Preprocessor Name",
                        choices=preprocessor_controlnet["canny"]
                    )


                    def change_preprocessor_choices(task):
                        task = task_stablepy[task]
                        if task in preprocessor_controlnet.keys():
                            choices_task = preprocessor_controlnet[task]
                        else:
                            choices_task = preprocessor_controlnet["canny"]
                        return gr.update(
                            choices=choices_task,
                            value=choices_task[0]
                        )


                    task_gui.change(
                        change_preprocessor_choices,
                        [task_gui],
                        [preprocessor_name_gui],
                    )
                    preprocess_resolution_gui = gr.Slider(
                        minimum=64,
                        maximum=2048,
                        step=64,
                        value=512,
                        label="Preprocess Resolution"
                    )
                    low_threshold_gui = gr.Slider(
                        minimum=1,
                        maximum=255,
                        step=1,
                        value=100,
                        label="Canny low threshold"
                    )
                    high_threshold_gui = gr.Slider(
                        minimum=1,
                        maximum=255,
                        step=1,
                        value=200,
                        label="Canny high threshold"
                    )
                    value_threshold_gui = gr.Slider(
                        minimum=1,
                        maximum=2.0,
                        step=0.01, value=0.1,
                        label="Hough value threshold (MLSD)"
                    )
                    distance_threshold_gui = gr.Slider(
                        minimum=1,
                        maximum=20.0,
                        step=0.01,
                        value=0.1,
                        label="Hough distance threshold (MLSD)"
                    )
                    control_net_output_scaling_gui = gr.Slider(
                        minimum=0,
                        maximum=5.0,
                        step=0.1,
                        value=1,
                        label="ControlNet Output Scaling in UNet"
                    )
                    control_net_start_threshold_gui = gr.Slider(
                        minimum=0,
                        maximum=1,
                        step=0.01,
                        value=0,
                        label="ControlNet Start Threshold (%)"
                    )
                    control_net_stop_threshold_gui = gr.Slider(
                        minimum=0,
                        maximum=1,
                        step=0.01,
                        value=1,
                        label="ControlNet Stop Threshold (%)"
                    )

                with gr.Accordion(
                        "T2I adapter",
                        open=False,
                        visible=True):
                    t2i_adapter_preprocessor_gui = gr.Checkbox(
                        value=True,
                        label="T2i Adapter Preprocessor"
                    )
                    adapter_conditioning_scale_gui = gr.Slider(
                        minimum=0,
                        maximum=5.,
                        step=0.1,
                        value=1,
                        label="Adapter Conditioning Scale"
                    )
                    adapter_conditioning_factor_gui = gr.Slider(
                        minimum=0,
                        maximum=1.,
                        step=0.01,
                        value=0.55,
                        label="Adapter Conditioning Factor (%)"
                    )

                with gr.Accordion(
                        "Styles",
                        open=False,
                        visible=True):

                    # noinspection PyBroadException
                    try:
                        style_names_found = SD_GEN.model.STYLE_NAMES
                    except Exception as e:
                        style_names_found = STYLE_NAMES

                    style_prompt_gui = gr.Dropdown(
                        style_names_found,
                        multiselect=True,
                        value=None,
                        label="Style Prompt",
                        interactive=True,
                    )
                    style_json_gui = gr.File(label="Style JSON File")
                    style_button = gr.Button("Load styles")


                    def load_json_style_file(json):
                        if not SD_GEN.model:
                            gr.Info("First load the model")
                            return gr.update(
                                value=None,
                                choices=STYLE_NAMES
                            )

                        SD_GEN.model.load_style_file(json)
                        gr.Info(f"{len(SD_GEN.model.STYLE_NAMES)} styles loaded")
                        return gr.update(
                            value=None,
                            choices=SD_GEN.model.STYLE_NAMES
                        )


                    style_button.click(
                        load_json_style_file,
                        [style_json_gui],
                        [style_prompt_gui]
                    )

                with gr.Accordion(
                        "Textual inversion",
                        open=False,
                        visible=False):
                    active_textual_inversion_gui = gr.Checkbox(
                        value=False,
                        label="Active Textual Inversion in prompt"
                    )

                with gr.Accordion(
                        "Detailfix",
                        open=False,
                        visible=True):
                    # Adetailer Inpaint Only
                    adetailer_inpaint_only_gui = gr.Checkbox(
                        label="Inpaint only",
                        value=True
                    )

                    # Adetailer Verbose
                    adetailer_verbose_gui = gr.Checkbox(
                        label="Verbose",
                        value=False
                    )

                    # Adetailer Sampler
                    adetailer_sampler_options = ["Use same sampler"] + scheduler_names[:-1]
                    adetailer_sampler_gui = gr.Dropdown(
                        label="Adetailer sampler:",
                        choices=adetailer_sampler_options,
                        value="Use same sampler"
                    )

                    with gr.Accordion(
                            "Detailfix A",
                            open=False,
                            visible=True):
                        # Adetailer A
                        adetailer_active_a_gui = gr.Checkbox(
                            label="Enable Adetailer A",
                            value=False
                        )
                        prompt_ad_a_gui = gr.Textbox(
                            label="Main prompt",
                            placeholder="Main prompt will be use",
                            lines=3
                        )
                        negative_prompt_ad_a_gui = gr.Textbox(
                            label="Negative prompt",
                            placeholder="Main negative prompt will be use",
                            lines=3
                        )
                        strength_ad_a_gui = gr.Number(
                            label="Strength:",
                            value=0.35, step=0.01,
                            minimum=0.01,
                            maximum=1.0
                        )
                        face_detector_ad_a_gui = gr.Checkbox(
                            label="Face detector",
                            value=True
                        )
                        person_detector_ad_a_gui = gr.Checkbox(
                            label="Person detector",
                            value=True
                        )
                        hand_detector_ad_a_gui = gr.Checkbox(
                            label="Hand detector",
                            value=False
                        )
                        mask_dilation_a_gui = gr.Number(
                            label="Mask dilation:",
                            value=4,
                            minimum=1
                        )
                        mask_blur_a_gui = gr.Number(
                            label="Mask blur:",
                            value=4,
                            minimum=1
                        )
                        mask_padding_a_gui = gr.Number(
                            label="Mask padding:",
                            value=32,
                            minimum=1
                        )

                    with gr.Accordion(
                            "Detailfix B",
                            open=False,
                            visible=True):
                        # Adetailer B
                        adetailer_active_b_gui = gr.Checkbox(
                            label="Enable Adetailer B",
                            value=False
                        )
                        prompt_ad_b_gui = gr.Textbox(
                            label="Main prompt",
                            placeholder="Main prompt will be use",
                            lines=3
                        )
                        negative_prompt_ad_b_gui = gr.Textbox(
                            label="Negative prompt",
                            placeholder="Main negative prompt will be use",
                            lines=3
                        )
                        strength_ad_b_gui = gr.Number(
                            label="Strength:",
                            value=0.35,
                            step=0.01,
                            minimum=0.01,
                            maximum=1.0
                        )
                        face_detector_ad_b_gui = gr.Checkbox(
                            label="Face detector",
                            value=True
                        )
                        person_detector_ad_b_gui = gr.Checkbox(
                            label="Person detector",
                            value=True
                        )
                        hand_detector_ad_b_gui = gr.Checkbox(
                            label="Hand detector",
                            value=False
                        )
                        mask_dilation_b_gui = gr.Number(
                            label="Mask dilation:",
                            value=4,
                            minimum=1
                        )
                        mask_blur_b_gui = gr.Number(
                            label="Mask blur:",
                            value=4,
                            minimum=1
                        )
                        mask_padding_b_gui = gr.Number(
                            label="Mask padding:",
                            value=32,
                            minimum=1
                        )

                with gr.Accordion(
                        "Other settings",
                        open=False,
                        visible=True):
                    image_previews_gui = gr.Checkbox(
                        value=True,
                        label="Image Previews"
                    )
                    hires_before_adetailer_gui = gr.Checkbox(
                        value=False,
                        label="Hires Before Adetailer"
                    )
                    hires_after_adetailer_gui = gr.Checkbox(
                        value=True,
                        label="Hires After Adetailer"
                    )
                    generator_in_cpu_gui = gr.Checkbox(
                        value=False,
                        label="Generator in CPU"
                    )

                with gr.Accordion(
                        "More settings",
                        open=False,
                        visible=False):
                    loop_generation_gui = gr.Slider(
                        minimum=1,
                        value=1,
                        label="Loop Generation"
                    )
                    retain_task_cache_gui = gr.Checkbox(
                        value=False,
                        label="Retain task model in cache"
                    )
                    leave_progress_bar_gui = gr.Checkbox(
                        value=True,
                        label="Leave Progress Bar"
                    )
                    disable_progress_bar_gui = gr.Checkbox(
                        value=False,
                        label="Disable Progress Bar"
                    )
                    display_images_gui = gr.Checkbox(
                        value=True,
                        label="Display Images"
                    )
                    save_generated_images_gui = gr.Checkbox(
                        value=False,
                        label="Save Generated Images"
                    )
                    image_storage_location_gui = gr.Textbox(
                        value="./images",
                        label="Image Storage Location"
                    )
                    retain_compel_previous_load_gui = gr.Checkbox(
                        value=False,
                        label="Retain Compel Previous Load"
                    )
                    retain_detail_fix_model_previous_load_gui = gr.Checkbox(
                        value=False,
                        label="Retain Detail fix Model Previous Load"
                    )
                    retain_hires_model_previous_load_gui = gr.Checkbox(
                        value=False,
                        label="Retain Hires Model Previous Load"
                    )
                    xformers_memory_efficient_attention_gui = gr.Checkbox(
                        value=False,
                        label="Xformers Memory Efficient Attention"
                    )

        # example and Help Section
        with gr.Accordion(
                "Examples and help",
                open=False,
                visible=True):
            gr.Markdown(
                """### Help:
                - The current space runs on a ZERO GPU which is assigned for approximately 60 seconds; Therefore, \
                if you submit expensive tasks, the operation may be canceled upon reaching the \
                maximum allowed time with 'GPU TASK ABORTED'.
                - Distorted or strange images often result from high prompt weights, \
                so it's best to use low weights and scales, and consider using Classic variants like 'Classic-original'.
                - For better results with Pony Diffusion, \
                try using sampler DPM++ 1s or DPM2 with Compel or Classic prompt weights.
                """
            )

            gr.Markdown(
                """### The following examples perform specific tasks:
                1. Generation with SDXL and upscale
                2. Generation with SDXL
                3. ControlNet Canny SDXL
                4. Optical pattern (Optical illusion) SDXL
                5. Convert an image to a coloring drawing
                6. ControlNet OpenPose SD 1.5

                - Different tasks can be performed, such as img2img or using the IP adapter, \
                to preserve a person's appearance or a specific style based on an image.
                """
            )

            gr.Examples(
                examples=example_prompts,
                fn=SD_GEN.generate_pipeline,
                inputs=[
                    prompt_gui,
                    neg_prompt_gui,
                    num_images_gui,
                    steps_gui,
                    cfg_gui,
                    clip_skip_gui,
                    seed_gui,
                    lora1_gui,
                    lora_scale_1_gui,
                    lora2_gui,
                    lora_scale_2_gui,
                    lora3_gui,
                    lora_scale_3_gui,
                    lora4_gui,
                    lora_scale_4_gui,
                    lora5_gui,
                    lora_scale_5_gui,
                    sampler_gui,
                    img_height_gui,
                    img_width_gui,
                    model_name_gui,
                    vae_model_gui,
                    task_gui,
                    image_control,
                    preprocessor_name_gui,
                    preprocess_resolution_gui,
                    image_resolution_gui,
                    style_prompt_gui,
                    style_json_gui,
                    image_mask_gui,
                    strength_gui,
                    low_threshold_gui,
                    high_threshold_gui,
                    value_threshold_gui,
                    distance_threshold_gui,
                    control_net_output_scaling_gui,
                    control_net_start_threshold_gui,
                    control_net_stop_threshold_gui,
                    active_textual_inversion_gui,
                    prompt_syntax_gui,
                    upscaler_model_path_gui,
                ],
                outputs=[result_images],
                cache_examples=False,
            )

    with gr.Tab("Inpaint mask maker", render=True):
        def create_mask_now(img, invert):
            import numpy as np
            import time

            time.sleep(0.5)

            transparent_image = img["layers"][0]

            # Extract the alpha channel
            alpha_channel = np.array(transparent_image)[:, :, 3]

            # Create a binary mask by thresholding the alpha channel
            binary_mask = alpha_channel > 1

            if invert:
                print("Invert")
                # Invert the binary mask so that the drawn shape is white and the rest is black
                binary_mask = np.invert(binary_mask)

            # Convert the binary mask to a 3-channel RGB mask
            rgb_mask = np.stack((binary_mask,) * 3, axis=-1)

            # Convert the mask to uint8
            rgb_mask = rgb_mask.astype(np.uint8) * 255

            return img["background"], rgb_mask


        with gr.Row():
            with gr.Column(scale=2):
                # image_base = gr.ImageEditor(label="Base image", show_label=True, brush=gr.Brush(colors=["#000000"]))
                image_base = gr.ImageEditor(
                    sources=[
                        "upload",
                        "clipboard"
                    ],
                    # crop_size="1:1",
                    # enable crop (or disable it)
                    # transforms=["crop"],
                    brush=gr.Brush(
                        default_size="16",  # or leave it as 'auto'
                        color_mode="fixed",  # 'fixed' hides the user swatches and colorpicker, 'defaults' shows it
                        # default_color="black", # html names are supported
                        colors=[
                            "rgba(0, 0, 0, 1)",  # rgb(a)
                            "rgba(0, 0, 0, 0.1)",
                            "rgba(255, 255, 255, 0.1)",
                            # "hsl(360, 120, 120)" # in fact any valid colorstring
                        ]
                    ),
                    eraser=gr.Eraser(default_size="16")
                )
                invert_mask = gr.Checkbox(
                    value=False,
                    label="Invert mask"
                )
                btn = gr.Button("Create mask")

            with gr.Column(scale=1):
                img_source = gr.Image(interactive=False)
                img_result = gr.Image(
                    label="Mask image",
                    show_label=True,
                    interactive=False
                )
                btn_send = gr.Button("Send to the first tab")

            btn.click(
                create_mask_now,
                [image_base, invert_mask],
                [img_source, img_result]
            )


            def send_img(img_source, img_result) -> tuple:
                return img_source, img_result


            btn_send.click(
                send_img,
                [img_source, img_result],
                [image_control, image_mask_gui]
            )

    generate_button.click(
        fn=SD_GEN.load_new_model,
        inputs=[
            model_name_gui,
            vae_model_gui,
            task_gui
        ],
        outputs=[load_model_gui],
        queue=True,
        show_progress="minimal",
    ).success(
        fn=SD_GEN.generate_pipeline,
        inputs=[
            prompt_gui,
            neg_prompt_gui,
            num_images_gui,
            steps_gui,
            cfg_gui,
            clip_skip_gui,
            seed_gui,
            lora1_gui,
            lora_scale_1_gui,
            lora2_gui,
            lora_scale_2_gui,
            lora3_gui,
            lora_scale_3_gui,
            lora4_gui,
            lora_scale_4_gui,
            lora5_gui,
            lora_scale_5_gui,
            sampler_gui,
            img_height_gui,
            img_width_gui,
            model_name_gui,
            vae_model_gui,
            task_gui,
            image_control,
            preprocessor_name_gui,
            preprocess_resolution_gui,
            image_resolution_gui,
            style_prompt_gui,
            style_json_gui,
            image_mask_gui,
            strength_gui,
            low_threshold_gui,
            high_threshold_gui,
            value_threshold_gui,
            distance_threshold_gui,
            control_net_output_scaling_gui,
            control_net_start_threshold_gui,
            control_net_stop_threshold_gui,
            active_textual_inversion_gui,
            prompt_syntax_gui,
            upscaler_model_path_gui,
            upscaler_increases_size_gui,
            esrgan_tile_gui,
            esrgan_tile_overlap_gui,
            hires_steps_gui,
            hires_denoising_strength_gui,
            hires_sampler_gui,
            hires_prompt_gui,
            hires_negative_prompt_gui,
            hires_before_adetailer_gui,
            hires_after_adetailer_gui,
            loop_generation_gui,
            leave_progress_bar_gui,
            disable_progress_bar_gui,
            image_previews_gui,
            display_images_gui,
            save_generated_images_gui,
            image_storage_location_gui,
            retain_compel_previous_load_gui,
            retain_detail_fix_model_previous_load_gui,
            retain_hires_model_previous_load_gui,
            t2i_adapter_preprocessor_gui,
            adapter_conditioning_scale_gui,
            adapter_conditioning_factor_gui,
            xformers_memory_efficient_attention_gui,
            free_u_gui,
            generator_in_cpu_gui,
            adetailer_inpaint_only_gui,
            adetailer_verbose_gui,
            adetailer_sampler_gui,
            adetailer_active_a_gui,
            prompt_ad_a_gui,
            negative_prompt_ad_a_gui,
            strength_ad_a_gui,
            face_detector_ad_a_gui,
            person_detector_ad_a_gui,
            hand_detector_ad_a_gui,
            mask_dilation_a_gui,
            mask_blur_a_gui,
            mask_padding_a_gui,
            adetailer_active_b_gui,
            prompt_ad_b_gui,
            negative_prompt_ad_b_gui,
            strength_ad_b_gui,
            face_detector_ad_b_gui,
            person_detector_ad_b_gui,
            hand_detector_ad_b_gui,
            mask_dilation_b_gui,
            mask_blur_b_gui,
            mask_padding_b_gui,
            retain_task_cache_gui,
            image_ip1,
            mask_ip1,
            model_ip1,
            mode_ip1,
            scale_ip1,
            image_ip2,
            mask_ip2,
            model_ip2,
            mode_ip2,
            scale_ip2,
        ],
        outputs=[
            result_images,
            actual_task_info
        ],
        queue=True,
        show_progress="minimal",
    )

app.queue()
app.launch(
    show_error=True,
    debug=True,
)