Add a 'Save' button in settings, to avoid starting/stopping threads while a user is still modifying their GPU settings

This commit is contained in:
cmdr2 2022-11-15 12:22:55 +05:30
parent 3546859fe5
commit 5cf763d51f
6 changed files with 206 additions and 230 deletions

View File

@ -6,8 +6,8 @@
<link rel="icon" type="image/png" href="/media/images/favicon-16x16.png" sizes="16x16"> <link rel="icon" type="image/png" href="/media/images/favicon-16x16.png" sizes="16x16">
<link rel="icon" type="image/png" href="/media/images/favicon-32x32.png" sizes="32x32"> <link rel="icon" type="image/png" href="/media/images/favicon-32x32.png" sizes="32x32">
<link rel="stylesheet" href="/media/css/fonts.css?v=1"> <link rel="stylesheet" href="/media/css/fonts.css?v=1">
<link rel="stylesheet" href="/media/css/themes.css?v=2"> <link rel="stylesheet" href="/media/css/themes.css?v=3">
<link rel="stylesheet" href="/media/css/main.css?v=15"> <link rel="stylesheet" href="/media/css/main.css?v=16">
<link rel="stylesheet" href="/media/css/auto-save.css?v=5"> <link rel="stylesheet" href="/media/css/auto-save.css?v=5">
<link rel="stylesheet" href="/media/css/modifier-thumbnails.css?v=4"> <link rel="stylesheet" href="/media/css/modifier-thumbnails.css?v=4">
<link rel="stylesheet" href="/media/css/fontawesome-all.min.css?v=1"> <link rel="stylesheet" href="/media/css/fontawesome-all.min.css?v=1">
@ -19,7 +19,7 @@
<div id="container"> <div id="container">
<div id="top-nav"> <div id="top-nav">
<div id="logo"> <div id="logo">
<h1>Stable Diffusion UI <small>v2.4.2 <span id="updateBranchLabel"></span></small></h1> <h1>Stable Diffusion UI <small>v2.4.3 <span id="updateBranchLabel"></span></small></h1>
</div> </div>
<div id="server-status"> <div id="server-status">
<div id="server-status-color"></div> <div id="server-status-color"></div>
@ -240,6 +240,8 @@
<h1>System Settings</h1> <h1>System Settings</h1>
<table class="form-table"></table> <table class="form-table"></table>
<br/> <br/>
<button id="save-system-settings-btn" class="primaryButton">Save</button>
<br/><br/>
<div> <div>
<h3><i class="fa fa-microchip icon"></i> System Info</h3> <h3><i class="fa fa-microchip icon"></i> System Info</h3>
<div id="system-info"></div> <div id="system-info"></div>
@ -322,13 +324,13 @@
</div> </div>
</body> </body>
<script src="media/js/parameters.js?v=7"></script> <script src="media/js/parameters.js?v=8"></script>
<script src="media/js/plugins.js?v=1"></script> <script src="media/js/plugins.js?v=1"></script>
<script src="media/js/utils.js?v=6"></script> <script src="media/js/utils.js?v=6"></script>
<script src="media/js/inpainting-editor.js?v=1"></script> <script src="media/js/inpainting-editor.js?v=1"></script>
<script src="media/js/image-modifiers.js?v=6"></script> <script src="media/js/image-modifiers.js?v=6"></script>
<script src="media/js/auto-save.js?v=8"></script> <script src="media/js/auto-save.js?v=8"></script>
<script src="media/js/main.js?v=21"></script> <script src="media/js/main.js?v=22"></script>
<script src="media/js/themes.js?v=4"></script> <script src="media/js/themes.js?v=4"></script>
<script src="media/js/dnd.js?v=9"></script> <script src="media/js/dnd.js?v=9"></script>
<script> <script>

View File

