ui.py 75.7 KB
Newer Older
1 2 3 4
import base64
import html
import io
import json
A
AUTOMATIC 已提交
5
import math
6 7
import mimetypes
import os
A
AUTOMATIC 已提交
8
import random
9
import sys
10
import tempfile
11 12
import time
import traceback
M
Michoko 已提交
13 14
import platform
import subprocess as sp
L
Liam 已提交
15
from functools import reduce
16

A
AUTOMATIC 已提交
17 18
import numpy as np
import torch
19
from PIL import Image, PngImagePlugin
20
import piexif
21 22 23

import gradio as gr
import gradio.utils
A
AUTOMATIC 已提交
24
import gradio.routes
25

26
from modules import sd_hijack, sd_models
27 28
from modules.paths import script_path
from modules.shared import opts, cmd_opts
29 30
if cmd_opts.deepdanbooru:
    from modules.deepbooru import get_deepbooru_tags
31 32
import modules.shared as shared
from modules.sd_samplers import samplers, samplers_for_img2img
33
from modules.sd_hijack import model_hijack
34
import modules.ldsr_model
A
AUTOMATIC 已提交
35
import modules.scripts
36 37
import modules.gfpgan_model
import modules.codeformer_model
A
AUTOMATIC 已提交
38
import modules.styles
39
import modules.generation_parameters_copypaste
A
AUTOMATIC 已提交
40
from modules import prompt_parser
M
Milly 已提交
41
from modules.images import save_image
42
import modules.textual_inversion.ui
43
import modules.hypernetworks.ui
Y
yfszzx 已提交
44
import modules.images_history as img_his
45

A
Aidan Holland 已提交
46
# this is a fix for Windows users. Without it, javascript files will be served with text/html content-type and the browser will not show any UI
47 48 49 50
mimetypes.init()
mimetypes.add_type('application/javascript', '.js')


51
if not cmd_opts.share and not cmd_opts.listen:
52 53 54 55
    # fix gradio phoning home
    gradio.utils.version_check = lambda: None
    gradio.utils.get_local_ip_address = lambda: '127.0.0.1'

J
JamnedZ 已提交
56 57 58 59 60
if cmd_opts.ngrok != None:
    import modules.ngrok as ngrok
    print('ngrok authtoken detected, trying to connect...')
    ngrok.connect(cmd_opts.ngrok, cmd_opts.port if cmd_opts.port != None else 7860)

61 62 63 64 65 66 67 68 69 70

def gr_show(visible=True):
    return {"visible": visible, "__type__": "update"}


sample_img2img = "assets/stable-samples/img2img/sketch-mountains-input.jpg"
sample_img2img = sample_img2img if os.path.exists(sample_img2img) else None

css_hide_progressbar = """
.wrap .m-12 svg { display:none!important; }
71
.wrap .m-12::before { content:"Loading..." }
72 73 74 75
.progress-bar { display:none!important; }
.meta-text { display:none!important; }
"""

76 77 78 79
# Using constants for these since the variation selector isn't visible.
# Important that they exactly match script.js for tooltip to work.
random_symbol = '\U0001f3b2\ufe0f'  # 🎲️
reuse_symbol = '\u267b\ufe0f'  # ♻️
80 81
art_symbol = '\U0001f3a8'  # 🎨
paste_symbol = '\u2199\ufe0f'  # ↙
82
folder_symbol = '\U0001f4c2'  # 📂
83
refresh_symbol = '\U0001f504'  # 🔄
A
AUTOMATIC 已提交
84 85
save_style_symbol = '\U0001f4be'  # 💾
apply_style_symbol = '\U0001f4cb'  # 📋
86

87

88
def plaintext_to_html(text):
89
    text = "<p>" + "<br>\n".join([f"{html.escape(x)}" for x in text.split('\n')]) + "</p>"
90 91 92 93
    return text


def image_from_url_text(filedata):
94 95 96 97 98 99 100 101
    if type(filedata) == dict and filedata["is_file"]:
        filename = filedata["name"]
        tempdir = os.path.normpath(tempfile.gettempdir())
        normfn = os.path.normpath(filename)
        assert normfn.startswith(tempdir), 'trying to open image file not in temporary directory'

        return Image.open(filename)

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
    if type(filedata) == list:
        if len(filedata) == 0:
            return None

        filedata = filedata[0]

    if filedata.startswith("data:image/png;base64,"):
        filedata = filedata[len("data:image/png;base64,"):]

    filedata = base64.decodebytes(filedata.encode('utf-8'))
    image = Image.open(io.BytesIO(filedata))
    return image


def send_gradio_gallery_to_image(x):
    if len(x) == 0:
        return None

    return image_from_url_text(x[0])

J
jtkelm2 已提交
122

A
aoirusann 已提交
123
def save_files(js_data, images, do_make_zip, index):
J
Justin Maier 已提交
124
    import csv
125
    filenames = []
A
aoirusann 已提交
126
    fullfns = []
127

A
Aidan Holland 已提交
128
    #quick dictionary to class object conversion. Its necessary due apply_filename_pattern requiring it
129 130 131 132 133 134
    class MyObject:
        def __init__(self, d=None):
            if d is not None:
                for key, value in d.items():
                    setattr(self, key, value)

135
    data = json.loads(js_data)
136

137 138
    p = MyObject(data)
    path = opts.outdir_save
139
    save_to_dirs = opts.use_save_to_dirs_for_ui
M
Milly 已提交
140 141
    extension: str = opts.samples_format
    start_index = 0
142

143
    if index > -1 and opts.save_selected_only and (index >= data["index_of_first_image"]):  # ensures we are looking at a specific non-grid picture, and we have save_selected_only
144

J
jtkelm2 已提交
145
        images = [images[index]]
M
Milly 已提交
146
        start_index = index
147

148 149
    os.makedirs(opts.outdir_save, exist_ok=True)

150
    with open(os.path.join(opts.outdir_save, "log.csv"), "a", encoding="utf8", newline='') as file:
151 152 153
        at_start = file.tell() == 0
        writer = csv.writer(file)
        if at_start:
154
            writer.writerow(["prompt", "seed", "width", "height", "sampler", "cfgs", "steps", "filename", "negative_prompt"])
155

M
Milly 已提交
156
        for image_index, filedata in enumerate(images, start_index):
157
            image = image_from_url_text(filedata)
158

M
Milly 已提交
159 160 161
            is_grid = image_index < p.index_of_first_image
            i = 0 if is_grid else (image_index - p.index_of_first_image)

G
Greg Fuller 已提交
162
            fullfn, txt_fullfn = save_image(image, path, "", seed=p.all_seeds[i], prompt=p.all_prompts[i], extension=extension, info=p.infotexts[image_index], grid=is_grid, p=p, save_to_dirs=save_to_dirs)
M
Milly 已提交
163 164

            filename = os.path.relpath(fullfn, path)
165
            filenames.append(filename)
A
aoirusann 已提交
166
            fullfns.append(fullfn)
A
aoirusann 已提交
167 168 169
            if txt_fullfn:
                filenames.append(os.path.basename(txt_fullfn))
                fullfns.append(txt_fullfn)
170

G
Greg Fuller 已提交
171
        writer.writerow([data["prompt"], data["seed"], data["width"], data["height"], data["sampler"], data["cfg_scale"], data["steps"], filenames[0], data["negative_prompt"]])
172

A
aoirusann 已提交
173 174 175 176 177 178 179 180 181 182 183
    # Make Zip
    if do_make_zip:
        zip_filepath = os.path.join(path, "images.zip")

        from zipfile import ZipFile
        with ZipFile(zip_filepath, "w") as zip_file:
            for i in range(len(fullfns)):
                with open(fullfns[i], mode="rb") as f:
                    zip_file.writestr(filenames[i], f.read())
        fullfns.insert(0, zip_filepath)

184
    return gr.File.update(value=fullfns, visible=True), '', '', plaintext_to_html(f"Saved: {filenames[0]}")
185 186


187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
def save_pil_to_file(pil_image, dir=None):
    use_metadata = False
    metadata = PngImagePlugin.PngInfo()
    for key, value in pil_image.info.items():
        if isinstance(key, str) and isinstance(value, str):
            metadata.add_text(key, value)
            use_metadata = True

    file_obj = tempfile.NamedTemporaryFile(delete=False, suffix=".png", dir=dir)
    pil_image.save(file_obj, pnginfo=(metadata if use_metadata else None))
    return file_obj


# override save to file function so that it also writes PNG info
gr.processing_utils.save_pil_to_file = save_pil_to_file


204 205
def wrap_gradio_call(func, extra_outputs=None):
    def f(*args, extra_outputs_array=extra_outputs, **kwargs):
E
EyeDeck 已提交
206 207
        run_memmon = opts.memmon_poll_rate > 0 and not shared.mem_mon.disabled
        if run_memmon:
208
            shared.mem_mon.monitor()
209 210 211 212 213
        t = time.perf_counter()

        try:
            res = list(func(*args, **kwargs))
        except Exception as e:
214 215 216
            # When printing out our debug argument list, do not print out more than a MB of text
            max_debug_str_len = 131072 # (1024*1024)/8

217
            print("Error completing request", file=sys.stderr)
218 219 220 221 222
            argStr = f"Arguments: {str(args)} {str(kwargs)}"
            print(argStr[:max_debug_str_len], file=sys.stderr)
            if len(argStr) > max_debug_str_len:
                print(f"(Argument list truncated at {max_debug_str_len}/{len(argStr)} characters)", file=sys.stderr)

223 224
            print(traceback.format_exc(), file=sys.stderr)

A
AUTOMATIC 已提交
225 226 227
            shared.state.job = ""
            shared.state.job_count = 0

228 229 230 231
            if extra_outputs_array is None:
                extra_outputs_array = [None, '']

            res = extra_outputs_array + [f"<div class='error'>{plaintext_to_html(type(e).__name__+': '+str(e))}</div>"]
232 233

        elapsed = time.perf_counter() - t
