Isolate all parsers in a local self-executing function

This commit is contained in:
DominikDoom
2025-07-12 18:54:56 +02:00
parent 8a574ec5e1
commit 87fa3851ca
10 changed files with 904 additions and 729 deletions

View File

@@ -1,21 +1,21 @@
class FunctionNotOverriddenError extends Error {
TAC.FunctionNotOverriddenError = class FunctionNotOverriddenError extends Error {
constructor(message = "", ...args) {
super(message, ...args);
this.message = message + " is an abstract base function and must be overwritten.";
}
}
class BaseTagParser {
TAC.BaseTagParser = class BaseTagParser {
triggerCondition = null;
constructor (triggerCondition) {
if (new.target === BaseTagParser) {
if (new.target === TAC.BaseTagParser) {
throw new TypeError("Cannot construct abstract BaseCompletionParser directly");
}
this.triggerCondition = triggerCondition;
}
parse() {
throw new FunctionNotOverriddenError("parse()");
throw new TAC.FunctionNotOverriddenError("parse()");
}
}

View File

@@ -1,57 +1,66 @@
const CHANT_REGEX = /<(?!e:|h:|l:)[^,> ]*>?/g;
const CHANT_TRIGGER = () => TAC.CFG.chantFile && TAC.CFG.chantFile !== "None" && TAC.Globals.tagword.match(CHANT_REGEX);
(function ChantExtension() {
const CHANT_REGEX = /<(?!e:|h:|l:)[^,> ]*>?/g;
const CHANT_TRIGGER = () =>
TAC.CFG.chantFile && TAC.CFG.chantFile !== "None" && TAC.Globals.tagword.match(CHANT_REGEX);
class ChantParser extends BaseTagParser {
parse() {
// Show Chant
let tempResults = [];
if (TAC.Globals.tagword !== "<" && TAC.Globals.tagword !== "<c:") {
let searchTerm = TAC.Globals.tagword.replace("<chant:", "").replace("<c:", "").replace("<", "");
let filterCondition = x => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), 'i');
return regex.test(x.terms.toLowerCase()) || regex.test(x.name.toLowerCase());
};
tempResults = TAC.Globals.chants.filter(x => filterCondition(x)); // Filter by tagword
class ChantParser extends TAC.BaseTagParser {
parse() {
// Show Chant
let tempResults = [];
if (TAC.Globals.tagword !== "<" && TAC.Globals.tagword !== "<c:") {
let searchTerm = TAC.Globals.tagword
.replace("<chant:", "")
.replace("<c:", "")
.replace("<", "");
let filterCondition = (x) => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), "i");
return regex.test(x.terms.toLowerCase()) || regex.test(x.name.toLowerCase());
};
tempResults = TAC.Globals.chants.filter((x) => filterCondition(x)); // Filter by tagword
} else {
tempResults = TAC.Globals.chants;
}
// Add final results
let finalResults = [];
tempResults.forEach((t) => {
let result = new TAC.TAC.AutocompleteResult(t.content.trim(), TAC.ResultType.chant);
result.meta = "Chant";
result.aliases = t.name;
result.category = t.color;
finalResults.push(result);
});
return finalResults;
}
}
async function load() {
if (TAC.CFG.chantFile && TAC.CFG.chantFile !== "None") {
try {
TAC.Globals.chants = await TacUtils.readFile(
`${TAC.Globals.tagBasePath}/${TAC.CFG.chantFile}?`,
true
);
} catch (e) {
console.error("Error loading chants.json: " + e);
}
} else {
tempResults = TAC.Globals.chants;
TAC.Globals.chants = [];
}
// Add final results
let finalResults = [];
tempResults.forEach(t => {
let result = new TAC.TAC.AutocompleteResult(t.content.trim(), TAC.ResultType.chant)
result.meta = "Chant";
result.aliases = t.name;
result.category = t.color;
finalResults.push(result);
});
return finalResults;
}
}
async function load() {
if (TAC.CFG.chantFile && TAC.CFG.chantFile !== "None") {
try {
TAC.Globals.chants = await TacUtils.readFile(`${TAC.Globals.tagBasePath}/${TAC.CFG.chantFile}?`, true);
} catch (e) {
console.error("Error loading chants.json: " + e);
function sanitize(tagType, text) {
if (tagType === TAC.ResultType.chant) {
return text;
}
} else {
TAC.Globals.chants = [];
return null;
}
}
function sanitize(tagType, text) {
if (tagType === TAC.ResultType.chant) {
return text;
}
return null;
}
TAC.Ext.PARSERS.push(new ChantParser(CHANT_TRIGGER));
TAC.Ext.PARSERS.push(new ChantParser(CHANT_TRIGGER));
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
TAC.Ext.QUEUE_AFTER_CONFIG_CHANGE.push(load);
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
TAC.Ext.QUEUE_AFTER_CONFIG_CHANGE.push(load);
})();

View File

@@ -1,72 +1,85 @@
const EMB_REGEX = /<(?!l:|h:|c:)[^,> ]*>?/g;
const EMB_TRIGGER = () => TAC.CFG.useEmbeddings && (TAC.Globals.tagword.match(EMB_REGEX) || TAC.CFG.includeEmbeddingsInNormalResults);
(function EmbeddingExtension() {
const EMB_REGEX = /<(?!l:|h:|c:)[^,> ]*>?/g;
const EMB_TRIGGER = () =>
TAC.CFG.useEmbeddings &&
(TAC.Globals.tagword.match(EMB_REGEX) || TAC.CFG.includeEmbeddingsInNormalResults);
class EmbeddingParser extends BaseTagParser {
parse() {
// Show embeddings
let tempResults = [];
if (TAC.Globals.tagword !== "<" && TAC.Globals.tagword !== "<e:") {
let searchTerm = TAC.Globals.tagword.replace("<e:", "").replace("<", "");
let versionString;
if (searchTerm.startsWith("v1") || searchTerm.startsWith("v2")) {
versionString = searchTerm.slice(0, 2);
searchTerm = searchTerm.slice(2);
} else if (searchTerm.startsWith("vxl")) {
versionString = searchTerm.slice(0, 3);
searchTerm = searchTerm.slice(3);
class EmbeddingParser extends TAC.BaseTagParser {
parse() {
// Show embeddings
let tempResults = [];
if (TAC.Globals.tagword !== "<" && TAC.Globals.tagword !== "<e:") {
let searchTerm = TAC.Globals.tagword.replace("<e:", "").replace("<", "");
let versionString;
if (searchTerm.startsWith("v1") || searchTerm.startsWith("v2")) {
versionString = searchTerm.slice(0, 2);
searchTerm = searchTerm.slice(2);
} else if (searchTerm.startsWith("vxl")) {
versionString = searchTerm.slice(0, 3);
searchTerm = searchTerm.slice(3);
}
let filterCondition = (x) => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), "i");
return (
regex.test(x[0].toLowerCase()) ||
regex.test(x[0].toLowerCase().replaceAll(" ", "_"))
);
};
if (versionString)
tempResults = TAC.Globals.embeddings.filter(
(x) =>
filterCondition(x) &&
x[2] &&
x[2].toLowerCase() === versionString.toLowerCase()
); // Filter by tagword
else tempResults = TAC.Globals.embeddings.filter((x) => filterCondition(x)); // Filter by tagword
} else {
tempResults = TAC.Globals.embeddings;
}
let filterCondition = x => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), 'i');
return regex.test(x[0].toLowerCase()) || regex.test(x[0].toLowerCase().replaceAll(" ", "_"));
};
// Add final results
let finalResults = [];
tempResults.forEach((t) => {
let lastDot = t[0].lastIndexOf(".") > -1 ? t[0].lastIndexOf(".") : t[0].length;
let lastSlash = t[0].lastIndexOf("/") > -1 ? t[0].lastIndexOf("/") : -1;
let name = t[0].trim().substring(lastSlash + 1, lastDot);
if (versionString)
tempResults = TAC.Globals.embeddings.filter(x => filterCondition(x) && x[2] && x[2].toLowerCase() === versionString.toLowerCase()); // Filter by tagword
else
tempResults = TAC.Globals.embeddings.filter(x => filterCondition(x)); // Filter by tagword
} else {
tempResults = TAC.Globals.embeddings;
}
let result = new TAC.AutocompleteResult(name, TAC.ResultType.embedding);
result.sortKey = t[1];
result.meta = t[2] + " Embedding";
finalResults.push(result);
});
// Add final results
let finalResults = [];
tempResults.forEach(t => {
let lastDot = t[0].lastIndexOf(".") > -1 ? t[0].lastIndexOf(".") : t[0].length;
let lastSlash = t[0].lastIndexOf("/") > -1 ? t[0].lastIndexOf("/") : -1;
let name = t[0].trim().substring(lastSlash + 1, lastDot);
let result = new TAC.AutocompleteResult(name, TAC.ResultType.embedding)
result.sortKey = t[1];
result.meta = t[2] + " Embedding";
finalResults.push(result);
});
return finalResults;
}
}
async function load() {
if (TAC.Globals.embeddings.length === 0) {
try {
TAC.Globals.embeddings = (await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/emb.txt`))
.filter(x => x[0]?.trim().length > 0) // Remove empty lines
.map(x => [x[0].trim(), x[1], x[2]]); // Return name, sortKey, hash tuples
} catch (e) {
console.error("Error loading embeddings.txt: " + e);
return finalResults;
}
}
}
function sanitize(tagType, text) {
if (tagType === TAC.ResultType.embedding) {
return text;
async function load() {
if (TAC.Globals.embeddings.length === 0) {
try {
TAC.Globals.embeddings = (
await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/emb.txt`)
)
.filter((x) => x[0]?.trim().length > 0) // Remove empty lines
.map((x) => [x[0].trim(), x[1], x[2]]); // Return name, sortKey, hash tuples
} catch (e) {
console.error("Error loading embeddings.txt: " + e);
}
}
}
return null;
}
TAC.Ext.PARSERS.push(new EmbeddingParser(EMB_TRIGGER));
function sanitize(tagType, text) {
if (tagType === TAC.ResultType.embedding) {
return text;
}
return null;
}
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
TAC.Ext.PARSERS.push(new EmbeddingParser(EMB_TRIGGER));
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
})();