@ -162,7 +162,7 @@ label {
#makeImage { #makeImage {
flex: 0 0 70px; flex: 0 0 70px;
background: var(--accent-color); background: var(--accent-color);
border: var(--make-image-border); border: var(--primary-button-border);
color: rgb(255, 221, 255); color: rgb(255, 221, 255);
width: 100%; width: 100%;
height: 30pt; height: 30pt;
@ -420,6 +420,12 @@ img {
border: 1px solid rgb(107, 75, 0); border: 1px solid rgb(107, 75, 0);
color:rgb(255, 242, 211) color:rgb(255, 242, 211)
} }
.primaryButton {
flex: 0 0 70px;
background: var(--accent-color);
border: var(--primary-button-border);
color: rgb(255, 221, 255);
}
.secondaryButton { .secondaryButton {
background: rgb(132, 8, 0); background: rgb(132, 8, 0);
border: 1px solid rgb(122, 29, 0); border: 1px solid rgb(122, 29, 0);
@ -903,3 +909,6 @@ i.active {
float: right; float: right;
font-weight: bold; font-weight: bold;
} }
#save-system-settings-btn {
padding: 4pt 8pt;
}

View File

@ -23,7 +23,7 @@
--input-border-size: 1px; --input-border-size: 1px;
--accent-color: hsl(var(--accent-hue), 100%, var(--accent-lightness)); --accent-color: hsl(var(--accent-hue), 100%, var(--accent-lightness));
--accent-color-hover: hsl(var(--accent-hue), 100%, var(--accent-lightness-hover)); --accent-color-hover: hsl(var(--accent-hue), 100%, var(--accent-lightness-hover));
--make-image-border: 2px solid hsl(var(--accent-hue), 100%, calc(var(--accent-lightness) - 21%)); --primary-button-border: none;
} }
.theme-light { .theme-light {
@ -47,7 +47,7 @@
--accent-hue: 235; --accent-hue: 235;
--accent-lightness: 65%; --accent-lightness: 65%;
--make-image-border: none; --primary-button-border: none;
--button-color: var(--accent-color); --button-color: var(--accent-color);
--button-border: none; --button-border: none;
@ -69,7 +69,7 @@
--background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step)))); --background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step))));
--accent-hue: 212; --accent-hue: 212;
--make-image-border: none; --primary-button-border: none;
--button-color: var(--accent-color); --button-color: var(--accent-color);
--button-border: none; --button-border: none;
@ -91,7 +91,7 @@
--background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (2 * var(--value-step)))); --background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (2 * var(--value-step))));
--background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step)))); --background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step))));
--make-image-border: none; --primary-button-border: none;
--button-color: var(--accent-color); --button-color: var(--accent-color);
--button-border: none; --button-border: none;
@ -112,7 +112,7 @@
--background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (2 * var(--value-step)))); --background-color3: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (2 * var(--value-step))));
--background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (1.4 * var(--value-step)))); --background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) + (1.4 * var(--value-step))));
--make-image-border: none; --primary-button-border: none;
--button-color: var(--accent-color); --button-color: var(--accent-color);
--button-border: none; --button-border: none;
@ -134,7 +134,7 @@
--background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step)))); --background-color4: hsl(var(--main-hue), var(--main-saturation), calc(var(--value-base) - (3 * var(--value-step))));
--accent-hue: 212; --accent-hue: 212;
--make-image-border: none; --primary-button-border: none;
--button-color: var(--accent-color); --button-color: var(--accent-color);
--button-border: none; --button-border: none;

View File