234 235 236 237 238
        elapsed_m = int(elapsed // 60)
        elapsed_s = elapsed % 60
        elapsed_text = f"{elapsed_s:.2f}s"
        if (elapsed_m > 0):
            elapsed_text = f"{elapsed_m}m "+elapsed_text
239

E
EyeDeck 已提交
240
        if run_memmon:
241 242 243 244 245 246 247
            mem_stats = {k: -(v//-(1024*1024)) for k, v in shared.mem_mon.stop().items()}
            active_peak = mem_stats['active_peak']
            reserved_peak = mem_stats['reserved_peak']
            sys_peak = mem_stats['system_peak']
            sys_total = mem_stats['total']
            sys_pct = round(sys_peak/max(sys_total, 1) * 100, 2)

E
EyeDeck 已提交
248
            vram_html = f"<p class='vram'>Torch active/reserved: {active_peak}/{reserved_peak} MiB, <wbr>Sys VRAM: {sys_peak}/{sys_total} MiB ({sys_pct}%)</p>"
249 250
        else:
            vram_html = ''
251

252
        # last item is always HTML
253
        res[-1] += f"<div class='performance'><p class='time'>Time taken: <wbr>{elapsed_text}</p>{vram_html}</div>"
254

255
        shared.state.skipped = False
256
        shared.state.interrupted = False
257
        shared.state.job_count = 0
258 259 260 261 262 263

        return tuple(res)

    return f


264
def check_progress_call(id_part):
A
AUTOMATIC 已提交
265
    if shared.state.job_count == 0:
266
        return "", gr_show(False), gr_show(False), gr_show(False)
A
AUTOMATIC 已提交
267

A
AUTOMATIC 已提交
268 269 270 271
    progress = 0

    if shared.state.job_count > 0:
        progress += shared.state.job_no / shared.state.job_count
A
AUTOMATIC 已提交
272 273 274 275 276
    if shared.state.sampling_steps > 0:
        progress += 1 / shared.state.job_count * shared.state.sampling_step / shared.state.sampling_steps

    progress = min(progress, 1)

A
AUTOMATIC 已提交
277 278 279 280 281 282 283 284
    progressbar = ""
    if opts.show_progressbar:
        progressbar = f"""<div class='progressDiv'><div class='progress' style="width:{progress * 100}%">{str(int(progress*100))+"%" if progress > 0.01 else ""}</div></div>"""

    image = gr_show(False)
    preview_visibility = gr_show(False)

    if opts.show_progress_every_n_steps > 0:
285
        if shared.parallel_processing_allowed:
A
AUTOMATIC 已提交
286

287 288 289
            if shared.state.sampling_step - shared.state.current_image_sampling_step >= opts.show_progress_every_n_steps and shared.state.current_latent is not None:
                shared.state.current_image = modules.sd_samplers.sample_to_image(shared.state.current_latent)
                shared.state.current_image_sampling_step = shared.state.sampling_step
A
AUTOMATIC 已提交
290

A
AUTOMATIC 已提交
291 292
        image = shared.state.current_image

A
AUTOMATIC 已提交
293
        if image is None:
A
AUTOMATIC 已提交
294 295 296
            image = gr.update(value=None)
        else:
            preview_visibility = gr_show(True)
A
AUTOMATIC 已提交
297

298 299 300 301 302 303
    if shared.state.textinfo is not None:
        textinfo_result = gr.HTML.update(value=shared.state.textinfo, visible=True)
    else:
        textinfo_result = gr_show(False)

    return f"<span id='{id_part}_progress_span' style='display: none'>{time.time()}</span><p>{progressbar}</p>", preview_visibility, image, textinfo_result
A
AUTOMATIC 已提交
304 305


306
def check_progress_call_initial(id_part):
307
    shared.state.job_count = -1
308 309
    shared.state.current_latent = None
    shared.state.current_image = None
310
    shared.state.textinfo = None
311

312
    return check_progress_call(id_part)
313 314


A
AUTOMATIC 已提交
315 316 317 318 319 320 321
def roll_artist(prompt):
    allowed_cats = set([x for x in shared.artist_db.categories() if len(opts.random_artist_categories)==0 or x in opts.random_artist_categories])
    artist = random.choice([x for x in shared.artist_db.artists if x.category in allowed_cats])

    return prompt + ", " + artist.name if prompt != '' else artist.name


A
AUTOMATIC 已提交
322 323 324 325 326 327 328
def visit(x, func, path=""):
    if hasattr(x, 'children'):
        for c in x.children:
            visit(c, func, path)
    elif x.label is not None:
        func(path + "/" + str(x.label), x)

329

330 331
def add_style(name: str, prompt: str, negative_prompt: str):
    if name is None:
A
AUTOMATIC 已提交
332
        return [gr_show() for x in range(4)]
A
AUTOMATIC 已提交
333

334
    style = modules.styles.PromptStyle(name, prompt, negative_prompt)
A
AUTOMATIC 已提交
335
    shared.prompt_styles.styles[style.name] = style
336 337
    # Save all loaded prompt styles: this allows us to update the storage format in the future more easily, because we
    # reserialize all styles every time we save them
A
AUTOMATIC 已提交
338
    shared.prompt_styles.save_styles(shared.styles_filename)
A
AUTOMATIC 已提交
339

340
    return [gr.Dropdown.update(visible=True, choices=list(shared.prompt_styles.styles)) for _ in range(4)]
A
AUTOMATIC 已提交
341 342 343 344 345 346 347


def apply_styles(prompt, prompt_neg, style1_name, style2_name):
    prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, [style1_name, style2_name])
    prompt_neg = shared.prompt_styles.apply_negative_styles_to_prompt(prompt_neg, [style1_name, style2_name])

    return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=prompt_neg), gr.Dropdown.update(value="None"), gr.Dropdown.update(value="None")]
A
AUTOMATIC 已提交
348 349


A
AUTOMATIC 已提交
350 351 352 353 354
def interrogate(image):
    prompt = shared.interrogator.interrogate(image)

    return gr_show(True) if prompt is None else prompt

A
AUTOMATIC 已提交
355

G
Greendayle 已提交
356 357 358 359 360
def interrogate_deepbooru(image):
    prompt = get_deepbooru_tags(image)
    return gr_show(True) if prompt is None else prompt


361 362 363 364
def create_seed_inputs():
    with gr.Row():
        with gr.Box():
            with gr.Row(elem_id='seed_row'):
365
                seed = (gr.Textbox if cmd_opts.use_textbox_seed else gr.Number)(label='Seed', value=-1)
366
                seed.style(container=False)
367 368
                random_seed = gr.Button(random_symbol, elem_id='random_seed')
                reuse_seed = gr.Button(reuse_symbol, elem_id='reuse_seed')
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398

        with gr.Box(elem_id='subseed_show_box'):
            seed_checkbox = gr.Checkbox(label='Extra', elem_id='subseed_show', value=False)

    # Components to show/hide based on the 'Extra' checkbox
    seed_extras = []

    with gr.Row(visible=False) as seed_extra_row_1:
        seed_extras.append(seed_extra_row_1)
        with gr.Box():
            with gr.Row(elem_id='subseed_row'):
                subseed = gr.Number(label='Variation seed', value=-1)
                subseed.style(container=False)
                random_subseed = gr.Button(random_symbol, elem_id='random_subseed')
                reuse_subseed = gr.Button(reuse_symbol, elem_id='reuse_subseed')
        subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01)

    with gr.Row(visible=False) as seed_extra_row_2:
        seed_extras.append(seed_extra_row_2)
        seed_resize_from_w = gr.Slider(minimum=0, maximum=2048, step=64, label="Resize seed from width", value=0)
        seed_resize_from_h = gr.Slider(minimum=0, maximum=2048, step=64, label="Resize seed from height", value=0)

    random_seed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[seed])
    random_subseed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[subseed])

    def change_visibility(show):
        return {comp: gr_show(show) for comp in seed_extras}

    seed_checkbox.change(change_visibility, show_progress=False, inputs=[seed_checkbox], outputs=seed_extras)

399
    return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox
400 401


402 403 404
def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: gr.Textbox, dummy_component, is_subseed):
    """ Connects a 'reuse (sub)seed' button's click event so that it copies last used
        (sub)seed value from generation info the to the seed field. If copying subseed and subseed strength
405
        was 0, i.e. no variation seed was used, it copies the normal seed value instead."""
406 407 408
    def copy_seed(gen_info_string: str, index):
        res = -1

409 410
        try:
            gen_info = json.loads(gen_info_string)
411 412 413 414 415
            index -= gen_info.get('index_of_first_image', 0)

            if is_subseed and gen_info.get('subseed_strength', 0) > 0:
                all_subseeds = gen_info.get('all_subseeds', [-1])
                res = all_subseeds[index if 0 <= index < len(all_subseeds) else 0]
416
            else:
417 418 419
                all_seeds = gen_info.get('all_seeds', [-1])
                res = all_seeds[index if 0 <= index < len(all_seeds) else 0]

420 421 422 423
        except json.decoder.JSONDecodeError as e:
            if gen_info_string != '':
                print("Error parsing JSON generation info:", file=sys.stderr)
                print(gen_info_string, file=sys.stderr)
424 425

        return [res, gr_show(False)]
426 427 428

    reuse_seed.click(
        fn=copy_seed,
429
        _js="(x, y) => [x, selected_gallery_index()]",
430
        show_progress=False,
431 432
        inputs=[generation_info, dummy_component],
        outputs=[seed, dummy_component]
433 434
    )

435

L
Liam 已提交
436
def update_token_counter(text, steps):
437
    try:
A
AUTOMATIC 已提交
438 439 440
        _, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
        prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)

441 442 443 444 445
    except Exception:
        # a parsing error can happen here during typing, and we don't want to bother the user with
        # messages related to it in console
        prompt_schedules = [[[steps, text]]]

L
Liam 已提交
446
    flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules)
447
    prompts = [prompt_text for step, prompt_text in flat_prompts]
L
Liam 已提交
448
    tokens, token_count, max_length = max([model_hijack.tokenize(prompt) for prompt in prompts], key=lambda args: args[1])
449 450
    style_class = ' class="red"' if (token_count > max_length) else ""
    return f"<span {style_class}>{token_count}/{max_length}</span>"
A
AUTOMATIC 已提交
451

