2023-02-12 10:18:09 +01:00
"use strict"
let modelsCache
let modelsOptions
/ *
* * * SEARCHABLE MODELS * * *
Creates searchable dropdowns for SD , VAE , or HN models .
Also adds a reload models button ( placed next to SD models , reloads everything including VAE and HN models ) .
More reload buttons may be added at strategic UI locations as needed .
Merely calling getModels ( ) makes all the magic happen behind the scene to refresh the dropdowns .
HOW TO CREATE A MODEL DROPDOWN :
1 ) Create an input element . Make sure to add a data - path property , as this is how model dropdowns are identified in auto - save . js .
2023-02-13 07:31:40 +01:00
< input id = "stable_diffusion_model" type = "text" spellcheck = "false" autocomplete = "off" class = "model-filter" data - path = "" / >
2023-02-12 10:18:09 +01:00
2 ) Just declare one of these for your own dropdown ( remember to change the element id , e . g . # stable _diffusion _models to your own input ' s id ) .
let stableDiffusionModelField = new ModelDropdown ( document . querySelector ( '#stable_diffusion_model' ) , 'stable-diffusion' )
let vaeModelField = new ModelDropdown ( document . querySelector ( '#vae_model' ) , 'vae' , 'None' )
let hypernetworkModelField = new ModelDropdown ( document . querySelector ( '#hypernetwork_model' ) , 'hypernetwork' , 'None' )
3 ) Model dropdowns will be refreshed automatically when the reload models button is invoked .
* /
class ModelDropdown
{
modelFilter //= document.querySelector("#model-filter")
modelFilterArrow //= document.querySelector("#model-filter-arrow")
modelList //= document.querySelector("#model-list")
modelResult //= document.querySelector("#model-result")
modelNoResult //= document.querySelector("#model-no-result")
currentSelection //= { elem: undefined, value: '', path: ''}
highlightedModelEntry //= undefined
activeModel //= undefined
inputModels //= undefined
modelKey //= undefined
flatModelList //= []
noneEntry //= ''
2023-02-13 07:31:40 +01:00
modelFilterInitialized //= undefined
2023-02-12 10:18:09 +01:00
/* MIMIC A REGULAR INPUT FIELD */
get parentElement ( ) {
return this . modelFilter . parentElement
}
get parentNode ( ) {
return this . modelFilter . parentNode
}
get value ( ) {
return this . modelFilter . dataset . path
}
set value ( path ) {
this . modelFilter . dataset . path = path
this . selectEntry ( path )
}
2023-02-16 14:59:08 +01:00
get disabled ( ) {
return this . modelFilter . disabled
}
set disabled ( state ) {
this . modelFilter . disabled = state
if ( this . modelFilterArrow ) {
this . modelFilterArrow . style . color = state ? 'dimgray' : ''
}
2023-02-23 00:18:06 +01:00
}
get modelElements ( ) {
return this . modelList . querySelectorAll ( '.model-file' )
}
2023-02-12 10:18:09 +01:00
addEventListener ( type , listener , options ) {
return this . modelFilter . addEventListener ( type , listener , options )
}
dispatchEvent ( event ) {
return this . modelFilter . dispatchEvent ( event )
}
appendChild ( option ) {
// do nothing
}
// remember 'this' - http://blog.niftysnippets.org/2008/04/you-must-remember-this.html
bind ( f , obj ) {
return function ( ) {
return f . apply ( obj , arguments )
}
}
/* SEARCHABLE INPUT */
constructor ( input , modelKey , noneEntry = '' ) {
this . modelFilter = input
this . noneEntry = noneEntry
this . modelKey = modelKey
if ( modelsOptions !== undefined ) { // reuse models from cache (only useful for plugins, which are loaded after models)
this . inputModels = modelsOptions [ this . modelKey ]
this . populateModels ( )
}
document . addEventListener ( "refreshModels" , this . bind ( function ( e ) {
// reload the models
this . inputModels = modelsOptions [ this . modelKey ]
this . populateModels ( )
} , this ) )
}
saveCurrentSelection ( elem , value , path ) {
this . currentSelection . elem = elem
this . currentSelection . value = value
this . currentSelection . path = path
this . modelFilter . dataset . path = path
this . modelFilter . value = value
this . modelFilter . dispatchEvent ( new Event ( 'change' ) )
}
processClick ( e ) {
e . preventDefault ( )
2023-02-27 02:26:22 +01:00
if ( e . srcElement . classList . contains ( 'model-file' ) || e . srcElement . classList . contains ( 'fa-file' ) ) {
const elem = e . srcElement . classList . contains ( 'model-file' ) ? e . srcElement : e . srcElement . parentElement
this . saveCurrentSelection ( elem , elem . innerText , elem . dataset . path )
2023-02-12 10:18:09 +01:00
this . hideModelList ( )
this . modelFilter . focus ( )
this . modelFilter . select ( )
}
}
2023-02-13 07:31:40 +01:00
getPreviousVisibleSibling ( elem ) {
2023-02-23 00:18:06 +01:00
const modelElements = Array . from ( this . modelElements )
const index = modelElements . indexOf ( elem )
if ( index <= 0 ) {
return undefined
2023-02-13 07:31:40 +01:00
}
2023-02-23 00:18:06 +01:00
return modelElements . slice ( 0 , index ) . reverse ( ) . find ( e => e . style . display === 'list-item' )
2023-02-13 07:31:40 +01:00
}
getLastVisibleChild ( elem ) {
let lastElementChild = elem . lastElementChild
if ( lastElementChild . style . display == 'list-item' ) return lastElementChild
return this . getPreviousVisibleSibling ( lastElementChild )
}
getNextVisibleSibling ( elem ) {
2023-02-23 00:18:06 +01:00
const modelElements = Array . from ( this . modelElements )
const index = modelElements . indexOf ( elem )
return modelElements . slice ( index + 1 ) . find ( e => e . style . display === 'list-item' )
2023-02-13 07:31:40 +01:00
}
getFirstVisibleChild ( elem ) {
let firstElementChild = elem . firstElementChild
if ( firstElementChild . style . display == 'list-item' ) return firstElementChild
return this . getNextVisibleSibling ( firstElementChild )
2023-02-12 10:18:09 +01:00
}
selectModelEntry ( elem ) {
if ( elem ) {
if ( this . highlightedModelEntry !== undefined ) {
this . highlightedModelEntry . classList . remove ( 'selected' )
}
this . saveCurrentSelection ( elem , elem . innerText , elem . dataset . path )
elem . classList . add ( 'selected' )
elem . scrollIntoView ( { block : 'nearest' } )
this . highlightedModelEntry = elem
}
}
selectPreviousFile ( ) {
2023-02-23 00:18:06 +01:00
const elem = this . getPreviousVisibleSibling ( this . highlightedModelEntry )
2023-02-12 10:18:09 +01:00
if ( elem ) {
this . selectModelEntry ( elem )
}
else
{
//this.highlightedModelEntry.parentElement.parentElement.scrollIntoView({block: 'nearest'})
this . highlightedModelEntry . closest ( '.model-list' ) . scrollTop = 0
}
this . modelFilter . select ( )
}
selectNextFile ( ) {
2023-02-23 00:18:06 +01:00
this . selectModelEntry ( this . getNextVisibleSibling ( this . highlightedModelEntry ) )
2023-02-12 10:18:09 +01:00
this . modelFilter . select ( )
}
selectFirstFile ( ) {
this . selectModelEntry ( this . modelList . querySelector ( '.model-file' ) )
this . highlightedModelEntry . scrollIntoView ( { block : 'nearest' } )
this . modelFilter . select ( )
}
selectLastFile ( ) {
const elems = this . modelList . querySelectorAll ( '.model-file:last-child' )
this . selectModelEntry ( elems [ elems . length - 1 ] )
this . modelFilter . select ( )
}
resetSelection ( ) {
this . hideModelList ( )
this . showAllEntries ( )
this . modelFilter . value = this . currentSelection . value
this . modelFilter . focus ( )
this . modelFilter . select ( )
}
validEntrySelected ( ) {
return ( this . modelNoResult . style . display === 'none' )
}
processKey ( e ) {
switch ( e . key ) {
case 'Escape' :
e . preventDefault ( )
this . resetSelection ( )
break
case 'Enter' :
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
if ( this . modelList . style . display != 'block' ) {
this . showModelList ( )
}
else
{
this . saveCurrentSelection ( this . highlightedModelEntry , this . highlightedModelEntry . innerText , this . highlightedModelEntry . dataset . path )
this . hideModelList ( )
2023-02-13 07:31:40 +01:00
this . showAllEntries ( )
2023-02-12 10:18:09 +01:00
}
this . modelFilter . focus ( )
}
else
{
this . resetSelection ( )
}
break
case 'ArrowUp' :
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectPreviousFile ( )
}
break
case 'ArrowDown' :
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectNextFile ( )
}
break
case 'ArrowLeft' :
if ( this . modelList . style . display != 'block' ) {
e . preventDefault ( )
}
break
case 'ArrowRight' :
if ( this . modelList . style . display != 'block' ) {
e . preventDefault ( )
}
break
case 'PageUp' :
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
this . selectPreviousFile ( )
}
break
case 'PageDown' :
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
this . selectNextFile ( )
}
break
case 'Home' :
//if (this.modelList.style.display != 'block') {
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectFirstFile ( )
}
//}
break
case 'End' :
//if (this.modelList.style.display != 'block') {
e . preventDefault ( )
if ( this . validEntrySelected ( ) ) {
this . selectLastFile ( )
}
//}
break
default :
//console.log(e.key)
}
}
modelListFocus ( ) {
this . selectEntry ( )
this . showAllEntries ( )
}
showModelList ( ) {
this . modelList . style . display = 'block'
this . selectEntry ( )
this . showAllEntries ( )
2023-02-18 08:26:17 +01:00
//this.modelFilter.value = ''
this . modelFilter . select ( ) // preselect the entire string so user can just start typing.
2023-02-12 10:18:09 +01:00
this . modelFilter . focus ( )
this . modelFilter . style . cursor = 'auto'
}
hideModelList ( ) {
this . modelList . style . display = 'none'
this . modelFilter . value = this . currentSelection . value
this . modelFilter . style . cursor = ''
}
toggleModelList ( e ) {
e . preventDefault ( )
2023-02-16 14:59:08 +01:00
if ( ! this . modelFilter . disabled ) {
if ( this . modelList . style . display != 'block' ) {
this . showModelList ( )
}
else
{
this . hideModelList ( )
this . modelFilter . select ( )
}
2023-02-12 10:18:09 +01:00
}
}
selectEntry ( path ) {
if ( path !== undefined ) {
2023-02-23 00:18:06 +01:00
const entries = this . modelElements ;
2023-02-12 10:18:09 +01:00
2023-02-23 00:18:06 +01:00
for ( const elem of entries ) {
if ( elem . dataset . path == path ) {
this . saveCurrentSelection ( elem , elem . innerText , elem . dataset . path )
this . highlightedModelEntry = elem
elem . scrollIntoView ( { block : 'nearest' } )
2023-02-12 10:18:09 +01:00
break
}
}
}
if ( this . currentSelection . elem !== undefined ) {
// select the previous element
if ( this . highlightedModelEntry !== undefined && this . highlightedModelEntry != this . currentSelection . elem ) {
this . highlightedModelEntry . classList . remove ( 'selected' )
}
this . currentSelection . elem . classList . add ( 'selected' )
this . highlightedModelEntry = this . currentSelection . elem
this . currentSelection . elem . scrollIntoView ( { block : 'nearest' } )
}
else
{
this . selectFirstFile ( )
}
}
highlightModelAtPosition ( e ) {
let elem = document . elementFromPoint ( e . clientX , e . clientY )
if ( elem . classList . contains ( 'model-file' ) ) {
this . highlightModel ( elem )
}
}
highlightModel ( elem ) {
if ( elem . classList . contains ( 'model-file' ) ) {
if ( this . highlightedModelEntry !== undefined && this . highlightedModelEntry != elem ) {
this . highlightedModelEntry . classList . remove ( 'selected' )
}
elem . classList . add ( 'selected' )
this . highlightedModelEntry = elem
}
}
showAllEntries ( ) {
this . modelList . querySelectorAll ( 'li' ) . forEach ( function ( li ) {
if ( li . id !== 'model-no-result' ) {
li . style . display = 'list-item'
}
} )
this . modelNoResult . style . display = 'none'
}
filterList ( e ) {
const filter = this . modelFilter . value . toLowerCase ( )
let found = false
let showAllChildren = false
this . modelList . querySelectorAll ( 'li' ) . forEach ( function ( li ) {
if ( li . classList . contains ( 'model-folder' ) ) {
showAllChildren = false
}
if ( filter == '' ) {
li . style . display = 'list-item'
found = true
} else if ( showAllChildren || li . textContent . toLowerCase ( ) . match ( filter ) ) {
li . style . display = 'list-item'
if ( li . classList . contains ( 'model-folder' ) && li . firstChild . textContent . toLowerCase ( ) . match ( filter ) ) {
showAllChildren = true
}
found = true
} else {
li . style . display = 'none'
}
} )
if ( found ) {
this . modelResult . style . display = 'list-item'
this . modelNoResult . style . display = 'none'
2023-02-23 00:18:06 +01:00
const elem = this . getNextVisibleSibling ( this . modelList . querySelector ( '.model-file' ) )
2023-02-12 10:18:09 +01:00
this . highlightModel ( elem )
elem . scrollIntoView ( { block : 'nearest' } )
}
else
{
this . modelResult . style . display = 'none'
this . modelNoResult . style . display = 'list-item'
}
this . modelList . style . display = 'block'
}
/* MODEL LOADER */
2023-02-13 10:37:00 +01:00
getElementDimensions ( element ) {
// Clone the element
const clone = element . cloneNode ( true )
// Copy the styles of the original element to the cloned element
const originalStyles = window . getComputedStyle ( element )
for ( let i = 0 ; i < originalStyles . length ; i ++ ) {
const property = originalStyles [ i ]
clone . style [ property ] = originalStyles . getPropertyValue ( property )
}
// Set its visibility to hidden and display to inline-block
clone . style . visibility = "hidden"
clone . style . display = "inline-block"
// Put the cloned element next to the original element
element . parentNode . insertBefore ( clone , element . nextSibling )
// Get its width and height
const width = clone . offsetWidth
const height = clone . offsetHeight
// Remove it from the DOM
clone . remove ( )
// Return its width and height
return { width , height }
}
2023-02-12 10:18:09 +01:00
2023-02-17 03:03:02 +01:00
/ * *
* @ param { Array < string > } models
* /
sortStringArray ( models ) {
models . sort ( ( a , b ) => a . localeCompare ( b , undefined , { sensitivity : 'base' } ) )
2023-02-12 10:18:09 +01:00
}
populateModels ( ) {
this . activeModel = this . modelFilter . dataset . path
this . currentSelection = { elem : undefined , value : '' , path : '' }
this . highlightedModelEntry = undefined
this . flatModelList = [ ]
if ( this . modelList !== undefined ) {
this . modelList . remove ( )
this . modelFilterArrow . remove ( )
}
this . createDropdown ( )
}
createDropdown ( ) {
// create dropdown entries
2023-02-24 15:38:19 +01:00
let rootModelList = this . createRootModelList ( this . inputModels )
this . modelFilter . insertAdjacentElement ( 'afterend' , rootModelList )
2023-02-17 03:03:02 +01:00
this . modelFilter . insertAdjacentElement (
'afterend' ,
this . createElement (
2023-02-17 03:16:19 +01:00
'i' ,
2023-02-17 03:03:02 +01:00
{ id : ` ${ this . modelFilter . id } -model-filter-arrow ` } ,
2023-02-17 03:16:19 +01:00
[ 'model-selector-arrow' , 'fa-solid' , 'fa-angle-down' ] ,
2023-02-17 03:03:02 +01:00
) ,
)
2023-02-12 10:18:09 +01:00
this . modelFilter . classList . add ( 'model-selector' )
this . modelFilterArrow = document . querySelector ( ` # ${ this . modelFilter . id } -model-filter-arrow ` )
2023-02-18 01:40:16 +01:00
if ( this . modelFilterArrow ) {
this . modelFilterArrow . style . color = this . modelFilter . disabled ? 'dimgray' : ''
}
2023-02-12 10:18:09 +01:00
this . modelList = document . querySelector ( ` # ${ this . modelFilter . id } -model-list ` )
this . modelResult = document . querySelector ( ` # ${ this . modelFilter . id } -model-result ` )
this . modelNoResult = document . querySelector ( ` # ${ this . modelFilter . id } -model-no-result ` )
2023-02-13 07:31:40 +01:00
if ( this . modelFilterInitialized !== true ) {
this . modelFilter . addEventListener ( 'input' , this . bind ( this . filterList , this ) )
this . modelFilter . addEventListener ( 'focus' , this . bind ( this . modelListFocus , this ) )
this . modelFilter . addEventListener ( 'blur' , this . bind ( this . hideModelList , this ) )
this . modelFilter . addEventListener ( 'click' , this . bind ( this . showModelList , this ) )
this . modelFilter . addEventListener ( 'keydown' , this . bind ( this . processKey , this ) )
this . modelFilterInitialized = true
}
2023-02-12 10:18:09 +01:00
this . modelFilterArrow . addEventListener ( 'mousedown' , this . bind ( this . toggleModelList , this ) )
this . modelList . addEventListener ( 'mousemove' , this . bind ( this . highlightModelAtPosition , this ) )
this . modelList . addEventListener ( 'mousedown' , this . bind ( this . processClick , this ) )
2023-02-24 15:38:19 +01:00
let modelFilterStyle = window . getComputedStyle ( this . modelFilter )
rootModelList . style . minWidth = modelFilterStyle . width
2023-02-12 10:18:09 +01:00
this . selectEntry ( this . activeModel )
}
2023-02-17 03:03:02 +01:00
/ * *
*
* @ param { string } tag
* @ param { object } attributes
* @ param { Array < string > } classes
* @ returns { HTMLElement }
* /
2023-02-23 17:41:53 +01:00
createElement ( tagName , attributes , classes , text , icon ) {
2023-02-17 03:03:02 +01:00
const element = document . createElement ( tagName )
if ( attributes ) {
Object . entries ( attributes ) . forEach ( ( [ key , value ] ) => {
element . setAttribute ( key , value )
} )
2023-02-12 10:18:09 +01:00
}
2023-02-17 03:03:02 +01:00
if ( classes ) {
classes . forEach ( className => element . classList . add ( className ) )
}
2023-02-23 17:41:53 +01:00
if ( icon ) {
let iconEl = document . createElement ( 'i' )
iconEl . className = icon + ' icon'
element . appendChild ( iconEl )
}
2023-02-17 03:03:02 +01:00
if ( text ) {
element . appendChild ( document . createTextNode ( text ) )
}
return element
}
/ * *
* @ param { Array < string | object } modelTree
* @ param { string } folderName
* @ param { boolean } isRootFolder
* @ returns { HTMLElement }
* /
createModelNodeList ( folderName , modelTree , isRootFolder ) {
const listElement = this . createElement ( 'ul' )
const foldersMap = new Map ( )
const modelsMap = new Map ( )
modelTree . forEach ( model => {
if ( Array . isArray ( model ) ) {
const [ childFolderName , childModels ] = model
foldersMap . set (
childFolderName ,
this . createModelNodeList (
2023-02-17 03:08:41 +01:00
` ${ folderName || '' } / ${ childFolderName } ` ,
2023-02-17 03:03:02 +01:00
childModels ,
false ,
) ,
)
} else {
const classes = [ 'model-file' ]
if ( isRootFolder ) {
classes . push ( 'in-root-folder' )
2023-02-12 10:18:09 +01:00
}
2023-02-17 05:29:32 +01:00
// Remove the leading slash from the model path
const fullPath = folderName ? ` ${ folderName . substring ( 1 ) } / ${ model } ` : model
2023-02-17 03:03:02 +01:00
modelsMap . set (
model ,
2023-02-23 17:41:53 +01:00
this . createElement ( 'li' , { 'data-path' : fullPath } , classes , model , 'fa-regular fa-file' ) ,
2023-02-17 03:03:02 +01:00
)
2023-02-12 10:18:09 +01:00
}
} )
2023-02-17 03:03:02 +01:00
const childFolderNames = Array . from ( foldersMap . keys ( ) )
this . sortStringArray ( childFolderNames )
const folderElements = childFolderNames . map ( name => foldersMap . get ( name ) )
const modelNames = Array . from ( modelsMap . keys ( ) )
this . sortStringArray ( modelNames )
const modelElements = modelNames . map ( name => modelsMap . get ( name ) )
if ( modelElements . length && folderName ) {
2023-02-23 17:41:53 +01:00
listElement . appendChild ( this . createElement ( 'li' , undefined , [ 'model-folder' ] , folderName . substring ( 1 ) , 'fa-solid fa-folder-open' ) )
2023-02-12 10:18:09 +01:00
}
2023-02-17 03:03:02 +01:00
2023-02-24 14:24:47 +01:00
// const allModelElements = isRootFolder ? [...folderElements, ...modelElements] : [...modelElements, ...folderElements]
const allModelElements = [ ... modelElements , ... folderElements ]
2023-02-17 03:03:02 +01:00
allModelElements . forEach ( e => listElement . appendChild ( e ) )
return listElement
}
/ * *
* @ param { object } modelTree
* @ returns { HTMLElement }
* /
createRootModelList ( modelTree ) {
const rootList = this . createElement (
'ul' ,
{ id : ` ${ this . modelFilter . id } -model-list ` } ,
[ 'model-list' ] ,
)
rootList . appendChild (
this . createElement (
'li' ,
{ id : ` ${ this . modelFilter . id } -model-no-result ` } ,
[ 'model-no-result' ] ,
'No result'
) ,
)
if ( this . noneEntry ) {
rootList . appendChild (
this . createElement (
'li' ,
{ 'data-path' : '' } ,
[ 'model-file' , 'in-root-folder' ] ,
this . noneEntry ,
) ,
)
}
2023-02-24 14:59:25 +01:00
if ( modelTree . length > 0 ) {
const containerListItem = this . createElement (
'li' ,
{ id : ` ${ this . modelFilter . id } -model-result ` } ,
[ 'model-result' ] ,
)
console . log ( containerListItem )
containerListItem . appendChild ( this . createModelNodeList ( undefined , modelTree , true ) )
rootList . appendChild ( containerListItem )
}
2023-02-17 03:03:02 +01:00
return rootList
2023-02-12 10:18:09 +01:00
}
}
/* (RE)LOAD THE MODELS */
async function getModels ( ) {
try {
modelsCache = await SD . getModels ( )
modelsOptions = modelsCache [ 'options' ]
if ( "scan-error" in modelsCache ) {
// let previewPane = document.getElementById('tab-content-wrapper')
let previewPane = document . getElementById ( 'preview' )
previewPane . style . background = "red"
previewPane . style . textAlign = "center"
previewPane . innerHTML = '<H1>🔥Malware alert!🔥</H1><h2>The file <i>' + modelsCache [ 'scan-error' ] + '</i> in your <tt>models/stable-diffusion</tt> folder is probably malware infected.</h2><h2>Please delete this file from the folder before proceeding!</h2>After deleting the file, reload this page.<br><br><button onClick="window.location.reload();">Reload Page</button>'
makeImageBtn . disabled = true
}
/ * T h i s c o d e s h o u l d n o l o n g e r b e n e e d e d . C o m m e n t i n g o u t f o r n o w , w i l l c l e a n u p l a t e r .
const sd _model _setting _key = "stable_diffusion_model"
const vae _model _setting _key = "vae_model"
const hypernetwork _model _key = "hypernetwork_model"
const stableDiffusionOptions = modelsOptions [ 'stable-diffusion' ]
const vaeOptions = modelsOptions [ 'vae' ]
const hypernetworkOptions = modelsOptions [ 'hypernetwork' ]
// TODO: set default for model here too
SETTINGS [ sd _model _setting _key ] . default = stableDiffusionOptions [ 0 ]
if ( getSetting ( sd _model _setting _key ) == '' || SETTINGS [ sd _model _setting _key ] . value == '' ) {
setSetting ( sd _model _setting _key , stableDiffusionOptions [ 0 ] )
}
* /
// notify ModelDropdown objects to refresh
document . dispatchEvent ( new Event ( 'refreshModels' ) )
} catch ( e ) {
console . log ( 'get models error' , e )
}
}
// reload models button
document . querySelector ( '#reload-models' ) . addEventListener ( 'click' , getModels )