diff --git a/CHANGELOG.md b/CHANGELOG.md index 947baa0d1..ad201367c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ ## Update for 2025-11-03 +- **Features** + - ability to disable parts of the app + useful for custom deployments where some features are not desired + *note*: this doesn't just hide it from user, it completely disables the code paths + use `--disable x,y,z` + possible values: + - main tabs: *control,txt2img,img2img,video,extras,caption,gallery* + - aside tabs: *extensions,models,info,update,history,monitor,onnx,system,networks,logs* + - special: *settings,config* - **Fixes** - video save to subfolder - `taesd` warn on long decode times diff --git a/extensions-builtin/sdnext-modernui b/extensions-builtin/sdnext-modernui index 5d9a6bb44..9f0e3f336 160000 --- a/extensions-builtin/sdnext-modernui +++ b/extensions-builtin/sdnext-modernui @@ -1 +1 @@ -Subproject commit 5d9a6bb44e34bf48eb34582bd70e0eef06b2b451 +Subproject commit 9f0e3f3360f5927d05ca8a2e728c80fbbda4c941 diff --git a/html/locale_en.json b/html/locale_en.json index 5b8b75e5b..54f20deb1 100644 --- a/html/locale_en.json +++ b/html/locale_en.json @@ -120,6 +120,9 @@ {"id":"","label":"Save","localized":"","reload":"","hint":"Save image"}, {"id":"","label":"Delete","localized":"","reload":"","hint":"Delete image"}, {"id":"","label":"Replace","localized":"","reload":"","hint":"Replace image"}, + {"id":"","label":"List","localized":"","reload":"","hint":"List all available models"}, + {"id":"","label":"Metadata","localized":"","reload":"","hint":"Update metadata for all available models"}, + {"id":"","label":"Loader","localized":"","reload":"","hint":"Allows to manually assemble a diffusion model from individual modules"}, {"id":"","label":"➠ Text","localized":"","reload":"","hint":"Transfer image to text interface"}, {"id":"","label":"➠ Image","localized":"","reload":"","hint":"Transfer image to image interface"}, {"id":"","label":"➠ Inpaint","localized":"","reload":"","hint":"Transfer image to inpaint interface"}, @@ -139,6 +142,8 @@ {"id":"","label":"HDR Maximize","localized":"","reload":"","hint":"Calculates a 'normalization factor' by dividing the maximum tensor value by the specified range multiplied by 4. This factor is then used to shift the channels within the given boundary, ensuring maximum dynamic range for subsequent processing. The objective is to optimize dynamic range for external applications like Photoshop, particularly for adjusting levels, contrast, and brightness"}, {"id":"","label":"Enable refine pass","localized":"","reload":"","hint":"Use a similar process as image to image to upscale and/or add detail to the final image. Optionally uses refiner model to enhance image details."}, {"id":"","label":"Enable detailer pass","localized":"","reload":"","hint":"Detect target objects such as face and reprocess it at higher resolution"}, + {"id":"","label":"Include detection results","localized":"","reload":"","hint":"Include original image with detected areas marked"}, + {"id":"","label":"Sort detections","localized":"","reload":"","hint":"Sort detected areas by from left to right instead of detection score"}, {"id":"","label":"Denoising strength","localized":"","reload":"","hint":"Determines how little respect the algorithm should have for image's content. At 0, nothing will change, and at 1 you'll get an unrelated image. With values below 1.0, processing will take less steps than the Sampling Steps slider specifies"}, {"id":"","label":"Denoise start","localized":"","reload":"","hint":"Override denoise strength by stating how early base model should finish and when refiner should start. Only applicable to refiner usage. If set to 0 or 1, denoising strength will be used"}, {"id":"","label":"Hires steps","localized":"","reload":"","hint":"Number of sampling steps for upscaled picture. If 0, uses same as for original"}, @@ -151,20 +156,27 @@ {"id":"","label":"Refiner start","localized":"","reload":"","hint":"Refiner pass will start when base model is this much complete (set to larger than 0 and smaller than 1 to run after full base model run)"}, {"id":"","label":"Refiner steps","localized":"","reload":"","hint":"Number of steps to use for refiner pass"}, {"id":"","label":"Refine guidance","localized":"","reload":"","hint":"CFG scale used for refiner pass"}, + {"id":"","label":"Input media","localized":"","reload":"","hint":"Add input image to be used for image-to-image, inpaint or control processing"}, + {"id":"","label":"Control media","localized":"","reload":"","hint":"Add input image as separate initialization image for control processing"}, + {"id":"","label":"Processed preview","localized":"","reload":"","hint":"Display results from pre-processing of input images before actual generate"}, {"id":"","label":"Attention guidance","localized":"","reload":"","hint":"CFG scale used for with PAG: Perturbed-Attention Guidance"}, {"id":"","label":"Adaptive scaling","localized":"","reload":"","hint":"Adaptive modifier for attention guidance scale"}, {"id":"","label":"Rescale guidance","localized":"","reload":"","hint":"Rescale CFG generated noise to avoid overexposed images"}, {"id":"","label":"Refine Prompt","localized":"","reload":"","hint":"Prompt used for both second encoder in base model (if it exists) and for refiner pass (if enabled)"}, {"id":"","label":"Refine negative prompt","localized":"","reload":"","hint":"Negative prompt used for both second encoder in base model (if it exists) and for refiner pass (if enabled)"}, + {"id":"","label":"Initial","localized":"","reload":"","hint":"Set image resolution before processing"}, + {"id":"","label":"Post","localized":"","reload":"","hint":"Resize image after processing"}, {"id":"","label":"Width","localized":"","reload":"","hint":"Image width"}, {"id":"","label":"Height","localized":"","reload":"","hint":"Image height"}, {"id":"","label":"Batch count","localized":"","reload":"","hint":"How many batches of images to create (has no impact on generation performance or VRAM usage)"}, {"id":"","label":"Batch size","localized":"","reload":"","hint":"How many image to create in a single batch (increases generation performance at cost of higher VRAM usage)"}, - {"id":"","label":"guidance scale","localized":"","reload":"","hint":"Classifier Free Guidance scale: how strongly the image should conform to prompt. Lower values produce more creative results, higher values make it follow the prompt more strictly; recommended values between 5-10"}, + {"id":"","label":"Guidance scale","localized":"","reload":"","hint":"Classifier Free Guidance scale: how strongly the image should conform to prompt. Lower values produce more creative results, higher values make it follow the prompt more strictly; recommended values between 5-10"}, + {"id":"","label":"Guidance rescale","localized":"","reload":"","hint":"Rescale guidance to avoid overexposed images at higher guidance values"}, {"id":"","label":"Guidance End","localized":"","reload":"","hint":"Ends the effect of CFG and PAG early: A value of 1 acts as normal, 0.5 stops guidance at 50% of steps"}, {"id":"","label":"Initial seed","localized":"","reload":"","hint":"A value that determines the output of random number generator - if you create an image with same parameters and seed as another image, you'll get the same result"}, {"id":"","label":"Variation","localized":"","reload":"","hint":"Second seed to be mixed with primary seed"}, {"id":"","label":"Variation strength","localized":"","reload":"","hint":"How strong of a variation to produce. At 0, there will be no effect. At 1, you will get the complete picture with variation seed (except for ancestral samplers, where you will just get something)"}, + {"id":"","label":"Resize method","localized":"","reload":"","hint":"Method used to resize the image: can be simple resize, upscaling model, latent resize or asymmetric decode"}, {"id":"","label":"Resize seed from width","localized":"","reload":"","hint":"Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution"}, {"id":"","label":"Resize seed from height","localized":"","reload":"","hint":"Make an attempt to produce a picture similar to what would have been produced with same seed at specified resolution"}, {"id":"","label":"Fixed","localized":"","reload":"","hint":"Resize image to target resolution. Unless height and width match, you will get incorrect aspect ratio"}, @@ -184,6 +196,7 @@ {"id":"","label":"Adjust end","localized":"","reload":"","hint":"Ending step when sigma adjust occurs"}, {"id":"","label":"Options","localized":"","reload":"","hint":"Options"}, {"id":"","label":"ControlNet","localized":"","reload":"","hint":"ControlNet is an advanced guidance model"}, + {"id":"","label":"Processor","localized":"","reload":"","hint":"Processor type to use to preprocess image used for ControlNet"}, {"id":"","label":"Renoise","localized":"","reload":"","hint":"Apply additional noise during detailing"}, {"id":"","label":"Renoise end","localized":"","reload":"","hint":"Final step when renoise is applied"}, {"id":"","label":"Merge detailers","localized":"","reload":"","hint":"Merge results from multiple detailers into single mask before running detailing process"}, @@ -305,7 +318,6 @@ {"id":"","label":"Text encoder","localized":"","reload":"","hint":"Settings related to text encoder and prompt encoding processing during generate"}, {"id":"","label":"Compute Settings","localized":"","reload":"","hint":"Settings related to compute precision, cross attention, and optimizations for computing platforms"}, {"id":"","label":"Backend Settings","localized":"","reload":"","hint":"Settings related to compute backends: torch, onnx and olive"}, - {"id":"","label":"Quantization Settings","localized":"","reload":"","hint":"Settings related to model quantization"}, {"id":"","label":"Pipeline modifiers","localized":"","reload":"","hint":"Additional functionality that can be enabled during generate"}, {"id":"","label":"Model compile","localized":"","reload":"","hint":"Settings related to different model compilation methods"}, {"id":"","label":"System Paths","localized":"","reload":"","hint":"Settings related to location of various model directories"}, @@ -1007,7 +1019,6 @@ {"id":"","label":"preview end","localized":"","reload":"","hint":"preview end"}, {"id":"","label":"preview start","localized":"","reload":"","hint":"preview start"}, {"id":"","label":"primary model","localized":"","reload":"","hint":"primary model"}, - {"id":"","label":"processor","localized":"","reload":"","hint":"processor"}, {"id":"","label":"processor move to cpu after use","localized":"","reload":"","hint":"processor move to cpu after use"}, {"id":"","label":"processor settings","localized":"","reload":"","hint":"processor settings"}, {"id":"","label":"processor unload after use","localized":"","reload":"","hint":"processor unload after use"}, diff --git a/javascript/changelog.js b/javascript/changelog.js index 4cd9a11c7..c0b0d7a5c 100644 --- a/javascript/changelog.js +++ b/javascript/changelog.js @@ -61,7 +61,7 @@ async function initChangelog() { const search = gradioApp().querySelector('#changelog_search > label> textarea'); const md = gradioApp().getElementById('changelog_markdown'); if (!search || !md) { - error('initChangelog', 'Missing search or markdown elements'); + // error('initChangelog', 'Missing search or markdown elements'); return; } const searchChangelog = async (e) => { diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js index aa9b71246..204422d78 100644 --- a/javascript/extraNetworks.js +++ b/javascript/extraNetworks.js @@ -577,7 +577,8 @@ function setupExtraNetworksForTab(tabName) { async function showNetworks() { for (const tabName of ['txt2img', 'img2img', 'control', 'video']) { - if (window.opts.extra_networks_show) gradioApp().getElementById(`${tabName}_extra_networks_btn`).click(); + const btn = gradioApp().getElementById(`${tabName}_extra_networks_btn`); + if (window.opts.extra_networks_show && btn) btn.click(); } log('showNetworks'); } diff --git a/javascript/logMonitor.js b/javascript/logMonitor.js index 21c03e88d..91ed8a7cd 100644 --- a/javascript/logMonitor.js +++ b/javascript/logMonitor.js @@ -99,6 +99,7 @@ async function initLogMonitor() { const el = document.getElementsByTagName('footer')[0]; if (!el) return; el.classList.add('log-monitor'); + if (window.opts.ui_disabled?.includes('logs')) return; el.innerHTML = ` diff --git a/javascript/script.js b/javascript/script.js index 80a9742ad..b794385d6 100644 --- a/javascript/script.js +++ b/javascript/script.js @@ -74,6 +74,8 @@ function executeCallbacks(queue, arg) { } } +const anyPromptExists = () => gradioApp().querySelectorAll('.main-prompts').length > 0; + function scheduleAfterUiUpdateCallbacks() { clearTimeout(uiAfterUpdateTimeout); uiAfterUpdateTimeout = setTimeout(() => executeCallbacks(uiAfterUpdateCallbacks, 500)); @@ -96,7 +98,7 @@ async function mutationCallback(mutations) { if (mutationTimer) clearTimeout(mutationTimer); mutationTimer = setTimeout(async () => { - if (!executedOnLoaded && gradioApp().getElementById('txt2img_prompt')) { // execute once + if (!executedOnLoaded && anyPromptExists()) { // execute once executedOnLoaded = true; executeCallbacks(uiLoadedCallbacks); } diff --git a/javascript/setHints.js b/javascript/setHints.js index 4dcd2a39f..6130d9fcc 100644 --- a/javascript/setHints.js +++ b/javascript/setHints.js @@ -168,17 +168,21 @@ async function tooltipHide(e) { localeData.currentElement = null; } -async function validateHints(json, elements) { +async function validateHints(json, elements, tab) { json.missing = []; const data = Object.values(json).flat().filter((e) => e.hint.length > 0); for (const e of data) e.label = e.label.trim(); + if (tab) { + elements = elements.filter((el) => el.closest(`#${tab}_tabitem`)); // include only elements within specified tab + elements = elements.filter((el) => !el.closest(`#${tab}_scripts_tabitem`)); + } let original = elements.map((e) => e.textContent.toLowerCase().trim()).sort(); // should be case sensitive let duplicateUI = original.filter((e, i, a) => a.indexOf(e.toLowerCase()) !== i).sort(); original = [...new Set(original)]; // remove duplicates duplicateUI = [...new Set(duplicateUI)]; // remove duplicates const current = data.map((e) => e.label.toLowerCase().trim()).sort(); // should be case sensitive - log('all elements:', original); - log('all hints:', current); + // log('all elements:', original); + // log('all hints:', current); log('hints-differences', { elements: original.length, hints: current.length }); const missingHints = original.filter((e) => !current.includes(e.toLowerCase())).sort(); const orphanedHints = current.filter((e) => !original.includes(e.toLowerCase())).sort(); @@ -333,6 +337,7 @@ async function setHints(analyze = false) { log('setHints', { type: localeData.type, locale: localeData.locale, elements: elements.length, localized, hints, data: localeData.data.length, override: overrideData.length, time: Math.round(t1 - t0) }); // sortUIElements(); if (analyze) { + log('analyzing hints', 'control_tabitem'); const [missingHints, orphanedHints] = await validateHints(json, elements); await addMissingHints(json, missingHints); await removeOrphanedHints(json, orphanedHints); diff --git a/modules/cmd_args.py b/modules/cmd_args.py index 15ce7b441..2d0195f91 100644 --- a/modules/cmd_args.py +++ b/modules/cmd_args.py @@ -24,6 +24,7 @@ def main_args(): group_config.add_argument("--freeze", default=os.environ.get("SD_FREEZE", False), action='store_true', help="Disable editing settings") group_config.add_argument("--medvram", default=os.environ.get("SD_MEDVRAM", False), action='store_true', help="Split model stages and keep only active part in VRAM, default: %(default)s") group_config.add_argument("--lowvram", default=os.environ.get("SD_LOWVRAM", False), action='store_true', help="Split model components and keep only active part in VRAM, default: %(default)s") + group_config.add_argument("--disable", default=os.environ.get("SD_DISABLE", ''), help="Disable specific UI tabs: %(default)s") def compatibility_args(): diff --git a/modules/scripts_postprocessing.py b/modules/scripts_postprocessing.py index 01c034e0c..98a80e309 100644 --- a/modules/scripts_postprocessing.py +++ b/modules/scripts_postprocessing.py @@ -49,7 +49,7 @@ def wrap_call(func, filename, funcname, *args, default=None, **kwargs): class ScriptPostprocessingRunner: def __init__(self): - self.scripts = None + self.scripts = [] self.ui_created = False def initialize_scripts(self, scripts_data): diff --git a/modules/shared.py b/modules/shared.py index 40c3fda32..797681cc5 100644 --- a/modules/shared.py +++ b/modules/shared.py @@ -570,6 +570,9 @@ options_templates.update(options_section(('ui', "User Interface"), { "subpath": OptionInfo("", "Mount URL subpath"), "ui_request_timeout": OptionInfo(120000, "UI request timeout", gr.Slider, {"minimum": 1000, "maximum": 300000, "step": 10}), + "ui_tabs": OptionInfo("

