forked from extern/easydiffusion
Merge branch 'beta' into refactor
This commit is contained in:
commit
25f488c6e1
@ -27,6 +27,7 @@
|
|||||||
- Support loading models in the safetensor format, for improved safety
|
- Support loading models in the safetensor format, for improved safety
|
||||||
|
|
||||||
### Detailed changelog
|
### Detailed changelog
|
||||||
|
* 2.4.19 - 10 Dec 2022 - Show init img in task list
|
||||||
* 2.4.19 - 7 Dec 2022 - Use pre-trained hypernetworks while generating images. Thanks @C0bra5
|
* 2.4.19 - 7 Dec 2022 - Use pre-trained hypernetworks while generating images. Thanks @C0bra5
|
||||||
* 2.4.19 - 6 Dec 2022 - Allow processing new tasks first. Thanks @madrang
|
* 2.4.19 - 6 Dec 2022 - Allow processing new tasks first. Thanks @madrang
|
||||||
* 2.4.19 - 6 Dec 2022 - Allow reordering the task queue (by dragging tasks). Thanks @madrang
|
* 2.4.19 - 6 Dec 2022 - Allow reordering the task queue (by dragging tasks). Thanks @madrang
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
<div id="tab-content-wrapper">
|
<div id="tab-content-wrapper">
|
||||||
<div id="tab-content-main" class="tab-content active flex-container">
|
<div id="tab-content-main" class="tab-content active flex-container">
|
||||||
<div id="editor">
|
<div id="editor" class="scrollbar-editor">
|
||||||
<div id="editor-inputs">
|
<div id="editor-inputs">
|
||||||
<div id="editor-inputs-prompt" class="row">
|
<div id="editor-inputs-prompt" class="row">
|
||||||
<label for="prompt"><b>Enter Prompt</b></label> <small>or</small> <button id="promptsFromFileBtn">Load from a file</button>
|
<label for="prompt"><b>Enter Prompt</b></label> <small>or</small> <button id="promptsFromFileBtn">Load from a file</button>
|
||||||
@ -55,7 +55,7 @@
|
|||||||
<input id="prompt_from_file" name="prompt_from_file" type="file" /> <!-- hidden -->
|
<input id="prompt_from_file" name="prompt_from_file" type="file" /> <!-- hidden -->
|
||||||
<label for="negative_prompt" class="collapsible" id="negative_prompt_handle">
|
<label for="negative_prompt" class="collapsible" id="negative_prompt_handle">
|
||||||
Negative Prompt
|
Negative Prompt
|
||||||
<a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Writing-prompts#negative-prompts" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip right">Click to learn more about Negative Prompts</span></i></a>
|
<a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Writing-prompts#negative-prompts" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Click to learn more about Negative Prompts</span></i></a>
|
||||||
<small>(optional)</small>
|
<small>(optional)</small>
|
||||||
</label>
|
</label>
|
||||||
<div class="collapsible-content">
|
<div class="collapsible-content">
|
||||||
@ -95,7 +95,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="editor-inputs-tags-container" class="row">
|
<div id="editor-inputs-tags-container" class="row">
|
||||||
<label>Image Modifiers <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip right">click an Image Modifier to remove it, use Ctrl+Mouse Wheel to adjust its weight</span></i>:</label>
|
<label>Image Modifiers <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">click an Image Modifier to remove it, use Ctrl+Mouse Wheel to adjust its weight</span></i>:</label>
|
||||||
<div id="editor-inputs-tags-list"></div>
|
<div id="editor-inputs-tags-list"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -109,7 +109,7 @@
|
|||||||
<h4 class="collapsible">
|
<h4 class="collapsible">
|
||||||
Image Settings
|
Image Settings
|
||||||
<i id="reset-image-settings" class="fa-solid fa-arrow-rotate-left section-button">
|
<i id="reset-image-settings" class="fa-solid fa-arrow-rotate-left section-button">
|
||||||
<span class="simple-tooltip right">
|
<span class="simple-tooltip top-left">
|
||||||
Reset Image Settings
|
Reset Image Settings
|
||||||
</span>
|
</span>
|
||||||
</i>
|
</i>
|
||||||
@ -123,13 +123,13 @@
|
|||||||
<select id="stable_diffusion_model" name="stable_diffusion_model">
|
<select id="stable_diffusion_model" name="stable_diffusion_model">
|
||||||
<!-- <option value="sd-v1-4" selected>sd-v1-4</option> -->
|
<!-- <option value="sd-v1-4" selected>sd-v1-4</option> -->
|
||||||
</select>
|
</select>
|
||||||
<a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Custom-Models" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip right">Click to learn more about custom models</span></i></a>
|
<a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/Custom-Models" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Click to learn more about custom models</span></i></a>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr class="pl-5"><td><label for="vae_model">Custom VAE:</i></label></td><td>
|
<tr class="pl-5"><td><label for="vae_model">Custom VAE:</i></label></td><td>
|
||||||
<select id="vae_model" name="vae_model">
|
<select id="vae_model" name="vae_model">
|
||||||
<!-- <option value="" selected>None</option> -->
|
<!-- <option value="" selected>None</option> -->
|
||||||
</select>
|
</select>
|
||||||
<a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/VAE-Variational-Auto-Encoder" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip right">Click to learn more about VAEs</span></i></a>
|
<a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/VAE-Variational-Auto-Encoder" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Click to learn more about VAEs</span></i></a>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr class="pl-5"><td><label for="hypernetwork_model">Hypernetwork:</i></label></td><td>
|
<tr class="pl-5"><td><label for="hypernetwork_model">Hypernetwork:</i></label></td><td>
|
||||||
<select id="hypernetwork_model" name="hypernetwork_model">
|
<select id="hypernetwork_model" name="hypernetwork_model">
|
||||||
@ -148,7 +148,7 @@
|
|||||||
<option value="dpm2_a">dpm2_a</option>
|
<option value="dpm2_a">dpm2_a</option>
|
||||||
<option value="lms">lms</option>
|
<option value="lms">lms</option>
|
||||||
</select>
|
</select>
|
||||||
<a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/How-to-Use#samplers" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip right">Click to learn more about samplers</span></i></a>
|
<a href="https://github.com/cmdr2/stable-diffusion-ui/wiki/How-to-Use#samplers" target="_blank"><i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">Click to learn more about samplers</span></i></a>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
<tr class="pl-5"><td><label>Image Size: </label></td><td>
|
<tr class="pl-5"><td><label>Image Size: </label></td><td>
|
||||||
<select id="width" name="width" value="512">
|
<select id="width" name="width" value="512">
|
||||||
@ -279,7 +279,7 @@
|
|||||||
<tr><td><label>Compatible Graphics Cards (all):</label></td><td id="system-info-gpus-all" class="value"></td></tr>
|
<tr><td><label>Compatible Graphics Cards (all):</label></td><td id="system-info-gpus-all" class="value"></td></tr>
|
||||||
<tr><td></td><td> </td></tr>
|
<tr><td></td><td> </td></tr>
|
||||||
<tr><td><label>Used for rendering 🔥:</label></td><td id="system-info-rendering-devices" class="value"></td></tr>
|
<tr><td><label>Used for rendering 🔥:</label></td><td id="system-info-rendering-devices" class="value"></td></tr>
|
||||||
<tr><td><label>Server Addresses <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip right">You can access Stable Diffusion UI from other devices using these addresses</span></i> :</label></td><td id="system-info-server-hosts" class="value"></td></tr>
|
<tr><td><label>Server Addresses <i class="fa-solid fa-circle-question help-btn"><span class="simple-tooltip top-left">You can access Stable Diffusion UI from other devices using these addresses</span></i> :</label></td><td id="system-info-server-hosts" class="value"></td></tr>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -783,9 +783,6 @@ input::file-selector-button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 700px) {
|
@media (min-width: 700px) {
|
||||||
/* #editor {
|
|
||||||
max-width: 480px;
|
|
||||||
}*/
|
|
||||||
.float-container {
|
.float-container {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
@ -794,6 +791,53 @@ input::file-selector-button {
|
|||||||
float: left;
|
float: left;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
#editor {
|
||||||
|
position: fixed;
|
||||||
|
overflow-y: auto;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding-right: 8px;
|
||||||
|
z-index: 1;
|
||||||
|
width: 374pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#preview {
|
||||||
|
padding-left: 380pt;
|
||||||
|
margin-right: 10pt;
|
||||||
|
left: 0;
|
||||||
|
right:0;
|
||||||
|
min-height: 80vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
#preview-pane {
|
||||||
|
display: none;
|
||||||
|
overflow-y: auto;
|
||||||
|
margin-top: 8pt;
|
||||||
|
left: 0;
|
||||||
|
right:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#preview-tools {
|
||||||
|
background: var(--background-color1);
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
transition: 0.25s;
|
||||||
|
z-index: 1;
|
||||||
|
padding-top:10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
-webkit-mask-image: linear-gradient(to bottom, black 0%, black 90%, transparent 100%);
|
||||||
|
mask-image: linear-gradient(to bottom, black 0%, black 50%, transparent 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
#editor-modifiers {
|
||||||
|
overflow-y: initial;
|
||||||
|
overflow-x: initial;
|
||||||
|
}
|
||||||
|
.image_preview_container {
|
||||||
|
padding: 6px;
|
||||||
|
width: 454px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.help-btn {
|
.help-btn {
|
||||||
@ -893,6 +937,15 @@ input::file-selector-button {
|
|||||||
transform: translate(-50%, 100%);
|
transform: translate(-50%, 100%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.simple-tooltip.top-left {
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
transform: translate(calc(-100% + 15%), calc(-100% + 15%));
|
||||||
|
}
|
||||||
|
:hover > .simple-tooltip.top-left {
|
||||||
|
transform: translate(-80%, -100%);
|
||||||
|
}
|
||||||
|
|
||||||
/* PROGRESS BAR */
|
/* PROGRESS BAR */
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
background: var(--background-color3);
|
background: var(--background-color3);
|
||||||
@ -901,6 +954,7 @@ input::file-selector-button {
|
|||||||
height: 16px;
|
height: 16px;
|
||||||
position: relative;
|
position: relative;
|
||||||
transition: 0.25s 1s border, 0.25s 1s height;
|
transition: 0.25s 1s border, 0.25s 1s height;
|
||||||
|
clear: both;
|
||||||
}
|
}
|
||||||
.progress-bar > div {
|
.progress-bar > div {
|
||||||
background: var(--accent-color);
|
background: var(--accent-color);
|
||||||
@ -1052,6 +1106,15 @@ button:active {
|
|||||||
left: 1px;
|
left: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.task-initimg > img {
|
||||||
|
margin-right: 6px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
div.task-fs-initimage {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
button#save-system-settings-btn {
|
button#save-system-settings-btn {
|
||||||
padding: 4pt 8pt;
|
padding: 4pt 8pt;
|
||||||
}
|
}
|
||||||
@ -1061,3 +1124,36 @@ button#save-system-settings-btn {
|
|||||||
#ip-info div {
|
#ip-info div {
|
||||||
line-height: 200%;
|
line-height: 200%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SCROLLBARS */
|
||||||
|
:root {
|
||||||
|
--scrollbar-width: 14px;
|
||||||
|
--scrollbar-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-editor::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-editor::-webkit-scrollbar-track {
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-editor::-webkit-scrollbar-thumb {
|
||||||
|
background: --background-color2;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: var(--scrollbar-width);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
box-shadow: inset 0 0 5px var(--input-border-color);
|
||||||
|
border-radius: var(--input-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: var(--background-color2);
|
||||||
|
border-radius: var(--scrollbar-radius);
|
||||||
|
}
|
||||||
|
@ -132,7 +132,7 @@ function loadSettings() {
|
|||||||
var saved_settings_text = localStorage.getItem(SETTINGS_KEY)
|
var saved_settings_text = localStorage.getItem(SETTINGS_KEY)
|
||||||
if (saved_settings_text) {
|
if (saved_settings_text) {
|
||||||
var saved_settings = JSON.parse(saved_settings_text)
|
var saved_settings = JSON.parse(saved_settings_text)
|
||||||
if (saved_settings.find(s => s.key == "auto_save_settings").value == false) {
|
if (saved_settings.find(s => s.key == "auto_save_settings")?.value == false) {
|
||||||
setSetting("auto_save_settings", false)
|
setSetting("auto_save_settings", false)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -457,7 +457,7 @@ function checkReadTextClipboardPermission (result) {
|
|||||||
// PASTE ICON
|
// PASTE ICON
|
||||||
const pasteIcon = document.createElement('i')
|
const pasteIcon = document.createElement('i')
|
||||||
pasteIcon.className = 'fa-solid fa-paste section-button'
|
pasteIcon.className = 'fa-solid fa-paste section-button'
|
||||||
pasteIcon.innerHTML = `<span class="simple-tooltip right">Paste Image Settings</span>`
|
pasteIcon.innerHTML = `<span class="simple-tooltip top-left">Paste Image Settings</span>`
|
||||||
pasteIcon.addEventListener('click', async (event) => {
|
pasteIcon.addEventListener('click', async (event) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
// Add css class 'active'
|
// Add css class 'active'
|
||||||
@ -497,7 +497,7 @@ function checkWriteToClipboardPermission (result) {
|
|||||||
// COPY ICON
|
// COPY ICON
|
||||||
const copyIcon = document.createElement('i')
|
const copyIcon = document.createElement('i')
|
||||||
copyIcon.className = 'fa-solid fa-clipboard section-button'
|
copyIcon.className = 'fa-solid fa-clipboard section-button'
|
||||||
copyIcon.innerHTML = `<span class="simple-tooltip right">Copy Image Settings</span>`
|
copyIcon.innerHTML = `<span class="simple-tooltip top-left">Copy Image Settings</span>`
|
||||||
copyIcon.addEventListener('click', (event) => {
|
copyIcon.addEventListener('click', (event) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
// Add css class 'active'
|
// Add css class 'active'
|
||||||
|
@ -196,7 +196,7 @@
|
|||||||
const eventSource = new GenericEventSource(EVENTS_TYPES)
|
const eventSource = new GenericEventSource(EVENTS_TYPES)
|
||||||
|
|
||||||
function setServerStatus(msgType, msg) {
|
function setServerStatus(msgType, msg) {
|
||||||
eventSource.fireEvent(EVENT_STATUS_CHANGED, {type: msgType, message: msg})
|
return eventSource.fireEvent(EVENT_STATUS_CHANGED, {type: msgType, message: msg})
|
||||||
}
|
}
|
||||||
|
|
||||||
const ServerStates = {
|
const ServerStates = {
|
||||||
@ -248,7 +248,7 @@
|
|||||||
setServerStatus('busy', 'rendering..')
|
setServerStatus('busy', 'rendering..')
|
||||||
break
|
break
|
||||||
default: // Unavailable
|
default: // Unavailable
|
||||||
console.error('Ping received an unexpedted server status. Status: %s', serverState.status)
|
console.error('Ping received an unexpected server status. Status: %s', serverState.status)
|
||||||
setServerStatus('error', serverState.status.toLowerCase())
|
setServerStatus('error', serverState.status.toLowerCase())
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -277,7 +277,7 @@
|
|||||||
case ServerStates.online:
|
case ServerStates.online:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
console.warn('Unexpedted server status. Server could be unavailable... Status: %s', serverState.status)
|
console.warn('Unexpected server status. Server could be unavailable... Status: %s', serverState.status)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -625,7 +625,7 @@
|
|||||||
}
|
}
|
||||||
this._setStatus(TaskStatus.pending)
|
this._setStatus(TaskStatus.pending)
|
||||||
task_queue.set(this, promiseGenerator)
|
task_queue.set(this, promiseGenerator)
|
||||||
eventSource.fireEvent(EVENT_TASK_QUEUED, {task:this})
|
await eventSource.fireEvent(EVENT_TASK_QUEUED, {task:this})
|
||||||
await Task.enqueue(promiseGenerator, ...args)
|
await Task.enqueue(promiseGenerator, ...args)
|
||||||
await this.waitUntil({status: TaskStatus.completed})
|
await this.waitUntil({status: TaskStatus.completed})
|
||||||
if (this.exception) {
|
if (this.exception) {
|
||||||
@ -841,7 +841,7 @@
|
|||||||
if (typeof jsonResponse?.task !== 'number') {
|
if (typeof jsonResponse?.task !== 'number') {
|
||||||
console.warn('Endpoint error response: ', jsonResponse)
|
console.warn('Endpoint error response: ', jsonResponse)
|
||||||
const event = Object.assign({task:this}, jsonResponse)
|
const event = Object.assign({task:this}, jsonResponse)
|
||||||
eventSource.fireEvent(EVENT_UNEXPECTED_RESPONSE, event)
|
await eventSource.fireEvent(EVENT_UNEXPECTED_RESPONSE, event)
|
||||||
if ('continueWith' in event) {
|
if ('continueWith' in event) {
|
||||||
jsonResponse = await Promise.resolve(event.continueWith)
|
jsonResponse = await Promise.resolve(event.continueWith)
|
||||||
}
|
}
|
||||||
@ -1079,12 +1079,13 @@
|
|||||||
|
|
||||||
function getServerCapacity() {
|
function getServerCapacity() {
|
||||||
let activeDevicesCount = Object.keys(serverState?.devices?.active || {}).length
|
let activeDevicesCount = Object.keys(serverState?.devices?.active || {}).length
|
||||||
if (window.document.visibilityState === 'hidden') {
|
if (typeof window === "object" && window.document.visibilityState === 'hidden') {
|
||||||
activeDevicesCount = 1 + activeDevicesCount
|
activeDevicesCount = 1 + activeDevicesCount
|
||||||
}
|
}
|
||||||
return activeDevicesCount
|
return activeDevicesCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let idleEventPromise = undefined
|
||||||
function continueTasks() {
|
function continueTasks() {
|
||||||
if (typeof navigator?.scheduling?.isInputPending === 'function') {
|
if (typeof navigator?.scheduling?.isInputPending === 'function') {
|
||||||
const inputPendingOptions = {
|
const inputPendingOptions = {
|
||||||
@ -1099,14 +1100,18 @@
|
|||||||
}
|
}
|
||||||
const serverCapacity = getServerCapacity()
|
const serverCapacity = getServerCapacity()
|
||||||
if (task_queue.size <= 0 && concurrent_generators.size <= 0) {
|
if (task_queue.size <= 0 && concurrent_generators.size <= 0) {
|
||||||
eventSource.fireEvent(EVENT_IDLE, {capacity: serverCapacity, idle: true})
|
if (!idleEventPromise?.isPending) {
|
||||||
|
idleEventPromise = makeQuerablePromise(eventSource.fireEvent(EVENT_IDLE, {capacity: serverCapacity, idle: true}))
|
||||||
|
}
|
||||||
// Calling idle could result in task being added to queue.
|
// Calling idle could result in task being added to queue.
|
||||||
if (task_queue.size <= 0 && concurrent_generators.size <= 0) {
|
if (task_queue.size <= 0 && concurrent_generators.size <= 0) {
|
||||||
return asyncDelay(IDLE_COOLDOWN)
|
return asyncDelay(IDLE_COOLDOWN).then(() => idleEventPromise)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (task_queue.size < serverCapacity) {
|
if (task_queue.size < serverCapacity) {
|
||||||
eventSource.fireEvent(EVENT_IDLE, {capacity: serverCapacity - task_queue.size})
|
if (!idleEventPromise?.isPending) {
|
||||||
|
idleEventPromise = makeQuerablePromise(eventSource.fireEvent(EVENT_IDLE, {capacity: serverCapacity - task_queue.size}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const completedTasks = []
|
const completedTasks = []
|
||||||
for (let [generator, promise] of concurrent_generators.entries()) {
|
for (let [generator, promise] of concurrent_generators.entries()) {
|
||||||
@ -1173,8 +1178,8 @@
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
const event = {task, generator};
|
const event = {task, generator};
|
||||||
eventSource.fireEvent(EVENT_TASK_START, event) // optional beforeStart promise to wait on before starting task.
|
const beforeStart = eventSource.fireEvent(EVENT_TASK_START, event) // optional beforeStart promise to wait on before starting task.
|
||||||
const promise = makeQuerablePromise(Promise.resolve(event.beforeStart))
|
const promise = makeQuerablePromise(beforeStart.then(() => Promise.resolve(event.beforeStart)))
|
||||||
concurrent_generators.set(event.generator, promise)
|
concurrent_generators.set(event.generator, promise)
|
||||||
task_queue.set(task, event.generator)
|
task_queue.set(task, event.generator)
|
||||||
}
|
}
|
||||||
@ -1199,7 +1204,7 @@
|
|||||||
}
|
}
|
||||||
const continuePromise = continueTasks().catch(async function(err) {
|
const continuePromise = continueTasks().catch(async function(err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
eventSource.fireEvent(EVENT_UNHANDLED_REJECTION, {reason: err})
|
await eventSource.fireEvent(EVENT_UNHANDLED_REJECTION, {reason: err})
|
||||||
await asyncDelay(RETRY_DELAY_ON_ERROR)
|
await asyncDelay(RETRY_DELAY_ON_ERROR)
|
||||||
})
|
})
|
||||||
taskPromise = makeQuerablePromise(continuePromise)
|
taskPromise = makeQuerablePromise(continuePromise)
|
||||||
|
@ -61,6 +61,29 @@ let maskSetting = document.querySelector('#enable_mask')
|
|||||||
|
|
||||||
const processOrder = document.querySelector('#process_order_toggle')
|
const processOrder = document.querySelector('#process_order_toggle')
|
||||||
|
|
||||||
|
const editorContainer = document.querySelector('#editor')
|
||||||
|
window.addEventListener("scroll", updatePreviewSize)
|
||||||
|
let lastScrollTop = 0
|
||||||
|
updatePreviewSize()
|
||||||
|
|
||||||
|
// update preview pane size and position
|
||||||
|
function updatePreviewSize() {
|
||||||
|
const scrollTop = window.pageYOffset || document.documentElement.scrollTop
|
||||||
|
if (scrollTop > lastScrollTop) {
|
||||||
|
previewTools.style.top = -previewTools.offsetHeight + 'px'
|
||||||
|
}
|
||||||
|
else if (scrollTop < lastScrollTop) {
|
||||||
|
const elem = preview.getElementsByClassName('img-batch')[0]
|
||||||
|
if (elem !== undefined && Math.round(window.scrollY) !== Math.round(elem.closest(".imageTaskContainer").offsetTop)) {
|
||||||
|
previewTools.style.top = '0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastScrollTop = scrollTop
|
||||||
|
|
||||||
|
$('#editor').css('top', Math.max(-window.pageYOffset + $("#tab-container").offset().top + $('#tab-container').outerHeight(true), 0) + 'px')
|
||||||
|
$('#editor').css('bottom', Math.max($(window).height() - ($("#footer .line-separator").offset().top - $(document).scrollTop()), 0) + 'px')
|
||||||
|
};
|
||||||
|
|
||||||
let imagePreview = document.querySelector("#preview")
|
let imagePreview = document.querySelector("#preview")
|
||||||
imagePreview.addEventListener('drop', function(ev) {
|
imagePreview.addEventListener('drop', function(ev) {
|
||||||
const data = ev.dataTransfer?.getData("text/plain");
|
const data = ev.dataTransfer?.getData("text/plain");
|
||||||
@ -269,9 +292,9 @@ function showImages(reqBody, res, outputContainer, livePreview) {
|
|||||||
imageElem.setAttribute('data-steps', imageInferenceSteps)
|
imageElem.setAttribute('data-steps', imageInferenceSteps)
|
||||||
imageElem.setAttribute('data-guidance', imageGuidanceScale)
|
imageElem.setAttribute('data-guidance', imageGuidanceScale)
|
||||||
|
|
||||||
|
|
||||||
const imageInfo = imageItemElem.querySelector('.imgItemInfo')
|
const imageInfo = imageItemElem.querySelector('.imgItemInfo')
|
||||||
imageInfo.style.visibility = (livePreview ? 'hidden' : 'visible')
|
imageInfo.style.visibility = (livePreview ? 'hidden' : 'visible')
|
||||||
|
updatePreviewSize()
|
||||||
|
|
||||||
if ('seed' in result && !imageElem.hasAttribute('data-seed')) {
|
if ('seed' in result && !imageElem.hasAttribute('data-seed')) {
|
||||||
const req = Object.assign({}, reqBody, {
|
const req = Object.assign({}, reqBody, {
|
||||||
@ -413,11 +436,7 @@ function getUncompletedTaskEntries() {
|
|||||||
document.querySelectorAll('#preview .imageTaskContainer .taskStatusLabel')
|
document.querySelectorAll('#preview .imageTaskContainer .taskStatusLabel')
|
||||||
).filter((taskLabel) => taskLabel.style.display !== 'none'
|
).filter((taskLabel) => taskLabel.style.display !== 'none'
|
||||||
).map(function(taskLabel) {
|
).map(function(taskLabel) {
|
||||||
let imageTaskContainer = taskLabel.parentNode
|
return taskLabel.closest('.imageTaskContainer')
|
||||||
while(!imageTaskContainer.classList.contains('imageTaskContainer') && imageTaskContainer.parentNode) {
|
|
||||||
imageTaskContainer = imageTaskContainer.parentNode
|
|
||||||
}
|
|
||||||
return imageTaskContainer
|
|
||||||
})
|
})
|
||||||
if (!processOrder.checked) {
|
if (!processOrder.checked) {
|
||||||
taskEntries.reverse()
|
taskEntries.reverse()
|
||||||
@ -438,10 +457,10 @@ function makeImage() {
|
|||||||
alert('The "Inference Steps" field must not be empty.')
|
alert('The "Inference Steps" field must not be empty.')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (numOutputsTotalField.value == '') {
|
if (numOutputsTotalField.value == '' || numOutputsTotalField.value == 0) {
|
||||||
numOutputsTotalField.value = 1
|
numOutputsTotalField.value = 1
|
||||||
}
|
}
|
||||||
if (numOutputsParallelField.value == '') {
|
if (numOutputsParallelField.value == '' || numOutputsParallelField.value == 0) {
|
||||||
numOutputsParallelField.value = 1
|
numOutputsParallelField.value = 1
|
||||||
}
|
}
|
||||||
if (guidanceScaleField.value == '') {
|
if (guidanceScaleField.value == '') {
|
||||||
@ -456,7 +475,7 @@ function makeImage() {
|
|||||||
initialText.style.display = 'none'
|
initialText.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
function onIdle() {
|
async function onIdle() {
|
||||||
const serverCapacity = SD.serverCapacity
|
const serverCapacity = SD.serverCapacity
|
||||||
for (const taskEntry of getUncompletedTaskEntries()) {
|
for (const taskEntry of getUncompletedTaskEntries()) {
|
||||||
if (SD.activeTasks.size >= serverCapacity) {
|
if (SD.activeTasks.size >= serverCapacity) {
|
||||||
@ -468,7 +487,7 @@ function onIdle() {
|
|||||||
taskStatusLabel.style.display = 'none'
|
taskStatusLabel.style.display = 'none'
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
onTaskStart(task)
|
await onTaskStart(task)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,10 +607,11 @@ function onTaskErrorHandler(task, reqBody, instance, reason) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onTaskCompleted(task, reqBody, instance, outputContainer, stepUpdate) {
|
function onTaskCompleted(task, reqBody, instance, outputContainer, stepUpdate) {
|
||||||
if (typeof stepUpdate !== 'object') {
|
if (typeof stepUpdate === 'object') {
|
||||||
return
|
if (stepUpdate.status === 'succeeded') {
|
||||||
}
|
showImages(reqBody, stepUpdate, outputContainer, false)
|
||||||
if (stepUpdate.status !== 'succeeded') {
|
} else {
|
||||||
|
task.isProcessing = false
|
||||||
const outputMsg = task['outputMsg']
|
const outputMsg = task['outputMsg']
|
||||||
let msg = ''
|
let msg = ''
|
||||||
if ('detail' in stepUpdate && typeof stepUpdate.detail === 'string' && stepUpdate.detail.length > 0) {
|
if ('detail' in stepUpdate && typeof stepUpdate.detail === 'string' && stepUpdate.detail.length > 0) {
|
||||||
@ -608,9 +628,8 @@ function onTaskCompleted(task, reqBody, instance, outputContainer, stepUpdate) {
|
|||||||
msg = `Unexpected Read Error:<br/><pre>StepUpdate: ${JSON.stringify(stepUpdate, undefined, 4)}</pre>`
|
msg = `Unexpected Read Error:<br/><pre>StepUpdate: ${JSON.stringify(stepUpdate, undefined, 4)}</pre>`
|
||||||
}
|
}
|
||||||
logError(msg, stepUpdate, outputMsg)
|
logError(msg, stepUpdate, outputMsg)
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
showImages(reqBody, stepUpdate, outputContainer, false)
|
}
|
||||||
if (task.isProcessing && task.batchesDone < task.batchCount) {
|
if (task.isProcessing && task.batchesDone < task.batchCount) {
|
||||||
task['taskStatusLabel'].innerText = "Pending"
|
task['taskStatusLabel'].innerText = "Pending"
|
||||||
task['taskStatusLabel'].classList.add('waitingTaskLabel')
|
task['taskStatusLabel'].classList.add('waitingTaskLabel')
|
||||||
@ -621,8 +640,6 @@ function onTaskCompleted(task, reqBody, instance, outputContainer, stepUpdate) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
setStatus('request', 'done', 'success')
|
|
||||||
|
|
||||||
task.isProcessing = false
|
task.isProcessing = false
|
||||||
task['stopTask'].innerHTML = '<i class="fa-solid fa-trash-can"></i> Remove'
|
task['stopTask'].innerHTML = '<i class="fa-solid fa-trash-can"></i> Remove'
|
||||||
task['taskStatusLabel'].style.display = 'none'
|
task['taskStatusLabel'].style.display = 'none'
|
||||||
@ -661,7 +678,7 @@ function onTaskCompleted(task, reqBody, instance, outputContainer, stepUpdate) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function onTaskStart(task) {
|
async function onTaskStart(task) {
|
||||||
if (!task.isProcessing || task.batchesDone >= task.batchCount) {
|
if (!task.isProcessing || task.batchesDone >= task.batchCount) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -699,22 +716,24 @@ function onTaskStart(task) {
|
|||||||
task.outputContainer.insertBefore(outputContainer, task.outputContainer.firstChild)
|
task.outputContainer.insertBefore(outputContainer, task.outputContainer.firstChild)
|
||||||
|
|
||||||
const eventInfo = {reqBody:newTaskReqBody}
|
const eventInfo = {reqBody:newTaskReqBody}
|
||||||
PLUGINS['TASK_CREATE'].forEach((hook) => {
|
const callbacksPromises = PLUGINS['TASK_CREATE'].map((hook) => {
|
||||||
if (typeof hook !== 'function') {
|
if (typeof hook !== 'function') {
|
||||||
console.error('The provided TASK_CREATE hook is not a function. Hook: %o', hook)
|
console.error('The provided TASK_CREATE hook is not a function. Hook: %o', hook)
|
||||||
return
|
return Promise.reject(new Error('hook is not a function.'))
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
hook.call(task, eventInfo)
|
return Promise.resolve(hook.call(task, eventInfo))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
return Promise.reject(err)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
await Promise.allSettled(callbacksPromises)
|
||||||
let instance = eventInfo.instance
|
let instance = eventInfo.instance
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
const factory = PLUGINS.OUTPUTS_FORMATS.get(eventInfo.reqBody?.output_format || newTaskReqBody.output_format)
|
const factory = PLUGINS.OUTPUTS_FORMATS.get(eventInfo.reqBody?.output_format || newTaskReqBody.output_format)
|
||||||
if (factory) {
|
if (factory) {
|
||||||
instance = factory(eventInfo.reqBody || newTaskReqBody)
|
instance = await Promise.resolve(factory(eventInfo.reqBody || newTaskReqBody))
|
||||||
}
|
}
|
||||||
if (!instance) {
|
if (!instance) {
|
||||||
console.error(`${factory ? "Factory " + String(factory) : 'No factory defined'} for output format ${eventInfo.reqBody?.output_format || newTaskReqBody.output_format}. Instance is ${instance || 'undefined'}. Using default renderer.`)
|
console.error(`${factory ? "Factory " + String(factory) : 'No factory defined'} for output format ${eventInfo.reqBody?.output_format || newTaskReqBody.output_format}. Instance is ${instance || 'undefined'}. Using default renderer.`)
|
||||||
@ -740,8 +759,38 @@ function onTaskStart(task) {
|
|||||||
previewTools.style.display = 'block'
|
previewTools.style.display = 'block'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Hover effect for the init image in the task list */
|
||||||
|
function createInitImageHover(taskEntry) {
|
||||||
|
var $tooltip = $( taskEntry.querySelector('.task-fs-initimage') )
|
||||||
|
$( taskEntry.querySelector('div.task-initimg > img') ).on('mouseenter', function() {
|
||||||
|
var img = this,
|
||||||
|
$img = $(img),
|
||||||
|
offset = $img.offset();
|
||||||
|
|
||||||
|
$tooltip
|
||||||
|
.css({
|
||||||
|
'top': offset.top,
|
||||||
|
'left': offset.left,
|
||||||
|
'z-index': 99999,
|
||||||
|
'display': 'block'
|
||||||
|
})
|
||||||
|
.append($img.clone().css({width:"", height:""}));
|
||||||
|
})
|
||||||
|
$tooltip.on('mouseleave', function() {
|
||||||
|
$tooltip.empty().addClass('hidden');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function createTask(task) {
|
function createTask(task) {
|
||||||
let taskConfig = `<b>Seed:</b> ${task.seed}, <b>Sampler:</b> ${task.reqBody.sampler_name}, <b>Inference Steps:</b> ${task.reqBody.num_inference_steps}, <b>Guidance Scale:</b> ${task.reqBody.guidance_scale}, <b>Model:</b> ${task.reqBody.use_stable_diffusion_model}`
|
let taskConfig = ''
|
||||||
|
|
||||||
|
if (task.reqBody.init_image !== undefined) {
|
||||||
|
let h = 80
|
||||||
|
let w = task.reqBody.width * h / task.reqBody.height >>0
|
||||||
|
taskConfig += `<div class="task-initimg" style="float:left;"><img style="width:${w}px;height:${h}px;" src="${task.reqBody.init_image}"><div class="task-fs-initimage"></div></div>`
|
||||||
|
}
|
||||||
|
taskConfig += `<b>Seed:</b> ${task.seed}, <b>Sampler:</b> ${task.reqBody.sampler_name}, <b>Inference Steps:</b> ${task.reqBody.num_inference_steps}, <b>Guidance Scale:</b> ${task.reqBody.guidance_scale}, <b>Model:</b> ${task.reqBody.use_stable_diffusion_model}`
|
||||||
|
|
||||||
if (task.reqBody.use_vae_model.trim() !== '') {
|
if (task.reqBody.use_vae_model.trim() !== '') {
|
||||||
taskConfig += `, <b>VAE:</b> ${task.reqBody.use_vae_model}`
|
taskConfig += `, <b>VAE:</b> ${task.reqBody.use_vae_model}`
|
||||||
}
|
}
|
||||||
@ -783,6 +832,11 @@ function createTask(task) {
|
|||||||
|
|
||||||
createCollapsibles(taskEntry)
|
createCollapsibles(taskEntry)
|
||||||
|
|
||||||
|
|
||||||
|
if (task.reqBody.init_image !== undefined) {
|
||||||
|
createInitImageHover(taskEntry)
|
||||||
|
}
|
||||||
|
|
||||||
task['taskStatusLabel'] = taskEntry.querySelector('.taskStatusLabel')
|
task['taskStatusLabel'] = taskEntry.querySelector('.taskStatusLabel')
|
||||||
task['outputContainer'] = taskEntry.querySelector('.img-preview')
|
task['outputContainer'] = taskEntry.querySelector('.img-preview')
|
||||||
task['outputMsg'] = taskEntry.querySelector('.outputMsg')
|
task['outputMsg'] = taskEntry.querySelector('.outputMsg')
|
||||||
@ -794,7 +848,7 @@ function createTask(task) {
|
|||||||
let question = (task['isProcessing'] ? "Stop this task?" : "Remove this task?")
|
let question = (task['isProcessing'] ? "Stop this task?" : "Remove this task?")
|
||||||
shiftOrConfirm(e, question, async function(e) {
|
shiftOrConfirm(e, question, async function(e) {
|
||||||
if (task.batchesDone <= 0 || !task.isProcessing) {
|
if (task.batchesDone <= 0 || !task.isProcessing) {
|
||||||
taskEntry.remove()
|
removeTask(taskEntry)
|
||||||
}
|
}
|
||||||
abortTask(task)
|
abortTask(task)
|
||||||
})
|
})
|
||||||
@ -904,14 +958,16 @@ function getPrompts(prompts) {
|
|||||||
prompts = prompts.map(prompt => prompt.trim())
|
prompts = prompts.map(prompt => prompt.trim())
|
||||||
prompts = prompts.filter(prompt => prompt !== '')
|
prompts = prompts.filter(prompt => prompt !== '')
|
||||||
|
|
||||||
|
let promptsToMake = applyPermuteOperator(prompts)
|
||||||
|
promptsToMake = applySetOperator(promptsToMake)
|
||||||
const newTags = activeTags.filter(tag => tag.inactive === undefined || tag.inactive === false)
|
const newTags = activeTags.filter(tag => tag.inactive === undefined || tag.inactive === false)
|
||||||
if (newTags.length > 0) {
|
if (newTags.length > 0) {
|
||||||
const promptTags = newTags.map(x => x.name).join(", ")
|
const promptTags = newTags.map(x => x.name).join(", ")
|
||||||
prompts = prompts.map((prompt) => `${prompt}, ${promptTags}`)
|
promptsToMake = promptsToMake.map((prompt) => `${prompt}, ${promptTags}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
let promptsToMake = applySetOperator(prompts)
|
|
||||||
promptsToMake = applyPermuteOperator(promptsToMake)
|
promptsToMake = applyPermuteOperator(promptsToMake)
|
||||||
|
promptsToMake = applySetOperator(promptsToMake)
|
||||||
|
|
||||||
return promptsToMake
|
return promptsToMake
|
||||||
}
|
}
|
||||||
@ -1023,6 +1079,7 @@ function removeTask(taskToRemove) {
|
|||||||
previewTools.style.display = 'none'
|
previewTools.style.display = 'none'
|
||||||
initialText.style.display = 'block'
|
initialText.style.display = 'block'
|
||||||
}
|
}
|
||||||
|
updatePreviewSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
clearAllPreviewsBtn.addEventListener('click', (e) => { shiftOrConfirm(e, "Clear all the results and tasks in this window?", async function() {
|
clearAllPreviewsBtn.addEventListener('click', (e) => { shiftOrConfirm(e, "Clear all the results and tasks in this window?", async function() {
|
||||||
|
@ -561,16 +561,22 @@ class GenericEventSource {
|
|||||||
throw new Error(`Event ${String(name)} missing from Events.types`)
|
throw new Error(`Event ${String(name)} missing from Events.types`)
|
||||||
}
|
}
|
||||||
if (!this.#events.hasOwnProperty(name)) {
|
if (!this.#events.hasOwnProperty(name)) {
|
||||||
return
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
if (!args || !args.length) {
|
if (!args || !args.length) {
|
||||||
args = []
|
args = []
|
||||||
}
|
}
|
||||||
const evs = this.#events[name]
|
const evs = this.#events[name]
|
||||||
const len = evs.length
|
if (evs.length <= 0) {
|
||||||
for (let i = 0; i < len; ++i) {
|
return Promise.resolve()
|
||||||
evs[i].apply(SD, args)
|
|
||||||
}
|
}
|
||||||
|
return Promise.allSettled(evs.map((callback) => {
|
||||||
|
try {
|
||||||
|
return Promise.resolve(callback.apply(SD, args))
|
||||||
|
} catch (ex) {
|
||||||
|
return Promise.reject(ex)
|
||||||
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,17 +17,11 @@
|
|||||||
prettifyInputs(document);
|
prettifyInputs(document);
|
||||||
let autoScroll = document.querySelector("#auto_scroll")
|
let autoScroll = document.querySelector("#auto_scroll")
|
||||||
|
|
||||||
/**
|
// save/restore the toggle state
|
||||||
* the use of initSettings() in the autoscroll plugin seems to be breaking the models dropdown and the save-to-disk folder field
|
autoScroll.addEventListener('click', (e) => {
|
||||||
* in the settings tab. They're both blank, because they're being re-initialized. Their earlier values came from the API call,
|
localStorage.setItem('auto_scroll', autoScroll.checked)
|
||||||
* but those values aren't stored in localStorage, since they aren't user-specified.
|
})
|
||||||
* So when initSettings() is called a second time, it overwrites the values with an empty string.
|
autoScroll.checked = localStorage.getItem('auto_scroll') == "true"
|
||||||
*
|
|
||||||
* We could either rework how new components can register themselves to be auto-saved, without having to call initSettings() again.
|
|
||||||
* Or we could move the autoscroll code into the main code, and include it in the list of fields in auto-save.js
|
|
||||||
*/
|
|
||||||
// SETTINGS_IDS_LIST.push("auto_scroll")
|
|
||||||
// initSettings()
|
|
||||||
|
|
||||||
// observe for changes in the preview pane
|
// observe for changes in the preview pane
|
||||||
var observer = new MutationObserver(function (mutations) {
|
var observer = new MutationObserver(function (mutations) {
|
||||||
|
Loading…
Reference in New Issue
Block a user