ui.py 70.4 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 10 11
import sys
import time
import traceback
M
Michoko 已提交
12 13
import platform
import subprocess as sp
L
Liam 已提交
14
from functools import reduce
15

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

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

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

A
Aidan Holland 已提交
44
# 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
45 46 47 48
mimetypes.init()
mimetypes.add_type('application/javascript', '.js')


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

J
JamnedZ 已提交
54 55 56 57 58
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)

59 60 61 62 63 64 65 66 67 68

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; }
69
.wrap .m-12::before { content:"Loading..." }
70 71 72 73
.progress-bar { display:none!important; }
.meta-text { display:none!important; }
"""

74 75 76 77
# 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'  # ♻️
78 79
art_symbol = '\U0001f3a8'  # 🎨
paste_symbol = '\u2199\ufe0f'  # ↙
80
folder_symbol = '\U0001f4c2'  # 📂
81 82
refresh_symbol = '\U0001f504'  # 🔄

83

84
def plaintext_to_html(text):
85
    text = "<p>" + "<br>\n".join([f"{html.escape(x)}" for x in text.split('\n')]) + "</p>"
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
    return text


def image_from_url_text(filedata):
    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 已提交
110

A
aoirusann 已提交
111
def save_files(js_data, images, do_make_zip, index):
J
Justin Maier 已提交
112
    import csv
113
    filenames = []
A
aoirusann 已提交
114
    fullfns = []
115

A
Aidan Holland 已提交
116
    #quick dictionary to class object conversion. Its necessary due apply_filename_pattern requiring it
117 118 119 120 121 122
    class MyObject:
        def __init__(self, d=None):
            if d is not None:
                for key, value in d.items():
                    setattr(self, key, value)

123
    data = json.loads(js_data)
124

125 126
    p = MyObject(data)
    path = opts.outdir_save
127
    save_to_dirs = opts.use_save_to_dirs_for_ui
M
Milly 已提交
128 129
    extension: str = opts.samples_format
    start_index = 0
130

131
    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
132

J
jtkelm2 已提交
133
        images = [images[index]]
M
Milly 已提交
134
        start_index = index
135

136 137
    os.makedirs(opts.outdir_save, exist_ok=True)

138
    with open(os.path.join(opts.outdir_save, "log.csv"), "a", encoding="utf8", newline='') as file:
139 140 141
        at_start = file.tell() == 0
        writer = csv.writer(file)
        if at_start:
142
            writer.writerow(["prompt", "seed", "width", "height", "sampler", "cfgs", "steps", "filename", "negative_prompt"])
143

M
Milly 已提交
144
        for image_index, filedata in enumerate(images, start_index):
145 146 147
            if filedata.startswith("data:image/png;base64,"):
                filedata = filedata[len("data:image/png;base64,"):]

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

M
Milly 已提交
150 151 152
            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 已提交
153
            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 已提交
154 155

            filename = os.path.relpath(fullfn, path)
156
            filenames.append(filename)
A
aoirusann 已提交
157
            fullfns.append(fullfn)
A
aoirusann 已提交
158 159 160
            if txt_fullfn:
                filenames.append(os.path.basename(txt_fullfn))
                fullfns.append(txt_fullfn)
161

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

A
aoirusann 已提交
164 165 166 167 168 169 170 171 172 173 174
    # 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)

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


178 179
def wrap_gradio_call(func, extra_outputs=None):
    def f(*args, extra_outputs_array=extra_outputs, **kwargs):
E
EyeDeck 已提交
180 181
        run_memmon = opts.memmon_poll_rate > 0 and not shared.mem_mon.disabled
        if run_memmon:
182
            shared.mem_mon.monitor()
183 184 185 186 187
        t = time.perf_counter()

        try:
            res = list(func(*args, **kwargs))
        except Exception as e:
188 189 190
            # 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

191
            print("Error completing request", file=sys.stderr)
192 193 194 195 196
            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)

197 198
            print(traceback.format_exc(), file=sys.stderr)

A
AUTOMATIC 已提交
199 200 201
            shared.state.job = ""
            shared.state.job_count = 0

202 203 204 205
            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>"]
206 207

        elapsed = time.perf_counter() - t
208 209 210 211 212
        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
213

E
EyeDeck 已提交
214
        if run_memmon:
215 216 217 218 219 220 221
            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 已提交
222
            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>"
223 224
        else:
            vram_html = ''
225

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

229
        shared.state.skipped = False
230
        shared.state.interrupted = False
231
        shared.state.job_count = 0
232 233 234 235 236 237

        return tuple(res)

    return f


238
def check_progress_call(id_part):
A
AUTOMATIC 已提交
239
    if shared.state.job_count == 0:
240
        return "", gr_show(False), gr_show(False), gr_show(False)
A
AUTOMATIC 已提交
241

A
AUTOMATIC 已提交
242 243 244 245
    progress = 0

    if shared.state.job_count > 0:
        progress += shared.state.job_no / shared.state.job_count
A
AUTOMATIC 已提交
246 247 248 249 250
    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 已提交
251 252 253 254 255 256 257 258
    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:
259
        if shared.parallel_processing_allowed:
A
AUTOMATIC 已提交
260

261 262 263
            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 已提交
264

A
AUTOMATIC 已提交
265 266
        image = shared.state.current_image

A
AUTOMATIC 已提交
267
        if image is None:
A
AUTOMATIC 已提交
268 269 270
            image = gr.update(value=None)
        else:
            preview_visibility = gr_show(True)
A
AUTOMATIC 已提交
271

272 273 274 275 276 277
    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 已提交
278 279


280
def check_progress_call_initial(id_part):
281
    shared.state.job_count = -1
282 283
    shared.state.current_latent = None
    shared.state.current_image = None
284
    shared.state.textinfo = None
285

286
    return check_progress_call(id_part)
287 288


A
AUTOMATIC 已提交
289 290 291 292 293 294 295
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 已提交
296 297 298 299 300 301 302
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)

303

304 305
def add_style(name: str, prompt: str, negative_prompt: str):
    if name is None:
A
AUTOMATIC 已提交
306 307
        return [gr_show(), gr_show()]

308
    style = modules.styles.PromptStyle(name, prompt, negative_prompt)
A
AUTOMATIC 已提交
309
    shared.prompt_styles.styles[style.name] = style
310 311
    # 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 已提交
312
    shared.prompt_styles.save_styles(shared.styles_filename)
A
AUTOMATIC 已提交
313

314
    return [gr.Dropdown.update(visible=True, choices=list(shared.prompt_styles.styles)) for _ in range(4)]
A
AUTOMATIC 已提交
315 316 317 318 319 320 321


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 已提交
322 323


A
AUTOMATIC 已提交
324 325 326 327 328
def interrogate(image):
    prompt = shared.interrogator.interrogate(image)

    return gr_show(True) if prompt is None else prompt

A
AUTOMATIC 已提交
329

G
Greendayle 已提交
330 331 332 333 334
def interrogate_deepbooru(image):
    prompt = get_deepbooru_tags(image)
    return gr_show(True) if prompt is None else prompt


335 336 337 338
def create_seed_inputs():
    with gr.Row():
        with gr.Box():
            with gr.Row(elem_id='seed_row'):
339
                seed = (gr.Textbox if cmd_opts.use_textbox_seed else gr.Number)(label='Seed', value=-1)
340
                seed.style(container=False)
341 342
                random_seed = gr.Button(random_symbol, elem_id='random_seed')
                reuse_seed = gr.Button(reuse_symbol, elem_id='reuse_seed')
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372

        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)

373
    return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox
374 375


376 377 378
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
379
        was 0, i.e. no variation seed was used, it copies the normal seed value instead."""
