diff --git a/CHANGELOG.md b/CHANGELOG.md
index 52b06a61f..41d131795 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,13 +1,25 @@
# Change Log for SD.Next
+## Update for 06/30/2023
+
+A bit bigger upadate this time, but contained to specific areas...
+
- change in behavior
extensions no longer auto-update on startup
using `--upgrade` flag upgrades core app as well as all submodules and extensions
-- live server log monitoring in ui
+- **live server log monitoring** in ui
configurable via settings -> live preview
-- auto-create thumbnails from preview images in extra networks in a background thread
- this creates significant load time saving on subsequent restarts
-- extensions sort by trending
+- new **extra networks interface**
+ *note: if you're using a 3rd party ui extension for extra networks, it will likely need to be updated to work with new interface*
+ - display in front of main ui, inline with main ui or as a sidebar
+ - lazy load thumbnails
+ drastically reduces load times for large number of extra networks
+ - auto-create thumbnails from preview images in extra networks in a background thread
+ significant load time saving on subsequent restarts
+ - support for info files in addition to description files
+ - support for variable aspect-ratio thumbnails
+ - new folder view
+- **extensions sort** by trending
- add requirements check for training
## Update for 06/26/2023
diff --git a/TODO.md b/TODO.md
index fa4d6e5f9..32ea90da2 100644
--- a/TODO.md
+++ b/TODO.md
@@ -52,4 +52,4 @@ Tech that can be integrated as part of the core workflow...
- port `p.all_hr_prompts`
- test `lyco_patch_lora`
- fix `lyco` logging
-- save `ui-settings.json`
+- delete thumb on preview replace
diff --git a/extensions-builtin/sd-webui-agent-scheduler b/extensions-builtin/sd-webui-agent-scheduler
index 9180642eb..8198489fd 160000
--- a/extensions-builtin/sd-webui-agent-scheduler
+++ b/extensions-builtin/sd-webui-agent-scheduler
@@ -1 +1 @@
-Subproject commit 9180642eb103706912fbfe7d46eb1e0fde1cfc78
+Subproject commit 8198489fd42883d3af119e219c320ba4853802c8
diff --git a/html/extra-networks-card-long.html b/html/extra-networks-card-long.html
deleted file mode 100644
index e2e01a15c..000000000
--- a/html/extra-networks-card-long.html
+++ /dev/null
@@ -1,14 +0,0 @@
-
diff --git a/javascript/black-orange.css b/javascript/black-orange.css
index bfc019f5f..79464fb6b 100644
--- a/javascript/black-orange.css
+++ b/javascript/black-orange.css
@@ -39,10 +39,6 @@ div.gradio-container.dark > div.w-full.flex.flex-col.min-h-screen > div { backgr
.dark fieldset span.text-gray-500, .dark .gr-block.gr-box span.text-gray-500, .dark label.block span { padding: 0; margin-top: -4px; }
.dark fieldset span.text-gray-500, .dark .gr-block.gr-box span.text-gray-500, .dark label.block span { border-radius: 0;}
.eta-bar { display: none !important }
-.extra-networks .tab-nav .search { max-height: 2em; }
-.extra-network-cards .card .actions .name { font-weight: 400; font-size: 1.2rem; }
-.extra-network-cards .card { width: 18em; height: 12em; box-shadow: none; }
-.extra-network-cards .card:hover { transform: scale(1.15); transition: all 0.2s ease; z-index: 99; box-shadow: none; }
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; }
@@ -56,7 +52,7 @@ svg.feather.feather-image, .feather .feather-image { display: none }
.tabs { background-color: black; }
.gradio-button.tool { border-radius: 0; }
.block.token-counter span { background-color: #222 !important; box-shadow: 2px 2px 2px #111; border: none !important; border-radius: 0; font-size: 0.8rem; }
-.tab-nav { zoom: 130%; margin-bottom: 16px; border-bottom: 2px solid #CE6400 !important; padding-bottom: 2px; }
+.tab-nav { zoom: 120%; margin-bottom: 10px; border-bottom: 2px solid #CE6400 !important; padding-bottom: 2px; }
.label-wrap { margin: 16px 0px 8px 0px; }
.gradio-slider input[type="number"] { width: 4.5em; font-size: 0.8rem; }
#tab_extensions table td, #tab_extensions table th { border: none; padding: 0.5em; }
@@ -68,6 +64,8 @@ svg.feather.feather-image, .feather .feather-image { display: none }
.progressDiv .progress { border-radius: 0 !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 #CE6400 !important; padding-left: 4px; }
+.image-buttons { gap: 10px !important}
/* gradio elements overrides */
#div.gradio-container.dark { overflow-x: hidden; }
@@ -99,7 +97,6 @@ svg.feather.feather-image, .feather .feather-image { display: none }
#txt2img_subseed_strength { margin-top: 0; }
#txtimg_hr_finalres { max-width: 200px; }
#pnginfo_html2_info { margin-top: -18px; background-color: var(--input-background-fill); padding: var(--input-padding) }
-#txt2img_extra_refresh, #txt2img_extra_close { height: 1.7em; }
#txt2img_tools > div > button, #img2img_tools > div > button { filter: hue-rotate(180deg) saturate(0.5); }
/* custom elements overrides */
diff --git a/javascript/extraNetworks.js b/javascript/extraNetworks.js
index 34d699bbf..254bbac7d 100644
--- a/javascript/extraNetworks.js
+++ b/javascript/extraNetworks.js
@@ -1,15 +1,20 @@
+let globalPopup = null;
+let globalPopupInner = null;
+const activePromptTextarea = {};
+
function setupExtraNetworksForTab(tabname) {
gradioApp().querySelector(`#${tabname}_extra_tabs`).classList.add('extra-networks');
const tabs = gradioApp().querySelector(`#${tabname}_extra_tabs > div`);
const search = gradioApp().querySelector(`#${tabname}_extra_search textarea`);
const refresh = gradioApp().getElementById(`${tabname}_extra_refresh`);
- const descriptInput = gradioApp().getElementById(`${tabname}_description_input`);
+ const description = gradioApp().getElementById(`${tabname}_description`);
const close = gradioApp().getElementById(`${tabname}_extra_close`);
search.classList.add('search');
- tabs.appendChild(search);
+ description.classList.add('description');
tabs.appendChild(refresh);
tabs.appendChild(close);
- tabs.appendChild(descriptInput);
+ tabs.appendChild(search);
+ tabs.appendChild(description);
search.addEventListener('input', (evt) => {
searchTerm = search.value.toLowerCase();
gradioApp().querySelectorAll(`#${tabname}_extra_tabs div.card`).forEach((elem) => {
@@ -17,13 +22,47 @@ function setupExtraNetworksForTab(tabname) {
elem.style.display = text.indexOf(searchTerm) == -1 ? 'none' : '';
});
});
+ intersectionObserver = new IntersectionObserver((entries) => {
+ // if (entries[0].intersectionRatio <= 0) onHidden();
+ if (entries[0].intersectionRatio > 0) {
+ for (el of Array.from(gradioApp().querySelectorAll('.extra-network-cards'))) {
+ const rect = el.getBoundingClientRect();
+ if (rect.top > 0) {
+ const en = gradioApp().getElementById(`${tabname}_extra_networks`);
+ if (!en) return
+ if (window.opts.extra_networks_card_cover == 'cover') {
+ en.style.zIndex = 0;
+ en.style.position = 'absolute';
+ en.style.right = 'unset';
+ en.style.width = 'unset';
+ el.style.height = document.body.offsetHeight - el.getBoundingClientRect().top + 'px';
+ gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 'unset'
+ } if (window.opts.extra_networks_card_cover == 'sidebar') {
+ en.style.zIndex = 9999;
+ en.style.position = 'absolute';
+ en.style.right = '0';
+ en.style.width = '38vw';
+ el.style.height = gradioApp().getElementById(`${tabname}_settings`).offsetHeight - 90 + 'px';
+ gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = '60vw'
+ } else {
+ en.style.zIndex = 0;
+ en.style.position = 'relative';
+ en.style.right = 'unset';
+ en.style.width = 'unset';
+ el.style.height = window.innerHeight - el.getBoundingClientRect().top + 'px';
+ gradioApp().getElementById(`${tabname}_settings`).parentNode.style.width = 'unset'
+ }
+ }
+ }
+ }
+ });
+ intersectionObserver.observe(search); // monitor visibility of
}
-const activePromptTextarea = {};
-
function setupExtraNetworks() {
setupExtraNetworksForTab('txt2img');
setupExtraNetworksForTab('img2img');
+
function registerPrompt(tabname, id) {
const textarea = gradioApp().querySelector(`#${id} > label > textarea`);
if (!activePromptTextarea[tabname]) activePromptTextarea[tabname] = textarea;
@@ -31,6 +70,7 @@ function setupExtraNetworks() {
activePromptTextarea[tabname] = textarea;
});
}
+
registerPrompt('txt2img', 'txt2img_prompt');
registerPrompt('txt2img', 'txt2img_neg_prompt');
registerPrompt('img2img', 'img2img_prompt');
@@ -93,9 +133,10 @@ function saveCardPreview(event, tabname, filename) {
}
function saveCardDescription(event, tabname, filename, descript) {
+ console.log('saveCardDescription', event, tabname, filename, descript);
const textarea = gradioApp().querySelector(`#${tabname}_description_filename > label > textarea`);
const button = gradioApp().getElementById(`${tabname}_save_description`);
- const description = gradioApp().getElementById(`${tabname}_description_input`);
+ const description = gradioApp().getElementById(`${tabname}_description`);
textarea.value = filename;
description.value = descript;
updateInput(textarea);
@@ -105,13 +146,15 @@ function saveCardDescription(event, tabname, filename, descript) {
}
function readCardDescription(event, tabname, filename, descript, extraPage, cardName) {
+ console.log('readCardDescription', event, tabname, filename, descript, extraPage, cardName);
const textarea = gradioApp().querySelector(`#${tabname}_description_filename > label > textarea`);
- const description_textarea = gradioApp().querySelector(`#${tabname}_description_input > label > textarea`);
+ const description = gradioApp().querySelector(`#${tabname}_description > label > textarea`);
const button = gradioApp().getElementById(`${tabname}_read_description`);
textarea.value = filename;
- description_textarea.value = descript;
+ description.value = descript;
+ console.log(textarea.value, description.value);
updateInput(textarea);
- updateInput(description_textarea);
+ updateInput(description);
button.click();
event.stopPropagation();
event.preventDefault();
@@ -125,8 +168,6 @@ function extraNetworksSearchButton(tabs_id, event) {
updateInput(searchTextarea);
}
-let globalPopup = null;
-let globalPopupInner = null;
function popup(contents) {
if (!globalPopup) {
globalPopup = document.createElement('div');
@@ -150,7 +191,7 @@ function popup(contents) {
function readCardMetadata(event, extraPage, cardName) {
requestGet('./sd_extra_networks/metadata', { page: extraPage, item: cardName }, (data) => {
- if (data && data.metadata) {
+ if (data?.metadata && (typeof(data?.metadata) === 'string')) {
elem = document.createElement('pre');
elem.classList.add('popup-metadata');
elem.textContent = data.metadata;
@@ -161,6 +202,19 @@ function readCardMetadata(event, extraPage, cardName) {
event.preventDefault();
}
+function readCardInformation(event, extraPage, cardName) {
+ requestGet('./sd_extra_networks/info', { page: extraPage, item: cardName }, (data) => {
+ if (data?.info && (typeof(data?.info) === 'string')) {
+ elem = document.createElement('pre');
+ elem.classList.add('popup-metadata');
+ elem.textContent = data.info;
+ popup(elem);
+ }
+ }, () => {});
+ event.stopPropagation();
+ event.preventDefault();
+}
+
function requestGet(url, data, handler, errorHandler) {
const xhr = new XMLHttpRequest();
const args = Object.keys(data).map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(data[k])}`).join('&');
diff --git a/javascript/logMonitor.js b/javascript/logMonitor.js
index f8718f0db..dce29c014 100644
--- a/javascript/logMonitor.js
+++ b/javascript/logMonitor.js
@@ -1,11 +1,15 @@
let logMonitorEl = null;
+let logMonitorStatus = true;
async function logMonitor() {
- setTimeout(logMonitor, opts.logmonitor_refresh_period);
+ if (logMonitorStatus) setTimeout(logMonitor, opts.logmonitor_refresh_period);
if (logMonitorEl) logMonitorEl.parentElement.style.display = opts.logmonitor_show ? 'block' : 'none';
if (!opts.logmonitor_show) return;
- const res = await fetch('/sdapi/v1/log?clear=True');
+ logMonitorStatus = false;
+ let res;
+ try { res = await fetch('/sdapi/v1/log?clear=True'); } catch {}
if (res?.ok) {
+ logMonitorStatus = true;
if (!logMonitorEl) logMonitorEl = document.getElementById('logMonitorData');
if (!logMonitorEl) return;
logMonitorEl.parentElement.style.display = 'block';
diff --git a/javascript/style.css b/javascript/style.css
index 3f0035073..fc1097f12 100644
--- a/javascript/style.css
+++ b/javascript/style.css
@@ -1,6 +1,7 @@
:root, .dark{ --checkbox-label-gap: 0.25em 0.1em; --section-header-text-size: 12pt; --block-background-fill: transparent;}
a { font-weight: bold; cursor: pointer; }
-div.gradio-container{ max-width: unset !important; }
+div.gradio-container{ max-width: unset !important; padding: 8px !important; }
+div.tabitem { padding: 0 !important; }
div.form{ border-width: 0; box-shadow: none; background: transparent; overflow: visible; gap: 0.5em; }
div.compact{ gap: 1em; }
div.gradio-html.min{ min-height: 0; }
@@ -33,6 +34,7 @@ div.gradio-html.min{ min-height: 0; }
.gradio-button.secondary-down:hover{ background: var(--button-secondary-background-fill-hover); color: var(--button-secondary-text-color-hover); }
.checkboxes-row{ margin-bottom: 0.5em; margin-left: 0em; }
.checkboxes-row > div{ flex: 0; white-space: nowrap; min-width: auto; }
+
button.custom-button{
border-radius: var(--button-large-radius);
padding: var(--button-large-padding);
@@ -141,30 +143,22 @@ div#extras_scale_to_tab div.form{
margin-bottom: 0.9em;
}
-#img2img_unused_scale_by_slider{
+#img2img_unused_scale_by_slider {
visibility: hidden;
width: 0.5em;
max-width: 0.5em;
min-width: 0.5em;
}
-.extra-network-cards{
- height: fit-content;
- max-height: 50vh;
- overflow-y: scroll;
- overflow-x: hidden;
- resize: vertical;
-}
-
.inactive{
opacity: 0.5;
}
-[id$=_column_batch]{
+[id$=_column_batch] {
min-width: min(13.5em, 100%) !important;
}
-div.dimensions-tools{
+div.dimensions-tools {
min-width: 0 !important;
max-width: fit-content;
flex-direction: row;
@@ -344,38 +338,15 @@ div#extras_scale_to_tab div.form{
padding: 0 0.5em;
}
-.livePreview{
- position: absolute;
- z-index: 300;
- background-color: transparent;
- width: -webkit-fill-available;
-}
-
-.dark .livePreview{
- background-color: rgb(17 24 39 / var(--tw-bg-opacity));
-}
-
-.livePreview img{
- position: absolute;
- object-fit: contain;
- width: 100%;
- height: 100%;
-}
-
-/* fullscreen popup (ie in Lora's (i) button) */
-
-.popup-metadata{
- color: black;
- background: white;
- display: inline-block;
- padding: 1em;
- white-space: pre-wrap;
-}
+.livePreview { position: absolute; z-index: 300; background-color: transparent; width: -webkit-fill-available; }
+.livePreview img { position: absolute; object-fit: contain; width: 100%; height: 100%; }
+.dark .livePreview { background-color: rgb(17 24 39 / var(--tw-bg-opacity)); }
+.popup-metadata { color: black; background: white; display: inline-block; padding: 1em; white-space: pre-wrap; font-size: 0.8em; opacity: 80%; }
.global-popup{
display: flex;
position: fixed;
- z-index: 1001;
+ z-index: 10001;
left: 0;
top: 0;
width: 100%;
@@ -548,7 +519,6 @@ table.settings-value-table td{
/* extensions */
-
#tab_extensions table{ border-collapse: collapse; }
#tab_extensions table td, #tab_extensions table th { border: 1px solid #ccc; padding: 0.25em 0.5em; }
#tab_extensions table input[type="checkbox"] { margin-right: 0.5em; appearance: checkbox; }
@@ -563,87 +533,26 @@ table.settings-value-table td{
.extension-button { font-size: 95% !important; width: 6em; }
/* extra networks */
-.extra-networks > div > [id *= '_extra_']{ margin: 0.3em; }
-.extra-network-subdirs { padding: 0.2em 0.35em; }
-.extra-network-subdirs button { margin: 0 0.15em; box-shadow: none; }
-.extra-networks .tab-nav .search { display: inline-block; max-width: 16em; margin: 0.3em; align-self: center; width: 16em; }
-#txt2img_extra_view, #img2img_extra_view { width: auto; }
-.extra-network-cards .nocards, .extra-network-thumbs .nocards{ margin: 1.25em 0.5em 0.5em 0.5em; }
-.extra-network-cards .nocards h1, .extra-network-thumbs .nocards h1{ font-size: 1.5em; margin-bottom: 1em; }
-.extra-network-cards .nocards li, .extra-network-thumbs .nocards li{ margin-left: 0.5em; }
-.extra-network-cards .card .metadata-button, .extra-network-thumbs .card .metadata-button{
- display: none;
- position: absolute;
- right: 0;
- color: white;
- text-shadow: 2px 2px 3px black;
- padding: 0.25em;
- font-size: 22pt;
- width: 1.5em;
-}
-.extra-network-cards .card:hover .metadata-button, .extra-network-thumbs .card:hover .metadata-button{ display: inline-block; }
-.extra-network-thumbs { display: flex; flex-flow: row wrap; gap: 10px; }
-.extra-network-cards .card .additional a:hover, .extra-network-thumbs .card .additional a:hover { color: darkorange }
-.extra-network-thumbs .card {
- display: inline-block;
- height: 9em;
- width: 9em;
- cursor: pointer;
- background-image: url('../html/card-no-preview.png');
- background-size: cover;
- background-position: center center;
- position: relative;
-}
-.extra-network-cards .card .additional, .extra-network-thumbs .card .additional { white-space: nowrap; overflow: hidden; }
-.extra-network-thumbs .card:hover .additional a { display: inline-block; }
-.extra-network-thumbs .actions .name {
- position: absolute;
- bottom: 0;
- font-size: 10px;
- padding: 3px;
- width: 100%;
- overflow: hidden;
- white-space: nowrap;
- text-overflow: ellipsis;
- background: rgba(0,0,0,.5);
- color: white;
-}
-.extra-network-thumbs .card:hover .actions .name { white-space: normal; word-break: break-all; }
-.extra-network-cards .card{
- display: inline-block;
- margin: 0.5em;
- width: 16em;
- height: 24em;
- box-shadow: 0 0 5px rgba(128, 128, 128, 0.5);
- border-radius: 0.2em;
- position: relative;
- background-size: cover;
- background-position: center;
- overflow: hidden;
- cursor: pointer;
- background-image: url('../html/card-no-preview.png')
-}
-.extra-network-cards .card:hover { box-shadow: 0 0 2px 0.3em rgba(0, 128, 255, 0.35); }
-.extra-network-cards .card .actions .additional, .extra-network-thumbs .card .actions .additional{ display: none; }
-.extra-network-cards .card .actions{
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- padding: 0.5em;
- background: rgba(0,0,0,0.5);
- box-shadow: 0 0 0.25em 0.25em rgba(0,0,0,0.5);
- text-shadow: 0 0 0.2em black;
-}
-.extra-network-cards .card .actions *{ color: white; }
-.extra-network-cards .card .actions:hover { box-shadow: 0 0 0.75em 0.75em rgba(0,0,0,0.5) !important; }
-.extra-network-cards .card .actions .name { font-size: 1.7em; font-weight: bold; line-break: anywhere; }
-.extra-network-cards .card .actions .description { display: block; max-height: 3em; white-space: pre-wrap; line-height: 1.1; }
-.extra-network-cards .card .actions .description:hover { max-height: none; }
-.extra-network-cards .card .actions:hover .additional, .extra-network-thumbs .card:hover .additional{ display: block; }
-.extra-network-cards .card ul{ margin: 0.25em 0 0.75em 0.25em; cursor: unset; }
-.extra-network-cards .card ul a{ cursor: pointer; }
-.extra-network-cards .card ul a:hover{ color: red; }
+.extra-networks > div { margin: 0; border-bottom: none !important; }
+.extra-networks .search { width: 150px; position: absolute; right: 0; height: unset !important; }
+.extra-networks .description { margin-top: 8px; }
+.extra-networks .tab-nav > button { margin-right: 0; height: auto; padding: 2px 4px 2px 4px; }
+.extra-networks-tab { padding: 0 !important; }
+.extra-network-subdirs { background: var(--input-background-fill); }
+.extra-networks-page { display: flex }
+.extra-networks .custom-button { min-width: 60px; width: 100%; background: none; justify-content: left; padding: 2px 8px 2px 8px; box-shadow: none; }
+.extra-networks .custom-button:hover { background: var(--button-primary-background-fill) }
+.extra-network-cards { display: flex; flex-wrap: wrap; height: 50vh; overflow-y: scroll; overflow-x: hidden; scroll-snap-type: y mandatory; }
+.extra-network-cards .card { height: fit-content; margin: 0.5em; position: relative; scroll-snap-align: start; scroll-margin-top: 0; }
+.extra-network-cards .card .overlay { position: absolute; bottom: 0; padding: 0.2em; z-index: 10; width: 100%; background: none; }
+.extra-network-cards .card:hover .overlay { background: rgba(0, 0, 0, 0.40); }
+.extra-network-cards .card .overlay .name { font-size: 1.2em; font-weight: bold; line-break: anywhere; text-shadow: 1px 1px black; }
+.extra-network-cards .card .overlay .actions { font-size: 1.8em; display: none; text-align-last: justify; cursor: pointer; word-spacing: -6px; }
+.extra-network-cards .card:hover .overlay .actions { display: block; }
+.extra-network-cards .card .overlay .description { line-break: anywhere; display: none; }
+.extra-network-cards .card:hover .overlay .description { display: block; }
+.extra-network-cards .card .preview { box-shadow: var(--button-shadow); min-height: 30px; }
+.extra-network-cards .card:hover .preview { box-shadow: none; }
/* controlnet */
.controlnet_control_type .controlnet_control_type_filter_group .wrap:last-of-type { display: grid; grid-auto-flow: row; grid-template-columns: repeat(4, minmax(0, 1fr)); }
diff --git a/modules/extra_networks.py b/modules/extra_networks.py
index 3a80fbe26..3793290ee 100644
--- a/modules/extra_networks.py
+++ b/modules/extra_networks.py
@@ -38,31 +38,18 @@ class ExtraNetwork:
def activate(self, p, params_list):
"""
- Called by processing on every run. Whatever the extra network is meant to do should be activated here.
- Passes arguments related to this extra network in params_list.
- User passes arguments by specifying this in his prompt:
-
+ Called by processing on every run. Whatever the extra network is meant to do should be activated here. Passes arguments related to this extra network in params_list. User passes arguments by specifying this in his prompt:
-
- Where name matches the name of this ExtraNetwork object, and arg1:arg2:arg3 are any natural number of text arguments
- separated by colon.
-
- Even if the user does not mention this ExtraNetwork in his prompt, the call will stil be made, with empty params_list -
- in this case, all effects of this extra networks should be disabled.
-
+ Where name matches the name of this ExtraNetwork object, and arg1:arg2:arg3 are any natural number of text arguments separated by colon.
+ Even if the user does not mention this ExtraNetwork in his prompt, the call will stil be made, with empty params_list - in this case, all effects of this extra networks should be disabled.
Can be called multiple times before deactivate() - each new call should override the previous call completely.
-
For example, if this ExtraNetwork's name is 'hypernet' and user's prompt is:
-
> "1girl, "
-
params_list will be:
-
[
ExtraNetworkParams(items=["agm", "1.1"]),
ExtraNetworkParams(items=["ray"])
]
-
"""
raise NotImplementedError
@@ -70,20 +57,16 @@ class ExtraNetwork:
"""
Called at the end of processing for housekeeping. No need to do anything here.
"""
-
raise NotImplementedError
def activate(p, extra_network_data):
- """call activate for extra networks in extra_network_data in specified order, then call
- activate for all remaining registered networks with an empty argument list"""
-
+ """call activate for extra networks in extra_network_data in specified order, then call activate for all remaining registered networks with an empty argument list"""
for extra_network_name, extra_network_args in extra_network_data.items():
extra_network = extra_network_registry.get(extra_network_name, None)
if extra_network is None:
print(f"Skipping unknown extra network: {extra_network_name}")
continue
-
try:
extra_network.activate(p, extra_network_args)
except Exception as e:
@@ -93,7 +76,6 @@ def activate(p, extra_network_data):
args = extra_network_data.get(extra_network_name, None)
if args is not None:
continue
-
try:
extra_network.activate(p, [])
except Exception as e:
@@ -101,14 +83,11 @@ def activate(p, extra_network_data):
def deactivate(p, extra_network_data):
- """call deactivate for extra networks in extra_network_data in specified order, then call
- deactivate for all remaining registered networks"""
-
+ """call deactivate for extra networks in extra_network_data in specified order, then call deactivate for all remaining registered networks"""
for extra_network_name in extra_network_data:
extra_network = extra_network_registry.get(extra_network_name, None)
if extra_network is None:
continue
-
try:
extra_network.deactivate(p)
except Exception as e:
@@ -118,7 +97,6 @@ def deactivate(p, extra_network_data):
args = extra_network_data.get(extra_network_name, None)
if args is not None:
continue
-
try:
extra_network.deactivate(p)
except Exception as e:
@@ -134,13 +112,9 @@ def parse_prompt(prompt):
def found(m):
name = m.group(1)
args = m.group(2)
-
res[name].append(ExtraNetworkParams(items=args.split(":")))
-
return ""
-
prompt = re.sub(re_extra_net, found, prompt)
-
return prompt, res
@@ -150,10 +124,8 @@ def parse_prompts(prompts):
for prompt in prompts:
updated_prompt, parsed_extra_data = parse_prompt(prompt)
-
if extra_data is None:
extra_data = parsed_extra_data
-
res.append(updated_prompt)
return res, extra_data
diff --git a/modules/generation_parameters_copypaste.py b/modules/generation_parameters_copypaste.py
index 2150c3d96..bccc7c0fe 100644
--- a/modules/generation_parameters_copypaste.py
+++ b/modules/generation_parameters_copypaste.py
@@ -105,11 +105,13 @@ def create_buttons(tabs_list):
for tab in tabs_list:
name = tab
if name == 'txt2img':
- name = 'text'
+ name = 'Text'
elif name == 'img2img':
- name = 'image'
+ name = 'Image'
+ elif name == 'inpaint':
+ name = 'Inpaint'
elif name == 'extras':
- name = 'process'
+ name = 'Process'
buttons[tab] = gr.Button(f"➠ {name}", elem_id=f"{tab}_tab")
return buttons
diff --git a/modules/lycoris b/modules/lycoris
index 4c2001111..b3776a3ab 160000
--- a/modules/lycoris
+++ b/modules/lycoris
@@ -1 +1 @@
-Subproject commit 4c200111133938d037c39dcc7d8481e4c1eecd20
+Subproject commit b3776a3ab9a61e8aaa9ea71f3b2073b0f2135c4b
diff --git a/modules/shared.py b/modules/shared.py
index b467638ec..11a711001 100644
--- a/modules/shared.py
+++ b/modules/shared.py
@@ -519,14 +519,15 @@ options_templates.update(options_section(('upscaling', "Upscaling"), {
}))
options_templates.update(options_section(('extra_networks', "Extra Networks"), {
+ "extra_networks_card_cover": OptionInfo("inline", "UI position", gr.Radio, lambda: {"choices": ["cover", "inline", "sidebar"]}),
+ "extra_networks_card_size": OptionInfo(200, "UI card size (px)", gr.Slider, {"minimum": 20, "maximum": 2000, "step": 1}),
+ "extra_networks_card_square": OptionInfo(False, "UI disable variable aspect ratio"),
+ "extra_networks_card_fit": OptionInfo("cover", "UI image contain method", gr.Radio, lambda: {"choices": ["contain", "cover", "fill"]}),
"lyco_patch_lora": OptionInfo(False, "Use LyCoris handler for all Lora types", gr.Checkbox),
"lora_disable": OptionInfo(False, "Disable built-in Lora handler", gr.Checkbox, { "visible": True }, onchange=lora_disable),
"lora_functional": OptionInfo(False, "Use Kohya method for handling multiple Loras", gr.Checkbox),
- "extra_networks_default_view": OptionInfo("cards", "Default view for Extra Networks", gr.Dropdown, {"choices": ["cards", "thumbs"]}),
- "extra_networks_default_multiplier": OptionInfo(1.0, "Multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
- "extra_networks_card_width": OptionInfo(0, "Card width for Extra Networks (px)"),
- "extra_networks_card_height": OptionInfo(0, "Card height for Extra Networks (px)"),
"extra_networks_add_text_separator": OptionInfo(" ", "Extra text to add before <...> when adding extra network to prompt", gr.Text, { "visible": False }),
+ "extra_networks_default_multiplier": OptionInfo(1.0, "Multiplier for extra networks", gr.Slider, {"minimum": 0.0, "maximum": 1.0, "step": 0.01}),
"sd_hypernetwork": OptionInfo("None", "Add hypernetwork to prompt", gr.Dropdown, lambda: {"choices": ["None"] + list(hypernetworks.keys())}, refresh=reload_hypernetworks),
}))
diff --git a/modules/ui.py b/modules/ui.py
index d90c12d1a..3edab8f2b 100644
--- a/modules/ui.py
+++ b/modules/ui.py
@@ -329,13 +329,13 @@ def create_ui():
modules.scripts.scripts_current = modules.scripts.scripts_txt2img
modules.scripts.scripts_txt2img.initialize_scripts(is_img2img=False)
with gr.Blocks(analytics_enabled=False) as txt2img_interface:
- txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, submit, _, _, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=False)
+ txt2img_prompt, txt2img_prompt_styles, txt2img_negative_prompt, submit, _interrogate, _deepbooru, txt2img_prompt_style_apply, txt2img_save_style, txt2img_paste, extra_networks_button, token_counter, token_button, negative_token_counter, negative_token_button = create_toprow(is_img2img=False)
dummy_component = gr.Label(visible=False)
txt_prompt_img = gr.File(label="", elem_id="txt2img_prompt_image", file_count="single", type="binary", visible=False)
with FormRow(variant='compact', elem_id="txt2img_extra_networks", visible=False) as extra_networks_ui:
from modules import ui_extra_networks
extra_networks_ui = ui_extra_networks.create_ui(extra_networks_ui, extra_networks_button, 'txt2img')
- with gr.Row().style(equal_height=False):
+ with gr.Row().style(equal_height=False, elem_id="txt2img_interface"):
with gr.Column(variant='compact', elem_id="txt2img_settings"):
for category in ordered_ui_categories():
if category == "sampler":
@@ -504,14 +504,14 @@ def create_ui():
from modules import ui_extra_networks
extra_networks_ui_img2img = ui_extra_networks.create_ui(extra_networks_ui, extra_networks_button, 'img2img')
- with FormRow().style(equal_height=False):
+ with FormRow().style(equal_height=False, elem_id="img2img_interface"):
with gr.Column(variant='compact', elem_id="img2img_settings"):
copy_image_buttons = []
copy_image_destinations = {}
def add_copy_image_controls(tab_name, elem):
with gr.Row(variant="compact", elem_id=f"img2img_copy_to_{tab_name}"):
- for title, name in zip(['➠ image', '➠ sketch', '➠ inpaint', '➠ inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']):
+ for title, name in zip(['➠ Image', '➠ Sketch', '➠ Inpaint', '➠ Inpaint sketch'], ['img2img', 'sketch', 'inpaint', 'inpaint_sketch']):
if name == tab_name:
gr.Button(title, interactive=False)
copy_image_destinations[name] = elem
diff --git a/modules/ui_common.py b/modules/ui_common.py
index a724e92df..ccd76024b 100644
--- a/modules/ui_common.py
+++ b/modules/ui_common.py
@@ -164,10 +164,10 @@ def create_output_panel(tabname, outdir):
with gr.Column():
with gr.Row(elem_id=f"image_buttons_{tabname}", elem_classes="image-buttons"):
- open_folder_button = gr.Button('show', visible=not shared.cmd_opts.hide_ui_dir_config)
- save = gr.Button('save', elem_id=f'save_{tabname}')
- save_zip = gr.Button('zip', elem_id=f'save_zip_{tabname}')
- delete = gr.Button('delete', elem_id=f'delete_{tabname}')
+ open_folder_button = gr.Button('Show', visible=not shared.cmd_opts.hide_ui_dir_config)
+ save = gr.Button('Save', elem_id=f'save_{tabname}')
+ save_zip = gr.Button('Zip', elem_id=f'save_zip_{tabname}')
+ delete = gr.Button('Delete', elem_id=f'delete_{tabname}')
buttons = parameters_copypaste.create_buttons(["img2img", "inpaint", "extras"])
open_folder_button.click(fn=lambda: open_folder(shared.opts.outdir_samples or outdir), inputs=[], outputs=[])
diff --git a/modules/ui_extra_networks.py b/modules/ui_extra_networks.py
index 164b8f4d3..ded4f809f 100644
--- a/modules/ui_extra_networks.py
+++ b/modules/ui_extra_networks.py
@@ -26,6 +26,8 @@ def register_page(page):
def fetch_file(filename: str = ""):
from starlette.responses import FileResponse, JSONResponse
+ if filename.startswith('html/'):
+ 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 os.path.splitext(filename)[1].lower() not in (".png", ".jpg", ".webp"):
@@ -37,28 +39,52 @@ def get_metadata(page: str = "", item: str = ""):
from starlette.responses import JSONResponse
page = next(iter([x for x in extra_pages if x.name == page]), None)
if page is None:
- return JSONResponse({})
- metadata = page.metadata.get(item)
- if metadata is None:
- return JSONResponse({})
+ return JSONResponse({ 'metadata': 'none' })
+ metadata = page.metadata.get(item, 'none')
return JSONResponse({"metadata": metadata})
+def get_info(page: str = "", item: str = ""):
+ from starlette.responses import JSONResponse
+ page = next(iter([x for x in extra_pages if x.name == page]), None)
+ if page is None:
+ return JSONResponse({ 'info': 'none' })
+ info = page.info.get(item, 'none')
+ return JSONResponse({"info": info})
+
+
def add_pages_to_demo(app):
app.add_api_route("/sd_extra_networks/thumb", fetch_file, methods=["GET"])
app.add_api_route("/sd_extra_networks/metadata", get_metadata, methods=["GET"])
+ app.add_api_route("/sd_extra_networks/info", get_info, methods=["GET"])
class ExtraNetworksPage:
def __init__(self, title):
self.title = title
self.name = title.lower()
- self.card_long = shared.html("extra-networks-card-long.html")
- self.card_short = shared.html("extra-networks-card-short.html")
self.allow_negative_prompt = False
self.metadata = {}
+ self.info = {}
self.items = []
self.missing_thumbs = []
+ self.card = '''
+
+
+ {search_term}
+
{name}
+
{description}
+
+ 💙
+ 📖
+ 🛅
+ 📘
+ ℹ️
+
+
+
+
+ ''' # noqa: RUF001
def refresh(self):
pass
@@ -93,8 +119,11 @@ class ExtraNetworksPage:
return ""
def is_empty(self, folder):
- files = [f for f in os.listdir(folder) if f.lower().endswith(".ckpt") or f.lower().endswith(".safetensors") or f.lower().endswith(".pt")]
- return len(files) == 0
+ for f in os.listdir(folder):
+ _fn, ext = os.path.splitext(f)
+ if ext.lower() in ['.ckpt', '.safetensors', '.pt'] or os.path.isdir(os.path.join(folder, f)):
+ return False
+ return True
def create_thumb(self):
created = 0
@@ -115,9 +144,7 @@ class ExtraNetworksPage:
self.missing_thumbs.clear()
def create_html(self, tabname):
- view = shared.opts.extra_networks_default_view
items_html = ''
- self.metadata = {}
subdirs = {}
allowed_folders = [os.path.abspath(x) for x in self.allowed_directories_for_previews()]
for parentdir in [*set(allowed_folders)]:
@@ -137,28 +164,27 @@ class ExtraNetworksPage:
subdirs_html = "".join([f"""
""" for subdir in subdirs])
- try:
- self.items = list(self.list_items())
- self.create_xyz_grid()
- for item in self.items:
- metadata = item.get("metadata")
- if metadata:
- self.metadata[item["name"]] = metadata
- items_html += self.create_html_for_item(item, tabname)
- if items_html == '':
- dirs = "".join([f"
{x}
" for x in self.allowed_directories_for_previews()])
- items_html = shared.html("extra-networks-no-cards.html").format(dirs=dirs)
- self_name_id = self.name.replace(" ", "_")
- res = f"""
-
{subdirs_html}
-
{items_html}
- """
- threading.Thread(target=self.create_thumb).start()
- return res
- except Exception as e:
- shared.log.error(f'Extra networks page error: {e}')
- return ''
+ """ for subdir in subdirs])
+# try:
+ self.items = list(self.list_items())
+ self.create_xyz_grid()
+ for item in self.items:
+ self.metadata[item["name"]] = item.get("metadata", {})
+ self.info[item["name"]] = self.find_info(item['filename'])
+ items_html += self.create_html_for_item(item, tabname)
+ if items_html == '':
+ dirs = "".join([f"
{x}
" for x in self.allowed_directories_for_previews()])
+ items_html = f'