|
|
|
|
@@ -179,26 +179,26 @@ async function syncOptions() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reload translations if the translation file changed
|
|
|
|
|
if (!CFG || newCFG.translation.translationFile !== CFG.translation.translationFile) {
|
|
|
|
|
if (!TAC_CFG || newCFG.translation.translationFile !== TAC_CFG.translation.translationFile) {
|
|
|
|
|
translations.clear();
|
|
|
|
|
await loadTranslations(newCFG);
|
|
|
|
|
await loadExtraTags(newCFG);
|
|
|
|
|
}
|
|
|
|
|
// Reload tags if the tag file changed (after translations so extra tag translations get re-added)
|
|
|
|
|
if (!CFG || newCFG.tagFile !== CFG.tagFile || newCFG.extra.extraFile !== CFG.extra.extraFile) {
|
|
|
|
|
if (!TAC_CFG || newCFG.tagFile !== TAC_CFG.tagFile || newCFG.extra.extraFile !== TAC_CFG.extra.extraFile) {
|
|
|
|
|
allTags = [];
|
|
|
|
|
await loadTags(newCFG);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Update CSS if maxResults changed
|
|
|
|
|
if (CFG && newCFG.maxResults !== CFG.maxResults) {
|
|
|
|
|
if (TAC_CFG && newCFG.maxResults !== TAC_CFG.maxResults) {
|
|
|
|
|
gradioApp().querySelectorAll(".autocompleteResults").forEach(r => {
|
|
|
|
|
r.style.maxHeight = `${newCFG.maxResults * 50}px`;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Apply changes
|
|
|
|
|
CFG = newCFG;
|
|
|
|
|
TAC_CFG = newCFG;
|
|
|
|
|
|
|
|
|
|
// Callback
|
|
|
|
|
await processQueue(QUEUE_AFTER_CONFIG_CHANGE, null);
|
|
|
|
|
@@ -212,7 +212,7 @@ function createResultsDiv(textArea) {
|
|
|
|
|
let textAreaId = getTextAreaIdentifier(textArea);
|
|
|
|
|
let typeClass = textAreaId.replaceAll(".", " ");
|
|
|
|
|
|
|
|
|
|
resultsDiv.style.maxHeight = `${CFG.maxResults * 50}px`;
|
|
|
|
|
resultsDiv.style.maxHeight = `${TAC_CFG.maxResults * 50}px`;
|
|
|
|
|
resultsDiv.setAttribute("class", `autocompleteResults ${typeClass} notranslate`);
|
|
|
|
|
resultsDiv.setAttribute("translate", "no");
|
|
|
|
|
resultsList.setAttribute("class", "autocompleteResultsList");
|
|
|
|
|
@@ -232,7 +232,7 @@ function showResults(textArea) {
|
|
|
|
|
let resultsDiv = gradioApp().querySelector('.autocompleteResults' + textAreaId);
|
|
|
|
|
resultsDiv.style.display = "block";
|
|
|
|
|
|
|
|
|
|
if (CFG.slidingPopup) {
|
|
|
|
|
if (TAC_CFG.slidingPopup) {
|
|
|
|
|
let caretPosition = getCaretCoordinates(textArea, textArea.selectionEnd).left;
|
|
|
|
|
let offset = Math.min(textArea.offsetLeft - textArea.scrollLeft + caretPosition, textArea.offsetWidth - resultsDiv.offsetWidth);
|
|
|
|
|
|
|
|
|
|
@@ -254,18 +254,18 @@ function hideResults(textArea) {
|
|
|
|
|
|
|
|
|
|
// Function to check activation criteria
|
|
|
|
|
function isEnabled() {
|
|
|
|
|
if (CFG.activeIn.global) {
|
|
|
|
|
if (TAC_CFG.activeIn.global) {
|
|
|
|
|
// Skip check if the current model was not correctly detected, since it could wrongly disable the script otherwise
|
|
|
|
|
if (!currentModelName || !currentModelHash) return true;
|
|
|
|
|
|
|
|
|
|
let modelList = CFG.activeIn.modelList
|
|
|
|
|
let modelList = TAC_CFG.activeIn.modelList
|
|
|
|
|
.split(",")
|
|
|
|
|
.map(x => x.trim())
|
|
|
|
|
.filter(x => x.length > 0);
|
|
|
|
|
|
|
|
|
|
let shortHash = currentModelHash.substring(0, 10);
|
|
|
|
|
let modelNameWithoutHash = currentModelName.replace(/\[.*\]$/g, "").trim();
|
|
|
|
|
if (CFG.activeIn.modelListMode.toLowerCase() === "blacklist") {
|
|
|
|
|
if (TAC_CFG.activeIn.modelListMode.toLowerCase() === "blacklist") {
|
|
|
|
|
// If the current model is in the blacklist, disable
|
|
|
|
|
return modelList.filter(x => x === currentModelName || x === modelNameWithoutHash || x === currentModelHash || x === shortHash).length === 0;
|
|
|
|
|
} else {
|
|
|
|
|
@@ -298,9 +298,9 @@ async function insertTextAtCursor(textArea, result, tagword) {
|
|
|
|
|
if (sanitizeResults && sanitizeResults.length > 0) {
|
|
|
|
|
sanitizedText = sanitizeResults[0];
|
|
|
|
|
} else {
|
|
|
|
|
sanitizedText = CFG.replaceUnderscores ? text.replaceAll("_", " ") : text;
|
|
|
|
|
sanitizedText = TAC_CFG.replaceUnderscores ? text.replaceAll("_", " ") : text;
|
|
|
|
|
|
|
|
|
|
if (CFG.escapeParentheses && tagType === ResultType.tag) {
|
|
|
|
|
if (TAC_CFG.escapeParentheses && tagType === ResultType.tag) {
|
|
|
|
|
sanitizedText = sanitizedText
|
|
|
|
|
.replaceAll("(", "\\(")
|
|
|
|
|
.replaceAll(")", "\\)")
|
|
|
|
|
@@ -321,11 +321,11 @@ async function insertTextAtCursor(textArea, result, tagword) {
|
|
|
|
|
var optionalSeparator = "";
|
|
|
|
|
let extraNetworkTypes = [ResultType.hypernetwork, ResultType.lora];
|
|
|
|
|
let noCommaTypes = [ResultType.wildcardFile, ResultType.yamlWildcard].concat(extraNetworkTypes);
|
|
|
|
|
if (CFG.appendComma && !noCommaTypes.includes(tagType)) {
|
|
|
|
|
if (TAC_CFG.appendComma && !noCommaTypes.includes(tagType)) {
|
|
|
|
|
optionalSeparator = surrounding.match(new RegExp(`${escapeRegExp(tagword)}[,:]`, "i")) !== null ? "" : ", ";
|
|
|
|
|
} else if (extraNetworkTypes.includes(tagType)) {
|
|
|
|
|
// Use the dedicated separator for extra networks if it's defined, otherwise fall back to space
|
|
|
|
|
optionalSeparator = CFG.extraNetworksSeparator || " ";
|
|
|
|
|
optionalSeparator = TAC_CFG.extraNetworksSeparator || " ";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Replace partial tag word with new text, add comma if needed
|
|
|
|
|
@@ -377,10 +377,10 @@ function addResultsToList(textArea, results, tagword, resetList) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Find right colors from config
|
|
|
|
|
let tagFileName = CFG.tagFile.split(".")[0];
|
|
|
|
|
let tagColors = CFG.colorMap;
|
|
|
|
|
let tagFileName = TAC_CFG.tagFile.split(".")[0];
|
|
|
|
|
let tagColors = TAC_CFG.colorMap;
|
|
|
|
|
let mode = (document.querySelector(".dark") || gradioApp().querySelector(".dark")) ? 0 : 1;
|
|
|
|
|
let nextLength = Math.min(results.length, resultCount + CFG.resultStepLength);
|
|
|
|
|
let nextLength = Math.min(results.length, resultCount + TAC_CFG.resultStepLength);
|
|
|
|
|
|
|
|
|
|
for (let i = resultCount; i < nextLength; i++) {
|
|
|
|
|
let result = results[i];
|
|
|
|
|
@@ -421,7 +421,7 @@ function addResultsToList(textArea, results, tagword, resetList) {
|
|
|
|
|
if (translations.has(bestAlias) && translations.get(bestAlias) !== bestAlias && bestAlias !== result.text)
|
|
|
|
|
displayText += `[${translations.get(bestAlias)}]`;
|
|
|
|
|
|
|
|
|
|
if (!CFG.alias.onlyShowAlias && result.text !== bestAlias)
|
|
|
|
|
if (!TAC_CFG.alias.onlyShowAlias && result.text !== bestAlias)
|
|
|
|
|
displayText += " ➝ " + result.text;
|
|
|
|
|
} else { // No alias
|
|
|
|
|
displayText = escapeHTML(result.text);
|
|
|
|
|
@@ -435,7 +435,7 @@ function addResultsToList(textArea, results, tagword, resetList) {
|
|
|
|
|
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
|
|
|
|
|
if (TAC_CFG.showWikiLinks
|
|
|
|
|
&& (result.type === ResultType.tag)
|
|
|
|
|
&& (tagFileName.toLowerCase().startsWith("danbooru") || tagFileName.toLowerCase().startsWith("e621"))) {
|
|
|
|
|
let wikiLink = document.createElement("a");
|
|
|
|
|
@@ -538,7 +538,7 @@ function updateSelectionStyle(textArea, newIndex, oldIndex) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set scrolltop to selected item if we are showing more than max results
|
|
|
|
|
if (items.length > CFG.maxResults) {
|
|
|
|
|
if (items.length > TAC_CFG.maxResults) {
|
|
|
|
|
let selected = items[newIndex];
|
|
|
|
|
resultDiv.scrollTop = selected.offsetTop - resultDiv.offsetTop;
|
|
|
|
|
}
|
|
|
|
|
@@ -621,7 +621,7 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
|
|
|
|
} else {
|
|
|
|
|
searchRegex = new RegExp(`(^|[^a-zA-Z])${escapeRegExp(tagword)}`, 'i');
|
|
|
|
|
}
|
|
|
|
|
let genericResults = allTags.filter(x => x[0].toLowerCase().search(searchRegex) > -1).slice(0, CFG.maxResults);
|
|
|
|
|
let genericResults = allTags.filter(x => x[0].toLowerCase().search(searchRegex) > -1).slice(0, TAC_CFG.maxResults);
|
|
|
|
|
|
|
|
|
|
genericResults.forEach(g => {
|
|
|
|
|
let result = new AutocompleteResult(g[0].trim(), ResultType.tag)
|
|
|
|
|
@@ -649,11 +649,11 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
|
|
|
|
|| x[3] && x[3].split(",").some(y => translations.has(y) && translations.get(y).toLowerCase().search(searchRegex) > -1);
|
|
|
|
|
|
|
|
|
|
let fil;
|
|
|
|
|
if (CFG.alias.searchByAlias && CFG.translation.searchByTranslation)
|
|
|
|
|
if (TAC_CFG.alias.searchByAlias && TAC_CFG.translation.searchByTranslation)
|
|
|
|
|
fil = (x) => baseFilter(x) || aliasFilter(x) || translationFilter(x);
|
|
|
|
|
else if (CFG.alias.searchByAlias && !CFG.translation.searchByTranslation)
|
|
|
|
|
else if (TAC_CFG.alias.searchByAlias && !TAC_CFG.translation.searchByTranslation)
|
|
|
|
|
fil = (x) => baseFilter(x) || aliasFilter(x);
|
|
|
|
|
else if (CFG.translation.searchByTranslation && !CFG.alias.searchByAlias)
|
|
|
|
|
else if (TAC_CFG.translation.searchByTranslation && !TAC_CFG.alias.searchByAlias)
|
|
|
|
|
fil = (x) => baseFilter(x) || translationFilter(x);
|
|
|
|
|
else
|
|
|
|
|
fil = (x) => baseFilter(x);
|
|
|
|
|
@@ -668,7 +668,7 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Add extras
|
|
|
|
|
if (CFG.extra.extraFile) {
|
|
|
|
|
if (TAC_CFG.extra.extraFile) {
|
|
|
|
|
let extraResults = [];
|
|
|
|
|
|
|
|
|
|
extras.filter(fil).forEach(e => {
|
|
|
|
|
@@ -679,7 +679,7 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
|
|
|
|
extraResults.push(result);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (CFG.extra.addMode === "Insert before") {
|
|
|
|
|
if (TAC_CFG.extra.addMode === "Insert before") {
|
|
|
|
|
results = extraResults.concat(results);
|
|
|
|
|
} else {
|
|
|
|
|
results = results.concat(extraResults);
|
|
|
|
|
@@ -687,8 +687,8 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Slice if the user has set a max result count
|
|
|
|
|
if (!CFG.showAllResults) {
|
|
|
|
|
results = results.slice(0, CFG.maxResults);
|
|
|
|
|
if (!TAC_CFG.showAllResults) {
|
|
|
|
|
results = results.slice(0, TAC_CFG.maxResults);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -707,7 +707,7 @@ function navigateInList(textArea, event) {
|
|
|
|
|
// Return if the function is deactivated in the UI or the current model is excluded due to white/blacklist settings
|
|
|
|
|
if (!isEnabled()) return;
|
|
|
|
|
|
|
|
|
|
let keys = CFG.keymap;
|
|
|
|
|
let keys = TAC_CFG.keymap;
|
|
|
|
|
|
|
|
|
|
// Close window if Home or End is pressed while not a keybinding, since it would break completion on leaving the original tag
|
|
|
|
|
if ((event.key === "Home" || event.key === "End") && !Object.values(keys).includes(event.key)) {
|
|
|
|
|
@@ -795,10 +795,10 @@ function navigateInList(textArea, event) {
|
|
|
|
|
function addAutocompleteToArea(area) {
|
|
|
|
|
// Return if autocomplete is disabled for the current area type in config
|
|
|
|
|
let textAreaId = getTextAreaIdentifier(area);
|
|
|
|
|
if ((!CFG.activeIn.img2img && textAreaId.includes("img2img"))
|
|
|
|
|
|| (!CFG.activeIn.txt2img && textAreaId.includes("txt2img"))
|
|
|
|
|
|| (!CFG.activeIn.negativePrompts && textAreaId.includes("n"))
|
|
|
|
|
|| (!CFG.activeIn.thirdParty && textAreaId.includes("thirdParty"))) {
|
|
|
|
|
if ((!TAC_CFG.activeIn.img2img && textAreaId.includes("img2img"))
|
|
|
|
|
|| (!TAC_CFG.activeIn.txt2img && textAreaId.includes("txt2img"))
|
|
|
|
|
|| (!TAC_CFG.activeIn.negativePrompts && textAreaId.includes("n"))
|
|
|
|
|
|| (!TAC_CFG.activeIn.thirdParty && textAreaId.includes("thirdParty"))) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -811,7 +811,7 @@ function addAutocompleteToArea(area) {
|
|
|
|
|
hideResults(area);
|
|
|
|
|
|
|
|
|
|
// Add autocomplete event listener
|
|
|
|
|
area.addEventListener('input', debounce(() => autocomplete(area, area.value), CFG.delayTime));
|
|
|
|
|
area.addEventListener('input', debounce(() => autocomplete(area, area.value), TAC_CFG.delayTime));
|
|
|
|
|
// Add focusout event listener
|
|
|
|
|
area.addEventListener('focusout', debounce(() => hideResults(area), 400));
|
|
|
|
|
// Add up and down arrow event listener
|
|
|
|
|
@@ -878,10 +878,10 @@ async function setup() {
|
|
|
|
|
if (textAreas.every(v => v === null || v === undefined)) return;
|
|
|
|
|
// Already added or unnecessary to add
|
|
|
|
|
if (gradioApp().querySelector('.autocompleteResults.p')) {
|
|
|
|
|
if (gradioApp().querySelector('.autocompleteResults.n') || !CFG.activeIn.negativePrompts) {
|
|
|
|
|
if (gradioApp().querySelector('.autocompleteResults.n') || !TAC_CFG.activeIn.negativePrompts) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
} else if (!CFG.activeIn.txt2img && !CFG.activeIn.img2img) {
|
|
|
|
|
} else if (!TAC_CFG.activeIn.txt2img && !TAC_CFG.activeIn.img2img) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -912,17 +912,17 @@ async function setup() {
|
|
|
|
|
// Callback
|
|
|
|
|
await processQueue(QUEUE_AFTER_SETUP, null);
|
|
|
|
|
}
|
|
|
|
|
let loading = false;
|
|
|
|
|
var tacLoading = false;
|
|
|
|
|
onUiUpdate(async () => {
|
|
|
|
|
if (loading) return;
|
|
|
|
|
if (tacLoading) return;
|
|
|
|
|
if (Object.keys(opts).length === 0) return;
|
|
|
|
|
if (CFG) return;
|
|
|
|
|
loading = true;
|
|
|
|
|
if (TAC_CFG) return;
|
|
|
|
|
tacLoading = true;
|
|
|
|
|
// Get our tag base path from the temp file
|
|
|
|
|
tagBasePath = await readFile(`tmp/tagAutocompletePath.txt`);
|
|
|
|
|
// Load config from webui opts
|
|
|
|
|
await syncOptions();
|
|
|
|
|
// Rest of setup
|
|
|
|
|
setup();
|
|
|
|
|
loading = false;
|
|
|
|
|
tacLoading = false;
|
|
|
|
|
});
|
|
|
|
|
|