diff --git a/javascript/ui.js b/javascript/ui.js index 3af1fba9..65d40d63 100644 --- a/javascript/ui.js +++ b/javascript/ui.js @@ -7,6 +7,8 @@ function set_theme(theme) { */ } +var selectedTabItemId = "tab_txt2img"; + function all_gallery_buttons() { var allGalleryButtons = gradioApp().querySelectorAll('[style="display: block;"].tabitem div[id$=_gallery].gradio-gallery .thumbnails > .thumbnail-item.thumbnail-small'); var visibleGalleryButtons = []; @@ -149,6 +151,7 @@ function showRestoreProgressButton(tabname, show) { button.style.display = show ? "flex" : "none"; } + function submit() { showSubmitButtons('txt2img', false); @@ -217,7 +220,6 @@ function restoreProgressImg2img() { return id; } - onUiLoaded(function() { showRestoreProgressButton('txt2img', localStorage.getItem("txt2img_task_id")); showRestoreProgressButton('img2img', localStorage.getItem("img2img_task_id")); @@ -249,138 +251,30 @@ function confirm_clear_prompt(prompt, negative_prompt) { } +var promptTokecountUpdateFuncs = {}; + +function recalculatePromptTokens(name) { + if (promptTokecountUpdateFuncs[name]) { + promptTokecountUpdateFuncs[name](); + } +} + +function recalculate_prompts_txt2img() { + recalculatePromptTokens('txt2img_prompt'); + recalculatePromptTokens('txt2img_neg_prompt'); + return Array.from(arguments); +} + +function recalculate_prompts_img2img() { + recalculatePromptTokens('img2img_prompt'); + recalculatePromptTokens('img2img_neg_prompt'); + return Array.from(arguments); +} + + var opts = {}; -onAfterUiUpdate(function() { - if (Object.keys(opts).length != 0) return; - - var json_elem = gradioApp().getElementById('settings_json'); - if (json_elem == null) return; - - var textarea = json_elem.querySelector('textarea'); - var jsdata = textarea.value; - opts = JSON.parse(jsdata); - - executeCallbacks(optionsChangedCallbacks); /*global optionsChangedCallbacks*/ - - Object.defineProperty(textarea, 'value', { - set: function(newValue) { - var valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value'); - var oldValue = valueProp.get.call(textarea); - valueProp.set.call(textarea, newValue); - - if (oldValue != newValue) { - opts = JSON.parse(textarea.value); - } - - executeCallbacks(optionsChangedCallbacks); - }, - get: function() { - var valueProp = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value'); - return valueProp.get.call(textarea); - } - }); - - json_elem.parentElement.style.display = "none"; - - setupTokenCounters(); - - var show_all_pages = gradioApp().getElementById('settings_show_all_pages'); - var settings_tabs = gradioApp().querySelector('#settings div'); - if (show_all_pages && settings_tabs) { - settings_tabs.appendChild(show_all_pages); - show_all_pages.onclick = function() { - gradioApp().querySelectorAll('#settings > div').forEach(function(elem) { - if (elem.id == "settings_tab_licenses") { - return; - } - - elem.style.display = "block"; - }); - }; - } -}); - -onOptionsChanged(function() { - var elem = gradioApp().getElementById('sd_checkpoint_hash'); - var sd_checkpoint_hash = opts.sd_checkpoint_hash || ""; - var shorthash = sd_checkpoint_hash.substring(0, 10); - - if (elem && elem.textContent != shorthash) { - elem.textContent = shorthash; - elem.title = sd_checkpoint_hash; - elem.href = "https://google.com/search?q=" + sd_checkpoint_hash; - } -}); - -let txt2img_textarea, img2img_textarea = undefined; -var desiredCheckpointName = null; -function selectCheckpoint(name) { - desiredCheckpointName = name; - gradioApp().getElementById('change_checkpoint').click(); -} - -function currentImg2imgSourceResolution(w, h, scaleBy) { - var img = gradioApp().querySelector('#mode_img2img > div[style="display: block;"] img'); - return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy]; -} - -function updateImg2imgResizeToTextAfterChangingImage() { - // At the time this is called from gradio, the image has no yet been replaced. - // There may be a better solution, but this is simple and straightforward so I'm going with it. - - setTimeout(function() { - gradioApp().getElementById('img2img_update_resize_to').click(); - }, 500); - - return []; - -} - -function setRandomSeed(elem_id) { - var input = gradioApp().querySelector("#" + elem_id + " input"); - if (!input) return []; - - input.value = "-1"; - updateInput(input); - return []; -} - -function switchWidthHeight(tabname) { - var width = gradioApp().querySelector("#" + tabname + "_width input[type=number]"); - var height = gradioApp().querySelector("#" + tabname + "_height input[type=number]"); - if (!width || !height) return []; - - var tmp = width.value; - width.value = height.value; - height.value = tmp; - - updateInput(width); - updateInput(height); - return []; -} - -onUiUpdate(function() { - const theme_menu = gradioApp().querySelector("#theme_menu"); - function disabled_extensions(value) { - if (value) { - theme_menu.classList.remove("hidden"); - } else { - theme_menu.classList.add("hidden"); - } - } - const theme_ext = gradioApp().querySelector('#extensions input[name="enable_sd_theme_editor"]'); - if(theme_ext){ - disabled_extensions(theme_ext.checked); - } -}) - -let selectedTabItemId = "tab_txt2img"; -let opts = {}; - -onUiLoaded(function () { - showRestoreProgressButton("txt2img", localStorage.getItem("txt2img_task_id")); - showRestoreProgressButton("img2img", localStorage.getItem("img2img_task_id")); - +onUiUpdate(function() { + if (Object.keys(opts).length != 0) return; var json_elem = gradioApp().getElementById("settings_json"); @@ -415,6 +309,8 @@ onUiLoaded(function () { }, }); + //console.log(opts); + json_elem.parentElement.style.display = "none"; function registerTextarea(id, id_counter, id_button) { @@ -1099,6 +995,7 @@ onUiLoaded(function () { function tabOpsSave(setting) { updateInput(setting); + } function tabsHiddenChange() { @@ -1295,7 +1192,7 @@ onUiLoaded(function () { const cEvent = new Event("click"); //submit Object.defineProperty(cEvent, "target", { value: settings_submit }); settings_submit.dispatchEvent(cEvent); - //console.log(setting_quicksettings.value); + console.log(setting_quicksettings.value); } /* @@ -1965,18 +1862,47 @@ onUiLoaded(function () { /* anapnoe ui end */ }); -onOptionsChanged(function () { - var elem = gradioApp().getElementById("sd_checkpoint_hash"); +onOptionsChanged(function() { + var elem = gradioApp().getElementById('sd_checkpoint_hash'); var sd_checkpoint_hash = opts.sd_checkpoint_hash || ""; var shorthash = sd_checkpoint_hash.substring(0, 10); if (elem && elem.textContent != shorthash) { - elem.textContent = shorthash; - elem.title = sd_checkpoint_hash; - elem.href = "https://google.com/search?q=" + sd_checkpoint_hash; + elem.textContent = shorthash; + elem.title = sd_checkpoint_hash; + elem.href = "https://google.com/search?q=" + sd_checkpoint_hash; } }); +let txt2img_textarea, img2img_textarea = undefined; +let wait_time = 800; +let token_timeouts = {}; + +function update_txt2img_tokens(...args) { + update_token_counter("txt2img_token_button"); + if (args.length == 2) { + return args[0]; + } + return args; +} + +function update_img2img_tokens(...args) { + update_token_counter( + "img2img_token_button" + ); + if (args.length == 2) { + return args[0]; + } + return args; +} + +function update_token_counter(button_id) { + if (token_timeouts[button_id]) { + clearTimeout(token_timeouts[button_id]); + } + token_timeouts[button_id] = setTimeout(() => gradioApp().getElementById(button_id)?.click(), wait_time); +} + function restart_reload() { @@ -2065,3 +1991,51 @@ window.onload = function () { document.body.style.display = "block"; }, 1000); }; + +var desiredCheckpointName = null; +function selectCheckpoint(name) { + desiredCheckpointName = name; + gradioApp().getElementById('change_checkpoint').click(); +} + +function currentImg2imgSourceResolution(w, h, scaleBy) { + var img = gradioApp().querySelector('#mode_img2img > div[style="display: block;"] img'); + return img ? [img.naturalWidth, img.naturalHeight, scaleBy] : [0, 0, scaleBy]; +} + +function updateImg2imgResizeToTextAfterChangingImage() { + // At the time this is called from gradio, the image has no yet been replaced. + // There may be a better solution, but this is simple and straightforward so I'm going with it. + + setTimeout(function() { + gradioApp().getElementById('img2img_update_resize_to').click(); + }, 500); + + return []; + +} + + + +function setRandomSeed(elem_id) { + var input = gradioApp().querySelector("#" + elem_id + " input"); + if (!input) return []; + + input.value = "-1"; + updateInput(input); + return []; +} + +function switchWidthHeight(tabname) { + var width = gradioApp().querySelector("#" + tabname + "_width input[type=number]"); + var height = gradioApp().querySelector("#" + tabname + "_height input[type=number]"); + if (!width || !height) return []; + + var tmp = width.value; + width.value = height.value; + height.value = tmp; + + updateInput(width); + updateInput(height); + return []; +} \ No newline at end of file diff --git a/modules/shared.py b/modules/shared.py index 234bab87..a7b7cb87 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -659,7 +659,7 @@ class Options: self.data = json.load(file) # 1.1.1 quicksettings list migration - if self.data.get('quicksettings') is not None and self.data.get('quicksettings_list') is None: + if self.data.get('quicksettings') is not None: self.data['quicksettings_list'] = [i.strip() for i in self.data.get('quicksettings').split(',')] # 1.4.0 ui_reorder diff --git a/modules/ui.py b/modules/ui.py index ac161226..e3f09f9d 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -12,13 +12,13 @@ import numpy as np from PIL import Image, PngImagePlugin # noqa: F401 from modules.call_queue import wrap_gradio_gpu_call, wrap_queued_call, wrap_gradio_call -from modules import sd_hijack, sd_models, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, errors, shared_items, ui_settings, timer, sysinfo -from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML -from modules.paths import script_path -from modules.ui_common import create_refresh_button -from modules.ui_gradio_extensions import reload_javascript +from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave, errors, shared_items, ui_settings, timer, sysinfo +#from modules import sd_hijack, sd_models, localization, script_callbacks, ui_extensions, deepbooru, sd_vae, extra_networks, ui_common, ui_postprocessing, progress, ui_loadsave +from modules.ui_components import FormRow, FormGroup, ToolButton, FormHTML +from modules.paths import script_path, data_path + from modules.shared import opts, cmd_opts import modules.codeformer_model @@ -368,6 +368,23 @@ def create_toprow(is_img2img): def setup_progressbar(*args, **kwargs): pass +def create_refresh_button(refresh_component, refresh_method, refreshed_args, elem_id): + def refresh(): + refresh_method() + args = refreshed_args() if callable(refreshed_args) else refreshed_args + + for k, v in args.items(): + setattr(refresh_component, k, v) + + return gr.update(**(args or {})) + + refresh_button = ToolButton(value=refresh_symbol, elem_id=elem_id) + refresh_button.click( + fn=refresh, + inputs=[], + outputs=[refresh_component] + ) + return refresh_button def apply_setting(key, value): if value is None: @@ -425,6 +442,14 @@ def ordered_ui_categories(): for _, category in sorted(enumerate(shared_items.ui_reorder_categories()), key=lambda x: user_order.get(x[1], x[0] * 2 + 0)): yield category +def get_value_for_setting(key): + value = getattr(opts, key) + + info = opts.data_labels[key] + args = info.component_args() if callable(info.component_args) else info.component_args or {} + args = {k: v for k, v in args.items() if k not in {'precision'}} + + return gr.update(value=value, **args) def create_override_settings_dropdown(tabname, row): dropdown = gr.Dropdown([], label="Override settings", visible=False, elem_id=f"{tabname}_override_settings", multiselect=True) @@ -469,9 +494,9 @@ def create_ui(): txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button, restore_progress_button = create_toprow(is_img2img=False) with gr.Row(elem_id="txt2img_extra_networks_row", visible=True) as extra_networks: - #from modules import ui_extra_networks - #extra_networks_ui = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'txt2img') - modules.scripts.scripts_txt2img.prepare_ui() + from modules import ui_extra_networks + extra_networks_ui = ui_extra_networks.create_ui(extra_networks, extra_networks_button, 'txt2img') + #modules.scripts.scripts_txt2img.prepare_ui() #with gr.Accordion("Parameters", open=True): @@ -1630,8 +1655,8 @@ def create_ui(): result = gr.HTML(elem_id="settings_result") - #quicksettings_names = opts.quicksettings_list - quicksettings_names = [x.strip() for x in opts.quicksettings.split(",")] + quicksettings_names = opts.quicksettings_list + #quicksettings_names = [x.strip() for x in opts.quicksettings.split(",")] quicksettings_names = {x: i for i, x in enumerate(quicksettings_names) if x != 'quicksettings'} quicksettings_list = [] @@ -1748,7 +1773,7 @@ def create_ui(): ] interfaces += script_callbacks.ui_tabs_callback() - interfaces += [(settings.interface, "Settings", "settings")] + interfaces += [(settings_interface, "Settings", "settings")] extensions_interface = ui_extensions.create_ui() interfaces += [(extensions_interface, "Extensions", "extensions")] @@ -1823,10 +1848,15 @@ def create_ui(): footer = footer.format(versions=versions_html()) gr.HTML(footer) - settings.add_functionality(demo) + text_settings = gr.Textbox(elem_id="settings_json", value=lambda: opts.dumpjson(), visible=False) + settings_submit.click( + fn=wrap_gradio_call(run_settings, extra_outputs=[gr.update()]), + inputs=components, + outputs=[text_settings, result], + ) update_image_cfg_scale_visibility = lambda: gr.update(visible=shared.sd_model and shared.sd_model.cond_stage_key == "edit") - settings.text_settings.change(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale]) + text_settings.change(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale]) demo.load(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale]) button_set_checkpoint = gr.Button('Change checkpoint', elem_id='change_checkpoint', visible=False) @@ -1843,8 +1873,34 @@ def create_ui(): outputs=[component_dict['sd_model_checkpoint'], text_settings], ) + + for _i, k, _item in quicksettings_list: + component = component_dict[k] + info = opts.data_labels[k] + + change_handler = component.release if hasattr(component, 'release') else component.change + change_handler( + fn=lambda value, k=k: run_settings_single(value, key=k), + inputs=[component], + outputs=[component, text_settings], + show_progress=info.refresh is not None, + ) + + update_image_cfg_scale_visibility = lambda: gr.update(visible=shared.sd_model and shared.sd_model.cond_stage_key == "edit") + text_settings.change(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale]) + demo.load(fn=update_image_cfg_scale_visibility, inputs=[], outputs=[image_cfg_scale]) + + button_set_checkpoint = gr.Button('Change checkpoint', elem_id='change_checkpoint', visible=False) + button_set_checkpoint.click( + fn=lambda value, _: run_settings_single(value, key='sd_model_checkpoint'), + _js="function(v){ var res = desiredCheckpointName; desiredCheckpointName = ''; return [res || v, null]; }", + inputs=[component_dict['sd_model_checkpoint'], dummy_component], + outputs=[component_dict['sd_model_checkpoint'], text_settings], + ) + component_keys = [k for k in opts.data_labels.keys() if k in component_dict] + def get_settings_values(): return [get_value_for_setting(key) for key in component_keys] @@ -1859,7 +1915,8 @@ def create_ui(): try: results = modules.extras.run_modelmerger(*args) except Exception as e: - errors.report("Error loading/saving model file", exc_info=True) + print("Error loading/saving model file:", file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) modules.sd_models.list_models() # to remove the potentially missing models from the list return [*[gr.Dropdown.update(choices=modules.sd_models.checkpoint_tiles()) for _ in range(4)], f"Error merging checkpoints: {e}"] return results @@ -1887,7 +1944,7 @@ def create_ui(): primary_model_name, secondary_model_name, tertiary_model_name, - settings.component_dict['sd_model_checkpoint'], + component_dict['sd_model_checkpoint'], modelmerger_result, ] ) @@ -1913,6 +1970,7 @@ def webpath(fn): def javascript_html(): # Ensure localization is in `window` before scripts head = f'\n' + #head = "" script_js = os.path.join(script_path, "script.js") head += f'\n' @@ -1931,7 +1989,6 @@ def javascript_html(): def css_html(): head = "" - def stylesheet(fn): return f''