mirror of
https://github.com/DominikDoom/a1111-sd-webui-tagcomplete.git
synced 2026-01-26 19:19:57 +00:00
Sort results by usage count
This commit is contained in:
@@ -24,6 +24,7 @@ class AutocompleteResult {
|
||||
// Additional info, only used in some cases
|
||||
category = null;
|
||||
count = null;
|
||||
usageBias = null;
|
||||
aliases = null;
|
||||
meta = null;
|
||||
hash = null;
|
||||
|
||||
@@ -170,25 +170,31 @@ function flatten(obj, roots = [], sep = ".") {
|
||||
}
|
||||
|
||||
// Calculate biased tag score based on post count and frequent usage
|
||||
function tagBias(count, uses) {
|
||||
return Math.log(count) + Math.log(uses);
|
||||
function calculateUsageBias(count, uses) {
|
||||
return Math.log(1 + count) + Math.log(1 + uses);
|
||||
}
|
||||
// Beautify return type for easier parsing
|
||||
function mapUseCountArray(useCounts) {
|
||||
return useCounts.map(useCount => {return {"name": useCount[0], "type": useCount[1], "count": useCount[2]}});
|
||||
}
|
||||
// Call API endpoint to increase bias of tag in the database
|
||||
function increaseUseCount(tagName, type) {
|
||||
postAPI(`tacapi/v1/increase-use-count?tagname=${tagName}&ttype=${type}`, null);
|
||||
async function increaseUseCount(tagName, type) {
|
||||
await postAPI(`tacapi/v1/increase-use-count?tagname=${tagName}&ttype=${type}`, null);
|
||||
}
|
||||
// Get use count of tag from the database
|
||||
async function getUseCount(tagName, type) {
|
||||
return (await fetchAPI(`tacapi/v1/get-use-count?tagname=${tagName}&ttype=${type}`, true, false))["result"];
|
||||
}
|
||||
async function getUseCounts(tagNames, types) {
|
||||
return (await fetchAPI(`tacapi/v1/get-use-count-list?tags=${tagNames.join("&tags=")}&ttypes=${types.join("&ttypes=")}`))["result"];
|
||||
const rawArray = (await fetchAPI(`tacapi/v1/get-use-count-list?tags=${tagNames.join("&tags=")}&ttypes=${types.join("&ttypes=")}`))["result"]
|
||||
return mapUseCountArray(rawArray);
|
||||
}
|
||||
async function getAllUseCounts() {
|
||||
return (await fetchAPI(`tacapi/v1/get-all-use-counts`))["result"];
|
||||
const rawArray = (await fetchAPI(`tacapi/v1/get-all-use-counts`))["result"];
|
||||
return mapUseCountArray(rawArray);
|
||||
}
|
||||
async function resetUseCount(tagName, type) {
|
||||
putAPI(`tacapi/v1/reset-use-count?tagname=${tagName}&ttype=${type}`, null);
|
||||
await putAPI(`tacapi/v1/reset-use-count?tagname=${tagName}&ttype=${type}`, null);
|
||||
}
|
||||
|
||||
// Sliding window function to get possible combination groups of an array
|
||||
|
||||
@@ -84,6 +84,10 @@ const autocompleteCSS = `
|
||||
white-space: nowrap;
|
||||
color: var(--meta-text-color);
|
||||
}
|
||||
.acMetaText.biased::before {
|
||||
content: "✨";
|
||||
margin-right: 2px;
|
||||
}
|
||||
.acWikiLink {
|
||||
padding: 0.5rem;
|
||||
margin: -0.5rem 0 -0.5rem -0.5rem;
|
||||
@@ -486,7 +490,7 @@ async function insertTextAtCursor(textArea, result, tagword, tabCompletedWithout
|
||||
// Sanitize name for API call
|
||||
name = encodeURIComponent(name)
|
||||
// Call API & update db
|
||||
increaseUseCount(name, tagType)
|
||||
await increaseUseCount(name, tagType)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -773,6 +777,11 @@ function addResultsToList(textArea, results, tagword, resetList) {
|
||||
flexDiv.appendChild(metaDiv);
|
||||
}
|
||||
|
||||
// Add small ✨ marker to indicate usage sorting
|
||||
if (result.usageBias) {
|
||||
flexDiv.querySelector(".acMetaText").classList.add("biased");
|
||||
}
|
||||
|
||||
// Add listener
|
||||
li.addEventListener("click", function () { insertTextAtCursor(textArea, result, tagword); });
|
||||
// Add element to list
|
||||
@@ -1042,6 +1051,9 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
||||
resultCountBeforeNormalTags = 0;
|
||||
tagword = tagword.toLowerCase().replace(/[\n\r]/g, "");
|
||||
|
||||
// Needed for slicing check later
|
||||
let normalTags = false;
|
||||
|
||||
// Process all parsers
|
||||
let resultCandidates = (await processParsers(textArea, prompt))?.filter(x => x.length > 0);
|
||||
// If one ore more result candidates match, use their results
|
||||
@@ -1077,6 +1089,7 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
||||
if (!resultCandidates || resultCandidates.length === 0
|
||||
|| (TAC_CFG.includeEmbeddingsInNormalResults && !(tagword.startsWith("<") || tagword.startsWith("*<")))
|
||||
) {
|
||||
normalTags = true;
|
||||
resultCountBeforeNormalTags = results.length;
|
||||
|
||||
// Create escaped search regex with support for * as a start placeholder
|
||||
@@ -1131,11 +1144,6 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
||||
results = results.concat(extraResults);
|
||||
}
|
||||
}
|
||||
|
||||
// Slice if the user has set a max result count
|
||||
if (!TAC_CFG.showAllResults) {
|
||||
results = results.slice(0, TAC_CFG.maxResults + resultCountBeforeNormalTags);
|
||||
}
|
||||
}
|
||||
|
||||
// Guard for empty results
|
||||
@@ -1145,6 +1153,49 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort again with frequency / usage count if enabled
|
||||
if (TAC_CFG.frequencySort) {
|
||||
// Split our results into a list of names and types
|
||||
let names = [];
|
||||
let types = [];
|
||||
// We need to limit size for the request url
|
||||
results.slice(0, 100).forEach(r => {
|
||||
const name = r.type === ResultType.chant ? r.aliases : r.text;
|
||||
names.push(name);
|
||||
types.push(r.type);
|
||||
});
|
||||
|
||||
// Request use counts from the DB
|
||||
const counts = await getUseCounts(names, types);
|
||||
const usedResults = counts.filter(c => c.count > 0).map(c => c.name);
|
||||
|
||||
// Sort all
|
||||
results = results.sort((a, b) => {
|
||||
const aName = a.type === ResultType.chant ? a.aliases : a.text;
|
||||
const bName = b.type === ResultType.chant ? b.aliases : b.text;
|
||||
|
||||
const aUseStats = counts.find(c => c.name === aName && c.type === a.type);
|
||||
const bUseStats = counts.find(c => c.name === bName && c.type === b.type);
|
||||
|
||||
const aWeight = calculateUsageBias(a.count || 0, aUseStats ? aUseStats.count : 0);
|
||||
const bWeight = calculateUsageBias(b.count || 0, bUseStats ? bUseStats.count : 0);
|
||||
|
||||
return bWeight - aWeight;
|
||||
});
|
||||
|
||||
// Mark results
|
||||
results.forEach(r => {
|
||||
const name = r.type === ResultType.chant ? r.aliases : r.text;
|
||||
if (usedResults.includes(name))
|
||||
r.usageBias = true;
|
||||
});
|
||||
}
|
||||
|
||||
// Slice if the user has set a max result count and we are not in a extra networks / wildcard list
|
||||
if (!TAC_CFG.showAllResults && normalTags) {
|
||||
results = results.slice(0, TAC_CFG.maxResults + resultCountBeforeNormalTags);
|
||||
}
|
||||
|
||||
addResultsToList(textArea, results, tagword, true);
|
||||
showResults(textArea);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user