452

A
AUTOMATIC 已提交
453
def create_toprow(is_img2img):
454 455
    id_part = "img2img" if is_img2img else "txt2img"

A
AUTOMATIC 已提交
456
    with gr.Row(elem_id="toprow"):
A
AUTOMATIC 已提交
457
        with gr.Column(scale=6):
A
AUTOMATIC 已提交
458
            with gr.Row():
459
                with gr.Column(scale=80):
A
AUTOMATIC 已提交
460
                    with gr.Row():
A
aoirusann 已提交
461 462 463 464
                        prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, lines=2, 
                            placeholder="Prompt (press Ctrl+Enter or Alt+Enter to generate)"
                        )

A
AUTOMATIC 已提交
465
            with gr.Row():
A
AUTOMATIC 已提交
466
                with gr.Column(scale=80):
B
Ben 已提交
467
                    with gr.Row():
A
aoirusann 已提交
468 469 470 471
                        negative_prompt = gr.Textbox(label="Negative prompt", elem_id=f"{id_part}_neg_prompt", show_label=False, lines=2, 
                            placeholder="Negative prompt (press Ctrl+Enter or Alt+Enter to generate)"
                        )

A
AUTOMATIC 已提交
472 473 474 475 476
        with gr.Column(scale=1, elem_id="roll_col"):
            roll = gr.Button(value=art_symbol, elem_id="roll", visible=len(shared.artist_db.artists) > 0)
            paste = gr.Button(value=paste_symbol, elem_id="paste")
            save_style = gr.Button(value=save_style_symbol, elem_id="style_create")
            prompt_style_apply = gr.Button(value=apply_style_symbol, elem_id="style_apply")
A
AUTOMATIC 已提交
477

A
AUTOMATIC 已提交
478 479 480 481 482 483 484 485 486 487 488
            token_counter = gr.HTML(value="<span></span>", elem_id=f"{id_part}_token_counter")
            token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")

        button_interrogate = None
        button_deepbooru = None
        if is_img2img:
            with gr.Column(scale=1, elem_id="interrogate_col"):
                button_interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate")

                if cmd_opts.deepdanbooru:
                    button_deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru")
A
AUTOMATIC 已提交
489 490 491

        with gr.Column(scale=1):
            with gr.Row():
492
                skip = gr.Button('Skip', elem_id=f"{id_part}_skip")
493
                interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt")
494
                submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary')
495

496 497 498 499 500 501
                skip.click(
                    fn=lambda: shared.state.skip(),
                    inputs=[],
                    outputs=[],
                )

502 503 504 505 506
                interrupt.click(
                    fn=lambda: shared.state.interrupt(),
                    inputs=[],
                    outputs=[],
                )
A
AUTOMATIC 已提交
507

A
AUTOMATIC 已提交
508 509 510 511 512 513 514 515
            with gr.Row():
                with gr.Column(scale=1, elem_id="style_pos_col"):
                    prompt_style = gr.Dropdown(label="Style 1", elem_id=f"{id_part}_style_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())))

                with gr.Column(scale=1, elem_id="style_neg_col"):
                    prompt_style2 = gr.Dropdown(label="Style 2", elem_id=f"{id_part}_style2_index", choices=[k for k, v in shared.prompt_styles.styles.items()], value=next(iter(shared.prompt_styles.styles.keys())))

    return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, button_interrogate, button_deepbooru, prompt_style_apply, save_style, paste, token_counter, token_button
A
AUTOMATIC 已提交
516 517


518 519 520
def setup_progressbar(progressbar, preview, id_part, textinfo=None):
    if textinfo is None:
        textinfo = gr.HTML(visible=False)
521

522
    check_progress = gr.Button('Check progress', elem_id=f"{id_part}_check_progress", visible=False)
523
    check_progress.click(
524
        fn=lambda: check_progress_call(id_part),
525 526
        show_progress=False,
        inputs=[],
527
        outputs=[progressbar, preview, preview, textinfo],
528 529
    )

530
    check_progress_initial = gr.Button('Check progress (first)', elem_id=f"{id_part}_check_progress_initial", visible=False)
531
    check_progress_initial.click(
532
        fn=lambda: check_progress_call_initial(id_part),
533 534
        show_progress=False,
        inputs=[],
535
        outputs=[progressbar, preview, preview, textinfo],
536
    )
A
AUTOMATIC 已提交
537 538


539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
def apply_setting(key, value):
    if value is None:
        return gr.update()

    if key == "sd_model_checkpoint":
        ckpt_info = sd_models.get_closet_checkpoint_match(value)

        if ckpt_info is not None:
            value = ckpt_info.title
        else:
            return gr.update()

    comp_args = opts.data_labels[key].component_args
    if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False:
        return

    valtype = type(opts.data_labels[key].default)
    oldval = opts.data[key]
    opts.data[key] = valtype(value) if valtype != type(None) else value
    if oldval != value and opts.data_labels[key].onchange is not None:
        opts.data_labels[key].onchange()

    opts.save(shared.config_filename)
    return value


565 566 567 568
def create_ui(wrap_gradio_gpu_call):
    import modules.img2img
    import modules.txt2img

569
    with gr.Blocks(analytics_enabled=False) as txt2img_interface:
570
        txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, token_counter, token_button = create_toprow(is_img2img=False)
571
        dummy_component = gr.Label(visible=False)
A
AUTOMATIC 已提交
572
        txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="bytes", visible=False)
573

574 575 576
        with gr.Row(elem_id='txt2img_progress_row'):
            with gr.Column(scale=1):
                pass
577

578 579
            with gr.Column(scale=1):
                progressbar = gr.HTML(elem_id="txt2img_progressbar")
580
                txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False)
581
                setup_progressbar(progressbar, txt2img_preview, 'txt2img')
582

583 584 585 586 587
        with gr.Row().style(equal_height=False):
            with gr.Column(variant='panel'):
                steps = gr.Slider(minimum=1, maximum=150, step=1, label="Sampling Steps", value=20)
                sampler_index = gr.Radio(label='Sampling method', elem_id="txt2img_sampling", choices=[x.name for x in samplers], value=samplers[0].name, type="index")

588 589 590 591
                with gr.Group():
                    width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512)
                    height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512)

592
                with gr.Row():
A
AUTOMATIC 已提交
593
                    restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1)
594
                    tiling = gr.Checkbox(label='Tiling', value=False)
A
AUTOMATIC 已提交
595 596 597
                    enable_hr = gr.Checkbox(label='Highres. fix', value=False)

                with gr.Row(visible=False) as hr_options:
598 599
                    firstphase_width = gr.Slider(minimum=0, maximum=1024, step=64, label="Firstpass width", value=0)
                    firstphase_height = gr.Slider(minimum=0, maximum=1024, step=64, label="Firstpass height", value=0)
600
                    denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7)
601 602

                with gr.Row(equal_height=True):
R
RW21 已提交
603
                    batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1)
604 605
                    batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1)

606
                cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0)
607

608
                seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs()
609

A
AUTOMATIC 已提交
610
                with gr.Group():
A
AUTOMATIC 已提交
611
                    custom_inputs = modules.scripts.scripts_txt2img.setup_ui(is_img2img=False)
612 613

            with gr.Column(variant='panel'):
A
AUTOMATIC 已提交
614

615
                with gr.Group():
A
AUTOMATIC 已提交
616
                    txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False)
A
AUTOMATIC 已提交
617
                    txt2img_gallery = gr.Gallery(label='Output', show_label=False, elem_id='txt2img_gallery').style(grid=4)
618

R
ruocaled 已提交
619
                with gr.Column():
620 621 622 623 624
                    with gr.Row():
                        save = gr.Button('Save')
                        send_to_img2img = gr.Button('Send to img2img')
                        send_to_inpaint = gr.Button('Send to inpaint')
                        send_to_extras = gr.Button('Send to extras')
M
Michoko 已提交
625
                        button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else 'open_folder'
M
Michoko 已提交
626
                        open_txt2img_folder = gr.Button(folder_symbol, elem_id=button_id)
627

A
aoirusann 已提交
628 629
                    with gr.Row():
                        do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False)
J
Justin Maier 已提交
630

A
aoirusann 已提交
631
                    with gr.Row():
632
                        download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False)
A
aoirusann 已提交
633

B
Ben 已提交
634 635 636
                    with gr.Group():
                        html_info = gr.HTML()
                        generation_info = gr.Textbox(visible=False)
637

638 639
            connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
            connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
640

641
            txt2img_args = dict(
642
                fn=wrap_gradio_gpu_call(modules.txt2img.txt2img),
A
AUTOMATIC 已提交
643
                _js="submit",
644
                inputs=[
A
AUTOMATIC 已提交
645
                    txt2img_prompt,
646
                    txt2img_negative_prompt,
A
AUTOMATIC 已提交
647
                    txt2img_prompt_style,
A
AUTOMATIC 已提交
648
                    txt2img_prompt_style2,
649 650
                    steps,
                    sampler_index,
A
AUTOMATIC 已提交
651
                    restore_faces,
652
                    tiling,
653 654 655 656
                    batch_count,
                    batch_size,
                    cfg_scale,
                    seed,
657
                    subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
658 659
                    height,
                    width,
A
AUTOMATIC 已提交
660 661
                    enable_hr,
                    denoising_strength,
662 663
                    firstphase_width,
                    firstphase_height,
A
AUTOMATIC 已提交
664
                ] + custom_inputs,
665 666 667 668
                outputs=[
                    txt2img_gallery,
                    generation_info,
                    html_info
669 670
                ],
                show_progress=False,
671 672
            )

A
AUTOMATIC 已提交
673
            txt2img_prompt.submit(**txt2img_args)
674 675
            submit.click(**txt2img_args)

D
d8ahazard 已提交
676 677 678 679 680 681 682 683 684 685 686
            txt_prompt_img.change(
                fn=modules.images.image_data,
                inputs=[
                    txt_prompt_img
                ],
                outputs=[
                    txt2img_prompt,
                    txt_prompt_img
                ]
            )

