ability to disable parts of the app

Signed-off-by: Vladimir Mandic <mandic00@live.com>
pull/4356/head
Vladimir Mandic 2025-11-03 19:36:55 -05:00
parent aa42dd9cca
commit 05261e708a
16 changed files with 191 additions and 127 deletions

View File

@ -2,6 +2,15 @@
## Update for 2025-11-03 ## 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** - **Fixes**
- video save to subfolder - video save to subfolder
- `taesd` warn on long decode times - `taesd` warn on long decode times

@ -1 +1 @@
Subproject commit 5d9a6bb44e34bf48eb34582bd70e0eef06b2b451 Subproject commit 9f0e3f3360f5927d05ca8a2e728c80fbbda4c941

View File

@ -120,6 +120,9 @@
{"id":"","label":"Save","localized":"","reload":"","hint":"Save image"}, {"id":"","label":"Save","localized":"","reload":"","hint":"Save image"},
{"id":"","label":"Delete","localized":"","reload":"","hint":"Delete image"}, {"id":"","label":"Delete","localized":"","reload":"","hint":"Delete image"},
{"id":"","label":"Replace","localized":"","reload":"","hint":"Replace 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":"➠ Text","localized":"","reload":"","hint":"Transfer image to text interface"},
{"id":"","label":"➠ Image","localized":"","reload":"","hint":"Transfer image to image interface"}, {"id":"","label":"➠ Image","localized":"","reload":"","hint":"Transfer image to image interface"},
{"id":"","label":"➠ Inpaint","localized":"","reload":"","hint":"Transfer image to inpaint 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":"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 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":"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":"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":"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"}, {"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 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":"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":"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":"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":"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":"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 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":"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":"Width","localized":"","reload":"","hint":"Image width"},
{"id":"","label":"Height","localized":"","reload":"","hint":"Image height"}, {"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 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":"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":"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":"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","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":"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 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":"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"}, {"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":"Adjust end","localized":"","reload":"","hint":"Ending step when sigma adjust occurs"},
{"id":"","label":"Options","localized":"","reload":"","hint":"Options"}, {"id":"","label":"Options","localized":"","reload":"","hint":"Options"},
{"id":"","label":"ControlNet","localized":"","reload":"","hint":"ControlNet is an advanced guidance model"}, {"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","localized":"","reload":"","hint":"Apply additional noise during detailing"},
{"id":"","label":"Renoise end","localized":"","reload":"","hint":"Final step when renoise is applied"}, {"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"}, {"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":"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":"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":"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":"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":"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"}, {"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 end","localized":"","reload":"","hint":"preview end"},
{"id":"","label":"preview start","localized":"","reload":"","hint":"preview start"}, {"id":"","label":"preview start","localized":"","reload":"","hint":"preview start"},
{"id":"","label":"primary model","localized":"","reload":"","hint":"primary model"}, {"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 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 settings","localized":"","reload":"","hint":"processor settings"},
{"id":"","label":"processor unload after use","localized":"","reload":"","hint":"processor unload after use"}, {"id":"","label":"processor unload after use","localized":"","reload":"","hint":"processor unload after use"},

View File

