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

378 lines
19 KiB
HTML

<html>
<head>
<meta charset="utf-8">
<title>{{ config.TITLE }}</title>
<meta name="description" content="Restoration Online">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link href="{{ url_for('static',filename='bootstrap.min.css') }}" rel="stylesheet">
</head>
<body>
<div class="container">
<nav class="navbar navbar-expand-lg bg-body-tertiary">
<div class="container-fluid">
<a class="navbar-brand" href="#">{{ config.TITLE }}</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" data-en_XX="Home" data-zh_CN="主页" href=".">Home</a>
</li>
<li class="nav-item">
<a class="nav-link active" data-en_XX="Restoration" data-zh_CN="图像修复"
href="restoration">Restoration</a>
</li>
<li class="nav-item">
<a class="nav-link" data-en_XX="Help" data-zh_CN="帮助">Help</a>
</li>
<li class="nav-item">
<a class="nav-link" data-en_XX="About" data-zh_CN="关于">About</a>
</li>
</ul>
</div>
<div class="col-md-4">
<div class="input-group">
<label class="input-group-text" for="language" data-en_XX="Language"
data-zh_CN="语言">Language</label>
<select class="form-select" id="language">
<option value="zh_CN">中文(测试)</option>
<option selected value="en_XX">English</option>
</select>
</div>
</div>
</div>
</nav>
<div class="card mb-3">
<div class="card-header">
<span data-en_XX="Restoration" data-zh_CN="图像修复">Restoration</span>
</div>
<div class="card-body">
<div class="row">
<div class="col mb-3">
<div class="input-group">
<label for="apiKey" class="input-group-text" data-en_XX="API Key" data-zh_CN="API 密钥">API
Key</label>
<input type="password" class="form-control" id="apiKey" value="">
<div class="input-group-text">
<input class="form-check-input" type="checkbox" value="" id="isPrivate">
</div>
<label for="isPrivate" class="input-group-text" data-en_XX="Generate Private Images"
data-zh_CN="生成非公开图片">Generate Private Images</label>
</div>
</div>
</div>
<div class="row">
<div class="col-md-3 mb-3">
<div class="input-group input-group-sm">
<label for="restorationUpscale" class="input-group-text" data-en_XX="Upscale"
data-zh_CN="放大倍数">Upscale</label>
<input type="number" class="form-control" id="restorationUpscale"
aria-describedby="upscaleHelp" placeholder="1" min="1" max="8">
</div>
<div id="upscaleHelp" class="form-text" data-en_XX="Upsampling scale of the image"
data-zh_CN="将图像放大多少倍">
Upsampling scale of the image
</div>
</div>
<div class="col-md-3 mb-3">
<div class="input-group input-group-sm">
<label for="restorationWeight" class="input-group-text" data-en_XX="Weight"
data-zh_CN="比重">Weight</label>
<input type="number" class="form-control" id="restorationWeight"
aria-describedby="weightHelp" placeholder="0.5" min="0" max="1">
</div>
<div id="weightHelp" class="form-text" data-en_XX="Adjustable weights" data-zh_CN="0-1比重">
Adjustable weights
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="card">
<div class="card-header" data-en_XX="1. Choose Original Image" data-zh_CN="1. 选择原图">
1. Choose Original Image
</div>
<div class="card-body">
<div class="row">
<button id="restoreUploadImg" class="btn btn-primary mb-3" data-en_XX="Upload image"
data-zh_CN="上传一张图片">Upload
image</button>
</div>
<div class="row">
<button id="newRestorationJob" class="btn btn-primary mb-3"
data-en_XX="Let's Go with Image Below!" data-zh_CN="修复下面的图!">Restore Image
Below!</button>
</div>
</div>
<img class="card-img-bottom" id="restoreOriginalImg">
</div>
</div>
<div class="col-md-6">
<div class="card">
<div class="card-header" data-en_XX="2. Result" data-zh_CN="2. 结果">
2. Result
</div>
<div class="card-body">
<ul class="list-group">
<li class="list-group-item d-flex justify-content-between align-items-center">
<span id="restorationJobUUID"></span>
<span class="badge bg-primary rounded-pill" data-en_XX="Job UUID"
data-zh_CN="图片唯一识别码">Job UUID</span>
</li>
<li class="list-group-item d-flex justify-content-between align-items-center">
<span id="restorationStatus"></span>
<span class="badge bg-primary rounded-pill" data-en_XX="Job Status"
data-zh_CN="生成状态">Job Status</span>
</li>
</ul>
</div>
<img class="card-img-bottom" id="restorationImg">
</div>
</div>
</div>
</div>
</div>
<div class="card mb-3">
<div class="card-header">
<span data-en_XX="History" data-zh_CN="历史">History</span>
</div>
<div class="card-body">
<div class="input-group mb-3">
<label for="lookupUUID" class="input-group-text" data-en_XX="UUID (Optional)"
data-zh_CN="图片唯一识别码(选填)">UUID (Optional)</label>
<input type="text" class="form-control" id="lookupUUID" value="">
<button id="getJobHistory" class="btn btn-primary" data-en_XX="Get Job(s)" data-zh_CN="搜索历史">Get
Job(s)</button>
</div>
<div id="joblist"></div>
</div>
</div>
</div>
<!-- CSS code -->
<style>
</style>
<script src="{{ url_for('static',filename='jquery-3.6.1.min.js') }}"></script>
<script src="{{ url_for('static',filename='bootstrap.bundle.min.js') }}"></script>
<script src="{{ url_for('static',filename='jsketch.min.js') }}"></script>
<script src="{{ url_for('static',filename='jquery.sketchable.min.js') }}"></script>
<script src="{{ url_for('static',filename='jquery.sketchable.memento.min.js') }}"></script>
<script src="{{ url_for('static',filename='masonry.pkgd.min.js') }}"></script>
<script src="{{ url_for('static',filename='imagesloaded.pkgd.min.js') }}"></script>
<script>
$(document).ready(function () {
$('input[id]').on('input', function () {
var input = $(this);
var key = input.attr('id');
var value = input.val();
if (input.attr('type') == "checkbox") {
value = input.is(":checked");
}
localStorage.setItem(key, value);
}).each(function () {
var input = $(this);
var key = input.attr('id');
var value = localStorage.getItem(key);
if (input.attr('type') == "checkbox") {
input.prop('checked', value == "true");
} else if (value) {
input.val(value);
}
});
// Define the function to update the text based on the selected language
function updateText(language) {
$("[data-" + language + "]").each(function () {
$(this).text($(this).data(language.toLowerCase()));
});
}
// Listen for changes to the select element
$("#language").change(function () {
// Get the newly selected value
var newLanguage = $(this).val();
// Store the selected value in cache
localStorage.setItem("selectedLanguage", newLanguage);
// Update the text based on the selected language
updateText(newLanguage);
});
// Get the selected value from cache (if it exists)
var cachedLanguage = localStorage.getItem("selectedLanguage");
if (cachedLanguage) {
// Set the selected value
$("#language").val(cachedLanguage);
// Update the text based on the selected language
updateText(cachedLanguage);
}
var restoreOriginalImgData = null;
$("#restoreUploadImg").click(function () {
var input = $("<input type='file' accept='image/*'>").on("change", function () {
var reader = new FileReader();
reader.onload = function (e) {
restoreOriginalImgData = e.target.result;
$("#restoreOriginalImg").attr("src", restoreOriginalImgData);
};
reader.readAsDataURL(this.files[0]);
});
input.click();
});
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({ 'apikey': apikeyVal, 'uuid': uuidValue }),
success: function (response) {
console.log(response);
if (response.jobs.length == 1) {
if (response.jobs[0].type == 'restoration') {
$('#restorationStatus').html(response.jobs[0].status);
$('#restorationJobUUID').html(uuidValue);
if (response.jobs[0].status == "done") {
$('#restorationImg').attr('src', response.jobs[0].img);
return;
}
if (response.jobs[0].status == "failed") {
return;
}
}
}
setTimeout(function () { waitForImage(apikeyVal, uuidValue); }, 1500); // refresh every 1.5 second
},
error: function (xhr, status, error) {
console.log(error);
setTimeout(function () { waitForImage(apikeyVal, uuidValue); }, 1500); // refresh every 1.5 second
}
});
}
function submitJob(formData, uuidSelector, statusSelector) {
$.ajax({
type: 'POST',
url: '/add_job',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify(formData),
success: function (response) {
if (response.uuid) {
$(uuidSelector).html(response.uuid);
}
$(statusSelector).html('Submitting new job..');
waitForImage(formData.apikey, response.uuid);
},
error: function (xhr, status, error) {
// Handle error response
console.log(xhr.responseText);
$(statusSelector).html('Failed');
}
});
}
$('#newRestorationJob').click(function (e) {
e.preventDefault(); // Prevent the default form submission
if (restoreOriginalImgData == null) {
alert("No image cached");
return;
}
// Helper function to get input field value or a default value if empty
function getInputValue(id, defaultValue) {
var value = $(id).val().trim();
return value !== '' ? value : defaultValue;
}
// Validate input field values
var restorationUpscaleVal = parseInt(getInputValue('#restorationUpscale', '1'));
var restorationWeightVal = parseFloat(getInputValue('#restorationWeight', '0.5'));
var apikeyVal = $('#apiKey').val();
var formData = {
'apikey': apikeyVal,
'type': 'restoration',
'ref_img': restoreOriginalImgData,
'steps': restorationUpscaleVal, // reuse sd keys
'strength': restorationWeightVal, // reuse sd keys
'lang': $("#language option:selected").val(),
'is_private': $('#isPrivate').is(":checked") ? 1 : 0
};
submitJob(formData, '#restorationJobUUID', '#restorationStatus');
});
$('#getJobHistory').click(function () {
var apikeyValue = $('#apiKey').val();
var uuidValue = $('#lookupUUID').val();
$.ajax({
type: 'POST',
url: '/get_jobs',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify({ 'apikey': apikeyValue, 'uuid': uuidValue, 'type': 'restoration' }),
success: function (response) {
var jobsLength = response.jobs.length;
if (jobsLength == 0) {
$('#joblist').html("found nothing");
return;
}
var $joblist = $('#joblist');
var $grid = $('<div class="row"></div>');
$joblist.html($grid);
for (var i = 0; i < jobsLength; i++) {
console.log(response.jobs[i]);
var isPrivate = response.jobs[i].is_private;
var element = $("<div class='col col-sm-6 col-md-6 col-lg-4 mb-3'><div class='card'>" +
(response.jobs[i].img ? ("<img src='" + response.jobs[i].img + "' class='card-img-top'><div class='card-body'>") : "") +
"<ul class='list-group list-group-flush'>" +
"<li class='list-group-item'>status: " + response.jobs[i].status + "</li>" +
"<li class='list-group-item'>scale: " + response.jobs[i].steps + "</li>" +
"<li class='list-group-item'>weight: " + response.jobs[i].strength + "</li>" +
"<li class='list-group-item'>uuid: " + response.jobs[i].uuid + "</li>" +
"<li class='list-group-item'>w x h: " + response.jobs[i].width + " x " + response.jobs[i].height + "</li>" +
"</ul></div>" +
(response.jobs[i].ref_img ? ("<img src='" + response.jobs[i].ref_img + "' class='card-img-bottom'>") : "") +
"</div></div>");
$grid.append(element);
};
$grid.imagesLoaded().progress(function () {
$grid.masonry({
itemSelector: '.col',
columnWidth: '.col',
percentPosition: true
});
});
},
error: function (xhr, status, error) {
// Handle error response
console.log(xhr.responseText);
$('#joblist').html("found nothing");
}
});
});
});
</script>
</body>
</html>