380 381 382
    def copy_seed(gen_info_string: str, index):
        res = -1

383 384
        try:
            gen_info = json.loads(gen_info_string)
385 386 387 388 389
            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]
390
            else:
391 392 393
                all_seeds = gen_info.get('all_seeds', [-1])
                res = all_seeds[index if 0 <= index < len(all_seeds) else 0]

394 395 396 397
        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)
398 399

        return [res, gr_show(False)]
400 401 402

    reuse_seed.click(
        fn=copy_seed,
403
        _js="(x, y) => [x, selected_gallery_index()]",
404
        show_progress=False,
405 406
        inputs=[generation_info, dummy_component],
        outputs=[seed, dummy_component]
407 408
    )

409

L
Liam 已提交
410
def update_token_counter(text, steps):
411
    try:
A
AUTOMATIC 已提交
412 413 414
        _, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
        prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)

415 416 417 418 419
    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 已提交
420
    flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules)
421
    prompts = [prompt_text for step, prompt_text in flat_prompts]
L
Liam 已提交
422
    tokens, token_count, max_length = max([model_hijack.tokenize(prompt) for prompt in prompts], key=lambda args: args[1])
423 424
    style_class = ' class="red"' if (token_count > max_length) else ""
    return f"<span {style_class}>{token_count}/{max_length}</span>"
A
AUTOMATIC 已提交
425

426

A
AUTOMATIC 已提交
427
def create_toprow(is_img2img):
428 429
    id_part = "img2img" if is_img2img else "txt2img"

A
AUTOMATIC 已提交
430 431 432
    with gr.Row(elem_id="toprow"):
        with gr.Column(scale=4):
            with gr.Row():
433
                with gr.Column(scale=80):
A
AUTOMATIC 已提交
434
                    with gr.Row():
435
                        prompt = gr.Textbox(label="Prompt", elem_id=f"{id_part}_prompt", show_label=False, placeholder="Prompt", lines=2)
A
AUTOMATIC 已提交
436

437 438 439
                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")
440
                    token_counter = gr.HTML(value="<span></span>", elem_id=f"{id_part}_token_counter")
L
Liam 已提交
441
                    token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")
442 443 444

                with gr.Column(scale=10, 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())), visible=len(shared.prompt_styles.styles) > 1)
A
AUTOMATIC 已提交
445 446 447

            with gr.Row():
                with gr.Column(scale=8):
B
Ben 已提交
448 449 450 451
                    with gr.Row():
                        negative_prompt = gr.Textbox(label="Negative prompt", elem_id="negative_prompt", show_label=False, placeholder="Negative prompt", lines=2)
                with gr.Column(scale=1, elem_id="roll_col"):
                    sh = gr.Button(elem_id="sh", visible=True)                           
A
AUTOMATIC 已提交
452 453

                with gr.Column(scale=1, elem_id="style_neg_col"):
454
                    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())), visible=len(shared.prompt_styles.styles) > 1)
A
AUTOMATIC 已提交
455 456 457

        with gr.Column(scale=1):
            with gr.Row():
458
                skip = gr.Button('Skip', elem_id=f"{id_part}_skip")
459
                interrupt = gr.Button('Interrupt', elem_id=f"{id_part}_interrupt")
460
                submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary')
461

462 463 464 465 466 467
                skip.click(
                    fn=lambda: shared.state.skip(),
                    inputs=[],
                    outputs=[],
                )

468 469 470 471 472
                interrupt.click(
                    fn=lambda: shared.state.interrupt(),
                    inputs=[],
                    outputs=[],
                )
A
AUTOMATIC 已提交
473

G
Greendayle 已提交
474
            with gr.Row(scale=1):
A
AUTOMATIC 已提交
475
                if is_img2img:
G
Greendayle 已提交
476
                    interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate")
477 478 479 480
                    if cmd_opts.deepdanbooru:
                        deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru")
                    else:
                        deepbooru = None
A
AUTOMATIC 已提交
481 482
                else:
                    interrogate = None
G
Greendayle 已提交
483
                    deepbooru = None
