add light theme, enhance profilng and logging

This commit is contained in:
Vladimir Mandic
2023-09-06 13:23:11 -04:00
parent e3268bf6c4
commit ac267d7f3f
22 changed files with 501 additions and 198 deletions
+5 -3
View File
@@ -5,10 +5,14 @@
One week later, another large update!
- system:
- new default theme: **black-teal**
- full **python 3.11** support
note that changing python version does require reinstall
and if you're already on python 3.10, really no need to upgrade
- themes:
- new default theme: **black-teal**
- new light theme: **light-teal**
- new additional theme: **midnight-barbie**
thanks @nyxia
- extra networks:
- support for **tags**
show tags on hover, search by tag, list tags, add to prompt, etc.
@@ -44,8 +48,6 @@ One week later, another large update!
- added **force zeros** setting
create zero-tensor for prompt if prompt is empty (positive or negative)
- general:
- new additional theme: **midnight-barbie**
thanks @nyxia
- `rembg` remove backgrounds support for **is-net** model
- **settings** now show markers for all items set to non-default values
- **metadata** refactored how/what/when metadata is added to images
Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

+1 -1
View File
@@ -158,7 +158,7 @@ svg.feather.feather-image, .feather .feather-image { display: none }
--checkbox-border-color: var(--neutral-700);
--checkbox-border-color-focus: var(--secondary-500);
--checkbox-border-color-hover: var(--neutral-600);
--checkbox-border-color-selected: var(--secondary-600);
--checkbox-border-color-selected: var(--primary-600);
--checkbox-border-width: var(--input-border-width);
--checkbox-label-background-fill: None;
--checkbox-label-background-fill-hover: None;
+15 -16
View File
@@ -17,10 +17,19 @@
--primary-950: #193232;
--highlight-color: var(--primary-200);
--inactive-color: var(--primary--800);
--body-text-color: var(--neutral-100);
--body-text-color-subdued: var(--neutral-300);
--background-color: #000000;
--background-fill-primary: var(--neutral-700);
--input-padding: 4px;
--radius-lg: 4px;
--input-background-fill: var(--neutral-800);
--input-shadow: 2px 2px 2px 2px var(--background-color);
--button-secondary-text-color: white;
--button-secondary-background-fill: linear-gradient(to bottom right, var(--neutral-400), var(--neutral-700));
--button-secondary-background-fill-hover: linear-gradient(to bottom right, var(--neutral-700), var(--neutral-400));
--block-title-text-color: var(--neutral-900);
--radius-sm: 2px;
--radius-lg: 4px;
--spacing-md: 4px;
--spacing-xxl: 8px;
--line-sm: 1.2em;
@@ -31,7 +40,6 @@ html { font-size: var(--font-size); }
body, button, input, select, textarea { font-family: var(--font);}
button { font-size: 1.2rem; max-width: 400px; }
img { background-color: var(--background-color); }
input[type=checkbox] { background-color: transparent !important; }
input[type=range] { height: var(--line-sm); appearance: none; margin-top: 0; min-width: 160px; background-color: var(--background-color); width: 100%; background: transparent; }
input[type=range]::-webkit-slider-runnable-track { width: 100%; height: var(--line-sm); cursor: pointer; box-shadow: 2px 2px 3px #111111; background: var(--input-background-fill); border-radius: var(--radius-lg); border: 0px solid #222222; }
input[type=range]::-moz-range-track { width: 100%; height: var(--line-sm); cursor: pointer; box-shadow: 2px 2px 3px #111111; background: var(--input-background-fill); border-radius: var(--radius-lg); border: 0px solid #222222; }
@@ -68,7 +76,7 @@ svg.feather.feather-image, .feather .feather-image { display: none }
.px-4 { padding-lefT: 1rem; padding-right: 1rem; }
.py-6 { padding-bottom: 0; }
.tabs { background-color: var(--background-color); }
.block.token-counter span { background-color: #222 !important; box-shadow: 2px 2px 2px #111; border: none !important; font-size: 0.8rem; }
.block.token-counter span { background-color: var(--input-background-fill) !important; box-shadow: 2px 2px 2px #111; border: none !important; font-size: 0.8rem; }
.tab-nav { zoom: 120%; margin-bottom: 10px; border-bottom: 2px solid var(--highlight-color) !important; padding-bottom: 2px; }
.label-wrap { margin: 16px 0px 8px 0px; }
.gradio-slider input[type="number"] { width: 4.5em; font-size: 0.8rem; height: 20px; }
@@ -122,9 +130,7 @@ svg.feather.feather-image, .feather .feather-image { display: none }
/* based on gradio built-in dark theme */
:root, .light, .dark {
--body-background-fill: var(--background-color);
--body-text-color: var(--neutral-100);
--color-accent-soft: var(--neutral-700);
--background-fill-primary: #222222;
--background-fill-secondary: none;
--border-color-accent: var(--background-color);
--border-color-primary: var(--background-color);
@@ -132,7 +138,6 @@ svg.feather.feather-image, .feather .feather-image { display: none }
--link-text-color: var(--secondary-500);
--link-text-color-hover: var(--secondary-400);
--link-text-color-visited: var(--secondary-600);
--body-text-color-subdued: var(--neutral-400);
--shadow-spread: 1px;
--block-background-fill: None;
--block-border-color: var(--border-color-primary);
@@ -146,18 +151,17 @@ svg.feather.feather-image, .feather .feather-image { display: none }
--block_title_background_fill: None;
--block_title_border_color: None;
--block_title_border_width: None;
--block-title-text-color: white;
--panel-background-fill: var(--background-fill-secondary);
--panel-border-color: var(--border-color-primary);
--panel_border_width: None;
--checkbox-background-color: var(--neutral-800);
--checkbox-background-color: var(--neutral-500);
--checkbox-background-color-focus: var(--checkbox-background-color);
--checkbox-background-color-hover: var(--checkbox-background-color);
--checkbox-background-color-selected: var(--secondary-600);
--checkbox-border-color: var(--neutral-700);
--checkbox-background-color-selected: var(--primary-500);
--checkbox-border-color: transparent;
--checkbox-border-color-focus: var(--secondary-500);
--checkbox-border-color-hover: var(--neutral-600);
--checkbox-border-color-selected: var(--secondary-600);
--checkbox-border-color-selected: var(--primary-600);
--checkbox-border-width: var(--input-border-width);
--checkbox-label-background-fill: None;
--checkbox-label-background-fill-hover: None;
@@ -171,7 +175,6 @@ svg.feather.feather-image, .feather .feather-image { display: none }
--error-border-color: var(--border-color-primary);
--error_border_width: None;
--error-text-color: #ef4444;
--input-background-fill: var(--neutral-800);
--input-background-fill-focus: var(--secondary-600);
--input-background-fill-hover: var(--input-background-fill);
--input-border-color: var(--border-color-primary);
@@ -179,7 +182,6 @@ svg.feather.feather-image, .feather .feather-image { display: none }
--input-border-color-hover: var(--input-border-color);
--input_border_width: None;
--input-placeholder-color: var(--neutral-500);
--input-shadow: 2px 2px 2px 2px #111111;
--input-shadow-focus: 2px 2px 2px 2px #111111;
--loader_color: None;
--slider_color: None;
@@ -201,11 +203,8 @@ svg.feather.feather-image, .feather .feather-image { display: none }
--button-primary-border-color-hover: var(--button-primary-border-color);
--button-primary-text-color: white;
--button-primary-text-color-hover: var(--button-primary-text-color);
--button-secondary-background-fill: linear-gradient(to bottom right, var(--neutral-600), var(--neutral-800));
--button-secondary-background-fill-hover: linear-gradient(to bottom right, var(--neutral-600), var(--neutral-400));
--button-secondary-border-color: var(--neutral-600);
--button-secondary-border-color-hover: var(--button-secondary-border-color);
--button-secondary-text-color: white;
--button-secondary-text-color-hover: var(--button-secondary-text-color);
--secondary-50: #eff6ff;
--secondary-100: #dbeafe;
+1 -1
View File
@@ -187,7 +187,7 @@ function setupExtraNetworksForTab(tabname) {
gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 'unset';
} else if (window.opts.extra_networks_card_cover === 'sidebar') {
en.style.transition = 'width 0.2s ease';
en.style.zIndex = 0;
en.style.zIndex = 9999;
en.style.position = 'absolute';
en.style.right = '0';
en.style.width = `${window.opts.extra_networks_sidebar_width}vw`;
+315
View File
@@ -0,0 +1,315 @@
/* generic html tags */
:root, .light, .dark {
--font: 'system-ui', 'ui-sans-serif', 'system-ui', "Roboto", sans-serif;
--font-mono: 'ui-monospace', 'Consolas', monospace;
--font-size: 16px;
--left-column: 490px;
--primary-50: #7dffff;
--primary-100: #72e8e8;
--primary-200: #67d2d2;
--primary-300: #5dbcbc;
--primary-400: #52a7a7;
--primary-500: #489292;
--primary-600: #3e7d7d;
--primary-700: #356969;
--primary-800: #2b5656;
--primary-900: #224444;
--primary-950: #193232;
--highlight-color: var(--primary-200);
--inactive-color: var(--primary--800);
--body-text-color: var(--neutral-800);
--body-text-color-subdued: var(--neutral-600);
--background-color: #FFFFFF;
--background-fill-primary: var(--neutral-400);
--input-padding: 4px;
--input-background-fill: var(--neutral-300);
--input-shadow: 2px 2px 2px 2px var(--neutral-500);
--button-secondary-text-color: black;
--button-secondary-background-fill: linear-gradient(to bottom right, var(--neutral-200), var(--neutral-500));
--button-secondary-background-fill-hover: linear-gradient(to bottom right, var(--neutral-500), var(--neutral-200));
--block-title-text-color: var(--neutral-900);
--radius-sm: 2px;
--radius-lg: 4px;
--spacing-md: 4px;
--spacing-xxl: 8px;
--line-sm: 1.2em;
--line-md: 1.4em;
}
html { font-size: var(--font-size); }
body, button, input, select, textarea { font-family: var(--font);}
button { font-size: 1.2rem; max-width: 400px; }
img { background-color: var(--background-color); }
input[type=range] { height: var(--line-sm); appearance: none; margin-top: 0; min-width: 160px; background-color: var(--background-color); width: 100%; background: transparent; }
input[type=range]::-webkit-slider-runnable-track { width: 100%; height: var(--line-sm); cursor: pointer; box-shadow: 2px 2px 3px #111111; background: var(--input-background-fill); border-radius: var(--radius-lg); border: 0px solid #222222; }
input[type=range]::-moz-range-track { width: 100%; height: var(--line-sm); cursor: pointer; box-shadow: 2px 2px 3px #111111; background: var(--input-background-fill); border-radius: var(--radius-lg); border: 0px solid #222222; }
input[type=range]::-webkit-slider-thumb { box-shadow: 2px 2px 3px #111111; border: 0px solid #000000; height: var(--line-sm); width: var(--line-sm); border-radius: var(--radius-lg); background: var(--highlight-color); cursor: pointer; appearance: none; margin-top: 0px; }
input[type=range]::-moz-range-thumb { box-shadow: 2px 2px 3px #111111; border: 0px solid #000000; height: var(--line-sm); width: var(--line-sm); border-radius: var(--radius-lg); background: var(--highlight-color); cursor: pointer; appearance: none; margin-top: 0px; }
::-webkit-scrollbar { width: 12px; }
::-webkit-scrollbar-track { background: #333333; }
::-webkit-scrollbar-thumb { background-color: var(--highlight-color); border-radius: var(--radius-lg); border-width: 0; box-shadow: 2px 2px 3px #111111; }
div.form { border-width: 0; box-shadow: none; background: transparent; overflow: visible; margin-bottom: 6px; }
div.compact { gap: 1em; }
/* gradio style classes */
fieldset .gr-block.gr-box, label.block span { padding: 0; margin-top: -4px; }
.border-2 { border-width: 0; }
.border-b-2 { border-bottom-width: 2px; border-color: var(--highlight-color) !important; padding-bottom: 2px; margin-bottom: 8px; }
.bg-white { color: lightyellow; background-color: var(--inactive-color); }
.gr-box { border-radius: var(--radius-sm) !important; background-color: #111111 !important; box-shadow: 2px 2px 3px #111111; border-width: 0; padding: 4px; margin: 12px 0px 12px 0px }
.gr-button { font-weight: normal; box-shadow: 2px 2px 3px #111111; font-size: 0.8rem; min-width: 32px; min-height: 32px; padding: 3px; margin: 3px; }
.gr-check-radio { background-color: var(--inactive-color); border-width: 0; border-radius: var(--radius-lg); box-shadow: 2px 2px 3px #111111; }
.gr-check-radio:checked { background-color: var(--highlight-color); }
.gr-compact { background-color: var(--background-color); }
.gr-form { border-width: 0; }
.gr-input { background-color: #333333 !important; padding: 4px; margin: 4px; }
.gr-input-label { color: lightyellow; border-width: 0; background: transparent; padding: 2px !important; }
.gr-panel { background-color: var(--background-color); }
.eta-bar { display: none !important }
svg.feather.feather-image, .feather .feather-image { display: none }
.gap-2 { padding-top: 8px; }
.gr-box > div > div > input.gr-text-input { right: 0; width: 4em; padding: 0; top: -12px; border: none; max-height: 20px; }
.output-html { line-height: 1.2rem; overflow-x: hidden; }
.output-html > div { margin-bottom: 8px; }
.overflow-hidden .flex .flex-col .relative col .gap-4 { min-width: var(--left-column); max-width: var(--left-column); } /* this is a problematic one */
.p-2 { padding: 0; }
.px-4 { padding-lefT: 1rem; padding-right: 1rem; }
.py-6 { padding-bottom: 0; }
.tabs { background-color: var(--background-color); }
.block.token-counter span { background-color: var(--input-background-fill) !important; box-shadow: 2px 2px 2px #111; border: none !important; font-size: 0.8rem; }
.tab-nav { zoom: 120%; margin-bottom: 10px; border-bottom: 2px solid var(--highlight-color) !important; padding-bottom: 2px; }
.label-wrap { margin: 16px 0px 8px 0px; }
.gradio-slider input[type="number"] { width: 4.5em; font-size: 0.8rem; height: 20px; }
.gradio-button.tool { border: none; background: none; box-shadow: none; filter: hue-rotate(340deg) saturate(0.5); }
#tab_extensions table td, #tab_extensions table th { border: none; padding: 0.5em; }
#tab_extensions table { width: 96vw }
#tab_extensions table thead { background-color: var(--neutral-700); }
/* automatic style classes */
.progressDiv { border-radius: var(--radius-sm) !important; position: fixed; top: 44px; right: 26px; max-width: 262px; height: 48px; z-index: 99; box-shadow: var(--button-shadow); }
.progressDiv .progress { border-radius: var(--radius-lg) !important; background: var(--highlight-color); line-height: 3rem; height: 48px; }
.gallery-item { box-shadow: none !important; }
.performance { color: #888; }
.extra-networks { border-left: 2px solid var(--highlight-color) !important; padding-left: 4px; }
.image-buttons { gap: 10px !important; justify-content: center; }
.image-buttons > button { max-width: 160px; }
#system_row > button, #settings_row > button, #config_row > button { max-width: 190px; }
/* gradio elements overrides */
#div.gradio-container { overflow-x: hidden; }
#img2img_label_copy_to_img2img { font-weight: normal; }
#txt2img_prompt, #txt2img_neg_prompt, #img2img_prompt, #img2img_neg_prompt { background-color: var(--background-color); box-shadow: 4px 4px 4px 0px #333333 !important; }
#txt2img_prompt > label > textarea, #txt2img_neg_prompt > label > textarea, #img2img_prompt > label > textarea, #img2img_neg_prompt > label > textarea { font-size: 1.1rem; }
#img2img_settings { min-width: calc(2 * var(--left-column)); max-width: calc(2 * var(--left-column)); background-color: #111111; padding-top: 16px; }
#interrogate, #deepbooru { margin: 0 0px 10px 0px; max-width: 80px; max-height: 80px; font-weight: normal; font-size: 0.95em; }
#quicksettings .gr-button-tool { font-size: 1.6rem; box-shadow: none; margin-left: -20px; margin-top: -2px; height: 2.4em; }
#quicksettings > div, #quicksettings > fieldset { line-height: 1.4em; margin-top: 0.4em; }
#open_folder_extras, #footer, #style_pos_col, #style_neg_col, #roll_col, #extras_upscaler_2, #extras_upscaler_2_visibility, #txt2img_seed_resize_from_w, #txt2img_seed_resize_from_h { display: none; }
#save-animation { border-radius: var(--radius-sm) !important; margin-bottom: 16px; background-color: #111111; }
#script_list { padding: 4px; margin-top: 20px; margin-bottom: 20px; }
#settings > div.flex-wrap { width: 15em; }
#tab_extensions table { background-color: #222222; }
#txt2img_cfg_scale { min-width: 200px; }
#txt2img_checkboxes, #img2img_checkboxes { background-color: transparent; }
#txt2img_checkboxes, #img2img_checkboxes { margin-bottom: 0.2em; }
#txt2img_actions_column, #img2img_actions_column { flex-flow: wrap; justify-content: space-between; }
#txt2img_enqueue_wrapper, #img2img_enqueue_wrapper { min-width: unset; width: 48%; }
#txt2img_generate_box, #img2img_generate_box { min-width: unset; width: 48%; }
#extras_upscale { margin-top: 10px }
#txt2img_progress_row > div { min-width: var(--left-column); max-width: var(--left-column); }
#txt2img_results, #img2img_results, #extras_results { background-color: var(--background-color); padding: 0; }
#txt2img_settings { min-width: var(--left-column); max-width: var(--left-column); background-color: #111111; padding-top: 16px; }
#pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) }
#txt2img_tools, #img2img_tools { margin-top: -4px; margin-bottom: -4px; }
#txt2img_styles_row, #img2img_styles_row { margin-top: -6px; }
/* custom elements overrides */
#steps-animation, #controlnet { border-width: 0; }
/* based on gradio built-in dark theme */
:root, .light, .dark {
--body-background-fill: var(--background-color);
--color-accent-soft: var(--neutral-700);
--background-fill-secondary: none;
--border-color-accent: var(--background-color);
--border-color-primary: var(--background-color);
--link-text-color-active: var(--secondary-500);
--link-text-color: var(--secondary-500);
--link-text-color-hover: var(--secondary-400);
--link-text-color-visited: var(--secondary-600);
--shadow-spread: 1px;
--block-background-fill: None;
--block-border-color: var(--border-color-primary);
--block_border_width: None;
--block-info-text-color: var(--body-text-color-subdued);
--block-label-background-fill: var(--background-fill-secondary);
--block-label-border-color: var(--border-color-primary);
--block_label_border_width: None;
--block-label-text-color: var(--neutral-200);
--block_shadow: None;
--block_title_background_fill: None;
--block_title_border_color: None;
--block_title_border_width: None;
--panel-background-fill: var(--background-fill-secondary);
--panel-border-color: var(--border-color-primary);
--panel_border_width: None;
--checkbox-background-color: var(--neutral-500);
--checkbox-background-color-focus: var(--checkbox-background-color);
--checkbox-background-color-hover: var(--checkbox-background-color);
--checkbox-background-color-selected: var(--primary-500);
--checkbox-border-color: transparent;
--checkbox-border-color-focus: var(--secondary-500);
--checkbox-border-color-hover: var(--neutral-600);
--checkbox-border-color-selected: var(--primary-600);
--checkbox-border-width: var(--input-border-width);
--checkbox-label-background-fill: None;
--checkbox-label-background-fill-hover: None;
--checkbox-label-background-fill-selected: var(--checkbox-label-background-fill);
--checkbox-label-border-color: var(--border-color-primary);
--checkbox-label-border-color-hover: var(--checkbox-label-border-color);
--checkbox-label-border-width: var(--input-border-width);
--checkbox-label-text-color: var(--body-text-color);
--checkbox-label-text-color-selected: var(--checkbox-label-text-color);
--error-background-fill: var(--background-fill-primary);
--error-border-color: var(--border-color-primary);
--error_border_width: None;
--error-text-color: #ef4444;
--input-background-fill-focus: var(--secondary-600);
--input-background-fill-hover: var(--input-background-fill);
--input-border-color: var(--border-color-primary);
--input-border-color-focus: var(--neutral-700);
--input-border-color-hover: var(--input-border-color);
--input_border_width: None;
--input-placeholder-color: var(--neutral-500);
--input-shadow-focus: 2px 2px 2px 2px #111111;
--loader_color: None;
--slider_color: None;
--stat-background-fill: linear-gradient(to right, var(--primary-400), var(--primary-600));
--table-border-color: var(--neutral-700);
--table-even-background-fill: #222222;
--table-odd-background-fill: #333333;
--table-row-focus: var(--color-accent-soft);
--button-border-width: var(--input-border-width);
--button-cancel-background-fill: linear-gradient(to bottom right, #dc2626, #b91c1c);
--button-cancel-background-fill-hover: linear-gradient(to bottom right, #dc2626, #dc2626);
--button-cancel-border-color: #dc2626;
--button-cancel-border-color-hover: var(--button-cancel-border-color);
--button-cancel-text-color: white;
--button-cancel-text-color-hover: var(--button-cancel-text-color);
--button-primary-background-fill: linear-gradient(to bottom right, var(--primary-500), var(--primary-800));
--button-primary-background-fill-hover: linear-gradient(to bottom right, var(--primary-500), var(--primary-300));
--button-primary-border-color: var(--primary-500);
--button-primary-border-color-hover: var(--button-primary-border-color);
--button-primary-text-color: white;
--button-primary-text-color-hover: var(--button-primary-text-color);
--button-secondary-border-color: var(--neutral-600);
--button-secondary-border-color-hover: var(--button-secondary-border-color);
--button-secondary-text-color-hover: var(--button-secondary-text-color);
--secondary-50: #eff6ff;
--secondary-100: #dbeafe;
--secondary-200: #bfdbfe;
--secondary-300: #93c5fd;
--secondary-400: #60a5fa;
--secondary-500: #3b82f6;
--secondary-600: #2563eb;
--secondary-700: #1d4ed8;
--secondary-800: #1e40af;
--secondary-900: #1e3a8a;
--secondary-950: #1d3660;
--neutral-50: #f0f0f0;
--neutral-100: #e0e0e0;
--neutral-200: #d0d0d0;
--neutral-300: #b0b0b0;
--neutral-400: #909090;
--neutral-500: #707070;
--neutral-600: #606060;
--neutral-700: #404040;
--neutral-800: #333333;
--neutral-900: #111827;
--neutral-950: #0b0f19;
--spacing-xxs: 1px;
--spacing-xs: 2px;
--spacing-sm: 4px;
--spacing-lg: 8px;
--spacing-xl: 10px;
--radius-xxs: 0;
--radius-xs: 0;
--radius-md: 0;
--radius-xl: 0;
--radius-xxl: 0;
--text-xxs: 9px;
--text-xs: 10px;
--text-sm: 12px;
--text-md: 14px;
--text-lg: 16px;
--text-xl: 22px;
--text-xxl: 26px;
--body-text-size: var(--text-md);
--body-text-weight: 400;
--embed-radius: var(--radius-lg);
--color-accent: var(--primary-500);
--shadow-drop: 0;
--shadow-drop-lg: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--shadow-inset: rgba(0,0,0,0.05) 0px 2px 4px 0px inset;
--block-border-width: 1px;
--block-info-text-size: var(--text-sm);
--block-info-text-weight: 400;
--block-label-border-width: 1px;
--block-label-margin: 0;
--block-label-padding: var(--spacing-sm) var(--spacing-lg);
--block-label-radius: calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px) 0;
--block-label-right-radius: 0 calc(var(--radius-lg) - 1px) 0 calc(var(--radius-lg) - 1px);
--block-label-text-size: var(--text-sm);
--block-label-text-weight: 400;
--block-padding: var(--spacing-xl) calc(var(--spacing-xl) + 2px);
--block-radius: var(--radius-lg);
--block-shadow: var(--shadow-drop);
--block-title-background-fill: none;
--block-title-border-color: none;
--block-title-border-width: 0px;
--block-title-padding: 0;
--block-title-radius: none;
--block-title-text-size: var(--text-md);
--block-title-text-weight: 400;
--container-radius: var(--radius-lg);
--form-gap-width: 1px;
--layout-gap: var(--spacing-xxl);
--panel-border-width: 0;
--section-header-text-size: var(--text-md);
--section-header-text-weight: 400;
--checkbox-border-radius: var(--radius-sm);
--checkbox-label-gap: 2px;
--checkbox-label-padding: var(--spacing-md);
--checkbox-label-shadow: var(--shadow-drop);
--checkbox-label-text-size: var(--text-md);
--checkbox-label-text-weight: 400;
--checkbox-check: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e");
--radio-circle: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e");
--checkbox-shadow: var(--input-shadow);
--error-border-width: 1px;
--input-border-width: 0;
--input-radius: var(--radius-lg);
--input-text-size: var(--text-md);
--input-text-weight: 400;
--loader-color: var(--color-accent);
--prose-text-size: var(--text-md);
--prose-text-weight: 400;
--prose-header-text-weight: 600;
--slider-color: ;
--table-radius: var(--radius-lg);
--button-large-padding: 2px 10px;
--button-large-radius: var(--radius-lg);
--button-large-text-size: var(--text-lg);
--button-large-text-weight: 400;
--button-shadow: 4px 4px 4px 0px #333333;
--button-shadow-active: 1px 1px 4px 0px #555555;
--button-shadow-hover: 1px 1px 4px 0px #555555;
--button-small-padding: var(--spacing-sm) calc(2 * var(--spacing-sm));
--button-small-radius: var(--radius-lg);
--button-small-text-size: var(--text-md);
--button-small-text-weight: 400;
--button-transition: none;
--size-9: 64px;
--size-14: 64px;
}
Executable → Regular
View File
+3 -2
View File
@@ -57,7 +57,7 @@ button.custom-button{
.theme-preview { display: none; position: fixed; border: 4px solid var(--neutral-600); box-shadow: 2px 2px 2px 2px var(--neutral-700); top: 0; bottom: 0; left: 0; right: 0; margin: auto; max-width: 75vw; z-index: 999; }
/* txt2img/img2img specific */
.block.token-counter{ position: absolute; display: inline-block; right: 1em; min-width: 0 !important; width: auto; z-index: 100; top: -0.75em; }
.block.token-counter{ position: absolute; display: inline-block; right: 0; min-width: 0 !important; width: auto; z-index: 100; top: -0.75em; }
.block.token-counter span{ background: var(--input-background-fill) !important; box-shadow: 0 0 0.0 0.3em rgba(192,192,192,0.15), inset 0 0 0.6em rgba(192,192,192,0.075); border: 2px solid rgba(192,192,192,0.4) !important; }
.block.token-counter.error span{ box-shadow: 0 0 0.0 0.3em rgba(255,0,0,0.15), inset 0 0 0.6em rgba(255,0,0,0.075); border: 2px solid rgba(255,0,0,0.4) !important; }
.block.token-counter div{ display: inline; }
@@ -226,7 +226,7 @@ table.settings-value-table td { padding: 0.4em; border: 1px solid #ccc; max-widt
/* extra networks */
.extra-networks > div { margin: 0; gap: 0.2em; border-bottom: none !important; }
.extra-networks .second-line { display: flex; width: -webkit-fill-available; gap: 0.2em; }
.extra-networks .second-line { display: flex; width: -webkit-fill-available; gap: 0.3em; box-shadow: var(--input-shadow); }
.extra-networks .search { flex: 1; }
.extra-networks .description { flex: 3; }
.extra-networks .tab-nav > button { margin-right: 0; height: 24px; padding: 2px 4px 2px 4px; }
@@ -271,6 +271,7 @@ div.controlnet_main_options { display: grid; grid-template-columns: 1fr 1fr; gri
#refresh_tac_refreshTempFiles { display: none; }
#train_tab { flex-flow: row-reverse; }
#models_tab { flex-flow: row-reverse; }
#swap_axes > button { min-width: 100px; font-size: 1em; }
.log-monitor { display: none; justify-content: unset !important; overflow: hidden; padding: 0; margin-top: auto; font-family: monospace; font-size: 0.85em; }
.log-monitor td, .log-monitor th { padding-left: 1em; }
+7 -16
View File
@@ -47,10 +47,8 @@ def wrap_gradio_gpu_call(func, extra_outputs=None):
def wrap_gradio_call(func, extra_outputs=None, add_stats=False):
def f(*args, extra_outputs_array=extra_outputs, **kwargs):
run_memmon = shared.opts.memmon_poll_rate > 0 and not shared.mem_mon.disabled and add_stats
if run_memmon:
shared.mem_mon.monitor()
t = time.perf_counter()
shared.mem_mon.reset()
try:
if shared.cmd_opts.profile:
pr = cProfile.Profile()
@@ -83,18 +81,11 @@ def wrap_gradio_call(func, extra_outputs=None, add_stats=False):
elapsed = time.perf_counter() - t
elapsed_m = int(elapsed // 60)
elapsed_s = elapsed % 60
elapsed_text = f"{elapsed_s:.2f}s"
if elapsed_m > 0:
elapsed_text = f"{elapsed_m}m "+elapsed_text
if run_memmon:
mem_stats = {k: -(v//-(1024*1024)) for k, v in shared.mem_mon.stop().items()}
active_peak = mem_stats['active_peak']
reserved_peak = mem_stats['reserved_peak']
sys_peak = mem_stats['system_peak']
sys_total = mem_stats['total']
vram_html = f" | <p class='vram'>GPU active {active_peak} MB reserved {reserved_peak} MB | System peak {sys_peak} MB total {sys_total} MB</p>"
else:
vram_html = ''
res[-1] += f"<div class='performance'><p class='time'>Time taken: {elapsed_text}</p>{vram_html}</div>"
elapsed_text = f"{elapsed_m}m {elapsed_s:.2f}s" if elapsed_m > 0 else f"{elapsed_s:.2f}s"
vram_html = ''
if not shared.mem_mon.disabled:
vram = {k: -(v//-(1024*1024)) for k, v in shared.mem_mon.read().items()}
vram_html += f" | <p class='vram'>GPU active {max(vram['active_peak'], vram['reserved_peak'])} MB reserved {vram['reserved']} | used {vram['used']} MB free {vram['free']} MB total {vram['total']} MB | retries {vram['retries']} oom {vram['oom']}</p>"
res[-1] += f"<div class='performance'><p class='time'>Time: {elapsed_text}</p>{vram_html}</div>"
return tuple(res)
return f
+1 -1
View File
@@ -451,7 +451,7 @@ def atomically_save_image():
image_format = 'JPEG'
if shared.opts.image_watermark_enabled:
image = set_watermark(image, shared.opts.image_watermark)
shared.log.debug(f'Saving image: type={image_format} size={image.size} {fn}')
shared.log.debug(f'Saving: image={fn} type={image_format} size={image.width}x{image.height}')
# actual save
exifinfo = (exifinfo or "") if shared.opts.image_metadata else ""
if image_format == 'PNG':
+1 -2
View File
@@ -74,7 +74,7 @@ def process_batch(p, input_files, input_dir, output_dir, inpaint_mask_dir, args)
for k, v in items.items():
image.info[k] = v
images.save_image(image, path=output_dir, basename=basename, seed=None, prompt=None, extension=ext, info=geninfo, short_filename=True, no_prompt=True, grid=False, pnginfo_section_name="extras", existing_info=image.info, forced_filename=None)
shared.log.debug(f'Processed: {len(image_files)} Memory: {memory_stats()} batch')
shared.log.debug(f'Processed: images={len(image_files)} memory={memory_stats()} op=batch')
def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_styles, init_img, sketch, init_img_with_mask, inpaint_color_sketch, inpaint_color_sketch_orig, init_img_inpaint, init_mask_inpaint, steps: int, sampler_index: int, latent_index: int, mask_blur: int, mask_alpha: float, inpainting_fill: int, full_quality: bool, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, diffusers_guidance_rescale: float, refiner_steps: int, refiner_start: float, clip_skip: int, denoising_strength: float, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, selected_scale_tab: int, height: int, width: int, scale_by: float, resize_mode: int, inpaint_full_res: bool, inpaint_full_res_padding: int, inpainting_mask_invert: int, img2img_batch_files: list, img2img_batch_input_dir: str, img2img_batch_output_dir: str, img2img_batch_inpaint_mask_dir: str, override_settings_texts, *args): # pylint: disable=unused-argument
@@ -195,5 +195,4 @@ def img2img(id_task: str, mode: int, prompt: str, negative_prompt: str, prompt_s
processed = processing.process_images(p)
p.close()
generation_info_js = processed.js()
shared.log.debug(f'Processed: {len(processed.images)} Memory: {memory_stats()} img')
return processed.images, generation_info_js, processed.info, plaintext_to_html(processed.comments)
+18 -39
View File
@@ -1,73 +1,52 @@
import threading
import time
from collections import defaultdict
import torch
from modules import devices
class MemUsageMonitor(threading.Thread):
run_flag = None
class MemUsageMonitor():
device = None
disabled = False
opts = None
data = None
def __init__(self, name, device, opts):
threading.Thread.__init__(self)
def __init__(self, name, device):
self.name = name
self.device = device
self.opts = opts
self.daemon = True
self.run_flag = threading.Event()
self.data = defaultdict(int)
if not torch.cuda.is_available():
self.disabled = True
else:
try:
self.cuda_mem_get_info()
torch.cuda.mem_get_info(self.device.index if self.device.index is not None else torch.cuda.current_device())
torch.cuda.memory_stats(self.device)
except Exception:
self.disabled = True
def cuda_mem_get_info(self):
index = self.device.index if self.device.index is not None else torch.cuda.current_device()
return torch.cuda.mem_get_info(index)
def run(self):
def cuda_mem_get_info(self): # legacy for extensions only
if self.disabled:
return
while True:
self.run_flag.wait()
torch.cuda.reset_peak_memory_stats()
self.data.clear()
if self.opts.memmon_poll_rate <= 0:
self.run_flag.clear()
continue
self.data["min_free"] = self.cuda_mem_get_info()[0]
while self.run_flag.is_set():
free, _total = self.cuda_mem_get_info()
self.data["min_free"] = min(self.data["min_free"], free)
time.sleep(1 / self.opts.memmon_poll_rate)
return 0, 0
return torch.cuda.mem_get_info(self.device.index if self.device.index is not None else torch.cuda.current_device())
def monitor(self):
self.run_flag.set()
def reset(self):
if not self.disabled:
torch.cuda.reset_peak_memory_stats(self.device)
self.data['retries'] = 0
self.data['oom'] = 0
# torch.cuda.reset_accumulated_memory_stats(self.device)
# torch.cuda.reset_max_memory_allocated(self.device)
# torch.cuda.reset_max_memory_cached(self.device)
def read(self):
if not self.disabled:
free, total = self.cuda_mem_get_info()
self.data["free"] = free
self.data["total"] = total
try:
self.data["free"], self.data["total"] = torch.cuda.mem_get_info(self.device.index if self.device.index is not None else torch.cuda.current_device())
torch_stats = torch.cuda.memory_stats(self.device)
self.data["active"] = torch_stats["active.all.current"]
self.data["active_peak"] = torch_stats["active_bytes.all.peak"]
self.data["reserved"] = torch_stats["reserved_bytes.all.current"]
self.data["reserved_peak"] = torch_stats["reserved_bytes.all.peak"]
self.data["system_peak"] = total - self.data["min_free"]
self.data['retries'] = torch_stats["num_alloc_retries"]
self.data['oom'] = torch_stats["num_ooms"]
self.data["used"] = self.data["total"] - self.data["free"]
except Exception:
self.disabled = True
return self.data
def stop(self):
self.run_flag.clear()
return self.read()
-4
View File
@@ -42,10 +42,6 @@ for d, must_exist, what, _options in path_dirs:
print(f"Warning: {what} not found at path {must_exist_path}", file=sys.stderr)
else:
d = os.path.abspath(d)
# if "atstart" in options:
# sys.path.insert(0, d)
# else:
# sys.path.append(d)
sys.path.append(d)
paths[what] = d
+63 -58
View File
@@ -1,29 +1,39 @@
import os
import json
import math
import os
import time
import hashlib
import random
from contextlib import nullcontext
from typing import Any, Dict, List
import torch
import numpy as np
from PIL import Image, ImageFilter, ImageOps
import cv2
from PIL import Image, ImageFilter, ImageOps
from skimage import exposure
from ldm.data.util import AddMiDaS
from ldm.models.diffusion.ddpm import LatentDepth2ImageDiffusion
from einops import repeat, rearrange
from blendmodes.blend import blendLayers, BlendType
from installer import git_commit
import modules.sd_hijack
from modules import devices, prompt_parser, masking, sd_samplers, lowvram, generation_parameters_copypaste, script_callbacks, extra_networks, sd_vae_approx, scripts, sd_samplers_common # pylint: disable=unused-import
import modules.shared as shared
import modules.paths as paths
from modules import shared, devices
import modules.memstats
import modules.lowvram
import modules.masking
import modules.paths
import modules.scripts
import modules.prompt_parser
import modules.extra_networks
import modules.face_restoration
import modules.images as images
import modules.styles
import modules.sd_models as sd_models
import modules.sd_vae as sd_vae
import modules.sd_hijack
import modules.sd_samplers
import modules.sd_samplers_common
import modules.sd_models
import modules.sd_vae
import modules.sd_vae_approx
import modules.generation_parameters_copypaste
opt_C = 4
@@ -451,7 +461,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su
index = position_in_batch + iteration * p.batch_size
if all_negative_prompts is None:
all_negative_prompts = p.all_negative_prompts
vae = (None if not shared.opts.add_model_name_to_info or sd_vae.loaded_vae_file is None else os.path.splitext(os.path.basename(sd_vae.loaded_vae_file))[0]) if p.full_quality else 'TAESD'
vae = (None if not shared.opts.add_model_name_to_info or modules.sd_vae.loaded_vae_file is None else os.path.splitext(os.path.basename(modules.sd_vae.loaded_vae_file))[0]) if p.full_quality else 'TAESD'
comment = ', '.join(comments) if comments is not None and type(comments) is list else None
args = {
@@ -473,7 +483,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su
"Prompt2": p.refiner_prompt if len(p.refiner_prompt) > 0 else None,
"Negative2": p.refiner_negative if len(p.refiner_negative) > 0 else None,
# other
"ENSD": shared.opts.eta_noise_seed_delta if shared.opts.eta_noise_seed_delta != 0 and sd_samplers_common.is_sampler_using_eta_noise_seed_delta(p) else None,
"ENSD": shared.opts.eta_noise_seed_delta if shared.opts.eta_noise_seed_delta != 0 and modules.sd_samplers_common.is_sampler_using_eta_noise_seed_delta(p) else None,
"Tiling": p.tiling if p.tiling else None,
# sdnext
"Backend": 'Diffusers' if shared.backend == shared.Backend.DIFFUSERS else 'Original',
@@ -524,7 +534,7 @@ def create_infotext(p: StableDiffusionProcessing, all_prompts, all_seeds, all_su
args['Token merging ratio hr'] = token_merging_ratio_hr if token_merging_ratio_hr != 0 else None
args.update(p.extra_generation_params)
params_text = ", ".join([k if k == v else f'{k}: {generation_parameters_copypaste.quote(v)}' for k, v in args.items() if v is not None])
params_text = ", ".join([k if k == v else f'{k}: {modules.generation_parameters_copypaste.quote(v)}' for k, v in args.items() if v is not None])
negative_prompt_text = f"\nNegative prompt: {all_negative_prompts[index]}" if all_negative_prompts[index] else ""
infotext = f"{all_prompts[index]}{negative_prompt_text}\n{params_text}".strip()
return infotext
@@ -568,18 +578,18 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
stored_opts[k] = shared.opts.data.get(k, None) or shared.opts.data_labels[k].default
try:
# if no checkpoint override or the override checkpoint can't be found, remove override entry and load opts checkpoint
if p.override_settings.get('sd_model_checkpoint', None) is not None and sd_models.checkpoint_aliases.get(p.override_settings.get('sd_model_checkpoint')) is None:
if p.override_settings.get('sd_model_checkpoint', None) is not None and modules.sd_models.checkpoint_aliases.get(p.override_settings.get('sd_model_checkpoint')) is None:
p.override_settings.pop('sd_model_checkpoint', None)
sd_models.reload_model_weights()
modules.sd_models.reload_model_weights()
for k, v in p.override_settings.items():
setattr(shared.opts, k, v)
if k == 'sd_model_checkpoint':
sd_models.reload_model_weights()
modules.sd_models.reload_model_weights()
if k == 'sd_vae':
sd_vae.reload_vae_weights()
modules.sd_vae.reload_vae_weights()
if not shared.opts.cuda_compile:
sd_models.apply_token_merging(p.sd_model, p.get_token_merging_ratio())
modules.sd_models.apply_token_merging(p.sd_model, p.get_token_merging_ratio())
if shared.cmd_opts.profile:
"""
@@ -598,16 +608,16 @@ def process_images(p: StableDiffusionProcessing) -> Processed:
res = process_images_inner(p)
finally:
if not shared.opts.cuda_compile:
sd_models.apply_token_merging(p.sd_model, 0)
modules.sd_models.apply_token_merging(p.sd_model, 0)
if p.override_settings_restore_afterwards: # restore opts to original state
for k, v in stored_opts.items():
setattr(shared.opts, k, v)
if k == 'sd_model_checkpoint':
sd_models.reload_model_weights()
modules.sd_models.reload_model_weights()
if k == 'sd_model_refiner':
sd_models.reload_model_weights()
modules.sd_models.reload_model_weights()
if k == 'sd_vae':
sd_vae.reload_vae_weights()
modules.sd_vae.reload_vae_weights()
return res
@@ -672,15 +682,6 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
cached_c = [None, None]
def get_conds_with_caching(function, required_prompts, steps, cache):
"""
Returns the result of calling function(shared.sd_model, required_prompts, steps)
using a cache to store the result if the same arguments have been used before.
cache is an array containing two elements. The first element is a tuple
representing the previously used arguments, or None if no arguments
have been used before. The second element is where the previously
computed result is stored.
"""
if cache[0] is not None and (required_prompts, steps) == cache[0]:
return cache[1]
with devices.autocast():
@@ -692,11 +693,12 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
return ''
ema_scope_context = p.sd_model.ema_scope if shared.backend == shared.Backend.ORIGINAL else nullcontext
with torch.no_grad(), ema_scope_context():
with torch.inference_mode(), ema_scope_context():
t0 = time.time()
with devices.autocast():
p.init(p.all_prompts, p.all_seeds, p.all_subseeds)
if shared.opts.live_previews_enable and shared.opts.show_progress_type == "Approximate NN" and shared.backend == shared.Backend.ORIGINAL:
sd_vae_approx.model()
modules.sd_vae_approx.model()
if shared.state.job_count == -1:
shared.state.job_count = p.n_iter
extra_network_data = None
@@ -717,25 +719,25 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
p.scripts.before_process_batch(p, batch_number=n, prompts=p.prompts, seeds=p.seeds, subseeds=p.subseeds)
if len(p.prompts) == 0:
break
p.prompts, extra_network_data = extra_networks.parse_prompts(p.prompts)
p.prompts, extra_network_data = modules.extra_networks.parse_prompts(p.prompts)
if not p.disable_extra_networks:
with devices.autocast():
extra_networks.activate(p, extra_network_data)
modules.extra_networks.activate(p, extra_network_data)
if p.scripts is not None:
p.scripts.process_batch(p, batch_number=n, prompts=p.prompts, seeds=p.seeds, subseeds=p.subseeds)
if n == 0:
with open(os.path.join(paths.data_path, "params.txt"), "w", encoding="utf8") as file:
with open(os.path.join(modules.paths.data_path, "params.txt"), "w", encoding="utf8") as file:
processed = Processed(p, [], p.seed, "")
file.write(processed.infotext(p, 0))
step_multiplier = 1
sampler_config = sd_samplers.find_sampler_config(p.sampler_name)
sampler_config = modules.sd_samplers.find_sampler_config(p.sampler_name)
step_multiplier = 2 if sampler_config and sampler_config.options.get("second_order", False) else 1
if p.n_iter > 1:
shared.state.job = f"Batch {n+1} out of {p.n_iter}"
if shared.backend == shared.Backend.ORIGINAL:
uc = get_conds_with_caching(prompt_parser.get_learned_conditioning, p.negative_prompts, p.steps * step_multiplier, cached_uc)
c = get_conds_with_caching(prompt_parser.get_multicond_learned_conditioning, p.prompts, p.steps * step_multiplier, cached_c)
uc = get_conds_with_caching(modules.prompt_parser.get_learned_conditioning, p.negative_prompts, p.steps * step_multiplier, cached_uc)
c = get_conds_with_caching(modules.prompt_parser.get_multicond_learned_conditioning, p.prompts, p.steps * step_multiplier, cached_c)
if len(modules.sd_hijack.model_hijack.comments) > 0:
for comment in modules.sd_hijack.model_hijack.comments:
comments[comment] = 1
@@ -749,8 +751,8 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
if not shared.opts.no_half and not shared.opts.no_half_vae and shared.cmd_opts.rollback_vae:
shared.log.warning('Tensor with all NaNs was produced in VAE')
devices.dtype_vae = torch.bfloat16
vae_file, vae_source = sd_vae.resolve_vae(p.sd_model.sd_model_checkpoint)
sd_vae.load_vae(p.sd_model, vae_file, vae_source)
vae_file, vae_source = modules.sd_vae.resolve_vae(p.sd_model.sd_model_checkpoint)
modules.sd_vae.load_vae(p.sd_model, vae_file, vae_source)
x_samples_ddim = [decode_first_stage(p.sd_model, samples_ddim[i:i+1].to(dtype=devices.dtype_vae))[0].cpu() for i in range(samples_ddim.size(0))]
for x in x_samples_ddim:
devices.test_for_nans(x, "vae")
@@ -768,14 +770,14 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
raise ValueError(f"Unknown backend {shared.backend}")
if shared.cmd_opts.lowvram or shared.cmd_opts.medvram and shared.backend == shared.Backend.ORIGINAL:
lowvram.send_everything_to_cpu()
modules.lowvram.send_everything_to_cpu()
devices.torch_gc()
if p.scripts is not None:
p.scripts.postprocess_batch(p, x_samples_ddim, batch_number=n)
if p.scripts is not None:
p.prompts = p.all_prompts[n * p.batch_size:(n + 1) * p.batch_size]
p.negative_prompts = p.all_negative_prompts[n * p.batch_size:(n + 1) * p.batch_size]
batch_params = scripts.PostprocessBatchListArgs(list(x_samples_ddim))
batch_params = modules.scripts.PostprocessBatchListArgs(list(x_samples_ddim))
p.scripts.postprocess_batch_list(p, batch_params, batch_number=n)
x_samples_ddim = batch_params.images
@@ -797,7 +799,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
x_sample = modules.face_restoration.restore_faces(x_sample)
image = Image.fromarray(x_sample)
if p.scripts is not None:
pp = scripts.PostprocessImageArgs(image)
pp = modules.scripts.PostprocessImageArgs(image)
p.scripts.postprocess_image(p, pp)
image = pp.image
if p.color_corrections is not None and i < len(p.color_corrections):
@@ -832,6 +834,9 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
devices.torch_gc()
shared.state.nextjob()
t1 = time.time()
shared.log.info(f'Processed: images={len(output_images)} time={t1 - t0:.2f}s its={(p.steps * len(output_images)) / (t1 - t0):.2f} memory={modules.memstats.memory_stats()}')
p.color_corrections = None
index_of_first_image = 0
unwanted_grid_because_of_img_count = len(output_images) < 2 and shared.opts.grid_only_if_multiple
@@ -848,7 +853,7 @@ def process_images_inner(p: StableDiffusionProcessing) -> Processed:
images.save_image(grid, p.outpath_grids, "grid", p.all_seeds[0], p.all_prompts[0], shared.opts.grid_format, info=infotext(), short_filename=not shared.opts.grid_extended_filename, p=p, grid=True)
if not p.disable_extra_networks and extra_network_data:
extra_networks.deactivate(p, extra_network_data)
modules.extra_networks.deactivate(p, extra_network_data)
res = Processed(
p,
@@ -905,7 +910,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
def init(self, all_prompts, all_seeds, all_subseeds):
if shared.backend == shared.Backend.DIFFUSERS:
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.TEXT_2_IMAGE)
modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.TEXT_2_IMAGE)
self.width = self.width or 512
self.height = self.height or 512
@@ -953,7 +958,7 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
if not shared.opts.save or self.do_not_save_samples or not shared.opts.save_images_before_highres_fix:
return
if not isinstance(image, Image.Image):
image = sd_samplers.sample_to_image(image, index, approximation=0)
image = modules.sd_samplers.sample_to_image(image, index, approximation=0)
orig1 = self.extra_generation_params
orig2 = self.restore_faces
self.extra_generation_params = {}
@@ -964,10 +969,10 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
images.save_image(image, self.outpath_samples, "", seeds[index], prompts[index], shared.opts.samples_format, info=info, suffix="-before-highres-fix")
if shared.backend == shared.Backend.DIFFUSERS:
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.TEXT_2_IMAGE)
modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.TEXT_2_IMAGE)
self.ops.append('txt2img')
self.sampler = sd_samplers.create_sampler(self.sampler_name, self.sd_model)
self.sampler = modules.sd_samplers.create_sampler(self.sampler_name, self.sd_model)
latent_scale_mode = shared.latent_upscale_modes.get(self.hr_upscaler, None) if self.hr_upscaler is not None else shared.latent_upscale_modes.get(shared.latent_upscale_default_mode, "None")
if self.enable_hr and latent_scale_mode is None:
if len([x for x in shared.sd_upscalers if x.name == self.hr_upscaler]) == 0:
@@ -1020,14 +1025,14 @@ class StableDiffusionProcessingTxt2Img(StableDiffusionProcessing):
shared.state.nextjob()
if self.latent_sampler == "PLMS":
self.latent_sampler = 'UniPC'
self.sampler = sd_samplers.create_sampler(self.latent_sampler or self.sampler_name, self.sd_model)
self.sampler = modules.sd_samplers.create_sampler(self.latent_sampler or self.sampler_name, self.sd_model)
samples = samples[:, :, self.truncate_y//2:samples.shape[2]-(self.truncate_y+1)//2, self.truncate_x//2:samples.shape[3]-(self.truncate_x+1)//2]
noise = create_random_tensors(samples.shape[1:], seeds=seeds, subseeds=subseeds, subseed_strength=subseed_strength, p=self)
x = None
devices.torch_gc() # GC now before running the next img2img to prevent running out of memory
sd_models.apply_token_merging(self.sd_model, self.get_token_merging_ratio(for_hr=True))
modules.sd_models.apply_token_merging(self.sd_model, self.get_token_merging_ratio(for_hr=True))
samples = self.sampler.sample_img2img(self, samples, noise, conditioning, unconditional_conditioning, steps=self.hr_second_pass_steps or self.steps, image_conditioning=image_conditioning)
sd_models.apply_token_merging(self.sd_model, self.get_token_merging_ratio())
modules.sd_models.apply_token_merging(self.sd_model, self.get_token_merging_ratio())
self.is_hr_pass = False
return samples
@@ -1065,14 +1070,14 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
def init(self, all_prompts, all_seeds, all_subseeds):
if shared.backend == shared.Backend.DIFFUSERS and self.image_mask is None:
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE)
modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.IMAGE_2_IMAGE)
elif shared.backend == shared.Backend.DIFFUSERS and self.image_mask is not None:
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.INPAINTING)
modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.INPAINTING)
self.sd_model.dtype = self.sd_model.unet.dtype
if self.sampler_name == "PLMS":
self.sampler_name = 'UniPC'
self.sampler = sd_samplers.create_sampler(self.sampler_name, self.sd_model)
self.sampler = modules.sd_samplers.create_sampler(self.sampler_name, self.sd_model)
if self.image_mask is not None:
self.ops.append('inpaint')
@@ -1089,8 +1094,8 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
if self.inpaint_full_res:
self.mask_for_overlay = image_mask
mask = image_mask.convert('L')
crop_region = masking.get_crop_region(np.array(mask), self.inpaint_full_res_padding)
crop_region = masking.expand_crop_region(crop_region, self.width, self.height, mask.width, mask.height)
crop_region = modules.masking.get_crop_region(np.array(mask), self.inpaint_full_res_padding)
crop_region = modules.masking.expand_crop_region(crop_region, self.width, self.height, mask.width, mask.height)
x1, y1, x2, y2 = crop_region
mask = mask.crop(crop_region)
image_mask = images.resize_image(3, mask, self.width, self.height)
@@ -1137,7 +1142,7 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
self.init_images = [image] # assign early for diffusers
if image_mask is not None:
if self.inpainting_fill != 1:
image = masking.fill(image, latent_mask)
image = modules.masking.fill(image, latent_mask)
if add_color_corrections:
self.color_corrections.append(setup_color_correction(image))
image = np.array(image).astype(np.float32) / 255.0
@@ -1183,9 +1188,9 @@ class StableDiffusionProcessingImg2Img(StableDiffusionProcessing):
def sample(self, conditioning, unconditional_conditioning, seeds, subseeds, subseed_strength, prompts):
if shared.backend == shared.Backend.DIFFUSERS:
if self.init_mask is None: # pylint: disable=no-member
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.IMAGE_2_IMAGE)
modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.IMAGE_2_IMAGE)
else:
sd_models.set_diffuser_pipe(self.sd_model, sd_models.DiffusersTaskType.INPAINTING)
modules.sd_models.set_diffuser_pipe(self.sd_model, modules.sd_models.DiffusersTaskType.INPAINTING)
self.sd_model.dtype = self.sd_model.unet.dtype
x = create_random_tensors([4, self.height // 8, self.width // 8], seeds=seeds, subseeds=subseeds, subseed_strength=self.subseed_strength, seed_resize_from_h=self.seed_resize_from_h, seed_resize_from_w=self.seed_resize_from_w, p=self)
+52 -38
View File
@@ -276,6 +276,25 @@ def wrap_call(func, filename, funcname, *args, default=None, **kwargs):
return default
class ScriptSummary:
def __init__(self, op):
self.start = time.time()
self.update = time.time()
self.op = op
self.time = {}
def record(self, script):
self.update = time.time()
self.time[script] = round(time.time() - self.update, 2)
def report(self):
total = sum(self.time.values())
if total == 0:
return
scripts = [f'{k}:{v}s' for k, v in self.time.items() if v > 0]
log.debug(f'Script: op={self.op} total={total}s scripts={scripts}')
class ScriptRunner:
def __init__(self):
self.scripts = []
@@ -405,6 +424,7 @@ class ScriptRunner:
return inputs
def run(self, p, *args):
s = ScriptSummary('run')
script_index = args[0]
if script_index == 0:
return None
@@ -412,117 +432,111 @@ class ScriptRunner:
if script is None:
return None
parsed = p.per_script_args.get(script.title(), args[script.args_from:script.args_to])
t0 = time.time()
processed = script.run(p, *parsed)
log.debug(f'Script run: {script.title()}:{round(time.time()-t0, 2)}s')
s.record(script.title())
s.report()
return processed
def process(self, p, **kwargs):
s = []
s = ScriptSummary('process')
for script in self.alwayson_scripts:
try:
t0 = time.time()
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
script.process(p, *args, **kwargs)
s.append(f'{script.title()}:{round(time.time()-t0, 2)}s')
except Exception as e:
errors.display(e, f'Running script process: {script.filename}')
log.debug(f'Script process: {s}')
s.record(script.title())
s.report()
def before_process_batch(self, p, **kwargs):
s = []
s = ScriptSummary('before-process-batch')
for script in self.alwayson_scripts:
try:
t0 = time.time()
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
script.before_process_batch(p, *args, **kwargs)
s.append(f'{script.title()}:{round(time.time()-t0, 2)}s')
except Exception as e:
errors.display(e, f'Running script before process batch: {script.filename}')
log.debug(f'Script before-process-batch: {s}')
s.record(script.title())
s.report()
def process_batch(self, p, **kwargs):
s = []
s = ScriptSummary('process-batch')
for script in self.alwayson_scripts:
try:
t0 = time.time()
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
script.process_batch(p, *args, **kwargs)
s.append(f'{script.title()}:{round(time.time()-t0, 2)}s')
except Exception as e:
errors.display(e, f'Running script process batch: {script.filename}')
log.debug(f'Script process-batch: {s}')
s.record(script.title())
s.report()
def postprocess(self, p, processed):
s = []
s = ScriptSummary('postprocess')
for script in self.alwayson_scripts:
try:
t0 = time.time()
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
script.postprocess(p, processed, *args)
s.append(f'{script.title()}:{round(time.time()-t0, 2)}s')
except Exception as e:
errors.display(e, f'Running script postprocess: {script.filename}')
log.debug(f'Script postprocess: {s}')
s.record(script.title())
s.report()
def postprocess_batch(self, p, images, **kwargs):
s = []
s = ScriptSummary('postprocess-batch')
for script in self.alwayson_scripts:
try:
t0 = time.time()
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
script.postprocess_batch(p, *args, images=images, **kwargs)
s.append(f'{script.title()}:{round(time.time()-t0, 2)}s')
except Exception as e:
errors.display(e, f'Running script before postprocess batch: {script.filename}')
log.debug(f'Script postprocess-batch: {s}')
s.record(script.title())
s.report()
def postprocess_batch_list(self, p, pp: PostprocessBatchListArgs, **kwargs):
s = []
s = ScriptSummary('postprocess-batch-list')
for script in self.alwayson_scripts:
try:
t0 = time.time()
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
script.postprocess_batch_list(p, pp, *args, **kwargs)
s.append(f'{script.title()}:{round(time.time()-t0, 2)}s')
except Exception as e:
errors.display(e, f'Running script before postprocess batch list: {script.filename}')
log.debug(f'Script postprocess-batch-list: {s}')
s.record(script.title())
s.report()
def postprocess_image(self, p, pp: PostprocessImageArgs):
s = []
s = ScriptSummary('postprocess-image')
for script in self.alwayson_scripts:
try:
t0 = time.time()
args = p.per_script_args.get(script.title(), p.script_args[script.args_from:script.args_to])
script.postprocess_image(p, pp, *args)
s.append(f'{script.title()}:{round(time.time()-t0, 2)}s')
except Exception as e:
errors.display(e, f'Running script postprocess image: {script.filename}')
log.debug(f'Script postprocess-image: {s}')
s.record(script.title())
s.report()
def before_component(self, component, **kwargs):
s = ScriptSummary('before-component')
for script in self.scripts:
try:
t0 = time.time()
script.before_component(component, **kwargs)
time_component[script.title()] = time_component.get(script.title(), 0) + (time.time()-t0)
except Exception as e:
errors.display(e, f'Running script before component: {script.filename}')
s.record(script.title())
s.report()
def after_component(self, component, **kwargs):
s = ScriptSummary('after-component')
for script in self.scripts:
try:
t0 = time.time()
script.after_component(component, **kwargs)
time_component[script.title()] = time_component.get(script.title(), 0) + (time.time()-t0)
except Exception as e:
errors.display(e, f'Running script after component: {script.filename}')
s.record(script.title())
s.report()
def reload_sources(self, cache):
s = []
s = ScriptSummary('reload-sources')
for si, script in list(enumerate(self.scripts)):
t0 = time.time()
args_from = script.args_from
args_to = script.args_to
filename = script.filename
@@ -536,8 +550,8 @@ class ScriptRunner:
self.scripts[si].filename = filename
self.scripts[si].args_from = args_from
self.scripts[si].args_to = args_to
s.append(f'{script.title()}:{round(time.time()-t0, 2)}s')
log.debug(f'Script reload-sources: {s}')
s.record(script.title())
s.report()
scripts_txt2img: ScriptRunner = None
+1 -1
View File
@@ -355,7 +355,7 @@ def read_state_dict(checkpoint_file, map_location=None): # pylint: disable=unuse
return None
try:
pl_sd = None
with progress.open(checkpoint_file, 'rb', description=f'Loading weights: [cyan]{checkpoint_file}', auto_refresh=True) as f:
with progress.open(checkpoint_file, 'rb', description=f'[cyan]Loading weights: [yellow]{checkpoint_file}', auto_refresh=True) as f:
_, extension = os.path.splitext(checkpoint_file)
if extension.lower() == ".ckpt" and shared.opts.sd_disable_ckpt:
shared.log.warning(f"Checkpoint loading disabled: {checkpoint_file}")
+2 -2
View File
@@ -47,14 +47,14 @@ def create_sampler(name, model):
sampler = config.constructor(model)
sampler.config = config
sampler.name = name
shared.log.debug(f'Sampler: {sampler.name} {sampler.config.options}')
shared.log.debug(f'Sampler: sampler={sampler.name} config={sampler.config.options}')
return sampler
elif shared.backend == shared.Backend.DIFFUSERS:
sampler = config.constructor(model)
if not hasattr(model, 'scheduler_config'):
model.scheduler_config = sampler.sampler.config.copy()
model.scheduler = sampler.sampler
shared.log.debug(f'Sampler: {sampler.name} {sampler.config}')
shared.log.debug(f'Sampler: sampler={sampler.name} config={sampler.config}')
return sampler.sampler
else:
return None
+3 -4
View File
@@ -378,7 +378,7 @@ options_templates.update(options_section(('optimizations', "Optimizations"), {
}))
options_templates.update(options_section(('cuda', "Compute Settings"), {
"memmon_poll_rate": OptionInfo(2, "VRAM usage polls per second during generation", gr.Slider, {"minimum": 0, "maximum": 40, "step": 1}),
# "memmon_poll_rate": OptionInfo(2, "VRAM usage polls per second during generation", gr.Slider, {"minimum": 0, "maximum": 40, "step": 1}),
"precision": OptionInfo("Autocast", "Precision type", gr.Radio, lambda: {"choices": ["Autocast", "Full"]}),
"cuda_dtype": OptionInfo("FP32" if sys.platform == "darwin" or cmd_opts.use_openvino else "BF16" if devices.backend == "ipex" else "FP16", "Device precision type", gr.Radio, lambda: {"choices": ["FP32", "FP16", "BF16"]}),
"no_half": OptionInfo(False, "Use full precision for model (--no-half)", None, None, None),
@@ -825,8 +825,7 @@ devices.device, devices.device_interrogate, devices.device_gfpgan, devices.devic
device = devices.device
batch_cond_uncond = opts.always_batch_cond_uncond or not (cmd_opts.lowvram or cmd_opts.medvram)
parallel_processing_allowed = not cmd_opts.lowvram
mem_mon = modules.memmon.MemUsageMonitor("MemMon", device, opts)
mem_mon.start()
mem_mon = modules.memmon.MemUsageMonitor("MemMon", devices.device)
if devices.backend == "directml":
directml_do_hijack()
@@ -916,7 +915,7 @@ def restart_server(restart=True):
demo.server.close()
demo.fns = []
# os._exit(0)
except Exception as e:
except (Exception, BaseException) as e:
log.error(f'Server shutdown error: {e}')
if restart:
log.info('Server will restart')
-2
View File
@@ -2,7 +2,6 @@ import modules.scripts
from modules import sd_samplers, shared, processing
from modules.generation_parameters_copypaste import create_override_settings_dict
from modules.ui import plaintext_to_html
from modules.memstats import memory_stats
def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, steps: int, sampler_index: int, latent_index: int, full_quality: bool, restore_faces: bool, tiling: bool, n_iter: int, batch_size: int, cfg_scale: float, image_cfg_scale: float, diffusers_guidance_rescale: float, clip_skip: int, seed: int, subseed: int, subseed_strength: float, seed_resize_from_h: int, seed_resize_from_w: int, height: int, width: int, enable_hr: bool, denoising_strength: float, hr_scale: float, hr_upscaler: str, hr_second_pass_steps: int, hr_resize_x: int, hr_resize_y: int, refiner_steps: int, refiner_start: int, refiner_prompt: str, refiner_negative: str, override_settings_texts, *args): # pylint: disable=unused-argument
@@ -68,5 +67,4 @@ def txt2img(id_task: str, prompt: str, negative_prompt: str, prompt_styles, step
if processed is None:
return [], '', '', 'Error: processing failed'
generation_info_js = processed.js()
shared.log.debug(f'Processed: {len(processed.images)} Memory: {memory_stats()} txt')
return processed.images, generation_info_js, processed.info, plaintext_to_html(processed.comments)
+12 -7
View File
@@ -17,7 +17,7 @@ import modules.ui_symbols as symbols
extra_pages = []
allowed_dirs = set()
allowed_dirs = []
dir_cache = {} # key=path, value=(mtime, listdir(path))
refresh_time = None
@@ -39,16 +39,21 @@ def register_page(page):
# registers extra networks page for the UI; recommend doing it in on_before_ui() callback for extensions
extra_pages.append(page)
allowed_dirs.clear()
allowed_dirs.update(set(sum([x.allowed_directories_for_previews() for x in extra_pages], [])))
for page in extra_pages:
for folder in page.allowed_directories_for_previews():
if folder not in allowed_dirs:
allowed_dirs.append(os.path.abspath(folder))
def fetch_file(filename: str = ""):
if filename.startswith('html/'):
if not os.path.exists(filename):
return JSONResponse({ "error": f"file {filename}: not found" }, status_code=404)
if filename.startswith('html/') or filename.startswith('models/'):
return FileResponse(filename, headers={"Accept-Ranges": "bytes"})
if not any(Path(x).absolute() in Path(filename).absolute().parents for x in allowed_dirs):
return JSONResponse({"error": f"File cannot be fetched: {filename}. Must be in one of directories registered by extra pages."})
if not any(Path(folder).absolute() in Path(filename).absolute().parents for folder in allowed_dirs):
return JSONResponse({ "error": f"file {filename}: must be in one of allowed directories" }, status_code=403)
if os.path.splitext(filename)[1].lower() not in (".png", ".jpg", ".jpeg", ".webp"):
return JSONResponse({"error": f"File cannot be fetched: {filename}. Only png and jpg and webp."})
return JSONResponse({"error": f"file {filename}: not an image file"}, status_code=403)
return FileResponse(filename, headers={"Accept-Ranges": "bytes"})
@@ -362,7 +367,7 @@ def create_ui(container, button, tabname, skip_indexing = False):
def refresh(title):
res = []
for page in extra_pages:
if title == '' or title == page.title:
if title == '' or title == page.title or len(page.html) == 0:
shared.log.debug(f"Refreshing Extra networks: page={page.title} tab={ui.tabname}")
page.refresh()
page.create_page(ui.tabname)