A
AUTOMATIC 已提交
687 688 689 690 691 692
            enable_hr.change(
                fn=lambda x: gr_show(x),
                inputs=[enable_hr],
                outputs=[hr_options],
            )

693 694
            save.click(
                fn=wrap_gradio_call(save_files),
A
aoirusann 已提交
695
                _js="(x, y, z, w) => [x, y, z, selected_gallery_index()]",
696 697 698
                inputs=[
                    generation_info,
                    txt2img_gallery,
A
aoirusann 已提交
699
                    do_make_zip,
700
                    html_info,
701 702
                ],
                outputs=[
A
aoirusann 已提交
703
                    download_files,
704 705 706 707 708 709
                    html_info,
                    html_info,
                    html_info,
                ]
            )

A
AUTOMATIC 已提交
710 711
            roll.click(
                fn=roll_artist,
L
Liam 已提交
712
                _js="update_txt2img_tokens",
A
AUTOMATIC 已提交
713
                inputs=[
A
AUTOMATIC 已提交
714
                    txt2img_prompt,
A
AUTOMATIC 已提交
715 716
                ],
                outputs=[
A
AUTOMATIC 已提交
717
                    txt2img_prompt,
A
AUTOMATIC 已提交
718 719 720
                ]
            )

721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
            txt2img_paste_fields = [
                (txt2img_prompt, "Prompt"),
                (txt2img_negative_prompt, "Negative prompt"),
                (steps, "Steps"),
                (sampler_index, "Sampler"),
                (restore_faces, "Face restoration"),
                (cfg_scale, "CFG scale"),
                (seed, "Seed"),
                (width, "Size-1"),
                (height, "Size-2"),
                (batch_size, "Batch size"),
                (subseed, "Variation seed"),
                (subseed_strength, "Variation seed strength"),
                (seed_resize_from_w, "Seed resize from-1"),
                (seed_resize_from_h, "Seed resize from-2"),
                (denoising_strength, "Denoising strength"),
                (enable_hr, lambda d: "Denoising strength" in d),
                (hr_options, lambda d: gr.Row.update(visible="Denoising strength" in d)),
739 740
                (firstphase_width, "First pass size-1"),
                (firstphase_height, "First pass size-2"),
741
            ]
742 743 744 745 746 747 748 749 750 751 752 753

            txt2img_preview_params = [
                txt2img_prompt,
                txt2img_negative_prompt,
                steps,
                sampler_index,
                cfg_scale,
                seed,
                width,
                height,
            ]

L
Liam 已提交
754
            token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter])
755

756
    with gr.Blocks(analytics_enabled=False) as img2img_interface:
757
        img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, img2img_paste, token_counter, token_button = create_toprow(is_img2img=True)
758

759
        with gr.Row(elem_id='img2img_progress_row'):
A
AUTOMATIC 已提交
760
            img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="bytes", visible=False)
D
d8ahazard 已提交
761

762 763
            with gr.Column(scale=1):
                pass
764

765 766
            with gr.Column(scale=1):
                progressbar = gr.HTML(elem_id="img2img_progressbar")
767
                img2img_preview = gr.Image(elem_id='img2img_preview', visible=False)
768
                setup_progressbar(progressbar, img2img_preview, 'img2img')
769

770 771
        with gr.Row().style(equal_height=False):
            with gr.Column(variant='panel'):
772

773
                with gr.Tabs(elem_id="mode_img2img") as tabs_img2img_mode:
774
                    with gr.TabItem('img2img', id='img2img'):
775
                        init_img = gr.Image(label="Image for img2img", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool=cmd_opts.gradio_img2img_tool).style(height=480)
776

777
                    with gr.TabItem('Inpaint', id='inpaint'):
778
                        init_img_with_mask = gr.Image(label="Image for inpainting with mask",  show_label=False, elem_id="img2maskimg", source="upload", interactive=True, type="pil", tool="sketch", image_mode="RGBA").style(height=480)
779

780 781
                        init_img_inpaint = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil", visible=False, elem_id="img_inpaint_base")
                        init_mask_inpaint = gr.Image(label="Mask", source="upload", interactive=True, type="pil", visible=False, elem_id="img_inpaint_mask")
782 783 784 785

                        mask_blur = gr.Slider(label='Mask blur', minimum=0, maximum=64, step=1, value=4)

                        with gr.Row():
786
                            mask_mode = gr.Radio(label="Mask mode", show_label=False, choices=["Draw mask", "Upload mask"], type="index", value="Draw mask", elem_id="mask_mode")
787 788
                            inpainting_mask_invert = gr.Radio(label='Masking mode', show_label=False, choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index")

789
                        inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index")
790 791 792 793 794

                        with gr.Row():
                            inpaint_full_res = gr.Checkbox(label='Inpaint at full resolution', value=False)
                            inpaint_full_res_padding = gr.Slider(label='Inpaint at full resolution padding, pixels', minimum=0, maximum=256, step=4, value=32)

795
                    with gr.TabItem('Batch img2img', id='batch'):
796
                        hidden = '<br>Disabled when launched with --hide-ui-dir-config.' if shared.cmd_opts.hide_ui_dir_config else ''
797
                        gr.HTML(f"<p class=\"text-gray-500\">Process images in a directory on the same machine where the server is running.<br>Use an empty output directory to save pictures normally instead of writing to the output directory.{hidden}</p>")
798 799
                        img2img_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs)
                        img2img_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs)
800 801

                with gr.Row():
802 803 804 805
                    resize_mode = gr.Radio(label="Resize mode", elem_id="resize_mode", show_label=False, choices=["Just resize", "Crop and resize", "Resize and fill"], type="index", value="Just resize")

                steps = gr.Slider(minimum=1, maximum=150, step=1, label="Sampling Steps", value=20)
                sampler_index = gr.Radio(label='Sampling method', choices=[x.name for x in samplers_for_img2img], value=samplers_for_img2img[0].name, type="index")
A
AUTOMATIC 已提交
806

807 808 809 810
                with gr.Group():
                    width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512)
                    height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512)

A
AUTOMATIC 已提交
811
                with gr.Row():
A
AUTOMATIC 已提交
812
                    restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1)
813
                    tiling = gr.Checkbox(label='Tiling', value=False)
814 815

                with gr.Row():
R
RW21 已提交
816
                    batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1)
817 818 819
                    batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1)

                with gr.Group():
820
                    cfg_scale = gr.Slider(minimum=1.0, maximum=30.0, step=0.5, label='CFG Scale', value=7.0)
821
                    denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.75)
822

823
                seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs()
824

A
AUTOMATIC 已提交
825
                with gr.Group():
A
AUTOMATIC 已提交
826
                    custom_inputs = modules.scripts.scripts_img2img.setup_ui(is_img2img=True)
A
AUTOMATIC 已提交
827

828
            with gr.Column(variant='panel'):
A
AUTOMATIC 已提交
829

830
                with gr.Group():
A
AUTOMATIC 已提交
831
                    img2img_preview = gr.Image(elem_id='img2img_preview', visible=False)
A
AUTOMATIC 已提交
832
                    img2img_gallery = gr.Gallery(label='Output', show_label=False, elem_id='img2img_gallery').style(grid=4)
833

R
ruocaled 已提交
834
                with gr.Column():
835 836
                    with gr.Row():
                        save = gr.Button('Save')
A
AUTOMATIC 已提交
837 838
                        img2img_send_to_img2img = gr.Button('Send to img2img')
                        img2img_send_to_inpaint = gr.Button('Send to inpaint')
839
                        img2img_send_to_extras = gr.Button('Send to extras')
M
Michoko 已提交
840
                        button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else 'open_folder'
M
Michoko 已提交
841
                        open_img2img_folder = gr.Button(folder_symbol, elem_id=button_id)
842

A
aoirusann 已提交
843 844
                    with gr.Row():
                        do_make_zip = gr.Checkbox(label="Make Zip when Save?", value=False)
J
Justin Maier 已提交
845

A
aoirusann 已提交
846
                    with gr.Row():
847
                        download_files = gr.File(None, file_count="multiple", interactive=False, show_label=False, visible=False)
A
aoirusann 已提交
848

B
Ben 已提交
849 850 851
                    with gr.Group():
                        html_info = gr.HTML()
                        generation_info = gr.Textbox(visible=False)
852

853 854
            connect_reuse_seed(seed, reuse_seed, generation_info, dummy_component, is_subseed=False)
            connect_reuse_seed(subseed, reuse_subseed, generation_info, dummy_component, is_subseed=True)
855

D
d8ahazard 已提交
856 857 858
            img2img_prompt_img.change(
                fn=modules.images.image_data,
                inputs=[
A
AUTOMATIC 已提交
859
                    img2img_prompt_img
D
d8ahazard 已提交
860 861 862 863 864 865 866
                ],
                outputs=[
                    img2img_prompt,
                    img2img_prompt_img
                ]
            )

867
            mask_mode.change(
868
                lambda mode, img: {
869
                    init_img_with_mask: gr_show(mode == 0),
870 871
                    init_img_inpaint: gr_show(mode == 1),
                    init_mask_inpaint: gr_show(mode == 1),
872
                },
873
                inputs=[mask_mode, init_img_with_mask],
874 875
                outputs=[
                    init_img_with_mask,
876 877
                    init_img_inpaint,
                    init_mask_inpaint,
878 879 880
                ],
            )

881
            img2img_args = dict(
882
                fn=wrap_gradio_gpu_call(modules.img2img.img2img),
883
                _js="submit_img2img",
884
                inputs=[
885
                    dummy_component,
A
AUTOMATIC 已提交
886
                    img2img_prompt,
887
                    img2img_negative_prompt,
A
AUTOMATIC 已提交
888
                    img2img_prompt_style,
A
AUTOMATIC 已提交
889
                    img2img_prompt_style2,
890 891
                    init_img,
                    init_img_with_mask,
892 893
                    init_img_inpaint,
                    init_mask_inpaint,
894
                    mask_mode,
895 896 897 898
                    steps,
                    sampler_index,
                    mask_blur,
                    inpainting_fill,
A
AUTOMATIC 已提交
899
                    restore_faces,
900
                    tiling,
901 902 903 904 905
                    batch_count,
                    batch_size,
                    cfg_scale,
                    denoising_strength,
                    seed,
906
                    subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
907 908 909 910
                    height,
                    width,
                    resize_mode,
                    inpaint_full_res,
911
                    inpaint_full_res_padding,
A
AUTOMATIC 已提交
912
                    inpainting_mask_invert,
913 914
                    img2img_batch_input_dir,
                    img2img_batch_output_dir,
A
AUTOMATIC 已提交
915
                ] + custom_inputs,
916 917 918 919
                outputs=[
                    img2img_gallery,
                    generation_info,
                    html_info
920 921
                ],
                show_progress=False,
922 923
            )