A
AUTOMATIC 已提交
484 485 486
                prompt_style_apply = gr.Button('Apply style', elem_id="style_apply")
                save_style = gr.Button('Create style', elem_id="style_create")

G
Greendayle 已提交
487
    return prompt, roll, prompt_style, negative_prompt, prompt_style2, submit, interrogate, deepbooru, prompt_style_apply, save_style, paste, token_counter, token_button
A
AUTOMATIC 已提交
488 489


490 491 492
def setup_progressbar(progressbar, preview, id_part, textinfo=None):
    if textinfo is None:
        textinfo = gr.HTML(visible=False)
493

494
    check_progress = gr.Button('Check progress', elem_id=f"{id_part}_check_progress", visible=False)
495
    check_progress.click(
496
        fn=lambda: check_progress_call(id_part),
497 498
        show_progress=False,
        inputs=[],
499
        outputs=[progressbar, preview, preview, textinfo],
500 501
    )

502
    check_progress_initial = gr.Button('Check progress (first)', elem_id=f"{id_part}_check_progress_initial", visible=False)
503
    check_progress_initial.click(
504
        fn=lambda: check_progress_call_initial(id_part),
505 506
        show_progress=False,
        inputs=[],
507
        outputs=[progressbar, preview, preview, textinfo],
508
    )
A
AUTOMATIC 已提交
509 510


511 512 513 514
def create_ui(wrap_gradio_gpu_call):
    import modules.img2img
    import modules.txt2img

515
    with gr.Blocks(analytics_enabled=False) as txt2img_interface:
G
Greendayle 已提交
516
        txt2img_prompt, roll, txt2img_prompt_style, txt2img_negative_prompt, txt2img_prompt_style2, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=False)
517
        dummy_component = gr.Label(visible=False)
518

519 520 521
        with gr.Row(elem_id='txt2img_progress_row'):
            with gr.Column(scale=1):
                pass
522

523 524
            with gr.Column(scale=1):
                progressbar = gr.HTML(elem_id="txt2img_progressbar")
525
                txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False)
526
                setup_progressbar(progressbar, txt2img_preview, 'txt2img')
527

528 529 530 531 532
        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")

533 534 535 536
                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)

537
                with gr.Row():
A
AUTOMATIC 已提交
538
                    restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1)
539
                    tiling = gr.Checkbox(label='Tiling', value=False)
A
AUTOMATIC 已提交
540 541 542
                    enable_hr = gr.Checkbox(label='Highres. fix', value=False)

                with gr.Row(visible=False) as hr_options:
543
                    scale_latent = gr.Checkbox(label='Scale latent', value=False)
A
AUTOMATIC 已提交
544
                    denoising_strength = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, label='Denoising strength', value=0.7)
545 546

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

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

552
                seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs()
553

A
AUTOMATIC 已提交
554
                with gr.Group():
A
AUTOMATIC 已提交
555
                    custom_inputs = modules.scripts.scripts_txt2img.setup_ui(is_img2img=False)
556 557

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

559
                with gr.Group():
A
AUTOMATIC 已提交
560
                    txt2img_preview = gr.Image(elem_id='txt2img_preview', visible=False)
A
AUTOMATIC 已提交
561
                    txt2img_gallery = gr.Gallery(label='Output', show_label=False, elem_id='txt2img_gallery').style(grid=4)
562 563 564 565 566 567 568

                with gr.Group():
                    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 已提交
569
                        button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else 'open_folder'
M
Michoko 已提交
570
                        open_txt2img_folder = gr.Button(folder_symbol, elem_id=button_id)
571

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

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

B
Ben 已提交
578 579 580
                    with gr.Group():
                        html_info = gr.HTML()
                        generation_info = gr.Textbox(visible=False)
581

582 583
            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)
584

585
            txt2img_args = dict(
586
                fn=wrap_gradio_gpu_call(modules.txt2img.txt2img),
A
AUTOMATIC 已提交
587
                _js="submit",
588
                inputs=[
A
AUTOMATIC 已提交
589
                    txt2img_prompt,
590
                    txt2img_negative_prompt,
A
AUTOMATIC 已提交
591
                    txt2img_prompt_style,
A
AUTOMATIC 已提交
592
                    txt2img_prompt_style2,
593 594
                    steps,
                    sampler_index,
A
AUTOMATIC 已提交
595
                    restore_faces,
596
                    tiling,
597 598 599 600
                    batch_count,
                    batch_size,
                    cfg_scale,
                    seed,
601
                    subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
602 603
                    height,
                    width,
A
AUTOMATIC 已提交
604 605 606
                    enable_hr,
                    scale_latent,
                    denoising_strength,
A
AUTOMATIC 已提交
607
                ] + custom_inputs,
608 609 610 611
                outputs=[
                    txt2img_gallery,
                    generation_info,
                    html_info
612 613
                ],
                show_progress=False,
614 615
            )

A
AUTOMATIC 已提交
616
            txt2img_prompt.submit(**txt2img_args)
617 618
            submit.click(**txt2img_args)

A
AUTOMATIC 已提交
619 620 621 622 623 624
            enable_hr.change(
                fn=lambda x: gr_show(x),
                inputs=[enable_hr],
                outputs=[hr_options],
            )

625 626
            save.click(
                fn=wrap_gradio_call(save_files),
A
aoirusann 已提交
627
                _js="(x, y, z, w) => [x, y, z, selected_gallery_index()]",
628 629 630
                inputs=[
                    generation_info,
                    txt2img_gallery,
A
aoirusann 已提交
631
                    do_make_zip,
632
                    html_info,
633 634
                ],
                outputs=[
A
aoirusann 已提交
635
                    download_files,
636 637 638 639 640 641
                    html_info,
                    html_info,
                    html_info,
                ]
            )

