|
|
window.state = window.state || {}; |
|
|
state = window.state; |
|
|
let selectingQueue = 0; |
|
|
|
|
|
state.utils = { |
|
|
|
|
|
testFunction: function testFunction() { |
|
|
|
|
|
|
|
|
|
|
|
value = "新建文件夹\\anything-v5-PrtRE.safetensors" |
|
|
value = value.replace("/","\\") |
|
|
parts = value.split("\\") |
|
|
console.log(parts[parts.length - 1]) |
|
|
}, |
|
|
|
|
|
target_is_newer_version: function(cur_version, target_version){ |
|
|
|
|
|
let cur = cur_version.replace("v","") |
|
|
cur = cur.split(".") |
|
|
|
|
|
let target = target_version.replace("v","") |
|
|
target = target.split(".") |
|
|
let version_len = Math.min(cur.length, target.length) |
|
|
|
|
|
|
|
|
for (let i=0; i < version_len; i++){ |
|
|
if(Number(cur[i]) > Number(target[i])){ |
|
|
return false |
|
|
} |
|
|
else if(Number(cur[i]) < Number(target[i])){ |
|
|
return true |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if(cur.length >= target.length){ |
|
|
return false |
|
|
} |
|
|
|
|
|
return true |
|
|
}, |
|
|
|
|
|
searchCheckPointByHash: async function searchCheckPointByHash(hash){ |
|
|
let downloadUrl = undefined |
|
|
hash_str = hash.replace("[","").replace("]","").replace(/^\s+|\s+$/g,"") |
|
|
await fetch("https://civitai.com/api/v1/model-versions/by-hash/"+hash_str) |
|
|
.then(response => response.json()) |
|
|
.then(data => { |
|
|
|
|
|
|
|
|
for (file of data["files"]){ |
|
|
for (key of Object.keys(file["hashes"])){ |
|
|
if(file["hashes"][key].toLowerCase() === hash_str.toLowerCase()) |
|
|
{ |
|
|
downloadUrl = file["downloadUrl"] |
|
|
console.log(downloadUrl) |
|
|
break |
|
|
} |
|
|
} |
|
|
} |
|
|
if(downloadUrl == undefined){downloadUrl = data["files"][0]["downloadUrl"]} |
|
|
|
|
|
}).catch(function(e) { |
|
|
console.log("search model error!"); |
|
|
}); |
|
|
|
|
|
return downloadUrl |
|
|
}, |
|
|
|
|
|
getTranslation: function getTranslation(key){ |
|
|
new_key = key |
|
|
try{ |
|
|
if(window.localization[new_key.replace(/^\s+|\s+$/g,"")] != undefined){ |
|
|
new_key = window.localization[new_key] |
|
|
} |
|
|
} catch (error) { |
|
|
console.warn('getTranslation error:', error); |
|
|
} |
|
|
return new_key |
|
|
}, |
|
|
|
|
|
reverseTranslation: function reverseTranslation(key){ |
|
|
new_key = [] |
|
|
try{ |
|
|
|
|
|
for (localize_key of Object.keys(window.localization)) { |
|
|
if(key.replace(/^\s+|\s+$/g,"") === window.localization[localize_key].replace(/^\s+|\s+$/g,"")){ |
|
|
tmp_key = localize_key |
|
|
new_key.push(tmp_key) |
|
|
|
|
|
} |
|
|
} |
|
|
} catch (error) { |
|
|
console.warn('reverseTranslation error:', error); |
|
|
} |
|
|
|
|
|
if(new_key.length == 0){new_key.push(key)} |
|
|
|
|
|
|
|
|
return new_key |
|
|
}, |
|
|
|
|
|
sleep: function sleep(time) { |
|
|
return new Promise((resolve) => setTimeout(resolve, time)); |
|
|
}, |
|
|
|
|
|
switch_to_img_inpaint: function switch_to_img_inpaint() { |
|
|
switch_to_img2img_tab(4); |
|
|
return Array.from(arguments); |
|
|
}, |
|
|
switch_to_txt2img_ControlNet: function switch_to_txt2img_ControlNet(unit) { |
|
|
|
|
|
switch_to_txt2img() |
|
|
|
|
|
let elem = undefined |
|
|
elem = gradioApp().getElementById('txt2img_controlnet') |
|
|
elem = elem.querySelector("#controlnet") |
|
|
|
|
|
try{ |
|
|
if(elem.className.split(' ').pop() != "open"){ |
|
|
state.utils.triggerMouseEvent(elem, 'click') |
|
|
} |
|
|
for(e of elem.children){ |
|
|
if(e.className.split(' ').pop() != "open"){ |
|
|
state.utils.triggerMouseEvent(e, 'click') |
|
|
} |
|
|
} |
|
|
} catch(error){console.log(error)} |
|
|
|
|
|
try{ |
|
|
gradioApp().getElementById('txt2img_controlnet_tabs').querySelectorAll('button')[Number(unit)].click() |
|
|
} catch (error) { |
|
|
console.warn('[switch_to_txt2img_ControlNet]: Error:', error); |
|
|
} |
|
|
}, |
|
|
switch_to_img2img_ControlNet: function switch_to_img2img_ControlNet(unit) { |
|
|
|
|
|
switch_to_img2img() |
|
|
|
|
|
let elem = undefined |
|
|
elem = gradioApp().getElementById('img2img_controlnet') |
|
|
elem = elem.querySelector("#controlnet") |
|
|
|
|
|
try{ |
|
|
if(elem.className.split(' ').pop() != "open"){ |
|
|
state.utils.triggerMouseEvent(elem, 'click') |
|
|
} |
|
|
for(e of elem.children){ |
|
|
if(e.className.split(' ').pop() != "open"){ |
|
|
state.utils.triggerMouseEvent(e, 'click') |
|
|
} |
|
|
} |
|
|
} catch(error){console.log(error)} |
|
|
|
|
|
try{ |
|
|
gradioApp().getElementById('img2img_controlnet_tabs').querySelectorAll('button')[Number(unit)].click() |
|
|
} catch (error) { |
|
|
console.warn('[switch_to_img2img_ControlNet]: Error:', error); |
|
|
} |
|
|
}, |
|
|
triggerEvent: function triggerEvent(element, event) { |
|
|
if (! element) { |
|
|
return; |
|
|
} |
|
|
element.dispatchEvent(new Event(event.trim())); |
|
|
return element; |
|
|
}, |
|
|
triggerMouseEvent: function triggerMouseEvent(element, event) { |
|
|
if (! element) { |
|
|
return; |
|
|
} |
|
|
event = event || 'click'; |
|
|
element.dispatchEvent(new MouseEvent(event, { |
|
|
view: window, |
|
|
bubbles: true, |
|
|
cancelable: true, |
|
|
})); |
|
|
return element; |
|
|
}, |
|
|
setValue: function setValue(element, value, event) { |
|
|
switch (element.type) { |
|
|
case 'checkbox': |
|
|
element.checked = value === 'true'; |
|
|
this.triggerEvent(element, event); |
|
|
break; |
|
|
case 'radio': |
|
|
if (element.value === value) { |
|
|
element.checked = true; |
|
|
this.triggerEvent(element, event); |
|
|
} |
|
|
else if(element.value == "Scribble/Sketch" && value == "Scribble"){ |
|
|
element.checked = true; |
|
|
this.triggerEvent(element, event); |
|
|
} |
|
|
else { |
|
|
element.checked = false; |
|
|
} |
|
|
break; |
|
|
default: |
|
|
element.value = value; |
|
|
this.triggerEvent(element, event); |
|
|
} |
|
|
}, |
|
|
onFrameContentChange: function onFrameContentChange(targetNode, func) { |
|
|
if(targetNode) { |
|
|
const observer = new MutationObserver((mutationsList, observer) => { |
|
|
for (const mutation of mutationsList) { |
|
|
if (mutation.type === 'childList' || |
|
|
(mutation.type === 'attributes' && mutation.attributeName == 'src') |
|
|
) { |
|
|
|
|
|
func(targetNode); |
|
|
} |
|
|
} |
|
|
}); |
|
|
observer.observe(targetNode, { |
|
|
|
|
|
childList: true, |
|
|
|
|
|
subtree: true |
|
|
}); |
|
|
} |
|
|
}, |
|
|
|
|
|
onContentChange: function onContentChange(targetNode, func) { |
|
|
if(targetNode) { |
|
|
const observer = new MutationObserver((mutationsList, observer) => { |
|
|
for (const mutation of mutationsList) { |
|
|
if (mutation.type === 'childList' || |
|
|
(mutation.type === 'attributes' && mutation.attributeName == 'src') |
|
|
) { |
|
|
func(targetNode); |
|
|
} |
|
|
} |
|
|
}); |
|
|
observer.observe(targetNode, { |
|
|
attributes: true, |
|
|
childList: true, |
|
|
characterData: true, |
|
|
subtree: true |
|
|
}); |
|
|
} |
|
|
}, |
|
|
|
|
|
onAccordionChange: function onAccordionChange(targetNode, func) { |
|
|
if(targetNode) { |
|
|
const observer = new MutationObserver((mutationsList, observer) => { |
|
|
for (const mutation of mutationsList) { |
|
|
if (mutation.type === 'attributes' ) { |
|
|
func(targetNode); |
|
|
} |
|
|
} |
|
|
}); |
|
|
observer.observe(targetNode, { |
|
|
attributes: true, |
|
|
}); |
|
|
} |
|
|
}, |
|
|
|
|
|
getCurSeed: function getCurSeed(tab) { |
|
|
const elements = gradioApp().getElementById(`html_info_${tab}`).querySelectorAll(`#html_info_${tab}`); |
|
|
if (! elements || ! elements.length || !elements[0].innerText) { |
|
|
return undefined; |
|
|
} |
|
|
seed = undefined |
|
|
values = elements[0].innerText.split(',') |
|
|
for (value of values){ |
|
|
pair = value.split(':') |
|
|
if(pair[0].replace(/^\s+|\s+$/g,"") == 'Seed'){ |
|
|
seed = pair[1].replace(/^\s+|\s+$/g,"") |
|
|
} |
|
|
} |
|
|
return seed |
|
|
}, |
|
|
|
|
|
handleImage: function handleImage(select, id, store, addEvtLsner=true) { |
|
|
if(addEvtLsner){ |
|
|
setTimeout(() => { |
|
|
state.utils.onContentChange(select, function (el) { |
|
|
|
|
|
let data = { |
|
|
method: 'POST', |
|
|
headers: { 'Content-Type': 'application/json' }, |
|
|
body: JSON.stringify({ |
|
|
"id":id, |
|
|
"img":"" |
|
|
}) |
|
|
} |
|
|
|
|
|
try { |
|
|
|
|
|
let img = el.querySelector('img'); |
|
|
if (img) { |
|
|
data.body = JSON.stringify({ |
|
|
"id":id, |
|
|
"img":img.src |
|
|
}) |
|
|
} |
|
|
} catch (error) { |
|
|
console.warn('[state]: Error:', error); |
|
|
} |
|
|
|
|
|
fetch(`/lightdiffusionflow/local/imgs_callback`, data) |
|
|
}); |
|
|
}, 150); |
|
|
} |
|
|
}, |
|
|
|
|
|
clearImage: function clearImage(select) { |
|
|
try { |
|
|
if(select){ |
|
|
|
|
|
let buttons = select.querySelectorAll('button'); |
|
|
buttons.forEach(button => { |
|
|
if(button.getAttribute("aria-label") == "Clear"){ |
|
|
button.click(); |
|
|
|
|
|
} |
|
|
}); |
|
|
|
|
|
} |
|
|
} catch (error) { |
|
|
console.warn('[state]: Error:', error); |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
forceSaveSelect: function forceSaveSelect(select, id, store) { |
|
|
let selected = select.querySelector('span.single-select'); |
|
|
if (selected) { |
|
|
store.set(id, selected.textContent); |
|
|
} else { |
|
|
|
|
|
let input = select.querySelector('input'); |
|
|
if (input) { |
|
|
store.set(id, input.value); |
|
|
} |
|
|
} |
|
|
}, |
|
|
handleAccordion: function handleAccordion(accordion, id, store, addEvtLsner=true){ |
|
|
try{ |
|
|
let value = store.get(id); |
|
|
let child = accordion.querySelector('div.cursor-pointer, .label-wrap'); |
|
|
if (value) { |
|
|
|
|
|
|
|
|
|
|
|
if(child.className.split(' ').pop() != "open"){ |
|
|
state.utils.triggerMouseEvent(child, 'click') |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if(addEvtLsner){ |
|
|
setTimeout(() => { |
|
|
state.utils.onAccordionChange(child, function (el) { |
|
|
store.set(id, el.className.split(' ').pop() == "open"); |
|
|
|
|
|
|
|
|
|
|
|
}); |
|
|
}, 150); |
|
|
} |
|
|
} catch (error) { |
|
|
console.warn(`accordion:${accordion}, id:${id}`) |
|
|
console.warn('[state]: Error:', error); |
|
|
} |
|
|
}, |
|
|
handleSelect: function handleSelect(select, id, store, force=false, addEvtLsner=true) { |
|
|
try { |
|
|
|
|
|
let value = store.get(id); |
|
|
if ( value ) { |
|
|
value = value.replace("/","\\") |
|
|
let parts = value.split("\\") |
|
|
value = parts[parts.length - 1] |
|
|
|
|
|
selectingQueue += 1; |
|
|
setTimeout(() => { |
|
|
|
|
|
let input = select.querySelector('input'); |
|
|
state.utils.triggerMouseEvent(input, 'focus'); |
|
|
setTimeout(() => { |
|
|
let items = Array.from(select.querySelectorAll('ul li')); |
|
|
let localized_value = this.getTranslation(value) |
|
|
let successed = false |
|
|
for (li of items){ |
|
|
|
|
|
let option = li.lastChild.wholeText.trim().replace(/^\s+|\s+$/g,"") |
|
|
option = option.replace("/","\\") |
|
|
let parts = option.split("\\") |
|
|
option = parts[parts.length - 1] |
|
|
if (localized_value.replace(/^\s+|\s+$/g,"") === option) { |
|
|
state.utils.triggerMouseEvent(li, 'mousedown'); |
|
|
successed = true |
|
|
break |
|
|
} |
|
|
} |
|
|
|
|
|
let hash_res = localized_value.match(/\[[0-9A-Fa-f]{8,10}\]/) |
|
|
if(!successed){ |
|
|
for (li of items){ |
|
|
|
|
|
|
|
|
let text = li.lastChild.wholeText.trim() |
|
|
text = text.replace("/","\\") |
|
|
let parts = text.split("\\") |
|
|
text = parts[parts.length - 1] |
|
|
|
|
|
let localized_value_no_hash = localized_value.replace(/\[[0-9A-Fa-f]{8,10}\]/,"").replace(/^\s+|\s+$/g,"") |
|
|
let text_no_hash = text.replace(/\[[0-9A-Fa-f]{8,10}\]/, "").replace(/^\s+|\s+$/g,"") |
|
|
|
|
|
if (localized_value_no_hash === text_no_hash) { |
|
|
successed = true |
|
|
} |
|
|
|
|
|
|
|
|
if(!successed && hash_res != null){ |
|
|
let hash_str = hash_res[0].replace(/^\s+|\s+$/g,"") |
|
|
let text_hash_res = text.match(/\[[0-9A-Fa-f]{8,10}\]/) |
|
|
if(text_hash_res != null){ |
|
|
let text_hash = text_hash_res[0].replace(/^\s+|\s+$/g,"") |
|
|
if (hash_str === text_hash) { |
|
|
successed = true |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if(successed){ |
|
|
state.utils.triggerMouseEvent(li, 'mousedown'); |
|
|
|
|
|
|
|
|
|
|
|
state.core.actions.preset_output_log("alt_option", value, li.lastChild.wholeText.trim()) |
|
|
break |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
if(!successed && items.length > 0) |
|
|
{ |
|
|
let option_name = store.prefix + id |
|
|
if(option_name === "state-setting_sd_model_checkpoint"){ |
|
|
|
|
|
|
|
|
state.core.actions.preset_output_log("no_option", "stable diffusion checkpoint", value) |
|
|
} |
|
|
else{ |
|
|
|
|
|
state.core.actions.preset_output_log("no_option", option_name, value) |
|
|
} |
|
|
if(hash_res != null){ |
|
|
let model_name = value |
|
|
let hash_str = hash_res[0] |
|
|
state.utils.searchCheckPointByHash(hash_str).then( downloadUrl => { |
|
|
if(downloadUrl != undefined){ |
|
|
|
|
|
|
|
|
|
|
|
state.core.actions.preset_output_log("download_url", model_name, downloadUrl) |
|
|
} |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
state.utils.triggerMouseEvent(input, 'blur'); |
|
|
selectingQueue -= 1; |
|
|
|
|
|
}, 100); |
|
|
|
|
|
}, selectingQueue * 200) |
|
|
} |
|
|
|
|
|
if(addEvtLsner) |
|
|
{ |
|
|
setTimeout(() => { |
|
|
state.utils.onContentChange(select, function (el) { |
|
|
let selected = el.querySelector('span.single-select'); |
|
|
if(force){ |
|
|
let localized_id = state.utils.getTranslation(id) |
|
|
let id_translations = state.utils.reverseTranslation(localized_id) |
|
|
|
|
|
for (trans_id of id_translations){ |
|
|
if (selected) { |
|
|
store.set(trans_id, selected.textContent); |
|
|
} else { |
|
|
|
|
|
let input = el.querySelector('input'); |
|
|
if (input) { |
|
|
store.set(trans_id, input.value); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
else{ |
|
|
if (selected) { |
|
|
store.set(id, selected.textContent); |
|
|
} else { |
|
|
|
|
|
let input = el.querySelector('input'); |
|
|
if (input) { |
|
|
store.set(id, input.value); |
|
|
} |
|
|
} |
|
|
} |
|
|
}); |
|
|
}, 150); |
|
|
} |
|
|
} catch (error) { |
|
|
console.warn('[state]: Error:', error); |
|
|
} |
|
|
}, |
|
|
handleMultipleSelect: function handleMultipleSelect(select, id, store, addEvtLsner=true) { |
|
|
try { |
|
|
let value = store.get(id); |
|
|
|
|
|
if (value) { |
|
|
|
|
|
value = value.split(',').reverse(); |
|
|
|
|
|
if (value.length) { |
|
|
|
|
|
let input = select.querySelector('input'); |
|
|
|
|
|
let selectOption = function () { |
|
|
|
|
|
if (! value.length) { |
|
|
state.utils.triggerMouseEvent(input, 'blur'); |
|
|
return; |
|
|
} |
|
|
|
|
|
let option = value.pop(); |
|
|
state.utils.triggerMouseEvent(input, 'focus'); |
|
|
|
|
|
setTimeout(() => { |
|
|
let successed = false |
|
|
let items = Array.from(select.querySelectorAll('ul li')); |
|
|
items.forEach(li => { |
|
|
if (li.lastChild.wholeText.trim() === option) { |
|
|
state.utils.triggerMouseEvent(li, 'mousedown'); |
|
|
successed = true |
|
|
return false; |
|
|
} |
|
|
}); |
|
|
if(!successed){ |
|
|
state.core.actions.preset_output_log("no_option", store.prefix + id, value) |
|
|
|
|
|
} |
|
|
setTimeout(selectOption, 100); |
|
|
}, 100); |
|
|
} |
|
|
selectOption(); |
|
|
} |
|
|
} |
|
|
|
|
|
if(addEvtLsner){ |
|
|
state.utils.onContentChange(select, function (el) { |
|
|
const selected = Array.from(el.querySelectorAll('.token > span')).map(item => item.textContent); |
|
|
store.set(id, selected); |
|
|
}); |
|
|
} |
|
|
} catch (error) { |
|
|
console.warn('[state]: Error:', error); |
|
|
} |
|
|
}, |
|
|
txtToId: function txtToId(txt) { |
|
|
return txt.split(' ').join('-').toLowerCase(); |
|
|
}, |
|
|
callXTimes: function callXTimes(func, times) { |
|
|
let called = 0; |
|
|
return function() { |
|
|
if (called < times) { |
|
|
called++; |
|
|
return func.apply(this); |
|
|
} |
|
|
} |
|
|
}, |
|
|
saveFile: function saveJSON(fileName ,data) { |
|
|
const json = JSON.stringify(data, null, 4); |
|
|
const blob = new Blob([json], {type: 'application/json'}); |
|
|
const url = URL.createObjectURL(blob); |
|
|
console.log(url) |
|
|
const link = document.createElement('a'); |
|
|
link.href = url; |
|
|
link.download = fileName; |
|
|
|
|
|
document.body.appendChild(link); |
|
|
link.click(); |
|
|
link.parentNode.removeChild(link); |
|
|
}, |
|
|
debounce: function debounce(func, delay) { |
|
|
let lastCallTime = 0; |
|
|
return function() { |
|
|
const currentCallTime = new Date().getTime(); |
|
|
if (currentCallTime - lastCallTime > delay) { |
|
|
lastCallTime = currentCallTime; |
|
|
func.apply(this, arguments); |
|
|
} |
|
|
} |
|
|
}, |
|
|
onNextUiUpdates: function (func) { |
|
|
|
|
|
onUiUpdate(this.callXTimes(function () { setTimeout(func, 5); }, 150)); |
|
|
} |
|
|
}; |
|
|
|
|
|
state.utils.html = { |
|
|
setStyle: function setStyle(elements, style) { |
|
|
if (elements instanceof NodeList) { |
|
|
elements = Array.from(elements); |
|
|
} else if (elements instanceof Node){ |
|
|
elements = [elements]; |
|
|
} else { |
|
|
return; |
|
|
} |
|
|
elements.forEach(element => { |
|
|
for (let key in style) { |
|
|
if (style.hasOwnProperty(key)) { |
|
|
element.style[key] = style[key]; |
|
|
} |
|
|
} |
|
|
}); |
|
|
}, |
|
|
create: function create(type, props, style) { |
|
|
const element = document.createElement(type); |
|
|
if (props) { |
|
|
for (let key in props) { |
|
|
if (props.hasOwnProperty(key)) { |
|
|
element[key] = props[key]; |
|
|
} |
|
|
} |
|
|
} |
|
|
if (style) { |
|
|
this.setStyle(element, style); |
|
|
} |
|
|
return element; |
|
|
}, |
|
|
createButton: function createButton(text, onclick) { |
|
|
const btn = document.createElement('button'); |
|
|
btn.innerHTML = text; |
|
|
btn.onclick = onclick || function () {}; |
|
|
btn.className = 'gr-button gr-button-lg gr-button-primary'; |
|
|
return btn; |
|
|
} |
|
|
}; |
|
|
|