UI Tabs

", "", gr.HTML), + "ui_disabled": OptionInfo("", "Disabled UI tabs", gr.Textbox, { 'visible': False }), + "cards_sep_ui": OptionInfo("

Networks panel

", "", gr.HTML), "extra_networks_card_size": OptionInfo(140, "Network card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}), "extra_networks_card_cover": OptionInfo("sidebar", "Network panel position", gr.Radio, {"choices": ["cover", "inline", "sidebar"]}), diff --git a/modules/ui.py b/modules/ui.py index f9daddb35..fdca1d725 100644 --- a/modules/ui.py +++ b/modules/ui.py @@ -69,86 +69,98 @@ def setup_progressbar(*args, **kwargs): # pylint: disable=unused-argument def create_ui(startup_timer = None): + global interfaces # pylint: disable=global-statement if startup_timer is None: timer.startup = timer.Timer() ui_javascript.reload_javascript() generation_parameters_copypaste.reset() scripts_manager.scripts_current = None + ui_disabled = [x.strip().lower() for x in shared.cmd_opts.disable.split(',') if x.strip()] + interfaces.clear() + shared.opts.ui_disabled = ui_disabled + if len(ui_disabled) > 0: + shared.log.warning(f'UI disabled: {ui_disabled}') - with gr.Blocks(analytics_enabled=False) as txt2img_interface: - from modules import ui_txt2img - ui_txt2img.create_ui() - timer.startup.record("ui-txt2img") + if 'txt2img' not in ui_disabled: + with gr.Blocks(analytics_enabled=False) as txt2img_interface: + from modules import ui_txt2img + ui_txt2img.create_ui() + timer.startup.record("ui-txt2img") + interfaces += [(txt2img_interface, "Text", "txt2img")] - with gr.Blocks(analytics_enabled=False) as img2img_interface: - from modules import ui_img2img - ui_img2img.create_ui() - timer.startup.record("ui-img2img") + if 'img2img' not in ui_disabled: + with gr.Blocks(analytics_enabled=False) as img2img_interface: + from modules import ui_img2img + ui_img2img.create_ui() + timer.startup.record("ui-img2img") + interfaces += [(img2img_interface, "Image", "img2img")] - with gr.Blocks(analytics_enabled=False) as control_interface: - from modules import ui_control - ui_control.create_ui() - timer.startup.record("ui-control") + if 'control' not in ui_disabled: + with gr.Blocks(analytics_enabled=False) as control_interface: + from modules import ui_control + ui_control.create_ui() + timer.startup.record("ui-control") + interfaces += [(control_interface, "Control", "control")] - with gr.Blocks(analytics_enabled=False) as video_interface: - from modules import ui_video - ui_video.create_ui() - timer.startup.record("ui-video") + if 'video' not in ui_disabled: + with gr.Blocks(analytics_enabled=False) as video_interface: + from modules import ui_video + ui_video.create_ui() + timer.startup.record("ui-video") + interfaces += [(video_interface, "Video", "video")] - with gr.Blocks(analytics_enabled=False) as extras_interface: - from modules import ui_postprocessing - ui_postprocessing.create_ui() - timer.startup.record("ui-extras") + if 'extras' not in ui_disabled: + with gr.Blocks(analytics_enabled=False) as extras_interface: + from modules import ui_postprocessing + ui_postprocessing.create_ui() + timer.startup.record("ui-extras") + interfaces += [(extras_interface, "Process", "process")] - with gr.Blocks(analytics_enabled=False) as caption_interface: - from modules import ui_caption - ui_caption.create_ui() - timer.startup.record("ui-caption") + if 'caption' not in ui_disabled: + with gr.Blocks(analytics_enabled=False) as caption_interface: + from modules import ui_caption + ui_caption.create_ui() + timer.startup.record("ui-caption") + interfaces += [(caption_interface, "Caption", "caption")] - with gr.Blocks(analytics_enabled=False) as models_interface: - from modules import ui_models - ui_models.create_ui() - timer.startup.record("ui-models") + if 'models' not in ui_disabled: + with gr.Blocks(analytics_enabled=False) as models_interface: + from modules import ui_models + ui_models.create_ui() + timer.startup.record("ui-models") + interfaces += [(models_interface, "Models", "models")] - with gr.Blocks(analytics_enabled=False) as gallery_interface: - from modules import ui_gallery - ui_gallery.create_ui() - timer.startup.record("ui-gallery") + if 'gallery' not in ui_disabled: + with gr.Blocks(analytics_enabled=False) as gallery_interface: + from modules import ui_gallery + ui_gallery.create_ui() + timer.startup.record("ui-gallery") + interfaces += [(gallery_interface, "Gallery", "gallery")] + + interfaces += script_callbacks.ui_tabs_callback() with gr.Blocks(analytics_enabled=False) as settings_interface: from modules import ui_settings - ui_settings.create_ui() + ui_settings.create_ui(ui_disabled) global ui_system_tabs # pylint: disable=global-statement ui_system_tabs = ui_settings.ui_system_tabs shared.opts.reorder() timer.startup.record("ui-extensions") + interfaces += [(settings_interface, "System", "system")] - with gr.Blocks(analytics_enabled=False) as info_interface: - from modules import ui_docs - ui_docs.create_ui() - timer.startup.record("ui-info") + if 'info' not in ui_disabled: + with gr.Blocks(analytics_enabled=False) as info_interface: + from modules import ui_docs + ui_docs.create_ui() + timer.startup.record("ui-info") + interfaces += [(info_interface, "Info", "info")] - with gr.Blocks(analytics_enabled=False) as extensions_interface: - from modules import ui_extensions - ui_extensions.create_ui() - timer.startup.record("ui-extensions") - - global interfaces # pylint: disable=global-statement - interfaces.clear() - interfaces += [(txt2img_interface, "Text", "txt2img")] - interfaces += [(img2img_interface, "Image", "img2img")] - if control_interface is not None: - interfaces += [(control_interface, "Control", "control")] - if video_interface is not None: - interfaces += [(video_interface, "Video", "video")] - interfaces += [(extras_interface, "Process", "process")] - interfaces += [(caption_interface, "Caption", "caption")] - interfaces += [(gallery_interface, "Gallery", "gallery")] - interfaces += [(models_interface, "Models", "models")] - interfaces += script_callbacks.ui_tabs_callback() - interfaces += [(settings_interface, "System", "system")] - interfaces += [(info_interface, "Info", "info")] - interfaces += [(extensions_interface, "Extensions", "extensions")] + if 'extensions' not in ui_disabled: + with gr.Blocks(analytics_enabled=False) as extensions_interface: + from modules import ui_extensions + ui_extensions.create_ui() + timer.startup.record("ui-extensions") + interfaces += [(extensions_interface, "Extensions", "extensions")] ui_app = ui_settings.create_quicksettings(interfaces) diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py index 6f3246236..f18e31ab8 100644 --- a/modules/ui_extra_networks.py +++ b/modules/ui_extra_networks.py @@ -603,6 +603,8 @@ class ExtraNetworksUi: def create_ui(container, button_parent, tabname, skip_indexing = False): + if 'networks' in shared.opts.ui_disabled: + return None debug(f'EN create-ui: {tabname}') ui = ExtraNetworksUi() ui.tabname = tabname @@ -1054,4 +1056,6 @@ def create_ui(container, button_parent, tabname, skip_indexing = False): def setup_ui(ui, gallery: gr.Gallery = None): + if ui is None: + return ui.gallery = gallery diff --git a/modules/ui_loadsave.py b/modules/ui_loadsave.py index 3b6484e06..ab1bc0546 100644 --- a/modules/ui_loadsave.py +++ b/modules/ui_loadsave.py @@ -290,7 +290,11 @@ class UiLoadsave: self.ui_defaults_review = gr.HTML("", elem_id="ui_defaults_review") def setup_ui(self): - self.ui_defaults_view.click(fn=self.ui_view, inputs=list(self.component_mapping.values()), outputs=[self.ui_defaults_review]) - self.ui_defaults_apply.click(fn=self.ui_apply, inputs=list(self.component_mapping.values()), outputs=[self.ui_defaults_review]) - self.ui_defaults_restore.click(fn=self.ui_restore, inputs=[], outputs=[self.ui_defaults_review]) - self.ui_defaults_submenu.click(fn=self.ui_submenu_apply, _js='uiOpenSubmenus', inputs=[self.ui_defaults_review], outputs=[self.ui_defaults_review]) + if self.ui_defaults_view: + self.ui_defaults_view.click(fn=self.ui_view, inputs=list(self.component_mapping.values()), outputs=[self.ui_defaults_review]) + if self.ui_defaults_apply: + self.ui_defaults_apply.click(fn=self.ui_apply, inputs=list(self.component_mapping.values()), outputs=[self.ui_defaults_review]) + if self.ui_defaults_restore: + self.ui_defaults_restore.click(fn=self.ui_restore, inputs=[], outputs=[self.ui_defaults_review]) + if self.ui_defaults_submenu: + self.ui_defaults_submenu.click(fn=self.ui_submenu_apply, _js='uiOpenSubmenus', inputs=[self.ui_defaults_review], outputs=[self.ui_defaults_review]) diff --git a/modules/ui_sections.py b/modules/ui_sections.py index b9f27781e..7b95ce282 100644 --- a/modules/ui_sections.py +++ b/modules/ui_sections.py @@ -20,11 +20,11 @@ def create_toprow(is_img2img: bool = False, id_part: str = None, generate_visibl with gr.Row(): with gr.Column(scale=80): with gr.Row(elem_id=f"{id_part}_prompt_row"): - prompt = gr.Textbox(elem_id=f"{id_part}_prompt", label="Prompt", show_label=False, lines=3 if negative_visible else 5, placeholder="Prompt", elem_classes=["prompt"]) + prompt = gr.Textbox(elem_id=f"{id_part}_prompt", label="Prompt", show_label=False, lines=3 if negative_visible else 5, placeholder="Prompt", elem_classes=["prompt", "main-prompts"]) with gr.Row(): with gr.Column(scale=80): with gr.Row(elem_id=f"{id_part}_negative_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"], visible=negative_visible) + 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", "main-prompts"], visible=negative_visible) with gr.Column(scale=1, elem_id=f"{id_part}_actions_column"): with gr.Row(elem_id=f"{id_part}_generate_box"): reprocess = [] diff --git a/modules/ui_settings.py b/modules/ui_settings.py index 5a3cc5cdf..330bba6b8 100644 --- a/modules/ui_settings.py +++ b/modules/ui_settings.py @@ -56,6 +56,8 @@ def create_setting_component(key, is_quicksettings=False): info = shared.opts.data_labels[key] t = type(info.default) args = (info.component_args() if callable(info.component_args) else info.component_args) or {} + if 'settings' in shared.opts.ui_disabled: + args['visible'] = False if info.component is not None: comp = info.component elif t == str: @@ -171,16 +173,35 @@ def run_settings_single(value, key, progress=False): return get_value_for_setting(key), shared.opts.dumpjson() -def create_ui(): +def create_ui(disabled_tabs=[]): shared.log.debug('UI initialize: tab=settings') global text_settings # pylint: disable=global-statement text_settings = gr.Textbox(elem_id="settings_json", elem_classes=["settings_json"], value=lambda: shared.opts.dumpjson(), visible=False) - with gr.Row(elem_id="system_row"): - unload_sd_model = gr.Button(value='Unload model', variant='primary', elem_id="sett_unload_sd_model") - reload_sd_model = gr.Button(value='Reload model', variant='primary', elem_id="sett_reload_sd_model") - restart_submit = gr.Button(value="Restart server", variant='primary', elem_id="restart_submit") - shutdown_submit = gr.Button(value="Shutdown server", variant='primary', elem_id="shutdown_submit") - enable_profiling = gr.Button(value='Start profiling', variant='primary', elem_id="enable_profiling") + + def unload_sd_weights(): + sd_models.unload_model_weights(op='model') + sd_models.unload_model_weights(op='refiner') + + def reload_sd_weights(): + sd_models.reload_model_weights(force=True) + + def switch_profiling(): + shared.cmd_opts.profile = not shared.cmd_opts.profile + shared.log.warning(f'Profiling: {shared.cmd_opts.profile}') + return 'Stop profiling' if shared.cmd_opts.profile else 'Start profiling' + + if 'system' not in disabled_tabs: + with gr.Row(elem_id="system_row"): + unload_sd_model = gr.Button(value='Unload model', variant='primary', elem_id="sett_unload_sd_model") + reload_sd_model = gr.Button(value='Reload model', variant='primary', elem_id="sett_reload_sd_model") + restart_submit = gr.Button(value="Restart server", variant='primary', elem_id="restart_submit") + shutdown_submit = gr.Button(value="Shutdown server", variant='primary', elem_id="shutdown_submit") + enable_profiling = gr.Button(value='Start profiling', variant='primary', elem_id="enable_profiling") + unload_sd_model.click(fn=unload_sd_weights, inputs=[], outputs=[]) + reload_sd_model.click(fn=reload_sd_weights, inputs=[], outputs=[]) + enable_profiling.click(fn=switch_profiling, inputs=[], outputs=[enable_profiling]) + restart_submit.click(fn=lambda: shared.restart_server(restart=True), _js="restartReload") + shutdown_submit.click(fn=lambda: shared.restart_server(restart=False), _js="restartReload") with gr.Tabs(elem_id="system") as system_tabs: global ui_system_tabs # pylint: disable=global-statement @@ -242,61 +263,51 @@ def create_ui(): shared.log.debug(f'Settings: sections={len(sections)} settings={len(shared.opts.list())}/{len(list(shared.opts.data_labels))} quicksettings={len(quicksettings_list)}') - with gr.TabItem("Update", id="system_update", elem_id="tab_update"): - from modules import update - update.create_ui() + if 'update' not in disabled_tabs: + with gr.TabItem("Update", id="system_update", elem_id="tab_update"): + from modules import update + update.create_ui() - with gr.TabItem("User interface", id="system_config", elem_id="tab_config"): - loadsave.create_ui() - create_dirty_indicator("tab_defaults", [], interactive=False) + if 'config' not in disabled_tabs: + with gr.TabItem("User interface", id="system_config", elem_id="tab_config"): + loadsave.create_ui() + create_dirty_indicator("tab_defaults", [], interactive=False) - with gr.TabItem("History", id="system_history", elem_id="tab_history"): - ui_history.create_ui() + if 'history' not in disabled_tabs: + with gr.TabItem("History", id="system_history", elem_id="tab_history"): + ui_history.create_ui() - with gr.TabItem("GPU Monitor", id="system_gpu", elem_id="tab_gpu"): - with gr.Row(elem_id='gpu-controls'): - gpu_start = gr.Button(value="Start", elem_id="gpu_start", variant="primary") - gpu_stop = gr.Button(value="Stop", elem_id="gpu_stop", variant="primary") - gpu_start.click(fn=lambda: None, _js='startGPU', inputs=[], outputs=[]) - gpu_stop.click(fn=lambda: None, _js='disableGPU', inputs=[], outputs=[]) - gr.HTML(''' -
-
- - -
-
- - ''', elem_id='gpu-container', visible=True) + if 'monitor' not in disabled_tabs: + with gr.TabItem("GPU Monitor", id="system_gpu", elem_id="tab_gpu"): + with gr.Row(elem_id='gpu-controls'): + gpu_start = gr.Button(value="Start", elem_id="gpu_start", variant="primary") + gpu_stop = gr.Button(value="Stop", elem_id="gpu_stop", variant="primary") + gpu_start.click(fn=lambda: None, _js='startGPU', inputs=[], outputs=[]) + gpu_stop.click(fn=lambda: None, _js='disableGPU', inputs=[], outputs=[]) + gr.HTML(''' +
+ + + +
+
+
+ ''', elem_id='gpu-container', visible=True) - with gr.TabItem("ONNX", id="onnx_config", elem_id="tab_onnx"): - from modules.onnx_impl import ui as ui_onnx - ui_onnx.create_ui() + if 'onnx' not in disabled_tabs: + with gr.TabItem("ONNX", id="onnx_config", elem_id="tab_onnx"): + from modules.onnx_impl import ui as ui_onnx + ui_onnx.create_ui() - def unload_sd_weights(): - sd_models.unload_model_weights(op='model') - sd_models.unload_model_weights(op='refiner') - - def reload_sd_weights(): - sd_models.reload_model_weights(force=True) - - def switch_profiling(): - shared.cmd_opts.profile = not shared.cmd_opts.profile - shared.log.warning(f'Profiling: {shared.cmd_opts.profile}') - return 'Stop profiling' if shared.cmd_opts.profile else 'Start profiling' - - unload_sd_model.click(fn=unload_sd_weights, inputs=[], outputs=[]) - reload_sd_model.click(fn=reload_sd_weights, inputs=[], outputs=[]) - enable_profiling.click(fn=switch_profiling, inputs=[], outputs=[enable_profiling]) - request_notifications.click(fn=lambda: None, inputs=[], outputs=[], _js='function(){}') + if request_notifications: + request_notifications.click(fn=lambda: None, inputs=[], outputs=[], _js='function(){}') settings_submit.click( fn=call_queue.wrap_gradio_call(run_settings, extra_outputs=[gr.update()]), inputs=components, outputs=[text_settings, result], ) - defaults_submit.click(fn=lambda: shared.restore_defaults(restart=True), _js="restartReload") - restart_submit.click(fn=lambda: shared.restart_server(restart=True), _js="restartReload") - shutdown_submit.click(fn=lambda: shared.restart_server(restart=False), _js="restartReload") + if defaults_submit: + defaults_submit.click(fn=lambda: shared.restore_defaults(restart=True), _js="restartReload") def reset_quicksettings(quick_components):