A
AUTOMATIC 已提交
642 643
            roll.click(
                fn=roll_artist,
L
Liam 已提交
644
                _js="update_txt2img_tokens",
A
AUTOMATIC 已提交
645
                inputs=[
A
AUTOMATIC 已提交
646
                    txt2img_prompt,
A
AUTOMATIC 已提交
647 648
                ],
                outputs=[
A
AUTOMATIC 已提交
649
                    txt2img_prompt,
A
AUTOMATIC 已提交
650 651 652
                ]
            )

653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671
            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)),
            ]
672
            modules.generation_parameters_copypaste.connect_paste(paste, txt2img_paste_fields, txt2img_prompt)
L
Liam 已提交
673
            token_button.click(fn=update_token_counter, inputs=[txt2img_prompt, steps], outputs=[token_counter])
674

675
    with gr.Blocks(analytics_enabled=False) as img2img_interface:
G
Greendayle 已提交
676
        img2img_prompt, roll, img2img_prompt_style, img2img_negative_prompt, img2img_prompt_style2, submit, img2img_interrogate, img2img_deepbooru, img2img_prompt_style_apply, img2img_save_style, paste, token_counter, token_button = create_toprow(is_img2img=True)
677

678 679 680
        with gr.Row(elem_id='img2img_progress_row'):
            with gr.Column(scale=1):
                pass
681

682 683
            with gr.Column(scale=1):
                progressbar = gr.HTML(elem_id="img2img_progressbar")
684
                img2img_preview = gr.Image(elem_id='img2img_preview', visible=False)
685
                setup_progressbar(progressbar, img2img_preview, 'img2img')
686

687 688
        with gr.Row().style(equal_height=False):
            with gr.Column(variant='panel'):
689

690
                with gr.Tabs(elem_id="mode_img2img") as tabs_img2img_mode:
691
                    with gr.TabItem('img2img', id='img2img'):
A
AUTOMATIC 已提交
692
                        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)
693

694
                    with gr.TabItem('Inpaint', id='inpaint'):
695 696
                        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")

697 698
                        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")
699 700 701 702

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

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

706
                        inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'latent noise', 'latent nothing'], value='original', type="index")
707 708 709 710 711

                        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)

712
                    with gr.TabItem('Batch img2img', id='batch'):
713
                        hidden = '<br>Disabled when launched with --hide-ui-dir-config.' if shared.cmd_opts.hide_ui_dir_config else ''
714
                        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>")
715 716
                        img2img_batch_input_dir = gr.Textbox(label="Input directory", **shared.hide_dirs)
                        img2img_batch_output_dir = gr.Textbox(label="Output directory", **shared.hide_dirs)
717 718

                with gr.Row():
719 720 721 722
                    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 已提交
723

724 725 726 727
                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 已提交
728
                with gr.Row():
A
AUTOMATIC 已提交
729
                    restore_faces = gr.Checkbox(label='Restore faces', value=False, visible=len(shared.face_restorers) > 1)
730
                    tiling = gr.Checkbox(label='Tiling', value=False)
731 732

                with gr.Row():
R
RW21 已提交
733
                    batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1)
734 735 736
                    batch_size = gr.Slider(minimum=1, maximum=8, step=1, label='Batch size', value=1)

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

740
                seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox = create_seed_inputs()
741

A
AUTOMATIC 已提交
742
                with gr.Group():
A
AUTOMATIC 已提交
743
                    custom_inputs = modules.scripts.scripts_img2img.setup_ui(is_img2img=True)
A
AUTOMATIC 已提交
744

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

747
                with gr.Group():
A
AUTOMATIC 已提交
748
                    img2img_preview = gr.Image(elem_id='img2img_preview', visible=False)
A
AUTOMATIC 已提交
749
                    img2img_gallery = gr.Gallery(label='Output', show_label=False, elem_id='img2img_gallery').style(grid=4)
750 751 752 753

                with gr.Group():
                    with gr.Row():
                        save = gr.Button('Save')
A
AUTOMATIC 已提交
754 755
                        img2img_send_to_img2img = gr.Button('Send to img2img')
                        img2img_send_to_inpaint = gr.Button('Send to inpaint')
756
                        img2img_send_to_extras = gr.Button('Send to extras')
M
Michoko 已提交
757
                        button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else 'open_folder'
M
Michoko 已提交
758
                        open_img2img_folder = gr.Button(folder_symbol, elem_id=button_id)
759

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

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

B
Ben 已提交
766 767 768
                    with gr.Group():
                        html_info = gr.HTML()
                        generation_info = gr.Textbox(visible=False)
769

770 771
            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)
772

773
            mask_mode.change(
774
                lambda mode, img: {
775
                    init_img_with_mask: gr_show(mode == 0),
776 777
                    init_img_inpaint: gr_show(mode == 1),
                    init_mask_inpaint: gr_show(mode == 1),
778
                },
779
                inputs=[mask_mode, init_img_with_mask],
780 781
                outputs=[
                    init_img_with_mask,
782 783
                    init_img_inpaint,
                    init_mask_inpaint,
784 785 786
                ],
            )

787
            img2img_args = dict(
788
                fn=wrap_gradio_gpu_call(modules.img2img.img2img),
789
                _js="submit_img2img",
790
                inputs=[
791
                    dummy_component,
A
AUTOMATIC 已提交
792
                    img2img_prompt,
793
                    img2img_negative_prompt,
A
AUTOMATIC 已提交
794
                    img2img_prompt_style,
A
AUTOMATIC 已提交
795
                    img2img_prompt_style2,
796 797
                    init_img,
                    init_img_with_mask,
798 799
                    init_img_inpaint,
                    init_mask_inpaint,
800
                    mask_mode,
801 802 803 804
                    steps,
                    sampler_index,
                    mask_blur,
                    inpainting_fill,
A
AUTOMATIC 已提交
805
                    restore_faces,
806
                    tiling,
807 808 809 810 811
                    batch_count,
                    batch_size,
                    cfg_scale,
                    denoising_strength,
                    seed,
812
                    subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w, seed_checkbox,
813 814 815 816
                    height,
                    width,
                    resize_mode,
                    inpaint_full_res,
817
                    inpaint_full_res_padding,
A
AUTOMATIC 已提交
818
                    inpainting_mask_invert,
819 820
                    img2img_batch_input_dir,
                    img2img_batch_output_dir,
A
AUTOMATIC 已提交
821
                ] + custom_inputs,
822 823 824 825
                outputs=[
                    img2img_gallery,
                    generation_info,
                    html_info
826 827
                ],
                show_progress=False,
828 829
            )

