2022-10-29 01:48:32 +02:00
|
|
|
/**
|
|
|
|
* Enum of parameter types
|
|
|
|
* @readonly
|
|
|
|
* @enum {string}
|
|
|
|
*/
|
|
|
|
var ParameterType = {
|
|
|
|
checkbox: "checkbox",
|
2022-11-30 07:48:34 +01:00
|
|
|
select: "select",
|
|
|
|
select_multiple: "select_multiple",
|
|
|
|
custom: "custom",
|
2022-10-29 01:48:32 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* JSDoc style
|
|
|
|
* @typedef {object} Parameter
|
|
|
|
* @property {string} id
|
|
|
|
* @property {ParameterType} type
|
|
|
|
* @property {string} label
|
|
|
|
* @property {?string} note
|
|
|
|
* @property {number|boolean|string} default
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/** @type {Array.<Parameter>} */
|
|
|
|
var PARAMETERS = [
|
2022-11-30 07:48:34 +01:00
|
|
|
{
|
|
|
|
id: "theme",
|
|
|
|
type: ParameterType.select,
|
|
|
|
label: "Theme",
|
|
|
|
default: "theme-default",
|
|
|
|
note: "customize the look and feel of the ui",
|
|
|
|
options: [ // Note: options expanded dynamically
|
|
|
|
{
|
|
|
|
value: "theme-default",
|
|
|
|
label: "Default"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
icon: "fa-palette"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "save_to_disk",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Auto-Save Images",
|
|
|
|
note: "automatically saves images to the specified location",
|
|
|
|
icon: "fa-download",
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "diskPath",
|
|
|
|
type: ParameterType.custom,
|
|
|
|
label: "Save Location",
|
|
|
|
render: (parameter) => {
|
|
|
|
return `<input id="${parameter.id}" name="${parameter.id}" size="30" disabled>`
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "sound_toggle",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Enable Sound",
|
|
|
|
note: "plays a sound on task completion",
|
|
|
|
icon: "fa-volume-low",
|
|
|
|
default: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "ui_open_browser_on_start",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Open browser on startup",
|
|
|
|
note: "starts the default browser on startup",
|
|
|
|
icon: "fa-window-restore",
|
|
|
|
default: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "turbo",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Turbo Mode",
|
|
|
|
note: "generates images faster, but uses an additional 1 GB of GPU memory",
|
|
|
|
icon: "fa-forward",
|
|
|
|
default: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "use_cpu",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Use CPU (not GPU)",
|
|
|
|
note: "warning: this will be *very* slow",
|
|
|
|
icon: "fa-microchip",
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "auto_pick_gpus",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Automatically pick the GPUs (experimental)",
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "use_gpus",
|
|
|
|
type: ParameterType.select_multiple,
|
|
|
|
label: "GPUs to use (experimental)",
|
|
|
|
note: "to process in parallel",
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "use_full_precision",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Use Full Precision",
|
|
|
|
note: "for GPU-only. warning: this will consume more VRAM",
|
|
|
|
icon: "fa-crosshairs",
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "auto_save_settings",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Auto-Save Settings",
|
|
|
|
note: "restores settings on browser load",
|
|
|
|
icon: "fa-gear",
|
|
|
|
default: true,
|
|
|
|
},
|
2022-11-30 09:17:08 +01:00
|
|
|
{
|
|
|
|
id: "confirm_dangerous_actions",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Confirm dangerous actions",
|
|
|
|
note: "Actions that might lead to data loss must either be clicked with the shift key pressed, or confirmed in an 'Are you sure?' dialog",
|
|
|
|
icon: "fa-check-double",
|
|
|
|
default: true,
|
|
|
|
},
|
2022-11-30 07:48:34 +01:00
|
|
|
{
|
|
|
|
id: "listen_to_network",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Make Stable Diffusion available on your network",
|
|
|
|
note: "Other devices on your network can access this web page",
|
|
|
|
icon: "fa-network-wired",
|
|
|
|
default: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "listen_port",
|
|
|
|
type: ParameterType.custom,
|
|
|
|
label: "Network port",
|
|
|
|
note: "Port that this server listens to. The '9000' part in 'http://localhost:9000'",
|
|
|
|
icon: "fa-anchor",
|
|
|
|
render: (parameter) => {
|
|
|
|
return `<input id="${parameter.id}" name="${parameter.id}" size="6" value="9000" onkeypress="preventNonNumericalInput(event)">`
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "test_sd2",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Test SD 2.0",
|
|
|
|
note: "Experimental! High memory usage! GPU-only! Not the final version! Please restart the program after changing this.",
|
|
|
|
icon: "fa-fire",
|
|
|
|
default: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
id: "use_beta_channel",
|
|
|
|
type: ParameterType.checkbox,
|
|
|
|
label: "Beta channel",
|
|
|
|
note: "Get the latest features immediately (but could be less stable). Please restart the program after changing this.",
|
|
|
|
icon: "fa-fire",
|
|
|
|
default: false,
|
|
|
|
},
|
2022-10-29 03:25:54 +02:00
|
|
|
];
|
|
|
|
|
2022-11-09 14:47:44 +01:00
|
|
|
function getParameterSettingsEntry(id) {
|
2022-11-30 07:48:34 +01:00
|
|
|
let parameter = PARAMETERS.filter(p => p.id === id)
|
|
|
|
if (parameter.length === 0) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return parameter[0].settingsEntry
|
2022-11-09 14:47:44 +01:00
|
|
|
}
|
2022-10-29 03:25:54 +02:00
|
|
|
|
|
|
|
function getParameterElement(parameter) {
|
2022-11-30 07:48:34 +01:00
|
|
|
switch (parameter.type) {
|
|
|
|
case ParameterType.checkbox:
|
|
|
|
var is_checked = parameter.default ? " checked" : "";
|
|
|
|
return `<input id="${parameter.id}" name="${parameter.id}"${is_checked} type="checkbox">`
|
|
|
|
case ParameterType.select:
|
|
|
|
case ParameterType.select_multiple:
|
|
|
|
var options = (parameter.options || []).map(option => `<option value="${option.value}">${option.label}</option>`).join("")
|
|
|
|
var multiple = (parameter.type == ParameterType.select_multiple ? 'multiple' : '')
|
|
|
|
return `<select id="${parameter.id}" name="${parameter.id}" ${multiple}>${options}</select>`
|
|
|
|
case ParameterType.custom:
|
|
|
|
return parameter.render(parameter)
|
|
|
|
default:
|
|
|
|
console.error(`Invalid type for parameter ${parameter.id}`);
|
|
|
|
return "ERROR: Invalid Type"
|
|
|
|
}
|
2022-10-29 03:25:54 +02:00
|
|
|
}
|
|
|
|
|
2022-11-18 02:58:09 +01:00
|
|
|
let parametersTable = document.querySelector("#system-settings .parameters-table")
|
2022-10-29 03:25:54 +02:00
|
|
|
/* fill in the system settings popup table */
|
|
|
|
function initParameters() {
|
2022-11-30 07:48:34 +01:00
|
|
|
PARAMETERS.forEach(parameter => {
|
|
|
|
var element = getParameterElement(parameter)
|
|
|
|
var note = parameter.note ? `<small>${parameter.note}</small>` : "";
|
|
|
|
var icon = parameter.icon ? `<i class="fa ${parameter.icon}"></i>` : "";
|
|
|
|
var newrow = document.createElement('div')
|
|
|
|
newrow.innerHTML = `
|
|
|
|
<div>${icon}</div>
|
|
|
|
<div><label for="${parameter.id}">${parameter.label}</label>${note}</div>
|
|
|
|
<div>${element}</div>`
|
|
|
|
parametersTable.appendChild(newrow)
|
|
|
|
parameter.settingsEntry = newrow
|
|
|
|
})
|
2022-10-29 03:25:54 +02:00
|
|
|
}
|
|
|
|
|
2022-11-15 07:52:55 +01:00
|
|
|
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')
|
2022-11-19 17:10:45 +01:00
|
|
|
let listenToNetworkField = document.querySelector("#listen_to_network")
|
|
|
|
let listenPortField = document.querySelector("#listen_port")
|
2022-11-25 07:47:44 +01:00
|
|
|
let testSD2Field = document.querySelector("#test_sd2")
|
2022-11-15 07:52:55 +01:00
|
|
|
let useBetaChannelField = document.querySelector("#use_beta_channel")
|
2022-11-16 08:13:46 +01:00
|
|
|
let uiOpenBrowserOnStartField = document.querySelector("#ui_open_browser_on_start")
|
2022-11-23 23:05:30 +01:00
|
|
|
let confirmDangerousActionsField = document.querySelector("#confirm_dangerous_actions")
|
2022-11-15 07:52:55 +01:00
|
|
|
|
|
|
|
let saveSettingsBtn = document.querySelector('#save-system-settings-btn')
|
|
|
|
|
2022-11-23 11:25:36 +01:00
|
|
|
let getServerIPBtn = document.querySelector('#get-server-ip')
|
|
|
|
let ipInfoContainer = document.querySelector('#ip-info')
|
|
|
|
|
|
|
|
|
2022-11-15 07:52:55 +01:00
|
|
|
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
|
2022-11-19 17:10:45 +01:00
|
|
|
document.querySelector("#updateBranchLabel").innerText = "(beta)"
|
2022-11-15 07:52:55 +01:00
|
|
|
}
|
2022-11-16 08:13:46 +01:00
|
|
|
if (config.ui && config.ui.open_browser_on_start === false) {
|
|
|
|
uiOpenBrowserOnStartField.checked = false
|
|
|
|
}
|
2022-11-25 07:47:44 +01:00
|
|
|
if ('test_sd2' in config) {
|
|
|
|
testSD2Field.checked = config['test_sd2']
|
|
|
|
}
|
2022-11-30 07:35:46 +01:00
|
|
|
|
2022-11-30 07:48:34 +01:00
|
|
|
let testSD2SettingEntry = getParameterSettingsEntry('test_sd2')
|
|
|
|
testSD2SettingEntry.style.display = (config.update_branch === 'beta' ? '' : 'none')
|
|
|
|
if (config.net && config.net.listen_to_network === false) {
|
|
|
|
listenToNetworkField.checked = false
|
|
|
|
}
|
|
|
|
if (config.net && config.net.listen_port !== undefined) {
|
|
|
|
listenPortField.value = config.net.listen_port
|
|
|
|
}
|
2022-11-15 07:52:55 +01:00
|
|
|
|
|
|
|
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() {
|
2022-11-30 07:48:34 +01:00
|
|
|
let updateBranch = (useBetaChannelField.checked ? 'beta' : 'main')
|
|
|
|
|
|
|
|
if (listenPortField.value == '') {
|
|
|
|
alert('The network port field must not be empty.')
|
|
|
|
} else if (listenPortField.value<1 || listenPortField.value>65535) {
|
|
|
|
alert('The network port must be a number from 1 to 65535')
|
|
|
|
} else {
|
|
|
|
changeAppConfig({
|
|
|
|
'render_devices': getCurrentRenderDeviceSelection(),
|
|
|
|
'update_branch': updateBranch,
|
|
|
|
'ui_open_browser_on_start': uiOpenBrowserOnStartField.checked,
|
|
|
|
'listen_to_network': listenToNetworkField.checked,
|
|
|
|
'listen_port': listenPortField.value,
|
|
|
|
'test_sd2': testSD2Field.checked
|
|
|
|
})
|
|
|
|
}
|
2022-11-17 06:31:10 +01:00
|
|
|
|
2022-11-30 07:48:34 +01:00
|
|
|
saveSettingsBtn.classList.add('active')
|
|
|
|
asyncDelay(300).then(() => saveSettingsBtn.classList.remove('active'))
|
2022-11-15 07:52:55 +01:00
|
|
|
})
|
2022-11-23 11:25:36 +01:00
|
|
|
|
|
|
|
getServerIPBtn.addEventListener('click', async function() {
|
|
|
|
ipInfoContainer.innerHTML = "Retrieving server addresses..."
|
|
|
|
let list = "<h4>List of server addresses</h4><p>If there is more than one result, not all of them might be reachable from other devices.</p><div>"
|
|
|
|
let res = await fetch('/get/ip_config')
|
|
|
|
let data = await res.json()
|
|
|
|
let port = listenPortField.value
|
|
|
|
// Merge hostname (field 0) into list of IPs (field 2)
|
|
|
|
data[2].push(data[0])
|
|
|
|
data[2].forEach((addr) => { let url=`http://${addr}:${port}/`; list+=`<div><a href="${url}">${url}</a></div>`;})
|
|
|
|
list += "</div>"
|
|
|
|
ipInfoContainer.innerHTML = list
|
|
|
|
})
|
|
|
|
|