From ae01f41f303a3e1f30ab0a0108dee790c4117d3f Mon Sep 17 00:00:00 2001 From: JM <71126090+Mulet-J@users.noreply.github.com> Date: Sun, 22 Jan 2023 19:24:59 +0100 Subject: [PATCH 1/5] add support for hypernetworks and lora --- javascript/_result.js | 4 +- javascript/tagAutocomplete.js | 115 ++++++++++++++++++++++++++++- scripts/tag_autocomplete_helper.py | 34 +++++++++ 3 files changed, 149 insertions(+), 4 deletions(-) diff --git a/javascript/_result.js b/javascript/_result.js index dbd0f29..5556caa 100644 --- a/javascript/_result.js +++ b/javascript/_result.js @@ -6,7 +6,9 @@ const ResultType = Object.freeze({ "embedding": 2, "wildcardTag": 3, "wildcardFile": 4, - "yamlWildcard": 5 + "yamlWildcard": 5, + "hypernetworks": 6, + "lora": 7 }); // Class to hold result data and annotations to make it clearer to use diff --git a/javascript/tagAutocomplete.js b/javascript/tagAutocomplete.js index a9e93f2..503fb0e 100644 --- a/javascript/tagAutocomplete.js +++ b/javascript/tagAutocomplete.js @@ -314,6 +314,10 @@ function insertTextAtCursor(textArea, result, tagword) { sanitizedText = text.replaceAll("_", " "); // Replace underscores only if the yaml tag is not using them } else if (tagType === ResultType.embedding) { sanitizedText = `${text.replace(/^.*?: /g, "")}`; + } else if (tagType === ResultType.hypernetworks) { + sanitizedText = ``; + } else if(tagType === ResultType.lora) { + sanitizedText = ``; } else { sanitizedText = CFG.replaceUnderscores ? text.replaceAll("_", " ") : text; } @@ -568,6 +572,8 @@ var wildcardExtFiles = []; var yamlWildcards = []; var umiPreviousTags = []; var embeddings = []; +var hypernetworks = []; +var lora = []; var results = []; var tagword = ""; var originalTagword = ""; @@ -831,11 +837,11 @@ async function autocomplete(textArea, prompt, fixedTag = null) { originalTagword = tagword; tagword = ""; } - } else if (CFG.useEmbeddings && tagword.match(/<[^,> ]*>?/g)) { + } else if (CFG.useEmbeddings && tagword.match(/ ]*>?/g)) { // Show embeddings let tempResults = []; - if (tagword !== "<") { - let searchTerm = tagword.replace("<", "") + if (tagword !== " ]*>?/g)) { + // Show hypernetworks + let tempResults = []; + if (tagword !== " x[0].toLowerCase().includes(searchTerm) && x[1] && x[1] === versionString); // Filter by tagword + else + tempResults = hypernetworks.filter(x => x[0].toLowerCase().includes(searchTerm)); // Filter by tagword + } else { + tempResults = hypernetworks; + } + // Since some tags are kaomoji, we have to still get the normal results first. + // Create escaped search regex with support for * as a start placeholder + let searchRegex; + if (tagword.startsWith("*")) { + tagword = tagword.slice(1); + searchRegex = new RegExp(`${escapeRegExp(tagword)}`, 'i'); + } 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); + + // Add final results + tempResults.forEach(t => { + let result = new AutocompleteResult(t[0].trim(), ResultType.hypernetworks) + result.meta = t[1] + " Hypernetworks"; + results.push(result); + }); + genericResults.forEach(g => { + let result = new AutocompleteResult(g[0].trim(), ResultType.tag) + result.category = g[1]; + result.count = g[2]; + result.aliases = g[3]; + results.push(result); + }); + } else if(tagword.match(/ ]*>?/g)){ + // Show lora + let tempResults = []; + if (tagword !== " x[0].toLowerCase().includes(searchTerm) && x[1] && x[1] === versionString); // Filter by tagword + else + tempResults = lora.filter(x => x[0].toLowerCase().includes(searchTerm)); // Filter by tagword + } else { + tempResults = lora; + } + // Since some tags are kaomoji, we have to still get the normal results first. + // Create escaped search regex with support for * as a start placeholder + let searchRegex; + if (tagword.startsWith("*")) { + tagword = tagword.slice(1); + searchRegex = new RegExp(`${escapeRegExp(tagword)}`, 'i'); + } 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); + + // Add final results + tempResults.forEach(t => { + let result = new AutocompleteResult(t[0].trim(), ResultType.lora) + result.meta = t[1] + " Lora"; + results.push(result); + }); + genericResults.forEach(g => { + let result = new AutocompleteResult(g[0].trim(), ResultType.tag) + result.category = g[1]; + result.count = g[2]; + result.aliases = g[3]; + results.push(result); + }); } else { // Create escaped search regex with support for * as a start placeholder let searchRegex; @@ -1080,6 +1169,26 @@ async function setup() { console.error("Error loading embeddings.txt: " + e); } } + // Load hypernetworks + if (hypernetworks.length === 0) { + try { + hypernetworks = (await readFile(`${tagBasePath}/temp/hyp.txt?${new Date().getTime()}`)).split("\n") + .filter(x => x.trim().length > 0) //Remove empty lines + .map(x => x.trim().split(",")); // Split into name, version type pairs + } catch (e) { + console.error("Error loading hypernetworks.txt: " + e); + } + } + // Load lora + if (lora.length === 0) { + try { + lora = (await readFile(`${tagBasePath}/temp/lora.txt?${new Date().getTime()}`)).split("\n") + .filter(x => x.trim().length > 0) // Remove empty lines + .map(x => x.trim().split(",")); // Split into name, version type pairs + } catch (e) { + console.error("Error loading lora.txt: " + e); + } + } // Find all textareas let textAreas = getTextAreas(); diff --git a/scripts/tag_autocomplete_helper.py b/scripts/tag_autocomplete_helper.py index 1ef751d..1a672ce 100644 --- a/scripts/tag_autocomplete_helper.py +++ b/scripts/tag_autocomplete_helper.py @@ -20,6 +20,8 @@ # The path to the folder containing the wildcards and embeddings WILDCARD_PATH = FILE_DIR.joinpath('scripts/wildcards') EMB_PATH = Path(shared.cmd_opts.embeddings_dir) +LORA_PATH = Path(shared.cmd_opts.lora_dir) +HYP_PATH = Path(shared.cmd_opts.hypernetwork_dir) def find_ext_wildcard_paths(): @@ -137,6 +139,36 @@ def get_embeddings(sd_model): write_to_temp_file('emb.txt', results) +def get_hypernetworks(sd_model): + """Write a list of all hypernetworks""" + + results = [] + + # Get a list of all hypernetworks in the folder + all_hypernetworks = [str(h.relative_to(HYP_PATH)) for h in HYP_PATH.rglob("*") if h.suffix in {".pt"}] + # Remove files with a size of 0 + all_hypernetworks = [h for h in all_hypernetworks if HYP_PATH.joinpath(h).stat().st_size > 0] + # Remove file extensions + all_hypernetworks = [h[:h.rfind('.')] for h in all_hypernetworks] + results = [h + "," for h in all_hypernetworks] + + write_to_temp_file('hyp.txt', results) + +def get_lora(sd_model): + """Write a list of all lora""" + + results = [] + + # Get a list of all lora in the folder + all_lora = [str(l.relative_to(LORA_PATH)) for l in LORA_PATH.rglob("*") if l.suffix in {".safetensors"}] + # Remove files with a size of 0 + all_lora = [l for l in all_lora if LORA_PATH.joinpath(l).stat().st_size > 0] + # Remove file extensions + all_lora = [l[:l.rfind('.')] for l in all_lora] + results = [l + "," for l in all_lora] + + write_to_temp_file('lora.txt', results) + def write_tag_base_path(): """Writes the tag base path to a fixed location temporary file""" @@ -202,6 +234,8 @@ def update_tag_files(): if EMB_PATH.exists(): # Get embeddings after the model loaded callback script_callbacks.on_model_loaded(get_embeddings) + script_callbacks.on_model_loaded(get_hypernetworks) + script_callbacks.on_model_loaded(get_lora) # Register autocomplete options From b29b496b88207efbfcc7bb469d841ccfbb6516ae Mon Sep 17 00:00:00 2001 From: Dominik Reh Date: Tue, 24 Jan 2023 14:08:11 +0100 Subject: [PATCH 2/5] Simplify lora and hypernetwork loading --- javascript/_result.js | 2 +- javascript/tagAutocomplete.js | 68 ++++-------------------------- scripts/tag_autocomplete_helper.py | 43 +++++++++---------- 3 files changed, 29 insertions(+), 84 deletions(-) diff --git a/javascript/_result.js b/javascript/_result.js index 5556caa..4799e81 100644 --- a/javascript/_result.js +++ b/javascript/_result.js @@ -7,7 +7,7 @@ const ResultType = Object.freeze({ "wildcardTag": 3, "wildcardFile": 4, "yamlWildcard": 5, - "hypernetworks": 6, + "hypernetwork": 6, "lora": 7 }); diff --git a/javascript/tagAutocomplete.js b/javascript/tagAutocomplete.js index 503fb0e..eb57585 100644 --- a/javascript/tagAutocomplete.js +++ b/javascript/tagAutocomplete.js @@ -314,7 +314,7 @@ function insertTextAtCursor(textArea, result, tagword) { sanitizedText = text.replaceAll("_", " "); // Replace underscores only if the yaml tag is not using them } else if (tagType === ResultType.embedding) { sanitizedText = `${text.replace(/^.*?: /g, "")}`; - } else if (tagType === ResultType.hypernetworks) { + } else if (tagType === ResultType.hypernetwork) { sanitizedText = ``; } else if(tagType === ResultType.lora) { sanitizedText = ``; @@ -573,7 +573,7 @@ var yamlWildcards = []; var umiPreviousTags = []; var embeddings = []; var hypernetworks = []; -var lora = []; +var loras = []; var results = []; var tagword = ""; var originalTagword = ""; @@ -884,69 +884,26 @@ async function autocomplete(textArea, prompt, fixedTag = null) { let tempResults = []; if (tagword !== " x[0].toLowerCase().includes(searchTerm) && x[1] && x[1] === versionString); // Filter by tagword - else - tempResults = hypernetworks.filter(x => x[0].toLowerCase().includes(searchTerm)); // Filter by tagword + tempResults = hypernetworks.filter(x => x[0].toLowerCase().includes(searchTerm)); // Filter by tagword } else { tempResults = hypernetworks; } - // Since some tags are kaomoji, we have to still get the normal results first. - // Create escaped search regex with support for * as a start placeholder - let searchRegex; - if (tagword.startsWith("*")) { - tagword = tagword.slice(1); - searchRegex = new RegExp(`${escapeRegExp(tagword)}`, 'i'); - } 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); // Add final results tempResults.forEach(t => { - let result = new AutocompleteResult(t[0].trim(), ResultType.hypernetworks) + let result = new AutocompleteResult(t[0].trim(), ResultType.hypernetwork) result.meta = t[1] + " Hypernetworks"; results.push(result); }); - genericResults.forEach(g => { - let result = new AutocompleteResult(g[0].trim(), ResultType.tag) - result.category = g[1]; - result.count = g[2]; - result.aliases = g[3]; - results.push(result); - }); } else if(tagword.match(/ ]*>?/g)){ // Show lora let tempResults = []; if (tagword !== " x[0].toLowerCase().includes(searchTerm) && x[1] && x[1] === versionString); // Filter by tagword - else - tempResults = lora.filter(x => x[0].toLowerCase().includes(searchTerm)); // Filter by tagword + tempResults = loras.filter(x => x[0].toLowerCase().includes(searchTerm)); // Filter by tagword } else { - tempResults = lora; + tempResults = loras; } - // Since some tags are kaomoji, we have to still get the normal results first. - // Create escaped search regex with support for * as a start placeholder - let searchRegex; - if (tagword.startsWith("*")) { - tagword = tagword.slice(1); - searchRegex = new RegExp(`${escapeRegExp(tagword)}`, 'i'); - } 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); // Add final results tempResults.forEach(t => { @@ -954,13 +911,6 @@ async function autocomplete(textArea, prompt, fixedTag = null) { result.meta = t[1] + " Lora"; results.push(result); }); - genericResults.forEach(g => { - let result = new AutocompleteResult(g[0].trim(), ResultType.tag) - result.category = g[1]; - result.count = g[2]; - result.aliases = g[3]; - results.push(result); - }); } else { // Create escaped search regex with support for * as a start placeholder let searchRegex; @@ -1174,17 +1124,15 @@ async function setup() { try { hypernetworks = (await readFile(`${tagBasePath}/temp/hyp.txt?${new Date().getTime()}`)).split("\n") .filter(x => x.trim().length > 0) //Remove empty lines - .map(x => x.trim().split(",")); // Split into name, version type pairs } catch (e) { console.error("Error loading hypernetworks.txt: " + e); } } // Load lora - if (lora.length === 0) { + if (loras.length === 0) { try { - lora = (await readFile(`${tagBasePath}/temp/lora.txt?${new Date().getTime()}`)).split("\n") + loras = (await readFile(`${tagBasePath}/temp/lora.txt?${new Date().getTime()}`)).split("\n") .filter(x => x.trim().length > 0) // Remove empty lines - .map(x => x.trim().split(",")); // Split into name, version type pairs } catch (e) { console.error("Error loading lora.txt: " + e); } diff --git a/scripts/tag_autocomplete_helper.py b/scripts/tag_autocomplete_helper.py index 1a672ce..23cabe0 100644 --- a/scripts/tag_autocomplete_helper.py +++ b/scripts/tag_autocomplete_helper.py @@ -139,35 +139,21 @@ def get_embeddings(sd_model): write_to_temp_file('emb.txt', results) -def get_hypernetworks(sd_model): +def get_hypernetworks(): """Write a list of all hypernetworks""" - results = [] - # Get a list of all hypernetworks in the folder - all_hypernetworks = [str(h.relative_to(HYP_PATH)) for h in HYP_PATH.rglob("*") if h.suffix in {".pt"}] - # Remove files with a size of 0 - all_hypernetworks = [h for h in all_hypernetworks if HYP_PATH.joinpath(h).stat().st_size > 0] + all_hypernetworks = [str(h.name) for h in HYP_PATH.rglob("*") if h.suffix in {".pt"}] # Remove file extensions - all_hypernetworks = [h[:h.rfind('.')] for h in all_hypernetworks] - results = [h + "," for h in all_hypernetworks] + return [h[:h.rfind('.')] for h in all_hypernetworks] - write_to_temp_file('hyp.txt', results) - -def get_lora(sd_model): +def get_lora(): """Write a list of all lora""" - results = [] - # Get a list of all lora in the folder - all_lora = [str(l.relative_to(LORA_PATH)) for l in LORA_PATH.rglob("*") if l.suffix in {".safetensors"}] - # Remove files with a size of 0 - all_lora = [l for l in all_lora if LORA_PATH.joinpath(l).stat().st_size > 0] + all_lora = [str(l.name) for l in LORA_PATH.rglob("*") if l.suffix in {".safetensors", ".ckpt", ".pt"}] # Remove file extensions - all_lora = [l[:l.rfind('.')] for l in all_lora] - results = [l + "," for l in all_lora] - - write_to_temp_file('lora.txt', results) + return [l[:l.rfind('.')] for l in all_lora] def write_tag_base_path(): @@ -210,6 +196,8 @@ def update_tag_files(): write_to_temp_file('wc.txt', []) write_to_temp_file('wce.txt', []) write_to_temp_file('wcet.txt', []) +write_to_temp_file('hyp.txt', []) +write_to_temp_file('lora.txt', []) # Only reload embeddings if the file doesn't exist, since they are already re-written on model load if not TEMP_PATH.joinpath("emb.txt").exists(): write_to_temp_file('emb.txt', []) @@ -234,9 +222,16 @@ def update_tag_files(): if EMB_PATH.exists(): # Get embeddings after the model loaded callback script_callbacks.on_model_loaded(get_embeddings) - script_callbacks.on_model_loaded(get_hypernetworks) - script_callbacks.on_model_loaded(get_lora) - + +if HYP_PATH.exists(): + hypernets = get_hypernetworks() + if hypernets: + write_to_temp_file('hyp.txt', hypernets) + +if LORA_PATH.exists(): + lora = get_lora() + if lora: + write_to_temp_file('lora.txt', lora) # Register autocomplete options def on_ui_settings(): @@ -258,6 +253,8 @@ 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_useHypernetworks", shared.OptionInfo(True, "Search for hypernetworks", section=TAC_SECTION)) + shared.opts.add_option("tac_useLora", shared.OptionInfo(True, "Search for Loras", 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)) From 8ab0e2504b020383bea13dfcb91235fda4f8a4a2 Mon Sep 17 00:00:00 2001 From: Dominik Reh Date: Tue, 24 Jan 2023 14:51:55 +0100 Subject: [PATCH 3/5] Fix meta display, add mixed results < will show all three, while = 1000000 || (postCount >= 1000 && postCount < 10000)) - formatter = Intl.NumberFormat("en", { notation: "compact", minimumFractionDigits: 1, maximumFractionDigits: 1 }); - else - formatter = Intl.NumberFormat("en", {notation: "compact"}); - - let formattedCount = formatter.format(postCount); - - let countDiv = document.createElement("div"); - countDiv.textContent = formattedCount; - countDiv.classList.add("acMetaText"); - flexDiv.appendChild(countDiv); - } - } else if (result.meta) { // Check if it is an embedding we have version info for + // Danbooru formats numbers with a padded fraction for 1M or 1k, but not for 10/100k + if (postCount >= 1000000 || (postCount >= 1000 && postCount < 10000)) + formatter = Intl.NumberFormat("en", { notation: "compact", minimumFractionDigits: 1, maximumFractionDigits: 1 }); + else + formatter = Intl.NumberFormat("en", {notation: "compact"}); + + let formattedCount = formatter.format(postCount); + + let countDiv = document.createElement("div"); + countDiv.textContent = formattedCount; + countDiv.classList.add("acMetaText"); + flexDiv.appendChild(countDiv); + } else if (result.meta) { // Check if there is meta info to display let metaDiv = document.createElement("div"); metaDiv.textContent = result.meta; metaDiv.classList.add("acMetaText"); @@ -854,16 +854,6 @@ async function autocomplete(textArea, prompt, fixedTag = null) { } else { tempResults = embeddings; } - // Since some tags are kaomoji, we have to still get the normal results first. - // Create escaped search regex with support for * as a start placeholder - let searchRegex; - if (tagword.startsWith("*")) { - tagword = tagword.slice(1); - searchRegex = new RegExp(`${escapeRegExp(tagword)}`, 'i'); - } 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); // Add final results tempResults.forEach(t => { @@ -871,44 +861,109 @@ async function autocomplete(textArea, prompt, fixedTag = null) { result.meta = t[1] + " Embedding"; results.push(result); }); - genericResults.forEach(g => { - let result = new AutocompleteResult(g[0].trim(), ResultType.tag) - result.category = g[1]; - result.count = g[2]; - result.aliases = g[3]; - results.push(result); - }); - - } else if(tagword.match(/ ]*>?/g)) { + } else if(CFG.useHypernetworks && tagword.match(/ ]*>?/g)) { // Show hypernetworks let tempResults = []; if (tagword !== " x[0].toLowerCase().includes(searchTerm)); // Filter by tagword + tempResults = hypernetworks.filter(x => x.toLowerCase().includes(searchTerm)); // Filter by tagword } else { tempResults = hypernetworks; } // Add final results tempResults.forEach(t => { - let result = new AutocompleteResult(t[0].trim(), ResultType.hypernetwork) - result.meta = t[1] + " Hypernetworks"; + let result = new AutocompleteResult(t.trim(), ResultType.hypernetwork) + result.meta = "Hypernetwork"; results.push(result); }); - } else if(tagword.match(/ ]*>?/g)){ + } else if(CFG.useLoras && tagword.match(/ ]*>?/g)){ // Show lora let tempResults = []; if (tagword !== " x[0].toLowerCase().includes(searchTerm)); // Filter by tagword + tempResults = loras.filter(x => x.toLowerCase().includes(searchTerm)); // Filter by tagword } else { tempResults = loras; } // Add final results tempResults.forEach(t => { - let result = new AutocompleteResult(t[0].trim(), ResultType.lora) - result.meta = t[1] + " Lora"; + let result = new AutocompleteResult(t.trim(), ResultType.lora) + result.meta = "Lora"; + results.push(result); + }); + } else if ((CFG.useEmbeddings || CFG.useHypernetworks || CFG.useLoras) && tagword.match(/<[^,> ]*>?/g)) { + // Embeddings, lora, wildcards all together with generic options + let tempEmbResults = []; + let tempHypResults = []; + let tempLoraResults = []; + if (tagword !== "<") { + let searchTerm = tagword.replace("<", "") + + let versionString; + if (searchTerm.startsWith("v1") || searchTerm.startsWith("v2")) { + versionString = searchTerm.slice(0, 2); + searchTerm = searchTerm.slice(2); + } + + if (versionString && CFG.useEmbeddings) { + // Version string is only for embeddings atm, so we don't search the other lists here. + tempEmbResults = embeddings.filter(x => x[0].toLowerCase().includes(searchTerm) && x[1] && x[1] === versionString); // Filter by tagword + } else { + tempEmbResults = embeddings.filter(x => x[0].toLowerCase().includes(searchTerm)); // Filter by tagword + tempHypResults = hypernetworks.filter(x => x.toLowerCase().includes(searchTerm)); // Filter by tagword + tempLoraResults = loras.filter(x => x.toLowerCase().includes(searchTerm)); // Filter by tagword + } + } else { + tempEmbResults = embeddings; + tempHypResults = hypernetworks; + tempLoraResults = loras; + } + + // Since some tags are kaomoji, we have to still get the normal results first. + // Create escaped search regex with support for * as a start placeholder + let searchRegex; + if (tagword.startsWith("*")) { + tagword = tagword.slice(1); + searchRegex = new RegExp(`${escapeRegExp(tagword)}`, 'i'); + } 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); + + // Add final results + let mixedResults = []; + if (CFG.useEmbeddings) { + tempEmbResults.forEach(t => { + let result = new AutocompleteResult(t[0].trim(), ResultType.embedding) + result.meta = t[1] + " Embedding"; + mixedResults.push(result); + }); + } + if (CFG.useHypernetworks) { + tempHypResults.forEach(t => { + let result = new AutocompleteResult(t.trim(), ResultType.hypernetwork) + result.meta = "Hypernetwork"; + mixedResults.push(result); + }); + } + if (CFG.useLoras) { + tempLoraResults.forEach(t => { + let result = new AutocompleteResult(t.trim(), ResultType.lora) + result.meta = "Lora"; + mixedResults.push(result); + }); + } + + // Add all mixed results to the final results, sorted by name so that they aren't after one another. + results = mixedResults.sort((a, b) => a.text.localeCompare(b.text)); + + genericResults.forEach(g => { + let result = new AutocompleteResult(g[0].trim(), ResultType.tag) + result.category = g[1]; + result.count = g[2]; + result.aliases = g[3]; results.push(result); }); } else { diff --git a/scripts/tag_autocomplete_helper.py b/scripts/tag_autocomplete_helper.py index 23cabe0..e7a48d6 100644 --- a/scripts/tag_autocomplete_helper.py +++ b/scripts/tag_autocomplete_helper.py @@ -254,7 +254,7 @@ def on_ui_settings(): 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_useHypernetworks", shared.OptionInfo(True, "Search for hypernetworks", section=TAC_SECTION)) - shared.opts.add_option("tac_useLora", shared.OptionInfo(True, "Search for Loras", section=TAC_SECTION)) + shared.opts.add_option("tac_useLoras", shared.OptionInfo(True, "Search for Loras", 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)) From 316d45e2facb02c9b2a2730a1d9d328626abce19 Mon Sep 17 00:00:00 2001 From: Dominik Reh Date: Tue, 24 Jan 2023 15:03:35 +0100 Subject: [PATCH 4/5] Use extra network multiplier from settings --- javascript/tagAutocomplete.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/javascript/tagAutocomplete.js b/javascript/tagAutocomplete.js index 76d7dcd..7a84566 100644 --- a/javascript/tagAutocomplete.js +++ b/javascript/tagAutocomplete.js @@ -198,7 +198,9 @@ async function syncOptions() { extra: { extraFile: opts["tac_extra.extraFile"], onlyAliasExtraFile: opts["tac_extra.onlyAliasExtraFile"] - } + }, + // Settings not from tac but still used by the script + extraNetworksDefaultMultiplier: opts["extra_networks_default_multiplier"] } if (CFG && CFG.colors) { @@ -317,9 +319,9 @@ function insertTextAtCursor(textArea, result, tagword) { } else if (tagType === ResultType.embedding) { sanitizedText = `${text.replace(/^.*?: /g, "")}`; } else if (tagType === ResultType.hypernetwork) { - sanitizedText = ``; + sanitizedText = ``; } else if(tagType === ResultType.lora) { - sanitizedText = ``; + sanitizedText = ``; } else { sanitizedText = CFG.replaceUnderscores ? text.replaceAll("_", " ") : text; } From 040be3516290004531fcb268d4311b126b654bd3 Mon Sep 17 00:00:00 2001 From: Dominik Reh Date: Tue, 24 Jan 2023 15:03:56 +0100 Subject: [PATCH 5/5] Don't escape parentheses for loras and hypernets --- javascript/tagAutocomplete.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/tagAutocomplete.js b/javascript/tagAutocomplete.js index 7a84566..de0ca85 100644 --- a/javascript/tagAutocomplete.js +++ b/javascript/tagAutocomplete.js @@ -326,7 +326,7 @@ function insertTextAtCursor(textArea, result, tagword) { sanitizedText = CFG.replaceUnderscores ? text.replaceAll("_", " ") : text; } - if (CFG.escapeParentheses) { + if (CFG.escapeParentheses && tagType === ResultType.tag) { sanitizedText = sanitizedText .replaceAll("(", "\\(") .replaceAll(")", "\\)")