A
AUTOMATIC 已提交
830
            img2img_prompt.submit(**img2img_args)
831 832
            submit.click(**img2img_args)

A
AUTOMATIC 已提交
833 834 835 836 837 838
            img2img_interrogate.click(
                fn=interrogate,
                inputs=[init_img],
                outputs=[img2img_prompt],
            )

839 840 841 842 843 844
            if cmd_opts.deepdanbooru:
                img2img_deepbooru.click(
                    fn=interrogate_deepbooru,
                    inputs=[init_img],
                    outputs=[img2img_prompt],
                )
G
Greendayle 已提交
845

846 847
            save.click(
                fn=wrap_gradio_call(save_files),
A
aoirusann 已提交
848
                _js="(x, y, z, w) => [x, y, z, selected_gallery_index()]",
849 850 851
                inputs=[
                    generation_info,
                    img2img_gallery,
A
aoirusann 已提交
852 853
                    do_make_zip,
                    html_info,
854 855
                ],
                outputs=[
A
aoirusann 已提交
856
                    download_files,
857 858 859 860 861 862
                    html_info,
                    html_info,
                    html_info,
                ]
            )

A
AUTOMATIC 已提交
863 864
            roll.click(
                fn=roll_artist,
L
Liam 已提交
865
                _js="update_img2img_tokens",
A
AUTOMATIC 已提交
866 867 868 869 870 871 872 873 874 875
                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 已提交
876
            style_js_funcs = ["update_txt2img_tokens", "update_img2img_tokens"]
A
AUTOMATIC 已提交
877 878

            for button, (prompt, negative_prompt) in zip([txt2img_save_style, img2img_save_style], prompts):
A
AUTOMATIC 已提交
879 880 881
                button.click(
                    fn=add_style,
                    _js="ask_for_style_name",
882 883 884
                    # 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 已提交
885 886 887
                    outputs=[txt2img_prompt_style, img2img_prompt_style, txt2img_prompt_style2, img2img_prompt_style2],
                )

888
            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 已提交
889 890
                button.click(
                    fn=apply_styles,
891
                    _js=js_func,
A
AUTOMATIC 已提交
892 893
                    inputs=[prompt, negative_prompt, style1, style2],
                    outputs=[prompt, negative_prompt, style1, style2],
A
AUTOMATIC 已提交
894 895
                )

896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912
            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"),
            ]
913
            modules.generation_parameters_copypaste.connect_paste(paste, img2img_paste_fields, img2img_prompt)
L
Liam 已提交
914
            token_button.click(fn=update_token_counter, inputs=[img2img_prompt, steps], outputs=[token_counter])
915

916 917 918
    with gr.Blocks(analytics_enabled=False) as extras_interface:
        with gr.Row().style(equal_height=False):
            with gr.Column(variant='panel'):
919
                with gr.Tabs(elem_id="mode_extras"):
A
ArrowM 已提交
920
                    with gr.TabItem('Single Image'):
921
                        extras_image = gr.Image(label="Source", source="upload", interactive=True, type="pil")
A
ArrowM 已提交
922 923

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

J
Justin Maier 已提交
926 927 928 929 930 931
                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 已提交
932 933
                                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 已提交
934
                            upscaling_crop = gr.Checkbox(label='Crop to fit', value=True)
A
AUTOMATIC 已提交
935 936 937 938 939 940 941 942 943

                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():
944 945 946 947
                    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)
948
                    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)
949 950 951 952

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

            with gr.Column(variant='panel'):
A
AUTOMATIC 已提交
953
                result_images = gr.Gallery(label="Result", show_label=False)
954 955
                html_info_x = gr.HTML()
                html_info = gr.HTML()
S
Seki 已提交
956
                extras_send_to_img2img = gr.Button('Send to img2img')
S
Seki 已提交
957
                extras_send_to_inpaint = gr.Button('Send to inpaint')
M
Michoko 已提交
958
                button_id = "hidden_element" if shared.cmd_opts.hide_ui_dir_config else ''
M
Michoko 已提交
959
                open_extras_folder = gr.Button('Open output directory', elem_id=button_id)
960

961
        submit.click(
962
            fn=wrap_gradio_gpu_call(modules.extras.run_extras),
963
            _js="get_extras_tab_index",
964
            inputs=[
J
Justin Maier 已提交
965
                dummy_component,
966
                dummy_component,
967
                extras_image,
A
ArrowM 已提交
968
                image_batch,
969 970 971
                gfpgan_visibility,
                codeformer_visibility,
                codeformer_weight,
A
AUTOMATIC 已提交
972
                upscaling_resize,
J
Justin Maier 已提交
973 974 975
                upscaling_resize_w,
                upscaling_resize_h,
                upscaling_crop,
A
AUTOMATIC 已提交
976 977 978
                extras_upscaler_1,
                extras_upscaler_2,
                extras_upscaler_2_visibility,
979 980
            ],
            outputs=[
A
ArrowM 已提交
981
                result_images,
982 983 984 985
                html_info_x,
                html_info,
            ]
        )
J
Justin Maier 已提交
986

S
Seki 已提交
987 988 989 990 991 992
        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 已提交
993

S
Seki 已提交
994 995
        extras_send_to_inpaint.click(
            fn=lambda x: image_from_url_text(x),
996
            _js="extract_image_from_gallery_inpaint",
S
Seki 已提交
997 998 999
            inputs=[result_images],
            outputs=[init_img_with_mask],
        )
1000