View File

@@ -1,55 +1,69 @@
const HYP_REGEX = /<(?!e:|l:|c:)[^,> ]*>?/g;
const HYP_TRIGGER = () => TAC.CFG.useHypernetworks && TAC.Globals.tagword.match(HYP_REGEX);
(function HypernetExtension() {
const HYP_REGEX = /<(?!e:|l:|c:)[^,> ]*>?/g;
const HYP_TRIGGER = () => TAC.CFG.useHypernetworks && TAC.Globals.tagword.match(HYP_REGEX);
class HypernetParser extends BaseTagParser {
parse() {
// Show hypernetworks
let tempResults = [];
if (TAC.Globals.tagword !== "<" && TAC.Globals.tagword !== "<h:" && TAC.Globals.tagword !== "<hypernet:") {
let searchTerm = TAC.Globals.tagword.replace("<hypernet:", "").replace("<h:", "").replace("<", "");
let filterCondition = x => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), 'i');
return regex.test(x.toLowerCase()) || regex.test(x.toLowerCase().replaceAll(" ", "_"));
};
tempResults = TAC.Globals.hypernetworks.filter(x => filterCondition(x[0])); // Filter by tagword
} else {
tempResults = TAC.Globals.hypernetworks;
}
class HypernetParser extends TAC.BaseTagParser {
parse() {
// Show hypernetworks
let tempResults = [];
if (
TAC.Globals.tagword !== "<" &&
TAC.Globals.tagword !== "<h:" &&
TAC.Globals.tagword !== "<hypernet:"
) {
let searchTerm = TAC.Globals.tagword
.replace("<hypernet:", "")
.replace("<h:", "")
.replace("<", "");
let filterCondition = (x) => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), "i");
return (
regex.test(x.toLowerCase()) ||
regex.test(x.toLowerCase().replaceAll(" ", "_"))
);
};
tempResults = TAC.Globals.hypernetworks.filter((x) => filterCondition(x[0])); // Filter by tagword
} else {
tempResults = TAC.Globals.hypernetworks;
}
// Add final results
let finalResults = [];
tempResults.forEach(t => {
let result = new TAC.AutocompleteResult(t[0].trim(), TAC.ResultType.hypernetwork)
result.meta = "Hypernetwork";
result.sortKey = t[1];
finalResults.push(result);
});
// Add final results
let finalResults = [];
tempResults.forEach((t) => {
let result = new TAC.AutocompleteResult(t[0].trim(), TAC.ResultType.hypernetwork);
result.meta = "Hypernetwork";
result.sortKey = t[1];
finalResults.push(result);
});
return finalResults;
}
}
async function load() {
if (TAC.Globals.hypernetworks.length === 0) {
try {
TAC.Globals.hypernetworks = (await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/hyp.txt`))
.filter(x => x[0]?.trim().length > 0) //Remove empty lines
.map(x => [x[0]?.trim(), x[1]]); // Remove carriage returns and padding if it exists
} catch (e) {
console.error("Error loading hypernetworks.txt: " + e);
return finalResults;
}
}
}
function sanitize(tagType, text) {
if (tagType === TAC.ResultType.hypernetwork) {
return `<hypernet:${text}:${TAC.CFG.extraNetworksDefaultMultiplier}>`;
async function load() {
if (TAC.Globals.hypernetworks.length === 0) {
try {
TAC.Globals.hypernetworks = (
await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/hyp.txt`)
)
.filter((x) => x[0]?.trim().length > 0) //Remove empty lines
.map((x) => [x[0]?.trim(), x[1]]); // Remove carriage returns and padding if it exists
} catch (e) {
console.error("Error loading hypernetworks.txt: " + e);
}
}
}
return null;
}
TAC.Ext.PARSERS.push(new HypernetParser(HYP_TRIGGER));
function sanitize(tagType, text) {
if (tagType === TAC.ResultType.hypernetwork) {
return `<hypernet:${text}:${TAC.CFG.extraNetworksDefaultMultiplier}>`;
}
return null;
}
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
TAC.Ext.PARSERS.push(new HypernetParser(HYP_TRIGGER));
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
})();

View File

