Added Progess to Page Title as mentioned in #307

This commit is contained in:
ManInDark 2023-06-26 19:36:26 +02:00
parent 398a0509d7
commit 49445d6473
No known key found for this signature in database
GPG Key ID: 72EC12A5B2D62779

View File

@ -62,6 +62,7 @@ const taskConfigSetup = {
let imageCounter = 0 let imageCounter = 0
let imageRequest = [] let imageRequest = []
let SHOW_PROGRESS = true
let promptField = document.querySelector("#prompt") let promptField = document.querySelector("#prompt")
let promptsFromFileSelector = document.querySelector("#prompt_from_file") let promptsFromFileSelector = document.querySelector("#prompt_from_file")
@ -1044,13 +1045,345 @@ function makeImage() {
newTaskRequests.forEach(createTask) newTaskRequests.forEach(createTask)
updateInitialText() updateInitialText()
}
const countBeforeBanner = localStorage.getItem("countBeforeBanner") || 1 async function onIdle() {
if (countBeforeBanner <= 0) { const serverCapacity = SD.serverCapacity
// supportBanner.classList.remove("displayNone") if (pauseClient === true) {
await resumeClient()
}
for (const taskEntry of getUncompletedTaskEntries()) {
if (SD.activeTasks.size >= serverCapacity) {
break
}
const task = htmlTaskMap.get(taskEntry)
if (!task) {
const taskStatusLabel = taskEntry.querySelector(".taskStatusLabel")
taskStatusLabel.style.display = "none"
continue
}
await onTaskStart(task)
}
}
function getTaskUpdater(task, reqBody, outputContainer) {
const outputMsg = task["outputMsg"]
const progressBar = task["progressBar"]
const progressBarInner = progressBar.querySelector("div")
const batchCount = task.batchCount
let lastStatus = undefined
return async function(event) {
if (this.status !== lastStatus) {
lastStatus = this.status
switch (this.status) {
case SD.TaskStatus.pending:
task["taskStatusLabel"].innerText = "Pending"
task["taskStatusLabel"].classList.add("waitingTaskLabel")
break
case SD.TaskStatus.waiting:
task["taskStatusLabel"].innerText = "Waiting"
task["taskStatusLabel"].classList.add("waitingTaskLabel")
task["taskStatusLabel"].classList.remove("activeTaskLabel")
break
case SD.TaskStatus.processing:
case SD.TaskStatus.completed:
task["taskStatusLabel"].innerText = "Processing"
task["taskStatusLabel"].classList.add("activeTaskLabel")
task["taskStatusLabel"].classList.remove("waitingTaskLabel")
break
case SD.TaskStatus.stopped:
break
case SD.TaskStatus.failed:
if (!SD.isServerAvailable()) {
logError(
"Stable Diffusion is still starting up, please wait. If this goes on beyond a few minutes, Stable Diffusion has probably crashed. Please check the error message in the command-line window.",
event,
outputMsg
)
} else if (typeof event?.response === "object") {
let msg = "Stable Diffusion had an error reading the response:<br/><pre>"
if (this.exception) {
msg += `Error: ${this.exception.message}<br/>`
}
try {
// 'Response': body stream already read
msg += "Read: " + (await event.response.text())
} catch (e) {
msg += "Unexpected end of stream. "
}
const bufferString = event.reader.bufferedString
if (bufferString) {
msg += "Buffered data: " + bufferString
}
msg += "</pre>"
logError(msg, event, outputMsg)
}
break
}
}
if ("update" in event) {
const stepUpdate = event.update
if (!("step" in stepUpdate)) {
return
}
// task.instances can be a mix of different tasks with uneven number of steps (Render Vs Filter Tasks)
const overallStepCount =
task.instances.reduce(
(sum, instance) =>
sum +
(instance.isPending
? Math.max(0, instance.step || stepUpdate.step) /
(instance.total_steps || stepUpdate.total_steps)
: 1),
0 // Initial value
) * stepUpdate.total_steps // Scale to current number of steps.
const totalSteps = task.instances.reduce(
(sum, instance) => sum + (instance.total_steps || stepUpdate.total_steps),
stepUpdate.total_steps * (batchCount - task.batchesDone) // Initial value at (unstarted task count * Nbr of steps)
)
const percent = Math.min(100, 100 * (overallStepCount / totalSteps)).toFixed(0)
if (SHOW_PROGRESS) {
document.title = `${percent}% - Easy Diffusion`
}
const timeTaken = stepUpdate.step_time // sec
const stepsRemaining = Math.max(0, totalSteps - overallStepCount)
const timeRemaining = timeTaken < 0 ? "" : millisecondsToStr(stepsRemaining * timeTaken * 1000)
outputMsg.innerHTML = `Batch ${task.batchesDone} of ${batchCount}. Generating image(s): ${percent}%. Time remaining (approx): ${timeRemaining}`
outputMsg.style.display = "block"
progressBarInner.style.width = `${percent}%`
if (stepUpdate.output) {
showImages(reqBody, stepUpdate, outputContainer, true)
}
}
}
}
function abortTask(task) {
if (!task.isProcessing) {
return false
}
task.isProcessing = false
task.progressBar.classList.remove("active")
task["taskStatusLabel"].style.display = "none"
task["stopTask"].innerHTML = '<i class="fa-solid fa-trash-can"></i> Remove'
if (!task.instances?.some((r) => r.isPending)) {
return
}
task.instances.forEach((instance) => {
try {
instance.abort()
} catch (e) {
console.error(e)
}
})
if (SHOW_PROGRESS) {
document.title = "Stopped - Easy Diffusion"
}
}
function onTaskErrorHandler(task, reqBody, instance, reason) {
if (!task.isProcessing) {
return
}
console.log("Render request %o, Instance: %o, Error: %s", reqBody, instance, reason)
abortTask(task)
const outputMsg = task["outputMsg"]
logError(
"Stable Diffusion had an error. Please check the logs in the command-line window. <br/><br/>" +
reason +
"<br/><pre>" +
reason.stack +
"</pre>",
task,
outputMsg
)
setStatus("request", "error", "error")
}
function onTaskCompleted(task, reqBody, instance, outputContainer, stepUpdate) {
if (typeof stepUpdate === "object") {
if (stepUpdate.status === "succeeded") {
showImages(reqBody, stepUpdate, outputContainer, false)
} else {
task.isProcessing = false
const outputMsg = task["outputMsg"]
let msg = ""
if ("detail" in stepUpdate && typeof stepUpdate.detail === "string" && stepUpdate.detail.length > 0) {
msg = stepUpdate.detail
if (msg.toLowerCase().includes("out of memory")) {
msg += `<br/><br/>
<b>Suggestions</b>:
<br/>
1. If you have set an initial image, please try reducing its dimension to ${MAX_INIT_IMAGE_DIMENSION}x${MAX_INIT_IMAGE_DIMENSION} or smaller.<br/>
2. Try picking a lower level in the '<em>GPU Memory Usage</em>' setting (in the '<em>Settings</em>' tab).<br/>
3. Try generating a smaller image.<br/>`
} else if (msg.includes("DefaultCPUAllocator: not enough memory")) {
msg += `<br/><br/>
Reason: Your computer is running out of system RAM!
<br/><br/>
<b>Suggestions</b>:
<br/>
1. Try closing unnecessary programs and browser tabs.<br/>
2. If that doesn't help, please increase your computer's virtual memory by following these steps for
<a href="https://www.ibm.com/docs/en/opw/8.2.0?topic=tuning-optional-increasing-paging-file-size-windows-computers" target="_blank">Windows</a> or
<a href="https://linuxhint.com/increase-swap-space-linux/" target="_blank">Linux</a>.<br/>
3. Try restarting your computer.<br/>`
}
} else {
msg = `Unexpected Read Error:<br/><pre>StepUpdate: ${JSON.stringify(stepUpdate, undefined, 4)}</pre>`
}
logError(msg, stepUpdate, outputMsg)
}
}
if (task.isProcessing && task.batchesDone < task.batchCount) {
task["taskStatusLabel"].innerText = "Pending"
task["taskStatusLabel"].classList.add("waitingTaskLabel")
task["taskStatusLabel"].classList.remove("activeTaskLabel")
return
}
if ("instances" in task && task.instances.some((ins) => ins != instance && ins.isPending)) {
return
}
task.isProcessing = false
task["stopTask"].innerHTML = '<i class="fa-solid fa-trash-can"></i> Remove'
task["taskStatusLabel"].style.display = "none"
let time = millisecondsToStr(Date.now() - task.startTime)
if (task.batchesDone == task.batchCount) {
if (!task.outputMsg.innerText.toLowerCase().includes("error")) {
task.outputMsg.innerText = `Processed ${task.numOutputsTotal} images in ${time}`
}
task.progressBar.style.height = "0px"
task.progressBar.style.border = "0px solid var(--background-color3)"
task.progressBar.classList.remove("active")
setStatus("request", "done", "success")
} else { } else {
localStorage.setItem("countBeforeBanner", countBeforeBanner - 1) localStorage.setItem("countBeforeBanner", countBeforeBanner - 1)
} }
if (randomSeedField.checked) {
seedField.value = task.seed
}
if (SD.activeTasks.size > 0) {
return
}
const uncompletedTasks = getUncompletedTaskEntries()
if (uncompletedTasks && uncompletedTasks.length > 0) {
return
}
if (pauseClient) {
resumeBtn.click()
}
renderButtons.style.display = "none"
renameMakeImageButton()
if (isSoundEnabled()) {
playSound()
}
if (SHOW_PROGRESS) {
document.title = "Completed - Easy Diffusion"
}
}
async function onTaskStart(task) {
if (!task.isProcessing || task.batchesDone >= task.batchCount) {
return
}
if (typeof task.startTime !== "number") {
task.startTime = Date.now()
}
if (!("instances" in task)) {
task["instances"] = []
}
task["stopTask"].innerHTML = '<i class="fa-solid fa-circle-stop"></i> Stop'
task["taskStatusLabel"].innerText = "Starting"
task["taskStatusLabel"].classList.add("waitingTaskLabel")
let newTaskReqBody = task.reqBody
if (task.batchCount > 1) {
// Each output render batch needs it's own task reqBody instance to avoid altering the other runs after they are completed.
newTaskReqBody = Object.assign({}, task.reqBody)
if (task.batchesDone == task.batchCount - 1) {
// Last batch of the task
// If the number of parallel jobs is no factor of the total number of images, the last batch must create less than "parallel jobs count" images
// E.g. with numOutputsTotal = 6 and num_outputs = 5, the last batch shall only generate 1 image.
newTaskReqBody.num_outputs = task.numOutputsTotal - task.reqBody.num_outputs * (task.batchCount - 1)
}
}
const startSeed = task.seed || newTaskReqBody.seed
const genSeeds = Boolean(
typeof newTaskReqBody.seed !== "number" || (newTaskReqBody.seed === task.seed && task.numOutputsTotal > 1)
)
if (genSeeds) {
newTaskReqBody.seed = parseInt(startSeed) + task.batchesDone * task.reqBody.num_outputs
}
// Update the seed *before* starting the processing so it's retained if user stops the task
if (randomSeedField.checked) {
seedField.value = task.seed
}
const outputContainer = document.createElement("div")
outputContainer.className = "img-batch"
task.outputContainer.insertBefore(outputContainer, task.outputContainer.firstChild)
const eventInfo = { reqBody: newTaskReqBody }
const callbacksPromises = PLUGINS["TASK_CREATE"].map((hook) => {
if (typeof hook !== "function") {
console.error("The provided TASK_CREATE hook is not a function. Hook: %o", hook)
return Promise.reject(new Error("hook is not a function."))
}
try {
return Promise.resolve(hook.call(task, eventInfo))
} catch (err) {
console.error(err)
return Promise.reject(err)
}
})
await Promise.allSettled(callbacksPromises)
let instance = eventInfo.instance
if (!instance) {
const factory = PLUGINS.OUTPUTS_FORMATS.get(eventInfo.reqBody?.output_format || newTaskReqBody.output_format)
if (factory) {
instance = await Promise.resolve(factory(eventInfo.reqBody || newTaskReqBody))
}
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.`
)
instance = new SD.RenderTask(eventInfo.reqBody || newTaskReqBody)
}
}
task["instances"].push(instance)
task.batchesDone++
instance.enqueue(getTaskUpdater(task, newTaskReqBody, outputContainer)).then(
(renderResult) => {
onTaskCompleted(task, newTaskReqBody, instance, outputContainer, renderResult)
},
(reason) => {
onTaskErrorHandler(task, newTaskReqBody, instance, reason)
}
)
setStatus("request", "fetching..")
renderButtons.style.display = "flex"
renameMakeImageButton()
updateInitialText()
} }
/* Hover effect for the init image in the task list */ /* Hover effect for the init image in the task list */