A
AUTOMATIC 已提交
924
            img2img_prompt.submit(**img2img_args)
925 926
            submit.click(**img2img_args)

A
AUTOMATIC 已提交
927 928 929 930 931 932
            img2img_interrogate.click(
                fn=interrogate,
                inputs=[init_img],
                outputs=[img2img_prompt],
            )

933 934 935 936 937 938
            if cmd_opts.deepdanbooru:
                img2img_deepbooru.click(
                    fn=interrogate_deepbooru,
                    inputs=[init_img],
                    outputs=[img2img_prompt],
                )
G
Greendayle 已提交
939

940 941
            save.click(
                fn=wrap_gradio_call(save_files),
A
aoirusann 已提交
942
                _js="(x, y, z, w) => [x, y, z, selected_gallery_index()]",
943 944 945
                inputs=[
                    generation_info,
                    img2img_gallery,
A
aoirusann 已提交
946 947
                    do_make_zip,
                    html_info,
948 949
                ],
                outputs=[
A
aoirusann 已提交
950
                    download_files,
951 952 953 954 955 956
                    html_info,
                    html_info,
                    html_info,
                ]
            )

A
AUTOMATIC 已提交
957 958
            roll.click(
                fn=roll_artist,
L
Liam 已提交
959
                _js="update_img2img_tokens",
A
AUTOMATIC 已提交
960 961 962 963 964 965 966 967 968 969
                inputs=[
                    img2img_prompt,
                ],
                outputs=[
                    img2img_prompt,
                ]
            )

            prompts = [(txt2img_prompt, txt2img_negative_prompt), (img2img_prompt, img2img_negative_prompt)]
            style_dropdowns = [(txt2img_prompt_style, txt2img_prompt_style2), (img2img_prompt_style, img2img_prompt_style2)]
L
Liam 已提交
970
            style_js_funcs = ["update_txt2img_tokens", "update_img2img_tokens"]
A
AUTOMATIC 已提交
971 972

            for button, (prompt, negative_prompt) in zip([txt2img_save_style, img2img_save_style], prompts):
A
AUTOMATIC 已提交
973 974 975
                button.click(
                    fn=add_style,
                    _js="ask_for_style_name",
976 977 978
                    # Have to pass empty dummy component here, because the JavaScript and Python function have to accept
                    # the same number of parameters, but we only know the style-name after the JavaScript prompt
                    inputs=[dummy_component, prompt, negative_prompt],
A
AUTOMATIC 已提交
979 980 981
                    outputs=[txt2img_prompt_style, img2img_prompt_style, txt2img_prompt_style2, img2img_prompt_style2],
                )

982
            for button, (prompt, negative_prompt), (style1, style2), js_func in zip([txt2img_prompt_style_apply, img2img_prompt_style_apply], prompts, style_dropdowns, style_js_funcs):
A
AUTOMATIC 已提交
983 984
                button.click(
                    fn=apply_styles,
985
                    _js=js_func,
A
AUTOMATIC 已提交
986 987
                    inputs=[prompt, negative_prompt, style1, style2],
                    outputs=[prompt, negative_prompt, style1, style2],
A
AUTOMATIC 已提交
988 989
                )

990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006
            img2img_paste_fields = [
                (img2img_prompt, "Prompt"),
                (img2img_negative_prompt, "Negative prompt"),
                (steps, "Steps"),
                (sampler_index, "Sampler"),
                (restore_faces, "Face restoration"),
                (cfg_scale, "CFG scale"),
                (seed, "Seed"),
                (width, "Size-1"),
                (height, "Size-2"),
                (batch_size, "Batch size"),
                (subseed, "Variation seed"),
                (subseed_strength, "Variation seed strength"),
                (seed_resize_from_w, "Seed resize from-1"),
                (seed_resize_from_h, "Seed resize from-2"),
                (denoising_strength, "Denoising strength"),
            ]
L
Liam 已提交
1007
            token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter])
1008

1009 1010 1011
    with gr.Blocks(analytics_enabled=False) as extras_interface:
        with gr.Row().style(equal_height=False):
            with gr.Column(variant='panel'):
1012
                with gr.Tabs(elem_id="mode_extras"):
A
ArrowM 已提交
1013
                    with gr.TabItem('Single Image'):
1014
                        extras_image = gr.Image(label="Source", source="upload", interactive=True, type="pil")
A
ArrowM 已提交
1015 1016

                    with gr.TabItem('Batch Process'):
1017
                        image_batch = gr.File(label="Batch Process", file_count="multiple", interactive=True, type="file")
A
AUTOMATIC 已提交
1018

1019 1020 1021 1022 1023 1024 1025 1026 1027
                    with gr.TabItem('Batch from Directory'):
                        extras_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs,
                            placeholder="A directory on the same machine where the server is running."
                        )
                        extras_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs,
                            placeholder="Leave blank to save images to the default path."
                        )
                        show_extras_results = gr.Checkbox(label='Show result images', value=True)

J
Justin Maier 已提交
1028 1029 1030 1031 1032 1033
                with gr.Tabs(elem_id="extras_resize_mode"):
                    with gr.TabItem('Scale by'):
                        upscaling_resize = gr.Slider(minimum=1.0, maximum=4.0, step=0.05, label="Resize", value=2)
                    with gr.TabItem('Scale to'):
                        with gr.Group():
                            with gr.Row():
J
Justin Maier 已提交
1034 1035
                                upscaling_resize_w = gr.Number(label="Width", value=512, precision=0)
                                upscaling_resize_h = gr.Number(label="Height", value=512, precision=0)
J
Justin Maier 已提交
1036
                            upscaling_crop = gr.Checkbox(label='Crop to fit', value=True)
A
AUTOMATIC 已提交
1037 1038 1039 1040 1041 1042 1043 1044 1045

                with gr.Group():
                    extras_upscaler_1 = gr.Radio(label='Upscaler 1', choices=[x.name for x in shared.sd_upscalers], value=shared.sd_upscalers[0].name, type="index")

                with gr.Group():
                    extras_upscaler_2 = gr.Radio(label='Upscaler 2', choices=[x.name for x in shared.sd_upscalers], value=shared.sd_upscalers[0].name, type="index")
                    extras_upscaler_2_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="Upscaler 2 visibility", value=1)

                with gr.Group():
1046 1047 1048 1049
                    gfpgan_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="GFPGAN visibility", value=0, interactive=modules.gfpgan_model.have_gfpgan)

                with gr.Group():
                    codeformer_visibility = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="CodeFormer visibility", value=0, interactive=modules.codeformer_model.have_codeformer)
1050
                    codeformer_weight = gr.Slider(minimum=0.0, maximum=1.0, step=0.001, label="CodeFormer weight (0 = maximum effect, 1 = minimum effect)", value=0, interactive=modules.codeformer_model.have_codeformer)
1051 1052 1053 1054

                submit = gr.Button('Generate', elem_id="extras_generate", variant='primary')

            with gr.Column(variant='panel'):
A
AUTOMATIC 已提交
1055
                result_images = gr.Gallery(label="Result", show_label=False)
1056 1057
                html_info_x = gr.HTML()
                html_info = gr.HTML()
S
Seki 已提交
1058
                extras_send_to_img2img = gr.Button('Send to img2img')
S
Seki 已提交
1059
                extras_send_to_inpaint = gr.Button('Send to inpaint')
M
Michoko 已提交
1060
                button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else ''
M
Michoko 已提交
1061
                open_extras_folder = gr.Button('Open output directory', elem_id=button_id)
1062

D
d8ahazard 已提交
1063

1064
        submit.click(
1065
            fn=wrap_gradio_gpu_call(modules.extras.run_extras),
1066
            _js="get_extras_tab_index",
1067
            inputs=[
J
Justin Maier 已提交
1068
                dummy_component,
1069
                dummy_component,
1070
                extras_image,
A
ArrowM 已提交
1071
                image_batch,
1072 1073 1074
                extras_batch_input_dir,
                extras_batch_output_dir,
                show_extras_results,
1075 1076 1077
                gfpgan_visibility,
                codeformer_visibility,
                codeformer_weight,
A
AUTOMATIC 已提交
1078
                upscaling_resize,
J
Justin Maier 已提交
1079 1080 1081
                upscaling_resize_w,
                upscaling_resize_h,
                upscaling_crop,
A
AUTOMATIC 已提交
1082 1083 1084
                extras_upscaler_1,
                extras_upscaler_2,
                extras_upscaler_2_visibility,
1085 1086
            ],
            outputs=[
A
ArrowM 已提交
1087
                result_images,
1088 1089 1090 1091
                html_info_x,
                html_info,
            ]
        )
J
Justin Maier 已提交
1092

S
Seki 已提交
1093 1094 1095 1096 1097 1098
        extras_send_to_img2img.click(
            fn=lambda x: image_from_url_text(x),
            _js="extract_image_from_gallery_img2img",
            inputs=[result_images],
            outputs=[init_img],
        )
J
Justin Maier 已提交
1099

S
Seki 已提交
1100 1101
        extras_send_to_inpaint.click(
            fn=lambda x: image_from_url_text(x),
1102
            _js="extract_image_from_gallery_inpaint",
S
Seki 已提交
1103 1104 1105
            inputs=[result_images],
            outputs=[init_img_with_mask],
        )
1106