@@ -1,67 +1,81 @@
const LORA_REGEX = /<(?!e:|h:|c:)[^,> ]*>?/g;
const LORA_TRIGGER = () => TAC.CFG.useLoras && TAC.Globals.tagword.match(LORA_REGEX);
(function LoraExtension() {
const LORA_REGEX = /<(?!e:|h:|c:)[^,> ]*>?/g;
const LORA_TRIGGER = () => TAC.CFG.useLoras && TAC.Globals.tagword.match(LORA_REGEX);
class LoraParser extends BaseTagParser {
parse() {
// Show lora
let tempResults = [];
if (TAC.Globals.tagword !== "<" && TAC.Globals.tagword !== "<l:" && TAC.Globals.tagword !== "<lora:") {
let searchTerm = TAC.Globals.tagword.replace("<lora:", "").replace("<l:", "").replace("<", "");
let filterCondition = x => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), 'i');
return regex.test(x.toLowerCase()) || regex.test(x.toLowerCase().replaceAll(" ", "_"));
};
tempResults = TAC.Globals.loras.filter(x => filterCondition(x[0])); // Filter by tagword
} else {
tempResults = TAC.Globals.loras;
}
class LoraParser extends TAC.BaseTagParser {
parse() {
// Show lora
let tempResults = [];
if (
TAC.Globals.tagword !== "<" &&
TAC.Globals.tagword !== "<l:" &&
TAC.Globals.tagword !== "<lora:"
) {
let searchTerm = TAC.Globals.tagword
.replace("<lora:", "")
.replace("<l:", "")
.replace("<", "");
let filterCondition = (x) => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), "i");
return (
regex.test(x.toLowerCase()) ||
regex.test(x.toLowerCase().replaceAll(" ", "_"))
);
};
tempResults = TAC.Globals.loras.filter((x) => filterCondition(x[0])); // Filter by tagword
} else {
tempResults = TAC.Globals.loras;
}
// Add final results
let finalResults = [];
tempResults.forEach(t => {
const text = t[0].trim();
let lastDot = text.lastIndexOf(".") > -1 ? text.lastIndexOf(".") : text.length;
let lastSlash = text.lastIndexOf("/") > -1 ? text.lastIndexOf("/") : -1;
let name = text.substring(lastSlash + 1, lastDot);
// Add final results
let finalResults = [];
tempResults.forEach((t) => {
const text = t[0].trim();
let lastDot = text.lastIndexOf(".") > -1 ? text.lastIndexOf(".") : text.length;
let lastSlash = text.lastIndexOf("/") > -1 ? text.lastIndexOf("/") : -1;
let name = text.substring(lastSlash + 1, lastDot);
let result = new TAC.AutocompleteResult(name, TAC.ResultType.lora)
result.meta = "Lora";
result.sortKey = t[1];
result.hash = t[2];
finalResults.push(result);
});
let result = new TAC.AutocompleteResult(name, TAC.ResultType.lora);
result.meta = "Lora";
result.sortKey = t[1];
result.hash = t[2];
finalResults.push(result);
});
return finalResults;
}
}
async function load() {
if (TAC.Globals.loras.length === 0) {
try {
TAC.Globals.loras = (await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/lora.txt`))
.filter(x => x[0]?.trim().length > 0) // Remove empty lines
.map(x => [x[0]?.trim(), x[1], x[2]]); // Trim filenames and return the name, sortKey, hash pairs
} catch (e) {
console.error("Error loading lora.txt: " + e);
return finalResults;
}
}
}
async function sanitize(tagType, text) {
if (tagType === TAC.ResultType.lora) {
let multiplier = TAC.CFG.extraNetworksDefaultMultiplier;
let info = await TacUtils.fetchAPI(`tacapi/v1/lora-info/${text}`)
if (info && info["preferred weight"]) {
multiplier = info["preferred weight"];
async function load() {
if (TAC.Globals.loras.length === 0) {
try {
TAC.Globals.loras = (
await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/lora.txt`)
)
.filter((x) => x[0]?.trim().length > 0) // Remove empty lines
.map((x) => [x[0]?.trim(), x[1], x[2]]); // Trim filenames and return the name, sortKey, hash pairs
} catch (e) {
console.error("Error loading lora.txt: " + e);
}
}
return `<lora:${text}:${multiplier}>`;
}
return null;
}
TAC.Ext.PARSERS.push(new LoraParser(LORA_TRIGGER));
async function sanitize(tagType, text) {
if (tagType === TAC.ResultType.lora) {
let multiplier = TAC.CFG.extraNetworksDefaultMultiplier;
let info = await TacUtils.fetchAPI(`tacapi/v1/lora-info/${text}`);
if (info && info["preferred weight"]) {
multiplier = info["preferred weight"];
}
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
return `<lora:${text}:${multiplier}>`;
}
return null;
}
TAC.Ext.PARSERS.push(new LoraParser(LORA_TRIGGER));
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
})();

View File

@@ -1,68 +1,84 @@
const LYCO_REGEX = /<(?!e:|h:|c:)[^,> ]*>?/g;
const LYCO_TRIGGER = () => TAC.CFG.useLycos && TAC.Globals.tagword.match(LYCO_REGEX);
(function LycoExtension() {
const LYCO_REGEX = /<(?!e:|h:|c:)[^,> ]*>?/g;
const LYCO_TRIGGER = () => TAC.CFG.useLycos && TAC.Globals.tagword.match(LYCO_REGEX);
class LycoParser extends BaseTagParser {
parse() {
// Show lyco
let tempResults = [];
if (TAC.Globals.tagword !== "<" && TAC.Globals.tagword !== "<l:" && TAC.Globals.tagword !== "<lyco:" && TAC.Globals.tagword !== "<lora:") {
let searchTerm = TAC.Globals.tagword.replace("<lyco:", "").replace("<lora:", "").replace("<l:", "").replace("<", "");
let filterCondition = x => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), 'i');
return regex.test(x.toLowerCase()) || regex.test(x.toLowerCase().replaceAll(" ", "_"));
};
tempResults = TAC.Globals.lycos.filter(x => filterCondition(x[0])); // Filter by tagword
} else {
tempResults = TAC.Globals.lycos;
}
class LycoParser extends TAC.BaseTagParser {
parse() {
// Show lyco
let tempResults = [];
if (
TAC.Globals.tagword !== "<" &&
TAC.Globals.tagword !== "<l:" &&
TAC.Globals.tagword !== "<lyco:" &&
TAC.Globals.tagword !== "<lora:"
) {
let searchTerm = TAC.Globals.tagword
.replace("<lyco:", "")
.replace("<lora:", "")
.replace("<l:", "")
.replace("<", "");
let filterCondition = (x) => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), "i");
return (
regex.test(x.toLowerCase()) ||
regex.test(x.toLowerCase().replaceAll(" ", "_"))
);
};
tempResults = TAC.Globals.lycos.filter((x) => filterCondition(x[0])); // Filter by tagword
} else {
tempResults = TAC.Globals.lycos;
}
// Add final results
let finalResults = [];
tempResults.forEach(t => {
const text = t[0].trim();
let lastDot = text.lastIndexOf(".") > -1 ? text.lastIndexOf(".") : text.length;
let lastSlash = text.lastIndexOf("/") > -1 ? text.lastIndexOf("/") : -1;
let name = text.substring(lastSlash + 1, lastDot);
// Add final results
let finalResults = [];
tempResults.forEach((t) => {
const text = t[0].trim();
let lastDot = text.lastIndexOf(".") > -1 ? text.lastIndexOf(".") : text.length;
let lastSlash = text.lastIndexOf("/") > -1 ? text.lastIndexOf("/") : -1;
let name = text.substring(lastSlash + 1, lastDot);
let result = new TAC.AutocompleteResult(name, TAC.ResultType.lyco)
result.meta = "Lyco";
result.sortKey = t[1];
result.hash = t[2];
finalResults.push(result);
});
let result = new TAC.AutocompleteResult(name, TAC.ResultType.lyco);
result.meta = "Lyco";
result.sortKey = t[1];
result.hash = t[2];
finalResults.push(result);
});
return finalResults;
}
}
async function load() {
if (TAC.Globals.lycos.length === 0) {
try {
TAC.Globals.lycos = (await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/lyco.txt`))
.filter(x => x[0]?.trim().length > 0) // Remove empty lines
.map(x => [x[0]?.trim(), x[1], x[2]]); // Trim filenames and return the name, sortKey, hash pairs
} catch (e) {
console.error("Error loading lyco.txt: " + e);
return finalResults;
}
}
}
async function sanitize(tagType, text) {
if (tagType === TAC.ResultType.lyco) {
let multiplier = TAC.CFG.extraNetworksDefaultMultiplier;
let info = await TacUtils.fetchAPI(`tacapi/v1/lyco-info/${text}`)
if (info && info["preferred weight"]) {
multiplier = info["preferred weight"];
async function load() {
if (TAC.Globals.lycos.length === 0) {
try {
TAC.Globals.lycos = (
await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/lyco.txt`)
)
.filter((x) => x[0]?.trim().length > 0) // Remove empty lines
.map((x) => [x[0]?.trim(), x[1], x[2]]); // Trim filenames and return the name, sortKey, hash pairs
} catch (e) {
console.error("Error loading lyco.txt: " + e);
}
}
let prefix = TAC.CFG.useLoraPrefixForLycos ? "lora" : "lyco";
return `<${prefix}:${text}:${multiplier}>`;
}
return null;
}
TAC.Ext.PARSERS.push(new LycoParser(LYCO_TRIGGER));
async function sanitize(tagType, text) {
if (tagType === TAC.ResultType.lyco) {
let multiplier = TAC.CFG.extraNetworksDefaultMultiplier;
let info = await TacUtils.fetchAPI(`tacapi/v1/lyco-info/${text}`);
if (info && info["preferred weight"]) {
multiplier = info["preferred weight"];
}
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
let prefix = TAC.CFG.useLoraPrefixForLycos ? "lora" : "lyco";
return `<${prefix}:${text}:${multiplier}>`;
}
return null;
}
TAC.Ext.PARSERS.push(new LycoParser(LYCO_TRIGGER));
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
})();

View File

