500 lines
15 KiB
JavaScript
500 lines
15 KiB
JavaScript
const enableCheckerInit = () => {
|
|
function isDarkColor(color) {
|
|
if (color.length === 0) {
|
|
return false;
|
|
}
|
|
let r;
|
|
let g;
|
|
let b;
|
|
|
|
if (color.startsWith("#")) {
|
|
[r, g, b] = color
|
|
.substring(1)
|
|
.match(/.{2}/g)
|
|
.map((c) => Number(`0x${c}`));
|
|
} else if (color.startsWith("rgb")) {
|
|
[r, g, b] = color.match(/\d+/g).map(Number);
|
|
} else {
|
|
const tempElem = document.createElement("div");
|
|
tempElem.style.color = color;
|
|
document.body.appendChild(tempElem);
|
|
[r, g, b] = window.getComputedStyle(tempElem).color.match(/\d+/g).map(Number);
|
|
document.body.removeChild(tempElem);
|
|
}
|
|
|
|
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
|
return brightness < 128;
|
|
}
|
|
|
|
class Setting {
|
|
constructor() {
|
|
this.enable_checker_activate_dropdown_check = opts.enable_checker_activate_dropdown_check;
|
|
this.enable_checker_activate_weight_check = opts.enable_checker_activate_weight_check;
|
|
this.enable_checker_activate_extra_network_check = opts.enable_checker_activate_extra_network_check;
|
|
|
|
this.loras = null;
|
|
|
|
if (opts?.enable_checker_custom_color) {
|
|
this.color_enable = opts.enable_checker_custom_color_enable;
|
|
this.color_disable = opts.enable_checker_custom_color_disable;
|
|
this.color_dropdown_enable = opts.enable_checker_custom_color_dropdown_enable;
|
|
this.color_dropdown_disable = opts.enable_checker_custom_color_dropdown_disable;
|
|
this.custom_color_zero_weihgt = opts.enable_checker_custom_color_zero_weihgt;
|
|
this.color_invalid_additional_networks = opts.enable_checker_custom_color_invalid_additional_networks;
|
|
} else {
|
|
if (isDarkColor(document.body.style.backgroundColor)) {
|
|
this.color_enable = "#237366";
|
|
this.color_disable = "#5a5757";
|
|
this.color_dropdown_enable = "#233873";
|
|
} else {
|
|
this.color_enable = "skyblue";
|
|
this.color_disable = "#aeaeae"; // light grey
|
|
this.color_dropdown_enable = "#a4f8f1"; // light green
|
|
}
|
|
this.color_dropdown_disable = this.color_disable;
|
|
this.custom_color_zero_weihgt = this.color_disable;
|
|
this.color_invalid_additional_networks = "#ed9797";
|
|
}
|
|
|
|
this.componentId2componentIndex = {};
|
|
for (let index = 0; index < window.gradio_config.components.length; index++) {
|
|
this.componentId2componentIndex[window.gradio_config.components[index].id] = index;
|
|
const elem_id = window.gradio_config.components[index]?.props?.elem_id;
|
|
if (elem_id) {
|
|
this.componentId2componentIndex[elem_id] = index;
|
|
}
|
|
}
|
|
}
|
|
|
|
getComponent(id) {
|
|
let target = id;
|
|
if (id.startsWith("component-")) {
|
|
target = Number(id.replace(/^component-/, ""));
|
|
}
|
|
|
|
return window.gradio_config.components[this.componentId2componentIndex[target]];
|
|
}
|
|
}
|
|
let setting = null;
|
|
|
|
function get_script_area(suffix) {
|
|
for (const name of ["img2img", "txt2img"]) {
|
|
const tab = gradioApp().getElementById(`tab_${name}`);
|
|
if (tab && tab.style.display !== "none") {
|
|
const area = gradioApp().getElementById(`${name}${suffix}`);
|
|
return area;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function get_enable_span(component) {
|
|
const spans = component.querySelectorAll("span");
|
|
for (let k = 0; k < spans.length; k++) {
|
|
const span = spans[k];
|
|
const text = span.innerText.toLowerCase();
|
|
if (
|
|
text.startsWith("enable") ||
|
|
text.endsWith("enabled") ||
|
|
text === "active" ||
|
|
text === "啟用" ||
|
|
text === "启用" ||
|
|
text === "Share attention in batch".toLowerCase() // sd-webui-forge
|
|
) {
|
|
return span;
|
|
}
|
|
}
|
|
}
|
|
|
|
function get_sibling_checkbox_status(node) {
|
|
const snodes = node.parentNode.childNodes;
|
|
for (let k = 0; k < snodes.length; k++) {
|
|
const snode = snodes[k];
|
|
if (snode.nodeName === "INPUT") {
|
|
return snode.checked;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function change_bg(header, is_active) {
|
|
if (is_active) {
|
|
header.style.backgroundColor = setting.color_enable;
|
|
} else {
|
|
header.style.backgroundColor = setting.color_disable;
|
|
}
|
|
}
|
|
|
|
function operate_controlnet_component(controlnet_parts) {
|
|
let found_active_tab = false;
|
|
|
|
const accordions = controlnet_parts.querySelectorAll(
|
|
"#txt2img_controlnet_accordions .input-accordion,#img2img_controlnet_accordions .input-accordion",
|
|
);
|
|
if (accordions.length > 0) {
|
|
// WebUI Forge
|
|
for (let k = 0; k < accordions.length; k++) {
|
|
const accordion = accordions[k];
|
|
const accordion_header = accordion.querySelector("div.label-wrap");
|
|
const enable_span = accordion.querySelector("input[type=checkbox]");
|
|
const is_active = enable_span.checked;
|
|
change_bg(accordion_header, is_active);
|
|
found_active_tab = found_active_tab || is_active;
|
|
}
|
|
return found_active_tab;
|
|
}
|
|
|
|
const divs = controlnet_parts.querySelector(".tabs").querySelectorAll(":scope>div");
|
|
if (divs === undefined || divs.length < 1) {
|
|
return null;
|
|
}
|
|
const tabs = controlnet_parts.querySelectorAll(".tab-nav")[0].querySelectorAll("button");
|
|
if (tabs.length === 0) {
|
|
return null;
|
|
}
|
|
for (let k = 1; k < divs.length; k++) {
|
|
const enable_span = get_enable_span(divs[k]);
|
|
const is_active = get_sibling_checkbox_status(enable_span);
|
|
change_bg(tabs[k - 1], is_active);
|
|
found_active_tab = found_active_tab || is_active;
|
|
}
|
|
return found_active_tab;
|
|
}
|
|
|
|
function get_component_header(component) {
|
|
return component.querySelector("div.label-wrap");
|
|
}
|
|
|
|
function operate_value_input(component) {
|
|
if (!setting.enable_checker_activate_weight_check) {
|
|
return;
|
|
}
|
|
const labels = component.querySelectorAll("label");
|
|
for (let k = 0; k < labels.length; k++) {
|
|
const labeldom = labels[k];
|
|
const label_text = labeldom.querySelector("span")?.innerText;
|
|
if (!label_text || !label_text.toLowerCase().includes("weight")) {
|
|
continue;
|
|
}
|
|
const input = labeldom.parentNode.querySelector("input");
|
|
if (!input) {
|
|
continue;
|
|
}
|
|
if (input.value === 0) {
|
|
input.style.backgroundColor = setting.custom_color_zero_weihgt;
|
|
} else {
|
|
input.style.backgroundColor = "";
|
|
}
|
|
}
|
|
}
|
|
|
|
function is_none(str) {
|
|
return str.toLowerCase() === "none" || str.toLowerCase() === "nothing";
|
|
}
|
|
|
|
function is_target_dropdown(component) {
|
|
let root = component;
|
|
while (root && !root.id) {
|
|
root = root.parentNode;
|
|
}
|
|
if (!root) {
|
|
return true;
|
|
}
|
|
|
|
const info = setting.getComponent(root.id);
|
|
|
|
if (info?.props?.choices) {
|
|
if (info.props.choices.length <= 1) {
|
|
return false;
|
|
}
|
|
const hasNoneOrNothing = info.props.choices.some((str) => {
|
|
return is_none(str);
|
|
});
|
|
|
|
return hasNoneOrNothing;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function operate_dropdown(component) {
|
|
if (!setting.enable_checker_activate_dropdown_check) {
|
|
return;
|
|
}
|
|
|
|
const inners = component.querySelectorAll("[class*=wrap-inner]");
|
|
for (let k = 0; k < inners.length; k++) {
|
|
const inner = inners[k];
|
|
const ddom = inner.querySelector("input");
|
|
if (!is_target_dropdown(ddom)) {
|
|
continue;
|
|
}
|
|
|
|
if (is_none(ddom.value)) {
|
|
inner.style.backgroundColor = setting.color_dropdown_disable;
|
|
} else {
|
|
inner.style.backgroundColor = setting.color_dropdown_enable;
|
|
}
|
|
}
|
|
}
|
|
|
|
function operate_component_in_script_container(component) {
|
|
operate_dropdown(component);
|
|
operate_value_input(component);
|
|
|
|
const header = get_component_header(component);
|
|
if (!header) {
|
|
return;
|
|
}
|
|
|
|
// check modules.ui_components.InputAccordion
|
|
let is_active = false;
|
|
const checkbox = header.querySelector("input[type=checkbox]");
|
|
if (checkbox) {
|
|
is_active = checkbox.checked;
|
|
change_bg(header, is_active);
|
|
return;
|
|
}
|
|
|
|
const enable_span = get_enable_span(component);
|
|
if (!enable_span) {
|
|
return;
|
|
}
|
|
|
|
const controlnet_parts = component.querySelector("#controlnet");
|
|
if (controlnet_parts) {
|
|
is_active = operate_controlnet_component(controlnet_parts);
|
|
|
|
//no tab (single ControlNet)
|
|
if (is_active === null) {
|
|
is_active = get_sibling_checkbox_status(enable_span);
|
|
}
|
|
} else {
|
|
is_active = get_sibling_checkbox_status(enable_span);
|
|
}
|
|
change_bg(header, is_active);
|
|
}
|
|
|
|
function operate_component_in_accordion(component) {
|
|
const header = get_component_header(component);
|
|
const checkbox = header.querySelector("input[type=checkbox]");
|
|
let is_active = checkbox.checked;
|
|
if (is_active && header.innerText.split("\n")[0] === "Refiner") {
|
|
const labels = component.querySelectorAll("label");
|
|
for (let j = 0; j < labels.length; j++) {
|
|
const label = labels[j];
|
|
const text = label.querySelector(":scope>span").innerText;
|
|
if (text === "Checkpoint") {
|
|
const model = label.querySelector("input");
|
|
if (model.value === "") {
|
|
is_active = false;
|
|
break;
|
|
}
|
|
} else if (text === "Switch at") {
|
|
const input = component.querySelector('input[type="number"]');
|
|
if (input.value === 1) {
|
|
is_active = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
change_bg(header, is_active);
|
|
}
|
|
|
|
function fix_seed(ev) {
|
|
let target;
|
|
if (!ev.composed) {
|
|
target = ev.target;
|
|
} else {
|
|
target = ev.composedPath()[0];
|
|
}
|
|
|
|
if (target?.tagName?.toLowerCase() !== "a" || target?.innerText !== "Generate forever") {
|
|
return;
|
|
}
|
|
|
|
function get_active_tab() {
|
|
for (const name of ["img2img", "txt2img"]) {
|
|
const tab = gradioApp().getElementById(`tab_${name}`);
|
|
if (tab && tab.style.display !== "none") {
|
|
return name;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
const active_tab = get_active_tab();
|
|
if (active_tab === null) {
|
|
return;
|
|
}
|
|
|
|
const seed_input = gradioApp().getElementById(`${active_tab}_seed`).querySelector("input");
|
|
seed_input.value = -1;
|
|
updateInput(seed_input);
|
|
}
|
|
|
|
function main_enable_checker(ev) {
|
|
if (Object.keys(opts).length === 0) {
|
|
// not ready
|
|
return;
|
|
}
|
|
if (opts.enable_checker_fix_forever_randomly_seed) {
|
|
fix_seed(ev);
|
|
}
|
|
|
|
if (!setting) {
|
|
setting = new Setting();
|
|
}
|
|
|
|
const area_acd = get_script_area("_accordions");
|
|
if (area_acd && opts !== undefined) {
|
|
const components = area_acd.querySelectorAll(":scope>div.input-accordion");
|
|
for (let j = 0; j < components.length; j++) {
|
|
const component = components[j];
|
|
operate_component_in_accordion(component);
|
|
}
|
|
}
|
|
|
|
const area_sc = get_script_area("_script_container");
|
|
if (area_sc && opts !== undefined) {
|
|
const components = area_sc.querySelectorAll(":scope>div>div");
|
|
for (let j = 0; j < components.length; j++) {
|
|
const component = components[j];
|
|
operate_component_in_script_container(component);
|
|
}
|
|
}
|
|
}
|
|
function init_network_checker(tabname, force) {
|
|
if (setting === null || !setting?.enable_checker_activate_extra_network_check) {
|
|
return;
|
|
}
|
|
if (!force && setting.loras !== null) {
|
|
return;
|
|
}
|
|
|
|
const reload = async () => {
|
|
const name_doms = gradioApp().getElementById(`${tabname}_lora_cards`).querySelectorAll(".name");
|
|
setting.loras = [];
|
|
for (let j = 0; j < name_doms.length; j++) {
|
|
setting.loras.push(name_doms[j].innerText);
|
|
}
|
|
};
|
|
|
|
setTimeout(async () => {
|
|
await reload();
|
|
}, 1000);
|
|
}
|
|
|
|
function main_network_checker(prefix) {
|
|
if (setting === null || !setting?.enable_checker_activate_extra_network_check) {
|
|
return;
|
|
}
|
|
const dom = gradioApp().querySelector(`#${prefix} > label > textarea`);
|
|
const log_dom_id = `${prefix}_error_log`;
|
|
let log_dom = gradioApp().getElementById(log_dom_id);
|
|
if (!log_dom) {
|
|
log_dom = document.createElement("div");
|
|
log_dom.id = log_dom_id;
|
|
dom.parentElement.parentElement.appendChild(log_dom);
|
|
}
|
|
|
|
const regex = /<lora:(.*?):[^>]+>/g;
|
|
const matches = dom.value.matchAll(regex);
|
|
const target_lora_names = Array.from(matches, (m) => m[1]);
|
|
const notIncluded = target_lora_names.filter((item) => !setting.loras.includes(item));
|
|
|
|
if (notIncluded.length === 0) {
|
|
dom.style.background = "";
|
|
log_dom.innerText = "";
|
|
return;
|
|
}
|
|
dom.style.background = setting.color_invalid_additional_networks;
|
|
log_dom.innerText = `Not found LoRA: ${notIncluded.join(", ")}`;
|
|
}
|
|
|
|
function check_version_for_enable_checker() {
|
|
const versions_str = document.getElementsByClassName("versions")[0].innerText;
|
|
const items = versions_str.split(" ");
|
|
if (items.length >= 2 && items[0] === "version:") {
|
|
const vers = items[1].split(".");
|
|
let err = false;
|
|
|
|
if (vers.length < 2) {
|
|
err = true;
|
|
} else {
|
|
// Support >= v1.7.0 for sd-webui
|
|
if (vers[0].startsWith("v")) {
|
|
const v0 = Number(vers[0].substring(1));
|
|
if (v0 < 1 || (v0 === 1 && Number(vers[1]) < 7)) {
|
|
err = true;
|
|
}
|
|
} else if (vers[0].startsWith("f")) {
|
|
// Support >= v0.0.11 for sd-webui-forge
|
|
const v2 = Number(vers[2].split("-")[0]);
|
|
if (v2 < 11) {
|
|
err = true;
|
|
}
|
|
} else {
|
|
err = true;
|
|
}
|
|
}
|
|
|
|
if (err) {
|
|
const msg = `Unexpected version (${vers}) for sd-webui-enable-checker. Please try install the latest WebUI and this extension`;
|
|
alert(msg);
|
|
console.log(msg);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function onui_enable_checker() {
|
|
const ok = check_version_for_enable_checker();
|
|
if (!ok) {
|
|
return;
|
|
}
|
|
|
|
for (const tabname of ["txt2img", "img2img"]) {
|
|
gradioApp()
|
|
.querySelector(`#${tabname}_extra_refresh,#${tabname}_lora_extra_refresh_internal`)
|
|
.addEventListener("click", () => {
|
|
init_network_checker(tabname, true);
|
|
});
|
|
|
|
for (const target_prompt of ["prompt", "neg_prompt"]) {
|
|
const prefix = `${tabname}_${target_prompt}`;
|
|
const textarea = gradioApp().querySelector(`#${prefix} > label > textarea`);
|
|
textarea.addEventListener("input", () => {
|
|
init_network_checker(tabname, false);
|
|
main_network_checker(prefix);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return [main_enable_checker, init_network_checker, main_network_checker, onui_enable_checker];
|
|
};
|
|
|
|
const init_enableChecker = enableCheckerInit();
|
|
const main_enable_checker = init_enableChecker[0];
|
|
const init_network_checker = init_enableChecker[1];
|
|
const main_network_checker = init_enableChecker[2];
|
|
const onui_enable_checker = init_enableChecker[3];
|
|
|
|
gradioApp().addEventListener("click", (ev) => {
|
|
main_enable_checker(ev);
|
|
});
|
|
|
|
gradioApp().addEventListener("change", (ev) => {
|
|
main_enable_checker(ev);
|
|
});
|
|
|
|
onUiUpdate((ev) => {
|
|
main_enable_checker(ev);
|
|
});
|
|
|
|
onUiLoaded(() => {
|
|
onui_enable_checker();
|
|
});
|