@ -25,15 +25,6 @@ let initImagePreview = document.querySelector("#init_image_preview")
let initImageSizeBox = document.querySelector("#init_image_size_box") let initImageSizeBox = document.querySelector("#init_image_size_box")
let maskImageSelector = document.querySelector("#mask") let maskImageSelector = document.querySelector("#mask")
let maskImagePreview = document.querySelector("#mask_preview") let maskImagePreview = document.querySelector("#mask_preview")
let turboField = document.querySelector('#turbo')
let useCPUField = document.querySelector('#use_cpu')
let autoPickGPUsField = document.querySelector('#auto_pick_gpus')
let useGPUsField = document.querySelector('#use_gpus')
let useFullPrecisionField = document.querySelector('#use_full_precision')
let saveToDiskField = document.querySelector('#save_to_disk')
let diskPathField = document.querySelector('#diskPath')
// let allowNSFWField = document.querySelector("#allow_nsfw")
let useBetaChannelField = document.querySelector("#use_beta_channel")
let promptStrengthSlider = document.querySelector('#prompt_strength_slider') let promptStrengthSlider = document.querySelector('#prompt_strength_slider')
let promptStrengthField = document.querySelector('#prompt_strength') let promptStrengthField = document.querySelector('#prompt_strength')
let samplerField = document.querySelector('#sampler') let samplerField = document.querySelector('#sampler')
@ -60,21 +51,10 @@ let initialText = document.querySelector("#initial-text")
let previewTools = document.querySelector("#preview-tools") let previewTools = document.querySelector("#preview-tools")
let clearAllPreviewsBtn = document.querySelector("#clear-all-previews") let clearAllPreviewsBtn = document.querySelector("#clear-all-previews")
// let maskSetting = document.querySelector('#editor-inputs-mask_setting')
// let maskImagePreviewContainer = document.querySelector('#mask_preview_container')
// let maskImageClearBtn = document.querySelector('#mask_clear')
let maskSetting = document.querySelector('#enable_mask') let maskSetting = document.querySelector('#enable_mask')
let imagePreview = document.querySelector("#preview") let imagePreview = document.querySelector("#preview")
// let previewPrompt = document.querySelector('#preview-prompt')
let showConfigToggle = document.querySelector('#configToggleBtn')
// let configBox = document.querySelector('#config')
// let outputMsg = document.querySelector('#outputMsg')
let soundToggle = document.querySelector('#sound_toggle')
let serverStatusColor = document.querySelector('#server-status-color') let serverStatusColor = document.querySelector('#server-status-color')
let serverStatusMsg = document.querySelector('#server-status-msg') let serverStatusMsg = document.querySelector('#server-status-msg')
@ -1093,15 +1073,16 @@ function onDimensionChange() {
} }
diskPathField.disabled = !saveToDiskField.checked diskPathField.disabled = !saveToDiskField.checked
saveToDiskField.addEventListener('change', function(e) {
diskPathField.disabled = !this.checked
})
upscaleModelField.disabled = !useUpscalingField.checked upscaleModelField.disabled = !useUpscalingField.checked
useUpscalingField.addEventListener('change', function(e) { useUpscalingField.addEventListener('change', function(e) {
upscaleModelField.disabled = !this.checked upscaleModelField.disabled = !this.checked
}) })
if (useBetaChannelField.checked) {
updateBranchLabel.innerText = "(beta)"
}
makeImageBtn.addEventListener('click', makeImage) makeImageBtn.addEventListener('click', makeImage)
document.onkeydown = function(e) { document.onkeydown = function(e) {
@ -1151,114 +1132,6 @@ promptStrengthSlider.addEventListener('input', updatePromptStrength)
promptStrengthField.addEventListener('input', updatePromptStrengthSlider) promptStrengthField.addEventListener('input', updatePromptStrengthSlider)
updatePromptStrength() updatePromptStrength()
function getCurrentRenderDeviceSelection() {
let selectedGPUs = $('#use_gpus').val()
if (useCPUField.checked && !autoPickGPUsField.checked) {
return 'cpu'
}
if (autoPickGPUsField.checked || selectedGPUs.length == 0) {
return 'auto'
}
return selectedGPUs.join(',')
}
useCPUField.addEventListener('click', function() {
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
let autoPickGPUSettingEntry = getParameterSettingsEntry('auto_pick_gpus')
if (this.checked) {
gpuSettingEntry.style.display = 'none'
autoPickGPUSettingEntry.style.display = 'none'
autoPickGPUsField.setAttribute('data-old-value', autoPickGPUsField.checked)
autoPickGPUsField.checked = false
} else if (useGPUsField.options.length >= MIN_GPUS_TO_SHOW_SELECTION) {
gpuSettingEntry.style.display = ''
autoPickGPUSettingEntry.style.display = ''
let oldVal = autoPickGPUsField.getAttribute('data-old-value')
if (oldVal === null || oldVal === undefined) { // the UI started with CPU selected by default
autoPickGPUsField.checked = true
} else {
autoPickGPUsField.checked = (oldVal === 'true')
}
gpuSettingEntry.style.display = (autoPickGPUsField.checked ? 'none' : '')
}
changeAppConfig({
'render_devices': getCurrentRenderDeviceSelection()
})
})
useGPUsField.addEventListener('click', function() {
let selectedGPUs = $('#use_gpus').val()
autoPickGPUsField.checked = (selectedGPUs.length === 0)
changeAppConfig({
'render_devices': getCurrentRenderDeviceSelection()
})
})
autoPickGPUsField.addEventListener('click', function() {
if (this.checked) {
$('#use_gpus').val([])
}
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
gpuSettingEntry.style.display = (this.checked ? 'none' : '')
changeAppConfig({
'render_devices': getCurrentRenderDeviceSelection()
})
})
async function changeAppConfig(configDelta) {
// if (!isServerAvailable()) {
// // logError('The server is still starting up..')
// alert('The server is still starting up..')
// e.preventDefault()
// return false
// }
try {
let res = await fetch('/app_config', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(configDelta)
})
res = await res.json()
console.log('set config status response', res)
} catch (e) {
console.log('set config status error', e)
}
}
useBetaChannelField.addEventListener('click', async function(e) {
let updateBranch = (this.checked ? 'beta' : 'main')
await changeAppConfig({
'update_branch': updateBranch
})
})
async function getAppConfig() {
try {
let res = await fetch('/get/app_config')
const config = await res.json()
if (config.update_branch === 'beta') {
useBetaChannelField.checked = true
updateBranchLabel.innerText = "(beta)"
}
console.log('get config status response', config)
} catch (e) {
console.log('get config status error', e)
}
}
async function getModels() { async function getModels() {
try { try {
var sd_model_setting_key = "stable_diffusion_model" var sd_model_setting_key = "stable_diffusion_model"
@ -1395,70 +1268,6 @@ promptsFromFileSelector.addEventListener('change', function() {
} }
}) })
async function getDiskPath() {
try {
var diskPath = getSetting("diskPath")
if (diskPath == '' || diskPath == undefined || diskPath == "undefined") {
let res = await fetch('/get/output_dir')
if (res.status === 200) {
res = await res.json()
res = res.output_dir
setSetting("diskPath", res)
}
}
} catch (e) {
console.log('error fetching output dir path', e)
}
}
async function getDevices() {
try {
let res = await fetch('/get/devices')
if (res.status === 200) {
res = await res.json()
let allDeviceIds = Object.keys(res['all']).filter(d => d !== 'cpu')
let activeDeviceIds = Object.keys(res['active']).filter(d => d !== 'cpu')
if (activeDeviceIds.length === 0) {
useCPUField.checked = true
}
if (allDeviceIds.length < MIN_GPUS_TO_SHOW_SELECTION || useCPUField.checked) {
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
gpuSettingEntry.style.display = 'none'
let autoPickGPUSettingEntry = getParameterSettingsEntry('auto_pick_gpus')
autoPickGPUSettingEntry.style.display = 'none'
}
if (allDeviceIds.length === 0) {
useCPUField.checked = true
useCPUField.disabled = true // no compatible GPUs, so make the CPU mandatory
}
autoPickGPUsField.checked = (res['config'] === 'auto')
useGPUsField.innerHTML = ''
allDeviceIds.forEach(device => {
let deviceName = res['all'][device]['name']
let deviceOption = `<option value="${device}">${deviceName} (${device})</option>`
useGPUsField.insertAdjacentHTML('beforeend', deviceOption)
})
if (autoPickGPUsField.checked) {
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
gpuSettingEntry.style.display = 'none'
} else {
$('#use_gpus').val(activeDeviceIds)
}
}
} catch (e) {
console.log('error fetching devices', e)
}
}
/* setup popup handlers */ /* setup popup handlers */
document.querySelectorAll('.popup').forEach(popup => { document.querySelectorAll('.popup').forEach(popup => {
popup.addEventListener('click', event => { popup.addEventListener('click', event => {

View File

@ -1,5 +1,3 @@
/** /**
* Enum of parameter types * Enum of parameter types
* @readonly * @readonly
@ -135,7 +133,7 @@ function getParameterElement(parameter) {
} }
} }
var parametersTable = document.querySelector("#system-settings table") let parametersTable = document.querySelector("#system-settings table")
/* fill in the system settings popup table */ /* fill in the system settings popup table */
function initParameters() { function initParameters() {
PARAMETERS.forEach(parameter => { PARAMETERS.forEach(parameter => {
@ -150,5 +148,171 @@ function initParameters() {
}) })
} }
initParameters(); initParameters()
let turboField = document.querySelector('#turbo')
let useCPUField = document.querySelector('#use_cpu')
let autoPickGPUsField = document.querySelector('#auto_pick_gpus')
let useGPUsField = document.querySelector('#use_gpus')
let useFullPrecisionField = document.querySelector('#use_full_precision')
let saveToDiskField = document.querySelector('#save_to_disk')
let diskPathField = document.querySelector('#diskPath')
let useBetaChannelField = document.querySelector("#use_beta_channel")
let saveSettingsBtn = document.querySelector('#save-system-settings-btn')
async function changeAppConfig(configDelta) {
try {
let res = await fetch('/app_config', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(configDelta)
})
res = await res.json()
console.log('set config status response', res)
} catch (e) {
console.log('set config status error', e)
}
}
async function getAppConfig() {
try {
let res = await fetch('/get/app_config')
const config = await res.json()
if (config.update_branch === 'beta') {
useBetaChannelField.checked = true
}
console.log('get config status response', config)
} catch (e) {
console.log('get config status error', e)
}
}
saveToDiskField.addEventListener('change', function(e) {
diskPathField.disabled = !this.checked
})
function getCurrentRenderDeviceSelection() {
let selectedGPUs = $('#use_gpus').val()
if (useCPUField.checked && !autoPickGPUsField.checked) {
return 'cpu'
}
if (autoPickGPUsField.checked || selectedGPUs.length == 0) {
return 'auto'
}
return selectedGPUs.join(',')
}
useCPUField.addEventListener('click', function() {
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
let autoPickGPUSettingEntry = getParameterSettingsEntry('auto_pick_gpus')
if (this.checked) {
gpuSettingEntry.style.display = 'none'
autoPickGPUSettingEntry.style.display = 'none'
autoPickGPUsField.setAttribute('data-old-value', autoPickGPUsField.checked)
autoPickGPUsField.checked = false
} else if (useGPUsField.options.length >= MIN_GPUS_TO_SHOW_SELECTION) {
gpuSettingEntry.style.display = ''
autoPickGPUSettingEntry.style.display = ''
let oldVal = autoPickGPUsField.getAttribute('data-old-value')
if (oldVal === null || oldVal === undefined) { // the UI started with CPU selected by default
autoPickGPUsField.checked = true
} else {
autoPickGPUsField.checked = (oldVal === 'true')
}
gpuSettingEntry.style.display = (autoPickGPUsField.checked ? 'none' : '')
}
})
useGPUsField.addEventListener('click', function() {
let selectedGPUs = $('#use_gpus').val()
autoPickGPUsField.checked = (selectedGPUs.length === 0)
})
autoPickGPUsField.addEventListener('click', function() {
if (this.checked) {
$('#use_gpus').val([])
}
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
gpuSettingEntry.style.display = (this.checked ? 'none' : '')
})
async function getDiskPath() {
try {
var diskPath = getSetting("diskPath")
if (diskPath == '' || diskPath == undefined || diskPath == "undefined") {
let res = await fetch('/get/output_dir')
if (res.status === 200) {
res = await res.json()
res = res.output_dir
setSetting("diskPath", res)
}
}
} catch (e) {
console.log('error fetching output dir path', e)
}
}
async function getDevices() {
try {
let res = await fetch('/get/devices')
if (res.status === 200) {
res = await res.json()
let allDeviceIds = Object.keys(res['all']).filter(d => d !== 'cpu')
let activeDeviceIds = Object.keys(res['active']).filter(d => d !== 'cpu')
if (activeDeviceIds.length === 0) {
useCPUField.checked = true
}
if (allDeviceIds.length < MIN_GPUS_TO_SHOW_SELECTION || useCPUField.checked) {
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
gpuSettingEntry.style.display = 'none'
let autoPickGPUSettingEntry = getParameterSettingsEntry('auto_pick_gpus')
autoPickGPUSettingEntry.style.display = 'none'
}
if (allDeviceIds.length === 0) {
useCPUField.checked = true
useCPUField.disabled = true // no compatible GPUs, so make the CPU mandatory
}
autoPickGPUsField.checked = (res['config'] === 'auto')
useGPUsField.innerHTML = ''
allDeviceIds.forEach(device => {
let deviceName = res['all'][device]['name']
let deviceOption = `<option value="${device}">${deviceName} (${device})</option>`
useGPUsField.insertAdjacentHTML('beforeend', deviceOption)
})
if (autoPickGPUsField.checked) {
let gpuSettingEntry = getParameterSettingsEntry('use_gpus')
gpuSettingEntry.style.display = 'none'
} else {
$('#use_gpus').val(activeDeviceIds)
}
}
} catch (e) {
console.log('error fetching devices', e)
}
}
saveSettingsBtn.addEventListener('click', function() {
let updateBranch = (useBetaChannelField.checked ? 'beta' : 'main')
changeAppConfig({
'render_devices': getCurrentRenderDeviceSelection(),
'update_branch': updateBranch
})
})

View File

@ -162,9 +162,13 @@ async def setAppConfig(req : SetAppConfigRequest):
if req.update_branch: if req.update_branch:
config['update_branch'] = req.update_branch config['update_branch'] = req.update_branch
if req.render_devices: if req.render_devices:
update_render_threads_from_request(req.render_devices) update_render_devices_in_config(config, req.render_devices)
try: try:
setConfig(config) setConfig(config)
if req.render_devices:
update_render_threads()
return JSONResponse({'status': 'OK'}, headers=NOCACHE_HEADERS) return JSONResponse({'status': 'OK'}, headers=NOCACHE_HEADERS)
except Exception as e: except Exception as e:
print(traceback.format_exc()) print(traceback.format_exc())
@ -278,26 +282,14 @@ def save_model_to_config(ckpt_model_name, vae_model_name):
setConfig(config) setConfig(config)
def save_render_devices_to_config(render_devices): def update_render_devices_in_config(config, render_devices):
config = getConfig() if render_devices not in ('cpu', 'auto') and not render_devices.startswith('cuda:'):
if 'render_devices' not in config: raise HTTPException(status_code=400, detail=f'Invalid render device requested: {render_devices}')
config['render_devices'] = {}
if render_devices.startswith('cuda:'):
render_devices = render_devices.split(',')
config['render_devices'] = render_devices config['render_devices'] = render_devices
if render_devices is None or len(render_devices) == 0:
del config['render_devices']
setConfig(config)
def update_render_threads_from_request(render_device):
if render_device not in ('cpu', 'auto') and not render_device.startswith('cuda:'):
raise HTTPException(status_code=400, detail=f'Invalid render device requested: {render_device}')
if render_device.startswith('cuda:'):
render_device = render_device.split(',')
save_render_devices_to_config(render_device)
update_render_threads()
@app.post('/render') @app.post('/render')
def render(req : task_manager.ImageRequest): def render(req : task_manager.ImageRequest):