| | |
| | |
| | const SDDP_HELP_TEXTS = { |
| | "sddp-disable-negative-prompt": "Don't use prompt magic on negative prompts.", |
| | "sddp-dynamic-prompts-enabled": "Complete documentation is available at https://github.com/adieyal/sd-dynamic-prompts. Please report any issues on GitHub.", |
| | "sddp-is-attention-grabber": "Add emphasis to a randomly selected keyword in the prompt.", |
| | "sddp-is-combinatorial": "Generate all possible prompt combinations.", |
| | "sddp-is-feelinglucky": "Generate random prompts from lexica.art (your prompt is used as a search query).", |
| | "sddp-is-fixed-seed": "Use the same seed for all prompts in this batch", |
| | "sddp-is-magicprompt": "Automatically update your prompt with interesting modifiers. (Runs slowly the first time)", |
| | "sddp-magic-prompt-model": "Note: Each model will download between 300mb and 1.4gb of data on first use.", |
| | "sddp-no-image-generation": "Disable image generation. Useful if you only want to generate text prompts. (1 image will still be generated to keep Auto1111 happy.).", |
| | "sddp-unlink-seed-from-prompt": "If this is set, then random prompts are generated, even if the seed is the same.", |
| | "sddp-write-prompts": "Write all generated prompts to a file", |
| | "sddp-write-raw-template": "Write template into image metadata.", |
| | }; |
| |
|
| | class SDDPTreeView { |
| | |
| | |
| | |
| | |
| | |
| | |
| | constructor(data, node) { |
| | this.handlers = {}; |
| | this.node = node; |
| | this.data = data; |
| | this.render(); |
| | } |
| |
|
| | |
| | |
| | |
| | render = () => { |
| | const container = this.node; |
| | container.innerHTML = ""; |
| | this.data.forEach((item) => container.appendChild(this.renderNode(item))); |
| | [...container.querySelectorAll(".tree-leaf-text,.tree-expando")].forEach( |
| | (node) => node.addEventListener("click", this.handleClickEvent), |
| | ); |
| | }; |
| |
|
| | renderNode = (item) => { |
| | const leaf = document.createElement("div"); |
| | const content = document.createElement("div"); |
| | const text = document.createElement("div"); |
| | const expando = document.createElement("div"); |
| | leaf.setAttribute("class", "tree-leaf"); |
| | content.setAttribute("class", "tree-leaf-content"); |
| | text.setAttribute("class", "tree-leaf-text"); |
| | const { children, name, expanded } = item; |
| | text.textContent = name; |
| | expando.setAttribute("class", `tree-expando ${expanded ? "expanded" : ""}`); |
| | expando.textContent = expanded ? "-" : "+"; |
| | content.appendChild(expando); |
| | content.appendChild(text); |
| | leaf.appendChild(content); |
| | if (children?.length > 0) { |
| | const childrenDiv = document.createElement("div"); |
| | childrenDiv.setAttribute("class", "tree-child-leaves"); |
| | children.forEach((child) => { |
| | childrenDiv.appendChild(this.renderNode(child)); |
| | }); |
| | if (!expanded) { |
| | childrenDiv.classList.add("hidden"); |
| | } |
| | leaf.appendChild(childrenDiv); |
| | } else { |
| | expando.classList.add("hidden"); |
| | content.setAttribute("data-item", JSON.stringify(item)); |
| | } |
| | return leaf; |
| | }; |
| |
|
| | handleClickEvent = (event) => { |
| | const parent = (event.target || event.currentTarget).parentNode; |
| | const leaves = parent.parentNode.querySelector(".tree-child-leaves"); |
| | if (leaves) { |
| | this.setSubtreeVisibility( |
| | parent, |
| | leaves, |
| | leaves.classList.contains("hidden"), |
| | ); |
| | } else { |
| | this.emit("select", { |
| | target: event, |
| | data: JSON.parse(parent.getAttribute("data-item")), |
| | }); |
| | } |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | setSubtreeVisibility(node, leaves, visible, skipEmit = false) { |
| | leaves.classList.toggle("hidden", !visible); |
| | node.querySelector(".tree-expando").textContent = visible ? "+" : "-"; |
| | if (skipEmit) { |
| | return; |
| | } |
| | this.emit(visible ? "expand" : "collapse", { |
| | target: node, |
| | leaves, |
| | }); |
| | } |
| |
|
| | on(name, callback, context = null) { |
| | const handlers = this.handlers[name] || []; |
| | handlers.push({ callback, context }); |
| | this.handlers[name] = handlers; |
| | } |
| |
|
| | off(name, callback) { |
| | this.handlers[name] = (this.handlers[name] || []).filter( |
| | (handle) => handle.callback !== callback, |
| | ); |
| | } |
| |
|
| | emit(name, ...args) { |
| | (this.handlers[name] || []).forEach((handle) => { |
| | window.setTimeout(() => { |
| | handle.callback.apply(handle.context, args); |
| | }, 0); |
| | }); |
| | } |
| | } |
| |
|
| | class SDDP_UI { |
| | constructor() { |
| | this.helpTextsConfigured = false; |
| | this.wildcardsLoaded = false; |
| | this.messageReadTimer = null; |
| | this.lastMessage = null; |
| | this.treeView = null; |
| | } |
| |
|
| | configureHelpTexts() { |
| | if (this.helpTextsConfigured) { |
| | return; |
| | } |
| | |
| | for (const elemId in SDDP_HELP_TEXTS) { |
| | const elem = gradioApp().getElementById(elemId); |
| | if (elem) { |
| | elem.setAttribute("title", SDDP_HELP_TEXTS[elemId]); |
| | } else { |
| | return; |
| | } |
| | } |
| | this.helpTextsConfigured = true; |
| | } |
| |
|
| | getInboxMessageText() { |
| | return gradioApp().querySelector( |
| | "#sddp-wildcard-s2c-message-textbox textarea", |
| | )?.value; |
| | } |
| |
|
| | formatPayload(payload) { |
| | return JSON.stringify({ ...payload, id: Math.floor(+new Date()) }, null, 2); |
| | } |
| |
|
| | sendAction(payload) { |
| | const outbox = gradioApp().querySelector( |
| | "#sddp-wildcard-c2s-message-textbox textarea", |
| | ); |
| | outbox.value = this.formatPayload(payload); |
| | |
| | window.updateInput?.(outbox); |
| | gradioApp().querySelector("#sddp-wildcard-c2s-action-button").click(); |
| | } |
| |
|
| | requestWildcardTree() { |
| | gradioApp().querySelector("#sddp-wildcard-load-tree-button")?.click(); |
| | } |
| |
|
| | doReadMessage() { |
| | const messageText = this.getInboxMessageText(); |
| | if (!messageText || this.lastMessage === messageText) { |
| | return; |
| | } |
| | this.lastMessage = messageText; |
| | const message = JSON.parse(messageText); |
| | const { action, success } = message; |
| | if (action === "load tree" && success) { |
| | this.setupTree(message.tree); |
| | } else if (action === "load file" && success) { |
| | this.loadFileIntoEditor(message); |
| | } else { |
| | console.warn("SDDP: Unknown message", message); |
| | } |
| | } |
| |
|
| | setupTree(content) { |
| | let { treeView } = this; |
| | if (!this.treeView) { |
| | const treeDiv = gradioApp().querySelector("#sddp-wildcard-tree"); |
| | if (treeDiv) { |
| | treeView = new SDDPTreeView(content, treeDiv); |
| | treeView.on("select", this.onSelectNode.bind(this), null); |
| | this.treeView = treeView; |
| | } |
| | } else { |
| | treeView.data = content; |
| | treeView.render(); |
| | } |
| | } |
| |
|
| | onSelectNode(node) { |
| | if (node.data?.name) { |
| | this.sendAction({ |
| | action: "load file", |
| | name: node.data.name, |
| | }); |
| | } |
| | } |
| |
|
| | loadFileIntoEditor(message) { |
| | const editor = gradioApp().querySelector( |
| | "#sddp-wildcard-file-editor textarea", |
| | ); |
| | const name = gradioApp().querySelector("#sddp-wildcard-file-name textarea"); |
| | const saveButton = gradioApp().querySelector("#sddp-wildcard-save-button"); |
| | const { contents, wrapped_name: wrappedName, can_edit: canEdit } = message; |
| | editor.value = contents; |
| | name.value = wrappedName; |
| | editor.readOnly = !canEdit; |
| | saveButton.disabled = !canEdit; |
| |
|
| | |
| | window.updateInput?.(editor); |
| | window.updateInput?.(name); |
| | } |
| |
|
| | onWildcardManagerTabActivate() { |
| | if (!this.wildcardsLoaded) { |
| | this.requestWildcardTree(); |
| | this.wildcardsLoaded = true; |
| | } |
| | if (!this.messageReadTimer) { |
| | this.messageReadTimer = setInterval(this.doReadMessage.bind(this), 120); |
| | } |
| | } |
| |
|
| | onDeleteTreeClick() { |
| | |
| | const sure = confirm("Are you sure you want to delete all your wildcards?"); |
| | return this.formatPayload({ action: "delete tree", sure }); |
| | } |
| |
|
| | onSaveFileClick() { |
| | const json = JSON.parse(this.getInboxMessageText()); |
| | const contents = gradioApp().querySelector( |
| | "#sddp-wildcard-file-editor textarea", |
| | ).value; |
| | return this.formatPayload({ |
| | action: "save wildcard", |
| | wildcard: json, |
| | contents, |
| | }); |
| | } |
| | } |
| |
|
| | const SDDP = new SDDP_UI(); |
| | window.SDDP = SDDP; |
| |
|
| | onUiUpdate(() => { |
| | SDDP.configureHelpTexts(); |
| | }); |
| |
|
| | onUiLoaded(() => { |
| | |
| | const mutationObserver = new MutationObserver(() => { |
| | if (get_uiCurrentTabContent()?.id === "tab_sddp-wildcard-manager") { |
| | SDDP.onWildcardManagerTabActivate(); |
| | } |
| | }); |
| | mutationObserver.observe(gradioApp(), { childList: true, subtree: true }); |
| | }); |
| |
|