1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121
    with gr.Blocks(analytics_enabled=False) as pnginfo_interface:
        with gr.Row().style(equal_height=False):
            with gr.Column(variant='panel'):
                image = gr.Image(elem_id="pnginfo_image", label="Source", source="upload", interactive=True, type="pil")

            with gr.Column(variant='panel'):
                html = gr.HTML()
                generation_info = gr.Textbox(visible=False)
                html2 = gr.HTML()

                with gr.Row():
                    pnginfo_send_to_txt2img = gr.Button('Send to txt2img')
                    pnginfo_send_to_img2img = gr.Button('Send to img2img')

        image.change(
1122
            fn=wrap_gradio_call(modules.extras.run_pnginfo),
1123 1124 1125
            inputs=[image],
            outputs=[html, generation_info, html2],
        )
Y
yfszzx 已提交
1126 1127 1128 1129 1130 1131
    #images history
    images_history_switch_dict = {
        "fn":modules.generation_parameters_copypaste.connect_paste,
        "t2i":txt2img_paste_fields,
        "i2i":img2img_paste_fields
    }
1132

1133
    images_history = img_his.create_history_tabs(gr, opts, wrap_gradio_call(modules.extras.run_pnginfo), images_history_switch_dict)
1134

1135 1136 1137
    with gr.Blocks() as modelmerger_interface:
        with gr.Row().style(equal_height=False):
            with gr.Column(variant='panel'):
1138
                gr.HTML(value="<p>A merger of the two checkpoints will be generated in your <b>checkpoint</b> directory.</p>")
1139

1140
                with gr.Row():
1141 1142 1143
                    primary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_primary_model_name", label="Primary model (A)")
                    secondary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_secondary_model_name", label="Secondary model (B)")
                    tertiary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_tertiary_model_name", label="Tertiary model (C)")
S
safentisAuth 已提交
1144
                custom_name = gr.Textbox(label="Custom Name (Optional)")
1145 1146
                interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Multiplier (M) - set to 0 to get model A', value=0.3)
                interp_method = gr.Radio(choices=["Weighted sum", "Add difference"], value="Weighted sum", label="Interpolation Method")
M
Milly 已提交
1147
                save_as_half = gr.Checkbox(value=False, label="Save as float16")
1148
                modelmerger_merge = gr.Button(elem_id="modelmerger_merge", label="Merge", variant='primary')
1149

1150
            with gr.Column(variant='panel'):
1151
                submit_result = gr.Textbox(elem_id="modelmerger_result", show_label=False)
1152

1153 1154
    sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings()

A
AUTOMATIC 已提交
1155
    with gr.Blocks() as train_interface:
1156
        with gr.Row().style(equal_height=False):
A
AUTOMATIC 已提交
1157
            gr.HTML(value="<p style='margin-bottom: 0.7em'>See <b><a href=\"https://github.com/AUTOMATIC1111/stable-diffusion-webui/wiki/Textual-Inversion\">wiki</a></b> for detailed explanation.</p>")
1158

A
AUTOMATIC 已提交
1159 1160
        with gr.Row().style(equal_height=False):
            with gr.Tabs(elem_id="train_tabs"):
1161

A
AUTOMATIC 已提交
1162
                with gr.Tab(label="Create embedding"):
1163
                    new_embedding_name = gr.Textbox(label="Name")
1164
                    initialization_text = gr.Textbox(label="Initialization text", value="*")
1165 1166 1167 1168 1169 1170 1171
                    nvpt = gr.Slider(label="Number of vectors per token", minimum=1, maximum=75, step=1, value=1)

                    with gr.Row():
                        with gr.Column(scale=3):
                            gr.HTML(value="")

                        with gr.Column():
A
AUTOMATIC 已提交
1172
                            create_embedding = gr.Button(value="Create embedding", variant='primary')
1173

A
AUTOMATIC 已提交
1174
                with gr.Tab(label="Create hypernetwork"):
A
AUTOMATIC 已提交
1175
                    new_hypernetwork_name = gr.Textbox(label="Name")
1176
                    new_hypernetwork_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "320", "640", "1280"])
A
AUTOMATIC 已提交
1177 1178 1179 1180 1181 1182

                    with gr.Row():
                        with gr.Column(scale=3):
                            gr.HTML(value="")

                        with gr.Column():
A
AUTOMATIC 已提交
1183
                            create_hypernetwork = gr.Button(value="Create hypernetwork", variant='primary')
1184

A
AUTOMATIC 已提交
1185
                with gr.Tab(label="Preprocess images"):
1186 1187
                    process_src = gr.Textbox(label='Source directory')
                    process_dst = gr.Textbox(label='Destination directory')
A
alg-wiki 已提交
1188 1189
                    process_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512)
                    process_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512)
1190 1191

                    with gr.Row():
D
DepFA 已提交
1192 1193
                        process_flip = gr.Checkbox(label='Create flipped copies')
                        process_split = gr.Checkbox(label='Split oversized images into two')
1194 1195
                        process_caption = gr.Checkbox(label='Use BLIP for caption')
                        process_caption_deepbooru = gr.Checkbox(label='Use deepbooru for caption', visible=True if cmd_opts.deepdanbooru else False)
1196 1197 1198 1199 1200 1201 1202 1203

                    with gr.Row():
                        with gr.Column(scale=3):
                            gr.HTML(value="")

                        with gr.Column():
                            run_preprocess = gr.Button(value="Preprocess", variant='primary')

A
AUTOMATIC 已提交
1204
                with gr.Tab(label="Train"):
1205
                    gr.HTML(value="<p style='margin-bottom: 0.7em'>Train an embedding; must specify a directory with a set of 1:1 ratio images</p>")
1206
                    train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys()))
A
AUTOMATIC 已提交
1207
                    train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', choices=[x for x in shared.hypernetworks.keys()])
A
AUTOMATIC 已提交
1208
                    learn_rate = gr.Textbox(label='Learning rate', placeholder="Learning rate", value="0.005")
1209
                    batch_size = gr.Number(label='Batch size', value=1, precision=0)
1210 1211 1212
                    dataset_directory = gr.Textbox(label='Dataset directory', placeholder="Path to directory with input images")
                    log_directory = gr.Textbox(label='Log directory', placeholder="Path to directory where to write outputs", value="textual_inversion")
                    template_file = gr.Textbox(label='Prompt template file', value=os.path.join(script_path, "textual_inversion_templates", "style_filewords.txt"))
A
alg-wiki 已提交
1213 1214
                    training_width = gr.Slider(minimum=64, maximum=2048, step=64, label="Width", value=512)
                    training_height = gr.Slider(minimum=64, maximum=2048, step=64, label="Height", value=512)
1215
                    steps = gr.Number(label='Max steps', value=100000, precision=0)
1216 1217
                    create_image_every = gr.Number(label='Save an image to log directory every N steps, 0 to disable', value=500, precision=0)
                    save_embedding_every = gr.Number(label='Save a copy of embedding to log directory every N steps, 0 to disable', value=500, precision=0)
D
DepFA 已提交
1218
                    save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True)
1219
                    preview_from_txt2img = gr.Checkbox(label='Read parameters (prompt, etc...) from txt2img tab when making previews', value=False)
1220 1221

                    with gr.Row():
A
AUTOMATIC 已提交
1222 1223 1224
                        interrupt_training = gr.Button(value="Interrupt")
                        train_hypernetwork = gr.Button(value="Train Hypernetwork", variant='primary')
                        train_embedding = gr.Button(value="Train Embedding", variant='primary')
1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239

            with gr.Column():
                progressbar = gr.HTML(elem_id="ti_progressbar")
                ti_output = gr.Text(elem_id="ti_output", value="", show_label=False)

                ti_gallery = gr.Gallery(label='Output', show_label=False, elem_id='ti_gallery').style(grid=4)
                ti_preview = gr.Image(elem_id='ti_preview', visible=False)
                ti_progress = gr.HTML(elem_id="ti_progress", value="")
                ti_outcome = gr.HTML(elem_id="ti_error", value="")
                setup_progressbar(progressbar, ti_preview, 'ti', textinfo=ti_progress)

        create_embedding.click(
            fn=modules.textual_inversion.ui.create_embedding,
            inputs=[
                new_embedding_name,
1240
                initialization_text,
1241 1242 1243 1244 1245 1246 1247 1248 1249
                nvpt,
            ],
            outputs=[
                train_embedding_name,
                ti_output,
                ti_outcome,
            ]
        )

A
AUTOMATIC 已提交
1250
        create_hypernetwork.click(
A
AUTOMATIC 已提交
1251
            fn=modules.hypernetworks.ui.create_hypernetwork,
A
AUTOMATIC 已提交
1252 1253
            inputs=[
                new_hypernetwork_name,
1254
                new_hypernetwork_sizes,
A
AUTOMATIC 已提交
1255 1256 1257 1258 1259 1260 1261 1262
            ],
            outputs=[
                train_hypernetwork_name,
                ti_output,
                ti_outcome,
            ]
        )

1263 1264 1265 1266 1267 1268
        run_preprocess.click(
            fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.preprocess, extra_outputs=[gr.update()]),
            _js="start_training_textual_inversion",
            inputs=[
                process_src,
                process_dst,
A
alg-wiki 已提交
1269 1270
                process_width,
                process_height,
1271 1272 1273
                process_flip,
                process_split,
                process_caption,
1274
                process_caption_deepbooru
1275 1276 1277 1278 1279 1280 1281
            ],
            outputs=[
                ti_output,
                ti_outcome,
            ],
        )

1282 1283 1284 1285 1286 1287
        train_embedding.click(
            fn=wrap_gradio_gpu_call(modules.textual_inversion.ui.train_embedding, extra_outputs=[gr.update()]),
            _js="start_training_textual_inversion",
            inputs=[
                train_embedding_name,
                learn_rate,
1288
                batch_size,
1289 1290
                dataset_directory,
                log_directory,
A
alg-wiki 已提交
1291 1292
                training_width,
                training_height,
1293 1294 1295 1296
                steps,
                create_image_every,
                save_embedding_every,
                template_file,
D
DepFA 已提交
1297
                save_image_with_stored_embedding,
1298 1299
                preview_from_txt2img,
                *txt2img_preview_params,
1300 1301 1302 1303 1304 1305 1306
            ],
            outputs=[
                ti_output,
                ti_outcome,
            ]
        )