1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
    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(
1016
            fn=wrap_gradio_call(modules.extras.run_pnginfo),
1017 1018 1019
            inputs=[image],
            outputs=[html, generation_info, html2],
        )
1020

1021 1022 1023
    with gr.Blocks() as modelmerger_interface:
        with gr.Row().style(equal_height=False):
            with gr.Column(variant='panel'):
1024
                gr.HTML(value="<p>A merger of the two checkpoints will be generated in your <b>checkpoint</b> directory.</p>")
1025

1026
                with gr.Row():
1027 1028
                    primary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_primary_model_name", label="Primary Model Name")
                    secondary_model_name = gr.Dropdown(modules.sd_models.checkpoint_tiles(), elem_id="modelmerger_secondary_model_name", label="Secondary Model Name")
S
safentisAuth 已提交
1029
                custom_name = gr.Textbox(label="Custom Name (Optional)")
1030
                interp_amount = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Interpolation Amount', value=0.3)
1031
                interp_method = gr.Radio(choices=["Weighted Sum", "Sigmoid", "Inverse Sigmoid"], value="Weighted Sum", label="Interpolation Method")
M
Milly 已提交
1032
                save_as_half = gr.Checkbox(value=False, label="Save as float16")
1033
                modelmerger_merge = gr.Button(elem_id="modelmerger_merge", label="Merge", variant='primary')
1034

1035
            with gr.Column(variant='panel'):
1036
                submit_result = gr.Textbox(elem_id="modelmerger_result", show_label=False)
1037

1038 1039
    sd_hijack.model_hijack.embedding_db.load_textual_inversion_embeddings()

A
AUTOMATIC 已提交
1040
    with gr.Blocks() as train_interface:
1041
        with gr.Row().style(equal_height=False):
A
AUTOMATIC 已提交
1042
            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>")
1043

A
AUTOMATIC 已提交
1044 1045
        with gr.Row().style(equal_height=False):
            with gr.Tabs(elem_id="train_tabs"):
1046

A
AUTOMATIC 已提交
1047
                with gr.Tab(label="Create embedding"):
1048
                    new_embedding_name = gr.Textbox(label="Name")
1049
                    initialization_text = gr.Textbox(label="Initialization text", value="*")
1050 1051 1052 1053 1054 1055 1056
                    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 已提交
1057
                            create_embedding = gr.Button(value="Create embedding", variant='primary')
1058

A
AUTOMATIC 已提交
1059
                with gr.Tab(label="Create hypernetwork"):
A
AUTOMATIC 已提交
1060
                    new_hypernetwork_name = gr.Textbox(label="Name")
1061
                    new_hypernetwork_sizes = gr.CheckboxGroup(label="Modules", value=["768", "320", "640", "1280"], choices=["768", "320", "640", "1280"])
A
AUTOMATIC 已提交
1062 1063 1064 1065 1066 1067

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

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

A
AUTOMATIC 已提交
1070
                with gr.Tab(label="Preprocess images"):
1071 1072
                    process_src = gr.Textbox(label='Source directory')
                    process_dst = gr.Textbox(label='Destination directory')
A
alg-wiki 已提交
1073 1074
                    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)
1075 1076

                    with gr.Row():
D
DepFA 已提交
1077 1078
                        process_flip = gr.Checkbox(label='Create flipped copies')
                        process_split = gr.Checkbox(label='Split oversized images into two')
1079 1080
                        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)
1081 1082 1083 1084 1085 1086 1087 1088

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

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

A
AUTOMATIC 已提交
1089
                with gr.Tab(label="Train"):
1090
                    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>")
1091
                    train_embedding_name = gr.Dropdown(label='Embedding', choices=sorted(sd_hijack.model_hijack.embedding_db.word_embeddings.keys()))
A
AUTOMATIC 已提交
1092
                    train_hypernetwork_name = gr.Dropdown(label='Hypernetwork', choices=[x for x in shared.hypernetworks.keys()])
A
AUTOMATIC 已提交
1093
                    learn_rate = gr.Textbox(label='Learning rate', placeholder="Learning rate", value="0.005")
1094 1095 1096
                    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 已提交
1097 1098
                    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)
1099
                    steps = gr.Number(label='Max steps', value=100000, precision=0)
1100 1101
                    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 已提交
1102
                    save_image_with_stored_embedding = gr.Checkbox(label='Save images with embedding in PNG chunks', value=True)
A
AUTOMATIC 已提交
1103
                    preview_image_prompt = gr.Textbox(label='Preview prompt', value="")
1104 1105

                    with gr.Row():
A
AUTOMATIC 已提交
1106 1107 1108
                        interrupt_training = gr.Button(value="Interrupt")
                        train_hypernetwork = gr.Button(value="Train Hypernetwork", variant='primary')
                        train_embedding = gr.Button(value="Train Embedding", variant='primary')
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123

            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,
1124
                initialization_text,
1125 1126 1127 1128 1129 1130 1131 1132 1133
                nvpt,
            ],
            outputs=[
                train_embedding_name,
                ti_output,
                ti_outcome,
            ]
        )

A
AUTOMATIC 已提交
1134
        create_hypernetwork.click(
A
AUTOMATIC 已提交
1135
            fn=modules.hypernetworks.ui.create_hypernetwork,
A
AUTOMATIC 已提交
1136 1137
            inputs=[
                new_hypernetwork_name,
1138
                new_hypernetwork_sizes,
A
AUTOMATIC 已提交
1139 1140 1141 1142 1143 1144 1145 1146
            ],
            outputs=[
                train_hypernetwork_name,
                ti_output,
                ti_outcome,
            ]
        )

1147 1148 1149 1150 1151 1152
        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 已提交
1153 1154
                process_width,
                process_height,
1155 1156 1157
                process_flip,
                process_split,
                process_caption,
1158
                process_caption_deepbooru
1159 1160 1161 1162 1163 1164 1165
            ],
            outputs=[
                ti_output,
                ti_outcome,
            ],
        )

