refactor: improve code readability and performance logging in autocomplete and similar tags logic
This commit is contained in:
+23
-19
@@ -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
@@ -1,4 +1,5 @@
|
||||
// Constants
|
||||
// --- Constants ---
|
||||
// Tag categories for display
|
||||
export const TagCategory = [
|
||||
'general',
|
||||
'artist',
|
||||
|
||||
+5
-1
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user