@@ -1,42 +1,56 @@
async function load() {
let modelKeywordParts = (await TacUtils.readFile(`tmp/modelKeywordPath.txt`)).split(",")
TAC.Globals.modelKeywordPath = modelKeywordParts[0];
let customFileExists = modelKeywordParts[1] === "True";
(function ModelKeywordExtension() {
async function load() {
let modelKeywordParts = (await TacUtils.readFile(`tmp/modelKeywordPath.txt`)).split(",");
TAC.Globals.modelKeywordPath = modelKeywordParts[0];
let customFileExists = modelKeywordParts[1] === "True";
if (TAC.Globals.modelKeywordPath.length > 0 && TAC.Globals.modelKeywordDict.size === 0) {
try {
let csv_lines = [];
// Only add default keywords if wanted by the user
if (TAC.CFG.modelKeywordCompletion !== "Only user list")
csv_lines = (await TacUtils.loadCSV(`${TAC.Globals.modelKeywordPath}/lora-keyword.txt`));
// Add custom user keywords if the file exists
if (customFileExists)
csv_lines = csv_lines.concat((await TacUtils.loadCSV(`${TAC.Globals.modelKeywordPath}/lora-keyword-user.txt`)));
if (TAC.Globals.modelKeywordPath.length > 0 && TAC.Globals.modelKeywordDict.size === 0) {
try {
let csv_lines = [];
// Only add default keywords if wanted by the user
if (TAC.CFG.modelKeywordCompletion !== "Only user list")
csv_lines = await TacUtils.loadCSV(
`${TAC.Globals.modelKeywordPath}/lora-keyword.txt`
);
// Add custom user keywords if the file exists
if (customFileExists)
csv_lines = csv_lines.concat(
await TacUtils.loadCSV(
`${TAC.Globals.modelKeywordPath}/lora-keyword-user.txt`
)
);
if (csv_lines.length === 0) return;
if (csv_lines.length === 0) return;
csv_lines = csv_lines.filter(x => x[0].trim().length > 0 && x[0].trim()[0] !== "#") // Remove empty lines and comments
csv_lines = csv_lines.filter(
(x) => x[0].trim().length > 0 && x[0].trim()[0] !== "#"
); // Remove empty lines and comments
// Add to the dict
csv_lines.forEach(parts => {
const hash = parts[0];
const keywords = parts[1]?.replaceAll("| ", ", ")?.replaceAll("|", ", ")?.trim();
const lastSepIndex = parts[2]?.lastIndexOf("/") + 1 || parts[2]?.lastIndexOf("\\") + 1 || 0;
const name = parts[2]?.substring(lastSepIndex).trim() || "none"
// Add to the dict
csv_lines.forEach((parts) => {
const hash = parts[0];
const keywords = parts[1]
?.replaceAll("| ", ", ")
?.replaceAll("|", ", ")
?.trim();
const lastSepIndex =
parts[2]?.lastIndexOf("/") + 1 || parts[2]?.lastIndexOf("\\") + 1 || 0;
const name = parts[2]?.substring(lastSepIndex).trim() || "none";
if (TAC.Globals.modelKeywordDict.has(hash) && name !== "none") {
// Add a new name key if the hash already exists
TAC.Globals.modelKeywordDict.get(hash).set(name, keywords);
} else {
// Create new hash entry
let map = new Map().set(name, keywords);
TAC.Globals.modelKeywordDict.set(hash, map);
}
});
} catch (e) {
console.error("Error loading model-keywords list: " + e);
if (TAC.Globals.modelKeywordDict.has(hash) && name !== "none") {
// Add a new name key if the hash already exists
TAC.Globals.modelKeywordDict.get(hash).set(name, keywords);
} else {
// Create new hash entry
let map = new Map().set(name, keywords);
TAC.Globals.modelKeywordDict.set(hash, map);
}
});
} catch (e) {
console.error("Error loading model-keywords list: " + e);
}
}
}
}
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_FILE_LOAD.push(load);
})();

View File

@@ -1,70 +1,77 @@
const STYLE_REGEX = /(\$(\d*)\(?)[^$|\[\],\s]*\)?/;
const STYLE_TRIGGER = () => TAC.CFG.useStyleVars && TAC.Globals.tagword.match(STYLE_REGEX);
(function StyleExtension() {
const STYLE_REGEX = /(\$(\d*)\(?)[^$|\[\],\s]*\)?/;
const STYLE_TRIGGER = () => TAC.CFG.useStyleVars && TAC.Globals.tagword.match(STYLE_REGEX);
var lastStyleVarIndex = "";
var lastStyleVarIndex = "";
class StyleParser extends BaseTagParser {
async parse() {
// Refresh if needed
await TacUtils.refreshStyleNamesIfChanged();
class StyleParser extends TAC.BaseTagParser {
async parse() {
// Refresh if needed
await TacUtils.refreshStyleNamesIfChanged();
// Show styles
let tempResults = [];
let matchGroups = TAC.Globals.tagword.match(STYLE_REGEX);
// Save index to insert again later or clear last one
lastStyleVarIndex = matchGroups[2] ? matchGroups[2] : "";
// Show styles
let tempResults = [];
let matchGroups = TAC.Globals.tagword.match(STYLE_REGEX);
if (TAC.Globals.tagword !== matchGroups[1]) {
let searchTerm = TAC.Globals.tagword.replace(matchGroups[1], "");
let filterCondition = x => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), 'i');
return regex.test(x[0].toLowerCase()) || regex.test(x[0].toLowerCase().replaceAll(" ", "_"));
};
tempResults = TAC.Globals.styleNames.filter(x => filterCondition(x)); // Filter by tagword
} else {
tempResults = TAC.Globals.styleNames;
}
// Save index to insert again later or clear last one
lastStyleVarIndex = matchGroups[2] ? matchGroups[2] : "";
// Add final results
let finalResults = [];
tempResults.forEach(t => {
let result = new TAC.AutocompleteResult(t[0].trim(), TAC.ResultType.styleName)
result.meta = "Style";
finalResults.push(result);
});
if (TAC.Globals.tagword !== matchGroups[1]) {
let searchTerm = TAC.Globals.tagword.replace(matchGroups[1], "");
return finalResults;
}
}
let filterCondition = (x) => {
let regex = new RegExp(TacUtils.escapeRegExp(searchTerm, true), "i");
return (
regex.test(x[0].toLowerCase()) ||
regex.test(x[0].toLowerCase().replaceAll(" ", "_"))
);
};
tempResults = TAC.Globals.styleNames.filter((x) => filterCondition(x)); // Filter by tagword
} else {
tempResults = TAC.Globals.styleNames;
}
async function load(force = false) {
if (TAC.Globals.styleNames.length === 0 || force) {
try {
TAC.Globals.styleNames = (await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/styles.txt`))
.filter(x => x[0]?.trim().length > 0) // Remove empty lines
.filter(x => x[0] !== "None") // Remove "None" style
.map(x => [x[0].trim()]); // Trim name
} catch (e) {
console.error("Error loading styles.txt: " + e);
// Add final results
let finalResults = [];
tempResults.forEach((t) => {
let result = new TAC.AutocompleteResult(t[0].trim(), TAC.ResultType.styleName);
result.meta = "Style";
finalResults.push(result);
});
return finalResults;
}
}
}
function sanitize(tagType, text) {
if (tagType === TAC.ResultType.styleName) {
if (text.includes(" ")) {
return `$${lastStyleVarIndex}(${text})`;
} else {
return`$${lastStyleVarIndex}${text}`
async function load(force = false) {
if (TAC.Globals.styleNames.length === 0 || force) {
try {
TAC.Globals.styleNames = (
await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/styles.txt`)
)
.filter((x) => x[0]?.trim().length > 0) // Remove empty lines
.filter((x) => x[0] !== "None") // Remove "None" style
.map((x) => [x[0].trim()]); // Trim name
} catch (e) {
console.error("Error loading styles.txt: " + e);
}
}
}
return null;
}
TAC.Ext.PARSERS.push(new StyleParser(STYLE_TRIGGER));
function sanitize(tagType, text) {
if (tagType === TAC.ResultType.styleName) {
if (text.includes(" ")) {
return `$${lastStyleVarIndex}(${text})`;
} else {
return `$${lastStyleVarIndex}${text}`;
}
}
return null;
}
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
TAC.Ext.PARSERS.push(new StyleParser(STYLE_TRIGGER));
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
})();

View File