1166 1167 1168 1169 1170 1171 1172 1173
        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,
                dataset_directory,
                log_directory,
A
alg-wiki 已提交
1174 1175
                training_width,
                training_height,
1176 1177 1178 1179
                steps,
                create_image_every,
                save_embedding_every,
                template_file,
D
DepFA 已提交
1180
                save_image_with_stored_embedding,
A
AUTOMATIC 已提交
1181
                preview_image_prompt,
1182 1183 1184 1185 1186 1187 1188
            ],
            outputs=[
                ti_output,
                ti_outcome,
            ]
        )

A
AUTOMATIC 已提交
1189
        train_hypernetwork.click(
A
AUTOMATIC 已提交
1190
            fn=wrap_gradio_gpu_call(modules.hypernetworks.ui.train_hypernetwork, extra_outputs=[gr.update()]),
A
AUTOMATIC 已提交
1191 1192 1193 1194 1195 1196
            _js="start_training_textual_inversion",
            inputs=[
                train_hypernetwork_name,
                learn_rate,
                dataset_directory,
                log_directory,
1197 1198 1199 1200
                steps,
                create_image_every,
                save_embedding_every,
                template_file,
A
AUTOMATIC 已提交
1201
                preview_image_prompt,
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
            ],
            outputs=[
                ti_output,
                ti_outcome,
            ]
        )

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

1215
    def create_setting_component(key, is_quicksettings=False):
1216 1217 1218 1219 1220 1221
        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)

1222 1223
        args = info.component_args() if callable(info.component_args) else info.component_args

1224
        if info.component is not None:
1225
            comp = info.component
1226
        elif t == str:
1227
            comp = gr.Textbox
1228
        elif t == int:
1229
            comp = gr.Number
1230
        elif t == bool:
1231
            comp = gr.Checkbox
1232 1233 1234
        else:
            raise Exception(f'bad options item type: {str(t)} for key {key}')

1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
        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 已提交
1247 1248 1249 1250

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

1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
                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
1263

A
AUTOMATIC 已提交
1264
    components = []
1265
    component_dict = {}
A
AUTOMATIC 已提交
1266

M
Michoko 已提交
1267
    def open_folder(f):
1268 1269 1270 1271 1272 1273 1274 1275 1276
        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 已提交
1277 1278 1279 1280 1281 1282 1283 1284
        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 已提交
1285

1286
    def run_settings(*args):
1287 1288 1289
        changed = 0

        for key, value, comp in zip(opts.data_labels.keys(), args, components):
1290 1291
            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()
1292

A
AUTOMATIC 已提交
1293
        for key, value, comp in zip(opts.data_labels.keys(), args, components):
1294 1295 1296
            if comp == dummy_component:
                continue

1297 1298 1299 1300
            comp_args = opts.data_labels[key].component_args
            if comp_args and isinstance(comp_args, dict) and comp_args.get('visible') is False:
                continue

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

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

1308
                changed += 1
1309 1310 1311

        opts.save(shared.config_filename)

1312
        return f'{changed} settings changed.', opts.dumpjson()
1313

1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
    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 已提交
1329
    with gr.Blocks(analytics_enabled=False) as settings_interface:
1330
        settings_submit = gr.Button(value="Apply settings", variant='primary')
A
AUTOMATIC 已提交
1331 1332
        result = gr.HTML()

1333 1334
        settings_cols = 3
        items_per_col = int(len(opts.data_labels) * 0.9 / settings_cols)
A
AUTOMATIC 已提交
1335

1336 1337 1338
        quicksettings_names = [x.strip() for x in opts.quicksettings.split(",")]
        quicksettings_names = set(x for x in quicksettings_names if x != 'quicksettings')

1339 1340
        quicksettings_list = []

1341 1342 1343 1344 1345 1346
        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 已提交
1347

1348 1349 1350 1351
                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 已提交
1352

1353 1354
                        column = gr.Column(variant='panel')
                        column.__enter__()
A
AUTOMATIC 已提交
1355

1356 1357 1358 1359 1360 1361 1362
                        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]))

1363
                if k in quicksettings_names:
1364 1365 1366 1367 1368 1369 1370
                    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
1371

1372 1373 1374 1375 1376
        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')

1377 1378 1379 1380
        request_notifications.click(
            fn=lambda: None,
            inputs=[],
            outputs=[],
1381
            _js='function(){}'
1382 1383
        )

D
DepFA 已提交
1384
        def reload_scripts():
D
DepFA 已提交
1385
            modules.scripts.reload_script_body_only()
D
DepFA 已提交
1386 1387 1388 1389 1390 1391 1392

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

        def request_restart():
1395
            shared.state.interrupt()
D
DepFA 已提交
1396
            settings_interface.gradio_ref.do_restart = True
1397 1398 1399 1400 1401 1402 1403

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

1405 1406 1407
        if column is not None:
            column.__exit__()

1408
    interfaces = [
A
AUTOMATIC 已提交
1409 1410 1411 1412
        (txt2img_interface, "txt2img", "txt2img"),
        (img2img_interface, "img2img", "img2img"),
        (extras_interface, "Extras", "extras"),
        (pnginfo_interface, "PNG Info", "pnginfo"),
1413
        (modelmerger_interface, "Checkpoint Merger", "modelmerger"),
A
AUTOMATIC 已提交
1414
        (train_interface, "Train", "ti"),
A
AUTOMATIC 已提交
1415
        (settings_interface, "Settings", "settings"),
1416 1417 1418 1419 1420
    ]

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

A
typo  
AUTOMATIC 已提交
1421
    if os.path.exists(os.path.join(script_path, "user.css")):
A
AUTOMATIC 已提交
1422 1423 1424 1425
        with open(os.path.join(script_path, "user.css"), "r", encoding="utf8") as file:
            usercss = file.read()
            css += usercss

1426 1427 1428
    if not cmd_opts.no_progressbar_hiding:
        css += css_hide_progressbar