A
AUTOMATIC 已提交
1307
        train_hypernetwork.click(
A
AUTOMATIC 已提交
1308
            fn=wrap_gradio_gpu_call(modules.hypernetworks.ui.train_hypernetwork, extra_outputs=[gr.update()]),
A
AUTOMATIC 已提交
1309 1310 1311 1312
            _js="start_training_textual_inversion",
            inputs=[
                train_hypernetwork_name,
                learn_rate,
1313
                batch_size,
A
AUTOMATIC 已提交
1314 1315
                dataset_directory,
                log_directory,
1316 1317 1318 1319
                steps,
                create_image_every,
                save_embedding_every,
                template_file,
1320 1321
                preview_from_txt2img,
                *txt2img_preview_params,
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
            ],
            outputs=[
                ti_output,
                ti_outcome,
            ]
        )

        interrupt_training.click(
            fn=lambda: shared.state.interrupt(),
            inputs=[],
            outputs=[],
        )

1335
    def create_setting_component(key, is_quicksettings=False):
1336 1337 1338 1339 1340 1341
        def fun():
            return opts.data[key] if key in opts.data else opts.data_labels[key].default

        info = opts.data_labels[key]
        t = type(info.default)

1342 1343
        args = info.component_args() if callable(info.component_args) else info.component_args

1344
        if info.component is not None:
1345
            comp = info.component
1346
        elif t == str:
1347
            comp = gr.Textbox
1348
        elif t == int:
1349
            comp = gr.Number
1350
        elif t == bool:
1351
            comp = gr.Checkbox
1352 1353 1354
        else:
            raise Exception(f'bad options item type: {str(t)} for key {key}')

1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366
        if info.refresh is not None:
            if is_quicksettings:
                res = comp(label=info.label, value=fun, **(args or {}))
                refresh_button = gr.Button(value=refresh_symbol, elem_id="refresh_"+key)
            else:
                with gr.Row(variant="compact"):
                    res = comp(label=info.label, value=fun, **(args or {}))
                    refresh_button = gr.Button(value=refresh_symbol, elem_id="refresh_" + key)

            def refresh():
                info.refresh()
                refreshed_args = info.component_args() if callable(info.component_args) else info.component_args
A
AUTOMATIC 已提交
1367 1368 1369 1370

                for k, v in refreshed_args.items():
                    setattr(res, k, v)

1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382
                return gr.update(**(refreshed_args or {}))

            refresh_button.click(
                fn=refresh,
                inputs=[],
                outputs=[res],
            )
        else:
            res = comp(label=info.label, value=fun, **(args or {}))


        return res
1383

A
AUTOMATIC 已提交
1384
    components = []
1385
    component_dict = {}
A
AUTOMATIC 已提交
1386

M
Michoko 已提交
1387
    def open_folder(f):
1388 1389 1390 1391 1392 1393 1394 1395 1396
        if not os.path.isdir(f):
            print(f"""
WARNING
An open_folder request was made with an argument that is not a folder.
This could be an error or a malicious attempt to run code on your computer.
Requested path was: {f}
""", file=sys.stderr)
            return

M
Michoko 已提交
1397 1398 1399 1400 1401 1402 1403 1404
        if not shared.cmd_opts.hide_ui_dir_config:
            path = os.path.normpath(f)
            if platform.system() == "Windows":
                os.startfile(path)
            elif platform.system() == "Darwin":
                sp.Popen(["open", path])
            else:
                sp.Popen(["xdg-open", path])
M
Michoko 已提交
1405

1406
    def run_settings(*args):
1407 1408 1409
        changed = 0

        for key, value, comp in zip(opts.data_labels.keys(), args, components):
1410 1411
            if comp != dummy_component and not opts.same_type(value, opts.data_labels[key].default):
                return f"Bad value for setting {key}: {value}; expecting {type(opts.data_labels[key].default).__name__}", opts.dumpjson()
1412

A
AUTOMATIC 已提交
1413
        for key, value, comp in zip(opts.data_labels.keys(), args, components):
1414 1415 1416
            if comp == dummy_component:
                continue

1417 1418 1419 1420
            comp_args = opts.data_labels[key].component_args
            if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False:
                continue

1421
            oldval = opts.data.get(key, None)
1422
            opts.data[key] = value
1423

1424 1425 1426
            if oldval != value:
                if opts.data_labels[key].onchange is not None:
                    opts.data_labels[key].onchange()
1427

1428
                changed += 1
1429 1430 1431

        opts.save(shared.config_filename)

1432
        return f'{changed} settings changed.', opts.dumpjson()
1433

1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
    def run_settings_single(value, key):
        if not opts.same_type(value, opts.data_labels[key].default):
            return gr.update(visible=True), opts.dumpjson()

        oldval = opts.data.get(key, None)
        opts.data[key] = value

        if oldval != value:
            if opts.data_labels[key].onchange is not None:
                opts.data_labels[key].onchange()

        opts.save(shared.config_filename)

        return gr.update(value=value), opts.dumpjson()

A
AUTOMATIC 已提交
1449
    with gr.Blocks(analytics_enabled=False) as settings_interface:
1450
        settings_submit = gr.Button(value="Apply settings", variant='primary')
A
AUTOMATIC 已提交
1451 1452
        result = gr.HTML()

1453 1454
        settings_cols = 3
        items_per_col = int(len(opts.data_labels) * 0.9 / settings_cols)
A
AUTOMATIC 已提交
1455

1456 1457 1458
        quicksettings_names = [x.strip() for x in opts.quicksettings.split(",")]
        quicksettings_names = set(x for x in quicksettings_names if x != 'quicksettings')

1459 1460
        quicksettings_list = []

1461 1462 1463 1464 1465 1466
        cols_displayed = 0
        items_displayed = 0
        previous_section = None
        column = None
        with gr.Row(elem_id="settings").style(equal_height=False):
            for i, (k, item) in enumerate(opts.data_labels.items()):
D
DepFA 已提交
1467

1468 1469 1470 1471
                if previous_section != item.section:
                    if cols_displayed < settings_cols and (items_displayed >= items_per_col or previous_section is None):
                        if column is not None:
                            column.__exit__()
D
DepFA 已提交
1472

1473 1474
                        column = gr.Column(variant='panel')
                        column.__enter__()
A
AUTOMATIC 已提交
1475

1476 1477 1478 1479 1480 1481 1482
                        items_displayed = 0
                        cols_displayed += 1

                    previous_section = item.section

                    gr.HTML(elem_id="settings_header_text_{}".format(item.section[0]), value='<h1 class="gr-button-lg">{}</h1>'.format(item.section[1]))

1483
                if k in quicksettings_names:
1484 1485 1486 1487 1488 1489 1490
                    quicksettings_list.append((i, k, item))
                    components.append(dummy_component)
                else:
                    component = create_setting_component(k)
                    component_dict[k] = component
                    components.append(component)
                    items_displayed += 1
1491

1492 1493 1494 1495 1496
        with gr.Row():
            request_notifications = gr.Button(value='Request browser notifications', elem_id="request_notifications")
            reload_script_bodies = gr.Button(value='Reload custom script bodies (No ui updates, No restart)', variant='secondary')
            restart_gradio = gr.Button(value='Restart Gradio and Refresh components (Custom Scripts, ui.py, js and css only)', variant='primary')

1497 1498 1499 1500
        request_notifications.click(
            fn=lambda: None,
            inputs=[],
            outputs=[],
1501
            _js='function(){}'
1502 1503
        )

D
DepFA 已提交
1504
        def reload_scripts():
D
DepFA 已提交
1505
            modules.scripts.reload_script_body_only()
D
DepFA 已提交
1506 1507 1508 1509 1510 1511 1512

        reload_script_bodies.click(
            fn=reload_scripts,
            inputs=[],
            outputs=[],
            _js='function(){}'
        )
1513 1514

        def request_restart():
1515
            shared.state.interrupt()
D
DepFA 已提交
1516
            settings_interface.gradio_ref.do_restart = True
1517 1518 1519 1520 1521 1522 1523

        restart_gradio.click(
            fn=request_restart,
            inputs=[],
            outputs=[],
            _js='function(){restart_reload()}'
        )
J
Justin Maier 已提交
1524

1525 1526 1527
        if column is not None:
            column.__exit__()

1528
    interfaces = [
A
AUTOMATIC 已提交
1529 1530 1531 1532
        (txt2img_interface, "txt2img", "txt2img"),
        (img2img_interface, "img2img", "img2img"),
        (extras_interface, "Extras", "extras"),
        (pnginfo_interface, "PNG Info", "pnginfo"),
1533
        (images_history, "History", "images_history"),
1534
        (modelmerger_interface, "Checkpoint Merger", "modelmerger"),
A
AUTOMATIC 已提交
1535
        (train_interface, "Train", "ti"),
A
AUTOMATIC 已提交
1536
        (settings_interface, "Settings", "settings"),
1537 1538 1539 1540 1541
    ]

    with open(os.path.join(script_path, "style.css"), "r", encoding="utf8") as file:
        css = file.read()

A
typo  
AUTOMATIC 已提交
1542
    if os.path.exists(os.path.join(script_path, "user.css")):
A
AUTOMATIC 已提交
1543 1544 1545 1546
        with open(os.path.join(script_path, "user.css"), "r", encoding="utf8") as file:
            usercss = file.read()
            css += usercss

1547 1548 1549
    if not cmd_opts.no_progressbar_hiding:
        css += css_hide_progressbar

A
AUTOMATIC 已提交
1550
    with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo:
1551 1552
        with gr.Row(elem_id="quicksettings"):
            for i, k, item in quicksettings_list:
1553
                component = create_setting_component(k, is_quicksettings=True)
1554 1555
                component_dict[k] = component

D
DepFA 已提交
1556
        settings_interface.gradio_ref = demo
J
Justin Maier 已提交
1557

1558
        with gr.Tabs(elem_id="tabs") as tabs:
A
AUTOMATIC 已提交
1559
            for interface, label, ifid in interfaces:
1560
                with gr.TabItem(label, id=ifid, elem_id='tab_' + ifid):
A
AUTOMATIC 已提交
1561
                    interface.render()
