stable-diffusion-for-fun/templates/index.html

294 lines
14 KiB
HTML

<html lang="en">
<head>
<meta charset="utf-8">
<title>Happy Diffusion (Private Access) | 9pm</title>
<meta name="description" content="Stable Diffusion Online">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-Zenh87qX5JnK2Jl0vWa8Ck2rdkQ2Bzep5IDxbcnCeuOxjzrPF/et3URy9Bv1WTRi" crossorigin="anonymous">
</head>
<body>
<div class="container">
<div class="card mb-3">
<div class="card-body">
<div class="row mb-3">
<div class="col-sm-8">
<label for="apiKey" class="form-label">API Key</label>
<input type="password" class="form-control" id="apiKey" value="demo">
</div>
<div class="col-sm-4">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="showPreview" disabled>
<label class="form-check-label" for="showPreview">
Preview Image
</label>
</div>
</div>
</div>
<div class="form-row mb-3">
<label for="prompt" class="form-label">Describe Your Image</label>
<input type="text" class="form-control" id="prompt" aria-describedby="promptHelp" value="">
<div id="promptHelp" class="form-text">Less than 77 words otherwise it'll be truncated. Example:
"photo of cute cat, RAW photo, (high detailed skin:1.2), 8k uhd, dslr, soft lighting, high
quality, film grain, Fujifilm XT3"</div>
</div>
<div class="form-row mb-3">
<label for="negPrompt" class="form-label">Describe What's NOT Your Image</label>
<input type="text" class="form-control" id="negPrompt" aria-describedby="negPromptHelp" value="">
<div id="negPromptHelp" class="form-text">Less than 77 words otherwise it'll be truncated.
Example: "(deformed iris, deformed pupils, semi-realistic, cgi, 3d, render, sketch, cartoon,
drawing, anime:1.4), text, close up, cropped, out of frame, worst quality, low quality, jpeg
artifacts, ugly, duplicate, morbid, mutilated, extra fingers, mutated hands, poorly drawn
hands, poorly drawn face, mutation, deformed, blurry, dehydrated, bad anatomy, bad
proportions, extra limbs, cloned face, disfigured, gross proportions, malformed limbs,
missing arms, missing legs, extra arms, extra legs, fused fingers, too many fingers, long
neck"</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="form-row">
<label for="inputSeed">Seed</label>
<input type="text" class="form-control" id="inputSeed" aria-describedby="inputSeedHelp"
value="">
<div id="inputSeedHelp" class="form-text">Leave it empty or put 0 to use a random
seed
</div>
</div>
<div class="form-row">
<label for="inputSteps">Steps</label>
<input type="number" class="form-control" id="inputSteps" aria-describedby="inputStepsHelp"
placeholder="default is 50">
<div id="inputStepsHelp" class="form-text">Each step is about 38s (CPU) or 0.1s
(GPU)
</div>
</div>
<div class="form-row">
<label for="inputWidth">Width</label>
<input type="number" class="form-control" id="inputWidth" placeholder="512" min="1"
max="1024">
</div>
<div class="form-row">
<label for="inputHeight">Height</label>
<input type="number" class="form-control" id="inputHeight" placeholder="512" min="1"
max="1024">
</div>
<button id="newJob" type="submit" class="btn btn-primary">Let's Go!</button>
</div>
<div class="col-md-9">
<div class="card mb-3">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs">
<li class="nav-item">
<a class="nav-link active" href="#card-txt">Text-to-Image</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#card-img">Image-to-Image</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#card-inpainting">Inpainting</a>
</li>
</ul>
</div>
<div class="card-body card-specific" id="card-img" style="display:none">
img
</div>
<div class="card-body card-specific" id="card-inpainting" style="display:none">
TBD
</div>
<div class="card-body card-specific" id="card-txt">
<div class="card">
<div class="card-header">
Result
</div>
<div class="card-body">
<ul class="list-group">
<li class="list-group-item d-flex justify-content-between align-items-center"
id="resultStatus"></li>
<li class="list-group-item d-flex justify-content-between align-items-center"
id="resultSeed"></li>
</ul>
</div>
<img class="card-img-bottom" id="newJobImg">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<form>
<div class="mb-3">
<label for="jobuuid" class="form-label">Job UUID</label>
<input type="jobuuid" class="form-control" id="jobuuid" aria-describedby="">
</div>
<button id="getjob" type="submit" class="btn btn-primary" disabled>Get Jobs</button>
<button id="canceljob" type="submit" class="btn btn-primary" disabled>Cancel Job</button>
</form>
<div class="mb-3" id="joblist">
</div>
</div>
<script src="https://code.jquery.com/jquery-3.6.1.min.js"
integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-OERcA2EqjJCMA+/3y+gxIOqMEjwtxJY7qPCqsdltbNJuaOe923+mo//f6V8Qbsw3"
crossorigin="anonymous"></script>
<script>
function waitForImage(apikeyVal, uuidValue) {
// Wait until image is done
$.ajax({
type: 'POST',
url: '/get_jobs',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify({ 'api_key': apikeyVal, 'uuid': uuidValue }),
success: function (response) {
console.log(response);
if (response.jobs.length == 1) {
$('#resultStatus').html(response.jobs[0].status)
$('#resultSeed').html("seed: " + response.jobs[0].seed)
if (response.jobs[0].status == "done") {
$('#newJobImg').attr('src', response.jobs[0].img);
return;
}
if (response.jobs[0].status == "failed") {
return;
}
}
setTimeout(function () { waitForImage(apikeyVal, uuidValue); }, 1000); // refresh every second
},
error: function (xhr, status, error) {
// Handle error response
console.log(xhr.responseText);
$('#resultStatus').html('failed');
}
});
}
$(document).ready(function () {
console.log("--- csrf token set ---");
var csrftoken = $("[name=csrfmiddlewaretoken]").val();
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$(".nav-link").click(function (e) {
e.preventDefault();
var target = $(this).attr("href"); // get the href value of the clicked link
// hide all card divs and show the corresponding one
$(".card-specific").hide();
$(".nav-link").removeClass("active");
$(this).addClass("active");
$(target).show();
});
$('#newJob').click(function (e) {
e.preventDefault(); // Prevent the default form submission
// Gather input field values
var apikeyVal = $('#apiKey').val();
var promptVal = $('#prompt').val();
var negPromptVal = $('#negPrompt').val();
var seedVal = $('#inputSeed').val();
if (seedVal == "0" || seedVal == "") {
seedVal = "0";
}
var stepsVal = parseInt($('#inputSteps').val());
if (isNaN(stepsVal)) {
stepsVal = 50;
}
var widthVal = parseInt($('#inputWidth').val());
if (isNaN(widthVal)) {
widthVal = 512;
}
var heightVal = parseInt($('#inputHeight').val());
if (isNaN(heightVal)) {
heightVal = 512;
}
if (promptVal == "") {
alert("missing prompt!");
return;
}
if (widthVal < 8 || widthVal > 960) {
alert("width must be between 8 and 960!");
return;
}
if (widthVal % 8 != 0) {
alert("width must be divisible by 8!");
return;
}
if (heightVal < 8 || heightVal > 960) {
alert("height must be between 8 and 960!");
return;
}
if (heightVal % 8 != 0) {
alert("height must be divisible by 8!");
return;
}
if (stepsVal > 200 || stepsVal < 1) {
alert("steps value must be between 1 and 200!");
return;
}
// Send POST request using Ajax
$.ajax({
type: 'POST',
url: '/add_job',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify({
'api_key': apikeyVal,
'type': 'txt',
'prompt': promptVal,
'seed': seedVal,
'steps': stepsVal,
'width': widthVal,
'height': heightVal,
'neg_prompt': negPromptVal
}),
success: function (response) {
console.log(response);
if (response.uuid) {
$('#jobuuid').val(response.uuid);
}
$('#resultStatus').html('submitting new job..');
waitForImage(apikeyVal, response.uuid);
},
error: function (xhr, status, error) {
// Handle error response
console.log(xhr.responseText);
$('#resultStatus').html('failed');
}
});
});
});
</script>
</body>
</html>