@@ -1,163 +1,210 @@
const UMI_PROMPT_REGEX = /<[^\s]*?\[[^,<>]*[\]|]?>?/gi;
const UMI_TAG_REGEX = /(?:\[|\||--)([^<>\[\]\-|]+)/gi;
(function UmiExtension() {
const UMI_PROMPT_REGEX = /<[^\s]*?\[[^,<>]*[\]|]?>?/gi;
const UMI_TAG_REGEX = /(?:\[|\||--)([^<>\[\]\-|]+)/gi;
const UMI_TRIGGER = () => TAC.CFG.useWildcards && [...TAC.Globals.tagword.matchAll(UMI_PROMPT_REGEX)].length > 0;
const UMI_TRIGGER = () =>
TAC.CFG.useWildcards && [...TAC.Globals.tagword.matchAll(UMI_PROMPT_REGEX)].length > 0;
class UmiParser extends BaseTagParser {
parse(textArea, prompt) {
// We are in a UMI yaml tag definition, parse further
let umiSubPrompts = [...prompt.matchAll(UMI_PROMPT_REGEX)];
class UmiParser extends TAC.BaseTagParser {
parse(textArea, prompt) {
// We are in a UMI yaml tag definition, parse further
let umiSubPrompts = [...prompt.matchAll(UMI_PROMPT_REGEX)];
let umiTags = [];
let umiTagsWithOperators = []
let umiTags = [];
let umiTagsWithOperators = [];
const insertAt = (str,char,pos) => str.slice(0,pos) + char + str.slice(pos);
const insertAt = (str, char, pos) => str.slice(0, pos) + char + str.slice(pos);
umiSubPrompts.forEach(umiSubPrompt => {
umiTags = umiTags.concat([...umiSubPrompt[0].matchAll(UMI_TAG_REGEX)].map(x => x[1].toLowerCase()));
const start = umiSubPrompt.index;
const end = umiSubPrompt.index + umiSubPrompt[0].length;
if (textArea.selectionStart >= start && textArea.selectionStart <= end) {
umiTagsWithOperators = insertAt(umiSubPrompt[0], '###', textArea.selectionStart - start);
}
});
// Safety check since UMI parsing sometimes seems to trigger outside of an UMI subprompt and thus fails
if (umiTagsWithOperators.length === 0) {
return null;
}
const promptSplitToTags = umiTagsWithOperators.replace(']###[', '][').split("][");
const clean = (str) => str
.replaceAll('>', '')
.replaceAll('<', '')
.replaceAll('[', '')
.replaceAll(']', '')
.trim();
const matches = promptSplitToTags.reduce((acc, curr) => {
let isOptional = curr.includes("|");
let isNegative = curr.startsWith("--");
let out;
if (isOptional) {
out = {
hasCursor: curr.includes("###"),
tags: clean(curr).split('|').map(x => ({
hasCursor: x.includes("###"),
isNegative: x.startsWith("--"),
tag: clean(x).replaceAll("###", '').replaceAll("--", '')
}))
};
acc.optional.push(out);
acc.all.push(...out.tags.map(x => x.tag));
} else if (isNegative) {
out = {
hasCursor: curr.includes("###"),
tags: clean(curr).replaceAll("###", '').split('|'),
};
out.tags = out.tags.map(x => x.startsWith("--") ? x.substring(2) : x);
acc.negative.push(out);
acc.all.push(...out.tags);
} else {
out = {
hasCursor: curr.includes("###"),
tags: clean(curr).replaceAll("###", '').split('|'),
};
acc.positive.push(out);
acc.all.push(...out.tags);
}
return acc;
}, { positive: [], negative: [], optional: [], all: [] });
//console.log({ matches })
const filteredWildcards = (tagword) => {
const wildcards = TAC.Globals.umiWildcards.filter(x => {
let tags = x[1];
const matchesNeg =
matches.negative.length === 0
|| matches.negative.every(x =>
x.hasCursor
|| x.tags.every(t => !tags[t])
);
if (!matchesNeg) return false;
const matchesPos =
matches.positive.length === 0
|| matches.positive.every(x =>
x.hasCursor
|| x.tags.every(t => tags[t])
);
if (!matchesPos) return false;
const matchesOpt =
matches.optional.length === 0
|| matches.optional.some(x =>
x.tags.some(t =>
t.hasCursor
|| t.isNegative
? !tags[t.tag]
: tags[t.tag]
));
if (!matchesOpt) return false;
return true;
}).reduce((acc, val) => {
Object.keys(val[1]).forEach(tag => acc[tag] = acc[tag] + 1 || 1);
return acc;
}, {});
return Object.entries(wildcards)
.sort((a, b) => b[1] - a[1])
.filter(x =>
x[0] === tagword
|| !matches.all.includes(x[0])
umiSubPrompts.forEach((umiSubPrompt) => {
umiTags = umiTags.concat(
[...umiSubPrompt[0].matchAll(UMI_TAG_REGEX)].map((x) => x[1].toLowerCase())
);
}
if (umiTags.length > 0) {
// Get difference for subprompt
let tagCountChange = umiTags.length - TAC.Globals.umiPreviousTags.length;
let diff = TacUtils.difference(umiTags, TAC.Globals.umiPreviousTags);
TAC.Globals.umiPreviousTags = umiTags;
const start = umiSubPrompt.index;
const end = umiSubPrompt.index + umiSubPrompt[0].length;
if (textArea.selectionStart >= start && textArea.selectionStart <= end) {
umiTagsWithOperators = insertAt(
umiSubPrompt[0],
"###",
textArea.selectionStart - start
);
}
});
// Show all condition
let showAll = TAC.Globals.tagword.endsWith("[") || TAC.Globals.tagword.endsWith("[--") || TAC.Globals.tagword.endsWith("|");
// Exit early if the user closed the bracket manually
if ((!diff || diff.length === 0 || (diff.length === 1 && tagCountChange < 0)) && !showAll) {
if (!TAC.Globals.hideBlocked) hideResults(textArea);
return;
// Safety check since UMI parsing sometimes seems to trigger outside of an UMI subprompt and thus fails
if (umiTagsWithOperators.length === 0) {
return null;
}
let umiTagword = tagCountChange < 0 ? '' : diff[0] || '';
let tempResults = [];
if (umiTagword && umiTagword.length > 0) {
umiTagword = umiTagword.toLowerCase().replace(/[\n\r]/g, "");
TAC.Globals.originalTagword = TAC.Globals.tagword;
TAC.Globals.tagword = umiTagword;
let filteredWildcardsSorted = filteredWildcards(umiTagword);
let searchRegex = new RegExp(`(^|[^a-zA-Z])${TacUtils.escapeRegExp(umiTagword)}`, 'i')
let baseFilter = x => x[0].toLowerCase().search(searchRegex) > -1;
let spaceIncludeFilter = x => x[0].toLowerCase().replaceAll(" ", "_").search(searchRegex) > -1;
tempResults = filteredWildcardsSorted.filter(x => baseFilter(x) || spaceIncludeFilter(x)) // Filter by tagword
const promptSplitToTags = umiTagsWithOperators.replace("]###[", "][").split("][");
// Add final results
let finalResults = [];
tempResults.forEach(t => {
let result = new TAC.AutocompleteResult(t[0].trim(), TAC.ResultType.umiWildcard)
result.count = t[1];
finalResults.push(result);
});
const clean = (str) =>
str
.replaceAll(">", "")
.replaceAll("<", "")
.replaceAll("[", "")
.replaceAll("]", "")
.trim();
finalResults = finalResults.sort((a, b) => b.count - a.count);
return finalResults;
} else if (showAll) {
const matches = promptSplitToTags.reduce(
(acc, curr) => {
let isOptional = curr.includes("|");
let isNegative = curr.startsWith("--");
let out;
if (isOptional) {
out = {
hasCursor: curr.includes("###"),
tags: clean(curr)
.split("|")
.map((x) => ({
hasCursor: x.includes("###"),
isNegative: x.startsWith("--"),
tag: clean(x).replaceAll("###", "").replaceAll("--", ""),
})),
};
acc.optional.push(out);
acc.all.push(...out.tags.map((x) => x.tag));
} else if (isNegative) {
out = {
hasCursor: curr.includes("###"),
tags: clean(curr).replaceAll("###", "").split("|"),
};
out.tags = out.tags.map((x) => (x.startsWith("--") ? x.substring(2) : x));
acc.negative.push(out);
acc.all.push(...out.tags);
} else {
out = {
hasCursor: curr.includes("###"),
tags: clean(curr).replaceAll("###", "").split("|"),
};
acc.positive.push(out);
acc.all.push(...out.tags);
}
return acc;
},
{ positive: [], negative: [], optional: [], all: [] }
);
//console.log({ matches })
const filteredWildcards = (tagword) => {
const wildcards = TAC.Globals.umiWildcards
.filter((x) => {
let tags = x[1];
const matchesNeg =
matches.negative.length === 0 ||
matches.negative.every(
(x) => x.hasCursor || x.tags.every((t) => !tags[t])
);
if (!matchesNeg) return false;
const matchesPos =
matches.positive.length === 0 ||
matches.positive.every(
(x) => x.hasCursor || x.tags.every((t) => tags[t])
);
if (!matchesPos) return false;
const matchesOpt =
matches.optional.length === 0 ||
matches.optional.some((x) =>
x.tags.some((t) =>
t.hasCursor || t.isNegative ? !tags[t.tag] : tags[t.tag]
)
);
if (!matchesOpt) return false;
return true;
})
.reduce((acc, val) => {
Object.keys(val[1]).forEach((tag) => (acc[tag] = acc[tag] + 1 || 1));
return acc;
}, {});
return Object.entries(wildcards)
.sort((a, b) => b[1] - a[1])
.filter((x) => x[0] === tagword || !matches.all.includes(x[0]));
};
if (umiTags.length > 0) {
// Get difference for subprompt
let tagCountChange = umiTags.length - TAC.Globals.umiPreviousTags.length;
let diff = TacUtils.difference(umiTags, TAC.Globals.umiPreviousTags);
TAC.Globals.umiPreviousTags = umiTags;
// Show all condition
let showAll =
TAC.Globals.tagword.endsWith("[") ||
TAC.Globals.tagword.endsWith("[--") ||
TAC.Globals.tagword.endsWith("|");
// Exit early if the user closed the bracket manually
if (
(!diff || diff.length === 0 || (diff.length === 1 && tagCountChange < 0)) &&
!showAll
) {
if (!TAC.Globals.hideBlocked) hideResults(textArea);
return;
}
let umiTagword = tagCountChange < 0 ? "" : diff[0] || "";
let tempResults = [];
if (umiTagword && umiTagword.length > 0) {
umiTagword = umiTagword.toLowerCase().replace(/[\n\r]/g, "");
TAC.Globals.originalTagword = TAC.Globals.tagword;
TAC.Globals.tagword = umiTagword;
let filteredWildcardsSorted = filteredWildcards(umiTagword);
let searchRegex = new RegExp(
`(^|[^a-zA-Z])${TacUtils.escapeRegExp(umiTagword)}`,
"i"
);
let baseFilter = (x) => x[0].toLowerCase().search(searchRegex) > -1;
let spaceIncludeFilter = (x) =>
x[0].toLowerCase().replaceAll(" ", "_").search(searchRegex) > -1;
tempResults = filteredWildcardsSorted.filter(
(x) => baseFilter(x) || spaceIncludeFilter(x)
); // Filter by tagword
// Add final results
let finalResults = [];
tempResults.forEach((t) => {
let result = new TAC.AutocompleteResult(
t[0].trim(),
TAC.ResultType.umiWildcard
);
result.count = t[1];
finalResults.push(result);
});
finalResults = finalResults.sort((a, b) => b.count - a.count);
return finalResults;
} else if (showAll) {
let filteredWildcardsSorted = filteredWildcards("");
// Add final results
let finalResults = [];
filteredWildcardsSorted.forEach((t) => {
let result = new TAC.AutocompleteResult(
t[0].trim(),
TAC.ResultType.umiWildcard
);
result.count = t[1];
finalResults.push(result);
});
TAC.Globals.originalTagword = TAC.Globals.tagword;
TAC.Globals.tagword = "";
finalResults = finalResults.sort((a, b) => b.count - a.count);
return finalResults;
}
} else {
let filteredWildcardsSorted = filteredWildcards("");
// Add final results
let finalResults = [];
filteredWildcardsSorted.forEach(t => {
let result = new TAC.AutocompleteResult(t[0].trim(), TAC.ResultType.umiWildcard)
filteredWildcardsSorted.forEach((t) => {
let result = new TAC.AutocompleteResult(
t[0].trim(),
TAC.ResultType.umiWildcard
);
result.count = t[1];
finalResults.push(result);
});
@@ -168,78 +215,65 @@ class UmiParser extends BaseTagParser {
finalResults = finalResults.sort((a, b) => b.count - a.count);
return finalResults;
}
} else {
let filteredWildcardsSorted = filteredWildcards("");
}
}
// Add final results
let finalResults = [];
filteredWildcardsSorted.forEach(t => {
let result = new TAC.AutocompleteResult(t[0].trim(), TAC.ResultType.umiWildcard)
result.count = t[1];
finalResults.push(result);
function updateUmiTags(tagType, sanitizedText, newPrompt, textArea) {
// If it was a umi wildcard, also update the TAC.Globals.umiPreviousTags
if (tagType === TAC.ResultType.umiWildcard && TAC.Globals.originalTagword.length > 0) {
let umiSubPrompts = [...newPrompt.matchAll(UMI_PROMPT_REGEX)];
let umiTags = [];
umiSubPrompts.forEach((umiSubPrompt) => {
umiTags = umiTags.concat(
[...umiSubPrompt[0].matchAll(UMI_TAG_REGEX)].map((x) => x[1].toLowerCase())
);
});
TAC.Globals.originalTagword = TAC.Globals.tagword;
TAC.Globals.tagword = "";
TAC.Globals.umiPreviousTags = umiTags;
finalResults = finalResults.sort((a, b) => b.count - a.count);
return finalResults;
hideResults(textArea);
return true;
}
return false;
}
async function load() {
if (TAC.Globals.umiWildcards.length === 0) {
try {
let umiTags = (
await TacUtils.readFile(`${TAC.Globals.tagBasePath}/temp/umi_tags.txt`)
).split("\n");
// Split into tag, count pairs
TAC.Globals.umiWildcards = umiTags
.map((x) => x.trim().split(","))
.map(([i, ...rest]) => [
i,
rest.reduce((a, b) => {
a[b.toLowerCase()] = true;
return a;
}, {}),
]);
} catch (e) {
console.error("Error loading umi wildcards: " + e);
}
}
}
}
function updateUmiTags(tagType, sanitizedText, newPrompt, textArea) {
// If it was a umi wildcard, also update the TAC.Globals.umiPreviousTags
if (tagType === TAC.ResultType.umiWildcard && TAC.Globals.originalTagword.length > 0) {
let umiSubPrompts = [...newPrompt.matchAll(UMI_PROMPT_REGEX)];
let umiTags = [];
umiSubPrompts.forEach(umiSubPrompt => {
umiTags = umiTags.concat([...umiSubPrompt[0].matchAll(UMI_TAG_REGEX)].map(x => x[1].toLowerCase()));
});
TAC.Globals.umiPreviousTags = umiTags;
hideResults(textArea);
return true;
}
return false;
}
async function load() {
if (TAC.Globals.umiWildcards.length === 0) {
try {
let umiTags = (await TacUtils.readFile(`${TAC.Globals.tagBasePath}/temp/umi_tags.txt`)).split("\n");
// Split into tag, count pairs
TAC.Globals.umiWildcards = umiTags.map(x => x
.trim()
.split(","))
.map(([i, ...rest]) => [
i,
rest.reduce((a, b) => {
a[b.toLowerCase()] = true;
return a;
}, {}),
]);
} catch (e) {
console.error("Error loading umi wildcards: " + e);
function sanitize(tagType, text) {
// Replace underscores only if the umi tag is not using them
if (tagType === TAC.ResultType.umiWildcard && !TAC.Globals.umiWildcards.includes(text)) {
return text.replaceAll("_", " ");
}
return null;
}
}
function sanitize(tagType, text) {
// Replace underscores only if the umi tag is not using them
if (tagType === TAC.ResultType.umiWildcard && !TAC.Globals.umiWildcards.includes(text)) {
return text.replaceAll("_", " ");
}
return null;
}
// Add UMI parser
TAC.Ext.PARSERS.push(new UmiParser(UMI_TRIGGER));
// Add UMI parser
TAC.Ext.PARSERS.push(new UmiParser(UMI_TRIGGER));
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
TAC.Ext.QUEUE_AFTER_INSERT.push(updateUmiTags);
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
TAC.Ext.QUEUE_AFTER_INSERT.push(updateUmiTags);
})();

View File

@@ -1,178 +1,232 @@
// Regex
const WC_REGEX = new RegExp(/__([^,]+)__([^, ]*)/g);
(function WildcardExtension() {
// Regex
const WC_REGEX = new RegExp(/__([^,]+)__([^, ]*)/g);
// Trigger conditions
const WC_TRIGGER = () => TAC.CFG.useWildcards && [...TAC.Globals.tagword.matchAll(new RegExp(WC_REGEX.source.replaceAll("__", TacUtils.escapeRegExp(TAC.CFG.wcWrap)), "g"))].length > 0;
const WC_FILE_TRIGGER = () => TAC.CFG.useWildcards && (TAC.Globals.tagword.startsWith(TAC.CFG.wcWrap) && !TAC.Globals.tagword.endsWith(TAC.CFG.wcWrap) || TAC.Globals.tagword === TAC.CFG.wcWrap);
// Trigger conditions
const WC_TRIGGER = () =>
TAC.CFG.useWildcards &&
[
...TAC.Globals.tagword.matchAll(
new RegExp(
WC_REGEX.source.replaceAll("__", TacUtils.escapeRegExp(TAC.CFG.wcWrap)),
"g"
)
),
].length > 0;
const WC_FILE_TRIGGER = () =>
TAC.CFG.useWildcards &&
((TAC.Globals.tagword.startsWith(TAC.CFG.wcWrap) &&
!TAC.Globals.tagword.endsWith(TAC.CFG.wcWrap)) ||
TAC.Globals.tagword === TAC.CFG.wcWrap);
class WildcardParser extends BaseTagParser {
async parse() {
// Show wildcards from a file with that name
let wcMatch = [...TAC.Globals.tagword.matchAll(new RegExp(WC_REGEX.source.replaceAll("__", TacUtils.escapeRegExp(TAC.CFG.wcWrap)), "g"))];
let wcFile = wcMatch[0][1];
let wcWord = wcMatch[0][2];
class WildcardParser extends TAC.BaseTagParser {
async parse() {
// Show wildcards from a file with that name
let wcMatch = [
...TAC.Globals.tagword.matchAll(
new RegExp(
WC_REGEX.source.replaceAll("__", TacUtils.escapeRegExp(TAC.CFG.wcWrap)),
"g"
)
),
];
let wcFile = wcMatch[0][1];
let wcWord = wcMatch[0][2];
// Look in normal wildcard files
let wcFound = TAC.Globals.wildcardFiles.filter(x => x[1].toLowerCase() === wcFile);
if (wcFound.length === 0) wcFound = null;
// Use found wildcard file or look in external wildcard files
let wcPairs = wcFound || TAC.Globals.wildcardExtFiles.filter(x => x[1].toLowerCase() === wcFile);
// Look in normal wildcard files
let wcFound = TAC.Globals.wildcardFiles.filter((x) => x[1].toLowerCase() === wcFile);
if (wcFound.length === 0) wcFound = null;
// Use found wildcard file or look in external wildcard files
let wcPairs =
wcFound ||
TAC.Globals.wildcardExtFiles.filter((x) => x[1].toLowerCase() === wcFile);
if (!wcPairs) return [];
if (!wcPairs) return [];
let wildcards = [];
for (let i = 0; i < wcPairs.length; i++) {
const basePath = wcPairs[i][0];
const fileName = wcPairs[i][1];
if (!basePath || !fileName) return;
let wildcards = [];
for (let i = 0; i < wcPairs.length; i++) {
const basePath = wcPairs[i][0];
const fileName = wcPairs[i][1];
if (!basePath || !fileName) return;
// YAML wildcards are already loaded as json, so we can get the values directly.
// basePath is the name of the file in this case, and fileName the key
if (basePath.endsWith(".yaml")) {
const getDescendantProp = (obj, desc) => {
const arr = desc.split("/");
while (arr.length) {
obj = obj[arr.shift()];
}
return obj;
}
wildcards = wildcards.concat(getDescendantProp(TAC.Globals.yamlWildcards[basePath], fileName));
} else {
const fileContent = (await TacUtils.fetchAPI(`tacapi/v1/wildcard-contents?basepath=${basePath}&filename=${fileName}.txt`, false))
.split("\n")
.filter(x => x.trim().length > 0 && !x.startsWith('#')); // Remove empty lines and comments
wildcards = wildcards.concat(fileContent);
}
}
if (TAC.CFG.sortWildcardResults)
wildcards.sort((a, b) => a.localeCompare(b));
let finalResults = [];
let tempResults = wildcards.filter(x => (wcWord !== null && wcWord.length > 0) ? x.toLowerCase().includes(wcWord) : x) // Filter by tagword
tempResults.forEach(t => {
let result = new TAC.AutocompleteResult(t.trim(), TAC.ResultType.wildcardTag);
result.meta = wcFile;
finalResults.push(result);
});
return finalResults;
}
}
class WildcardFileParser extends BaseTagParser {
parse() {
// Show available wildcard files
let tempResults = [];
if (TAC.Globals.tagword !== TAC.CFG.wcWrap) {
let lmb = (x) => x[1].toLowerCase().includes(TAC.Globals.tagword.replace(TAC.CFG.wcWrap, ""))
tempResults = TAC.Globals.wildcardFiles.filter(lmb).concat(TAC.Globals.wildcardExtFiles.filter(lmb)) // Filter by tagword
} else {
tempResults = TAC.Globals.wildcardFiles.concat(TAC.Globals.wildcardExtFiles);
}
let finalResults = [];
const alreadyAdded = new Map();
// Get final results
tempResults.forEach(wcFile => {
// Skip duplicate entries incase multiple files have the same name or yaml category
if (alreadyAdded.has(wcFile[1])) return;
let result = null;
if (wcFile[0].endsWith(".yaml")) {
result = new TAC.AutocompleteResult(wcFile[1].trim(), TAC.ResultType.yamlWildcard);
result.meta = "YAML wildcard collection";
} else {
result = new TAC.AutocompleteResult(wcFile[1].trim(), TAC.ResultType.wildcardFile);
result.meta = "Wildcard file";
result.sortKey = wcFile[2].trim();
}
finalResults.push(result);
alreadyAdded.set(wcFile[1], true);
});
finalResults.sort(TacUtils.getSortFunction());
return finalResults;
}
}
async function load() {
if (TAC.Globals.wildcardFiles.length === 0 && TAC.Globals.wildcardExtFiles.length === 0) {
try {
let wcFileArr = await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/wc.txt`);
if (wcFileArr && wcFileArr.length > 0) {
let wcBasePath = wcFileArr[0][0].trim(); // First line should be the base path
TAC.Globals.wildcardFiles = wcFileArr.slice(1)
.filter(x => x[0]?.trim().length > 0) //Remove empty lines
.map(x => [wcBasePath, x[0]?.trim().replace(".txt", ""), x[1]]); // Remove file extension & newlines
}
// To support multiple sources, we need to separate them using the provided "-----" strings
let wcExtFileArr = await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/wce.txt`);
let splitIndices = [];
for (let index = 0; index < wcExtFileArr.length; index++) {
if (wcExtFileArr[index][0].trim() === "-----") {
splitIndices.push(index);
}
}
// For each group, add them to the wildcardFiles array with the base path as the first element
for (let i = 0; i < splitIndices.length; i++) {
let start = splitIndices[i - 1] || 0;
if (i > 0) start++; // Skip the "-----" line
let end = splitIndices[i];
let wcExtFile = wcExtFileArr.slice(start, end);
if (wcExtFile && wcExtFile.length > 0) {
let base = wcExtFile[0][0].trim() + "/";
wcExtFile = wcExtFile.slice(1)
.filter(x => x[0]?.trim().length > 0) //Remove empty lines
.map(x => [base, x[0]?.trim().replace(base, "").replace(".txt", ""), x[1]]);
TAC.Globals.wildcardExtFiles.push(...wcExtFile);
// YAML wildcards are already loaded as json, so we can get the values directly.
// basePath is the name of the file in this case, and fileName the key
if (basePath.endsWith(".yaml")) {
const getDescendantProp = (obj, desc) => {
const arr = desc.split("/");
while (arr.length) {
obj = obj[arr.shift()];
}
return obj;
};
wildcards = wildcards.concat(
getDescendantProp(TAC.Globals.yamlWildcards[basePath], fileName)
);
} else {
const fileContent = (
await TacUtils.fetchAPI(
`tacapi/v1/wildcard-contents?basepath=${basePath}&filename=${fileName}.txt`,
false
)
)
.split("\n")
.filter((x) => x.trim().length > 0 && !x.startsWith("#")); // Remove empty lines and comments
wildcards = wildcards.concat(fileContent);
}
}
// Load the yaml wildcard json file and append it as a wildcard file, appending each key as a path component until we reach the end
TAC.Globals.yamlWildcards = await TacUtils.readFile(`${TAC.Globals.tagBasePath}/temp/wc_yaml.json`, true);
if (TAC.CFG.sortWildcardResults) wildcards.sort((a, b) => a.localeCompare(b));
// Append each key as a path component until we reach a leaf
Object.keys(TAC.Globals.yamlWildcards).forEach(file => {
const flattened = TacUtils.flatten(TAC.Globals.yamlWildcards[file], [], "/");
Object.keys(flattened).forEach(key => {
TAC.Globals.wildcardExtFiles.push([file, key]);
});
let finalResults = [];
let tempResults = wildcards.filter((x) =>
wcWord !== null && wcWord.length > 0 ? x.toLowerCase().includes(wcWord) : x
); // Filter by tagword
tempResults.forEach((t) => {
let result = new TAC.AutocompleteResult(t.trim(), TAC.ResultType.wildcardTag);
result.meta = wcFile;
finalResults.push(result);
});
} catch (e) {
console.error("Error loading wildcards: " + e);
return finalResults;
}
}
}
function sanitize(tagType, text) {
if (tagType === TAC.ResultType.wildcardFile || tagType === TAC.ResultType.yamlWildcard) {
return `${TAC.CFG.wcWrap}${text}${TAC.CFG.wcWrap}`;
} else if (tagType === TAC.ResultType.wildcardTag) {
return text;
class WildcardFileParser extends TAC.BaseTagParser {
parse() {
// Show available wildcard files
let tempResults = [];
if (TAC.Globals.tagword !== TAC.CFG.wcWrap) {
let lmb = (x) =>
x[1].toLowerCase().includes(TAC.Globals.tagword.replace(TAC.CFG.wcWrap, ""));
tempResults = TAC.Globals.wildcardFiles
.filter(lmb)
.concat(TAC.Globals.wildcardExtFiles.filter(lmb)); // Filter by tagword
} else {
tempResults = TAC.Globals.wildcardFiles.concat(TAC.Globals.wildcardExtFiles);
}
let finalResults = [];
const alreadyAdded = new Map();
// Get final results
tempResults.forEach((wcFile) => {
// Skip duplicate entries incase multiple files have the same name or yaml category
if (alreadyAdded.has(wcFile[1])) return;
let result = null;
if (wcFile[0].endsWith(".yaml")) {
result = new TAC.AutocompleteResult(
wcFile[1].trim(),
TAC.ResultType.yamlWildcard
);
result.meta = "YAML wildcard collection";
} else {
result = new TAC.AutocompleteResult(
wcFile[1].trim(),
TAC.ResultType.wildcardFile
);
result.meta = "Wildcard file";
result.sortKey = wcFile[2].trim();
}
finalResults.push(result);
alreadyAdded.set(wcFile[1], true);
});
finalResults.sort(TacUtils.getSortFunction());
return finalResults;
}
}
return null;
}
function keepOpenIfWildcard(tagType, sanitizedText, newPrompt, textArea) {
// If it's a wildcard, we want to keep the results open so the user can select another wildcard
if (tagType === TAC.ResultType.wildcardFile || tagType === TAC.ResultType.yamlWildcard) {
TAC.Globals.hideBlocked = true;
setTimeout(() => { TAC.Globals.hideBlocked = false; }, 450);
return true;
async function load() {
if (TAC.Globals.wildcardFiles.length === 0 && TAC.Globals.wildcardExtFiles.length === 0) {
try {
let wcFileArr = await TacUtils.loadCSV(`${TAC.Globals.tagBasePath}/temp/wc.txt`);
if (wcFileArr && wcFileArr.length > 0) {
let wcBasePath = wcFileArr[0][0].trim(); // First line should be the base path
TAC.Globals.wildcardFiles = wcFileArr
.slice(1)
.filter((x) => x[0]?.trim().length > 0) //Remove empty lines
.map((x) => [wcBasePath, x[0]?.trim().replace(".txt", ""), x[1]]); // Remove file extension & newlines
}
// To support multiple sources, we need to separate them using the provided "-----" strings
let wcExtFileArr = await TacUtils.loadCSV(
`${TAC.Globals.tagBasePath}/temp/wce.txt`
);
let splitIndices = [];
for (let index = 0; index < wcExtFileArr.length; index++) {
if (wcExtFileArr[index][0].trim() === "-----") {
splitIndices.push(index);
}
}
// For each group, add them to the wildcardFiles array with the base path as the first element
for (let i = 0; i < splitIndices.length; i++) {
let start = splitIndices[i - 1] || 0;
if (i > 0) start++; // Skip the "-----" line
let end = splitIndices[i];
let wcExtFile = wcExtFileArr.slice(start, end);
if (wcExtFile && wcExtFile.length > 0) {
let base = wcExtFile[0][0].trim() + "/";
wcExtFile = wcExtFile
.slice(1)
.filter((x) => x[0]?.trim().length > 0) //Remove empty lines
.map((x) => [
base,
x[0]?.trim().replace(base, "").replace(".txt", ""),
x[1],
]);
TAC.Globals.wildcardExtFiles.push(...wcExtFile);
}
}
// Load the yaml wildcard json file and append it as a wildcard file, appending each key as a path component until we reach the end
TAC.Globals.yamlWildcards = await TacUtils.readFile(
`${TAC.Globals.tagBasePath}/temp/wc_yaml.json`,
true
);
// Append each key as a path component until we reach a leaf
Object.keys(TAC.Globals.yamlWildcards).forEach((file) => {
const flattened = TacUtils.flatten(TAC.Globals.yamlWildcards[file], [], "/");
Object.keys(flattened).forEach((key) => {
TAC.Globals.wildcardExtFiles.push([file, key]);
});
});
} catch (e) {
console.error("Error loading wildcards: " + e);
}
}
}
return false;
}
// Register the parsers
TAC.Ext.PARSERS.push(new WildcardParser(WC_TRIGGER));
TAC.Ext.PARSERS.push(new WildcardFileParser(WC_FILE_TRIGGER));
function sanitize(tagType, text) {
if (tagType === TAC.ResultType.wildcardFile || tagType === TAC.ResultType.yamlWildcard) {
return `${TAC.CFG.wcWrap}${text}${TAC.CFG.wcWrap}`;
} else if (tagType === TAC.ResultType.wildcardTag) {
return text;
}
return null;
}
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
TAC.Ext.QUEUE_AFTER_INSERT.push(keepOpenIfWildcard);
function keepOpenIfWildcard(tagType, sanitizedText, newPrompt, textArea) {
// If it's a wildcard, we want to keep the results open so the user can select another wildcard
if (tagType === TAC.ResultType.wildcardFile || tagType === TAC.ResultType.yamlWildcard) {
TAC.Globals.hideBlocked = true;
setTimeout(() => {
TAC.Globals.hideBlocked = false;
}, 450);
return true;
}
return false;
}
// Register the parsers
TAC.Ext.PARSERS.push(new WildcardParser(WC_TRIGGER));
TAC.Ext.PARSERS.push(new WildcardFileParser(WC_FILE_TRIGGER));
// Add our utility functions to their respective queues
TAC.Ext.QUEUE_FILE_LOAD.push(load);
TAC.Ext.QUEUE_SANITIZE.push(sanitize);
TAC.Ext.QUEUE_AFTER_INSERT.push(keepOpenIfWildcard);
})();