Compare commits

...

4 Commits

Author SHA1 Message Date
Dominik Reh
bec222f2b3 Fix for 1-letter completion
Completion would sometimes not show if the prompt was only one letter long and identical to the previous completion
2023-01-12 15:54:57 +01:00
Dominik Reh
d4db6a7907 Option to show ? wiki links for danbooru/e621 tags
Disabled by default since the wiki pages likely contain NSFW images.
Closes #109
2023-01-12 15:49:53 +01:00
Dominik Reh
52593e6ac8 Update setting descriptions for black/whitelist 2023-01-12 14:45:16 +01:00
Dominik Reh
849e346924 Black/whitelisting options for models
Enables selective (de)activation based on model hash.
Closes #14
2023-01-12 14:35:54 +01:00
2 changed files with 84 additions and 6 deletions

View File

@@ -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,11 +266,34 @@ function hideResults(textArea) {
selectedTag = null;
}
var currentModelHash = "";
// 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);
if (CFG.activeIn.modelListMode.toLowerCase() === "blacklist") {
// If the current model is in the blacklist, disable
return !modelList.includes(currentModelHash);
} else {
// If the current model is in the whitelist, enable.
// An empty whitelist is ignored.
return modelList.length === 0 || modelList.includes(currentModelHash);
}
} else {
return false;
}
}
const WEIGHT_REGEX = /[([]([^,()[\]:| ]+)(?::(?:\d+(?:\.\d+)?|\.\d+))?[)\]]/g;
const TAG_REGEX = /(<[^\t\n\r,>]+>?|[^\s,|<>]+|<)/g
const WC_REGEX = /\b__([^, ]+)__([^, ]*)\b/g;
const UMI_PROMPT_REGEX = /<[^\s]*?\[[^,<>]*[\]|]?>?/gi;
const UMI_TAG_REGEX = /(?:\[|\||--)([^<>\[\]\-|]+)/gi;
const MODEL_HASH_REGEX = /\[(.+)\]/g;
let hideBlocked = false;
// On click, insert the tag into the prompt textbox with respect to the cursor position
@@ -383,7 +416,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 +453,31 @@ 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 && (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 +493,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 +571,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 +592,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 +926,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"];
@@ -1032,6 +1099,14 @@ async function setup() {
}, 500);
});
});
// Add change listener to model dropdown to react to model changes
let modelDropdown = gradioApp().querySelector("#setting_sd_model_checkpoint select");
currentModelHash = [...modelDropdown.value.matchAll(MODEL_HASH_REGEX)][0][1]; // Set initial model hash
modelDropdown.addEventListener("change", () => {
setTimeout(() => {
currentModelHash = [...modelDropdown.value.matchAll(MODEL_HASH_REGEX)][0][1];
}, 100);
});
// Not found, we're on a page without prompt textareas
if (textAreas.every(v => v === null || v === undefined)) return;

View File

@@ -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 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 hash 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))