mirror of
https://github.com/DominikDoom/a1111-sd-webui-tagcomplete.git
synced 2026-01-27 11:39:55 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fdad1bf62 | ||
|
|
a91a098243 | ||
|
|
c663abcbcb | ||
|
|
bec222f2b3 | ||
|
|
d4db6a7907 | ||
|
|
52593e6ac8 | ||
|
|
849e346924 |
@@ -70,6 +70,13 @@ const autocompleteCSS = `
|
||||
flex-grow: 1;
|
||||
color: var(--meta-text-color);
|
||||
}
|
||||
.acWikiLink {
|
||||
padding: 0.5rem;
|
||||
margin: -0.5rem 0 -0.5rem -0.5rem;
|
||||
}
|
||||
.acWikiLink:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.acListItem.acEmbeddingV1 {
|
||||
color: var(--embedding-v1-color);
|
||||
}
|
||||
@@ -158,7 +165,9 @@ async function syncOptions() {
|
||||
txt2img: opts["tac_activeIn.txt2img"],
|
||||
img2img: opts["tac_activeIn.img2img"],
|
||||
negativePrompts: opts["tac_activeIn.negativePrompts"],
|
||||
thirdParty: opts["tac_activeIn.thirdParty"]
|
||||
thirdParty: opts["tac_activeIn.thirdParty"],
|
||||
modelList: opts["tac_activeIn.modelList"],
|
||||
modelListMode: opts["tac_activeIn.modelListMode"]
|
||||
},
|
||||
// Results related settings
|
||||
maxResults: opts["tac_maxResults"],
|
||||
@@ -167,6 +176,7 @@ async function syncOptions() {
|
||||
delayTime: opts["tac_delayTime"],
|
||||
useWildcards: opts["tac_useWildcards"],
|
||||
useEmbeddings: opts["tac_useEmbeddings"],
|
||||
showWikiLinks: opts["tac_showWikiLinks"],
|
||||
// Insertion related settings
|
||||
replaceUnderscores: opts["tac_replaceUnderscores"],
|
||||
escapeParentheses: opts["tac_escapeParentheses"],
|
||||
@@ -256,6 +266,30 @@ function hideResults(textArea) {
|
||||
selectedTag = null;
|
||||
}
|
||||
|
||||
var currentModelHash = "";
|
||||
var currentModelName = "";
|
||||
// Function to check activation criteria
|
||||
function isEnabled() {
|
||||
if (CFG.activeIn.global) {
|
||||
let modelList = CFG.activeIn.modelList
|
||||
.split(",")
|
||||
.map(x => x.trim())
|
||||
.filter(x => x.length > 0);
|
||||
|
||||
let shortHash = currentModelHash.substring(0, 10);
|
||||
if (CFG.activeIn.modelListMode.toLowerCase() === "blacklist") {
|
||||
// If the current model is in the blacklist, disable
|
||||
return modelList.filter(x => x === currentModelName || x === currentModelHash || x === shortHash).length === 0;
|
||||
} else {
|
||||
// If the current model is in the whitelist, enable.
|
||||
// An empty whitelist is ignored.
|
||||
return modelList.length === 0 || modelList.filter(x => x === currentModelName || x === currentModelHash || x === shortHash).length > 0;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const WEIGHT_REGEX = /[([]([^,()[\]:| ]+)(?::(?:\d+(?:\.\d+)?|\.\d+))?[)\]]/g;
|
||||
const TAG_REGEX = /(<[^\t\n\r,>]+>?|[^\s,|<>]+|<)/g
|
||||
const WC_REGEX = /\b__([^, ]+)__([^, ]*)\b/g;
|
||||
@@ -383,7 +417,6 @@ function addResultsToList(textArea, results, tagword, resetList) {
|
||||
|
||||
let itemText = document.createElement("div");
|
||||
itemText.classList.add("acListItem");
|
||||
flexDiv.appendChild(itemText);
|
||||
|
||||
let displayText = "";
|
||||
// If the tag matches the tagword, we don't need to display the alias
|
||||
@@ -421,6 +454,33 @@ function addResultsToList(textArea, results, tagword, resetList) {
|
||||
// Print search term bolded in result
|
||||
itemText.innerHTML = displayText.replace(tagword, `<b>${tagword}</b>`);
|
||||
|
||||
// Add wiki link if the setting is enabled and a supported tag set loaded
|
||||
if (CFG.showWikiLinks
|
||||
&& (result.type === ResultType.tag)
|
||||
&& (tagFileName.toLowerCase().startsWith("danbooru") || tagFileName.toLowerCase().startsWith("e621"))) {
|
||||
let wikiLink = document.createElement("a");
|
||||
wikiLink.classList.add("acWikiLink");
|
||||
wikiLink.innerText = "?";
|
||||
|
||||
let linkPart = displayText;
|
||||
// Only use alias result if it is one
|
||||
if (displayText.includes("➝"))
|
||||
linkPart = displayText.split(" ➝ ")[1];
|
||||
|
||||
// Set link based on selected file
|
||||
let tagFileNameLower = tagFileName.toLowerCase();
|
||||
if (tagFileNameLower.startsWith("danbooru")) {
|
||||
wikiLink.href = `https://danbooru.donmai.us/wiki_pages/${linkPart}`;
|
||||
} else if (tagFileNameLower.startsWith("e621")) {
|
||||
wikiLink.href = `https://e621.net/wiki_pages/${linkPart}`;
|
||||
}
|
||||
|
||||
wikiLink.target = "_blank";
|
||||
flexDiv.appendChild(wikiLink);
|
||||
}
|
||||
|
||||
flexDiv.appendChild(itemText);
|
||||
|
||||
// Add post count & color if it's a tag
|
||||
// Wildcards & Embeds have no tag category
|
||||
if (![ResultType.wildcardFile, ResultType.wildcardTag, ResultType.embedding].includes(result.type)) {
|
||||
@@ -436,7 +496,7 @@ function addResultsToList(textArea, results, tagword, resetList) {
|
||||
if (!colorGroup[cat])
|
||||
cat = "-1";
|
||||
|
||||
itemText.style = `color: ${colorGroup[cat][mode]};`;
|
||||
flexDiv.style = `color: ${colorGroup[cat][mode]};`;
|
||||
}
|
||||
|
||||
// Post count
|
||||
@@ -514,11 +574,13 @@ var originalTagword = "";
|
||||
var resultCount = 0;
|
||||
async function autocomplete(textArea, prompt, fixedTag = null) {
|
||||
// Return if the function is deactivated in the UI
|
||||
if (!CFG.activeIn.global) return;
|
||||
if (!isEnabled()) return;
|
||||
|
||||
// Guard for empty prompt
|
||||
if (prompt.length === 0) {
|
||||
hideResults(textArea);
|
||||
previousTags = [];
|
||||
tagword = "";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -533,6 +595,14 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
||||
.concat(weightedTags);
|
||||
}
|
||||
|
||||
// Guard for no tags
|
||||
if (!tags || tags.length === 0) {
|
||||
previousTags = [];
|
||||
tagword = "";
|
||||
hideResults(textArea);
|
||||
return;
|
||||
}
|
||||
|
||||
let tagCountChange = tags.length - previousTags.length;
|
||||
let diff = difference(tags, previousTags);
|
||||
previousTags = tags;
|
||||
@@ -859,8 +929,8 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
||||
|
||||
var oldSelectedTag = null;
|
||||
function navigateInList(textArea, event) {
|
||||
// Return if the function is deactivated in the UI
|
||||
if (!CFG.activeIn.global) return;
|
||||
// Return if the function is deactivated in the UI or the current model is excluded due to white/blacklist settings
|
||||
if (!isEnabled()) return;
|
||||
|
||||
validKeys = ["ArrowUp", "ArrowDown", "PageUp", "PageDown", "Home", "End", "Enter", "Tab", "Escape"];
|
||||
|
||||
@@ -1033,6 +1103,28 @@ async function setup() {
|
||||
});
|
||||
});
|
||||
|
||||
// Add change listener to model dropdown to react to model changes
|
||||
let modelDropdown = gradioApp().querySelector("#setting_sd_model_checkpoint select");
|
||||
currentModelName = modelDropdown.value;
|
||||
modelDropdown.addEventListener("change", () => {
|
||||
setTimeout(() => {
|
||||
currentModelName = modelDropdown.value;
|
||||
}, 100);
|
||||
});
|
||||
// Add mutation observer for the model hash text to also allow hash-based blacklist again
|
||||
let modelHashText = gradioApp().querySelector("#sd_checkpoint_hash");
|
||||
if (modelHashText) {
|
||||
currentModelHash = modelHashText.title
|
||||
let modelHashObserver = new MutationObserver((mutationList, observer) => {
|
||||
for (const mutation of mutationList) {
|
||||
if (mutation.type === "attributes" && mutation.attributeName === "title") {
|
||||
currentModelHash = mutation.target.title;
|
||||
}
|
||||
}
|
||||
});
|
||||
modelHashObserver.observe(modelHashText, { attributes: true });
|
||||
}
|
||||
|
||||
// Not found, we're on a page without prompt textareas
|
||||
if (textAreas.every(v => v === null || v === undefined)) return;
|
||||
// Already added or unnecessary to add
|
||||
|
||||
@@ -215,6 +215,8 @@ def on_ui_settings():
|
||||
shared.opts.add_option("tac_activeIn.img2img", shared.OptionInfo(True, "Active in img2img (Requires restart)", section=TAC_SECTION))
|
||||
shared.opts.add_option("tac_activeIn.negativePrompts", shared.OptionInfo(True, "Active in negative prompts (Requires restart)", section=TAC_SECTION))
|
||||
shared.opts.add_option("tac_activeIn.thirdParty", shared.OptionInfo(True, "Active in third party textboxes [Dataset Tag Editor] (Requires restart)", section=TAC_SECTION))
|
||||
shared.opts.add_option("tac_activeIn.modelList", shared.OptionInfo("", "List of model names (with file extension) or their hashes to use as black/whitelist, separated by commas.", section=TAC_SECTION))
|
||||
shared.opts.add_option("tac_activeIn.modelListMode", shared.OptionInfo("Blacklist", "Mode to use for model list", gr.Dropdown, lambda: {"choices": ["Blacklist","Whitelist"]}, section=TAC_SECTION))
|
||||
# Results related settings
|
||||
shared.opts.add_option("tac_maxResults", shared.OptionInfo(5, "Maximum results", section=TAC_SECTION))
|
||||
shared.opts.add_option("tac_showAllResults", shared.OptionInfo(False, "Show all results", section=TAC_SECTION))
|
||||
@@ -222,6 +224,7 @@ def on_ui_settings():
|
||||
shared.opts.add_option("tac_delayTime", shared.OptionInfo(100, "Time in ms to wait before triggering completion again (Requires restart)", section=TAC_SECTION))
|
||||
shared.opts.add_option("tac_useWildcards", shared.OptionInfo(True, "Search for wildcards", section=TAC_SECTION))
|
||||
shared.opts.add_option("tac_useEmbeddings", shared.OptionInfo(True, "Search for embeddings", section=TAC_SECTION))
|
||||
shared.opts.add_option("tac_showWikiLinks", shared.OptionInfo(False, "Show '?' next to tags, linking to its Danbooru or e621 wiki page (Warning: This is an external site and very likely contains NSFW examples!)", section=TAC_SECTION))
|
||||
# Insertion related settings
|
||||
shared.opts.add_option("tac_replaceUnderscores", shared.OptionInfo(True, "Replace underscores with spaces on insertion", section=TAC_SECTION))
|
||||
shared.opts.add_option("tac_escapeParentheses", shared.OptionInfo(True, "Escape parentheses on insertion", section=TAC_SECTION))
|
||||
|
||||
Reference in New Issue
Block a user