refactor: improve code readability and performance logging in autocomplete and similar tags logic

This commit is contained in:
newtextdoc1111
2025-05-07 12:37:27 +09:00
parent d71730ad16
commit eff7437945
5 changed files with 82 additions and 41 deletions
+23 -19
View File
@@ -1,4 +1,4 @@
import {
import {
TagCategory,
autoCompleteData
} from './data.js';
@@ -538,7 +538,7 @@ const autocompleteUI = new AutocompleteUI();
* @returns {Array<{tag: string, count: number, alias?: string}>}
*/
function findCompletionCandidates(query) {
const startTime = performance.now(); // 検索開始時間を記録
const startTime = performance.now(); // Record start time for performance measurement
if (!query) {
return [];
@@ -568,7 +568,7 @@ function findCompletionCandidates(query) {
// Ensure tagData.tag is treated as lowercase for comparison
const lowerTag = tagData.tag.toLowerCase();
// Check primary tag against all variations for exact match first
for (const variation of queryVariations) {
if (lowerTag === variation || lowerTag === variation.replace(/[\-_\s]/g, '')) {
@@ -577,7 +577,7 @@ function findCompletionCandidates(query) {
break;
}
}
// If not an exact match, check for partial matches in the tag
if (!isExactMatch) {
for (const variation of queryVariations) {
@@ -596,7 +596,7 @@ function findCompletionCandidates(query) {
if (!matched && tagData.alias && Array.isArray(tagData.alias) && tagData.alias.length > 0) {
for (const alias of tagData.alias) {
const lowerAlias = alias.toLowerCase();
// Check for exact matches in aliases first
for (const variation of queryVariations) {
if (lowerAlias === variation) {
@@ -606,7 +606,7 @@ function findCompletionCandidates(query) {
break;
}
}
// If not an exact match in alias, check for partial matches
if (!isExactMatch) {
for (const variation of queryVariations) {
@@ -617,7 +617,7 @@ function findCompletionCandidates(query) {
}
}
}
if (matched) break; // Stop checking aliases for this tag if one matched
}
}
@@ -630,25 +630,27 @@ function findCompletionCandidates(query) {
category: tagData.category,
count: tagData.count,
};
// Add to exact matches or partial matches based on match type
if (isExactMatch) {
exactMatches.push(candidateItem);
} else {
partialMatches.push(candidateItem);
}
addedTags.add(tagData.tag);
// Check if we've reached the maximum suggestions limit combining both arrays
if (exactMatches.length + partialMatches.length >= settingValues.maxSuggestions) {
// Return the combined results, prioritizing exact matches
const result = [...exactMatches, ...partialMatches].slice(0, settingValues.maxSuggestions);
// const endTime = performance.now();
// const duration = endTime - startTime;
// console.debug(`[Autocomplete-Plus] Search for "${query}" took ${duration.toFixed(2)}ms. Found ${result.length} candidates (max reached).`);
if (settingValues.logprocessingTime) {
const endTime = performance.now();
const duration = endTime - startTime;
console.debug(`[Autocomplete-Plus] Search for "${query}" took ${duration.toFixed(2)}ms. Found ${result.length} candidates (max reached).`);
}
return result; // Early exit
}
}
@@ -656,10 +658,12 @@ function findCompletionCandidates(query) {
// Combine results, with exact matches first
const candidates = [...exactMatches, ...partialMatches];
// const endTime = performance.now();
// const duration = endTime - startTime;
// console.debug(`[Autocomplete-Plus] Search for "${query}" took ${duration.toFixed(2)}ms. Found ${candidates.length} candidates.`);
if (settingValues.logprocessingTime) {
const endTime = performance.now();
const duration = endTime - startTime;
console.debug(`[Autocomplete-Plus] Search for "${query}" took ${duration.toFixed(2)}ms. Found ${candidates.length} candidates.`);
}
return candidates;
}
@@ -790,7 +794,7 @@ export class AutocompleteEventHandler {
}
handleBlur(event) {
if(!settingValues.hideWhenOutofFocus) return;
if (!settingValues.hideWhenOutofFocus) return;
// Need a slight delay because clicking the autocomplete list causes blur
setTimeout(() => {
+2 -1
View File
@@ -1,4 +1,5 @@
// Constants
// --- Constants ---
// Tag categories for display
export const TagCategory = [
'general',
'artist',
+5 -1
View File
@@ -7,5 +7,9 @@ export const settingValues = {
enableSimilarTags: true,
maxSimilarTags: 20,
similarTagsDisplayPosition: 'horizontal', // 'horizontal' or 'vertical'
hideWhenOutofFocus: true, // Hide similar tags when the input is out of focus
// Debugging settings (use internally)
hideWhenOutofFocus: true, // Hide UI when the input is out of focus
logprocessingTime: true, // Log processing time for debugging
}
+21 -12
View File
@@ -4,6 +4,7 @@ import { TagCategory, autoCompleteData } from './data.js';
import {
normalizeTagToInsert,
normalizeTagToSearch,
isValidTag,
getViewportMargin
} from './utils.js';
@@ -96,7 +97,7 @@ class SimilarTagsUI {
// Update header with current tag
this.header.innerHTML = ''; // Clear previous content
this.header.textContent = 'Similar Tags: ';
this.header.textContent = 'Tags related to: ';
const tagNameSpan = document.createElement('span');
tagNameSpan.className = 'similar-tags-header-tag-name';
tagNameSpan.textContent = this.currentTag;
@@ -266,15 +267,15 @@ class SimilarTagsUI {
height: Math.min(elemHeight, viewportHeight - margin.top - margin.bottom)
};
if(settingValues.similarTagsDisplayPosition === 'vertical') {
if (settingValues.similarTagsDisplayPosition === 'vertical') {
// Vertical placement
const topSpace = inputRect.top - margin.top;
const bottomSpace = viewportHeight - inputRect.bottom - margin.bottom;
if(topSpace > bottomSpace) {
if (topSpace > bottomSpace) {
// Place above
area.height = Math.min(area.height, topSpace);
area.y = Math.max(inputRect.y - area.height, margin.top);
}else{
} else {
// Place below
area.height = Math.min(area.height, bottomSpace);
area.y = inputRect.bottom;
@@ -282,15 +283,15 @@ class SimilarTagsUI {
// Adjust x position to avoid overflow
area.x = Math.min(area.x, viewportWidth - area.width - margin.right);
}else{
} else {
// Horizontal placement
const leftSpace = inputRect.x - margin.left;
const rightSpace = viewportWidth - inputRect.right - margin.right;
if(leftSpace > rightSpace) {
if (leftSpace > rightSpace) {
// Place left
area.width = Math.min(area.width, leftSpace);
area.x = Math.max(inputRect.x - area.width, margin.left);
}else{
} else {
// Place right
area.width = Math.min(area.width, rightSpace);
area.x = inputRect.right;
@@ -337,6 +338,8 @@ function calculateJaccardSimilarity(tagA, tagB) {
* @returns {Array<{tag: string, similarity: number, count: number, alias?: string[]}>}
*/
function findSimilarTags(tag) {
const startTime = performance.now(); // Record start time for performance measurement
if (!tag || !autoCompleteData.cooccurrenceMap.has(tag)) {
return [];
}
@@ -369,7 +372,13 @@ function findSimilarTags(tag) {
similarTags.sort((a, b) => b.similarity - a.similarity);
// Limit to max number of suggestions
return similarTags.slice(0, settingValues.maxSimilarTags);
const result = similarTags.slice(0, settingValues.maxSimilarTags);
const endTime = performance.now();
const duration = endTime - startTime;
console.debug(`[Related-Tags] Find tags to related "${tag}" took ${duration.toFixed(2)}ms.`);
return result;
}
/**
@@ -408,7 +417,7 @@ function getCurrentTag(inputElement) {
// If no tag found, return null
if (!tag) return null;
// Process the tag: swap underscores/spaces and unescape parentheses
return normalizeTagToSearch(tag);
}
@@ -573,7 +582,7 @@ function showSimilarTagsForCurrentPosition(textareaElement) {
const currentTag = getCurrentTag(textareaElement);
// If no valid tag or tag is too short, hide the panel
if (!currentTag || currentTag.length < 2) {
if (!isValidTag(currentTag)) {
similarTagsUI.hide();
return;
}
@@ -603,7 +612,7 @@ export class SimilarTagsEventHandler {
}
handleBlur(event) {
if(!settingValues.hideWhenOutofFocus) {
if (!settingValues.hideWhenOutofFocus) {
return;
}
@@ -643,7 +652,7 @@ export class SimilarTagsEventHandler {
}
handleMouseMove(event) {
}
handleClick(event) {
+31 -8
View File
@@ -85,10 +85,10 @@ export function unescapeParentheses(str) {
*/
export function removePromptWeight(str) {
if (!str) return str;
// First remove weight notation (e.g., ":1.2")
let result = str.replace(/(.+?):\d+(\.\d+)?/, '$1');
// Then remove non-escaped brackets at the beginning and/or end
// Use negative lookbehind (?<!\\) to avoid matching escaped brackets
result = result.replace(/^(?<!\\)\((.+)$/, '$1');
@@ -102,7 +102,7 @@ export function removePromptWeight(str) {
* @returns
*/
export function normalizeTagToSearch(str) {
if(!str) return str;
if (!str) return str;
return unescapeParentheses(removePromptWeight(str).replace(/ /g, "_"));
}
@@ -115,6 +115,29 @@ export function normalizeTagToInsert(str) {
return escapeParentheses(str.replace(/_/g, " "));
}
/**
* Checks if a tag is valid.
* @param {string} tag
* @returns
*/
export function isValidTag(tag) {
if (!tag || tag.length < 2) {
return false;
}
// Skip wildcard notation (e.g., "__character__")
if (tag.startsWith('__') && tag.endsWith('__')) {
return false;
}
// Skip Lora notation (e.g., "<lora:lorapath/loraname:0.8>")
if (/<lora:.+>/i.test(tag)) {
return false;
}
return true;
}
// --- End String Helper Functions ---
// Function to load a CSS file
@@ -133,11 +156,11 @@ export function loadCSS(href) {
* Get the viewport margin based on the positions of the top, bottom, left, and right bars.
* @returns {Object} - An object containing the top, bottom, left, and right margins of the viewport.
*/
export function getViewportMargin(){
const topBarRect = document.querySelector("#comfyui-body-top")?.getBoundingClientRect() || {top: 0, bottom: 0};
const bottomBarRect = document.querySelector("#comfyui-body-bottom")?.getBoundingClientRect() || {top: 0, bottom: 0};
const leftBarRect = document.querySelector("#comfyui-body-left")?.getBoundingClientRect() || {left: 0, right: 0};
const rightBarRect = document.querySelector("#comfyui-body-right")?.getBoundingClientRect() || {left: 0, right: 0};
export function getViewportMargin() {
const topBarRect = document.querySelector("#comfyui-body-top")?.getBoundingClientRect() || { top: 0, bottom: 0 };
const bottomBarRect = document.querySelector("#comfyui-body-bottom")?.getBoundingClientRect() || { top: 0, bottom: 0 };
const leftBarRect = document.querySelector("#comfyui-body-left")?.getBoundingClientRect() || { left: 0, right: 0 };
const rightBarRect = document.querySelector("#comfyui-body-right")?.getBoundingClientRect() || { left: 0, right: 0 };
return {
top: topBarRect.height,