add pause button

This commit is contained in:
Vladimir Mandic
2023-05-31 11:47:22 -04:00
parent d9f72b066f
commit fcb9bde068
9 changed files with 91 additions and 214 deletions
+1 -6
View File
@@ -81,19 +81,14 @@ svg.feather.feather-image, .feather .feather-image { display: none }
#quicksettings > div, #quicksettings > fieldset { min-width: 24em; max-width: 26em; line-height: 2em; }
#refresh_sd_model_checkpoint { height: 48px; margin-left: -14px; background: #333333; box-shadow: none; }
#open_folder_extras, #footer, #style_pos_col, #style_neg_col, #roll_col, #extras_upscaler_2, #extras_upscaler_2_visibility, #txt2img_seed_resize_from_w, #txt2img_seed_resize_from_h { display: none; }
#refresh_txt2img_styles, #refresh_img2img_styles { height: 45px; margin-left: -8px; }
#save-animation { border-radius: 0 !important; margin-bottom: 16px; background-color: #111111; }
#script_list { padding: 4px; margin-top: 20px; margin-bottom: 20px; }
#settings > div.flex-wrap { width: 15em; }
#tab_extensions table { background-color: #222222; }
#txt2img_actions_column, #img2img_actions_column { min-width: 280px !important; max-width: 280px !important; gap: 0.6em }
#txt2img_cfg_scale { min-width: 200px; }
#txt2img_checkboxes, #img2img_checkboxes { background-color: transparent; }
#txt2img_checkboxes, #img2img_checkboxes { margin-bottom: 0.2em; }
#txt2img_gallery, #img2img_gallery, #extras_gallery { background: black !important; padding: 0; margin: 0; object-fit: contain; box-shadow: none; min-height: 0; }
#txt2img_generate, #img2img_generate { height: 36px; border: none; border-radius: 0; min-height: 36px; padding: 0; }
#txt2img_interrupt, #img2img_interrupt, #txt2img_skip, #img2img_skip { height: 36px; min-width: 116px; max-width: 116px; border: none; border-radius: 0; background-color: var(--inactive-color); margin-top: 46px; display: block !important; padding: 0; }
#extras_generate, #extras_interrupt, #extras_skip { border: none; border-radius: 0; background-color: var(--inactive-color); }
#extras_upscale { margin-top: 10px }
#txt2img_progress_row > div { min-width: var(--left-column); max-width: var(--left-column); }
#txt2img_results, #img2img_results, #extras_results { background-color: black; padding: 0; }
@@ -102,10 +97,10 @@ svg.feather.feather-image, .feather .feather-image { display: none }
#txt2img_subseed_row { padding: 0; margin-top: 16px; }
#txt2img_subseed_show, #img2img_subseed_show { display: None }
#txt2img_subseed_strength { margin-top: 0; }
#txt2img_tools, #img2img_tools { margin-top: 54px; scale: 120%; margin-left: 40px; filter: hue-rotate(180deg) saturate(0.5); }
#txtimg_hr_finalres { max-width: 200px; }
#pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) }
#txt2img_extra_refresh, #txt2img_extra_close { height: 1.7em; }
#txt2img_tools > div > button, #img2img_tools > div > button { filter: hue-rotate(180deg) saturate(0.5); }
/* custom elements overrides */
#steps-animation, #controlnet { border-width: 0; }
+46 -194
View File
@@ -1,4 +1,5 @@
:root, .dark{ --checkbox-label-gap: 0.25em 0.1em; --section-header-text-size: 12pt; --block-background-fill: transparent;}
a { font-weight: bold; cursor: pointer; }
div.gradio-container{ max-width: unset !important; }
div.form{ border-width: 0; box-shadow: none; background: transparent; overflow: visible; gap: 0.5em; }
div.compact{ gap: 1em; }
@@ -48,6 +49,12 @@ button.custom-button{
text-align: center;
}
/* remove footer */
footer { display: none !important; }
/* themes */
.theme-preview { display: none; position: fixed; border: 4px solid var(--neutral-600); box-shadow: 2px 2px 2px 2px var(--neutral-700); top: 0; bottom: 0; left: 0; right: 0; margin: auto; max-width: 75vw; z-index: 999; }
/* txt2img/img2img specific */
.block.token-counter{
position: absolute;
@@ -85,45 +92,22 @@ button.custom-button{
align-self: end;
}
.performance {
font-size: 0.85em;
color: #444;
}
.performance p{
display: inline-block;
color: var(--primary-100) !important
}
.performance .time {
margin-right: 0;
}
#txt2img_generate, #img2img_generate {
min-height: 4.5em;
}
.performance { font-size: 0.85em; color: #444; }
.performance p { display: inline-block; color: var(--primary-100) !important }
.performance .time { margin-right: 0; }
@media screen and (min-width: 2500px) {
#txt2img_gallery, #img2img_gallery {
min-height: 768px;
}
#txt2img_gallery, #img2img_gallery { min-height: 768px; }
}
a{
font-weight: bold;
cursor: pointer;
}
#txt2img_gallery img, #img2img_gallery img, #extras_gallery img {
object-fit: scale-down;
width: -webkit-fill-available !important;
}
#txt2img_actions_column, #img2img_actions_column {
gap: 0.5em;
}
#txt2img_tools, #img2img_tools{
gap: 0.4em;
}
#txt2img_gallery img, #img2img_gallery img, #extras_gallery img { object-fit: scale-down; width: -webkit-fill-available !important; }
#txt2img_actions_column, #img2img_actions_column { gap: 0.5em; }
#txt2img_generate_line1 > button, #img2img_generate_line1 > button { height: 2.2em; line-height: 0; }
#txt2img_generate_line2 > button, #img2img_generate_line2 > button, #extras_generate_box > button { height: 2.2em; line-height: 0; min-width: unset; display: block !important; }
#txt2img_generate_line2 { display: flex; }
#txt2img_tools > div, #img2img_tools > div { justify-content: space-around; margin-top: 0.5em; margin-bottom: 0em; }
#txt2img_tools > div > button, #img2img_tools > div > button { scale: 120%; }
#refresh_txt2img_styles, #refresh_img2img_styles { height: 2.46em; margin-left: -8px; }
.interrogate-col{
min-width: 0 !important;
@@ -134,28 +118,6 @@ a{
flex: 1;
}
.generate-box{
position: relative;
}
.gradio-button.generate-box-skip, .gradio-button.generate-box-interrupt{
position: absolute;
width: 50%;
height: 100%;
display: none;
background: #b4c0cc;
}
.gradio-button.generate-box-skip:hover, .gradio-button.generate-box-interrupt:hover{
background: #c2cfdb;
}
.gradio-button.generate-box-interrupt{
left: 0;
border-radius: 0.5rem 0 0 0.5rem;
}
.gradio-button.generate-box-skip{
right: 0;
border-radius: 0 0.5rem 0.5rem 0;
}
#txtimg_hr_finalres{
min-height: 0 !important;
padding: .625rem .75rem;
@@ -508,81 +470,20 @@ table.settings-value-table td{
/* extensions */
#tab_extensions table{
border-collapse: collapse;
}
#tab_extensions table{ border-collapse: collapse; }
#tab_extensions table td, #tab_extensions table th { border: 1px solid #ccc; padding: 0.25em 0.5em; }
#tab_extensions table input[type="checkbox"] { margin-right: 0.5em; appearance: checkbox; }
#tab_extensions button{ max-width: 16em; }
#tab_extensions input[disabled="disabled"]{ opacity: 0.5; }
.extension-tag{ font-weight: bold; font-size: 95%; }
#extensions .name{ font-size: 1.1rem }
#extensions .type{ opacity: 0.5; font-size: 90%; text-align: center; }
#extensions .version{ opacity: 0.7; }
#extensions .info{ margin: 0; }
#extensions .date{ opacity: 0.85; font-size: 90%; }
.extension-button { font-size: 95% !important; width: 6em; }
#tab_extensions table td, #tab_extensions table th{
border: 1px solid #ccc;
padding: 0.25em 0.5em;
}
#tab_extensions table input[type="checkbox"]{
margin-right: 0.5em;
appearance: checkbox;
}
#tab_extensions button{
max-width: 16em;
}
#tab_extensions input[disabled="disabled"]{
opacity: 0.5;
}
.extension-tag{
font-weight: bold;
font-size: 95%;
}
#extensions .name{
font-size: 1.1rem
}
#extensions .type{
opacity: 0.5;
font-size: 90%;
text-align: center;
}
#extensions .version{
opacity: 0.7;
}
#extensions .info{
margin: 0;
}
#extensions .date{
opacity: 0.85;
font-size: 90%;
}
.extension-button {
font-size: 95% !important;
width: 6em;
}
/* replace original footer with ours */
footer {
display: none !important;
}
#footer{
text-align: center;
}
#footer div{
display: inline-block;
}
#footer .versions{
font-size: 85%;
opacity: 0.85;
}
/* extra networks UI */
/* extra networks */
.extra-networks > div > [id *= '_extra_']{ margin: 0.3em; }
.extra-network-subdirs{ padding: 0.2em 0.35em; }
.extra-network-subdirs button{ margin: 0 0.15em; }
@@ -591,7 +492,6 @@ footer {
.extra-network-cards .nocards, .extra-network-thumbs .nocards{ margin: 1.25em 0.5em 0.5em 0.5em; }
.extra-network-cards .nocards h1, .extra-network-thumbs .nocards h1{ font-size: 1.5em; margin-bottom: 1em; }
.extra-network-cards .nocards li, .extra-network-thumbs .nocards li{ margin-left: 0.5em; }
.extra-network-cards .card .metadata-button, .extra-network-thumbs .card .metadata-button{
display: none;
position: absolute;
@@ -605,7 +505,6 @@ footer {
.extra-network-cards .card:hover .metadata-button, .extra-network-thumbs .card:hover .metadata-button{ display: inline-block; }
.extra-network-thumbs { display: flex; flex-flow: row wrap; gap: 10px; }
.extra-network-cards .card .additional a:hover, .extra-network-thumbs .card .additional a:hover { color: darkorange }
.extra-network-thumbs .card {
display: inline-block;
height: 9em;
@@ -616,7 +515,6 @@ footer {
background-position: center center;
position: relative;
}
.extra-network-cards .card .additional, .extra-network-thumbs .card .additional { white-space: nowrap; overflow: hidden; }
.extra-network-thumbs .card:hover .additional a { display: inline-block; }
.extra-network-thumbs .actions .name {
@@ -631,7 +529,6 @@ footer {
background: rgba(0,0,0,.5);
color: white;
}
.extra-network-thumbs .card:hover .actions .name { white-space: normal; word-break: break-all; }
.extra-network-cards .card{
display: inline-block;
@@ -647,10 +544,8 @@ footer {
cursor: pointer;
background-image: url('../html/card-no-preview.png')
}
.extra-network-cards .card:hover { box-shadow: 0 0 2px 0.3em rgba(0, 128, 255, 0.35); }
.extra-network-cards .card .actions .additional, .extra-network-thumbs .card .actions .additional{ display: none; }
.extra-network-cards .card .actions{
position: absolute;
bottom: 0;
@@ -661,7 +556,6 @@ footer {
box-shadow: 0 0 0.25em 0.25em rgba(0,0,0,0.5);
text-shadow: 0 0 0.2em black;
}
.extra-network-cards .card .actions *{ color: white; }
.extra-network-cards .card .actions:hover { box-shadow: 0 0 0.75em 0.75em rgba(0,0,0,0.5) !important; }
.extra-network-cards .card .actions .name { font-size: 1.7em; font-weight: bold; line-break: anywhere; }
@@ -671,63 +565,21 @@ footer {
.extra-network-cards .card ul{ margin: 0.25em 0 0.75em 0.25em; cursor: unset; }
.extra-network-cards .card ul a{ cursor: pointer; }
.extra-network-cards .card ul a:hover{ color: red; }
.theme-preview { display: none; position: fixed; border: 4px solid var(--neutral-600); box-shadow: 2px 2px 2px 2px var(--neutral-700); top: 0; bottom: 0; left: 0; right: 0; margin: auto; max-width: 75vw; z-index: 999; }
/* controlnet */
.controlnet_control_type .controlnet_control_type_filter_group .wrap:last-of-type { display: grid; grid-auto-flow: row; grid-template-columns: repeat(4, minmax(0, 1fr)); }
fieldset.controlnet_resize_mode_radio .wrap:last-of-type, fieldset.controlnet_control_mode_radio .wrap:last-of-type { flex-direction: column; }
div.controlnet_preprocessor_model { display: grid; grid-auto-flow: row; grid-template-columns: 1fr max-content; }
div.controlnet_preprocessor_model button.gradio-button { align-self: center; }
div.controlnet_weight_steps > div.form { display: grid; grid-template: repeat(2, 1fr) / repeat(2, 1fr); }
div.controlnet_weight_steps .controlnet_control_weight_slider { grid-column: 1 / -1; }
div.controlnet_image_controls { display: grid; grid-template-columns: repeat(4, 1fr); }
div.controlnet_image_controls .controlnet_invert_warning { grid-column: 1 / -1; }
div.controlnet_image_controls button { justify-self: center; }
div.controlnet_main_options { display: grid; grid-template-columns: 1fr 1fr; grid-auto-flow: row; }
/* specific elements */
#modelmerger_interp_description { margin-top: 1em; margin-bottom: 1em; }
#scripts_alwayson_txt2img, #scripts_alwayson_img2img { display: grid }
#extras_generate, #extras_interrupt, #extras_skip { display: block !important; position: relative; height: 36px; }
#extras_upscale { margin-top: 10px }
.controlnet_control_type .controlnet_control_type_filter_group .wrap:last-of-type {
display: grid;
grid-auto-flow: row;
grid-template-columns: repeat(4, minmax(0, 1fr));
}
div.controlnet_preprocessor_model {
display: grid;
grid-auto-flow: row;
grid-template-columns: 1fr max-content;
}
div.controlnet_preprocessor_model button.gradio-button {
align-self: center;
}
fieldset.controlnet_resize_mode_radio .wrap:last-of-type,
fieldset.controlnet_control_mode_radio .wrap:last-of-type {
flex-direction: column;
}
div.controlnet_weight_steps > div.form {
display: grid;
grid-template: repeat(2, 1fr) / repeat(2, 1fr);
}
div.controlnet_weight_steps .controlnet_control_weight_slider {
grid-column: 1 / -1;
}
div.controlnet_image_controls {
display: grid;
grid-template-columns: repeat(4, 1fr);
}
div.controlnet_image_controls .controlnet_invert_warning {
grid-column: 1 / -1;
}
div.controlnet_image_controls button {
justify-self: center;
}
div.controlnet_main_options {
display: grid;
grid-template-columns: 1fr 1fr;
grid-auto-flow: row;
}
#modelmerger_interp_description { margin-top: 1em; margin-bottom: 1em; }
.thumbnail-item > img {
}
+1
View File
@@ -76,6 +76,7 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False):
res = extra_outputs_array + [f"<div class='error'>{html.escape(type(e).__name__+': '+str(e))}</div>"]
shared.state.skipped = False
shared.state.interrupted = False
shared.state.paused = False
shared.state.job_count = 0
if not add_stats:
return tuple(res)
+9 -5
View File
@@ -7,13 +7,14 @@ from rich import print
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
"""
import os
import re
from collections import namedtuple
from typing import List
import lark
import torch
from compel import Compel
from modules.shared import opts
from modules.shared import opts, log
# a prompt like this: "fantasy landscape with a [mountain:lake:0.25] and [an oak:a christmas tree:0.75][ in foreground::0.6][ in background:0.25] [shoddy:masterful:0.5]"
# will be represented with prompt_schedule like this (assuming steps=100):
@@ -67,6 +68,9 @@ re_attention_v1 = re.compile(r"""
""", re.X)
debug_output = os.environ.get('SD_PROMPT_DEBUG', None)
debug = log.info if debug_output is not None else lambda *args, **kwargs: None
def get_learned_conditioning_prompt_schedules(prompts, steps):
"""
@@ -161,7 +165,7 @@ def get_learned_conditioning(model, prompts, steps):
prompt_schedules = get_learned_conditioning_prompt_schedules(prompts, steps)
cache = {}
for prompt, prompt_schedule in zip(prompts, prompt_schedules):
# log.debug(f'Prompt schedule: {prompt_schedule}')
debug(f'Prompt schedule: {prompt_schedule}')
cached = cache.get(prompt, None)
if cached is not None:
res.append(cached)
@@ -299,7 +303,7 @@ def parse_prompt_attention(text):
square_brackets = []
if opts.prompt_attention == 'Fixed attention':
res = [[text, 1.0]]
# log.debug(f'Prompt parse-attention: {opts.prompt_attention} {res}')
debug(f'Prompt parse-attention: {opts.prompt_attention} {res}')
return res
elif opts.prompt_attention == 'Compel parser':
conjunction = Compel.parse_prompt_string(text)
@@ -308,7 +312,7 @@ def parse_prompt_attention(text):
res = []
for frag in conjunction.prompts[0].children:
res.append([frag.text, frag.weight])
# log.debug(f'Prompt parse-attention: {opts.prompt_attention} {res}')
debug(f'Prompt parse-attention: {opts.prompt_attention} {res}')
return res
elif opts.prompt_attention == 'A1111 parser':
re_attention = re_attention_v1
@@ -363,7 +367,7 @@ def parse_prompt_attention(text):
res.pop(i + 1)
else:
i += 1
# log.debug(f'Prompt parse-attention: {opts.prompt_attention} {res}')
debug(f'Prompt parse-attention: {opts.prompt_attention} {res}')
return res
if __name__ == "__main__":
+7
View File
@@ -64,6 +64,13 @@ class VanillaStableDiffusionSampler:
def before_sample(self, x, ts, cond, unconditional_conditioning):
if state.interrupted or state.skipped:
raise sd_samplers_common.InterruptedException
if state.paused:
shared.log.debug('Sampling paused')
while state.paused:
if state.interrupted or state.skipped:
raise sd_samplers_common.InterruptedException
import time
time.sleep(0.1)
if self.stop_at is not None and self.step > self.stop_at:
raise sd_samplers_common.InterruptedException
+8 -1
View File
@@ -81,6 +81,13 @@ class CFGDenoiser(torch.nn.Module):
def forward(self, x, sigma, uncond, cond, cond_scale, s_min_uncond, image_cond):
if state.interrupted or state.skipped:
raise sd_samplers_common.InterruptedException
if state.paused:
shared.log.debug('Sampling paused')
while state.paused:
if state.interrupted or state.skipped:
raise sd_samplers_common.InterruptedException
import time
time.sleep(0.1)
# at self.image_cfg_scale == 1.0 produced results for edit model are the same as with normal sampling,
# so is_edit_model is set to False to support AND composition.
@@ -321,7 +328,7 @@ class KDiffusionSampler:
current_iter_seeds = p.all_seeds[p.iteration * p.batch_size:(p.iteration + 1) * p.batch_size]
if cmd_opts.use_ipex: #Remove this after Intel adds support for torch.Generator()
try:
return BrownianTreeNoiseSampler(x.to("cpu"), sigma_min, sigma_max, seed=current_iter_seeds, transform=lambda x: x.to("cpu"), transform_last=lambda x: x.to("xpu"))
return BrownianTreeNoiseSampler(x.to("cpu"), sigma_min, sigma_max, seed=current_iter_seeds, transform=lambda x: x.to("cpu"), transform_last=lambda x: x.to("xpu")) # pylint: disable=E1123
except:
print("ERROR Please apply this patch to repositories/k-diffusion/k_diffusion/sampling.py: https://github.com/crowsonkb/k-diffusion/pull/68/files")
return None
+9 -2
View File
@@ -86,6 +86,7 @@ def reload_hypernetworks():
class State:
skipped = False
interrupted = False
paused = False
job = ""
job_no = 0
job_count = 0
@@ -103,13 +104,17 @@ class State:
server_start = None
def skip(self):
log.debug('Skip requested')
log.debug('Requested skip')
self.skipped = True
def interrupt(self):
log.debug('Interrupt requested')
log.debug('Requested interrupt')
self.interrupted = True
def pause(self):
self.paused = not self.paused
log.debug(f'Requested {"pause" if self.paused else "continue"}')
def nextjob(self):
if opts.live_previews_enable and opts.show_progress_every_n_steps == -1:
self.do_set_current_image()
@@ -142,6 +147,7 @@ class State:
self.id_live_preview = 0
self.skipped = False
self.interrupted = False
self.paused = False
self.textinfo = None
self.time_start = time.time()
devices.torch_gc()
@@ -149,6 +155,7 @@ class State:
def end(self):
self.job = ""
self.job_count = 0
self.paused = False
devices.torch_gc()
def set_current_image(self):
+9 -5
View File
@@ -237,23 +237,27 @@ def create_toprow(is_img2img):
button_interrogate = gr.Button('Interrogate\nCLIP', elem_id="interrogate")
button_deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id="deepbooru")
with gr.Column(scale=1, elem_id=f"{id_part}_actions_column"):
with gr.Row(elem_id=f"{id_part}_generate_box", elem_classes="generate-box"):
interrupt = gr.Button('Stop', elem_id=f"{id_part}_interrupt", elem_classes="generate-box-interrupt")
skip = gr.Button('Skip', elem_id=f"{id_part}_skip", elem_classes="generate-box-skip")
with gr.Row(elem_id=f"{id_part}_generate_line1"):
submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary')
skip.click(fn=lambda: modules.shared.state.skip(), inputs=[], outputs=[])
with gr.Row(elem_id=f"{id_part}_generate_line2"):
interrupt = gr.Button('Stop', elem_id=f"{id_part}_interrupt")
interrupt.click(fn=lambda: modules.shared.state.interrupt(), inputs=[], outputs=[])
skip = gr.Button('Skip', elem_id=f"{id_part}_skip")
skip.click(fn=lambda: modules.shared.state.skip(), inputs=[], outputs=[])
pause = gr.Button('Pause', elem_id=f"{id_part}_pause")
pause.click(fn=lambda: modules.shared.state.pause(), inputs=[], outputs=[])
with gr.Row(elem_id=f"{id_part}_tools"):
paste = ToolButton(value=paste_symbol, elem_id="paste")
clear_prompt_button = ToolButton(value=clear_prompt_symbol, elem_id=f"{id_part}_clear_prompt")
extra_networks_button = ToolButton(value=extra_networks_symbol, elem_id=f"{id_part}_extra_networks")
prompt_style_apply = ToolButton(value=apply_style_symbol, elem_id=f"{id_part}_style_apply")
save_style = ToolButton(value=save_style_symbol, elem_id=f"{id_part}_style_create")
clear_prompt_button.click(fn=lambda *x: x, _js="confirm_clear_prompt", inputs=[prompt, negative_prompt], outputs=[prompt, negative_prompt])
with gr.Row(elem_id=f"{id_part}_counters"):
token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_token_counter", elem_classes=["token-counter"])
token_button = gr.Button(visible=False, elem_id=f"{id_part}_token_button")
negative_token_counter = gr.HTML(value="<span>0/75</span>", elem_id=f"{id_part}_negative_token_counter", elem_classes=["token-counter"])
negative_token_button = gr.Button(visible=False, elem_id=f"{id_part}_negative_token_button")
clear_prompt_button.click(fn=lambda *x: x, _js="confirm_clear_prompt", inputs=[prompt, negative_prompt], outputs=[prompt, negative_prompt])
with gr.Row(elem_id=f"{id_part}_styles_row"):
prompt_styles = gr.Dropdown(label="Styles", elem_id=f"{id_part}_styles", choices=[k for k, v in modules.shared.prompt_styles.styles.items()], value=[], multiselect=True)
create_refresh_button(prompt_styles, modules.shared.prompt_styles.reload, lambda: {"choices": [k for k, v in modules.shared.prompt_styles.styles.items()]}, f"refresh_{id_part}_styles")
+1 -1
View File
@@ -39,9 +39,9 @@ def create_ui():
with gr.Row(elem_id=f"{id_part}_generate_box", elem_classes="generate-box"):
submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary')
interrupt = gr.Button('Stop', elem_id=f"{id_part}_interrupt", variant='secondary')
interrupt.click(fn=lambda: shared.state.interrupt(), inputs=[], outputs=[])
skip = gr.Button('Skip', elem_id=f"{id_part}_skip", variant='secondary')
skip.click(fn=lambda: shared.state.skip(), inputs=[], outputs=[])
interrupt.click(fn=lambda: shared.state.interrupt(), inputs=[], outputs=[])
result_images, generation_info, html_info, html_log = ui_common.create_output_panel("extras", shared.opts.outdir_extras_samples)
gr.HTML('File metadata')
exif_info = gr.HTML(elem_id="pnginfo_html_info")