mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
remove old swagger related files since security issues (#2730)
This commit is contained in:
commit
8352ab2076
@ -1,19 +0,0 @@
|
||||
<!-- HTML for static distribution bundle build -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Swagger UI</title>
|
||||
<link rel="stylesheet" type="text/css" href="swagger-ui/swagger-ui.css" />
|
||||
<link rel="stylesheet" type="text/css" href="swagger-ui/index.css" />
|
||||
<link rel="icon" type="image/png" href="swagger-ui/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="swagger-ui/favicon-16x16.png" sizes="16x16" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="swagger-ui/swagger-ui-bundle.js" charset="UTF-8"> </script>
|
||||
<script src="swagger-ui/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
||||
<script src="swagger-ui/swagger-initializer.js" charset="UTF-8"> </script>
|
||||
</body>
|
||||
</html>
|
@ -1,73 +0,0 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Stable Diffusion
|
||||
description: |-
|
||||
TODO: Description Here
|
||||
|
||||
Some useful links:
|
||||
- [Stable Diffusion Dream Server](https://github.com/lstein/stable-diffusion)
|
||||
|
||||
license:
|
||||
name: MIT License
|
||||
url: https://github.com/lstein/stable-diffusion/blob/main/LICENSE
|
||||
version: 1.0.0
|
||||
servers:
|
||||
- url: http://localhost:9090/api
|
||||
tags:
|
||||
- name: images
|
||||
description: Retrieve and manage generated images
|
||||
paths:
|
||||
/images/{imageId}:
|
||||
get:
|
||||
tags:
|
||||
- images
|
||||
summary: Get image by ID
|
||||
description: Returns a single image
|
||||
operationId: getImageById
|
||||
parameters:
|
||||
- name: imageId
|
||||
in: path
|
||||
description: ID of image to return
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
image/png:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
'404':
|
||||
description: Image not found
|
||||
/intermediates/{intermediateId}/{step}:
|
||||
get:
|
||||
tags:
|
||||
- images
|
||||
summary: Get intermediate image by ID
|
||||
description: Returns a single intermediate image
|
||||
operationId: getIntermediateById
|
||||
parameters:
|
||||
- name: intermediateId
|
||||
in: path
|
||||
description: ID of intermediate to return
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: step
|
||||
in: path
|
||||
description: The generation step of the intermediate
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
description: successful operation
|
||||
content:
|
||||
image/png:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
'404':
|
||||
description: Intermediate not found
|
Binary file not shown.
Before Width: | Height: | Size: 665 B |
Binary file not shown.
Before Width: | Height: | Size: 628 B |
@ -1,16 +0,0 @@
|
||||
html {
|
||||
box-sizing: border-box;
|
||||
overflow: -moz-scrollbars-vertical;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: #fafafa;
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<title>Swagger UI: OAuth2 Redirect</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
'use strict';
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var redirectUrl = oauth2.redirectUrl;
|
||||
var isValid, qp, arr;
|
||||
|
||||
if (/code|token|error/.test(window.location.hash)) {
|
||||
qp = window.location.hash.substring(1).replace('?', '&');
|
||||
} else {
|
||||
qp = location.search.substring(1);
|
||||
}
|
||||
|
||||
arr = qp.split("&");
|
||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
|
||||
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||
function (key, value) {
|
||||
return key === "" ? value : decodeURIComponent(value);
|
||||
}
|
||||
) : {};
|
||||
|
||||
isValid = qp.state === sentState;
|
||||
|
||||
if ((
|
||||
oauth2.auth.schema.get("flow") === "accessCode" ||
|
||||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
|
||||
oauth2.auth.schema.get("flow") === "authorization_code"
|
||||
) && !oauth2.auth.code) {
|
||||
if (!isValid) {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "warning",
|
||||
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
|
||||
});
|
||||
}
|
||||
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||
} else {
|
||||
let oauthErrorMsg;
|
||||
if (qp.error) {
|
||||
oauthErrorMsg = "["+qp.error+"]: " +
|
||||
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||
}
|
||||
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "error",
|
||||
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
|
||||
});
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
|
||||
if (document.readyState !== 'loading') {
|
||||
run();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
run();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -1,20 +0,0 @@
|
||||
window.onload = function() {
|
||||
//<editor-fold desc="Changeable Configuration Block">
|
||||
|
||||
// the following lines will be replaced by docker/configurator, when it runs in a docker-container
|
||||
window.ui = SwaggerUIBundle({
|
||||
url: "openapi3_0.yaml",
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout"
|
||||
});
|
||||
|
||||
//</editor-fold>
|
||||
};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
@ -1,179 +0,0 @@
|
||||
:root {
|
||||
--fields-dark:#DCDCDC;
|
||||
--fields-light:#F5F5F5;
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Arial';
|
||||
font-size: 100%;
|
||||
}
|
||||
body {
|
||||
font-size: 1em;
|
||||
}
|
||||
textarea {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
header, form, #progress-section {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 1024px;
|
||||
text-align: center;
|
||||
}
|
||||
fieldset {
|
||||
border: none;
|
||||
line-height: 2.2em;
|
||||
}
|
||||
fieldset > legend {
|
||||
width: auto;
|
||||
margin-left: 0;
|
||||
margin-right: auto;
|
||||
font-weight:bold;
|
||||
}
|
||||
select, input {
|
||||
margin-right: 10px;
|
||||
padding: 2px;
|
||||
}
|
||||
input:disabled {
|
||||
cursor:auto;
|
||||
}
|
||||
input[type=submit] {
|
||||
cursor: pointer;
|
||||
background-color: #666;
|
||||
color: white;
|
||||
}
|
||||
input[type=checkbox] {
|
||||
cursor: pointer;
|
||||
margin-right: 0px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
input#seed {
|
||||
margin-right: 0px;
|
||||
}
|
||||
div {
|
||||
padding: 10px 10px 10px 10px;
|
||||
}
|
||||
header {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
header h1 {
|
||||
margin-bottom: 0;
|
||||
font-size: 2em;
|
||||
}
|
||||
#search-box {
|
||||
display: flex;
|
||||
}
|
||||
#scaling-inprocess-message {
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
display: none;
|
||||
}
|
||||
#prompt {
|
||||
flex-grow: 1;
|
||||
padding: 5px 10px 5px 10px;
|
||||
border: 1px solid #999;
|
||||
outline: none;
|
||||
}
|
||||
#submit {
|
||||
padding: 5px 10px 5px 10px;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
#reset-all, #remove-image {
|
||||
margin-top: 12px;
|
||||
font-size: 0.8em;
|
||||
background-color: pink;
|
||||
border: 1px solid #999;
|
||||
border-radius: 4px;
|
||||
}
|
||||
#results {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
padding-top: 10px;
|
||||
}
|
||||
#results figure {
|
||||
display: inline-block;
|
||||
margin: 10px;
|
||||
}
|
||||
#results figcaption {
|
||||
font-size: 0.8em;
|
||||
padding: 3px;
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
}
|
||||
#results img {
|
||||
border-radius: 5px;
|
||||
object-fit: contain;
|
||||
background-color: var(--fields-dark);
|
||||
}
|
||||
#fieldset-config {
|
||||
line-height:2em;
|
||||
}
|
||||
input[type="number"] {
|
||||
width: 60px;
|
||||
}
|
||||
#seed {
|
||||
width: 150px;
|
||||
}
|
||||
button#reset-seed {
|
||||
font-size: 1.7em;
|
||||
background: #efefef;
|
||||
border: 1px solid #999;
|
||||
border-radius: 4px;
|
||||
line-height: 0.8;
|
||||
margin: 0 10px 0 0;
|
||||
padding: 0 5px 3px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
#progress-section {
|
||||
display: none;
|
||||
}
|
||||
#progress-image {
|
||||
width: 30vh;
|
||||
height: 30vh;
|
||||
object-fit: contain;
|
||||
background-color: var(--fields-dark);
|
||||
}
|
||||
#cancel-button {
|
||||
cursor: pointer;
|
||||
color: red;
|
||||
}
|
||||
#txt2img {
|
||||
background-color: var(--fields-dark);
|
||||
}
|
||||
#variations {
|
||||
background-color: var(--fields-light);
|
||||
}
|
||||
#initimg {
|
||||
background-color: var(--fields-dark);
|
||||
}
|
||||
#img2img {
|
||||
background-color: var(--fields-light);
|
||||
}
|
||||
#initimg > :not(legend) {
|
||||
background-color: var(--fields-light);
|
||||
margin: .5em;
|
||||
}
|
||||
|
||||
#postprocess, #initimg {
|
||||
display:flex;
|
||||
flex-wrap:wrap;
|
||||
padding: 0;
|
||||
margin-top: 1em;
|
||||
background-color: var(--fields-dark);
|
||||
}
|
||||
#postprocess > fieldset, #initimg > * {
|
||||
flex-grow: 1;
|
||||
}
|
||||
#postprocess > fieldset {
|
||||
background-color: var(--fields-dark);
|
||||
}
|
||||
#progress-section {
|
||||
background-color: var(--fields-light);
|
||||
}
|
||||
#no-results-message:not(:only-child) {
|
||||
display: none;
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title>Stable Diffusion Dream Server</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="static/dream_web/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<script src="config.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"
|
||||
integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA=="
|
||||
crossorigin="anonymous"></script>
|
||||
<link rel="stylesheet" href="index.css">
|
||||
<script src="index.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1>Stable Diffusion Dream Server</h1>
|
||||
<div id="about">
|
||||
For news and support for this web service, visit our <a href="http://github.com/lstein/stable-diffusion">GitHub
|
||||
site</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<!--
|
||||
<div id="dropper" style="background-color:red;width:200px;height:200px;">
|
||||
</div>
|
||||
-->
|
||||
<form id="generate-form" method="post" action="api/jobs">
|
||||
<fieldset id="txt2img">
|
||||
<legend>
|
||||
<input type="checkbox" name="enable_generate" id="enable_generate" checked>
|
||||
<label for="enable_generate">Generate</label>
|
||||
</legend>
|
||||
<div id="search-box">
|
||||
<textarea rows="3" id="prompt" name="prompt"></textarea>
|
||||
</div>
|
||||
<label for="iterations">Images to generate:</label>
|
||||
<input value="1" type="number" id="iterations" name="iterations" size="4">
|
||||
<label for="steps">Steps:</label>
|
||||
<input value="50" type="number" id="steps" name="steps">
|
||||
<label for="cfg_scale">Cfg Scale:</label>
|
||||
<input value="7.5" type="number" id="cfg_scale" name="cfg_scale" step="any">
|
||||
<label for="sampler_name">Sampler:</label>
|
||||
<select id="sampler_name" name="sampler_name" value="k_lms">
|
||||
<option value="ddim">DDIM</option>
|
||||
<option value="plms">PLMS</option>
|
||||
<option value="k_lms" selected>KLMS</option>
|
||||
<option value="k_dpm_2">KDPM_2</option>
|
||||
<option value="k_dpm_2_a">KDPM_2A</option>
|
||||
<option value="k_dpmpp_2">KDPMPP_2</option>
|
||||
<option value="k_dpmpp_2_a">KDPMPP_2A</option>
|
||||
<option value="k_euler">KEULER</option>
|
||||
<option value="k_euler_a">KEULER_A</option>
|
||||
<option value="k_heun">KHEUN</option>
|
||||
</select>
|
||||
<input type="checkbox" name="seamless" id="seamless">
|
||||
<label for="seamless">Seamless circular tiling</label>
|
||||
<br>
|
||||
<label title="Set to multiple of 64" for="width">Width:</label>
|
||||
<select id="width" name="width" value="512">
|
||||
<option value="64">64</option>
|
||||
<option value="128">128</option>
|
||||
<option value="192">192</option>
|
||||
<option value="256">256</option>
|
||||
<option value="320">320</option>
|
||||
<option value="384">384</option>
|
||||
<option value="448">448</option>
|
||||
<option value="512" selected>512</option>
|
||||
<option value="576">576</option>
|
||||
<option value="640">640</option>
|
||||
<option value="704">704</option>
|
||||
<option value="768">768</option>
|
||||
<option value="832">832</option>
|
||||
<option value="896">896</option>
|
||||
<option value="960">960</option>
|
||||
<option value="1024">1024</option>
|
||||
</select>
|
||||
<label title="Set to multiple of 64" for="height">Height:</label>
|
||||
<select id="height" name="height" value="512">
|
||||
<option value="64">64</option>
|
||||
<option value="128">128</option>
|
||||
<option value="192">192</option>
|
||||
<option value="256">256</option>
|
||||
<option value="320">320</option>
|
||||
<option value="384">384</option>
|
||||
<option value="448">448</option>
|
||||
<option value="512" selected>512</option>
|
||||
<option value="576">576</option>
|
||||
<option value="640">640</option>
|
||||
<option value="704">704</option>
|
||||
<option value="768">768</option>
|
||||
<option value="832">832</option>
|
||||
<option value="896">896</option>
|
||||
<option value="960">960</option>
|
||||
<option value="1024">1024</option>
|
||||
</select>
|
||||
<label title="Set to 0 for random seed" for="seed">Seed:</label>
|
||||
<input value="0" type="number" id="seed" name="seed">
|
||||
<button type="button" id="reset-seed">↺</button>
|
||||
<input type="checkbox" name="progress_images" id="progress_images">
|
||||
<label for="progress_images">Display in-progress images (slower)</label>
|
||||
<div>
|
||||
<label title="If > 0, adds thresholding to restrict values for k-diffusion samplers (0 disables)" for="threshold">Threshold:</label>
|
||||
<input value="0" type="number" id="threshold" name="threshold" step="0.1" min="0">
|
||||
<label title="Perlin: optional 0-1 value adds a percentage of perlin noise to the initial noise" for="perlin">Perlin:</label>
|
||||
<input value="0" type="number" id="perlin" name="perlin" step="0.01" min="0" max="1">
|
||||
<button type="button" id="reset-all">Reset to Defaults</button>
|
||||
</div>
|
||||
<div id="variations">
|
||||
<label
|
||||
title="If > 0, generates variations on the initial seed instead of random seeds per iteration. Must be between 0 and 1. Higher values will be more different."
|
||||
for="variation_amount">Variation amount (0 to disable):</label>
|
||||
<input value="0" type="number" id="variation_amount" name="variation_amount" step="0.01" min="0" max="1">
|
||||
<label title="list of variations to apply, in the format `seed:weight,seed:weight,..."
|
||||
for="with_variations">With variations (seed:weight,seed:weight,...):</label>
|
||||
<input value="" type="text" id="with_variations" name="with_variations">
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset id="initimg">
|
||||
<legend>
|
||||
<input type="checkbox" name="enable_init_image" id="enable_init_image" checked>
|
||||
<label for="enable_init_image">Enable init image</label>
|
||||
</legend>
|
||||
<div>
|
||||
<label title="Upload an image to use img2img" for="initimg">Initial image:</label>
|
||||
<input type="file" id="initimg" name="initimg" accept=".jpg, .jpeg, .png">
|
||||
<button type="button" id="remove-image">Remove Image</button>
|
||||
</div>
|
||||
<fieldset id="img2img">
|
||||
<legend>
|
||||
<input type="checkbox" name="enable_img2img" id="enable_img2img" checked>
|
||||
<label for="enable_img2img">Enable Img2Img</label>
|
||||
</legend>
|
||||
<label for="strength">Img2Img Strength:</label>
|
||||
<input value="0.75" type="number" id="strength" name="strength" step="0.01" min="0" max="1">
|
||||
<input type="checkbox" id="fit" name="fit" checked>
|
||||
<label title="Rescale image to fit within requested width and height" for="fit">Fit to width/height:</label>
|
||||
</fieldset>
|
||||
</fieldset>
|
||||
<div id="postprocess">
|
||||
<fieldset id="gfpgan">
|
||||
<legend>
|
||||
<input type="checkbox" name="enable_gfpgan" id="enable_gfpgan">
|
||||
<label for="enable_gfpgan">Enable gfpgan</label>
|
||||
</legend>
|
||||
<label title="Strength of the gfpgan (face fixing) algorithm." for="facetool_strength">GPFGAN Strength:</label>
|
||||
<input value="0.8" min="0" max="1" type="number" id="facetool_strength" name="facetool_strength" step="0.05">
|
||||
</fieldset>
|
||||
<fieldset id="upscale">
|
||||
<legend>
|
||||
<input type="checkbox" name="enable_upscale" id="enable_upscale">
|
||||
<label for="enable_upscale">Enable Upscaling</label>
|
||||
</legend>
|
||||
<label title="Upscaling to perform using ESRGAN." for="upscale_level">Upscaling Level:</label>
|
||||
<select id="upscale_level" name="upscale_level" value="">
|
||||
<option value="" selected>None</option>
|
||||
<option value="2">2x</option>
|
||||
<option value="4">4x</option>
|
||||
</select>
|
||||
<label title="Strength of the esrgan (upscaling) algorithm." for="upscale_strength">Upscale Strength:</label>
|
||||
<input value="0.75" min="0" max="1" type="number" id="upscale_strength" name="upscale_strength" step="0.05">
|
||||
</fieldset>
|
||||
</div>
|
||||
<input type="submit" id="submit" value="Generate">
|
||||
</form>
|
||||
<br>
|
||||
<section id="progress-section">
|
||||
<div id="progress-container">
|
||||
<progress id="progress-bar" value="0" max="1"></progress>
|
||||
<span id="cancel-button" title="Cancel">✖</span>
|
||||
<br>
|
||||
<img id="progress-image" src='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"/>'>
|
||||
<div id="scaling-inprocess-message">
|
||||
<i><span>Postprocessing...</span><span id="processing_cnt">1</span>/<span id="processing_total">3</span></i>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="results">
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
@ -1,396 +0,0 @@
|
||||
const socket = io();
|
||||
|
||||
var priorResultsLoadState = {
|
||||
page: 0,
|
||||
pages: 1,
|
||||
per_page: 10,
|
||||
total: 20,
|
||||
offset: 0, // number of items generated since last load
|
||||
loading: false,
|
||||
initialized: false
|
||||
};
|
||||
|
||||
function loadPriorResults() {
|
||||
// Fix next page by offset
|
||||
let offsetPages = priorResultsLoadState.offset / priorResultsLoadState.per_page;
|
||||
priorResultsLoadState.page += offsetPages;
|
||||
priorResultsLoadState.pages += offsetPages;
|
||||
priorResultsLoadState.total += priorResultsLoadState.offset;
|
||||
priorResultsLoadState.offset = 0;
|
||||
|
||||
if (priorResultsLoadState.loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (priorResultsLoadState.page >= priorResultsLoadState.pages) {
|
||||
return; // Nothing more to load
|
||||
}
|
||||
|
||||
// Load
|
||||
priorResultsLoadState.loading = true
|
||||
let url = new URL('/api/images', document.baseURI);
|
||||
url.searchParams.append('page', priorResultsLoadState.initialized ? priorResultsLoadState.page + 1 : priorResultsLoadState.page);
|
||||
url.searchParams.append('per_page', priorResultsLoadState.per_page);
|
||||
fetch(url.href, {
|
||||
method: 'GET',
|
||||
headers: new Headers({'content-type': 'application/json'})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
priorResultsLoadState.page = data.page;
|
||||
priorResultsLoadState.pages = data.pages;
|
||||
priorResultsLoadState.per_page = data.per_page;
|
||||
priorResultsLoadState.total = data.total;
|
||||
|
||||
data.items.forEach(function(dreamId, index) {
|
||||
let src = 'api/images/' + dreamId;
|
||||
fetch('/api/images/' + dreamId + '/metadata', {
|
||||
method: 'GET',
|
||||
headers: new Headers({'content-type': 'application/json'})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(metadata => {
|
||||
let seed = metadata.seed || 0; // TODO: Parse old metadata
|
||||
appendOutput(src, seed, metadata, true);
|
||||
});
|
||||
});
|
||||
|
||||
// Load until page is full
|
||||
if (!priorResultsLoadState.initialized) {
|
||||
if (document.body.scrollHeight <= window.innerHeight) {
|
||||
loadPriorResults();
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
priorResultsLoadState.loading = false;
|
||||
priorResultsLoadState.initialized = true;
|
||||
});
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
var form = document.getElementById('generate-form');
|
||||
form.querySelector('fieldset').removeAttribute('disabled');
|
||||
}
|
||||
|
||||
function initProgress(totalSteps, showProgressImages) {
|
||||
// TODO: Progress could theoretically come from multiple jobs at the same time (in the future)
|
||||
let progressSectionEle = document.querySelector('#progress-section');
|
||||
progressSectionEle.style.display = 'initial';
|
||||
let progressEle = document.querySelector('#progress-bar');
|
||||
progressEle.setAttribute('max', totalSteps);
|
||||
|
||||
let progressImageEle = document.querySelector('#progress-image');
|
||||
progressImageEle.src = BLANK_IMAGE_URL;
|
||||
progressImageEle.style.display = showProgressImages ? 'initial': 'none';
|
||||
}
|
||||
|
||||
function setProgress(step, totalSteps, src) {
|
||||
let progressEle = document.querySelector('#progress-bar');
|
||||
progressEle.setAttribute('value', step);
|
||||
|
||||
if (src) {
|
||||
let progressImageEle = document.querySelector('#progress-image');
|
||||
progressImageEle.src = src;
|
||||
}
|
||||
}
|
||||
|
||||
function resetProgress(hide = true) {
|
||||
if (hide) {
|
||||
let progressSectionEle = document.querySelector('#progress-section');
|
||||
progressSectionEle.style.display = 'none';
|
||||
}
|
||||
let progressEle = document.querySelector('#progress-bar');
|
||||
progressEle.setAttribute('value', 0);
|
||||
}
|
||||
|
||||
function toBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const r = new FileReader();
|
||||
r.readAsDataURL(file);
|
||||
r.onload = () => resolve(r.result);
|
||||
r.onerror = (error) => reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
function ondragdream(event) {
|
||||
let dream = event.target.dataset.dream;
|
||||
event.dataTransfer.setData("dream", dream);
|
||||
}
|
||||
|
||||
function seedClick(event) {
|
||||
// Get element
|
||||
var image = event.target.closest('figure').querySelector('img');
|
||||
var dream = JSON.parse(decodeURIComponent(image.dataset.dream));
|
||||
|
||||
let form = document.querySelector("#generate-form");
|
||||
for (const [k, v] of new FormData(form)) {
|
||||
if (k == 'initimg') { continue; }
|
||||
let formElem = form.querySelector(`*[name=${k}]`);
|
||||
formElem.value = dream[k] !== undefined ? dream[k] : formElem.defaultValue;
|
||||
}
|
||||
|
||||
document.querySelector("#seed").value = dream.seed;
|
||||
document.querySelector('#iterations').value = 1; // Reset to 1 iteration since we clicked a single image (not a full job)
|
||||
|
||||
// NOTE: leaving this manual for the user for now - it was very confusing with this behavior
|
||||
// document.querySelector("#with_variations").value = variations || '';
|
||||
// if (document.querySelector("#variation_amount").value <= 0) {
|
||||
// document.querySelector("#variation_amount").value = 0.2;
|
||||
// }
|
||||
|
||||
saveFields(document.querySelector("#generate-form"));
|
||||
}
|
||||
|
||||
function appendOutput(src, seed, config, toEnd=false) {
|
||||
let outputNode = document.createElement("figure");
|
||||
let altText = seed.toString() + " | " + config.prompt;
|
||||
|
||||
// img needs width and height for lazy loading to work
|
||||
// TODO: store the full config in a data attribute on the image?
|
||||
const figureContents = `
|
||||
<a href="${src}" target="_blank">
|
||||
<img src="${src}"
|
||||
alt="${altText}"
|
||||
title="${altText}"
|
||||
loading="lazy"
|
||||
width="256"
|
||||
height="256"
|
||||
draggable="true"
|
||||
ondragstart="ondragdream(event, this)"
|
||||
data-dream="${encodeURIComponent(JSON.stringify(config))}"
|
||||
data-dreamId="${encodeURIComponent(config.dreamId)}">
|
||||
</a>
|
||||
<figcaption onclick="seedClick(event, this)">${seed}</figcaption>
|
||||
`;
|
||||
|
||||
outputNode.innerHTML = figureContents;
|
||||
|
||||
if (toEnd) {
|
||||
document.querySelector("#results").append(outputNode);
|
||||
} else {
|
||||
document.querySelector("#results").prepend(outputNode);
|
||||
}
|
||||
document.querySelector("#no-results-message")?.remove();
|
||||
}
|
||||
|
||||
function saveFields(form) {
|
||||
for (const [k, v] of new FormData(form)) {
|
||||
if (typeof v !== 'object') { // Don't save 'file' type
|
||||
localStorage.setItem(k, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadFields(form) {
|
||||
for (const [k, v] of new FormData(form)) {
|
||||
const item = localStorage.getItem(k);
|
||||
if (item != null) {
|
||||
form.querySelector(`*[name=${k}]`).value = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearFields(form) {
|
||||
localStorage.clear();
|
||||
let prompt = form.prompt.value;
|
||||
form.reset();
|
||||
form.prompt.value = prompt;
|
||||
}
|
||||
|
||||
const BLANK_IMAGE_URL = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"/>';
|
||||
async function generateSubmit(form) {
|
||||
// Convert file data to base64
|
||||
// TODO: Should probably uplaod files with formdata or something, and store them in the backend?
|
||||
let formData = Object.fromEntries(new FormData(form));
|
||||
if (!formData.enable_generate && !formData.enable_init_image) {
|
||||
gen_label = document.querySelector("label[for=enable_generate]").innerHTML;
|
||||
initimg_label = document.querySelector("label[for=enable_init_image]").innerHTML;
|
||||
alert(`Error: one of "${gen_label}" or "${initimg_label}" must be set`);
|
||||
}
|
||||
|
||||
|
||||
formData.initimg_name = formData.initimg.name
|
||||
formData.initimg = formData.initimg.name !== '' ? await toBase64(formData.initimg) : null;
|
||||
|
||||
// Evaluate all checkboxes
|
||||
let checkboxes = form.querySelectorAll('input[type=checkbox]');
|
||||
checkboxes.forEach(function (checkbox) {
|
||||
if (checkbox.checked) {
|
||||
formData[checkbox.name] = 'true';
|
||||
}
|
||||
});
|
||||
|
||||
let strength = formData.strength;
|
||||
let totalSteps = formData.initimg ? Math.floor(strength * formData.steps) : formData.steps;
|
||||
let showProgressImages = formData.progress_images;
|
||||
|
||||
// Set enabling flags
|
||||
|
||||
|
||||
// Initialize the progress bar
|
||||
initProgress(totalSteps, showProgressImages);
|
||||
|
||||
// POST, use response to listen for events
|
||||
fetch(form.action, {
|
||||
method: form.method,
|
||||
headers: new Headers({'content-type': 'application/json'}),
|
||||
body: JSON.stringify(formData),
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
var jobId = data.jobId;
|
||||
socket.emit('join_room', { 'room': jobId });
|
||||
});
|
||||
|
||||
form.querySelector('fieldset').setAttribute('disabled','');
|
||||
}
|
||||
|
||||
function fieldSetEnableChecked(event) {
|
||||
cb = event.target;
|
||||
fields = cb.closest('fieldset');
|
||||
fields.disabled = !cb.checked;
|
||||
}
|
||||
|
||||
// Socket listeners
|
||||
socket.on('job_started', (data) => {})
|
||||
|
||||
socket.on('dream_result', (data) => {
|
||||
var jobId = data.jobId;
|
||||
var dreamId = data.dreamId;
|
||||
var dreamRequest = data.dreamRequest;
|
||||
var src = 'api/images/' + dreamId;
|
||||
|
||||
priorResultsLoadState.offset += 1;
|
||||
appendOutput(src, dreamRequest.seed, dreamRequest);
|
||||
|
||||
resetProgress(false);
|
||||
})
|
||||
|
||||
socket.on('dream_progress', (data) => {
|
||||
// TODO: it'd be nice if we could get a seed reported here, but the generator would need to be updated
|
||||
var step = data.step;
|
||||
var totalSteps = data.totalSteps;
|
||||
var jobId = data.jobId;
|
||||
var dreamId = data.dreamId;
|
||||
|
||||
var progressType = data.progressType
|
||||
if (progressType === 'GENERATION') {
|
||||
var src = data.hasProgressImage ?
|
||||
'api/intermediates/' + dreamId + '/' + step
|
||||
: null;
|
||||
setProgress(step, totalSteps, src);
|
||||
} else if (progressType === 'UPSCALING_STARTED') {
|
||||
// step and totalSteps are used for upscale count on this message
|
||||
document.getElementById("processing_cnt").textContent = step;
|
||||
document.getElementById("processing_total").textContent = totalSteps;
|
||||
document.getElementById("scaling-inprocess-message").style.display = "block";
|
||||
} else if (progressType == 'UPSCALING_DONE') {
|
||||
document.getElementById("scaling-inprocess-message").style.display = "none";
|
||||
}
|
||||
})
|
||||
|
||||
socket.on('job_canceled', (data) => {
|
||||
resetForm();
|
||||
resetProgress();
|
||||
})
|
||||
|
||||
socket.on('job_done', (data) => {
|
||||
jobId = data.jobId
|
||||
socket.emit('leave_room', { 'room': jobId });
|
||||
|
||||
resetForm();
|
||||
resetProgress();
|
||||
})
|
||||
|
||||
window.onload = async () => {
|
||||
document.querySelector("#prompt").addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
const form = e.target.form;
|
||||
generateSubmit(form);
|
||||
}
|
||||
});
|
||||
document.querySelector("#generate-form").addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const form = e.target;
|
||||
|
||||
generateSubmit(form);
|
||||
});
|
||||
document.querySelector("#generate-form").addEventListener('change', (e) => {
|
||||
saveFields(e.target.form);
|
||||
});
|
||||
document.querySelector("#reset-seed").addEventListener('click', (e) => {
|
||||
document.querySelector("#seed").value = 0;
|
||||
saveFields(e.target.form);
|
||||
});
|
||||
document.querySelector("#reset-all").addEventListener('click', (e) => {
|
||||
clearFields(e.target.form);
|
||||
});
|
||||
document.querySelector("#remove-image").addEventListener('click', (e) => {
|
||||
initimg.value=null;
|
||||
});
|
||||
loadFields(document.querySelector("#generate-form"));
|
||||
|
||||
document.querySelector('#cancel-button').addEventListener('click', () => {
|
||||
fetch('/api/cancel').catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
});
|
||||
document.documentElement.addEventListener('keydown', (e) => {
|
||||
if (e.key === "Escape")
|
||||
fetch('/api/cancel').catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
|
||||
if (!config.gfpgan_model_exists) {
|
||||
document.querySelector("#gfpgan").style.display = 'none';
|
||||
}
|
||||
|
||||
window.addEventListener("scroll", () => {
|
||||
if ((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
|
||||
loadPriorResults();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// Enable/disable forms by checkboxes
|
||||
document.querySelectorAll("legend > input[type=checkbox]").forEach(function(cb) {
|
||||
cb.addEventListener('change', fieldSetEnableChecked);
|
||||
fieldSetEnableChecked({ target: cb})
|
||||
});
|
||||
|
||||
|
||||
// Load some of the previous results
|
||||
loadPriorResults();
|
||||
|
||||
// Image drop/upload WIP
|
||||
/*
|
||||
let drop = document.getElementById('dropper');
|
||||
function ondrop(event) {
|
||||
let dreamData = event.dataTransfer.getData('dream');
|
||||
if (dreamData) {
|
||||
var dream = JSON.parse(decodeURIComponent(dreamData));
|
||||
alert(dream.dreamId);
|
||||
}
|
||||
};
|
||||
|
||||
function ondragenter(event) {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
function ondragover(event) {
|
||||
event.preventDefault();
|
||||
};
|
||||
|
||||
function ondragleave(event) {
|
||||
|
||||
}
|
||||
|
||||
drop.addEventListener('drop', ondrop);
|
||||
drop.addEventListener('dragenter', ondragenter);
|
||||
drop.addEventListener('dragover', ondragover);
|
||||
drop.addEventListener('dragleave', ondragleave);
|
||||
*/
|
||||
};
|
Binary file not shown.
Before Width: | Height: | Size: 1.1 KiB |
@ -1,152 +0,0 @@
|
||||
* {
|
||||
font-family: 'Arial';
|
||||
font-size: 100%;
|
||||
}
|
||||
body {
|
||||
font-size: 1em;
|
||||
}
|
||||
textarea {
|
||||
font-size: 0.95em;
|
||||
}
|
||||
header, form, #progress-section {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 1024px;
|
||||
text-align: center;
|
||||
}
|
||||
fieldset {
|
||||
border: none;
|
||||
line-height: 2.2em;
|
||||
}
|
||||
select, input {
|
||||
margin-right: 10px;
|
||||
padding: 2px;
|
||||
}
|
||||
input[type=submit] {
|
||||
background-color: #666;
|
||||
color: white;
|
||||
}
|
||||
input[type=checkbox] {
|
||||
margin-right: 0px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
input#seed {
|
||||
margin-right: 0px;
|
||||
}
|
||||
div {
|
||||
padding: 10px 10px 10px 10px;
|
||||
}
|
||||
header {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
header h1 {
|
||||
margin-bottom: 0;
|
||||
font-size: 2em;
|
||||
}
|
||||
#search-box {
|
||||
display: flex;
|
||||
}
|
||||
#scaling-inprocess-message {
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
display: none;
|
||||
}
|
||||
#prompt {
|
||||
flex-grow: 1;
|
||||
padding: 5px 10px 5px 10px;
|
||||
border: 1px solid #999;
|
||||
outline: none;
|
||||
}
|
||||
#submit {
|
||||
padding: 5px 10px 5px 10px;
|
||||
border: 1px solid #999;
|
||||
}
|
||||
#reset-all, #remove-image {
|
||||
margin-top: 12px;
|
||||
font-size: 0.8em;
|
||||
background-color: pink;
|
||||
border: 1px solid #999;
|
||||
border-radius: 4px;
|
||||
}
|
||||
#results {
|
||||
text-align: center;
|
||||
margin: auto;
|
||||
padding-top: 10px;
|
||||
}
|
||||
#results figure {
|
||||
display: inline-block;
|
||||
margin: 10px;
|
||||
}
|
||||
#results figcaption {
|
||||
font-size: 0.8em;
|
||||
padding: 3px;
|
||||
color: #888;
|
||||
cursor: pointer;
|
||||
}
|
||||
#results img {
|
||||
border-radius: 5px;
|
||||
object-fit: cover;
|
||||
}
|
||||
#fieldset-config {
|
||||
line-height:2em;
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
input[type="number"] {
|
||||
width: 60px;
|
||||
}
|
||||
#seed {
|
||||
width: 150px;
|
||||
}
|
||||
button#reset-seed {
|
||||
font-size: 1.7em;
|
||||
background: #efefef;
|
||||
border: 1px solid #999;
|
||||
border-radius: 4px;
|
||||
line-height: 0.8;
|
||||
margin: 0 10px 0 0;
|
||||
padding: 0 5px 3px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
#progress-section {
|
||||
display: none;
|
||||
}
|
||||
#progress-image {
|
||||
width: 30vh;
|
||||
height: 30vh;
|
||||
}
|
||||
#cancel-button {
|
||||
cursor: pointer;
|
||||
color: red;
|
||||
}
|
||||
#basic-parameters {
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
#txt2img {
|
||||
background-color: #DCDCDC;
|
||||
}
|
||||
#variations {
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
#img2img {
|
||||
background-color: #DCDCDC;
|
||||
}
|
||||
#gfpgan {
|
||||
background-color: #EEEEEE;
|
||||
}
|
||||
#progress-section {
|
||||
background-color: #F5F5F5;
|
||||
}
|
||||
.section-header {
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
#no-results-message:not(:only-child) {
|
||||
display: none;
|
||||
}
|
||||
|
@ -1,137 +0,0 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Stable Diffusion Dream Server</title>
|
||||
<meta charset="utf-8">
|
||||
<link rel="icon" type="image/x-icon" href="static/legacy_web/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="static/legacy_web/index.css">
|
||||
<script src="config.js"></script>
|
||||
<script src="static/legacy_web/index.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Stable Diffusion Dream Server</h1>
|
||||
<div id="about">
|
||||
For news and support for this web service, visit our <a href="http://github.com/lstein/stable-diffusion">GitHub site</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<form id="generate-form" method="post" action="#">
|
||||
<fieldset id="txt2img">
|
||||
<div id="search-box">
|
||||
<textarea rows="3" id="prompt" name="prompt"></textarea>
|
||||
<input type="submit" id="submit" value="Generate">
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset id="fieldset-config">
|
||||
<div class="section-header">Basic options</div>
|
||||
<label for="iterations">Images to generate:</label>
|
||||
<input value="1" type="number" id="iterations" name="iterations" size="4">
|
||||
<label for="steps">Steps:</label>
|
||||
<input value="50" type="number" id="steps" name="steps">
|
||||
<label for="cfg_scale">Cfg Scale:</label>
|
||||
<input value="7.5" type="number" id="cfg_scale" name="cfg_scale" step="any">
|
||||
<label for="sampler_name">Sampler:</label>
|
||||
<select id="sampler_name" name="sampler_name" value="k_lms">
|
||||
<option value="ddim">DDIM</option>
|
||||
<option value="plms">PLMS</option>
|
||||
<option value="k_lms" selected>KLMS</option>
|
||||
<option value="k_dpm_2">KDPM_2</option>
|
||||
<option value="k_dpm_2_a">KDPM_2A</option>
|
||||
<option value="k_dpmpp_2">KDPMPP_2</option>
|
||||
<option value="k_dpmpp_2_a">KDPMPP_2A</option>
|
||||
<option value="k_euler">KEULER</option>
|
||||
<option value="k_euler_a">KEULER_A</option>
|
||||
<option value="k_heun">KHEUN</option>
|
||||
</select>
|
||||
<input type="checkbox" name="seamless" id="seamless">
|
||||
<label for="seamless">Seamless circular tiling</label>
|
||||
<br>
|
||||
<label title="Set to multiple of 64" for="width">Width:</label>
|
||||
<select id="width" name="width" value="512">
|
||||
<option value="64">64</option> <option value="128">128</option>
|
||||
<option value="192">192</option> <option value="256">256</option>
|
||||
<option value="320">320</option> <option value="384">384</option>
|
||||
<option value="448">448</option> <option value="512" selected>512</option>
|
||||
<option value="576">576</option> <option value="640">640</option>
|
||||
<option value="704">704</option> <option value="768">768</option>
|
||||
<option value="832">832</option> <option value="896">896</option>
|
||||
<option value="960">960</option> <option value="1024">1024</option>
|
||||
</select>
|
||||
<label title="Set to multiple of 64" for="height">Height:</label>
|
||||
<select id="height" name="height" value="512">
|
||||
<option value="64">64</option> <option value="128">128</option>
|
||||
<option value="192">192</option> <option value="256">256</option>
|
||||
<option value="320">320</option> <option value="384">384</option>
|
||||
<option value="448">448</option> <option value="512" selected>512</option>
|
||||
<option value="576">576</option> <option value="640">640</option>
|
||||
<option value="704">704</option> <option value="768">768</option>
|
||||
<option value="832">832</option> <option value="896">896</option>
|
||||
<option value="960">960</option> <option value="1024">1024</option>
|
||||
</select>
|
||||
<label title="Set to -1 for random seed" for="seed">Seed:</label>
|
||||
<input value="-1" type="number" id="seed" name="seed">
|
||||
<button type="button" id="reset-seed">↺</button>
|
||||
<input type="checkbox" name="progress_images" id="progress_images">
|
||||
<label for="progress_images">Display in-progress images (slower)</label>
|
||||
<div>
|
||||
<label title="If > 0, adds thresholding to restrict values for k-diffusion samplers (0 disables)" for="threshold">Threshold:</label>
|
||||
<input value="0" type="number" id="threshold" name="threshold" step="0.1" min="0">
|
||||
<label title="Perlin: optional 0-1 value adds a percentage of perlin noise to the initial noise" for="perlin">Perlin:</label>
|
||||
<input value="0" type="number" id="perlin" name="perlin" step="0.01" min="0" max="1">
|
||||
<button type="button" id="reset-all">Reset to Defaults</button>
|
||||
</div>
|
||||
<span id="variations">
|
||||
<label title="If > 0, generates variations on the initial seed instead of random seeds per iteration. Must be between 0 and 1. Higher values will be more different." for="variation_amount">Variation amount (0 to disable):</label>
|
||||
<input value="0" type="number" id="variation_amount" name="variation_amount" step="0.01" min="0" max="1">
|
||||
<label title="list of variations to apply, in the format `seed:weight,seed:weight,..." for="with_variations">With variations (seed:weight,seed:weight,...):</label>
|
||||
<input value="" type="text" id="with_variations" name="with_variations">
|
||||
</span>
|
||||
</fieldset>
|
||||
<fieldset id="img2img">
|
||||
<div class="section-header">Image-to-image options</div>
|
||||
<label title="Upload an image to use img2img" for="initimg">Initial image:</label>
|
||||
<input type="file" id="initimg" name="initimg" accept=".jpg, .jpeg, .png">
|
||||
<button type="button" id="remove-image">Remove Image</button>
|
||||
<br>
|
||||
<label for="strength">Img2Img Strength:</label>
|
||||
<input value="0.75" type="number" id="strength" name="strength" step="0.01" min="0" max="1">
|
||||
<input type="checkbox" id="fit" name="fit" checked>
|
||||
<label title="Rescale image to fit within requested width and height" for="fit">Fit to width/height</label>
|
||||
</fieldset>
|
||||
<fieldset id="gfpgan">
|
||||
<div class="section-header">Post-processing options</div>
|
||||
<label title="Strength of the gfpgan (face fixing) algorithm." for="facetool_strength">GPFGAN Strength (0 to disable):</label>
|
||||
<input value="0.0" min="0" max="1" type="number" id="facetool_strength" name="facetool_strength" step="0.1">
|
||||
<label title="Upscaling to perform using ESRGAN." for="upscale_level">Upscaling Level</label>
|
||||
<select id="upscale_level" name="upscale_level" value="">
|
||||
<option value="" selected>None</option>
|
||||
<option value="2">2x</option>
|
||||
<option value="4">4x</option>
|
||||
</select>
|
||||
<label title="Strength of the esrgan (upscaling) algorithm." for="upscale_strength">Upscale Strength:</label>
|
||||
<input value="0.75" min="0" max="1" type="number" id="upscale_strength" name="upscale_strength" step="0.05">
|
||||
</fieldset>
|
||||
</form>
|
||||
<br>
|
||||
<section id="progress-section">
|
||||
<div id="progress-container">
|
||||
<progress id="progress-bar" value="0" max="1"></progress>
|
||||
<span id="cancel-button" title="Cancel">✖</span>
|
||||
<br>
|
||||
<img id="progress-image" src='data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"/>'>
|
||||
<div id="scaling-inprocess-message">
|
||||
<i><span>Postprocessing...</span><span id="processing_cnt">1/3</span></i>
|
||||
</div>
|
||||
</span>
|
||||
</section>
|
||||
|
||||
<div id="results">
|
||||
<div id="no-results-message">
|
||||
<i><p>No results...</p></i>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
@ -1,213 +0,0 @@
|
||||
function toBase64(file) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const r = new FileReader();
|
||||
r.readAsDataURL(file);
|
||||
r.onload = () => resolve(r.result);
|
||||
r.onerror = (error) => reject(error);
|
||||
});
|
||||
}
|
||||
|
||||
function appendOutput(src, seed, config) {
|
||||
let outputNode = document.createElement("figure");
|
||||
|
||||
let variations = config.with_variations;
|
||||
if (config.variation_amount > 0) {
|
||||
variations = (variations ? variations + ',' : '') + seed + ':' + config.variation_amount;
|
||||
}
|
||||
let baseseed = (config.with_variations || config.variation_amount > 0) ? config.seed : seed;
|
||||
let altText = baseseed + ' | ' + (variations ? variations + ' | ' : '') + config.prompt;
|
||||
|
||||
// img needs width and height for lazy loading to work
|
||||
const figureContents = `
|
||||
<a href="${src}" target="_blank">
|
||||
<img src="${src}"
|
||||
alt="${altText}"
|
||||
title="${altText}"
|
||||
loading="lazy"
|
||||
width="256"
|
||||
height="256">
|
||||
</a>
|
||||
<figcaption>${seed}</figcaption>
|
||||
`;
|
||||
|
||||
outputNode.innerHTML = figureContents;
|
||||
let figcaption = outputNode.querySelector('figcaption');
|
||||
|
||||
// Reload image config
|
||||
figcaption.addEventListener('click', () => {
|
||||
let form = document.querySelector("#generate-form");
|
||||
for (const [k, v] of new FormData(form)) {
|
||||
if (k == 'initimg') { continue; }
|
||||
form.querySelector(`*[name=${k}]`).value = config[k];
|
||||
}
|
||||
|
||||
document.querySelector("#seed").value = baseseed;
|
||||
document.querySelector("#with_variations").value = variations || '';
|
||||
if (document.querySelector("#variation_amount").value <= 0) {
|
||||
document.querySelector("#variation_amount").value = 0.2;
|
||||
}
|
||||
|
||||
saveFields(document.querySelector("#generate-form"));
|
||||
});
|
||||
|
||||
document.querySelector("#results").prepend(outputNode);
|
||||
}
|
||||
|
||||
function saveFields(form) {
|
||||
for (const [k, v] of new FormData(form)) {
|
||||
if (typeof v !== 'object') { // Don't save 'file' type
|
||||
localStorage.setItem(k, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function loadFields(form) {
|
||||
for (const [k, v] of new FormData(form)) {
|
||||
const item = localStorage.getItem(k);
|
||||
if (item != null) {
|
||||
form.querySelector(`*[name=${k}]`).value = item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearFields(form) {
|
||||
localStorage.clear();
|
||||
let prompt = form.prompt.value;
|
||||
form.reset();
|
||||
form.prompt.value = prompt;
|
||||
}
|
||||
|
||||
const BLANK_IMAGE_URL = 'data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"/>';
|
||||
async function generateSubmit(form) {
|
||||
const prompt = document.querySelector("#prompt").value;
|
||||
|
||||
// Convert file data to base64
|
||||
let formData = Object.fromEntries(new FormData(form));
|
||||
formData.initimg_name = formData.initimg.name
|
||||
formData.initimg = formData.initimg.name !== '' ? await toBase64(formData.initimg) : null;
|
||||
|
||||
let strength = formData.strength;
|
||||
let totalSteps = formData.initimg ? Math.floor(strength * formData.steps) : formData.steps;
|
||||
|
||||
let progressSectionEle = document.querySelector('#progress-section');
|
||||
progressSectionEle.style.display = 'initial';
|
||||
let progressEle = document.querySelector('#progress-bar');
|
||||
progressEle.setAttribute('max', totalSteps);
|
||||
let progressImageEle = document.querySelector('#progress-image');
|
||||
progressImageEle.src = BLANK_IMAGE_URL;
|
||||
|
||||
progressImageEle.style.display = {}.hasOwnProperty.call(formData, 'progress_images') ? 'initial': 'none';
|
||||
|
||||
// Post as JSON, using Fetch streaming to get results
|
||||
fetch(form.action, {
|
||||
method: form.method,
|
||||
body: JSON.stringify(formData),
|
||||
}).then(async (response) => {
|
||||
const reader = response.body.getReader();
|
||||
|
||||
let noOutputs = true;
|
||||
while (true) {
|
||||
let {value, done} = await reader.read();
|
||||
value = new TextDecoder().decode(value);
|
||||
if (done) {
|
||||
progressSectionEle.style.display = 'none';
|
||||
break;
|
||||
}
|
||||
|
||||
for (let event of value.split('\n').filter(e => e !== '')) {
|
||||
const data = JSON.parse(event);
|
||||
|
||||
if (data.event === 'result') {
|
||||
noOutputs = false;
|
||||
appendOutput(data.url, data.seed, data.config);
|
||||
progressEle.setAttribute('value', 0);
|
||||
progressEle.setAttribute('max', totalSteps);
|
||||
} else if (data.event === 'upscaling-started') {
|
||||
document.getElementById("processing_cnt").textContent=data.processed_file_cnt;
|
||||
document.getElementById("scaling-inprocess-message").style.display = "block";
|
||||
} else if (data.event === 'upscaling-done') {
|
||||
document.getElementById("scaling-inprocess-message").style.display = "none";
|
||||
} else if (data.event === 'step') {
|
||||
progressEle.setAttribute('value', data.step);
|
||||
if (data.url) {
|
||||
progressImageEle.src = data.url;
|
||||
}
|
||||
} else if (data.event === 'canceled') {
|
||||
// avoid alerting as if this were an error case
|
||||
noOutputs = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-enable form, remove no-results-message
|
||||
form.querySelector('fieldset').removeAttribute('disabled');
|
||||
document.querySelector("#prompt").value = prompt;
|
||||
document.querySelector('progress').setAttribute('value', '0');
|
||||
|
||||
if (noOutputs) {
|
||||
alert("Error occurred while generating.");
|
||||
}
|
||||
});
|
||||
|
||||
// Disable form while generating
|
||||
form.querySelector('fieldset').setAttribute('disabled','');
|
||||
document.querySelector("#prompt").value = `Generating: "${prompt}"`;
|
||||
}
|
||||
|
||||
async function fetchRunLog() {
|
||||
try {
|
||||
let response = await fetch('/run_log.json')
|
||||
const data = await response.json();
|
||||
for(let item of data.run_log) {
|
||||
appendOutput(item.url, item.seed, item);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
window.onload = async () => {
|
||||
document.querySelector("#prompt").addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
const form = e.target.form;
|
||||
generateSubmit(form);
|
||||
}
|
||||
});
|
||||
document.querySelector("#generate-form").addEventListener('submit', (e) => {
|
||||
e.preventDefault();
|
||||
const form = e.target;
|
||||
|
||||
generateSubmit(form);
|
||||
});
|
||||
document.querySelector("#generate-form").addEventListener('change', (e) => {
|
||||
saveFields(e.target.form);
|
||||
});
|
||||
document.querySelector("#reset-seed").addEventListener('click', (e) => {
|
||||
document.querySelector("#seed").value = -1;
|
||||
saveFields(e.target.form);
|
||||
});
|
||||
document.querySelector("#reset-all").addEventListener('click', (e) => {
|
||||
clearFields(e.target.form);
|
||||
});
|
||||
document.querySelector("#remove-image").addEventListener('click', (e) => {
|
||||
initimg.value=null;
|
||||
});
|
||||
loadFields(document.querySelector("#generate-form"));
|
||||
|
||||
document.querySelector('#cancel-button').addEventListener('click', () => {
|
||||
fetch('/cancel').catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
});
|
||||
document.documentElement.addEventListener('keydown', (e) => {
|
||||
if (e.key === "Escape")
|
||||
fetch('/cancel').catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
|
||||
if (!config.gfpgan_model_exists) {
|
||||
document.querySelector("#gfpgan").style.display = 'none';
|
||||
}
|
||||
await fetchRunLog()
|
||||
};
|
Loading…
Reference in New Issue
Block a user