A
AUTOMATIC 已提交
1429
    with gr.Blocks(css=css, analytics_enabled=False, title="Stable Diffusion") as demo:
1430 1431
        with gr.Row(elem_id="quicksettings"):
            for i, k, item in quicksettings_list:
1432
                component = create_setting_component(k, is_quicksettings=True)
1433 1434
                component_dict[k] = component

D
DepFA 已提交
1435
        settings_interface.gradio_ref = demo
J
Justin Maier 已提交
1436

A
AUTOMATIC 已提交
1437 1438
        with gr.Tabs() as tabs:
            for interface, label, ifid in interfaces:
1439
                with gr.TabItem(label, id=ifid, elem_id='tab_' + ifid):
A
AUTOMATIC 已提交
1440
                    interface.render()
J
Justin Maier 已提交
1441

1442 1443
        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 已提交
1444

1445
        text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False)
1446
        settings_submit.click(
1447 1448 1449
            fn=run_settings,
            inputs=components,
            outputs=[result, text_settings],
1450
        )
1451 1452 1453 1454 1455 1456 1457 1458 1459 1460

        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 已提交
1461 1462
        def modelmerger(*args):
            try:
1463
                results = modules.extras.run_modelmerger(*args)
S
safentisAuth 已提交
1464 1465 1466
            except Exception as e:
                print("Error loading/saving model file:", file=sys.stderr)
                print(traceback.format_exc(), file=sys.stderr)
1467
                modules.sd_models.list_models()  # to remove the potentially missing models from the list
S
safentisAuth 已提交
1468 1469
                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
1470

1471
        modelmerger_merge.click(
S
safentisAuth 已提交
1472
            fn=modelmerger,
1473 1474 1475 1476 1477 1478
            inputs=[
                primary_model_name,
                secondary_model_name,
                interp_method,
                interp_amount,
                save_as_half,
S
safentisAuth 已提交
1479
                custom_name,
1480 1481 1482 1483 1484 1485 1486 1487
            ],
            outputs=[
                submit_result,
                primary_model_name,
                secondary_model_name,
                component_dict['sd_model_checkpoint'],
            ]
        )
1488 1489 1490
        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 已提交
1491
        send_to_img2img.click(
1492 1493 1494 1495
            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 已提交
1496 1497 1498
        )

        send_to_inpaint.click(
1499 1500 1501 1502
            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 已提交
1503 1504 1505 1506
        )

        img2img_send_to_img2img.click(
            fn=lambda x: image_from_url_text(x),
1507
            _js="extract_image_from_gallery_img2img",
A
AUTOMATIC 已提交
1508 1509 1510 1511 1512 1513
            inputs=[img2img_gallery],
            outputs=[init_img],
        )

        img2img_send_to_inpaint.click(
            fn=lambda x: image_from_url_text(x),
1514
            _js="extract_image_from_gallery_inpaint",
A
AUTOMATIC 已提交
1515 1516 1517 1518 1519 1520
            inputs=[img2img_gallery],
            outputs=[init_img_with_mask],
        )

        send_to_extras.click(
            fn=lambda x: image_from_url_text(x),
S
Seki 已提交
1521
            _js="extract_image_from_gallery_extras",
A
AUTOMATIC 已提交
1522
            inputs=[txt2img_gallery],
1523
            outputs=[extras_image],
A
AUTOMATIC 已提交
1524 1525
        )

M
Michoko 已提交
1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543
        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 已提交
1544 1545
        img2img_send_to_extras.click(
            fn=lambda x: image_from_url_text(x),
S
Seki 已提交
1546
            _js="extract_image_from_gallery_extras",
A
AUTOMATIC 已提交
1547
            inputs=[img2img_gallery],
1548
            outputs=[extras_image],
A
AUTOMATIC 已提交
1549
        )
1550

1551 1552 1553
        modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_txt2img, txt2img_paste_fields, generation_info, 'switch_to_txt2img')
        modules.generation_parameters_copypaste.connect_paste(pnginfo_send_to_img2img, img2img_paste_fields, generation_info, 'switch_to_img2img_img2img')

1554
    ui_config_file = cmd_opts.ui_config_file
A
AUTOMATIC 已提交
1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568
    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):
1569
        def apply_field(obj, field, condition=None):
A
AUTOMATIC 已提交
1570
            key = path + "/" + field
1571 1572 1573

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

A
AUTOMATIC 已提交
1575 1576
            if getattr(obj, 'do_not_save_to_config', False):
                return
J
Justin Maier 已提交
1577

A
AUTOMATIC 已提交
1578 1579 1580
            saved_value = ui_settings.get(key, None)
            if saved_value is None:
                ui_settings[key] = getattr(obj, field)
1581
            elif condition is None or condition(saved_value):
A
AUTOMATIC 已提交
1582 1583
                setattr(obj, field, saved_value)

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

A
AUTOMATIC 已提交
1587 1588 1589 1590 1591 1592 1593
        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:
1594
            apply_field(x, 'value', lambda val: val in x.choices)
A
AUTOMATIC 已提交
1595

D
DepFA 已提交
1596
        if type(x) == gr.Checkbox:
D
DepFA 已提交
1597
            apply_field(x, 'value')
D
DepFA 已提交
1598 1599

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

D
DepFA 已提交
1602
        if type(x) == gr.Number:
D
DepFA 已提交
1603
            apply_field(x, 'value')
J
Justin Maier 已提交
1604

A
AUTOMATIC 已提交
1605 1606
    visit(txt2img_interface, loadsave, "txt2img")
    visit(img2img_interface, loadsave, "img2img")
1607
    visit(extras_interface, loadsave, "extras")
A
AUTOMATIC 已提交
1608 1609 1610 1611 1612

    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)

1613 1614 1615
    return demo


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

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


1625
if 'gradio_routes_templates_response' not in globals():
D
DepFA 已提交
1626 1627 1628 1629 1630 1631 1632 1633
    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