mirror of
https://github.com/vladmandic/automatic
synced 2026-09-19 17:24:32 +02:00
fully modularize ui.py
This commit is contained in:
@@ -36,6 +36,9 @@ And it also includes fixes for all reported issues so far
|
||||
- vae: enable taesd batch decode
|
||||
enable/disable with settings -> diffusers > vae slicing
|
||||
- updated core requirements
|
||||
- major internal ui module refactoring
|
||||
this may cause compatibility issues if an extension is doing a direct import from `ui.py`
|
||||
in which case, report it so i can add a compatibility layer
|
||||
- **Compile**
|
||||
- new option: **fused projections**
|
||||
pretty much free 5% performance boost for compatible models
|
||||
@@ -56,6 +59,7 @@ And it also includes fixes for all reported issues so far
|
||||
- ipadapter: allow changing of model/image on-the-fly
|
||||
- ipadapter: fix fallback of cross-attention on unload
|
||||
- python: fix python 3.9 compatibility
|
||||
- sdxl: fix positive prompt embeds
|
||||
- img2img: clip and blip interrogate
|
||||
- img2img: sampler selection offset
|
||||
- sampler: guard against invalid sampler index
|
||||
|
||||
+2
-7
@@ -114,14 +114,13 @@ def img2img(id_task: str, mode: int,
|
||||
init_img_inpaint,
|
||||
init_mask_inpaint,
|
||||
steps,
|
||||
sampler_index, hr_sampler_index,
|
||||
sampler_index,
|
||||
mask_blur, mask_alpha,
|
||||
inpainting_fill,
|
||||
full_quality, restore_faces, tiling,
|
||||
n_iter, batch_size,
|
||||
cfg_scale, image_cfg_scale,
|
||||
diffusers_guidance_rescale,
|
||||
refiner_steps,
|
||||
refiner_start,
|
||||
clip_skip,
|
||||
denoising_strength,
|
||||
@@ -140,7 +139,7 @@ def img2img(id_task: str, mode: int,
|
||||
shared.log.warning('Model not loaded')
|
||||
return [], '', '', 'Error: model not loaded'
|
||||
|
||||
debug(f'img2img: id_task={id_task}|mode={mode}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|init_img={init_img}|sketch={sketch}|init_img_with_mask={init_img_with_mask}|inpaint_color_sketch={inpaint_color_sketch}|inpaint_color_sketch_orig={inpaint_color_sketch_orig}|init_img_inpaint={init_img_inpaint}|init_mask_inpaint={init_mask_inpaint}|steps={steps}|sampler_index={sampler_index}|hr_sampler_index={hr_sampler_index}|mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|full_quality={full_quality}|restore_faces={restore_faces}|tiling={tiling}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|image_cfg_scale={image_cfg_scale}|clip_skip={clip_skip}|denoising_strength={denoising_strength}|seed={seed}|subseed{subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}|selected_scale_tab={selected_scale_tab}|height={height}|width={width}|scale_by={scale_by}|resize_mode={resize_mode}|resize_name={resize_name}|inpaint_full_res={inpaint_full_res}|inpaint_full_res_padding={inpaint_full_res_padding}|inpainting_mask_invert={inpainting_mask_invert}|img2img_batch_files={img2img_batch_files}|img2img_batch_input_dir={img2img_batch_input_dir}|img2img_batch_output_dir={img2img_batch_output_dir}|img2img_batch_inpaint_mask_dir={img2img_batch_inpaint_mask_dir}|override_settings_texts={override_settings_texts}')
|
||||
debug(f'img2img: id_task={id_task}|mode={mode}|prompt={prompt}|negative_prompt={negative_prompt}|prompt_styles={prompt_styles}|init_img={init_img}|sketch={sketch}|init_img_with_mask={init_img_with_mask}|inpaint_color_sketch={inpaint_color_sketch}|inpaint_color_sketch_orig={inpaint_color_sketch_orig}|init_img_inpaint={init_img_inpaint}|init_mask_inpaint={init_mask_inpaint}|steps={steps}|sampler_index={sampler_index}||mask_blur={mask_blur}|mask_alpha={mask_alpha}|inpainting_fill={inpainting_fill}|full_quality={full_quality}|restore_faces={restore_faces}|tiling={tiling}|n_iter={n_iter}|batch_size={batch_size}|cfg_scale={cfg_scale}|image_cfg_scale={image_cfg_scale}|clip_skip={clip_skip}|denoising_strength={denoising_strength}|seed={seed}|subseed{subseed}|subseed_strength={subseed_strength}|seed_resize_from_h={seed_resize_from_h}|seed_resize_from_w={seed_resize_from_w}|selected_scale_tab={selected_scale_tab}|height={height}|width={width}|scale_by={scale_by}|resize_mode={resize_mode}|resize_name={resize_name}|inpaint_full_res={inpaint_full_res}|inpaint_full_res_padding={inpaint_full_res_padding}|inpainting_mask_invert={inpainting_mask_invert}|img2img_batch_files={img2img_batch_files}|img2img_batch_input_dir={img2img_batch_input_dir}|img2img_batch_output_dir={img2img_batch_output_dir}|img2img_batch_inpaint_mask_dir={img2img_batch_inpaint_mask_dir}|override_settings_texts={override_settings_texts}')
|
||||
|
||||
if mode == 5:
|
||||
if img2img_batch_files is None or len(img2img_batch_files) == 0:
|
||||
@@ -150,8 +149,6 @@ def img2img(id_task: str, mode: int,
|
||||
|
||||
if sampler_index is None:
|
||||
sampler_index = 0
|
||||
if hr_sampler_index is None:
|
||||
hr_sampler_index = 0
|
||||
|
||||
override_settings = create_override_settings_dict(override_settings_texts)
|
||||
|
||||
@@ -213,7 +210,6 @@ def img2img(id_task: str, mode: int,
|
||||
seed_resize_from_w=seed_resize_from_w,
|
||||
seed_enable_extras=True,
|
||||
sampler_name = processing.get_sampler_name(sampler_index, img=True),
|
||||
hr_sampler_name = processing.get_sampler_name(hr_sampler_index, img=True),
|
||||
batch_size=batch_size,
|
||||
n_iter=n_iter,
|
||||
steps=steps,
|
||||
@@ -233,7 +229,6 @@ def img2img(id_task: str, mode: int,
|
||||
denoising_strength=denoising_strength,
|
||||
image_cfg_scale=image_cfg_scale,
|
||||
diffusers_guidance_rescale=diffusers_guidance_rescale,
|
||||
refiner_steps=refiner_steps,
|
||||
refiner_start=refiner_start,
|
||||
inpaint_full_res=inpaint_full_res != 0,
|
||||
inpaint_full_res_padding=inpaint_full_res_padding,
|
||||
|
||||
@@ -225,8 +225,8 @@ def process_diffusers(p: StableDiffusionProcessing):
|
||||
if 'prompt' in possible:
|
||||
if hasattr(model, 'text_encoder') and 'prompt_embeds' in possible and len(p.prompt_embeds) > 0 and p.prompt_embeds[0] is not None:
|
||||
args['prompt_embeds'] = p.prompt_embeds[0]
|
||||
if 'XL' in model.__class__.__name__ and len(getattr(p, 'negative_pooleds', [])) > 0:
|
||||
args['pooled_prompt_embeds'] = p.negative_pooleds[0]
|
||||
if 'XL' in model.__class__.__name__ and len(getattr(p, 'positive_pooleds', [])) > 0:
|
||||
args['pooled_prompt_embeds'] = p.positive_pooleds[0]
|
||||
else:
|
||||
args['prompt'] = prompts
|
||||
if 'negative_prompt' in possible:
|
||||
|
||||
@@ -570,7 +570,6 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), {
|
||||
|
||||
"postprocessing_sep_img2img": OptionInfo("<h2>Img2Img & Inpainting</h2>", "", gr.HTML),
|
||||
"img2img_color_correction": OptionInfo(False, "Apply color correction"),
|
||||
# "img2img_apply_overlay": OptionInfo(False, "Apply result as overlay"),
|
||||
"img2img_fix_steps": OptionInfo(False, "For image processing do exact number of steps as specified", gr.Checkbox, { "visible": False }),
|
||||
"img2img_background_color": OptionInfo("#ffffff", "Image transparent color fill", ui_components.FormColorPicker, {}),
|
||||
"inpainting_mask_weight": OptionInfo(1.0, "Inpainting conditioning mask strength", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
|
||||
@@ -584,7 +583,6 @@ options_templates.update(options_section(('postprocessing', "Postprocessing"), {
|
||||
|
||||
"postprocessing_sep_upscalers": OptionInfo("<h2>Upscaling</h2>", "", gr.HTML),
|
||||
"upscaler_unload": OptionInfo(False, "Unload upscaler after processing"),
|
||||
# 'upscaling_max_images_in_cache': OptionInfo(5, "Maximum number of images in upscaling cache", gr.Slider, {"minimum": 0, "maximum": 10, "step": 1, "visible": False}),
|
||||
"upscaler_for_img2img": OptionInfo("None", "Default upscaler for image resize operations", gr.Dropdown, lambda: {"choices": [x.name for x in sd_upscalers], "visible": False}, refresh=refresh_upscalers),
|
||||
"upscaler_tile_size": OptionInfo(192, "Upscaler tile size", gr.Slider, {"minimum": 0, "maximum": 512, "step": 16}),
|
||||
"upscaler_tile_overlap": OptionInfo(8, "Upscaler tile overlap", gr.Slider, {"minimum": 0, "maximum": 64, "step": 1}),
|
||||
|
||||
+22
-891
File diff suppressed because it is too large
Load Diff
+75
-5
@@ -4,9 +4,11 @@ import os
|
||||
import shutil
|
||||
import platform
|
||||
import subprocess
|
||||
from functools import reduce
|
||||
import gradio as gr
|
||||
from modules import call_queue, shared
|
||||
from modules import call_queue, shared, prompt_parser
|
||||
from modules.generation_parameters_copypaste import image_from_url_text, parse_generation_parameters
|
||||
from modules.ui_components import FormRow, ToolButton
|
||||
import modules.ui_symbols as symbols
|
||||
import modules.images
|
||||
import modules.script_callbacks
|
||||
@@ -17,6 +19,10 @@ debug = shared.log.trace if os.environ.get('SD_PASTE_DEBUG', None) is not None e
|
||||
debug('Trace: PASTE')
|
||||
|
||||
|
||||
def gr_show(visible=True):
|
||||
return {"visible": visible, "__type__": "update"}
|
||||
|
||||
|
||||
def update_generation_info(generation_info, html_info, img_index):
|
||||
try:
|
||||
generation_info = json.loads(generation_info)
|
||||
@@ -259,7 +265,6 @@ def create_output_panel(tabname, preview=True):
|
||||
|
||||
|
||||
def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id, visible: bool = True):
|
||||
|
||||
def refresh():
|
||||
refresh_method()
|
||||
args = refreshed_args() if callable(refreshed_args) else refreshed_args
|
||||
@@ -267,21 +272,86 @@ def create_refresh_button(refresh_component, refresh_method, refreshed_args, ele
|
||||
setattr(refresh_component, k, v)
|
||||
return gr.update(**(args or {}))
|
||||
|
||||
from modules.ui_components import ToolButton
|
||||
refresh_button = ToolButton(value=symbols.refresh, elem_id=elem_id, visible=visible)
|
||||
refresh_button.click(fn=refresh, inputs=[], outputs=[refresh_component])
|
||||
return refresh_button
|
||||
|
||||
def create_browse_button(browse_component, elem_id):
|
||||
|
||||
def create_browse_button(browse_component, elem_id):
|
||||
def browse(folder):
|
||||
# import subprocess
|
||||
if folder is not None:
|
||||
return gr.update(value = folder)
|
||||
return gr.update()
|
||||
|
||||
from modules.ui_components import ToolButton
|
||||
browse_button = ToolButton(value=symbols.folder, elem_id=elem_id)
|
||||
browse_button.click(fn=browse, _js="async () => await browseFolder()", inputs=[browse_component], outputs=[browse_component])
|
||||
# browse_button.click(fn=browse, inputs=[browse_component], outputs=[browse_component])
|
||||
return browse_button
|
||||
|
||||
|
||||
def create_override_inputs(tab): # pylint: disable=unused-argument
|
||||
with FormRow(elem_id=f"{tab}_override_settings_row"):
|
||||
override_settings = gr.Dropdown([], value=None, label="Override settings", visible=False, elem_id=f"{tab}_override_settings", multiselect=True)
|
||||
override_settings.change(fn=lambda x: gr.Dropdown.update(visible=len(x) > 0), inputs=[override_settings], outputs=[override_settings])
|
||||
return override_settings
|
||||
|
||||
|
||||
def connect_reuse_seed(seed: gr.Number, reuse_seed: gr.Button, generation_info: gr.Textbox, 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
|
||||
was 0, i.e. no variation seed was used, it copies the normal seed value instead."""
|
||||
def copy_seed(gen_info_string: str, index: int):
|
||||
res = -1
|
||||
try:
|
||||
gen_info = json.loads(gen_info_string)
|
||||
shared.log.debug(f'Reuse: info={gen_info}')
|
||||
index -= gen_info.get('index_of_first_image', 0)
|
||||
index = int(index)
|
||||
|
||||
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]
|
||||
else:
|
||||
all_seeds = gen_info.get('all_seeds', [-1])
|
||||
res = all_seeds[index if 0 <= index < len(all_seeds) else 0]
|
||||
except json.decoder.JSONDecodeError:
|
||||
if gen_info_string != '':
|
||||
shared.log.error(f"Error parsing JSON generation info: {gen_info_string}")
|
||||
return [res, gr_show(False)]
|
||||
|
||||
dummy_component = gr.Number(visible=False, value=0)
|
||||
reuse_seed.click(fn=copy_seed, _js="(x, y) => [x, selected_gallery_index()]", show_progress=False, inputs=[generation_info, dummy_component], outputs=[seed, dummy_component])
|
||||
|
||||
|
||||
def update_token_counter(text, steps):
|
||||
from modules import extra_networks, sd_hijack
|
||||
try:
|
||||
text, _ = extra_networks.parse_prompt(text)
|
||||
_, prompt_flat_list, _ = prompt_parser.get_multicond_prompt_list([text])
|
||||
prompt_schedules = prompt_parser.get_learned_conditioning_prompt_schedules(prompt_flat_list, steps)
|
||||
except Exception:
|
||||
prompt_schedules = [[[steps, text]]]
|
||||
|
||||
flat_prompts = reduce(lambda list1, list2: list1+list2, prompt_schedules)
|
||||
prompts = [prompt_text for step, prompt_text in flat_prompts]
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
token_count, max_length = max([sd_hijack.model_hijack.get_prompt_lengths(prompt) for prompt in prompts], key=lambda args: args[0])
|
||||
elif shared.backend == shared.Backend.DIFFUSERS:
|
||||
if shared.sd_model is not None and hasattr(shared.sd_model, 'tokenizer'):
|
||||
tokenizer = shared.sd_model.tokenizer
|
||||
if tokenizer is None:
|
||||
token_count = 0
|
||||
max_length = 75
|
||||
else:
|
||||
has_bos_token = tokenizer.bos_token_id is not None
|
||||
has_eos_token = tokenizer.eos_token_id is not None
|
||||
ids = [shared.sd_model.tokenizer(prompt) for prompt in prompts]
|
||||
if len(ids) > 0 and hasattr(ids[0], 'input_ids'):
|
||||
ids = [x.input_ids for x in ids]
|
||||
token_count = max([len(x) for x in ids]) - int(has_bos_token) - int(has_eos_token)
|
||||
max_length = tokenizer.model_max_length - int(has_bos_token) - int(has_eos_token)
|
||||
else:
|
||||
token_count = 0
|
||||
max_length = 75
|
||||
return f"<span class='gr-box gr-text-input'>{token_count}/{max_length}</span>"
|
||||
|
||||
+10
-10
@@ -12,7 +12,7 @@ from modules.control.units import lite # vislearn ControlNet-XS
|
||||
from modules.control.units import t2iadapter # TencentARC T2I-Adapter
|
||||
from modules.control.units import reference # reference pipeline
|
||||
from modules.control.units import ipadapter # reference pipeline
|
||||
from modules import errors, shared, progress, sd_samplers, ui, ui_components, ui_symbols, ui_common, generation_parameters_copypaste, call_queue
|
||||
from modules import errors, shared, progress, sd_samplers, ui_components, ui_symbols, ui_common, ui_sections, generation_parameters_copypaste, call_queue
|
||||
from modules.ui_components import FormRow, FormGroup
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@ def create_ui(_blocks: gr.Blocks=None):
|
||||
return [(control_ui, 'Control', 'control')]
|
||||
|
||||
with gr.Blocks(analytics_enabled = False) as control_ui:
|
||||
prompt, styles, negative, btn_generate, _btn_interrogate, _btn_deepbooru, btn_paste, btn_extra, prompt_counter, btn_prompt_counter, negative_counter, btn_negative_counter = ui.create_toprow(is_img2img=False, id_part='control')
|
||||
prompt, styles, negative, btn_generate, _btn_interrogate, _btn_deepbooru, btn_paste, btn_extra, prompt_counter, btn_prompt_counter, negative_counter, btn_negative_counter = ui_sections.create_toprow(is_img2img=False, id_part='control')
|
||||
with FormGroup(elem_id="control_interface", equal_height=False):
|
||||
with gr.Row(elem_id='control_settings'):
|
||||
|
||||
@@ -329,15 +329,15 @@ def create_ui(_blocks: gr.Blocks=None):
|
||||
mask_blur = gr.Slider(minimum=0, maximum=100, step=1, label='Blur', value=8, elem_id="control_mask_blur")
|
||||
mask_overlap = gr.Slider(minimum=0, maximum=100, step=1, label='Overlap', value=8, elem_id="control_mask_overlap")
|
||||
|
||||
resize_mode, resize_name, width, height, scale_by, selected_scale_tab, resize_time = ui.create_resize_inputs('control', [], time_selector=True, scale_visible=False, mode='Fixed')
|
||||
resize_mode, resize_name, width, height, scale_by, selected_scale_tab, resize_time = ui_sections.create_resize_inputs('control', [], time_selector=True, scale_visible=False, mode='Fixed')
|
||||
|
||||
with gr.Accordion(open=False, label="Sampler", elem_id="control_sampler", elem_classes=["small-accordion"]):
|
||||
sd_samplers.set_samplers()
|
||||
steps, sampler_index = ui.create_sampler_and_steps_selection(sd_samplers.samplers, "control")
|
||||
steps, sampler_index = ui_sections.create_sampler_and_steps_selection(sd_samplers.samplers, "control")
|
||||
|
||||
batch_count, batch_size = ui.create_batch_inputs('control')
|
||||
seed, _reuse_seed, subseed, _reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui.create_seed_inputs('control', reuse_visible=False)
|
||||
cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, full_quality, restore_faces, tiling, hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_center, hdr_max_boundry = ui.create_advanced_inputs('control')
|
||||
batch_count, batch_size = ui_sections.create_batch_inputs('control')
|
||||
seed, _reuse_seed, subseed, _reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui_sections.create_seed_inputs('control', reuse_visible=False)
|
||||
cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, full_quality, restore_faces, tiling, hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_center, hdr_max_boundry = ui_sections.create_advanced_inputs('control')
|
||||
|
||||
with gr.Accordion(open=False, label="Video", elem_id="control_video", elem_classes=["small-accordion"]):
|
||||
with gr.Row():
|
||||
@@ -351,7 +351,7 @@ def create_ui(_blocks: gr.Blocks=None):
|
||||
video_interpolate = gr.Slider(label='Interpolate frames', minimum=0, maximum=24, step=1, value=0, visible=False)
|
||||
video_type.change(fn=video_type_change, inputs=[video_type], outputs=[video_duration, video_loop, video_pad, video_interpolate])
|
||||
|
||||
override_settings = ui.create_override_inputs('control')
|
||||
override_settings = ui_common.create_override_inputs('control')
|
||||
|
||||
with FormRow(variant='compact', elem_id="control_extra_networks", visible=False) as extra_networks_ui:
|
||||
from modules import timer, ui_extra_networks
|
||||
@@ -680,8 +680,8 @@ def create_ui(_blocks: gr.Blocks=None):
|
||||
show_preview.change(fn=lambda x: gr.update(visible=x), inputs=[show_preview], outputs=[column_preview])
|
||||
show_ip.change(fn=lambda x: gr.update(visible=x), inputs=[show_ip], outputs=[column_ip])
|
||||
input_type.change(fn=lambda x: gr.update(visible=x == 2), inputs=[input_type], outputs=[column_init])
|
||||
btn_prompt_counter.click(fn=call_queue.wrap_queued_call(ui.update_token_counter), inputs=[prompt, steps], outputs=[prompt_counter])
|
||||
btn_negative_counter.click(fn=call_queue.wrap_queued_call(ui.update_token_counter), inputs=[negative, steps], outputs=[negative_counter])
|
||||
btn_prompt_counter.click(fn=call_queue.wrap_queued_call(ui_common.update_token_counter), inputs=[prompt, steps], outputs=[prompt_counter])
|
||||
btn_negative_counter.click(fn=call_queue.wrap_queued_call(ui_common.update_token_counter), inputs=[negative, steps], outputs=[negative_counter])
|
||||
|
||||
select_fields = [input_mode, input_image, init_image, input_type, input_resize, input_inpaint, input_video, input_batch, input_folder, mask_blur, mask_overlap]
|
||||
select_output = [output_tabs, result_txt]
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
import os
|
||||
from PIL import Image
|
||||
import gradio as gr
|
||||
import numpy as np
|
||||
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call
|
||||
from modules import shared, ui_common, ui_sections, generation_parameters_copypaste
|
||||
from modules.ui_components import FormRow, FormGroup
|
||||
|
||||
|
||||
def process_interrogate(interrogation_function, mode, ii_input_files, ii_input_dir, ii_output_dir, *ii_singles):
|
||||
mode = int(mode)
|
||||
if mode in {0, 1, 3, 4}:
|
||||
return [interrogation_function(ii_singles[mode]), None]
|
||||
if mode == 2:
|
||||
return [interrogation_function(ii_singles[mode]["image"]), None]
|
||||
if mode == 5:
|
||||
if len(ii_input_files) > 0:
|
||||
images = [f.name for f in ii_input_files]
|
||||
else:
|
||||
if not os.path.isdir(ii_input_dir):
|
||||
shared.log.error(f"Interrogate: Input directory not found: {ii_input_dir}")
|
||||
return [gr.update(), None]
|
||||
images = shared.listfiles(ii_input_dir)
|
||||
if ii_output_dir != "":
|
||||
os.makedirs(ii_output_dir, exist_ok=True)
|
||||
else:
|
||||
ii_output_dir = ii_input_dir
|
||||
for image in images:
|
||||
img = Image.open(image)
|
||||
filename = os.path.basename(image)
|
||||
left, _ = os.path.splitext(filename)
|
||||
print(interrogation_function(img), file=open(os.path.join(ii_output_dir, f"{left}.txt"), 'a', encoding='utf-8')) # pylint: disable=consider-using-with
|
||||
return [gr.update(), None]
|
||||
|
||||
|
||||
def interrogate(image):
|
||||
if image is None:
|
||||
shared.log.error("Interrogate: no image selected")
|
||||
return gr.update()
|
||||
prompt = shared.interrogator.interrogate(image.convert("RGB"))
|
||||
return gr.update() if prompt is None else prompt
|
||||
|
||||
|
||||
def interrogate_deepbooru(image):
|
||||
from modules import deepbooru
|
||||
prompt = deepbooru.model.tag(image)
|
||||
return gr.update() if prompt is None else prompt
|
||||
|
||||
|
||||
def create_ui():
|
||||
import modules.img2img # pylint: disable=redefined-outer-name
|
||||
modules.scripts.scripts_current = modules.scripts.scripts_img2img
|
||||
modules.scripts.scripts_img2img.initialize_scripts(is_img2img=True)
|
||||
with gr.Blocks(analytics_enabled=False) as _img2img_interface:
|
||||
img2img_prompt, img2img_prompt_styles, img2img_negative_prompt, submit, img2img_interrogate, img2img_deepbooru, img2img_paste, img2img_extra_networks_button, img2img_token_counter, img2img_token_button, img2img_negative_token_counter, img2img_negative_token_button = ui_sections.create_toprow(is_img2img=True, id_part="img2img")
|
||||
img2img_prompt_img = gr.File(label="", elem_id="img2img_prompt_image", file_count="single", type="binary", visible=False)
|
||||
|
||||
with FormRow(variant='compact', elem_id="img2img_extra_networks", visible=False) as extra_networks_ui:
|
||||
from modules import ui_extra_networks
|
||||
extra_networks_ui_img2img = ui_extra_networks.create_ui(extra_networks_ui, img2img_extra_networks_button, 'img2img', skip_indexing=shared.opts.extra_network_skip_indexing)
|
||||
|
||||
with FormRow(elem_id="img2img_interface", equal_height=False):
|
||||
with gr.Column(variant='compact', elem_id="img2img_settings"):
|
||||
copy_image_buttons = []
|
||||
copy_image_destinations = {}
|
||||
|
||||
def copy_image(img):
|
||||
return img['image'] if isinstance(img, dict) and 'image' in img else img
|
||||
|
||||
def add_copy_image_controls(tab_name, elem):
|
||||
with gr.Row(variant="compact", elem_id=f"img2img_copy_to_{tab_name}"):
|
||||
for title, name in zip(['➠ Image', '➠ Sketch', '➠ Inpaint', '➠ Inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']):
|
||||
if name == tab_name:
|
||||
gr.Button(title, interactive=False)
|
||||
copy_image_destinations[name] = elem
|
||||
continue
|
||||
button = gr.Button(title)
|
||||
copy_image_buttons.append((button, name, elem))
|
||||
|
||||
with gr.Tabs(elem_id="mode_img2img"):
|
||||
img2img_selected_tab = gr.State(0) # pylint: disable=abstract-class-instantiated
|
||||
with gr.TabItem('Image', id='img2img', elem_id="img2img_img2img_tab") as tab_img2img:
|
||||
init_img = gr.Image(label="Image for img2img", elem_id="img2img_image", show_label=False, source="upload", interactive=True, type="pil", tool="editor", image_mode="RGBA", height=512)
|
||||
add_copy_image_controls('img2img', init_img)
|
||||
|
||||
with gr.TabItem('Sketch', id='img2img_sketch', elem_id="img2img_img2img_sketch_tab") as tab_sketch:
|
||||
sketch = gr.Image(label="Image for img2img", elem_id="img2img_sketch", show_label=False, source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA", height=512)
|
||||
add_copy_image_controls('sketch', sketch)
|
||||
|
||||
with gr.TabItem('Inpaint', id='inpaint', elem_id="img2img_inpaint_tab") as tab_inpaint:
|
||||
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", height=512)
|
||||
add_copy_image_controls('inpaint', init_img_with_mask)
|
||||
|
||||
with gr.TabItem('Inpaint sketch', id='inpaint_sketch', elem_id="img2img_inpaint_sketch_tab") as tab_inpaint_color:
|
||||
inpaint_color_sketch = gr.Image(label="Color sketch inpainting", show_label=False, elem_id="inpaint_sketch", source="upload", interactive=True, type="pil", tool="color-sketch", image_mode="RGBA", height=512)
|
||||
inpaint_color_sketch_orig = gr.State(None) # pylint: disable=abstract-class-instantiated
|
||||
add_copy_image_controls('inpaint_sketch', inpaint_color_sketch)
|
||||
|
||||
def update_orig(image, state):
|
||||
if image is not None:
|
||||
same_size = state is not None and state.size == image.size
|
||||
has_exact_match = np.any(np.all(np.array(image) == np.array(state), axis=-1))
|
||||
edited = same_size and has_exact_match
|
||||
return image if not edited or state is None else state
|
||||
return state
|
||||
|
||||
inpaint_color_sketch.change(update_orig, [inpaint_color_sketch, inpaint_color_sketch_orig], inpaint_color_sketch_orig)
|
||||
|
||||
with gr.TabItem('Inpaint upload', id='inpaint_upload', elem_id="img2img_inpaint_upload_tab") as tab_inpaint_upload:
|
||||
init_img_inpaint = gr.Image(label="Image for img2img", show_label=False, source="upload", interactive=True, type="pil", elem_id="img_inpaint_base")
|
||||
init_mask_inpaint = gr.Image(label="Mask", source="upload", interactive=True, type="pil", elem_id="img_inpaint_mask")
|
||||
|
||||
with gr.TabItem('Batch', id='batch', elem_id="img2img_batch_tab") as tab_batch:
|
||||
hidden = '<br>Disabled when launched with --hide-ui-dir-config.' if shared.cmd_opts.hide_ui_dir_config else ''
|
||||
gr.HTML(
|
||||
"<p style='padding-bottom: 1em;' class=\"text-gray-500\">Upload images or process images in a directory" +
|
||||
"<br>Add inpaint batch mask directory to enable inpaint batch processing"
|
||||
f"{hidden}</p>"
|
||||
)
|
||||
img2img_batch_files = gr.Files(label="Batch Process", interactive=True, elem_id="img2img_image_batch")
|
||||
img2img_batch_input_dir = gr.Textbox(label="Inpaint batch input directory", **shared.hide_dirs, elem_id="img2img_batch_input_dir")
|
||||
img2img_batch_output_dir = gr.Textbox(label="Inpaint batch output directory", **shared.hide_dirs, elem_id="img2img_batch_output_dir")
|
||||
img2img_batch_inpaint_mask_dir = gr.Textbox(label="Inpaint batch mask directory", **shared.hide_dirs, elem_id="img2img_batch_inpaint_mask_dir")
|
||||
|
||||
img2img_tabs = [tab_img2img, tab_sketch, tab_inpaint, tab_inpaint_color, tab_inpaint_upload, tab_batch]
|
||||
for i, tab in enumerate(img2img_tabs):
|
||||
tab.select(fn=lambda tabnum=i: tabnum, inputs=[], outputs=[img2img_selected_tab])
|
||||
|
||||
for button, name, elem in copy_image_buttons:
|
||||
button.click(fn=copy_image, inputs=[elem], outputs=[copy_image_destinations[name]])
|
||||
button.click(fn=lambda: None, _js=f"switch_to_{name.replace(' ', '_')}", inputs=[], outputs=[])
|
||||
|
||||
with FormGroup(elem_classes="settings-accordion"):
|
||||
|
||||
steps, sampler_index = ui_sections.create_sampler_inputs('img2img')
|
||||
resize_mode, resize_name, width, height, scale_by, selected_scale_tab, _resize_time = ui_sections.create_resize_inputs('img2img', [init_img, sketch])
|
||||
batch_count, batch_size = ui_sections.create_batch_inputs('img2img')
|
||||
seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui_sections.create_seed_inputs('img2img')
|
||||
|
||||
with gr.Accordion(open=False, label="Denoise", elem_classes=["small-accordion"], elem_id="img2img_denoise_group"):
|
||||
with FormRow():
|
||||
denoising_strength = gr.Slider(minimum=0.0, maximum=0.99, step=0.01, label='Denoising strength', value=0.50, elem_id="img2img_denoising_strength")
|
||||
refiner_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Denoise start', value=0.0, elem_id="img2img_refiner_start")
|
||||
|
||||
cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, full_quality, restore_faces, tiling, hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_center, hdr_max_boundry = ui_sections.create_advanced_inputs('img2img')
|
||||
|
||||
with FormGroup(elem_id="inpaint_controls", visible=False) as inpaint_controls:
|
||||
with FormRow():
|
||||
mask_blur = gr.Slider(label='Mask blur', minimum=0, maximum=64, step=1, value=4, elem_id="img2img_mask_blur")
|
||||
mask_alpha = gr.Slider(label="Mask transparency", visible=False, elem_id="img2img_mask_alpha")
|
||||
with FormRow():
|
||||
with gr.Column():
|
||||
inpainting_mask_invert = gr.Radio(label='Mask mode', choices=['Inpaint masked', 'Inpaint not masked'], value='Inpaint masked', type="index", elem_id="img2img_mask_mode")
|
||||
with gr.Column():
|
||||
inpainting_fill = gr.Radio(label='Masked content', choices=['fill', 'original', 'noise', 'nothing'], value='original', type="index", elem_id="img2img_inpainting_fill")
|
||||
with FormRow():
|
||||
with gr.Column():
|
||||
inpaint_full_res = gr.Radio(label="Inpaint area", choices=["Whole picture", "Only masked"], type="index", value="Whole picture", elem_id="img2img_inpaint_full_res")
|
||||
with gr.Column():
|
||||
inpaint_full_res_padding = gr.Slider(label='Masked padding', minimum=0, maximum=256, step=4, value=32, elem_id="img2img_inpaint_full_res_padding")
|
||||
|
||||
def select_img2img_tab(tab):
|
||||
return gr.update(visible=tab in [2, 3, 4]), gr.update(visible=tab == 3)
|
||||
|
||||
for i, elem in enumerate(img2img_tabs):
|
||||
elem.select(fn=lambda tab=i: select_img2img_tab(tab), inputs=[], outputs=[inpaint_controls, mask_alpha]) # pylint: disable=cell-var-from-loop
|
||||
|
||||
override_settings = ui_common.create_override_inputs('img2img')
|
||||
|
||||
with FormGroup(elem_id="img2img_script_container"):
|
||||
img2img_script_inputs = modules.scripts.scripts_img2img.setup_ui()
|
||||
|
||||
img2img_gallery, img2img_generation_info, img2img_html_info, _img2img_html_info_formatted, img2img_html_log = ui_common.create_output_panel("img2img")
|
||||
|
||||
ui_common.connect_reuse_seed(seed, reuse_seed, img2img_generation_info, is_subseed=False)
|
||||
ui_common.connect_reuse_seed(subseed, reuse_subseed, img2img_generation_info, is_subseed=True)
|
||||
|
||||
img2img_prompt_img.change(fn=modules.images.image_data, inputs=[img2img_prompt_img], outputs=[img2img_prompt, img2img_prompt_img])
|
||||
dummy_component1 = gr.Textbox(visible=False, value='dummy')
|
||||
dummy_component2 = gr.Number(visible=False, value=0)
|
||||
img2img_args = [
|
||||
dummy_component1, dummy_component2,
|
||||
img2img_prompt, img2img_negative_prompt, img2img_prompt_styles,
|
||||
init_img,
|
||||
sketch,
|
||||
init_img_with_mask,
|
||||
inpaint_color_sketch,
|
||||
inpaint_color_sketch_orig,
|
||||
init_img_inpaint,
|
||||
init_mask_inpaint,
|
||||
steps,
|
||||
sampler_index,
|
||||
mask_blur, mask_alpha,
|
||||
inpainting_fill,
|
||||
full_quality, restore_faces, tiling,
|
||||
batch_count, batch_size,
|
||||
cfg_scale, image_cfg_scale,
|
||||
diffusers_guidance_rescale,
|
||||
refiner_start,
|
||||
clip_skip,
|
||||
denoising_strength,
|
||||
seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w,
|
||||
selected_scale_tab,
|
||||
height, width,
|
||||
scale_by,
|
||||
resize_mode, resize_name,
|
||||
inpaint_full_res, inpaint_full_res_padding, inpainting_mask_invert,
|
||||
img2img_batch_files, img2img_batch_input_dir, img2img_batch_output_dir, img2img_batch_inpaint_mask_dir,
|
||||
hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_center, hdr_max_boundry,
|
||||
override_settings,
|
||||
]
|
||||
img2img_dict = dict(
|
||||
fn=wrap_gradio_gpu_call(modules.img2img.img2img, extra_outputs=[None, '', '']),
|
||||
_js="submit_img2img",
|
||||
inputs= img2img_args + img2img_script_inputs,
|
||||
outputs=[
|
||||
img2img_gallery,
|
||||
img2img_generation_info,
|
||||
img2img_html_info,
|
||||
img2img_html_log,
|
||||
],
|
||||
show_progress=False,
|
||||
)
|
||||
img2img_prompt.submit(**img2img_dict)
|
||||
submit.click(**img2img_dict)
|
||||
dummy_component = gr.Textbox(visible=False, value='dummy')
|
||||
|
||||
interrogate_args = dict(
|
||||
_js="get_img2img_tab_index",
|
||||
inputs=[
|
||||
dummy_component,
|
||||
img2img_batch_files,
|
||||
img2img_batch_input_dir,
|
||||
img2img_batch_output_dir,
|
||||
init_img,
|
||||
sketch,
|
||||
init_img_with_mask,
|
||||
inpaint_color_sketch,
|
||||
init_img_inpaint,
|
||||
],
|
||||
outputs=[img2img_prompt, dummy_component],
|
||||
)
|
||||
img2img_interrogate.click(fn=lambda *args: process_interrogate(interrogate, *args), **interrogate_args)
|
||||
img2img_deepbooru.click(fn=lambda *args: process_interrogate(interrogate_deepbooru, *args), **interrogate_args)
|
||||
|
||||
img2img_token_button.click(fn=wrap_queued_call(ui_common.update_token_counter), inputs=[img2img_prompt, steps], outputs=[img2img_token_counter])
|
||||
img2img_negative_token_button.click(fn=wrap_queued_call(ui_common.update_token_counter), inputs=[img2img_negative_prompt, steps], outputs=[img2img_negative_token_counter])
|
||||
|
||||
ui_extra_networks.setup_ui(extra_networks_ui_img2img, img2img_gallery)
|
||||
img2img_paste_fields = [
|
||||
# prompt
|
||||
(img2img_prompt, "Prompt"),
|
||||
(img2img_negative_prompt, "Negative prompt"),
|
||||
# sampler
|
||||
(sampler_index, "Sampler"),
|
||||
(steps, "Steps"),
|
||||
# resize
|
||||
(resize_mode, "Resize mode"),
|
||||
(width, "Size-1"),
|
||||
(height, "Size-2"),
|
||||
(scale_by, "Resize scale"),
|
||||
# batch
|
||||
(batch_count, "Batch-1"),
|
||||
(batch_size, "Batch-2"),
|
||||
# seed
|
||||
(seed, "Seed"),
|
||||
(subseed, "Variation seed"),
|
||||
(subseed_strength, "Variation strength"),
|
||||
# denoise
|
||||
(denoising_strength, "Denoising strength"),
|
||||
(refiner_start, "Refiner start"),
|
||||
# advanced
|
||||
(cfg_scale, "CFG scale"),
|
||||
(image_cfg_scale, "Image CFG scale"),
|
||||
(clip_skip, "Clip skip"),
|
||||
(diffusers_guidance_rescale, "CFG rescale"),
|
||||
(full_quality, "Full quality"),
|
||||
(restore_faces, "Face restoration"),
|
||||
(tiling, "Tiling"),
|
||||
# inpaint
|
||||
(mask_blur, "Mask blur"),
|
||||
(mask_alpha, "Mask alpha"),
|
||||
(inpainting_mask_invert, "Mask invert"),
|
||||
(inpainting_fill, "Masked content"),
|
||||
(inpaint_full_res, "Mask area"),
|
||||
(inpaint_full_res_padding, "Masked padding"),
|
||||
# hidden
|
||||
(seed_resize_from_w, "Seed resize from-1"),
|
||||
(seed_resize_from_h, "Seed resize from-2"),
|
||||
*modules.scripts.scripts_img2img.infotext_fields
|
||||
]
|
||||
generation_parameters_copypaste.add_paste_fields("img2img", init_img, img2img_paste_fields, override_settings)
|
||||
generation_parameters_copypaste.add_paste_fields("inpaint", init_img_with_mask, img2img_paste_fields, override_settings)
|
||||
img2img_bindings = generation_parameters_copypaste.ParamBinding(paste_button=img2img_paste, tabname="img2img", source_text_component=img2img_prompt, source_image_component=None)
|
||||
generation_parameters_copypaste.register_paste_params_button(img2img_bindings)
|
||||
@@ -0,0 +1,99 @@
|
||||
import os
|
||||
import gradio.routes
|
||||
import gradio.utils
|
||||
from modules import shared, theme
|
||||
from modules.paths import script_path, data_path
|
||||
import modules.scripts
|
||||
|
||||
def webpath(fn):
|
||||
if fn.startswith(script_path):
|
||||
web_path = os.path.relpath(fn, script_path).replace('\\', '/')
|
||||
else:
|
||||
web_path = os.path.abspath(fn)
|
||||
return f'file={web_path}?{os.path.getmtime(fn)}'
|
||||
|
||||
|
||||
def html_head():
|
||||
head = ''
|
||||
main = ['script.js']
|
||||
for js in main:
|
||||
script_js = os.path.join(script_path, "javascript", js)
|
||||
head += f'<script type="text/javascript" src="{webpath(script_js)}"></script>\n'
|
||||
added = []
|
||||
for script in modules.scripts.list_scripts("javascript", ".js"):
|
||||
if script.filename in main:
|
||||
continue
|
||||
head += f'<script type="text/javascript" src="{webpath(script.path)}"></script>\n'
|
||||
added.append(script.path)
|
||||
for script in modules.scripts.list_scripts("javascript", ".mjs"):
|
||||
head += f'<script type="module" src="{webpath(script.path)}"></script>\n'
|
||||
added.append(script.path)
|
||||
added = [a.replace(script_path, '').replace('\\', '/') for a in added]
|
||||
# log.debug(f'Adding JS scripts: {added}')
|
||||
return head
|
||||
|
||||
|
||||
def html_body():
|
||||
body = ''
|
||||
inline = ''
|
||||
if shared.opts.theme_style != 'Auto':
|
||||
inline += f"set_theme('{shared.opts.theme_style.lower()}');"
|
||||
body += f'<script type="text/javascript">{inline}</script>\n'
|
||||
return body
|
||||
|
||||
|
||||
def html_css(is_builtin: bool):
|
||||
added = []
|
||||
|
||||
def stylesheet(fn):
|
||||
added.append(fn)
|
||||
return f'<link rel="stylesheet" property="stylesheet" href="{webpath(fn)}">'
|
||||
|
||||
css = 'sdnext.css' if is_builtin else 'base.css'
|
||||
head = stylesheet(os.path.join(script_path, 'javascript', css))
|
||||
for cssfile in modules.scripts.list_files_with_name("style.css"):
|
||||
if not os.path.isfile(cssfile):
|
||||
continue
|
||||
head += stylesheet(cssfile)
|
||||
if shared.opts.gradio_theme in theme.list_builtin_themes():
|
||||
head += stylesheet(os.path.join(script_path, "javascript", f"{shared.opts.gradio_theme}.css"))
|
||||
if os.path.exists(os.path.join(data_path, "user.css")):
|
||||
head += stylesheet(os.path.join(data_path, "user.css"))
|
||||
added = [a.replace(script_path, '').replace('\\', '/') for a in added]
|
||||
# log.debug(f'Adding CSS stylesheets: {added}')
|
||||
return head
|
||||
|
||||
|
||||
def reload_javascript():
|
||||
is_builtin = theme.reload_gradio_theme()
|
||||
head = html_head()
|
||||
css = html_css(is_builtin)
|
||||
body = html_body()
|
||||
|
||||
def template_response(*args, **kwargs):
|
||||
res = shared.GradioTemplateResponseOriginal(*args, **kwargs)
|
||||
res.body = res.body.replace(b'</head>', f'{head}</head>'.encode("utf8"))
|
||||
res.body = res.body.replace(b'</body>', f'{css}{body}</body>'.encode("utf8"))
|
||||
res.init_headers()
|
||||
return res
|
||||
|
||||
gradio.routes.templates.TemplateResponse = template_response
|
||||
|
||||
|
||||
def setup_ui_api(app):
|
||||
from pydantic import BaseModel, Field # pylint: disable=no-name-in-module
|
||||
from typing import List
|
||||
|
||||
class QuicksettingsHint(BaseModel): # pylint: disable=too-few-public-methods
|
||||
name: str = Field(title="Name of the quicksettings field")
|
||||
label: str = Field(title="Label of the quicksettings field")
|
||||
|
||||
def quicksettings_hint():
|
||||
return [QuicksettingsHint(name=k, label=v.label) for k, v in shared.opts.data_labels.items()]
|
||||
|
||||
app.add_api_route("/internal/quicksettings-hint", quicksettings_hint, methods=["GET"], response_model=List[QuicksettingsHint])
|
||||
app.add_api_route("/internal/ping", lambda: {}, methods=["GET"])
|
||||
|
||||
|
||||
if not hasattr(shared, 'GradioTemplateResponseOriginal'):
|
||||
shared.GradioTemplateResponseOriginal = gradio.routes.templates.TemplateResponse
|
||||
@@ -0,0 +1,258 @@
|
||||
import gradio as gr
|
||||
from modules import shared, modelloader, ui_symbols, ui_common, sd_samplers
|
||||
from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML
|
||||
|
||||
|
||||
def create_toprow(is_img2img: bool = False, id_part: str = None):
|
||||
def apply_styles(prompt, prompt_neg, styles):
|
||||
prompt = shared.prompt_styles.apply_styles_to_prompt(prompt, styles)
|
||||
prompt_neg = shared.prompt_styles.apply_negative_styles_to_prompt(prompt_neg, styles)
|
||||
return [gr.Textbox.update(value=prompt), gr.Textbox.update(value=prompt_neg), gr.Dropdown.update(value=[])]
|
||||
|
||||
|
||||
def parse_style(styles):
|
||||
return styles.split('|')
|
||||
|
||||
if id_part is None:
|
||||
id_part = "img2img" if is_img2img else "txt2img"
|
||||
with gr.Row(elem_id=f"{id_part}_toprow", variant="compact"):
|
||||
with gr.Column(elem_id=f"{id_part}_prompt_container", scale=6):
|
||||
with gr.Row():
|
||||
with gr.Column(scale=80):
|
||||
with gr.Row():
|
||||
prompt = gr.Textbox(elem_id=f"{id_part}_prompt", label="Prompt", show_label=False, lines=3, placeholder="Prompt", elem_classes=["prompt"])
|
||||
with gr.Row():
|
||||
with gr.Column(scale=80):
|
||||
with gr.Row():
|
||||
negative_prompt = gr.Textbox(elem_id=f"{id_part}_neg_prompt", label="Negative prompt", show_label=False, lines=3, placeholder="Negative prompt", elem_classes=["prompt"])
|
||||
button_interrogate = None
|
||||
button_deepbooru = None
|
||||
if is_img2img:
|
||||
with gr.Column(scale=1, elem_classes="interrogate-col"):
|
||||
button_interrogate = gr.Button('Interrogate\nCLIP', elem_id=f"{id_part}_interrogate")
|
||||
button_deepbooru = gr.Button('Interrogate\nDeepBooru', elem_id=f"{id_part}_deepbooru")
|
||||
with gr.Column(scale=1, elem_id=f"{id_part}_actions_column"):
|
||||
with gr.Row(elem_id=f"{id_part}_generate_box"):
|
||||
submit = gr.Button('Generate', elem_id=f"{id_part}_generate", variant='primary')
|
||||
with gr.Row(elem_id=f"{id_part}_generate_line2"):
|
||||
interrupt = gr.Button('Stop', elem_id=f"{id_part}_interrupt")
|
||||
interrupt.click(fn=lambda: shared.state.interrupt(), _js="requestInterrupt", inputs=[], outputs=[])
|
||||
skip = gr.Button('Skip', elem_id=f"{id_part}_skip")
|
||||
skip.click(fn=lambda: shared.state.skip(), inputs=[], outputs=[])
|
||||
pause = gr.Button('Pause', elem_id=f"{id_part}_pause")
|
||||
pause.click(fn=lambda: shared.state.pause(), _js='checkPaused', inputs=[], outputs=[])
|
||||
with gr.Row(elem_id=f"{id_part}_tools"):
|
||||
button_paste = gr.Button(value='Restore', variant='secondary', elem_id=f"{id_part}_paste") # symbols.paste
|
||||
button_clear = gr.Button(value='Clear', variant='secondary', elem_id=f"{id_part}_clear_prompt_btn") # symbols.clear
|
||||
button_extra = gr.Button(value='Networks', variant='secondary', elem_id=f"{id_part}_extra_networks_btn") # symbols.networks
|
||||
button_clear.click(fn=lambda *x: ['', ''], inputs=[prompt, negative_prompt], outputs=[prompt, negative_prompt], show_progress=False)
|
||||
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")
|
||||
with gr.Row(elem_id=f"{id_part}_styles_row"):
|
||||
styles = gr.Dropdown(label="Styles", elem_id=f"{id_part}_styles", choices=[style.name for style in shared.prompt_styles.styles.values()], value=[], multiselect=True)
|
||||
_styles_btn_refresh = ui_common.create_refresh_button(styles, shared.prompt_styles.reload, lambda: {"choices": list(shared.prompt_styles.styles)}, f"{id_part}_styles_refresh")
|
||||
# styles_btn_refresh = ToolButton(symbols.refresh, elem_id=f"{id_part}_styles_refresh", visible=True)
|
||||
# styles_btn_refresh.click(fn=lambda: gr.update(choices=[style.name for style in shared.prompt_styles.styles.values()]), inputs=[], outputs=[styles])
|
||||
styles_btn_select = gr.Button('Select', elem_id=f"{id_part}_styles_select", visible=False)
|
||||
styles_btn_select.click(_js="applyStyles", fn=parse_style, inputs=[styles], outputs=[styles])
|
||||
styles_btn_apply = ToolButton(ui_symbols.apply, elem_id=f"{id_part}_extra_apply", visible=False)
|
||||
styles_btn_apply.click(fn=apply_styles, inputs=[prompt, negative_prompt, styles], outputs=[prompt, negative_prompt, styles])
|
||||
return prompt, styles, negative_prompt, submit, button_interrogate, button_deepbooru, button_paste, button_extra, token_counter, token_button, negative_token_counter, negative_token_button
|
||||
|
||||
|
||||
def create_sampler_inputs(tab, accordion=True):
|
||||
with gr.Accordion(open=False, label="Sampler", elem_id=f"{tab}_sampler", elem_classes=["small-accordion"]) if accordion else gr.Group():
|
||||
with FormRow(elem_id=f"{tab}_row_sampler"):
|
||||
sd_samplers.set_samplers()
|
||||
steps, sampler_index = create_sampler_and_steps_selection(sd_samplers.samplers, tab)
|
||||
return steps, sampler_index
|
||||
|
||||
|
||||
def create_batch_inputs(tab):
|
||||
with gr.Accordion(open=False, label="Batch", elem_id=f"{tab}_batch", elem_classes=["small-accordion"]):
|
||||
with FormRow(elem_id=f"{tab}_row_batch"):
|
||||
batch_count = gr.Slider(minimum=1, step=1, label='Batch count', value=1, elem_id=f"{tab}_batch_count")
|
||||
batch_size = gr.Slider(minimum=1, maximum=32, step=1, label='Batch size', value=1, elem_id=f"{tab}_batch_size")
|
||||
batch_switch_btn = ToolButton(value=ui_symbols.switch, elem_id=f"{tab}_batch_switch_btn", label="Switch dims")
|
||||
batch_switch_btn.click(lambda w, h: (h, w), inputs=[batch_count, batch_size], outputs=[batch_count, batch_size], show_progress=False)
|
||||
return batch_count, batch_size
|
||||
|
||||
|
||||
def create_seed_inputs(tab, reuse_visible=True):
|
||||
with gr.Accordion(open=False, label="Seed", elem_id=f"{tab}_seed_group", elem_classes=["small-accordion"]):
|
||||
with FormRow(elem_id=f"{tab}_seed_row", variant="compact"):
|
||||
seed = gr.Number(label='Initial seed', value=-1, elem_id=f"{tab}_seed", container=True)
|
||||
random_seed = ToolButton(ui_symbols.random, elem_id=f"{tab}_random_seed", label='Random seed')
|
||||
reuse_seed = ToolButton(ui_symbols.reuse, elem_id=f"{tab}_reuse_seed", label='Reuse seed', visible=reuse_visible)
|
||||
with FormRow(elem_id=f"{tab}_subseed_row", variant="compact", visible=shared.backend==shared.Backend.ORIGINAL):
|
||||
subseed = gr.Number(label='Variation', value=-1, elem_id=f"{tab}_subseed", container=True)
|
||||
random_subseed = ToolButton(ui_symbols.random, elem_id=f"{tab}_random_subseed")
|
||||
reuse_subseed = ToolButton(ui_symbols.reuse, elem_id=f"{tab}_reuse_subseed", visible=reuse_visible)
|
||||
subseed_strength = gr.Slider(label='Variation strength', value=0.0, minimum=0, maximum=1, step=0.01, elem_id=f"{tab}_subseed_strength")
|
||||
with FormRow(visible=False):
|
||||
seed_resize_from_w = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from width", value=0, elem_id=f"{tab}_seed_resize_from_w")
|
||||
seed_resize_from_h = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize seed from height", value=0, elem_id=f"{tab}_seed_resize_from_h")
|
||||
random_seed.click(fn=lambda: [-1, -1], show_progress=False, inputs=[], outputs=[seed, subseed])
|
||||
random_subseed.click(fn=lambda: -1, show_progress=False, inputs=[], outputs=[subseed])
|
||||
return seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w
|
||||
|
||||
|
||||
def create_advanced_inputs(tab):
|
||||
with gr.Accordion(open=False, label="Advanced", elem_id=f"{tab}_advanced", elem_classes=["small-accordion"]):
|
||||
with gr.Group():
|
||||
with FormRow():
|
||||
cfg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='CFG scale', value=6.0, elem_id=f"{tab}_cfg_scale")
|
||||
clip_skip = gr.Slider(label='CLIP skip', value=1, minimum=1, maximum=14, step=1, elem_id=f"{tab}_clip_skip", interactive=True)
|
||||
with FormRow():
|
||||
image_cfg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='Secondary CFG scale', value=6.0, elem_id=f"{tab}_image_cfg_scale")
|
||||
diffusers_guidance_rescale = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Guidance rescale', value=0.7, elem_id=f"{tab}_image_cfg_rescale", visible=shared.backend == shared.Backend.DIFFUSERS)
|
||||
with gr.Group():
|
||||
with FormRow():
|
||||
full_quality = gr.Checkbox(label='Full quality', value=True, elem_id=f"{tab}_full_quality")
|
||||
restore_faces = gr.Checkbox(label='Face restore', value=False, visible=len(shared.face_restorers) > 1, elem_id=f"{tab}_restore_faces")
|
||||
tiling = gr.Checkbox(label='Tiling', value=False, elem_id=f"{tab}_tiling", visible=shared.backend == shared.Backend.ORIGINAL)
|
||||
with gr.Group(visible=shared.backend == shared.Backend.DIFFUSERS):
|
||||
with FormRow():
|
||||
hdr_clamp = gr.Checkbox(label='HDR clamp', value=False, elem_id=f"{tab}_hdr_clamp")
|
||||
hdr_boundary = gr.Slider(minimum=0.0, maximum=10.0, step=0.1, value=4.0, label='Range', elem_id=f"{tab}_hdr_boundary")
|
||||
hdr_threshold = gr.Slider(minimum=0.0, maximum=1.0, step=0.01, value=0.95, label='Threshold', elem_id=f"{tab}_hdr_threshold")
|
||||
with FormRow():
|
||||
hdr_center = gr.Checkbox(label='HDR center', value=False, elem_id=f"{tab}_hdr_center")
|
||||
hdr_channel_shift = gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=1.0, label='Channel shift', elem_id=f"{tab}_hdr_channel_shift")
|
||||
hdr_full_shift = gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=1, label='Full shift', elem_id=f"{tab}_hdr_full_shift")
|
||||
with FormRow():
|
||||
hdr_maximize = gr.Checkbox(label='HDR maximize', value=False, elem_id=f"{tab}_hdr_maximize")
|
||||
hdr_max_center = gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=0.6, label='Center', elem_id=f"{tab}_hdr_max_center")
|
||||
hdr_max_boundry = gr.Slider(minimum=0.5, maximum=2.0, step=0.1, value=1.0, label='Range', elem_id=f"{tab}_hdr_max_boundry")
|
||||
return cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, full_quality, restore_faces, tiling, hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_center, hdr_max_boundry
|
||||
|
||||
|
||||
def create_sampler_and_steps_selection(choices, tabname):
|
||||
def set_sampler_original_options(sampler_options, sampler_algo):
|
||||
shared.opts.data['schedulers_brownian_noise'] = 'brownian noise' in sampler_options
|
||||
shared.opts.data['schedulers_discard_penultimate'] = 'discard penultimate sigma' in sampler_options
|
||||
shared.opts.data['schedulers_sigma'] = sampler_algo
|
||||
shared.opts.save(shared.config_filename, silent=True)
|
||||
|
||||
def set_sampler_diffuser_options(sampler_options):
|
||||
shared.opts.data['schedulers_use_karras'] = 'karras' in sampler_options
|
||||
shared.opts.data['schedulers_use_thresholding'] = 'dynamic thresholding' in sampler_options
|
||||
shared.opts.data['schedulers_use_loworder'] = 'low order' in sampler_options
|
||||
shared.opts.data['schedulers_rescale_betas'] = 'rescale beta' in sampler_options
|
||||
shared.opts.save(shared.config_filename, silent=True)
|
||||
|
||||
with FormRow(elem_classes=['flex-break']):
|
||||
sampler_index = gr.Dropdown(label='Sampling method', elem_id=f"{tabname}_sampling", choices=[x.name for x in choices], value='Default', type="index")
|
||||
steps = gr.Slider(minimum=1, maximum=99, step=1, label="Sampling steps", elem_id=f"{tabname}_steps", value=20)
|
||||
if shared.backend == shared.Backend.ORIGINAL:
|
||||
with FormRow(elem_classes=['flex-break']):
|
||||
choices = ['brownian noise', 'discard penultimate sigma']
|
||||
values = []
|
||||
values += ['brownian noise'] if shared.opts.data.get('schedulers_brownian_noise', False) else []
|
||||
values += ['discard penultimate sigma'] if shared.opts.data.get('schedulers_discard_penultimate', True) else []
|
||||
sampler_options = gr.CheckboxGroup(label='Sampler options', choices=choices, value=values, type='value')
|
||||
with FormRow(elem_classes=['flex-break']):
|
||||
shared.opts.data['schedulers_sigma'] = shared.opts.data.get('schedulers_sigma', 'default')
|
||||
sampler_algo = gr.Radio(label='Sigma algorithm', choices=['default', 'karras', 'exponential', 'polyexponential'], value=shared.opts.data['schedulers_sigma'], type='value')
|
||||
sampler_options.change(fn=set_sampler_original_options, inputs=[sampler_options, sampler_algo], outputs=[])
|
||||
sampler_algo.change(fn=set_sampler_original_options, inputs=[sampler_options, sampler_algo], outputs=[])
|
||||
else:
|
||||
with FormRow(elem_classes=['flex-break']):
|
||||
choices = ['karras', 'dynamic threshold', 'low order', 'rescale beta']
|
||||
values = []
|
||||
values += ['karras'] if shared.opts.data.get('schedulers_use_karras', True) else []
|
||||
values += ['dynamic threshold'] if shared.opts.data.get('schedulers_use_thresholding', False) else []
|
||||
values += ['low order'] if shared.opts.data.get('schedulers_use_loworder', True) else []
|
||||
values += ['rescale beta'] if shared.opts.data.get('schedulers_rescale_betas', False) else []
|
||||
sampler_options = gr.CheckboxGroup(label='Sampler options', choices=choices, value=values, type='value')
|
||||
sampler_options.change(fn=set_sampler_diffuser_options, inputs=[sampler_options], outputs=[])
|
||||
return steps, sampler_index
|
||||
|
||||
|
||||
def create_hires_inputs(tab):
|
||||
with gr.Accordion(open=False, label="Second pass", elem_id=f"{tab}_second_pass", elem_classes=["small-accordion"]):
|
||||
with FormGroup():
|
||||
with FormRow(elem_id=f"{tab}_hires_row1"):
|
||||
enable_hr = gr.Checkbox(label='Enable second pass', value=False, elem_id=f"{tab}_enable_hr")
|
||||
with FormRow(elem_id=f"{tab}_hires_row2"):
|
||||
hr_sampler_index = gr.Dropdown(label='Secondary sampler', elem_id=f"{tab}_sampling_alt", choices=[x.name for x in sd_samplers.samplers], value='Default', type="index")
|
||||
denoising_strength = gr.Slider(minimum=0.0, maximum=0.99, step=0.01, label='Denoising strength', value=0.5, elem_id=f"{tab}_denoising_strength")
|
||||
with FormRow(elem_id=f"{tab}_hires_finalres", variant="compact"):
|
||||
hr_final_resolution = FormHTML(value="", elem_id=f"{tab}_hr_finalres", label="Upscaled resolution", interactive=False)
|
||||
with FormRow(elem_id=f"{tab}_hires_fix_row1", variant="compact"):
|
||||
hr_upscaler = gr.Dropdown(label="Upscaler", elem_id=f"{tab}_hr_upscaler", choices=[*shared.latent_upscale_modes, *[x.name for x in shared.sd_upscalers]], value=shared.latent_upscale_default_mode)
|
||||
hr_force = gr.Checkbox(label='Force Hires', value=False, elem_id=f"{tab}_hr_force")
|
||||
with FormRow(elem_id=f"{tab}_hires_fix_row2", variant="compact"):
|
||||
hr_second_pass_steps = gr.Slider(minimum=0, maximum=99, step=1, label='Hires steps', elem_id=f"{tab}_steps_alt", value=20)
|
||||
hr_scale = gr.Slider(minimum=1.0, maximum=8.0, step=0.05, label="Upscale by", value=2.0, elem_id=f"{tab}_hr_scale")
|
||||
with FormRow(elem_id=f"{tab}_hires_fix_row3", variant="compact"):
|
||||
hr_resize_x = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize width to", value=0, elem_id=f"{tab}_hr_resize_x")
|
||||
hr_resize_y = gr.Slider(minimum=0, maximum=4096, step=8, label="Resize height to", value=0, elem_id=f"{tab}_hr_resize_y")
|
||||
with FormGroup(visible=shared.backend == shared.Backend.DIFFUSERS):
|
||||
with FormRow(elem_id=f"{tab}_refiner_row1", variant="compact"):
|
||||
refiner_start = gr.Slider(minimum=0.0, maximum=1.0, step=0.05, label='Refiner start', value=0.8, elem_id=f"{tab}_refiner_start")
|
||||
refiner_steps = gr.Slider(minimum=0, maximum=99, step=1, label="Refiner steps", elem_id=f"{tab}_refiner_steps", value=5)
|
||||
with FormRow(elem_id=f"{tab}_refiner_row3", variant="compact"):
|
||||
refiner_prompt = gr.Textbox(value='', label='Secondary prompt', elem_id=f"{tab}_refiner_prompt")
|
||||
with FormRow(elem_id="txt2img_refiner_row4", variant="compact"):
|
||||
refiner_negative = gr.Textbox(value='', label='Secondary negative prompt', elem_id=f"{tab}_refiner_neg_prompt")
|
||||
return enable_hr, hr_sampler_index, denoising_strength, hr_final_resolution, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative
|
||||
|
||||
|
||||
def create_resize_inputs(tab, images, time_selector=False, scale_visible=True, mode=None):
|
||||
def resize_from_to_html(width, height, scale_by):
|
||||
target_width = int(width * scale_by)
|
||||
target_height = int(height * scale_by)
|
||||
if not target_width or not target_height:
|
||||
return "Hires resize: no image selected"
|
||||
return f"Hires resize: from <span class='resolution'>{width}x{height}</span> to <span class='resolution'>{target_width}x{target_height}</span>"
|
||||
|
||||
dummy_component = gr.Number(visible=False, value=0)
|
||||
with gr.Accordion(open=False, label="Resize", elem_classes=["small-accordion"], elem_id=f"{tab}_resize_group"):
|
||||
with gr.Row():
|
||||
if mode is not None:
|
||||
resize_mode = gr.Radio(label="Resize mode", elem_id=f"{tab}_resize_mode", choices=shared.resize_modes, type="index", value=mode, visible=False)
|
||||
else:
|
||||
resize_mode = gr.Radio(label="Resize mode", elem_id=f"{tab}_resize_mode", choices=shared.resize_modes, type="index", value='None')
|
||||
resize_time = gr.Radio(label="Resize order", elem_id=f"{tab}_resize_order", choices=['Before', 'After'], value="Before", visible=time_selector)
|
||||
with gr.Row():
|
||||
resize_name = gr.Dropdown(label="Resize method", elem_id=f"{tab}_resize_name", choices=[x.name for x in shared.sd_upscalers], value=shared.opts.upscaler_for_img2img)
|
||||
ui_common.create_refresh_button(resize_name, modelloader.load_upscalers, lambda: {"choices": modelloader.load_upscalers()}, 'refresh_upscalers')
|
||||
|
||||
with FormRow(visible=True) as _resize_group:
|
||||
with gr.Column(elem_id=f"{tab}_column_size"):
|
||||
selected_scale_tab = gr.State(value=0) # pylint: disable=abstract-class-instantiated
|
||||
with gr.Tabs():
|
||||
with gr.Tab(label="Resize to") as tab_scale_to:
|
||||
with FormRow():
|
||||
with gr.Column(elem_id=f"{tab}_column_size"):
|
||||
with FormRow():
|
||||
width = gr.Slider(minimum=64, maximum=8192, step=8, label="Width", value=512, elem_id=f"{tab}_width")
|
||||
height = gr.Slider(minimum=64, maximum=8192, step=8, label="Height", value=512, elem_id=f"{tab}_height")
|
||||
res_switch_btn = ToolButton(value=ui_symbols.switch, elem_id=f"{tab}_res_switch_btn")
|
||||
res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False)
|
||||
detect_image_size_btn = ToolButton(value=ui_symbols.detect, elem_id=f"{tab}_detect_image_size_btn")
|
||||
detect_image_size_btn.click(fn=lambda w, h, _: (w or gr.update(), h or gr.update()), _js="currentImg2imgSourceResolution", inputs=[dummy_component, dummy_component, dummy_component], outputs=[width, height], show_progress=False)
|
||||
|
||||
with gr.Tab(label="Resize by") as tab_scale_by:
|
||||
scale_by = gr.Slider(minimum=0.05, maximum=8.0, step=0.05, label="Scale", value=1.0, elem_id=f"{tab}_scale")
|
||||
if scale_visible:
|
||||
with FormRow():
|
||||
scale_by_html = FormHTML(resize_from_to_html(0, 0, 0.0), elem_id=f"{tab}_scale_resolution_preview")
|
||||
gr.Slider(label="Unused", elem_id=f"{tab}_unused_scale_by_slider")
|
||||
button_update_resize_to = gr.Button(visible=False, elem_id=f"{tab}_update_resize_to")
|
||||
|
||||
on_change_args = dict(fn=resize_from_to_html, _js="currentImg2imgSourceResolution", inputs=[dummy_component, dummy_component, scale_by], outputs=scale_by_html, show_progress=False)
|
||||
scale_by.release(**on_change_args)
|
||||
button_update_resize_to.click(**on_change_args)
|
||||
|
||||
for component in images:
|
||||
component.change(fn=lambda: None, _js="updateImg2imgResizeToTextAfterChangingImage", inputs=[], outputs=[], show_progress=False)
|
||||
|
||||
tab_scale_to.select(fn=lambda: 0, inputs=[], outputs=[selected_scale_tab])
|
||||
tab_scale_by.select(fn=lambda: 1, inputs=[], outputs=[selected_scale_tab])
|
||||
# resize_mode.change(fn=lambda x: gr.update(visible=x != 0), inputs=[resize_mode], outputs=[_resize_group])
|
||||
return resize_mode, resize_name, width, height, scale_by, selected_scale_tab, resize_time
|
||||
+19
-2
@@ -3,12 +3,13 @@ import gradio as gr
|
||||
from modules import sd_hijack, script_callbacks, shared
|
||||
from modules.ui_components import FormRow
|
||||
from modules.ui_common import create_refresh_button
|
||||
from modules.ui_sections import create_sampler_inputs
|
||||
from modules.call_queue import wrap_gradio_gpu_call
|
||||
from modules.textual_inversion import textual_inversion
|
||||
import modules.errors
|
||||
|
||||
|
||||
def create_ui(txt2img_preview_params):
|
||||
def create_ui():
|
||||
dummy_component = gr.Label(visible=False)
|
||||
|
||||
with gr.Row(elem_id="train_tab"):
|
||||
@@ -41,8 +42,24 @@ def create_ui(txt2img_preview_params):
|
||||
return gr_show(False), gr_show(True), gr_show(False)
|
||||
elif tab == 'hn':
|
||||
return gr_show(False), gr_show(False), gr_show(True)
|
||||
else:
|
||||
elif tab == 'pr':
|
||||
return gr_show(True), gr_show(False), gr_show(False)
|
||||
else:
|
||||
return gr_show(False), gr_show(False), gr_show(False)
|
||||
|
||||
### preview tab
|
||||
|
||||
with gr.Tab(label="Preview settings", id="train_preview_tab") as tab_preview:
|
||||
tab_preview.select(fn=lambda: train_tab_change('pr'), inputs=[], outputs=[action_pp, action_ti, action_hn])
|
||||
prompt = gr.Textbox(label="Prompt", value="", placeholder="Prompt to be used for previews", lines=2)
|
||||
negative = gr.Textbox(label="Negative prompt", value="", placeholder="Negative prompt to be used for previews", lines=2)
|
||||
steps, sampler_index = create_sampler_inputs('train', accordion=False)
|
||||
cfg_scale = gr.Slider(minimum=0.0, maximum=30.0, step=0.1, label='CFG scale', value=6.0)
|
||||
seed = gr.Number(label='Initial seed', value=-1)
|
||||
with gr.Row():
|
||||
width = gr.Slider(minimum=64, maximum=8192, step=8, label="Width", value=512)
|
||||
height = gr.Slider(minimum=64, maximum=8192, step=8, label="Height", value=512)
|
||||
txt2img_preview_params = [prompt, negative, steps, sampler_index, cfg_scale, seed, width, height]
|
||||
|
||||
### preprocess tab
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
import gradio as gr
|
||||
from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call
|
||||
from modules import timer, shared, ui_common, ui_symbols, ui_sections, generation_parameters_copypaste
|
||||
from modules.ui_components import FormRow, FormGroup, ToolButton
|
||||
|
||||
|
||||
def calc_resolution_hires(width, height, hr_scale, hr_resize_x, hr_resize_y, hr_upscaler):
|
||||
from modules import processing, devices
|
||||
if hr_upscaler == "None":
|
||||
return "Hires resize: None"
|
||||
p = processing.StableDiffusionProcessingTxt2Img(width=width, height=height, enable_hr=True, hr_scale=hr_scale, hr_resize_x=hr_resize_x, hr_resize_y=hr_resize_y)
|
||||
p.init_hr()
|
||||
with devices.autocast():
|
||||
p.init([""], [0], [0])
|
||||
return f"Hires resize: from <span class='resolution'>{p.width}x{p.height}</span> to <span class='resolution'>{p.hr_resize_x or p.hr_upscale_to_x}x{p.hr_resize_y or p.hr_upscale_to_y}</span>"
|
||||
|
||||
|
||||
def create_ui():
|
||||
import modules.txt2img # pylint: disable=redefined-outer-name
|
||||
modules.scripts.scripts_current = modules.scripts.scripts_txt2img
|
||||
modules.scripts.scripts_txt2img.initialize_scripts(is_img2img=False)
|
||||
with gr.Blocks(analytics_enabled=False) as _txt2img_interface:
|
||||
txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, txt2img_submit, _interrogate, _deepbooru, txt2img_paste, txt2img_extra_networks_button, txt2img_token_counter, txt2img_token_button, txt2img_negative_token_counter, txt2img_negative_token_button = ui_sections.create_toprow(is_img2img=False, id_part="txt2img")
|
||||
|
||||
txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="binary", visible=False)
|
||||
txt_prompt_img.change(fn=modules.images.image_data, inputs=[txt_prompt_img], outputs=[txt2img_prompt, txt_prompt_img])
|
||||
|
||||
with FormRow(variant='compact', elem_id="txt2img_extra_networks", visible=False) as extra_networks_ui:
|
||||
from modules import ui_extra_networks
|
||||
extra_networks_ui = ui_extra_networks.create_ui(extra_networks_ui, txt2img_extra_networks_button, 'txt2img', skip_indexing=shared.opts.extra_network_skip_indexing)
|
||||
timer.startup.record('ui-extra-networks')
|
||||
|
||||
with gr.Row(elem_id="txt2img_interface", equal_height=False):
|
||||
with gr.Column(variant='compact', elem_id="txt2img_settings"):
|
||||
|
||||
with FormRow():
|
||||
width = gr.Slider(minimum=64, maximum=4096, step=8, label="Width", value=512, elem_id="txt2img_width")
|
||||
height = gr.Slider(minimum=64, maximum=4096, step=8, label="Height", value=512, elem_id="txt2img_height")
|
||||
res_switch_btn = ToolButton(value=ui_symbols.switch, elem_id="txt2img_res_switch_btn", label="Switch dims")
|
||||
res_switch_btn.click(lambda w, h: (h, w), inputs=[width, height], outputs=[width, height], show_progress=False)
|
||||
|
||||
with FormGroup(elem_classes="settings-accordion"):
|
||||
|
||||
steps, sampler_index = ui_sections.create_sampler_inputs('txt2img')
|
||||
batch_count, batch_size = ui_sections.create_batch_inputs('txt2img')
|
||||
seed, reuse_seed, subseed, reuse_subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w = ui_sections.create_seed_inputs('txt2img')
|
||||
cfg_scale, clip_skip, image_cfg_scale, diffusers_guidance_rescale, full_quality, restore_faces, tiling, hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_center, hdr_max_boundry = ui_sections.create_advanced_inputs('txt2img')
|
||||
enable_hr, hr_sampler_index, denoising_strength, hr_final_resolution, hr_upscaler, hr_force, hr_second_pass_steps, hr_scale, hr_resize_x, hr_resize_y, refiner_steps, refiner_start, refiner_prompt, refiner_negative = ui_sections.create_hires_inputs('txt2img')
|
||||
override_settings = ui_common.create_override_inputs('txt2img')
|
||||
|
||||
txt2img_script_inputs = modules.scripts.scripts_txt2img.setup_ui()
|
||||
|
||||
hr_resolution_preview_inputs = [width, height, hr_scale, hr_resize_x, hr_resize_y, hr_upscaler]
|
||||
for preview_input in hr_resolution_preview_inputs:
|
||||
preview_input.change(
|
||||
fn=calc_resolution_hires,
|
||||
_js="onCalcResolutionHires",
|
||||
inputs=hr_resolution_preview_inputs,
|
||||
outputs=[hr_final_resolution],
|
||||
show_progress=False,
|
||||
)
|
||||
|
||||
txt2img_gallery, txt2img_generation_info, txt2img_html_info, _txt2img_html_info_formatted, txt2img_html_log = ui_common.create_output_panel("txt2img")
|
||||
ui_common.connect_reuse_seed(seed, reuse_seed, txt2img_generation_info, is_subseed=False)
|
||||
ui_common.connect_reuse_seed(subseed, reuse_subseed, txt2img_generation_info, is_subseed=True)
|
||||
|
||||
dummy_component = gr.Textbox(visible=False, value='dummy')
|
||||
txt2img_args = [
|
||||
dummy_component,
|
||||
txt2img_prompt, txt2img_negative_prompt, txt2img_prompt_styles,
|
||||
steps, sampler_index, hr_sampler_index,
|
||||
full_quality, restore_faces, tiling,
|
||||
batch_count, batch_size,
|
||||
cfg_scale, image_cfg_scale, diffusers_guidance_rescale,
|
||||
clip_skip,
|
||||
seed, subseed, subseed_strength, seed_resize_from_h, seed_resize_from_w,
|
||||
height, width,
|
||||
enable_hr, denoising_strength,
|
||||
hr_scale, hr_upscaler, hr_force, hr_second_pass_steps, hr_resize_x, hr_resize_y,
|
||||
refiner_steps, refiner_start, refiner_prompt, refiner_negative,
|
||||
hdr_clamp, hdr_boundary, hdr_threshold, hdr_center, hdr_channel_shift, hdr_full_shift, hdr_maximize, hdr_max_center, hdr_max_boundry,
|
||||
override_settings,
|
||||
]
|
||||
txt2img_dict = dict(
|
||||
fn=wrap_gradio_gpu_call(modules.txt2img.txt2img, extra_outputs=[None, '', '']),
|
||||
_js="submit_txt2img",
|
||||
inputs=txt2img_args + txt2img_script_inputs,
|
||||
outputs=[
|
||||
txt2img_gallery,
|
||||
txt2img_generation_info,
|
||||
txt2img_html_info,
|
||||
txt2img_html_log,
|
||||
],
|
||||
show_progress=False,
|
||||
)
|
||||
txt2img_prompt.submit(**txt2img_dict)
|
||||
txt2img_submit.click(**txt2img_dict)
|
||||
txt2img_paste_fields = [
|
||||
# prompt
|
||||
(txt2img_prompt, "Prompt"),
|
||||
(txt2img_negative_prompt, "Negative prompt"),
|
||||
# main
|
||||
(width, "Size-1"),
|
||||
(height, "Size-2"),
|
||||
# sampler
|
||||
(sampler_index, "Sampler"),
|
||||
(steps, "Steps"),
|
||||
# batch
|
||||
(batch_count, "Batch-1"),
|
||||
(batch_size, "Batch-2"),
|
||||
# seed
|
||||
(seed, "Seed"),
|
||||
(subseed, "Variation seed"),
|
||||
(subseed_strength, "Variation strength"),
|
||||
# advanced
|
||||
(cfg_scale, "CFG scale"),
|
||||
(clip_skip, "Clip skip"),
|
||||
(image_cfg_scale, "Image CFG scale"),
|
||||
(diffusers_guidance_rescale, "CFG rescale"),
|
||||
(full_quality, "Full quality"),
|
||||
(restore_faces, "Face restoration"),
|
||||
(tiling, "Tiling"),
|
||||
# second pass
|
||||
(enable_hr, "Second pass"),
|
||||
(hr_sampler_index, "Hires sampler"),
|
||||
(denoising_strength, "Denoising strength"),
|
||||
(hr_upscaler, "Hires upscaler"),
|
||||
(hr_force, "Hires force"),
|
||||
(hr_second_pass_steps, "Hires steps"),
|
||||
(hr_scale, "Hires upscale"),
|
||||
(hr_resize_x, "Hires resize-1"),
|
||||
(hr_resize_y, "Hires resize-2"),
|
||||
# refiner
|
||||
(refiner_start, "Refiner start"),
|
||||
(refiner_steps, "Refiner steps"),
|
||||
(refiner_prompt, "Prompt2"),
|
||||
(refiner_negative, "Negative2"),
|
||||
# hidden
|
||||
(seed_resize_from_w, "Seed resize from-1"),
|
||||
(seed_resize_from_h, "Seed resize from-2"),
|
||||
*modules.scripts.scripts_txt2img.infotext_fields
|
||||
]
|
||||
generation_parameters_copypaste.add_paste_fields("txt2img", None, txt2img_paste_fields, override_settings)
|
||||
txt2img_bindings = generation_parameters_copypaste.ParamBinding(paste_button=txt2img_paste, tabname="txt2img", source_text_component=txt2img_prompt, source_image_component=None)
|
||||
generation_parameters_copypaste.register_paste_params_button(txt2img_bindings)
|
||||
|
||||
txt2img_token_button.click(fn=wrap_queued_call(ui_common.update_token_counter), inputs=[txt2img_prompt, steps], outputs=[txt2img_token_counter])
|
||||
txt2img_negative_token_button.click(fn=wrap_queued_call(ui_common.update_token_counter), inputs=[txt2img_negative_prompt, steps], outputs=[txt2img_negative_token_counter])
|
||||
|
||||
ui_extra_networks.setup_ui(extra_networks_ui, txt2img_gallery)
|
||||
+1
-1
Submodule wiki updated: 87ee8d4c1c...671e644b4a
Reference in New Issue
Block a user