J
Justin Maier 已提交
1562

1563 1564
        if os.path.exists(os.path.join(script_path, "notification.mp3")):
            audio_notification = gr.Audio(interactive=False, value=os.path.join(script_path, "notification.mp3"), elem_id="audio_notification", visible=False)
A
AUTOMATIC 已提交
1565

1566
        text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False)
1567
        settings_submit.click(
1568 1569 1570
            fn=run_settings,
            inputs=components,
            outputs=[result, text_settings],
1571
        )
1572 1573 1574 1575 1576 1577 1578 1579 1580 1581

        for i, k, item in quicksettings_list:
            component = component_dict[k]

            component.change(
                fn=lambda value, k=k: run_settings_single(value, key=k),
                inputs=[component],
                outputs=[component, text_settings],
            )

S
safentisAuth 已提交
1582 1583
        def modelmerger(*args):
            try:
1584
                results = modules.extras.run_modelmerger(*args)
S
safentisAuth 已提交
1585 1586 1587
            except Exception as e:
                print("Error loading/saving model file:", file=sys.stderr)
                print(traceback.format_exc(), file=sys.stderr)
1588
                modules.sd_models.list_models()  # to remove the potentially missing models from the list
S
safentisAuth 已提交
1589 1590
                return ["Error loading/saving model file. It doesn't exist or the name contains illegal characters"] + [gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(3)]
            return results
1591

1592
        modelmerger_merge.click(
S
safentisAuth 已提交
1593
            fn=modelmerger,
1594 1595 1596
            inputs=[
                primary_model_name,
                secondary_model_name,
1597
                tertiary_model_name,
1598 1599 1600
                interp_method,
                interp_amount,
                save_as_half,
S
safentisAuth 已提交
1601
                custom_name,
1602 1603 1604 1605 1606
            ],
            outputs=[
                submit_result,
                primary_model_name,
                secondary_model_name,
1607
                tertiary_model_name,
1608 1609 1610
                component_dict['sd_model_checkpoint'],
            ]
        )
1611 1612 1613
        paste_field_names = ['Prompt', 'Negative prompt', 'Steps', 'Face restoration', 'Seed', 'Size-1', 'Size-2']
        txt2img_fields = [field for field,name in txt2img_paste_fields if name in paste_field_names]
        img2img_fields = [field for field,name in img2img_paste_fields if name in paste_field_names]
A
AUTOMATIC 已提交
1614
        send_to_img2img.click(
1615 1616 1617 1618
            fn=lambda img, *args: (image_from_url_text(img),*args),
            _js="(gallery, ...args) => [extract_image_from_gallery_img2img(gallery), ...args]",
            inputs=[txt2img_gallery] + txt2img_fields,
            outputs=[init_img] + img2img_fields,
A
AUTOMATIC 已提交
1619 1620 1621
        )

        send_to_inpaint.click(
1622 1623 1624 1625
            fn=lambda x, *args: (image_from_url_text(x), *args),
            _js="(gallery, ...args) => [extract_image_from_gallery_inpaint(gallery), ...args]",
            inputs=[txt2img_gallery] + txt2img_fields,
            outputs=[init_img_with_mask] + img2img_fields,
A
AUTOMATIC 已提交
1626 1627 1628 1629
        )

        img2img_send_to_img2img.click(
            fn=lambda x: image_from_url_text(x),
1630
            _js="extract_image_from_gallery_img2img",
A
AUTOMATIC 已提交
1631 1632 1633 1634 1635 1636
            inputs=[img2img_gallery],
            outputs=[init_img],
        )

        img2img_send_to_inpaint.click(
            fn=lambda x: image_from_url_text(x),
1637
            _js="extract_image_from_gallery_inpaint",
A
AUTOMATIC 已提交
1638 1639 1640 1641 1642 1643
            inputs=[img2img_gallery],
            outputs=[init_img_with_mask],
        )

        send_to_extras.click(
            fn=lambda x: image_from_url_text(x),
S
Seki 已提交
1644
            _js="extract_image_from_gallery_extras",
A
AUTOMATIC 已提交
1645
            inputs=[txt2img_gallery],
1646
            outputs=[extras_image],
A
AUTOMATIC 已提交
1647 1648
        )

M
Michoko 已提交
1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666
        open_txt2img_folder.click(
            fn=lambda: open_folder(opts.outdir_samples or opts.outdir_txt2img_samples),
            inputs=[],
            outputs=[],
        )

        open_img2img_folder.click(
            fn=lambda: open_folder(opts.outdir_samples or opts.outdir_img2img_samples),
            inputs=[],
            outputs=[],
        )

        open_extras_folder.click(
            fn=lambda: open_folder(opts.outdir_samples or opts.outdir_extras_samples),
            inputs=[],
            outputs=[],
        )

A
AUTOMATIC 已提交
1667 1668
        img2img_send_to_extras.click(
            fn=lambda x: image_from_url_text(x),
S
Seki 已提交
1669
            _js="extract_image_from_gallery_extras",
A
AUTOMATIC 已提交
1670
            inputs=[img2img_gallery],
1671
            outputs=[extras_image],
A
AUTOMATIC 已提交
1672
        )
1673

1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689
        settings_map = {
            'sd_hypernetwork': 'Hypernet',
            'CLIP_stop_at_last_layers': 'Clip skip',
            'sd_model_checkpoint': 'Model hash',
        }

        settings_paste_fields = [
            (component_dict[k], lambda d, k=k, v=v: apply_setting(k, d.get(v, None)))
            for k, v in settings_map.items()
        ]

        modules.generation_parameters_copypaste.connect_paste(txt2img_paste, txt2img_paste_fields + settings_paste_fields, txt2img_prompt)
        modules.generation_parameters_copypaste.connect_paste(img2img_paste, img2img_paste_fields + settings_paste_fields, img2img_prompt)

        modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_txt2img, txt2img_paste_fields + settings_paste_fields, generation_info, 'switch_to_txt2img')
        modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_img2img, img2img_paste_fields + settings_paste_fields, generation_info, 'switch_to_img2img_img2img')
1690

1691
    ui_config_file = cmd_opts.ui_config_file
A
AUTOMATIC 已提交
1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705
    ui_settings = {}
    settings_count = len(ui_settings)
    error_loading = False

    try:
        if os.path.exists(ui_config_file):
            with open(ui_config_file, "r", encoding="utf8") as file:
                ui_settings = json.load(file)
    except Exception:
        error_loading = True
        print("Error loading settings:", file=sys.stderr)
        print(traceback.format_exc(), file=sys.stderr)

    def loadsave(path, x):
1706
        def apply_field(obj, field, condition=None):
A
AUTOMATIC 已提交
1707
            key = path + "/" + field
1708 1709 1710

            if getattr(obj,'custom_script_source',None) is not None:
              key = 'customscript/' + obj.custom_script_source + '/' + key
J
Justin Maier 已提交
1711

A
AUTOMATIC 已提交
1712 1713
            if getattr(obj, 'do_not_save_to_config', False):
                return
J
Justin Maier 已提交
1714

A
AUTOMATIC 已提交
1715 1716 1717
            saved_value = ui_settings.get(key, None)
            if saved_value is None:
                ui_settings[key] = getattr(obj, field)
1718
            elif condition is None or condition(saved_value):
A
AUTOMATIC 已提交
1719 1720
                setattr(obj, field, saved_value)

A
AUTOMATIC 已提交
1721 1722 1723
        if type(x) in [gr.Slider, gr.Radio, gr.Checkbox, gr.Textbox, gr.Number] and x.visible:
            apply_field(x, 'visible')

A
AUTOMATIC 已提交
1724 1725 1726 1727 1728 1729 1730
        if type(x) == gr.Slider:
            apply_field(x, 'value')
            apply_field(x, 'minimum')
            apply_field(x, 'maximum')
            apply_field(x, 'step')

        if type(x) == gr.Radio:
1731
            apply_field(x, 'value', lambda val: val in x.choices)
A
AUTOMATIC 已提交
1732

D
DepFA 已提交
1733
        if type(x) == gr.Checkbox:
D
DepFA 已提交
1734
            apply_field(x, 'value')
D
DepFA 已提交
1735 1736

        if type(x) == gr.Textbox:
D
DepFA 已提交
1737
            apply_field(x, 'value')
J
Justin Maier 已提交
1738

D
DepFA 已提交
1739
        if type(x) == gr.Number:
D
DepFA 已提交
1740
            apply_field(x, 'value')
J
Justin Maier 已提交
1741

A
AUTOMATIC 已提交
1742 1743
    visit(txt2img_interface, loadsave, "txt2img")
    visit(img2img_interface, loadsave, "img2img")
1744
    visit(extras_interface, loadsave, "extras")
A
AUTOMATIC 已提交
1745 1746 1747 1748 1749

    if not error_loading and (not os.path.exists(ui_config_file) or settings_count != len(ui_settings)):
        with open(ui_config_file, "w", encoding="utf8") as file:
            json.dump(ui_settings, file, indent=4)

1750 1751 1752
    return demo


A
AUTOMATIC 已提交
1753
with open(os.path.join(script_path, "script.js"), "r", encoding="utf8") as jsfile:
A
AUTOMATIC 已提交
1754 1755 1756
    javascript = f'<script>{jsfile.read()}</script>'

jsdir = os.path.join(script_path, "javascript")
1757
for filename in sorted(os.listdir(jsdir)):
A
AUTOMATIC 已提交
1758 1759
    with open(os.path.join(jsdir, filename), "r", encoding="utf8") as jsfile:
        javascript += f"\n<script>{jsfile.read()}</script>"
1760 1761


1762
if 'gradio_routes_templates_response' not in globals():
D
DepFA 已提交
1763 1764 1765 1766 1767 1768 1769 1770
    def template_response(*args, **kwargs):
        res = gradio_routes_templates_response(*args, **kwargs)
        res.body = res.body.replace(b'</head>', f'{javascript}</head>'.encode("utf8"))
        res.init_headers()
        return res

    gradio_routes_templates_response = gradio.routes.templates.TemplateResponse
    gradio.routes.templates.TemplateResponse = template_response
Y
yfszzx 已提交
1771