2022-10-29 01:48:32 +02:00
/ * *
* Enum of parameter types
* @ readonly
* @ enum { string }
* /
2023-04-08 16:43:44 +02:00
var ParameterType = {
2022-10-29 01:48:32 +02:00
checkbox : "checkbox" ,
2022-11-30 07:48:34 +01:00
select : "select" ,
select _multiple : "select_multiple" ,
2023-02-22 15:02:00 +01:00
slider : "slider" ,
2023-04-28 12:20:44 +02:00
custom : "custom" ,
2023-04-27 19:56:56 +02:00
}
2022-10-29 01:48:32 +02:00
2023-05-28 00:50:23 +02:00
/ * *
* Element shortcuts
* /
let parametersTable = document . querySelector ( "#system-settings-table" )
let networkParametersTable = document . querySelector ( "#system-settings-network-table" )
2022-10-29 01:48:32 +02:00
/ * *
* JSDoc style
* @ typedef { object } Parameter
* @ property { string } id
2023-03-30 02:56:24 +02:00
* @ property { keyof ParameterType } type
* @ property { string | ( parameter : Parameter ) => ( HTMLElement | string ) } label
* @ property { string | ( parameter : Parameter ) => ( HTMLElement | string ) | undefined } note
* @ property { ( parameter : Parameter ) => ( HTMLElement | string ) | undefined } render
* @ property { string | undefined } icon
2022-10-29 01:48:32 +02:00
* @ property { number | boolean | string } default
2023-03-30 02:56:24 +02:00
* @ property { boolean ? } saveInAppConfig
2022-10-29 01:48:32 +02:00
* /
/** @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" ,
2023-04-27 19:56:56 +02:00
options : [
// Note: options expanded dynamically
2022-11-30 07:48:34 +01:00
{
value : "theme-default" ,
2023-04-28 12:20:44 +02:00
label : "Default" ,
} ,
2022-11-30 07:48:34 +01:00
] ,
2023-04-28 12:20:44 +02:00
icon : "fa-palette" ,
2022-11-30 07:48:34 +01:00
} ,
{
id : "save_to_disk" ,
type : ParameterType . checkbox ,
label : "Auto-Save Images" ,
note : "automatically saves images to the specified location" ,
icon : "fa-download" ,
2023-04-28 12:20:44 +02:00
default : false ,
2022-11-30 07:48:34 +01:00
} ,
{
id : "diskPath" ,
type : ParameterType . custom ,
label : "Save Location" ,
render : ( parameter ) => {
return ` <input id=" ${ parameter . id } " name=" ${ parameter . id } " size="30" disabled> `
2023-04-28 12:20:44 +02:00
} ,
2022-11-30 07:48:34 +01:00
} ,
2022-12-12 09:36:20 +01:00
{
id : "metadata_output_format" ,
type : ParameterType . select ,
label : "Metadata format" ,
2022-12-14 05:48:01 +01:00
note : "will be saved to disk in this format" ,
2023-02-10 13:43:08 +01:00
default : "txt" ,
2022-12-12 09:36:20 +01:00
options : [
2023-01-24 10:47:48 +01:00
{
value : "none" ,
2023-04-28 12:20:44 +02:00
label : "none" ,
2023-01-24 10:47:48 +01:00
} ,
2022-12-12 09:36:20 +01:00
{
value : "txt" ,
2023-04-28 12:20:44 +02:00
label : "txt" ,
2022-12-14 05:48:01 +01:00
} ,
{
value : "json" ,
2023-04-28 12:20:44 +02:00
label : "json" ,
2023-01-24 10:47:48 +01:00
} ,
{
value : "embed" ,
2023-04-28 12:20:44 +02:00
label : "embed" ,
2023-03-29 05:49:05 +02:00
} ,
{
value : "embed,txt" ,
2023-04-28 12:20:44 +02:00
label : "embed & txt" ,
2023-03-29 05:49:05 +02:00
} ,
{
value : "embed,json" ,
2023-04-28 12:20:44 +02:00
label : "embed & json" ,
} ,
] ,
2022-12-12 09:36:20 +01:00
} ,
2023-02-18 10:31:13 +01:00
{
id : "block_nsfw" ,
type : ParameterType . checkbox ,
label : "Block NSFW images" ,
note : "blurs out NSFW images" ,
icon : "fa-land-mine-on" ,
2023-04-28 12:20:44 +02:00
default : false ,
2023-02-18 10:31:13 +01:00
} ,
2022-11-30 07:48:34 +01:00
{
id : "sound_toggle" ,
type : ParameterType . checkbox ,
label : "Enable Sound" ,
note : "plays a sound on task completion" ,
icon : "fa-volume-low" ,
2023-04-28 12:20:44 +02:00
default : true ,
2022-11-30 07:48:34 +01:00
} ,
2022-12-06 12:34:08 +01:00
{
id : "process_order_toggle" ,
type : ParameterType . checkbox ,
label : "Process newest jobs first" ,
note : "reverse the normal processing order" ,
2022-12-27 04:10:37 +01:00
icon : "fa-arrow-down-short-wide" ,
2023-04-28 12:20:44 +02:00
default : false ,
2022-12-06 12:34:08 +01:00
} ,
2022-11-30 07:48:34 +01:00
{
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 ,
2023-04-28 12:20:44 +02:00
saveInAppConfig : true ,
2022-11-30 07:48:34 +01:00
} ,
{
2022-12-16 07:04:49 +01:00
id : "vram_usage_level" ,
2022-12-15 19:00:06 +01:00
type : ParameterType . select ,
2022-12-16 07:04:49 +01:00
label : "GPU Memory Usage" ,
2023-04-27 19:56:56 +02:00
note :
"Faster performance requires more GPU memory (VRAM)<br/><br/>" +
"<b>Balanced:</b> nearly as fast as High, much lower VRAM usage<br/>" +
"<b>High:</b> fastest, maximum GPU memory usage</br>" +
"<b>Low:</b> slowest, recommended for GPUs with 3 to 4 GB memory" ,
2022-11-30 07:48:34 +01:00
icon : "fa-forward" ,
2022-12-16 07:04:49 +01:00
default : "balanced" ,
2022-12-15 19:00:06 +01:00
options : [
2023-04-27 19:56:56 +02:00
{ value : "balanced" , label : "Balanced" } ,
{ value : "high" , label : "High" } ,
2023-04-28 12:20:44 +02:00
{ value : "low" , label : "Low" } ,
] ,
2022-11-30 07:48:34 +01:00
} ,
{
id : "use_cpu" ,
type : ParameterType . checkbox ,
label : "Use CPU (not GPU)" ,
note : "warning: this will be *very* slow" ,
icon : "fa-microchip" ,
2023-04-28 12:20:44 +02:00
default : false ,
2022-11-30 07:48:34 +01:00
} ,
{
id : "auto_pick_gpus" ,
type : ParameterType . checkbox ,
label : "Automatically pick the GPUs (experimental)" ,
2023-04-28 12:20:44 +02:00
default : false ,
2022-11-30 07:48:34 +01:00
} ,
{
id : "use_gpus" ,
type : ParameterType . select _multiple ,
label : "GPUs to use (experimental)" ,
note : "to process in parallel" ,
2023-04-28 12:20:44 +02:00
default : false ,
2022-11-30 07:48:34 +01:00
} ,
{
id : "auto_save_settings" ,
type : ParameterType . checkbox ,
label : "Auto-Save Settings" ,
note : "restores settings on browser load" ,
icon : "fa-gear" ,
2023-04-28 12:20:44 +02:00
default : true ,
2022-11-30 07:48:34 +01:00
} ,
2022-11-30 09:17:08 +01:00
{
id : "confirm_dangerous_actions" ,
type : ParameterType . checkbox ,
label : "Confirm dangerous actions" ,
2023-04-27 19:56:56 +02:00
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" ,
2022-11-30 09:17:08 +01:00
icon : "fa-check-double" ,
2023-04-28 12:20:44 +02:00
default : true ,
2022-11-30 09:17:08 +01:00
} ,
2022-11-30 07:48:34 +01:00
{
id : "listen_to_network" ,
type : ParameterType . checkbox ,
2023-05-21 17:59:06 +02:00
label : "Make Stable Diffusion available on your network" ,
note : "Other devices on your network can access this web page. Please restart the program after changing this." ,
2022-11-30 07:48:34 +01:00
icon : "fa-network-wired" ,
default : true ,
2023-04-28 12:20:44 +02:00
saveInAppConfig : true ,
2023-05-28 00:50:23 +02:00
table : networkParametersTable ,
2022-11-30 07:48:34 +01:00
} ,
{
id : "listen_port" ,
type : ParameterType . custom ,
label : "Network port" ,
2023-05-24 12:54:29 +02:00
note :
"Port that this server listens to. The '9000' part in 'http://localhost:9000'. Please restart the program after changing this." ,
2022-11-30 07:48:34 +01:00
icon : "fa-anchor" ,
render : ( parameter ) => {
return ` <input id=" ${ parameter . id } " name=" ${ parameter . id } " size="6" value="9000" onkeypress="preventNonNumericalInput(event)"> `
2023-03-30 02:56:24 +02:00
} ,
2023-04-28 12:20:44 +02:00
saveInAppConfig : true ,
2023-05-28 00:50:23 +02:00
table : networkParametersTable ,
2022-11-30 07:48:34 +01:00
} ,
{
id : "use_beta_channel" ,
type : ParameterType . checkbox ,
label : "Beta channel" ,
2023-04-27 19:56:56 +02:00
note :
"Get the latest features immediately (but could be less stable). Please restart the program after changing this." ,
2022-11-30 07:48:34 +01:00
icon : "fa-fire" ,
2023-04-28 12:20:44 +02:00
default : false ,
2022-11-30 07:48:34 +01:00
} ,
2023-03-21 13:29:20 +01:00
{
id : "test_diffusers" ,
type : ParameterType . checkbox ,
label : "Test Diffusers" ,
2023-04-27 19:56:56 +02:00
note :
"<b>Experimental! Can have bugs!</b> Use upcoming features (like LoRA) in our new engine. Please press Save, then restart the program after changing this." ,
2023-03-21 13:29:20 +01:00
icon : "fa-bolt" ,
default : false ,
2023-04-28 12:20:44 +02:00
saveInAppConfig : true ,
} ,
2023-05-28 00:50:23 +02:00
{
id : "cloudflare" ,
type : ParameterType . custom ,
label : "Cloudflare tunnel" ,
note : ` <span id="cloudflare-off">Create a VPN tunnel to share your Easy Diffusion instance with your friends. This will
generate a web server address on the public Internet for your Easy Diffusion instance . < / s p a n >
< div id = "cloudflare-on" class = "displayNone" > < div > This Easy Diffusion server is available on the Internet using the
2023-07-01 00:15:18 +02:00
address : < / d i v > < d i v > < i n p u t i d = " c l o u d f l a r e - a d d r e s s " v a l u e = " " r e a d o n l y > < b u t t o n i d = " c o p y - c l o u d f l a r e - a d d r e s s " > C o p y < / b u t t o n > < / d i v > < / d i v >
2023-05-28 00:50:23 +02:00
< b > Anyone knowing this address can access your server . < / b > T h e a d d r e s s o f y o u r s e r v e r w i l l c h a n g e e a c h t i m e
you share a session . < br >
Uses < a href = "https://try.cloudflare.com/" target = "_blank" > Cloudflare services < / a > . ` ,
icon : [ "fa-brands" , "fa-cloudflare" ] ,
render : ( ) => '<button id="toggle-cloudflare-tunnel" class="primaryButton">Start</button>' ,
table : networkParametersTable ,
}
2023-04-27 19:56:56 +02:00
]
2022-10-29 03:25:54 +02:00
2022-11-09 14:47:44 +01:00
function getParameterSettingsEntry ( id ) {
2023-04-27 19:56:56 +02:00
let parameter = PARAMETERS . filter ( ( p ) => p . id === id )
2022-11-30 07:48:34 +01:00
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
2023-02-22 15:02:00 +01:00
function sliderUpdate ( event ) {
2023-04-27 19:56:56 +02:00
if ( event . srcElement . id . endsWith ( "-input" ) ) {
let slider = document . getElementById ( event . srcElement . id . slice ( 0 , - 6 ) )
2023-02-22 15:26:45 +01:00
slider . value = event . srcElement . value
slider . dispatchEvent ( new Event ( "change" ) )
2023-02-22 15:02:00 +01:00
} else {
2023-04-27 19:56:56 +02:00
let field = document . getElementById ( event . srcElement . id + "-input" )
2023-02-22 15:26:45 +01:00
field . value = event . srcElement . value
field . dispatchEvent ( new Event ( "change" ) )
2023-02-22 15:02:00 +01:00
}
}
2023-03-30 02:56:24 +02:00
/ * *
2023-04-27 19:56:56 +02:00
* @ param { Parameter } parameter
2023-03-30 02:56:24 +02:00
* @ returns { string | HTMLElement }
* /
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 :
2023-04-27 19:56:56 +02:00
var is _checked = parameter . default ? " checked" : ""
2022-11-30 07:48:34 +01:00
return ` <input id=" ${ parameter . id } " name=" ${ parameter . id } " ${ is _checked } type="checkbox"> `
case ParameterType . select :
case ParameterType . select _multiple :
2023-04-27 19:56:56 +02:00
var options = ( parameter . options || [ ] )
. map ( ( option ) => ` <option value=" ${ option . value } "> ${ option . label } </option> ` )
. join ( "" )
var multiple = parameter . type == ParameterType . select _multiple ? "multiple" : ""
2022-11-30 07:48:34 +01:00
return ` <select id=" ${ parameter . id } " name=" ${ parameter . id } " ${ multiple } > ${ options } </select> `
2023-02-22 15:02:00 +01:00
case ParameterType . slider :
return ` <input id=" ${ parameter . id } " name=" ${ parameter . id } " class="editor-slider" type="range" value=" ${ parameter . default } " min=" ${ parameter . slider _min } " max=" ${ parameter . slider _max } " oninput="sliderUpdate(event)"> <input id=" ${ parameter . id } -input" name=" ${ parameter . id } -input" size="4" value=" ${ parameter . default } " pattern="^[0-9 \. ]+ $ " onkeypress="preventNonNumericalInput(event)" oninput="sliderUpdate(event)"> ${ parameter . slider _unit } `
2022-11-30 07:48:34 +01:00
case ParameterType . custom :
return parameter . render ( parameter )
default :
2023-04-27 19:56:56 +02:00
console . error ( ` Invalid type ${ parameter . type } for parameter ${ parameter . id } ` )
2022-11-30 07:48:34 +01:00
return "ERROR: Invalid Type"
}
2022-10-29 03:25:54 +02:00
}
2023-03-30 02:56:24 +02:00
/ * *
* fill in the system settings popup table
* @ param { Array < Parameter > | undefined } parameters
* * /
function initParameters ( parameters ) {
2023-04-27 19:56:56 +02:00
parameters . forEach ( ( parameter ) => {
2023-03-30 02:56:24 +02:00
const element = getParameterElement ( parameter )
2023-04-27 19:56:56 +02:00
const elementWrapper = createElement ( "div" )
2023-03-30 02:56:24 +02:00
if ( element instanceof Node ) {
elementWrapper . appendChild ( element )
} else {
elementWrapper . innerHTML = element
}
2023-04-27 19:56:56 +02:00
const note = typeof parameter . note === "function" ? parameter . note ( parameter ) : parameter . note
2023-03-30 02:56:24 +02:00
const noteElements = [ ]
if ( note ) {
2023-04-27 19:56:56 +02:00
const noteElement = createElement ( "small" )
2023-03-30 02:56:24 +02:00
if ( note instanceof Node ) {
noteElement . appendChild ( note )
} else {
2023-04-27 19:56:56 +02:00
noteElement . innerHTML = note || ""
2023-03-30 02:56:24 +02:00
}
noteElements . push ( noteElement )
}
2023-05-28 00:50:23 +02:00
if ( typeof ( parameter . icon ) == "string" ) {
parameter . icon = [ parameter . icon ]
}
const icon = parameter . icon ? [ createElement ( "i" , undefined , [ "fa" , ... parameter . icon ] ) ] : [ ]
2023-03-30 02:56:24 +02:00
2023-04-27 19:56:56 +02:00
const label = typeof parameter . label === "function" ? parameter . label ( parameter ) : parameter . label
const labelElement = createElement ( "label" , { for : parameter . id } )
2023-03-30 02:56:24 +02:00
if ( label instanceof Node ) {
labelElement . appendChild ( label )
} else {
labelElement . innerHTML = label
}
const newrow = createElement (
2023-04-27 19:56:56 +02:00
"div" ,
{ "data-setting-id" : parameter . id , "data-save-in-app-config" : parameter . saveInAppConfig } ,
2023-03-30 02:56:24 +02:00
undefined ,
[
2023-04-27 19:56:56 +02:00
createElement ( "div" , undefined , undefined , icon ) ,
createElement ( "div" , undefined , undefined , [ labelElement , ... noteElements ] ) ,
2023-04-28 12:20:44 +02:00
elementWrapper ,
2023-03-30 02:56:24 +02:00
]
)
2023-05-28 00:50:23 +02:00
let p = parametersTable
if ( parameter . table ) {
p = parameter . table
}
p . appendChild ( newrow )
2022-11-30 07:48:34 +01:00
parameter . settingsEntry = newrow
} )
2022-10-29 03:25:54 +02:00
}
2023-03-30 02:56:24 +02:00
initParameters ( PARAMETERS )
// listen to parameters from plugins
2023-04-27 19:56:56 +02:00
PARAMETERS . addEventListener ( "push" , ( ... items ) => {
2023-03-30 02:56:24 +02:00
initParameters ( items )
2023-04-27 19:56:56 +02:00
if ( items . find ( ( item ) => item . saveInAppConfig ) ) {
console . log (
"Reloading app config for new parameters" ,
items . map ( ( p ) => p . id )
)
2023-03-30 02:56:24 +02:00
getAppConfig ( )
}
} )
2022-11-15 07:52:55 +01:00
2023-04-27 19:56:56 +02:00
let vramUsageLevelField = document . querySelector ( "#vram_usage_level" )
let useCPUField = document . querySelector ( "#use_cpu" )
let autoPickGPUsField = document . querySelector ( "#auto_pick_gpus" )
let useGPUsField = document . querySelector ( "#use_gpus" )
let saveToDiskField = document . querySelector ( "#save_to_disk" )
let diskPathField = document . querySelector ( "#diskPath" )
let metadataOutputFormatField = document . querySelector ( "#metadata_output_format" )
2022-11-19 17:10:45 +01:00
let listenToNetworkField = document . querySelector ( "#listen_to_network" )
let listenPortField = document . querySelector ( "#listen_port" )
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" )
2023-03-21 13:29:20 +01:00
let testDiffusers = document . querySelector ( "#test_diffusers" )
2022-11-15 07:52:55 +01:00
2023-04-27 19:56:56 +02:00
let saveSettingsBtn = document . querySelector ( "#save-system-settings-btn" )
2022-11-23 11:25:36 +01:00
2022-11-15 07:52:55 +01:00
async function changeAppConfig ( configDelta ) {
try {
2023-04-27 19:56:56 +02:00
let res = await fetch ( "/app_config" , {
method : "POST" ,
2022-11-15 07:52:55 +01:00
headers : {
2023-04-28 12:20:44 +02:00
"Content-Type" : "application/json" ,
2022-11-15 07:52:55 +01:00
} ,
2023-04-28 12:20:44 +02:00
body : JSON . stringify ( configDelta ) ,
2022-11-15 07:52:55 +01:00
} )
res = await res . json ( )
2023-04-27 19:56:56 +02:00
console . log ( "set config status response" , res )
2022-11-15 07:52:55 +01:00
} catch ( e ) {
2023-04-27 19:56:56 +02:00
console . log ( "set config status error" , e )
2022-11-15 07:52:55 +01:00
}
}
async function getAppConfig ( ) {
try {
2023-04-27 19:56:56 +02:00
let res = await fetch ( "/get/app_config" )
2022-11-15 07:52:55 +01:00
const config = await res . json ( )
2023-04-08 16:43:44 +02:00
applySettingsFromConfig ( config )
// custom overrides
2023-04-27 19:56:56 +02:00
if ( config . update _branch === "beta" ) {
2022-11-15 07:52:55 +01:00
useBetaChannelField . checked = true
2022-11-19 17:10:45 +01:00
document . querySelector ( "#updateBranchLabel" ) . innerText = "(beta)"
2023-04-01 13:12:06 +02:00
} else {
getParameterSettingsEntry ( "test_diffusers" ) . style . display = "none"
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-30 07:48:34 +01:00
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
}
2023-05-18 03:13:06 +02:00
const testDiffusersEnabled = config . test _diffusers && config . update _branch !== "main"
testDiffusers . checked = testDiffusersEnabled
if ( ! testDiffusersEnabled ) {
2023-04-27 19:56:56 +02:00
document . querySelector ( "#lora_model_container" ) . style . display = "none"
2023-05-25 12:11:41 +02:00
document . querySelector ( "#tiling_container" ) . style . display = "none"
2023-05-18 03:13:06 +02:00
2023-05-24 12:54:29 +02:00
document . querySelectorAll ( "#sampler_name option.diffusers-only" ) . forEach ( ( option ) => {
2023-05-18 03:13:06 +02:00
option . style . display = "none"
} )
2023-04-04 12:40:16 +02:00
} else {
2023-05-18 03:13:06 +02:00
document . querySelector ( "#lora_model_container" ) . style . display = ""
2023-05-25 12:11:41 +02:00
document . querySelector ( "#tiling_container" ) . style . display = ""
2023-05-18 03:13:06 +02:00
2023-05-24 12:54:29 +02:00
document . querySelectorAll ( "#sampler_name option.k_diffusion-only" ) . forEach ( ( option ) => {
2023-05-18 03:13:06 +02:00
option . disabled = true
} )
2023-05-18 13:55:45 +02:00
document . querySelector ( "#clip_skip_config" ) . classList . remove ( "displayNone" )
2023-06-30 20:17:46 +02:00
document . querySelector ( "#embeddings-container" ) . classList . remove ( "displayNone" )
2023-03-21 13:29:20 +01:00
}
2022-11-15 07:52:55 +01:00
2023-04-27 19:56:56 +02:00
console . log ( "get config status response" , config )
2023-03-30 02:56:24 +02:00
return config
2022-11-15 07:52:55 +01:00
} catch ( e ) {
2023-04-27 19:56:56 +02:00
console . log ( "get config status error" , e )
2023-03-30 02:56:24 +02:00
return { }
2022-11-15 07:52:55 +01:00
}
}
2023-04-08 16:43:44 +02:00
function applySettingsFromConfig ( config ) {
2023-04-27 19:56:56 +02:00
Array . from ( parametersTable . children ) . forEach ( ( parameterRow ) => {
if ( parameterRow . dataset . settingId in config && parameterRow . dataset . saveInAppConfig === "true" ) {
2023-04-08 16:43:44 +02:00
const configValue = config [ parameterRow . dataset . settingId ]
2023-04-27 19:56:56 +02:00
const parameterElement =
document . getElementById ( parameterRow . dataset . settingId ) ||
parameterRow . querySelector ( "input" ) ||
parameterRow . querySelector ( "select" )
2023-04-08 16:43:44 +02:00
switch ( parameterElement ? . tagName ) {
2023-04-27 19:56:56 +02:00
case "INPUT" :
if ( parameterElement . type === "checkbox" ) {
2023-04-08 16:43:44 +02:00
parameterElement . checked = configValue
} else {
parameterElement . value = configValue
}
2023-04-27 19:56:56 +02:00
parameterElement . dispatchEvent ( new Event ( "change" ) )
2023-04-08 16:43:44 +02:00
break
2023-04-27 19:56:56 +02:00
case "SELECT" :
2023-04-08 16:43:44 +02:00
if ( Array . isArray ( configValue ) ) {
2023-04-27 19:56:56 +02:00
Array . from ( parameterElement . options ) . forEach ( ( option ) => {
2023-04-08 16:43:44 +02:00
if ( configValue . includes ( option . value || option . text ) ) {
option . selected = true
}
} )
} else {
parameterElement . value = configValue
}
2023-04-27 19:56:56 +02:00
parameterElement . dispatchEvent ( new Event ( "change" ) )
2023-04-08 16:43:44 +02:00
break
}
}
} )
}
2023-04-27 19:56:56 +02:00
saveToDiskField . addEventListener ( "change" , function ( e ) {
2022-11-15 07:52:55 +01:00
diskPathField . disabled = ! this . checked
2023-01-24 10:47:48 +01:00
metadataOutputFormatField . disabled = ! this . checked
2022-11-15 07:52:55 +01:00
} )
function getCurrentRenderDeviceSelection ( ) {
2023-04-27 19:56:56 +02:00
let selectedGPUs = $ ( "#use_gpus" ) . val ( )
2022-11-15 07:52:55 +01:00
if ( useCPUField . checked && ! autoPickGPUsField . checked ) {
2023-04-27 19:56:56 +02:00
return "cpu"
2022-11-15 07:52:55 +01:00
}
if ( autoPickGPUsField . checked || selectedGPUs . length == 0 ) {
2023-04-27 19:56:56 +02:00
return "auto"
2022-11-15 07:52:55 +01:00
}
2023-04-27 19:56:56 +02:00
return selectedGPUs . join ( "," )
2022-11-15 07:52:55 +01:00
}
2023-04-27 19:56:56 +02:00
useCPUField . addEventListener ( "click" , function ( ) {
let gpuSettingEntry = getParameterSettingsEntry ( "use_gpus" )
let autoPickGPUSettingEntry = getParameterSettingsEntry ( "auto_pick_gpus" )
2022-11-15 07:52:55 +01:00
if ( this . checked ) {
2023-04-27 19:56:56 +02:00
gpuSettingEntry . style . display = "none"
autoPickGPUSettingEntry . style . display = "none"
autoPickGPUsField . setAttribute ( "data-old-value" , autoPickGPUsField . checked )
2022-11-15 07:52:55 +01:00
autoPickGPUsField . checked = false
} else if ( useGPUsField . options . length >= MIN _GPUS _TO _SHOW _SELECTION ) {
2023-04-27 19:56:56 +02:00
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
2022-11-15 07:52:55 +01:00
autoPickGPUsField . checked = true
} else {
2023-04-27 19:56:56 +02:00
autoPickGPUsField . checked = oldVal === "true"
2022-11-15 07:52:55 +01:00
}
2023-04-27 19:56:56 +02:00
gpuSettingEntry . style . display = autoPickGPUsField . checked ? "none" : ""
2022-11-15 07:52:55 +01:00
}
} )
2023-04-27 19:56:56 +02:00
useGPUsField . addEventListener ( "click" , function ( ) {
let selectedGPUs = $ ( "#use_gpus" ) . val ( )
autoPickGPUsField . checked = selectedGPUs . length === 0
2022-11-15 07:52:55 +01:00
} )
2023-04-27 19:56:56 +02:00
autoPickGPUsField . addEventListener ( "click" , function ( ) {
2022-11-15 07:52:55 +01:00
if ( this . checked ) {
2023-04-27 19:56:56 +02:00
$ ( "#use_gpus" ) . val ( [ ] )
2022-11-15 07:52:55 +01:00
}
2023-04-27 19:56:56 +02:00
let gpuSettingEntry = getParameterSettingsEntry ( "use_gpus" )
gpuSettingEntry . style . display = this . checked ? "none" : ""
2022-11-15 07:52:55 +01:00
} )
2023-04-27 19:56:56 +02:00
async function setDiskPath ( defaultDiskPath , force = false ) {
2022-12-08 17:09:09 +01:00
var diskPath = getSetting ( "diskPath" )
2023-04-27 19:56:56 +02:00
if ( force || diskPath == "" || diskPath == undefined || diskPath == "undefined" ) {
2022-12-08 17:09:09 +01:00
setSetting ( "diskPath" , defaultDiskPath )
2022-11-15 07:52:55 +01:00
}
}
2022-11-30 10:04:24 +01:00
function setDeviceInfo ( devices ) {
let cpu = devices . all . cpu . name
2023-04-27 19:56:56 +02:00
let allGPUs = Object . keys ( devices . all ) . filter ( ( d ) => d != "cpu" )
2022-11-30 10:04:24 +01:00
let activeGPUs = Object . keys ( devices . active )
function ID _TO _TEXT ( d ) {
let info = devices . all [ d ]
if ( "mem_free" in info && "mem_total" in info ) {
2023-04-27 19:56:56 +02:00
return ` ${ info . name } <small>( ${ d } ) ( ${ info . mem _free . toFixed ( 1 ) } Gb free / ${ info . mem _total . toFixed (
1
) } Gb total ) < / s m a l l > `
2022-11-30 10:04:24 +01:00
} else {
return ` ${ info . name } <small>( ${ d } ) (no memory info)</small> `
}
}
allGPUs = allGPUs . map ( ID _TO _TEXT )
activeGPUs = activeGPUs . map ( ID _TO _TEXT )
2023-04-27 19:56:56 +02:00
let systemInfoEl = document . querySelector ( "#system-info" )
systemInfoEl . querySelector ( "#system-info-cpu" ) . innerText = cpu
systemInfoEl . querySelector ( "#system-info-gpus-all" ) . innerHTML = allGPUs . join ( "</br>" )
systemInfoEl . querySelector ( "#system-info-rendering-devices" ) . innerHTML = activeGPUs . join ( "</br>" )
2022-11-30 10:04:24 +01:00
}
function setHostInfo ( hosts ) {
let port = listenPortField . value
2023-04-27 19:56:56 +02:00
hosts = hosts . map ( ( addr ) => ` http:// ${ addr } : ${ port } / ` ) . map ( ( url ) => ` <div><a href=" ${ url } "> ${ url } </a></div> ` )
document . querySelector ( "#system-info-server-hosts" ) . innerHTML = hosts . join ( "" )
2022-11-30 10:04:24 +01:00
}
async function getSystemInfo ( ) {
2022-11-15 07:52:55 +01:00
try {
2022-12-06 12:34:08 +01:00
const res = await SD . getSystemInfo ( )
2023-04-27 19:56:56 +02:00
let devices = res [ "devices" ]
2022-11-15 07:52:55 +01:00
2023-04-27 19:56:56 +02:00
let allDeviceIds = Object . keys ( devices [ "all" ] ) . filter ( ( d ) => d !== "cpu" )
let activeDeviceIds = Object . keys ( devices [ "active" ] ) . filter ( ( d ) => d !== "cpu" )
2022-11-15 07:52:55 +01:00
2022-12-06 12:34:08 +01:00
if ( activeDeviceIds . length === 0 ) {
useCPUField . checked = true
}
2022-11-15 07:52:55 +01:00
2022-12-06 12:34:08 +01:00
if ( allDeviceIds . length < MIN _GPUS _TO _SHOW _SELECTION || useCPUField . checked ) {
2023-04-27 19:56:56 +02:00
let gpuSettingEntry = getParameterSettingsEntry ( "use_gpus" )
gpuSettingEntry . style . display = "none"
let autoPickGPUSettingEntry = getParameterSettingsEntry ( "auto_pick_gpus" )
autoPickGPUSettingEntry . style . display = "none"
2022-12-06 12:34:08 +01:00
}
2022-11-15 07:52:55 +01:00
2022-12-06 12:34:08 +01:00
if ( allDeviceIds . length === 0 ) {
useCPUField . checked = true
useCPUField . disabled = true // no compatible GPUs, so make the CPU mandatory
2023-05-24 12:54:29 +02:00
getParameterSettingsEntry ( "use_cpu" ) . addEventListener ( "click" , function ( ) {
alert (
"Sorry, we could not find a compatible graphics card! Easy Diffusion supports graphics cards with minimum 2 GB of RAM. " +
"Only NVIDIA cards are supported on Windows. NVIDIA and AMD cards are supported on Linux.<br/><br/>" +
"If you have a compatible graphics card, please try updating to the latest drivers.<br/><br/>" +
"Only the CPU can be used for generating images, without a compatible graphics card." ,
"No compatible graphics card found!"
)
} )
2022-12-06 12:34:08 +01:00
}
2022-11-15 07:52:55 +01:00
2023-04-27 19:56:56 +02:00
autoPickGPUsField . checked = devices [ "config" ] === "auto"
2022-11-15 07:52:55 +01:00
2023-04-27 19:56:56 +02:00
useGPUsField . innerHTML = ""
allDeviceIds . forEach ( ( device ) => {
let deviceName = devices [ "all" ] [ device ] [ "name" ]
2022-12-06 12:34:08 +01:00
let deviceOption = ` <option value=" ${ device } "> ${ deviceName } ( ${ device } )</option> `
2023-04-27 19:56:56 +02:00
useGPUsField . insertAdjacentHTML ( "beforeend" , deviceOption )
2022-12-06 12:34:08 +01:00
} )
2022-11-30 10:04:24 +01:00
2022-12-06 12:34:08 +01:00
if ( autoPickGPUsField . checked ) {
2023-04-27 19:56:56 +02:00
let gpuSettingEntry = getParameterSettingsEntry ( "use_gpus" )
gpuSettingEntry . style . display = "none"
2022-12-06 12:34:08 +01:00
} else {
2023-04-27 19:56:56 +02:00
$ ( "#use_gpus" ) . val ( activeDeviceIds )
2022-11-15 07:52:55 +01:00
}
2022-12-06 12:34:08 +01:00
2023-05-24 12:54:29 +02:00
document . dispatchEvent ( new CustomEvent ( "system_info_update" , { detail : devices } ) )
2023-04-27 19:56:56 +02:00
setHostInfo ( res [ "hosts" ] )
2022-12-30 21:05:25 +01:00
let force = false
2023-04-27 19:56:56 +02:00
if ( res [ "enforce_output_dir" ] !== undefined ) {
force = res [ "enforce_output_dir" ]
2023-02-21 04:09:16 +01:00
if ( force == true ) {
2023-04-27 19:56:56 +02:00
saveToDiskField . checked = true
metadataOutputFormatField . disabled = false
2023-02-21 04:09:16 +01:00
}
2022-12-30 21:05:25 +01:00
saveToDiskField . disabled = force
diskPathField . disabled = force
}
2023-04-27 19:56:56 +02:00
setDiskPath ( res [ "default_output_dir" ] , force )
2022-11-15 07:52:55 +01:00
} catch ( e ) {
2023-04-27 19:56:56 +02:00
console . log ( "error fetching devices" , e )
2022-11-15 07:52:55 +01:00
}
}
2023-04-27 19:56:56 +02:00
saveSettingsBtn . addEventListener ( "click" , function ( ) {
if ( listenPortField . value == "" ) {
alert ( "The network port field must not be empty." )
2022-12-06 12:34:08 +01:00
return
}
if ( listenPortField . value < 1 || listenPortField . value > 65535 ) {
2023-04-27 19:56:56 +02:00
alert ( "The network port must be a number from 1 to 65535" )
2022-12-06 12:34:08 +01:00
return
2022-11-30 07:48:34 +01:00
}
2023-04-27 19:56:56 +02:00
const updateBranch = useBetaChannelField . checked ? "beta" : "main"
2023-03-30 02:56:24 +02:00
const updateAppConfigRequest = {
2023-04-27 19:56:56 +02:00
render _devices : getCurrentRenderDeviceSelection ( ) ,
2023-04-28 12:20:44 +02:00
update _branch : updateBranch ,
2023-03-30 02:56:24 +02:00
}
2023-06-19 21:50:56 +02:00
document . querySelectorAll ( '#system-settings [data-setting-id]' ) . forEach ( ( parameterRow ) => {
2023-04-27 19:56:56 +02:00
if ( parameterRow . dataset . saveInAppConfig === "true" ) {
const parameterElement =
document . getElementById ( parameterRow . dataset . settingId ) ||
parameterRow . querySelector ( "input" ) ||
parameterRow . querySelector ( "select" )
2023-03-30 02:56:24 +02:00
switch ( parameterElement ? . tagName ) {
2023-04-27 19:56:56 +02:00
case "INPUT" :
if ( parameterElement . type === "checkbox" ) {
2023-03-30 02:56:24 +02:00
updateAppConfigRequest [ parameterRow . dataset . settingId ] = parameterElement . checked
} else {
updateAppConfigRequest [ parameterRow . dataset . settingId ] = parameterElement . value
}
break
2023-04-27 19:56:56 +02:00
case "SELECT" :
2023-03-30 02:56:24 +02:00
if ( parameterElement . multiple ) {
updateAppConfigRequest [ parameterRow . dataset . settingId ] = Array . from ( parameterElement . options )
2023-04-27 19:56:56 +02:00
. filter ( ( option ) => option . selected )
. map ( ( option ) => option . value || option . text )
2023-03-30 02:56:24 +02:00
} else {
updateAppConfigRequest [ parameterRow . dataset . settingId ] = parameterElement . value
}
break
default :
2023-04-27 19:56:56 +02:00
console . error (
` Setting parameter ${ parameterRow . dataset . settingId } couldn't be saved to app.config - element # ${ parameter . id } is a < ${ parameterElement ? . tagName } /> instead of a <input /> or a <select />! `
)
2023-03-30 02:56:24 +02:00
break
}
}
2022-12-06 12:34:08 +01:00
} )
2023-03-30 02:56:24 +02:00
const savePromise = changeAppConfig ( updateAppConfigRequest )
2023-05-28 00:50:23 +02:00
showToast ( "Settings saved" )
2023-04-27 19:56:56 +02:00
saveSettingsBtn . classList . add ( "active" )
Promise . all ( [ savePromise , asyncDelay ( 300 ) ] ) . then ( ( ) => saveSettingsBtn . classList . remove ( "active" ) )
2022-11-15 07:52:55 +01:00
} )
2023-05-21 17:42:47 +02:00
2023-05-28 00:50:23 +02:00
listenToNetworkField . addEventListener ( "change" , debounce ( ( ) => {
saveSettingsBtn . click ( )
} , 1000 ) )
listenPortField . addEventListener ( "change" , debounce ( ( ) => {
saveSettingsBtn . click ( )
} , 1000 ) )
2023-05-28 01:18:39 +02:00
let copyCloudflareAddressBtn = document . querySelector ( "#copy-cloudflare-address" )
let cloudflareAddressField = document . getElementById ( "cloudflare-address" )
2023-07-01 00:15:18 +02:00
navigator . permissions . query ( { name : "clipboard-write" } ) . then ( function ( result ) {
if ( result . state === "granted" ) {
// you can read from the clipboard
copyCloudflareAddressBtn . addEventListener ( "click" , ( e ) => {
navigator . clipboard . writeText ( cloudflareAddressField . innerHTML )
showToast ( "Copied server address to clipboard" )
} )
} else {
copyCloudflareAddressBtn . classList . add ( "displayNone" )
}
} ) ;
2023-05-28 01:18:39 +02:00
2023-05-21 17:42:47 +02:00
document . addEventListener ( "system_info_update" , ( e ) => setDeviceInfo ( e . detail ) )