mirror of
https://github.com/DominikDoom/a1111-sd-webui-tagcomplete.git
synced 2026-01-26 19:19:57 +00:00
Last used & min count settings
Also some performance improvements
This commit is contained in:
@@ -173,7 +173,16 @@ function flatten(obj, roots = [], sep = ".") {
|
||||
}
|
||||
|
||||
// Calculate biased tag score based on post count and frequent usage
|
||||
function calculateUsageBias(count, uses) {
|
||||
function calculateUsageBias(result, count, uses, lastUseDate) {
|
||||
// Guard for minimum usage count & last usage date
|
||||
const diffTime = Math.abs(Date.now() - (lastUseDate || Date.now()));
|
||||
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
||||
if (uses < TAC_CFG.frequencyMinCount || diffDays > TAC_CFG.frequencyMaxAge) {
|
||||
uses = 0;
|
||||
} else if (uses != 0) {
|
||||
result.usageBias = true;
|
||||
}
|
||||
|
||||
switch (TAC_CFG.frequencyFunction) {
|
||||
case "Logarithmic (weak)":
|
||||
return Math.log(1 + count) + Math.log(1 + uses);
|
||||
@@ -187,7 +196,14 @@ function calculateUsageBias(count, uses) {
|
||||
}
|
||||
// Beautify return type for easier parsing
|
||||
function mapUseCountArray(useCounts) {
|
||||
return useCounts.map(useCount => {return {"name": useCount[0], "type": useCount[1], "count": useCount[2]}});
|
||||
return useCounts.map(useCount => {
|
||||
return {
|
||||
"name": useCount[0],
|
||||
"type": useCount[1],
|
||||
"count": useCount[2],
|
||||
"lastUseDate": useCount[3]
|
||||
}
|
||||
});
|
||||
}
|
||||
// Call API endpoint to increase bias of tag in the database
|
||||
function increaseUseCount(tagName, type, negative = false) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const styleColors = {
|
||||
const styleColors = {
|
||||
"--results-bg": ["#0b0f19", "#ffffff"],
|
||||
"--results-border-color": ["#4b5563", "#e5e7eb"],
|
||||
"--results-border-width": ["1px", "1.5px"],
|
||||
@@ -224,6 +224,8 @@ async function syncOptions() {
|
||||
modelSortOrder: opts["tac_modelSortOrder"],
|
||||
frequencySort: opts["tac_frequencySort"],
|
||||
frequencyFunction: opts["tac_frequencyFunction"],
|
||||
frequencyMinCount: opts["tac_frequencyMinCount"],
|
||||
frequencyMaxAge: opts["tac_frequencyMaxAge"],
|
||||
// Insertion related settings
|
||||
replaceUnderscores: opts["tac_replaceUnderscores"],
|
||||
escapeParentheses: opts["tac_escapeParentheses"],
|
||||
@@ -1169,7 +1171,6 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
||||
|
||||
// Request use counts from the DB
|
||||
const counts = await getUseCounts(names, types, isNegative);
|
||||
const usedResults = counts.filter(c => c.count > 0).map(c => c.name);
|
||||
|
||||
// Sort all
|
||||
results = results.sort((a, b) => {
|
||||
@@ -1178,19 +1179,16 @@ async function autocomplete(textArea, prompt, fixedTag = null) {
|
||||
|
||||
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 aUses = aUseStats?.count || 0;
|
||||
const bUses = bUseStats?.count || 0;
|
||||
const aLastUseDate = Date.parse(aUseStats?.lastUseDate);
|
||||
const bLastUseDate = Date.parse(bUseStats?.lastUseDate);
|
||||
|
||||
const aWeight = calculateUsageBias(a.count, aUseStats ? aUseStats.count : 0);
|
||||
const bWeight = calculateUsageBias(b.count, bUseStats ? bUseStats.count : 0);
|
||||
const aWeight = calculateUsageBias(a, a.count, aUses, aLastUseDate);
|
||||
const bWeight = calculateUsageBias(b, b.count, bUses, bLastUseDate);
|
||||
|
||||
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
|
||||
|
||||
@@ -421,6 +421,8 @@ def on_ui_settings():
|
||||
"tac_modelSortOrder": shared.OptionInfo("Name", "Model sort order", gr.Dropdown, lambda: {"choices": list(sort_criteria.keys())}).info("Order for extra network models and wildcards in dropdown"),
|
||||
"tac_frequencySort": shared.OptionInfo(True, "Locally record tag usage and sort frequent tags higher").info("Will also work for extra networks, keeping the specified base order"),
|
||||
"tac_frequencyFunction": shared.OptionInfo("Logarithmic (weak)", "Function to use for frequency sorting", gr.Dropdown, lambda: {"choices": list(frequency_sort_functions.keys())}).info("; ".join([f'<b>{key}</b>: {val}' for key, val in frequency_sort_functions.items()])),
|
||||
"tac_frequencyMinCount": shared.OptionInfo(3, "Minimum number of uses for a tag to be considered frequent").info("Tags with less uses than this will not be sorted higher, even if the sorting function would normally result in a higher position."),
|
||||
"tac_frequencyMaxAge": shared.OptionInfo(30, "Maximum days since last use for a tag to be considered frequent").info("Similar to the above, tags that haven't been used in this many days will not be sorted higher."),
|
||||
# Insertion related settings
|
||||
"tac_replaceUnderscores": shared.OptionInfo(True, "Replace underscores with spaces on insertion"),
|
||||
"tac_escapeParentheses": shared.OptionInfo(True, "Escape parentheses on insertion"),
|
||||
@@ -597,7 +599,7 @@ def api_tac(_: gr.Blocks, app: FastAPI):
|
||||
if get:
|
||||
ret = func()
|
||||
if ret is list:
|
||||
ret = [{"name": t[0], "type": t[1], "count": t[2]} for t in ret]
|
||||
ret = [{"name": t[0], "type": t[1], "count": t[2], "lastUseDate": t[3]} for t in ret]
|
||||
return JSONResponse({"result": ret})
|
||||
else:
|
||||
func()
|
||||
|
||||
@@ -91,7 +91,7 @@ class TagFrequencyDb:
|
||||
with transaction() as cursor:
|
||||
cursor.execute(
|
||||
f"""
|
||||
SELECT name, type, {count_str}
|
||||
SELECT name, type, {count_str}, last_used
|
||||
FROM tag_frequency
|
||||
ORDER BY {count_str} DESC
|
||||
"""
|
||||
@@ -105,15 +105,15 @@ class TagFrequencyDb:
|
||||
with transaction() as cursor:
|
||||
cursor.execute(
|
||||
f"""
|
||||
SELECT {count_str}
|
||||
SELECT {count_str}, last_used
|
||||
FROM tag_frequency
|
||||
WHERE name = ? AND type = ?
|
||||
""",
|
||||
(tag,ttype),
|
||||
(tag, ttype),
|
||||
)
|
||||
tag_count = cursor.fetchone()
|
||||
|
||||
return tag_count[0] if tag_count else 0
|
||||
return tag_count[0], tag_count[1] if tag_count else 0
|
||||
|
||||
def get_tag_counts(self, tags: list[str], ttypes: list[str], negative=False):
|
||||
count_str = "count_neg" if negative else "count_pos"
|
||||
@@ -121,18 +121,18 @@ class TagFrequencyDb:
|
||||
for tag, ttype in zip(tags, ttypes):
|
||||
cursor.execute(
|
||||
f"""
|
||||
SELECT {count_str}
|
||||
SELECT {count_str}, last_used
|
||||
FROM tag_frequency
|
||||
WHERE name = ? AND type = ?
|
||||
""",
|
||||
(tag,ttype),
|
||||
(tag, ttype),
|
||||
)
|
||||
tag_count = cursor.fetchone()
|
||||
yield (tag, ttype, tag_count[0]) if tag_count else (tag, ttype, 0)
|
||||
yield (tag, ttype, tag_count[0], tag_count[1]) if tag_count else (tag, ttype, 0)
|
||||
|
||||
def increase_tag_count(self, tag, ttype, negative=False):
|
||||
pos_count = self.get_tag_count(tag, ttype, False)
|
||||
neg_count = self.get_tag_count(tag, ttype, True)
|
||||
pos_count = self.get_tag_count(tag, ttype, False)[0]
|
||||
neg_count = self.get_tag_count(tag, ttype, True)[0]
|
||||
|
||||
if negative:
|
||||
neg_count += 1
|
||||
@@ -156,7 +156,7 @@ class TagFrequencyDb:
|
||||
set_str = "count_pos = 0"
|
||||
elif negative:
|
||||
set_str = "count_neg = 0"
|
||||
|
||||
|
||||
with transaction() as cursor:
|
||||
cursor.execute(
|
||||
f"""
|
||||
@@ -164,5 +164,5 @@ class TagFrequencyDb:
|
||||
SET {set_str}
|
||||
WHERE name = ? AND type = ?
|
||||
""",
|
||||
(tag,ttype),
|
||||
(tag, ttype),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user