@ -61,7 +61,7 @@ async function initChangelog() {
const search = gradioApp().querySelector('#changelog_search > label> textarea'); const search = gradioApp().querySelector('#changelog_search > label> textarea');
const md = gradioApp().getElementById('changelog_markdown'); const md = gradioApp().getElementById('changelog_markdown');
if (!search || !md) { if (!search || !md) {
error('initChangelog', 'Missing search or markdown elements'); // error('initChangelog', 'Missing search or markdown elements');
return; return;
} }
const searchChangelog = async (e) => { const searchChangelog = async (e) => {

View File

@ -577,7 +577,8 @@ function setupExtraNetworksForTab(tabName) {
async function showNetworks() { async function showNetworks() {
for (const tabName of ['txt2img', 'img2img', 'control', 'video']) { 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'); log('showNetworks');
} }

View File

@ -99,6 +99,7 @@ async function initLogMonitor() {
const el = document.getElementsByTagName('footer')[0]; const el = document.getElementsByTagName('footer')[0];
if (!el) return; if (!el) return;
el.classList.add('log-monitor'); el.classList.add('log-monitor');
if (window.opts.ui_disabled?.includes('logs')) return;
el.innerHTML = ` el.innerHTML = `
<table id="logMonitor" style="width: 100%;"> <table id="logMonitor" style="width: 100%;">
<thead style="display: block; text-align: left; border-bottom: solid 1px var(--button-primary-border-color)"> <thead style="display: block; text-align: left; border-bottom: solid 1px var(--button-primary-border-color)">

View File

@ -74,6 +74,8 @@ function executeCallbacks(queue, arg) {
} }
} }
const anyPromptExists = () => gradioApp().querySelectorAll('.main-prompts').length > 0;
function scheduleAfterUiUpdateCallbacks() { function scheduleAfterUiUpdateCallbacks() {
clearTimeout(uiAfterUpdateTimeout); clearTimeout(uiAfterUpdateTimeout);
uiAfterUpdateTimeout = setTimeout(() => executeCallbacks(uiAfterUpdateCallbacks, 500)); uiAfterUpdateTimeout = setTimeout(() => executeCallbacks(uiAfterUpdateCallbacks, 500));
@ -96,7 +98,7 @@ async function mutationCallback(mutations) {
if (mutationTimer) clearTimeout(mutationTimer); if (mutationTimer) clearTimeout(mutationTimer);
mutationTimer = setTimeout(async () => { mutationTimer = setTimeout(async () => {
if (!executedOnLoaded && gradioApp().getElementById('txt2img_prompt')) { // execute once if (!executedOnLoaded && anyPromptExists()) { // execute once
executedOnLoaded = true; executedOnLoaded = true;
executeCallbacks(uiLoadedCallbacks); executeCallbacks(uiLoadedCallbacks);
} }

View File

@ -168,17 +168,21 @@ async function tooltipHide(e) {
localeData.currentElement = null; localeData.currentElement = null;
} }
async function validateHints(json, elements) { async function validateHints(json, elements, tab) {
json.missing = []; json.missing = [];
const data = Object.values(json).flat().filter((e) => e.hint.length > 0); const data = Object.values(json).flat().filter((e) => e.hint.length > 0);
for (const e of data) e.label = e.label.trim(); 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 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(); let duplicateUI = original.filter((e, i, a) => a.indexOf(e.toLowerCase()) !== i).sort();
original = [...new Set(original)]; // remove duplicates original = [...new Set(original)]; // remove duplicates
duplicateUI = [...new Set(duplicateUI)]; // remove duplicates duplicateUI = [...new Set(duplicateUI)]; // remove duplicates
const current = data.map((e) => e.label.toLowerCase().trim()).sort(); // should be case sensitive const current = data.map((e) => e.label.toLowerCase().trim()).sort(); // should be case sensitive
log('all elements:', original); // log('all elements:', original);
log('all hints:', current); // log('all hints:', current);
log('hints-differences', { elements: original.length, hints: current.length }); log('hints-differences', { elements: original.length, hints: current.length });
const missingHints = original.filter((e) => !current.includes(e.toLowerCase())).sort(); const missingHints = original.filter((e) => !current.includes(e.toLowerCase())).sort();
const orphanedHints = current.filter((e) => !original.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) }); 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(); // sortUIElements();
if (analyze) { if (analyze) {
log('analyzing hints', 'control_tabitem');
const [missingHints, orphanedHints] = await validateHints(json, elements); const [missingHints, orphanedHints] = await validateHints(json, elements);
await addMissingHints(json, missingHints); await addMissingHints(json, missingHints);
await removeOrphanedHints(json, orphanedHints); await removeOrphanedHints(json, orphanedHints);

View File

@ -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("--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("--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("--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(): def compatibility_args():

View File

@ -49,7 +49,7 @@ def wrap_call(func, filename, funcname, *args, default=None, **kwargs):
class ScriptPostprocessingRunner: class ScriptPostprocessingRunner:
def __init__(self): def __init__(self):
self.scripts = None self.scripts = []
self.ui_created = False self.ui_created = False
def initialize_scripts(self, scripts_data): def initialize_scripts(self, scripts_data):

View File

@ -570,6 +570,9 @@ options_templates.update(options_section(('ui', "User Interface"), {
"subpath": OptionInfo("", "Mount URL subpath"), "subpath": OptionInfo("", "Mount URL subpath"),
"ui_request_timeout": OptionInfo(120000, "UI request timeout", gr.Slider, {"minimum": 1000, "maximum": 300000, "step": 10}), "ui_request_timeout": OptionInfo(120000, "UI request timeout", gr.Slider, {"minimum": 1000, "maximum": 300000, "step": 10}),
"ui_tabs": OptionInfo("<h2>UI Tabs</h2>", "", gr.HTML),
"ui_disabled": OptionInfo("", "Disabled UI tabs", gr.Textbox, { 'visible': False }),
"cards_sep_ui": OptionInfo("<h2>Networks panel</h2>", "", gr.HTML), "cards_sep_ui": OptionInfo("<h2>Networks panel</h2>", "", gr.HTML),
"extra_networks_card_size": OptionInfo(140, "Network card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}), "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"]}), "extra_networks_card_cover": OptionInfo("sidebar", "Network panel position", gr.Radio, {"choices": ["cover", "inline", "sidebar"]}),

View File

@ -69,86 +69,98 @@ def setup_progressbar(*args, **kwargs): # pylint: disable=unused-argument
def create_ui(startup_timer = None): def create_ui(startup_timer = None):
global interfaces # pylint: disable=global-statement
if startup_timer is None: if startup_timer is None:
timer.startup = timer.Timer() timer.startup = timer.Timer()
ui_javascript.reload_javascript() ui_javascript.reload_javascript()
generation_parameters_copypaste.reset() generation_parameters_copypaste.reset()
scripts_manager.scripts_current = None 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: if 'txt2img' not in ui_disabled:
from modules import ui_txt2img with gr.Blocks(analytics_enabled=False) as txt2img_interface:
ui_txt2img.create_ui() from modules import ui_txt2img
timer.startup.record("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: if 'img2img' not in ui_disabled:
from modules import ui_img2img with gr.Blocks(analytics_enabled=False) as img2img_interface:
ui_img2img.create_ui() from modules import ui_img2img
timer.startup.record("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: if 'control' not in ui_disabled:
from modules import ui_control with gr.Blocks(analytics_enabled=False) as control_interface:
ui_control.create_ui() from modules import ui_control
timer.startup.record("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: if 'video' not in ui_disabled:
from modules import ui_video with gr.Blocks(analytics_enabled=False) as video_interface:
ui_video.create_ui() from modules import ui_video
timer.startup.record("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: if 'extras' not in ui_disabled:
from modules import ui_postprocessing with gr.Blocks(analytics_enabled=False) as extras_interface:
ui_postprocessing.create_ui() from modules import ui_postprocessing
timer.startup.record("ui-extras") ui_postprocessing.create_ui()
timer.startup.record("ui-extras")
interfaces += [(extras_interface, "Process", "process")]
with gr.Blocks(analytics_enabled=False) as caption_interface: if 'caption' not in ui_disabled:
from modules import ui_caption with gr.Blocks(analytics_enabled=False) as caption_interface:
ui_caption.create_ui() from modules import ui_caption
timer.startup.record("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: if 'models' not in ui_disabled:
from modules import ui_models with gr.Blocks(analytics_enabled=False) as models_interface:
ui_models.create_ui() from modules import ui_models
timer.startup.record("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: if 'gallery' not in ui_disabled:
from modules import ui_gallery with gr.Blocks(analytics_enabled=False) as gallery_interface:
ui_gallery.create_ui() from modules import ui_gallery
timer.startup.record("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: with gr.Blocks(analytics_enabled=False) as settings_interface:
from modules import ui_settings from modules import ui_settings
ui_settings.create_ui() ui_settings.create_ui(ui_disabled)
global ui_system_tabs # pylint: disable=global-statement global ui_system_tabs # pylint: disable=global-statement
ui_system_tabs = ui_settings.ui_system_tabs ui_system_tabs = ui_settings.ui_system_tabs
shared.opts.reorder() shared.opts.reorder()
timer.startup.record("ui-extensions") timer.startup.record("ui-extensions")
interfaces += [(settings_interface, "System", "system")]
with gr.Blocks(analytics_enabled=False) as info_interface: if 'info' not in ui_disabled:
from modules import ui_docs with gr.Blocks(analytics_enabled=False) as info_interface:
ui_docs.create_ui() from modules import ui_docs
timer.startup.record("ui-info") ui_docs.create_ui()
timer.startup.record("ui-info")
interfaces += [(info_interface, "Info", "info")]
with gr.Blocks(analytics_enabled=False) as extensions_interface: if 'extensions' not in ui_disabled:
from modules import ui_extensions with gr.Blocks(analytics_enabled=False) as extensions_interface:
ui_extensions.create_ui() from modules import ui_extensions
timer.startup.record("ui-extensions") ui_extensions.create_ui()
timer.startup.record("ui-extensions")
global interfaces # pylint: disable=global-statement interfaces += [(extensions_interface, "Extensions", "extensions")]
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")]
ui_app = ui_settings.create_quicksettings(interfaces) ui_app = ui_settings.create_quicksettings(interfaces)

View File

@ -603,6 +603,8 @@ class ExtraNetworksUi:
def create_ui(container, button_parent, tabname, skip_indexing = False): 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}') debug(f'EN create-ui: {tabname}')
ui = ExtraNetworksUi() ui = ExtraNetworksUi()
ui.tabname = tabname 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): def setup_ui(ui, gallery: gr.Gallery = None):
if ui is None:
return
ui.gallery = gallery ui.gallery = gallery

View File

@ -290,7 +290,11 @@ class UiLoadsave:
self.ui_defaults_review = gr.HTML("", elem_id="ui_defaults_review") self.ui_defaults_review = gr.HTML("", elem_id="ui_defaults_review")
def setup_ui(self): def setup_ui(self):
self.ui_defaults_view.click(fn=self.ui_view, inputs=list(self.component_mapping.values()), outputs=[self.ui_defaults_review]) if self.ui_defaults_view:
self.ui_defaults_apply.click(fn=self.ui_apply, inputs=list(self.component_mapping.values()), outputs=[self.ui_defaults_review]) self.ui_defaults_view.click(fn=self.ui_view, 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]) if self.ui_defaults_apply:
self.ui_defaults_submenu.click(fn=self.ui_submenu_apply, _js='uiOpenSubmenus', inputs=[self.ui_defaults_review], 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])
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])

View File

@ -20,11 +20,11 @@ def create_toprow(is_img2img: bool = False, id_part: str = None, generate_visibl
with gr.Row(): with gr.Row():
with gr.Column(scale=80): with gr.Column(scale=80):
with gr.Row(elem_id=f"{id_part}_prompt_row"): 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.Row():
with gr.Column(scale=80): with gr.Column(scale=80):
with gr.Row(elem_id=f"{id_part}_negative_row"): 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.Column(scale=1, elem_id=f"{id_part}_actions_column"):
with gr.Row(elem_id=f"{id_part}_generate_box"): with gr.Row(elem_id=f"{id_part}_generate_box"):
reprocess = [] reprocess = []

View File

@ -56,6 +56,8 @@ def create_setting_component(key, is_quicksettings=False):
info = shared.opts.data_labels[key] info = shared.opts.data_labels[key]
t = type(info.default) t = type(info.default)
args = (info.component_args() if callable(info.component_args) else info.component_args) or {} 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: if info.component is not None:
comp = info.component comp = info.component
elif t == str: elif t == str:
@ -171,16 +173,35 @@ def run_settings_single(value, key, progress=False):
return get_value_for_setting(key), shared.opts.dumpjson() return get_value_for_setting(key), shared.opts.dumpjson()
def create_ui(): def create_ui(disabled_tabs=[]):
shared.log.debug('UI initialize: tab=settings') shared.log.debug('UI initialize: tab=settings')
global text_settings # pylint: disable=global-statement 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) 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") def unload_sd_weights():
reload_sd_model = gr.Button(value='Reload model', variant='primary', elem_id="sett_reload_sd_model") sd_models.unload_model_weights(op='model')
restart_submit = gr.Button(value="Restart server", variant='primary', elem_id="restart_submit") sd_models.unload_model_weights(op='refiner')
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 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: with gr.Tabs(elem_id="system") as system_tabs:
global ui_system_tabs # pylint: disable=global-statement 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)}') 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"): if 'update' not in disabled_tabs:
from modules import update with gr.TabItem("Update", id="system_update", elem_id="tab_update"):
update.create_ui() from modules import update
update.create_ui()
with gr.TabItem("User interface", id="system_config", elem_id="tab_config"): if 'config' not in disabled_tabs:
loadsave.create_ui() with gr.TabItem("User interface", id="system_config", elem_id="tab_config"):
create_dirty_indicator("tab_defaults", [], interactive=False) loadsave.create_ui()
create_dirty_indicator("tab_defaults", [], interactive=False)
with gr.TabItem("History", id="system_history", elem_id="tab_history"): if 'history' not in disabled_tabs:
ui_history.create_ui() 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"): if 'monitor' not in disabled_tabs:
with gr.Row(elem_id='gpu-controls'): with gr.TabItem("GPU Monitor", id="system_gpu", elem_id="tab_gpu"):
gpu_start = gr.Button(value="Start", elem_id="gpu_start", variant="primary") with gr.Row(elem_id='gpu-controls'):
gpu_stop = gr.Button(value="Stop", elem_id="gpu_stop", variant="primary") gpu_start = gr.Button(value="Start", elem_id="gpu_start", variant="primary")
gpu_start.click(fn=lambda: None, _js='startGPU', inputs=[], outputs=[]) gpu_stop = gr.Button(value="Stop", elem_id="gpu_stop", variant="primary")
gpu_stop.click(fn=lambda: None, _js='disableGPU', inputs=[], outputs=[]) gpu_start.click(fn=lambda: None, _js='startGPU', inputs=[], outputs=[])
gr.HTML(''' gpu_stop.click(fn=lambda: None, _js='disableGPU', inputs=[], outputs=[])
<div class="gpu" id="gpu"> gr.HTML('''
<table class="gpu-table" id="gpu-table"> <div class="gpu" id="gpu">
<thead><tr><th></th><th></th></tr></thead> <table class="gpu-table" id="gpu-table">
<tbody></tbody> <thead><tr><th></th><th></th></tr></thead>
</table> <tbody></tbody>
<div id="gpuChart"></div> </table>
</div> <div id="gpuChart"></div>
''', elem_id='gpu-container', visible=True) </div>
''', elem_id='gpu-container', visible=True)
with gr.TabItem("ONNX", id="onnx_config", elem_id="tab_onnx"): if 'onnx' not in disabled_tabs:
from modules.onnx_impl import ui as ui_onnx with gr.TabItem("ONNX", id="onnx_config", elem_id="tab_onnx"):
ui_onnx.create_ui() from modules.onnx_impl import ui as ui_onnx
ui_onnx.create_ui()
def unload_sd_weights(): if request_notifications:
sd_models.unload_model_weights(op='model') request_notifications.click(fn=lambda: None, inputs=[], outputs=[], _js='function(){}')
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(){}')
settings_submit.click( settings_submit.click(
fn=call_queue.wrap_gradio_call(run_settings, extra_outputs=[gr.update()]), fn=call_queue.wrap_gradio_call(run_settings, extra_outputs=[gr.update()]),
inputs=components, inputs=components,
outputs=[text_settings, result], outputs=[text_settings, result],
) )
defaults_submit.click(fn=lambda: shared.restore_defaults(restart=True), _js="restartReload") if defaults_submit:
restart_submit.click(fn=lambda: shared.restart_server(restart=True), _js="restartReload") defaults_submit.click(fn=lambda: shared.restore_defaults(restart=True), _js="restartReload")
shutdown_submit.click(fn=lambda: shared.restart_server(restart=False), _js="restartReload")
def reset_quicksettings(quick_components): def reset_quicksettings(quick_components):