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" )
2023-07-29 08:11:44 +02:00
let installExtrasTable = document . querySelector ( "#system-settings-install-extras-table" )
2023-05-28 00:50:23 +02:00
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-09-01 07:10:18 +02:00
{
id : "models_dir" ,
type : ParameterType . custom ,
icon : "fa-folder-tree" ,
label : "Models Folder" ,
2024-10-01 10:25:35 +02:00
note : "Path to the 'models' folder. Please save and restart Easy Diffusion after changing this." ,
2023-09-01 07:10:18 +02:00
saveInAppConfig : true ,
render : ( parameter ) => {
return ` <input id=" ${ parameter . id } " name=" ${ parameter . id } " size="30"> `
} ,
} ,
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
} ,
2023-08-03 15:08:25 +02:00
{
id : "extract_lora_from_prompt" ,
type : ParameterType . checkbox ,
label : "Extract LoRA tags from the prompt" ,
note :
"Automatically extract lora tags like <lora:name:0.4> from the prompt, and apply the correct LoRA (if present)" ,
icon : "fa-code" ,
default : true ,
} ,
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
} ,
2023-08-17 08:03:05 +02:00
{
id : "profileName" ,
type : ParameterType . custom ,
label : "Profile Name" ,
2023-08-23 09:32:20 +02:00
note :
"Name of the profile for model manager settings, e.g. thumbnails for embeddings. Use this to have different settings for different users." ,
2023-08-17 08:03:05 +02:00
render : ( parameter ) => {
return ` <input id=" ${ parameter . id } " name=" ${ parameter . id } " value="default" size="12"> `
} ,
icon : "fa-user-gear" ,
} ,
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
{
2024-10-01 07:24:58 +02:00
id : "backend" ,
type : ParameterType . select ,
label : "Engine to use" ,
2023-04-27 19:56:56 +02:00
note :
2024-10-01 07:24:58 +02:00
"Use our new v3.5 engine (Forge), with additional features like Flux, SD3, Lycoris and lots more! Please press Save, then restart the program after changing this." ,
icon : "fa-robot" ,
2023-04-28 12:20:44 +02:00
saveInAppConfig : true ,
2024-10-01 07:24:58 +02:00
default : "ed_diffusers" ,
options : [
{ value : "webui" , label : "v3.5 (latest)" } ,
{ value : "ed_diffusers" , label : "v3.0" } ,
{ value : "ed_classic" , label : "v2.0" } ,
] ,
2023-04-28 12:20:44 +02:00
} ,
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-07-24 13:08:45 +02:00
} ,
2023-07-29 08:11:44 +02:00
{
id : "nvidia_tensorrt" ,
type : ParameterType . custom ,
label : "NVIDIA TensorRT" ,
note : ` Faster image generation by converting your Stable Diffusion models to the NVIDIA TensorRT format. You can choose the
2023-07-29 17:39:27 +02:00
models to convert . Download size : approximately 2 GB . < br / > < br / >
2023-08-01 20:23:01 +02:00
< b > Early access version : < / b > s u p p o r t f o r L o R A i s s t i l l u n d e r d e v e l o p m e n t .
< div id = "trt-build-config" class = "displayNone" >
< h3 > Build Config : < / h 3 >
2023-08-02 13:15:12 +02:00
Batch size range :
< label > Min : < /label> <input id="trt-build-min-batch" type="number" min="1" value="1" style="width: 40pt" / >
< label > Max : < /label> <input id="trt-build-max-batch" type="number" min="1" value="1" style="width: 40pt" / > < br / > < br / >
2023-08-01 20:23:01 +02:00
< b > Build for resolutions < /b>:<br/ >
< input id = "trt-build-res-512" type = "checkbox" value = "1" / > 512 x512 to 768 x768 < br / >
< input id = "trt-build-res-768" type = "checkbox" value = "1" checked / > 768 x768 to 1024 x1024 < br / >
< input id = "trt-build-res-1024" type = "checkbox" value = "1" / > 1024 x1024 to 1280 x1280 < br / >
< input id = "trt-build-res-1280" type = "checkbox" value = "1" / > 1280 x1280 to 1536 x1536 < br / >
< input id = "trt-build-res-1536" type = "checkbox" value = "1" / > 1536 x1536 to 1792 x1792 < br / >
< / d i v > ` ,
2023-07-29 08:11:44 +02:00
icon : "fa-angles-up" ,
2023-07-29 17:39:27 +02:00
render : ( ) => '<button id="toggle-tensorrt-install" class="primaryButton">Install</button>' ,
2023-07-29 08:11:44 +02:00
table : installExtrasTable ,
} ,
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-07-24 13:08:45 +02:00
if ( typeof parameter . icon == "string" ) {
2023-05-28 00:50:23 +02:00
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
2023-07-24 13:08:45 +02:00
}
2023-05-28 00:50:23 +02:00
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-08-31 15:50:26 +02:00
let testDiffusers = document . querySelector ( "#use_v3_engine" )
2024-10-01 07:24:58 +02:00
let backendEngine = document . querySelector ( "#backend" )
2023-08-17 08:03:05 +02:00
let profileNameField = document . querySelector ( "#profileName" )
2023-09-01 07:10:18 +02:00
let modelsDirField = document . querySelector ( "#models_dir" )
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
}
}
2024-10-01 07:24:58 +02:00
function getDefaultDisplay ( element ) {
const tag = element . tagName . toLowerCase ( ) ;
const defaultDisplays = {
div : 'block' ,
span : 'inline' ,
p : 'block' ,
tr : 'table-row' ,
table : 'table' ,
li : 'list-item' ,
ul : 'block' ,
ol : 'block' ,
button : 'inline' ,
// Add more if needed
} ;
return defaultDisplays [ tag ] || 'block' ; // Default to 'block' if not listed
}
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)"
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-09-01 07:10:18 +02:00
modelsDirField . value = config . models _dir
2023-05-18 03:13:06 +02:00
2023-08-23 09:32:20 +02:00
let testDiffusersEnabled = true
2024-10-01 07:24:58 +02:00
if ( config . backend === "ed_classic" ) {
2023-08-03 16:31:27 +02:00
testDiffusersEnabled = false
}
2023-05-18 03:13:06 +02:00
testDiffusers . checked = testDiffusersEnabled
2024-10-01 07:24:58 +02:00
backendEngine . value = config . backend
2023-08-31 18:54:27 +02:00
document . querySelector ( "#test_diffusers" ) . checked = testDiffusers . checked // don't break plugins
2024-10-01 07:24:58 +02:00
document . querySelector ( "#use_v3_engine" ) . checked = testDiffusers . checked // don't break plugins
2023-05-18 03:13:06 +02:00
2023-07-09 22:54:25 +02:00
if ( config . config _on _startup ) {
2024-10-01 07:24:58 +02:00
if ( config . config _on _startup ? . backend !== "ed_classic" ) {
2023-07-24 13:08:45 +02:00
document . body . classList . add ( "diffusers-enabled-on-startup" )
document . body . classList . remove ( "diffusers-disabled-on-startup" )
2023-07-09 22:54:25 +02:00
} else {
2023-07-24 13:08:45 +02:00
document . body . classList . add ( "diffusers-disabled-on-startup" )
document . body . classList . remove ( "diffusers-enabled-on-startup" )
2023-07-09 22:54:25 +02:00
}
}
2024-10-01 07:24:58 +02:00
if ( config . backend === "ed_classic" ) {
2023-08-03 14:10:26 +02:00
IMAGE _STEP _SIZE = 64
2023-04-04 12:40:16 +02:00
} else {
2023-08-03 14:10:26 +02:00
IMAGE _STEP _SIZE = 8
2023-03-21 13:29:20 +01:00
}
2022-11-15 07:52:55 +01:00
2024-10-01 07:24:58 +02:00
customWidthField . step = IMAGE _STEP _SIZE
customHeightField . step = IMAGE _STEP _SIZE
const currentBackendKey = "backend_" + config . backend
document . querySelectorAll ( '.gated-feature' ) . forEach ( ( element ) => {
const featureKeys = element . getAttribute ( 'data-feature-keys' ) . split ( ' ' )
if ( featureKeys . includes ( currentBackendKey ) ) {
element . style . display = getDefaultDisplay ( element )
} else {
element . style . display = 'none'
}
} ) ;
2023-09-29 16:53:24 +02:00
if ( config . force _save _metadata ) {
metadataOutputFormatField . value = config . force _save _metadata
}
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>" )
2023-07-29 08:11:44 +02:00
// tensorRT
2023-07-29 17:39:27 +02:00
if ( devices . active && testDiffusers . checked && devices . enable _trt === true ) {
2023-07-29 08:11:44 +02:00
let nvidiaGPUs = Object . keys ( devices . active ) . filter ( ( d ) => {
let gpuName = devices . active [ d ] . name
gpuName = gpuName . toLowerCase ( )
return (
gpuName . includes ( "nvidia" ) ||
gpuName . includes ( "geforce" ) ||
gpuName . includes ( "quadro" ) ||
gpuName . includes ( "tesla" )
)
} )
if ( nvidiaGPUs . length > 0 ) {
document . querySelector ( "#install-extras-container" ) . classList . remove ( "displayNone" )
}
}
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
2023-09-30 16:41:28 +02:00
metadataOutputFormatField . disabled = res [ "enforce_output_metadata" ]
diskPathField . disabled = true
2023-02-21 04:09:16 +01:00
}
2022-12-30 21:05:25 +01:00
saveToDiskField . disabled = force
2023-09-30 16:41:28 +02:00
} else {
diskPathField . disabled = ! saveToDiskField . checked
metadataOutputFormatField . disabled = ! saveToDiskField . checked
2022-12-30 21:05:25 +01:00
}
2023-04-27 19:56:56 +02:00
setDiskPath ( res [ "default_output_dir" ] , force )
2024-10-01 07:24:58 +02:00
// backend info
if ( res [ "backend_url" ] ) {
document . querySelector ( "#backend-url" ) . setAttribute ( "href" , res [ "backend_url" ] )
}
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-07-24 13:08:45 +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-07-24 13:08:45 +02:00
listenToNetworkField . addEventListener (
"change" ,
debounce ( ( ) => {
saveSettingsBtn . click ( )
} , 1000 )
)
2023-05-28 00:50:23 +02:00
2023-07-24 13:08:45 +02:00
listenPortField . addEventListener (
"change" ,
debounce ( ( ) => {
saveSettingsBtn . click ( )
} , 1000 )
)
2023-05-28 00:50:23 +02:00
2023-05-28 01:18:39 +02:00
let copyCloudflareAddressBtn = document . querySelector ( "#copy-cloudflare-address" )
let cloudflareAddressField = document . getElementById ( "cloudflare-address" )
2023-07-24 13:08:45 +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 ) )