diff --git a/ui/index.html b/ui/index.html index 14cf25ec..776eb627 100644 --- a/ui/index.html +++ b/ui/index.html @@ -17,6 +17,7 @@ + diff --git a/ui/media/css/animations.css b/ui/media/css/animations.css new file mode 100644 index 00000000..71ee642f --- /dev/null +++ b/ui/media/css/animations.css @@ -0,0 +1,68 @@ +@keyframes ldio-8f673ktaleu-1 { + 0% { transform: rotate(0deg) } + 50% { transform: rotate(-45deg) } + 100% { transform: rotate(0deg) } +} +@keyframes ldio-8f673ktaleu-2 { + 0% { transform: rotate(180deg) } + 50% { transform: rotate(225deg) } + 100% { transform: rotate(180deg) } +} +.ldio-8f673ktaleu > div:nth-child(2) { + transform: translate(-15px,0); +} +.ldio-8f673ktaleu > div:nth-child(2) div { + position: absolute; + top: 20px; + left: 20px; + width: 60px; + height: 30px; + border-radius: 60px 60px 0 0; + background: #f3b72e; + animation: ldio-8f673ktaleu-1 1s linear infinite; + transform-origin: 30px 30px +} +.ldio-8f673ktaleu > div:nth-child(2) div:nth-child(2) { + animation: ldio-8f673ktaleu-2 1s linear infinite +} +.ldio-8f673ktaleu > div:nth-child(2) div:nth-child(3) { + transform: rotate(-90deg); + animation: none; +}@keyframes ldio-8f673ktaleu-3 { + 0% { transform: translate(95px,0); opacity: 0 } + 20% { opacity: 1 } + 100% { transform: translate(35px,0); opacity: 1 } +} +.ldio-8f673ktaleu > div:nth-child(1) { + display: block; +} +.ldio-8f673ktaleu > div:nth-child(1) div { + position: absolute; + top: 46px; + left: -4px; + width: 8px; + height: 8px; + border-radius: 50%; + background: #3869c5; + animation: ldio-8f673ktaleu-3 1s linear infinite +} +.ldio-8f673ktaleu > div:nth-child(1) div:nth-child(1) { animation-delay: -0.67s } +.ldio-8f673ktaleu > div:nth-child(1) div:nth-child(2) { animation-delay: -0.33s } +.ldio-8f673ktaleu > div:nth-child(1) div:nth-child(3) { animation-delay: 0s } +.loadingio-spinner-bean-eater-x0y3u8qky4n { + width: 58px; + height: 58px; + display: inline-block; + overflow: hidden; + background: none; +} +.ldio-8f673ktaleu { + width: 100%; + height: 100%; + position: relative; + transform: translateZ(0) scale(0.58); + backface-visibility: hidden; + transform-origin: 0 0; /* see note above */ +} +.ldio-8f673ktaleu div { box-sizing: content-box; } +/* generated by https://loading.io/ */ diff --git a/ui/media/css/main.css b/ui/media/css/main.css index f6be52c5..4d7a0f62 100644 --- a/ui/media/css/main.css +++ b/ui/media/css/main.css @@ -1753,3 +1753,20 @@ body.wait-pause { content: "Please restart Easy Diffusion!"; font-size: 10pt; } + +.imgContainer .spinner { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + margin: 0; + padding: 0; + + background: var(--background-color3); + opacity: 0.8; + border-radius: 5px; + padding: 4pt; +} +.imgContainer .spinnerStatus { + font-size: 10pt; +} diff --git a/ui/media/js/engine.js b/ui/media/js/engine.js index c584a609..a11dd8b3 100644 --- a/ui/media/js/engine.js +++ b/ui/media/js/engine.js @@ -1056,11 +1056,26 @@ * @memberof Task */ async post(timeout = -1) { - let res = await super.post("/filter", timeout) - //this._setId(jsonResponse.task) + let jsonResponse = await super.post("/filter", timeout) + if (typeof jsonResponse?.task !== "number") { + console.warn("Endpoint error response: ", jsonResponse) + const event = Object.assign({ task: this }, jsonResponse) + await eventSource.fireEvent(EVENT_UNEXPECTED_RESPONSE, event) + if ("continueWith" in event) { + jsonResponse = await Promise.resolve(event.continueWith) + } + if (typeof jsonResponse?.task !== "number") { + const err = new Error(jsonResponse?.detail || "Endpoint response does not contains a task ID.") + this.abort(err) + throw err + } + } + this._setId(jsonResponse.task) + if (jsonResponse.stream) { + this.streamUrl = jsonResponse.stream + } this._setStatus(TaskStatus.waiting) - - return res + return jsonResponse } checkReqBody() {} enqueue(progressCallback) { @@ -1087,6 +1102,51 @@ yield progressCallback?.call(this, { detail: e.message }) throw e } + + try { + // Wait for task to start on server. + yield this.waitUntil({ + callback: function() { + return progressCallback?.call(this, {}) + }, + status: TaskStatus.processing, + }) + } catch (e) { + this.abort(err) + throw e + } + + // Task started! + // Open the reader. + const reader = this.reader + const task = this + reader.onError = function(response) { + if (progressCallback) { + task.abort(new Error(response.statusText)) + return progressCallback.call(task, { response, reader }) + } + return Task.prototype.onError.call(task, response) + } + yield progressCallback?.call(this, { reader }) + + //Start streaming the results. + const streamGenerator = reader.open() + let value = undefined + let done = undefined + yield progressCallback?.call(this, { stream: streamGenerator }) + do { + ;({ value, done } = yield streamGenerator.next()) + if (typeof value !== "object") { + continue + } + if (value.status !== undefined) { + yield progressCallback?.call(this, value) + if (value.status === "succeeded" || value.status === "failed") { + done = true + } + } + } while (!done) + return value } static start(task, progressCallback) { if (typeof task !== "object") { diff --git a/ui/media/js/main.js b/ui/media/js/main.js index 0b936066..3bfc3233 100644 --- a/ui/media/js/main.js +++ b/ui/media/js/main.js @@ -5,6 +5,9 @@ const MIN_GPUS_TO_SHOW_SELECTION = 2 const IMAGE_REGEX = new RegExp("data:image/[A-Za-z]+;base64") const htmlTaskMap = new WeakMap() +const spinnerPacmanHtml = + '