diff --git a/javascript/__globals.js b/javascript/__globals.js index 64df353..ec585e4 100644 --- a/javascript/__globals.js +++ b/javascript/__globals.js @@ -13,6 +13,7 @@ var yamlWildcards = []; var embeddings = []; var hypernetworks = []; var loras = []; +var lycos = []; // Selected model info for black/whitelisting var currentModelHash = ""; diff --git a/javascript/_result.js b/javascript/_result.js index bba990a..7fa5b09 100644 --- a/javascript/_result.js +++ b/javascript/_result.js @@ -9,7 +9,8 @@ const ResultType = Object.freeze({ "wildcardFile": 5, "yamlWildcard": 6, "hypernetwork": 7, - "lora": 8 + "lora": 8, + "lyco": 9 }); // Class to hold result data and annotations to make it clearer to use diff --git a/javascript/ext_lycos.js b/javascript/ext_lycos.js new file mode 100644 index 0000000..4bac510 --- /dev/null +++ b/javascript/ext_lycos.js @@ -0,0 +1,51 @@ +const LYCO_REGEX = /<(?!e:|h:)[^,> ]*>?/g; +const LYCO_TRIGGER = () => CFG.useLycos && tagword.match(LYCO_REGEX); + +class LycoParser extends BaseTagParser { + parse() { + // Show lyco + let tempResults = []; + if (tagword !== "<" && tagword !== " x.toLowerCase().includes(searchTerm) || x.toLowerCase().replaceAll(" ", "_").includes(searchTerm); + tempResults = lycos.filter(x => filterCondition(x)); // Filter by tagword + } else { + tempResults = lycos; + } + + // Add final results + let finalResults = []; + tempResults.forEach(t => { + let result = new AutocompleteResult(t.trim(), ResultType.lyco) + result.meta = "Lyco"; + finalResults.push(result); + }); + + return finalResults; + } +} + +async function load() { + if (lycos.length === 0) { + try { + lycos = (await readFile(`${tagBasePath}/temp/lyco.txt`)).split("\n") + .filter(x => x.trim().length > 0) // Remove empty lines + .map(x => x.trim()); // Remove carriage returns and padding if it exists + } catch (e) { + console.error("Error loading lyco.txt: " + e); + } + } +} + +function sanitize(tagType, text) { + if (tagType === ResultType.lyco) { + return ``; + } + return null; +} + +PARSERS.push(new LycoParser(LYCO_TRIGGER)); + +// Add our utility functions to their respective queues +QUEUE_FILE_LOAD.push(load); +QUEUE_SANITIZE.push(sanitize); \ No newline at end of file diff --git a/javascript/tagAutocomplete.js b/javascript/tagAutocomplete.js index 4c71263..3278604 100644 --- a/javascript/tagAutocomplete.js +++ b/javascript/tagAutocomplete.js @@ -141,6 +141,7 @@ async function syncOptions() { useEmbeddings: opts["tac_useEmbeddings"], useHypernetworks: opts["tac_useHypernetworks"], useLoras: opts["tac_useLoras"], + useLycos: opts["tac_useLycos"], showWikiLinks: opts["tac_showWikiLinks"], // Insertion related settings replaceUnderscores: opts["tac_replaceUnderscores"], diff --git a/scripts/tag_autocomplete_helper.py b/scripts/tag_autocomplete_helper.py index 4bfc1ad..b370c42 100644 --- a/scripts/tag_autocomplete_helper.py +++ b/scripts/tag_autocomplete_helper.py @@ -31,6 +31,11 @@ try: LORA_PATH = Path(shared.cmd_opts.lora_dir) except AttributeError: LORA_PATH = None + +try: + LYCO_PATH = Path(shared.cmd_opts.lyco_dir) +except AttributeError: + LYCO_PATH = None def find_ext_wildcard_paths(): """Returns the path to the extension wildcards folder""" @@ -166,6 +171,13 @@ def get_lora(): # Remove file extensions return sorted([l[:l.rfind('.')] for l in all_lora], key=lambda x: x.lower()) +def get_lyco(): + """Write a list of all LyCORIS/LOHA from https://github.com/KohakuBlueleaf/a1111-sd-webui-lycoris""" + + # Get a list of all LyCORIS in the folder + all_lyco = [str(ly.name) for ly in LYCO_PATH.rglob("*") if ly.suffix in {".safetensors", ".ckpt", ".pt"}] + # Remove file extensions + return sorted([ly[:ly.rfind('.')] for ly in all_lyco], key=lambda x: x.lower()) def write_tag_base_path(): """Writes the tag base path to a fixed location temporary file""" @@ -209,6 +221,7 @@ write_to_temp_file('wce.txt', []) write_to_temp_file('wcet.txt', []) write_to_temp_file('hyp.txt', []) write_to_temp_file('lora.txt', []) +write_to_temp_file('lyco.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', []) @@ -244,6 +257,11 @@ if LORA_PATH is not None and LORA_PATH.exists(): if lora: write_to_temp_file('lora.txt', lora) +if LYCO_PATH is not None and LYCO_PATH.exists(): + lyco = get_lyco() + if lyco: + write_to_temp_file('lyco.txt', lyco) + # Register autocomplete options def on_ui_settings(): TAC_SECTION = ("tac", "Tag Autocomplete") @@ -267,6 +285,7 @@ def on_ui_settings(): 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_useLoras", shared.OptionInfo(True, "Search for Loras", section=TAC_SECTION)) + shared.opts.add_option("tac_useLycos", shared.OptionInfo(True, "Search for LyCORIS/LoHa", 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))