From eb29f03ab01072eae8cd860608869f3756bcde9f Mon Sep 17 00:00:00 2001 From: Joe Date: Sat, 23 Nov 2024 20:11:46 -0800 Subject: [PATCH 01/31] Sped up character search by 93% --- public/scripts/power-user.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 43c26bf21..088a56a10 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -330,6 +330,12 @@ const debug_functions = []; const setHotswapsDebounced = debounce(favsToHotswap); +const fuzzySearchCharactersCache = new Map(); +const fuzzySearchWorldInfoCache = new Map(); +const fuzzySearchPersonasCache = new Map(); +const fuzzySearchTagsCache = new Map(); +const fuzzySearchGroupsCache = new Map(); + function playMessageSound() { if (!power_user.play_message_sound) { return; @@ -1830,6 +1836,11 @@ async function loadContextSettings() { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchCharacters(searchValue) { + + if (fuzzySearchCharactersCache.has(searchValue)) { + return fuzzySearchCharactersCache.get(searchValue); + } + // @ts-ignore const fuse = new Fuse(characters, { keys: [ @@ -1853,6 +1864,7 @@ export function fuzzySearchCharacters(searchValue) { const results = fuse.search(searchValue); console.debug('Characters fuzzy search results for ' + searchValue, results); + fuzzySearchCharactersCache.set(searchValue, results); return results; } @@ -1863,6 +1875,10 @@ export function fuzzySearchCharacters(searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchWorldInfo(data, searchValue) { + if (fuzzySearchWorldInfoCache.has(searchValue)) { + return fuzzySearchWorldInfoCache.get(searchValue); + } + // @ts-ignore const fuse = new Fuse(data, { keys: [ @@ -1882,6 +1898,7 @@ export function fuzzySearchWorldInfo(data, searchValue) { const results = fuse.search(searchValue); console.debug('World Info fuzzy search results for ' + searchValue, results); + fuzzySearchWorldInfoCache.set(searchValue, results); return results; } @@ -1892,6 +1909,10 @@ export function fuzzySearchWorldInfo(data, searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchPersonas(data, searchValue) { + if (fuzzySearchPersonasCache.has(searchValue)) { + return fuzzySearchPersonasCache.get(searchValue); + } + data = data.map(x => ({ key: x, name: power_user.personas[x] ?? '', description: power_user.persona_descriptions[x]?.description ?? '' })); // @ts-ignore const fuse = new Fuse(data, { @@ -1907,6 +1928,7 @@ export function fuzzySearchPersonas(data, searchValue) { const results = fuse.search(searchValue); console.debug('Personas fuzzy search results for ' + searchValue, results); + fuzzySearchPersonasCache.set(searchValue, results); return results; } @@ -1916,6 +1938,10 @@ export function fuzzySearchPersonas(data, searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchTags(searchValue) { + if (fuzzySearchTagsCache.has(searchValue)) { + return fuzzySearchTagsCache.get(searchValue); + } + // @ts-ignore const fuse = new Fuse(tags, { keys: [ @@ -1929,6 +1955,7 @@ export function fuzzySearchTags(searchValue) { const results = fuse.search(searchValue); console.debug('Tags fuzzy search results for ' + searchValue, results); + fuzzySearchTagsCache.set(searchValue, results); return results; } @@ -1938,6 +1965,10 @@ export function fuzzySearchTags(searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchGroups(searchValue) { + if (fuzzySearchGroupsCache.has(searchValue)) { + return fuzzySearchGroupsCache.get(searchValue); + } + // @ts-ignore const fuse = new Fuse(groups, { keys: [ @@ -1954,6 +1985,7 @@ export function fuzzySearchGroups(searchValue) { const results = fuse.search(searchValue); console.debug('Groups fuzzy search results for ' + searchValue, results); + fuzzySearchGroupsCache.set(searchValue, results); return results; } From 2661881bc4c95f752786b35daa06af3cffe05e15 Mon Sep 17 00:00:00 2001 From: Joe Date: Sat, 23 Nov 2024 22:13:20 -0800 Subject: [PATCH 02/31] Handle stale cache --- public/scripts/power-user.js | 228 +++++++++++++++++++++++++---------- 1 file changed, 165 insertions(+), 63 deletions(-) diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 088a56a10..fef259016 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -330,12 +330,6 @@ const debug_functions = []; const setHotswapsDebounced = debounce(favsToHotswap); -const fuzzySearchCharactersCache = new Map(); -const fuzzySearchWorldInfoCache = new Map(); -const fuzzySearchPersonasCache = new Map(); -const fuzzySearchTagsCache = new Map(); -const fuzzySearchGroupsCache = new Map(); - function playMessageSound() { if (!power_user.play_message_sound) { return; @@ -1830,32 +1824,70 @@ async function loadContextSettings() { }); } +// Create separate caches for each type of fuzzy search +const fuzzySearchCaches = { + characters: { keyHash: null, resultMap: new Map() }, + worldInfo: { keyHash: null, resultMap: new Map() }, + personas: { keyHash: null, resultMap: new Map() }, + tags: { keyHash: null, resultMap: new Map() }, + groups: { keyHash: null, resultMap: new Map() }, +}; + /** - * Fuzzy search characters by a search term + * Generates a hash of the Fuse configuration keys + * @param {Array<{name: string, weight: number, getFn?: Function}>} keys + * @returns {number} Hash of the keys configuration + */ +function hashFuseKeys(keys) { + // Convert keys to a stable string representation + const keyString = keys.map(k => { + const getFnString = k.getFn ? k.getFn.toString() : ''; + return `${k.name}:${k.weight}:${getFnString}`; + }).join('|'); + + return getStringHash(keyString); +} + +/** + * Fuzzy search characters by a search term with caching * @param {string} searchValue - The search term * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchCharacters(searchValue) { + const fuseKeys = [ + { name: 'data.name', weight: 20 }, + { name: '#tags', weight: 10, getFn: (character) => getTagsList(character.avatar).map(x => x.name).join('||') }, + { name: 'data.description', weight: 3 }, + { name: 'data.mes_example', weight: 3 }, + { name: 'data.scenario', weight: 2 }, + { name: 'data.personality', weight: 2 }, + { name: 'data.first_mes', weight: 2 }, + { name: 'data.creator_notes', weight: 2 }, + { name: 'data.creator', weight: 1 }, + { name: 'data.tags', weight: 1 }, + { name: 'data.alternate_greetings', weight: 1 }, + ]; - if (fuzzySearchCharactersCache.has(searchValue)) { - return fuzzySearchCharactersCache.get(searchValue); + // Generate hash of current keys configuration + const currentKeyHash = hashFuseKeys(fuseKeys); + const cache = fuzzySearchCaches.characters; + + // Check if we have a cached result for this search value + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { + console.debug('Using cached fuzzy search results for ' + searchValue); + return cache.resultMap.get(searchValue); } - // @ts-ignore + // If key configuration changed, clear the cache + if (cache.keyHash !== currentKeyHash) { + console.debug('Fuse keys changed, clearing cache'); + cache.keyHash = currentKeyHash; + cache.resultMap.clear(); + } + + // Create new Fuse instance and perform search const fuse = new Fuse(characters, { - keys: [ - { name: 'data.name', weight: 20 }, - { name: '#tags', weight: 10, getFn: (character) => getTagsList(character.avatar).map(x => x.name).join('||') }, - { name: 'data.description', weight: 3 }, - { name: 'data.mes_example', weight: 3 }, - { name: 'data.scenario', weight: 2 }, - { name: 'data.personality', weight: 2 }, - { name: 'data.first_mes', weight: 2 }, - { name: 'data.creator_notes', weight: 2 }, - { name: 'data.creator', weight: 1 }, - { name: 'data.tags', weight: 1 }, - { name: 'data.alternate_greetings', weight: 1 }, - ], + keys: fuseKeys, includeScore: true, ignoreLocation: true, useExtendedSearch: true, @@ -1863,8 +1895,11 @@ export function fuzzySearchCharacters(searchValue) { }); const results = fuse.search(searchValue); + + // Cache the results + cache.resultMap.set(searchValue, results); + console.debug('Characters fuzzy search results for ' + searchValue, results); - fuzzySearchCharactersCache.set(searchValue, results); return results; } @@ -1875,21 +1910,34 @@ export function fuzzySearchCharacters(searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchWorldInfo(data, searchValue) { - if (fuzzySearchWorldInfoCache.has(searchValue)) { - return fuzzySearchWorldInfoCache.get(searchValue); + const fuseKeys = [ + { name: 'key', weight: 20 }, + { name: 'group', weight: 15 }, + { name: 'comment', weight: 10 }, + { name: 'keysecondary', weight: 10 }, + { name: 'content', weight: 3 }, + { name: 'uid', weight: 1 }, + { name: 'automationId', weight: 1 }, + ]; + + const currentKeyHash = hashFuseKeys(fuseKeys); + const cache = fuzzySearchCaches.worldInfo; + + // Check cache for existing results + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { + console.debug('Using cached WI fuzzy search results for ' + searchValue); + return cache.resultMap.get(searchValue); + } + + // Clear cache if keys changed + if (cache.keyHash !== currentKeyHash) { + console.debug('WI Fuse keys changed, clearing cache'); + cache.keyHash = currentKeyHash; + cache.resultMap.clear(); } - // @ts-ignore const fuse = new Fuse(data, { - keys: [ - { name: 'key', weight: 20 }, - { name: 'group', weight: 15 }, - { name: 'comment', weight: 10 }, - { name: 'keysecondary', weight: 10 }, - { name: 'content', weight: 3 }, - { name: 'uid', weight: 1 }, - { name: 'automationId', weight: 1 }, - ], + keys: fuseKeys, includeScore: true, ignoreLocation: true, useExtendedSearch: true, @@ -1897,8 +1945,9 @@ export function fuzzySearchWorldInfo(data, searchValue) { }); const results = fuse.search(searchValue); + cache.resultMap.set(searchValue, results); + console.debug('World Info fuzzy search results for ' + searchValue, results); - fuzzySearchWorldInfoCache.set(searchValue, results); return results; } @@ -1909,17 +1958,31 @@ export function fuzzySearchWorldInfo(data, searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchPersonas(data, searchValue) { - if (fuzzySearchPersonasCache.has(searchValue)) { - return fuzzySearchPersonasCache.get(searchValue); + data = data.map(x => ({ key: x, name: power_user.personas[x] ?? '', description: power_user.persona_descriptions[x]?.description ?? '' })); + + const fuseKeys = [ + { name: 'name', weight: 20 }, + { name: 'description', weight: 3 }, + ]; + + const currentKeyHash = hashFuseKeys(fuseKeys); + const cache = fuzzySearchCaches.personas; + + // Check cache for existing results + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { + console.debug('Using cached personas fuzzy search results for ' + searchValue); + return cache.resultMap.get(searchValue); + } + + // Clear cache if keys changed + if (cache.keyHash !== currentKeyHash) { + console.debug('Personas Fuse keys changed, clearing cache'); + cache.keyHash = currentKeyHash; + cache.resultMap.clear(); } - data = data.map(x => ({ key: x, name: power_user.personas[x] ?? '', description: power_user.persona_descriptions[x]?.description ?? '' })); - // @ts-ignore const fuse = new Fuse(data, { - keys: [ - { name: 'name', weight: 20 }, - { name: 'description', weight: 3 }, - ], + keys: fuseKeys, includeScore: true, ignoreLocation: true, useExtendedSearch: true, @@ -1927,8 +1990,9 @@ export function fuzzySearchPersonas(data, searchValue) { }); const results = fuse.search(searchValue); + cache.resultMap.set(searchValue, results); + console.debug('Personas fuzzy search results for ' + searchValue, results); - fuzzySearchPersonasCache.set(searchValue, results); return results; } @@ -1938,15 +2002,28 @@ export function fuzzySearchPersonas(data, searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchTags(searchValue) { - if (fuzzySearchTagsCache.has(searchValue)) { - return fuzzySearchTagsCache.get(searchValue); + const fuseKeys = [ + { name: 'name', weight: 1 }, + ]; + + const currentKeyHash = hashFuseKeys(fuseKeys); + const cache = fuzzySearchCaches.tags; + + // Check cache for existing results + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { + console.debug('Using cached tags fuzzy search results for ' + searchValue); + return cache.resultMap.get(searchValue); + } + + // Clear cache if keys changed + if (cache.keyHash !== currentKeyHash) { + console.debug('Tags Fuse keys changed, clearing cache'); + cache.keyHash = currentKeyHash; + cache.resultMap.clear(); } - // @ts-ignore const fuse = new Fuse(tags, { - keys: [ - { name: 'name', weight: 1 }, - ], + keys: fuseKeys, includeScore: true, ignoreLocation: true, useExtendedSearch: true, @@ -1954,8 +2031,9 @@ export function fuzzySearchTags(searchValue) { }); const results = fuse.search(searchValue); + cache.resultMap.set(searchValue, results); + console.debug('Tags fuzzy search results for ' + searchValue, results); - fuzzySearchTagsCache.set(searchValue, results); return results; } @@ -1965,18 +2043,31 @@ export function fuzzySearchTags(searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchGroups(searchValue) { - if (fuzzySearchGroupsCache.has(searchValue)) { - return fuzzySearchGroupsCache.get(searchValue); + const fuseKeys = [ + { name: 'name', weight: 20 }, + { name: 'members', weight: 15 }, + { name: '#tags', weight: 10, getFn: (group) => getTagsList(group.id).map(x => x.name).join('||') }, + { name: 'id', weight: 1 }, + ]; + + const currentKeyHash = hashFuseKeys(fuseKeys); + const cache = fuzzySearchCaches.groups; + + // Check cache for existing results + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { + console.debug('Using cached groups fuzzy search results for ' + searchValue); + return cache.resultMap.get(searchValue); + } + + // Clear cache if keys changed + if (cache.keyHash !== currentKeyHash) { + console.debug('Groups Fuse keys changed, clearing cache'); + cache.keyHash = currentKeyHash; + cache.resultMap.clear(); } - // @ts-ignore const fuse = new Fuse(groups, { - keys: [ - { name: 'name', weight: 20 }, - { name: 'members', weight: 15 }, - { name: '#tags', weight: 10, getFn: (group) => getTagsList(group.id).map(x => x.name).join('||') }, - { name: 'id', weight: 1 }, - ], + keys: fuseKeys, includeScore: true, ignoreLocation: true, useExtendedSearch: true, @@ -1984,11 +2075,22 @@ export function fuzzySearchGroups(searchValue) { }); const results = fuse.search(searchValue); + cache.resultMap.set(searchValue, results); + console.debug('Groups fuzzy search results for ' + searchValue, results); - fuzzySearchGroupsCache.set(searchValue, results); return results; } +/** + * Clears all fuzzy search caches + */ +export function clearFuzzySearchCaches() { + for (const cache of Object.values(fuzzySearchCaches)) { + cache.keyHash = null; + cache.resultMap.clear(); + } +} + /** * Renders a story string template with the given parameters. * @param {object} params Template parameters. From e2c083ba31d0c9e3ab1e168995f03c0e9d37daac Mon Sep 17 00:00:00 2001 From: Joe Date: Sat, 23 Nov 2024 22:34:56 -0800 Subject: [PATCH 03/31] Remove duplicated code --- public/scripts/power-user.js | 257 +++++++++++------------------------ 1 file changed, 82 insertions(+), 175 deletions(-) diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index fef259016..9d6910a3f 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -328,6 +328,22 @@ const contextControls = [ let browser_has_focus = true; const debug_functions = []; +const fuzzySearchCaches = { + characters: { keyHash: null, resultMap: new Map() }, + worldInfo: { keyHash: null, resultMap: new Map() }, + personas: { keyHash: null, resultMap: new Map() }, + tags: { keyHash: null, resultMap: new Map() }, + groups: { keyHash: null, resultMap: new Map() }, +}; + +const fuzzySearchCategories = { + characters: 'characters', + worldInfo: 'worldInfo', + personas: 'personas', + tags: 'tags', + groups: 'groups', +}; + const setHotswapsDebounced = debounce(favsToHotswap); function playMessageSound() { @@ -1824,15 +1840,6 @@ async function loadContextSettings() { }); } -// Create separate caches for each type of fuzzy search -const fuzzySearchCaches = { - characters: { keyHash: null, resultMap: new Map() }, - worldInfo: { keyHash: null, resultMap: new Map() }, - personas: { keyHash: null, resultMap: new Map() }, - tags: { keyHash: null, resultMap: new Map() }, - groups: { keyHash: null, resultMap: new Map() }, -}; - /** * Generates a hash of the Fuse configuration keys * @param {Array<{name: string, weight: number, getFn?: Function}>} keys @@ -1849,12 +1856,62 @@ function hashFuseKeys(keys) { } /** - * Fuzzy search characters by a search term with caching + * Common function to perform fuzzy search with caching + * @param {string} type - Type of search from fuzzySearchCategories + * @param {any[]} data - Data array to search in + * @param {Array<{name: string, weight: number, getFn?: Function}>} keys - Fuse.js keys configuration + * @param {string} searchValue - The search term + * @returns {import('fuse.js').FuseResult[]} Results as items with their score + */ +function performFuzzySearch(type, data, keys, searchValue) { + const currentKeyHash = hashFuseKeys(keys); + const cache = fuzzySearchCaches[type]; + + // Check cache for existing results + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { + console.log(`Using cached ${type} fuzzy search results for ${searchValue}`); + return cache.resultMap.get(searchValue); + } + + // Clear cache if keys changed + if (cache.keyHash !== currentKeyHash) { + console.log(`${type} Fuse keys changed, clearing cache`); + cache.keyHash = currentKeyHash; + cache.resultMap.clear(); + } + + const fuse = new Fuse(data, { + keys: keys, + includeScore: true, + ignoreLocation: true, + useExtendedSearch: true, + threshold: 0.2, + }); + + const results = fuse.search(searchValue); + cache.resultMap.set(searchValue, results); + + console.log(`${type} fuzzy search results for ${searchValue}`, results); + return results; +} + +/** + * Clears all fuzzy search caches + */ +export function clearFuzzySearchCaches() { + for (const cache of Object.values(fuzzySearchCaches)) { + cache.keyHash = null; + cache.resultMap.clear(); + } +} + +/** + * Fuzzy search characters by a search term * @param {string} searchValue - The search term * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchCharacters(searchValue) { - const fuseKeys = [ + const keys = [ { name: 'data.name', weight: 20 }, { name: '#tags', weight: 10, getFn: (character) => getTagsList(character.avatar).map(x => x.name).join('||') }, { name: 'data.description', weight: 3 }, @@ -1868,39 +1925,7 @@ export function fuzzySearchCharacters(searchValue) { { name: 'data.alternate_greetings', weight: 1 }, ]; - // Generate hash of current keys configuration - const currentKeyHash = hashFuseKeys(fuseKeys); - const cache = fuzzySearchCaches.characters; - - // Check if we have a cached result for this search value - if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { - console.debug('Using cached fuzzy search results for ' + searchValue); - return cache.resultMap.get(searchValue); - } - - // If key configuration changed, clear the cache - if (cache.keyHash !== currentKeyHash) { - console.debug('Fuse keys changed, clearing cache'); - cache.keyHash = currentKeyHash; - cache.resultMap.clear(); - } - - // Create new Fuse instance and perform search - const fuse = new Fuse(characters, { - keys: fuseKeys, - includeScore: true, - ignoreLocation: true, - useExtendedSearch: true, - threshold: 0.2, - }); - - const results = fuse.search(searchValue); - - // Cache the results - cache.resultMap.set(searchValue, results); - - console.debug('Characters fuzzy search results for ' + searchValue, results); - return results; + return performFuzzySearch(fuzzySearchCategories.characters, characters, keys, searchValue); } /** @@ -1910,7 +1935,7 @@ export function fuzzySearchCharacters(searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchWorldInfo(data, searchValue) { - const fuseKeys = [ + const keys = [ { name: 'key', weight: 20 }, { name: 'group', weight: 15 }, { name: 'comment', weight: 10 }, @@ -1920,35 +1945,7 @@ export function fuzzySearchWorldInfo(data, searchValue) { { name: 'automationId', weight: 1 }, ]; - const currentKeyHash = hashFuseKeys(fuseKeys); - const cache = fuzzySearchCaches.worldInfo; - - // Check cache for existing results - if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { - console.debug('Using cached WI fuzzy search results for ' + searchValue); - return cache.resultMap.get(searchValue); - } - - // Clear cache if keys changed - if (cache.keyHash !== currentKeyHash) { - console.debug('WI Fuse keys changed, clearing cache'); - cache.keyHash = currentKeyHash; - cache.resultMap.clear(); - } - - const fuse = new Fuse(data, { - keys: fuseKeys, - includeScore: true, - ignoreLocation: true, - useExtendedSearch: true, - threshold: 0.2, - }); - - const results = fuse.search(searchValue); - cache.resultMap.set(searchValue, results); - - console.debug('World Info fuzzy search results for ' + searchValue, results); - return results; + return performFuzzySearch(fuzzySearchCategories.worldInfo, data, keys, searchValue); } /** @@ -1958,42 +1955,18 @@ export function fuzzySearchWorldInfo(data, searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchPersonas(data, searchValue) { - data = data.map(x => ({ key: x, name: power_user.personas[x] ?? '', description: power_user.persona_descriptions[x]?.description ?? '' })); + const mappedData = data.map(x => ({ + key: x, + name: power_user.personas[x] ?? '', + description: power_user.persona_descriptions[x]?.description ?? '' + })); - const fuseKeys = [ + const keys = [ { name: 'name', weight: 20 }, { name: 'description', weight: 3 }, ]; - const currentKeyHash = hashFuseKeys(fuseKeys); - const cache = fuzzySearchCaches.personas; - - // Check cache for existing results - if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { - console.debug('Using cached personas fuzzy search results for ' + searchValue); - return cache.resultMap.get(searchValue); - } - - // Clear cache if keys changed - if (cache.keyHash !== currentKeyHash) { - console.debug('Personas Fuse keys changed, clearing cache'); - cache.keyHash = currentKeyHash; - cache.resultMap.clear(); - } - - const fuse = new Fuse(data, { - keys: fuseKeys, - includeScore: true, - ignoreLocation: true, - useExtendedSearch: true, - threshold: 0.2, - }); - - const results = fuse.search(searchValue); - cache.resultMap.set(searchValue, results); - - console.debug('Personas fuzzy search results for ' + searchValue, results); - return results; + return performFuzzySearch(fuzzySearchCategories.personas, mappedData, keys, searchValue); } /** @@ -2002,39 +1975,11 @@ export function fuzzySearchPersonas(data, searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchTags(searchValue) { - const fuseKeys = [ + const keys = [ { name: 'name', weight: 1 }, ]; - const currentKeyHash = hashFuseKeys(fuseKeys); - const cache = fuzzySearchCaches.tags; - - // Check cache for existing results - if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { - console.debug('Using cached tags fuzzy search results for ' + searchValue); - return cache.resultMap.get(searchValue); - } - - // Clear cache if keys changed - if (cache.keyHash !== currentKeyHash) { - console.debug('Tags Fuse keys changed, clearing cache'); - cache.keyHash = currentKeyHash; - cache.resultMap.clear(); - } - - const fuse = new Fuse(tags, { - keys: fuseKeys, - includeScore: true, - ignoreLocation: true, - useExtendedSearch: true, - threshold: 0.2, - }); - - const results = fuse.search(searchValue); - cache.resultMap.set(searchValue, results); - - console.debug('Tags fuzzy search results for ' + searchValue, results); - return results; + return performFuzzySearch(fuzzySearchCategories.tags, tags, keys, searchValue); } /** @@ -2043,52 +1988,14 @@ export function fuzzySearchTags(searchValue) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ export function fuzzySearchGroups(searchValue) { - const fuseKeys = [ + const keys = [ { name: 'name', weight: 20 }, { name: 'members', weight: 15 }, { name: '#tags', weight: 10, getFn: (group) => getTagsList(group.id).map(x => x.name).join('||') }, { name: 'id', weight: 1 }, ]; - const currentKeyHash = hashFuseKeys(fuseKeys); - const cache = fuzzySearchCaches.groups; - - // Check cache for existing results - if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { - console.debug('Using cached groups fuzzy search results for ' + searchValue); - return cache.resultMap.get(searchValue); - } - - // Clear cache if keys changed - if (cache.keyHash !== currentKeyHash) { - console.debug('Groups Fuse keys changed, clearing cache'); - cache.keyHash = currentKeyHash; - cache.resultMap.clear(); - } - - const fuse = new Fuse(groups, { - keys: fuseKeys, - includeScore: true, - ignoreLocation: true, - useExtendedSearch: true, - threshold: 0.2, - }); - - const results = fuse.search(searchValue); - cache.resultMap.set(searchValue, results); - - console.debug('Groups fuzzy search results for ' + searchValue, results); - return results; -} - -/** - * Clears all fuzzy search caches - */ -export function clearFuzzySearchCaches() { - for (const cache of Object.values(fuzzySearchCaches)) { - cache.keyHash = null; - cache.resultMap.clear(); - } + return performFuzzySearch(fuzzySearchCategories.groups, groups, keys, searchValue); } /** From d1cac298c61601449a42b0021b5b860b83c9d8e2 Mon Sep 17 00:00:00 2001 From: Joe Date: Sat, 23 Nov 2024 22:51:48 -0800 Subject: [PATCH 04/31] Coment out log statements --- public/scripts/power-user.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 9d6910a3f..8b9e837c2 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -1869,13 +1869,13 @@ function performFuzzySearch(type, data, keys, searchValue) { // Check cache for existing results if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { - console.log(`Using cached ${type} fuzzy search results for ${searchValue}`); + // console.debug(`Using cached ${type} fuzzy search results for ${searchValue}`); return cache.resultMap.get(searchValue); } // Clear cache if keys changed if (cache.keyHash !== currentKeyHash) { - console.log(`${type} Fuse keys changed, clearing cache`); + // console.debug(`${type} Fuse keys changed, clearing cache`); cache.keyHash = currentKeyHash; cache.resultMap.clear(); } @@ -1891,7 +1891,7 @@ function performFuzzySearch(type, data, keys, searchValue) { const results = fuse.search(searchValue); cache.resultMap.set(searchValue, results); - console.log(`${type} fuzzy search results for ${searchValue}`, results); + // console.debug(`${type} fuzzy search results for ${searchValue}`, results); return results; } From 9382845dee9ff283cdc774ef38b4213634343b33 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sun, 24 Nov 2024 19:05:41 +0200 Subject: [PATCH 05/31] Claude: remove user filler from prompt converter --- default/content/presets/openai/Default.json | 1 - public/index.html | 9 -------- public/scripts/openai.js | 24 --------------------- src/endpoints/backends/chat-completions.js | 2 +- src/prompt-converters.js | 7 +++--- 5 files changed, 4 insertions(+), 39 deletions(-) diff --git a/default/content/presets/openai/Default.json b/default/content/presets/openai/Default.json index b8a38560c..345199cc1 100644 --- a/default/content/presets/openai/Default.json +++ b/default/content/presets/openai/Default.json @@ -230,7 +230,6 @@ "show_external_models": false, "assistant_prefill": "", "assistant_impersonation": "", - "human_sysprompt_message": "Let's get started. Please generate your response based on the information and instructions provided above.", "claude_use_sysprompt": false, "use_alt_scale": false, "squash_system_messages": false, diff --git a/public/index.html b/public/index.html index ebb09daa4..d8dd438dd 100644 --- a/public/index.html +++ b/public/index.html @@ -1951,15 +1951,6 @@ Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt. -
-
- User first message -
-
-
-
- -
diff --git a/public/scripts/openai.js b/public/scripts/openai.js index da1d950cd..8e2dae2e2 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -99,7 +99,6 @@ const default_wi_format = '{0}'; const default_new_chat_prompt = '[Start a new Chat]'; const default_new_group_chat_prompt = '[Start a new group chat. Group members: {{group}}]'; const default_new_example_chat_prompt = '[Example Chat]'; -const default_claude_human_sysprompt_message = 'Let\'s get started. Please generate your response based on the information and instructions provided above.'; const default_continue_nudge_prompt = '[Continue the following message. Do not include ANY parts of the original message. Use capitalization and punctuation as if your reply is a part of the original message: {{lastChatMessage}}]'; const default_bias = 'Default (none)'; const default_personality_format = '[{{char}}\'s personality: {{personality}}]'; @@ -276,7 +275,6 @@ const default_settings = { proxy_password: '', assistant_prefill: '', assistant_impersonation: '', - human_sysprompt_message: default_claude_human_sysprompt_message, claude_use_sysprompt: false, use_makersuite_sysprompt: true, use_alt_scale: false, @@ -353,7 +351,6 @@ const oai_settings = { proxy_password: '', assistant_prefill: '', assistant_impersonation: '', - human_sysprompt_message: default_claude_human_sysprompt_message, claude_use_sysprompt: false, use_makersuite_sysprompt: true, use_alt_scale: false, @@ -1892,7 +1889,6 @@ async function sendOpenAIRequest(type, messages, signal) { generate_data['top_k'] = Number(oai_settings.top_k_openai); generate_data['claude_use_sysprompt'] = oai_settings.claude_use_sysprompt; generate_data['stop'] = getCustomStoppingStrings(); // Claude shouldn't have limits on stop strings. - generate_data['human_sysprompt_message'] = substituteParams(oai_settings.human_sysprompt_message); // Don't add a prefill on quiet gens (summarization) and when using continue prefill. if (!isQuiet && !(isContinue && oai_settings.continue_prefill)) { generate_data['assistant_prefill'] = isImpersonate ? substituteParams(oai_settings.assistant_impersonation) : substituteParams(oai_settings.assistant_prefill); @@ -3030,7 +3026,6 @@ function loadOpenAISettings(data, settings) { oai_settings.proxy_password = settings.proxy_password ?? default_settings.proxy_password; oai_settings.assistant_prefill = settings.assistant_prefill ?? default_settings.assistant_prefill; oai_settings.assistant_impersonation = settings.assistant_impersonation ?? default_settings.assistant_impersonation; - oai_settings.human_sysprompt_message = settings.human_sysprompt_message ?? default_settings.human_sysprompt_message; oai_settings.image_inlining = settings.image_inlining ?? default_settings.image_inlining; oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality; oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check; @@ -3070,7 +3065,6 @@ function loadOpenAISettings(data, settings) { $('#openai_proxy_password').val(oai_settings.proxy_password); $('#claude_assistant_prefill').val(oai_settings.assistant_prefill); $('#claude_assistant_impersonation').val(oai_settings.assistant_impersonation); - $('#claude_human_sysprompt_textarea').val(oai_settings.human_sysprompt_message); $('#openai_image_inlining').prop('checked', oai_settings.image_inlining); $('#openai_bypass_status_check').prop('checked', oai_settings.bypass_status_check); @@ -3400,7 +3394,6 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { show_external_models: settings.show_external_models, assistant_prefill: settings.assistant_prefill, assistant_impersonation: settings.assistant_impersonation, - human_sysprompt_message: settings.human_sysprompt_message, claude_use_sysprompt: settings.claude_use_sysprompt, use_makersuite_sysprompt: settings.use_makersuite_sysprompt, use_alt_scale: settings.use_alt_scale, @@ -3825,7 +3818,6 @@ function onSettingsPresetChange() { proxy_password: ['#openai_proxy_password', 'proxy_password', false], assistant_prefill: ['#claude_assistant_prefill', 'assistant_prefill', false], assistant_impersonation: ['#claude_assistant_impersonation', 'assistant_impersonation', false], - human_sysprompt_message: ['#claude_human_sysprompt_textarea', 'human_sysprompt_message', false], claude_use_sysprompt: ['#claude_use_sysprompt', 'claude_use_sysprompt', true], use_makersuite_sysprompt: ['#use_makersuite_sysprompt', 'use_makersuite_sysprompt', true], use_alt_scale: ['#use_alt_scale', 'use_alt_scale', true], @@ -4677,10 +4669,6 @@ function toggleChatCompletionForms() { const validSources = $(this).data('source').split(','); $(this).toggle(validSources.includes(oai_settings.chat_completion_source)); }); - - if (chat_completion_sources.CLAUDE == oai_settings.chat_completion_source) { - $('#claude_human_sysprompt_message_block').toggle(oai_settings.claude_use_sysprompt); - } } async function testApiConnection() { @@ -5036,7 +5024,6 @@ export function initOpenAI() { $('#claude_use_sysprompt').on('change', function () { oai_settings.claude_use_sysprompt = !!$('#claude_use_sysprompt').prop('checked'); - $('#claude_human_sysprompt_message_block').toggle(oai_settings.claude_use_sysprompt); saveSettingsDebounced(); }); @@ -5113,12 +5100,6 @@ export function initOpenAI() { saveSettingsDebounced(); }); - $('#claude_human_sysprompt_message_restore').on('click', function () { - oai_settings.human_sysprompt_message = default_claude_human_sysprompt_message; - $('#claude_human_sysprompt_textarea').val(oai_settings.human_sysprompt_message); - saveSettingsDebounced(); - }); - $('#newgroupchat_prompt_restore').on('click', function () { oai_settings.new_group_chat_prompt = default_new_group_chat_prompt; $('#newgroupchat_prompt_textarea').val(oai_settings.new_group_chat_prompt); @@ -5210,11 +5191,6 @@ export function initOpenAI() { saveSettingsDebounced(); }); - $('#claude_human_sysprompt_textarea').on('input', function () { - oai_settings.human_sysprompt_message = String($('#claude_human_sysprompt_textarea').val()); - saveSettingsDebounced(); - }); - $('#openrouter_use_fallback').on('input', function () { oai_settings.openrouter_use_fallback = !!$(this).prop('checked'); saveSettingsDebounced(); diff --git a/src/endpoints/backends/chat-completions.js b/src/endpoints/backends/chat-completions.js index b78ba45b5..aa15c7278 100644 --- a/src/endpoints/backends/chat-completions.js +++ b/src/endpoints/backends/chat-completions.js @@ -102,7 +102,7 @@ async function sendClaudeRequest(request, response) { const additionalHeaders = {}; const useTools = request.body.model.startsWith('claude-3') && Array.isArray(request.body.tools) && request.body.tools.length > 0; const useSystemPrompt = (request.body.model.startsWith('claude-2') || request.body.model.startsWith('claude-3')) && request.body.claude_use_sysprompt; - const convertedPrompt = convertClaudeMessages(request.body.messages, request.body.assistant_prefill, useSystemPrompt, useTools, request.body.human_sysprompt_message, request.body.char_name, request.body.user_name); + const convertedPrompt = convertClaudeMessages(request.body.messages, request.body.assistant_prefill, useSystemPrompt, useTools, request.body.char_name, request.body.user_name); // Add custom stop sequences const stopSequences = []; if (Array.isArray(request.body.stop)) { diff --git a/src/prompt-converters.js b/src/prompt-converters.js index b5d624a1c..79db3965c 100644 --- a/src/prompt-converters.js +++ b/src/prompt-converters.js @@ -91,11 +91,10 @@ export function convertClaudePrompt(messages, addAssistantPostfix, addAssistantP * @param {string} prefillString User determined prefill string * @param {boolean} useSysPrompt See if we want to use a system prompt * @param {boolean} useTools See if we want to use tools - * @param {string} humanMsgFix Add Human message between system prompt and assistant. * @param {string} charName Character name * @param {string} userName User name */ -export function convertClaudeMessages(messages, prefillString, useSysPrompt, useTools, humanMsgFix, charName = '', userName = '') { +export function convertClaudeMessages(messages, prefillString, useSysPrompt, useTools, charName, userName) { let systemPrompt = []; if (useSysPrompt) { // Collect all the system messages up until the first instance of a non-system message, and then remove them from the messages array. @@ -122,10 +121,10 @@ export function convertClaudeMessages(messages, prefillString, useSysPrompt, use // Check if the first message in the array is of type user, if not, interject with humanMsgFix or a blank message. // Also prevents erroring out if the messages array is empty. - if (messages.length === 0 || (messages.length > 0 && messages[0].role !== 'user')) { + if (messages.length === 0) { messages.unshift({ role: 'user', - content: humanMsgFix || PROMPT_PLACEHOLDER, + content: PROMPT_PLACEHOLDER, }); } } From e1d6a47048e0d53921214607387f2687d2fb805f Mon Sep 17 00:00:00 2001 From: Joe Date: Sun, 24 Nov 2024 14:54:12 -0800 Subject: [PATCH 06/31] Remove key hashing and explicitly clear the cache after printing characters --- public/script.js | 2 ++ public/scripts/power-user.js | 27 +++++++++------------------ 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/public/script.js b/public/script.js index 57acf537e..4d6e41648 100644 --- a/public/script.js +++ b/public/script.js @@ -268,6 +268,7 @@ import { initServerHistory } from './scripts/server-history.js'; import { initSettingsSearch } from './scripts/setting-search.js'; import { initBulkEdit } from './scripts/bulk-edit.js'; import { deriveTemplatesFromChatTemplate } from './scripts/chat-templates.js'; +import { clearFuzzySearchCaches } from './scripts/power-user.js'; //exporting functions and vars for mods export { @@ -1515,6 +1516,7 @@ export async function printCharacters(fullRefresh = false) { }); favsToHotswap(); + clearFuzzySearchCaches(); } /** Checks the state of the current search, and adds/removes the search sorting option accordingly */ diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 8b9e837c2..91ba33844 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -329,11 +329,11 @@ let browser_has_focus = true; const debug_functions = []; const fuzzySearchCaches = { - characters: { keyHash: null, resultMap: new Map() }, - worldInfo: { keyHash: null, resultMap: new Map() }, - personas: { keyHash: null, resultMap: new Map() }, - tags: { keyHash: null, resultMap: new Map() }, - groups: { keyHash: null, resultMap: new Map() }, + characters: { resultMap: new Map() }, + worldInfo: { resultMap: new Map() }, + personas: { resultMap: new Map() }, + tags: { resultMap: new Map() }, + groups: { resultMap: new Map() }, }; const fuzzySearchCategories = { @@ -1864,22 +1864,14 @@ function hashFuseKeys(keys) { * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ function performFuzzySearch(type, data, keys, searchValue) { - const currentKeyHash = hashFuseKeys(keys); const cache = fuzzySearchCaches[type]; // Check cache for existing results - if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { - // console.debug(`Using cached ${type} fuzzy search results for ${searchValue}`); + if (cache.resultMap.has(searchValue)) { return cache.resultMap.get(searchValue); } - // Clear cache if keys changed - if (cache.keyHash !== currentKeyHash) { - // console.debug(`${type} Fuse keys changed, clearing cache`); - cache.keyHash = currentKeyHash; - cache.resultMap.clear(); - } - + // @ts-ignore const fuse = new Fuse(data, { keys: keys, includeScore: true, @@ -1890,19 +1882,18 @@ function performFuzzySearch(type, data, keys, searchValue) { const results = fuse.search(searchValue); cache.resultMap.set(searchValue, results); - - // console.debug(`${type} fuzzy search results for ${searchValue}`, results); return results; } + /** * Clears all fuzzy search caches */ export function clearFuzzySearchCaches() { for (const cache of Object.values(fuzzySearchCaches)) { - cache.keyHash = null; cache.resultMap.clear(); } + console.log('Fuzzy search caches cleared'); } /** From e56faaaed581626866c76b2bb154f76234ef797b Mon Sep 17 00:00:00 2001 From: Joe Date: Sun, 24 Nov 2024 14:55:22 -0800 Subject: [PATCH 07/31] Remove hash function --- public/scripts/power-user.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 91ba33844..5b780b700 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -1840,21 +1840,6 @@ async function loadContextSettings() { }); } -/** - * Generates a hash of the Fuse configuration keys - * @param {Array<{name: string, weight: number, getFn?: Function}>} keys - * @returns {number} Hash of the keys configuration - */ -function hashFuseKeys(keys) { - // Convert keys to a stable string representation - const keyString = keys.map(k => { - const getFnString = k.getFn ? k.getFn.toString() : ''; - return `${k.name}:${k.weight}:${getFnString}`; - }).join('|'); - - return getStringHash(keyString); -} - /** * Common function to perform fuzzy search with caching * @param {string} type - Type of search from fuzzySearchCategories From e664806990f2eb49df4fadeabf66e238985506a6 Mon Sep 17 00:00:00 2001 From: AlpinDale Date: Mon, 25 Nov 2024 22:28:58 +0000 Subject: [PATCH 08/31] add DRY, skew, and no repeat ngram penalty --- public/index.html | 6 +++--- public/scripts/textgen-settings.js | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/public/index.html b/public/index.html index 2791dbd70..0b2d166cc 100644 --- a/public/index.html +++ b/public/index.html @@ -1342,12 +1342,12 @@
-
+
No Repeat Ngram Size
-
+
Skew @@ -1402,7 +1402,7 @@
-
+

diff --git a/public/scripts/textgen-settings.js b/public/scripts/textgen-settings.js index c81c056f0..0dfae364f 100644 --- a/public/scripts/textgen-settings.js +++ b/public/scripts/textgen-settings.js @@ -1258,6 +1258,7 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, 'xtc_probability': settings.xtc_probability, 'nsigma': settings.nsigma, 'custom_token_bans': toIntArray(banned_tokens), + 'no_repeat_ngram_size': settings.no_repeat_ngram_size, }; if (settings.type === OPENROUTER) { From 16ba8331b5bd0bec42bf005551c51799a1e58c1e Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 26 Nov 2024 13:27:27 -0800 Subject: [PATCH 09/31] Document Fuzzy Search process --- docs/fuzzy_search_flow.md | 113 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 docs/fuzzy_search_flow.md diff --git a/docs/fuzzy_search_flow.md b/docs/fuzzy_search_flow.md new file mode 100644 index 000000000..b6d686c71 --- /dev/null +++ b/docs/fuzzy_search_flow.md @@ -0,0 +1,113 @@ +## Input Sources to printCharacters + + +`printCharacters` is the main function that triggers the fuzzy search process if fuzzy search is enabled. + +```mermaid +flowchart TD + subgraph User Actions + UA1[Character Search Input] + UA2[Tag Filter Click] + UA3[Folder Navigation] + UA4[Character Delete] + UA5[Character Create] + UA6[Character Import] + UA7[Clear All Filters] + UA8[Bulk Edit Operations] + UA9[Persona Changes] + end + + subgraph API Events + API1[Character List Update] + API2[Group Update] + API3[Tag Update] + end + + subgraph System Events + SE1[Page Load] + SE2[Content Manager Update] + SE3[Extension Events] + end + + UA1 -->|triggers| PCD[printCharactersDebounced] + UA2 -->|triggers| PCD + UA7 -->|triggers| PCD + UA8 -->|triggers| PCD + UA9 -->|triggers| PCD + + UA3 -->|triggers| PC[printCharacters] + UA4 -->|triggers| PC + UA5 -->|triggers| PC + UA6 -->|triggers| PC + + API1 -->|triggers| PC + API2 -->|triggers| PC + API3 -->|triggers| PC + + SE1 -->|triggers| PC + SE2 -->|triggers| PC + SE3 -->|triggers| PC + + PCD -->|debounced call| PC + + style PC fill:#f96,stroke:#333 + style PCD fill:#f96,stroke:#333 +``` + +This diagram shows how `printCharacters` is called throughout the application: + +1. User Actions that trigger character list updates: + - Search input (debounced) + - Tag filter clicks (debounced) + - Folder navigation (direct) + - Character management operations (direct) + +2. API Events that require list refresh: + - Character list updates + - Group updates + - Tag system updates + +3. System Events: + - Initial page load + - Content manager updates + - Extension-triggered refreshes + + + +## Fuzzy Search Flow + + +This diagram shows the flow of fuzzy search operations: +```mermaid +sequenceDiagram + participant Data as Data Sources + participant PC as printCharacters + participant GEL as getEntitiesList + participant FH as FilterHelper + participant AF as applyFilters + participant FS as FuzzySearch Functions + participant Cache as FuzzySearchCaches + + Note over Data: Changes from:
- Tags
- Personas
- World Info
- Groups + + Data->>PC: All changes trigger printCharacters
(direct or debounced) + + PC->>GEL: Call with {doFilter: true} + GEL->>FH: filterByTagState(entities) + GEL->>AF: entitiesFilter.applyFilters(entities) + + AF->>FH: Check scoreCache for existing results + FH-->>AF: Return cached scores if exist + + Note over FS: Filter functions include:
SEARCH,
FAV,
GROUP,
FOLDER,
TAG,
WORLD_INFO_SEARCH,
PERSONA_SEARCH + AF->>FS: fuzzySearchCharacters/Groups/Tags + FS->>Cache: Check/Store results + + FS-->>AF: Return search results + AF->>FH: Cache new scores + AF-->>GEL: Return filtered entities + GEL-->>PC: Return final entities list + + PC->>Cache: clearFuzzySearchCaches() + Note over Cache: Cache is cleared at the end of
each printCharacters call,
ensuring fresh results for next search +``` From dd4a1bf07227c8552a57c48fe0a762e51f0bfa63 Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 26 Nov 2024 13:32:40 -0800 Subject: [PATCH 10/31] Attempt to allow preview for github --- docs/fuzzy_search_flow.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/fuzzy_search_flow.md b/docs/fuzzy_search_flow.md index b6d686c71..af6af0e62 100644 --- a/docs/fuzzy_search_flow.md +++ b/docs/fuzzy_search_flow.md @@ -1,9 +1,9 @@ ## Input Sources to printCharacters - `printCharacters` is the main function that triggers the fuzzy search process if fuzzy search is enabled. ```mermaid +%%{init: {'flowchart': {'nodeSpacing': 50, 'rankSpacing': 50}}}%% flowchart TD subgraph User Actions UA1[Character Search Input] From 8d67bdee841a29364e1c94e311b5e628d5f6feca Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Wed, 27 Nov 2024 11:58:12 +0900 Subject: [PATCH 11/31] Add Tulu templates --- default/content/index.json | 8 ++++++++ default/content/presets/context/Tulu.json | 11 +++++++++++ default/content/presets/instruct/Tulu.json | 22 ++++++++++++++++++++++ public/scripts/chat-templates.js | 6 ++++++ 4 files changed, 47 insertions(+) create mode 100644 default/content/presets/context/Tulu.json create mode 100644 default/content/presets/instruct/Tulu.json diff --git a/default/content/index.json b/default/content/index.json index f08573e56..6df03b78d 100644 --- a/default/content/index.json +++ b/default/content/index.json @@ -627,6 +627,14 @@ "filename": "presets/instruct/Synthia.json", "type": "instruct" }, + { + "filename": "presets/instruct/Tulu.json", + "type": "instruct" + }, + { + "filename": "presets/context/Tulu.json", + "type": "context" + }, { "filename": "presets/instruct/Vicuna 1.0.json", "type": "instruct" diff --git a/default/content/presets/context/Tulu.json b/default/content/presets/context/Tulu.json new file mode 100644 index 000000000..af3c1f9cf --- /dev/null +++ b/default/content/presets/context/Tulu.json @@ -0,0 +1,11 @@ +{ + "story_string": "<|system|>\n{{#if system}}{{system}}\n{{/if}}{{#if wiBefore}}{{wiBefore}}\n{{/if}}{{#if description}}{{description}}\n{{/if}}{{#if personality}}{{char}}'s personality: {{personality}}\n{{/if}}{{#if scenario}}Scenario: {{scenario}}\n{{/if}}{{#if wiAfter}}{{wiAfter}}\n{{/if}}{{#if persona}}{{persona}}\n{{/if}}{{trim}}\n", + "example_separator": "", + "chat_start": "", + "use_stop_strings": false, + "allow_jailbreak": false, + "always_force_name2": true, + "trim_sentences": false, + "single_line": false, + "name": "Tulu" +} diff --git a/default/content/presets/instruct/Tulu.json b/default/content/presets/instruct/Tulu.json new file mode 100644 index 000000000..7ac968507 --- /dev/null +++ b/default/content/presets/instruct/Tulu.json @@ -0,0 +1,22 @@ +{ + "input_sequence": "<|user|>\n", + "output_sequence": "<|assistant|>\n", + "first_output_sequence": "", + "last_output_sequence": "", + "system_sequence_prefix": "", + "system_sequence_suffix": "", + "stop_sequence": "<|end_of_text|>", + "wrap": false, + "macro": true, + "names_behavior": "always", + "activation_regex": "", + "skip_examples": false, + "output_suffix": "<|end_of_text|>\n", + "input_suffix": "", + "system_sequence": "<|system|>\n", + "system_suffix": "", + "user_alignment_message": "", + "last_system_sequence": "", + "system_same_as_user": false, + "name": "Tulu" +} diff --git a/public/scripts/chat-templates.js b/public/scripts/chat-templates.js index ee73bc3e9..ea732b90c 100644 --- a/public/scripts/chat-templates.js +++ b/public/scripts/chat-templates.js @@ -53,6 +53,12 @@ const hash_derivations = { // command-r-08-2024 'Command R' , + + // Tulu + 'ac7498a36a719da630e99d48e6ebc4409de85a77556c2b6159eeb735bcbd11df': + // Tulu-3-8B + // Tulu-3-70B + 'Tulu' }; const substr_derivations = { From 1395c0b8c6e4c1a59192051ecd72cd509dcdf709 Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 26 Nov 2024 19:47:09 -0800 Subject: [PATCH 12/31] Encapsulate logic into filters instead of spreading around --- docs/fuzzy_search_flow.md | 113 ----------------------------------- public/script.js | 10 ++-- public/scripts/filters.js | 57 ++++++++++++++++-- public/scripts/power-user.js | 66 +++++++++----------- 4 files changed, 84 insertions(+), 162 deletions(-) delete mode 100644 docs/fuzzy_search_flow.md diff --git a/docs/fuzzy_search_flow.md b/docs/fuzzy_search_flow.md deleted file mode 100644 index af6af0e62..000000000 --- a/docs/fuzzy_search_flow.md +++ /dev/null @@ -1,113 +0,0 @@ -## Input Sources to printCharacters - -`printCharacters` is the main function that triggers the fuzzy search process if fuzzy search is enabled. - -```mermaid -%%{init: {'flowchart': {'nodeSpacing': 50, 'rankSpacing': 50}}}%% -flowchart TD - subgraph User Actions - UA1[Character Search Input] - UA2[Tag Filter Click] - UA3[Folder Navigation] - UA4[Character Delete] - UA5[Character Create] - UA6[Character Import] - UA7[Clear All Filters] - UA8[Bulk Edit Operations] - UA9[Persona Changes] - end - - subgraph API Events - API1[Character List Update] - API2[Group Update] - API3[Tag Update] - end - - subgraph System Events - SE1[Page Load] - SE2[Content Manager Update] - SE3[Extension Events] - end - - UA1 -->|triggers| PCD[printCharactersDebounced] - UA2 -->|triggers| PCD - UA7 -->|triggers| PCD - UA8 -->|triggers| PCD - UA9 -->|triggers| PCD - - UA3 -->|triggers| PC[printCharacters] - UA4 -->|triggers| PC - UA5 -->|triggers| PC - UA6 -->|triggers| PC - - API1 -->|triggers| PC - API2 -->|triggers| PC - API3 -->|triggers| PC - - SE1 -->|triggers| PC - SE2 -->|triggers| PC - SE3 -->|triggers| PC - - PCD -->|debounced call| PC - - style PC fill:#f96,stroke:#333 - style PCD fill:#f96,stroke:#333 -``` - -This diagram shows how `printCharacters` is called throughout the application: - -1. User Actions that trigger character list updates: - - Search input (debounced) - - Tag filter clicks (debounced) - - Folder navigation (direct) - - Character management operations (direct) - -2. API Events that require list refresh: - - Character list updates - - Group updates - - Tag system updates - -3. System Events: - - Initial page load - - Content manager updates - - Extension-triggered refreshes - - - -## Fuzzy Search Flow - - -This diagram shows the flow of fuzzy search operations: -```mermaid -sequenceDiagram - participant Data as Data Sources - participant PC as printCharacters - participant GEL as getEntitiesList - participant FH as FilterHelper - participant AF as applyFilters - participant FS as FuzzySearch Functions - participant Cache as FuzzySearchCaches - - Note over Data: Changes from:
- Tags
- Personas
- World Info
- Groups - - Data->>PC: All changes trigger printCharacters
(direct or debounced) - - PC->>GEL: Call with {doFilter: true} - GEL->>FH: filterByTagState(entities) - GEL->>AF: entitiesFilter.applyFilters(entities) - - AF->>FH: Check scoreCache for existing results - FH-->>AF: Return cached scores if exist - - Note over FS: Filter functions include:
SEARCH,
FAV,
GROUP,
FOLDER,
TAG,
WORLD_INFO_SEARCH,
PERSONA_SEARCH - AF->>FS: fuzzySearchCharacters/Groups/Tags - FS->>Cache: Check/Store results - - FS-->>AF: Return search results - AF->>FH: Cache new scores - AF-->>GEL: Return filtered entities - GEL-->>PC: Return final entities list - - PC->>Cache: clearFuzzySearchCaches() - Note over Cache: Cache is cleared at the end of
each printCharacters call,
ensuring fresh results for next search -``` diff --git a/public/script.js b/public/script.js index 3db294dd5..22b5f9eac 100644 --- a/public/script.js +++ b/public/script.js @@ -268,7 +268,6 @@ import { initServerHistory } from './scripts/server-history.js'; import { initSettingsSearch } from './scripts/setting-search.js'; import { initBulkEdit } from './scripts/bulk-edit.js'; import { deriveTemplatesFromChatTemplate } from './scripts/chat-templates.js'; -import { clearFuzzySearchCaches } from './scripts/power-user.js'; //exporting functions and vars for mods export { @@ -1516,7 +1515,6 @@ export async function printCharacters(fullRefresh = false) { }); favsToHotswap(); - clearFuzzySearchCaches(); } /** Checks the state of the current search, and adds/removes the search sorting option accordingly */ @@ -1623,7 +1621,7 @@ export function getEntitiesList({ doFilter = false, doSort = true } = {}) { subEntities = filterByTagState(entities, { subForEntity: entity }); if (doFilter) { // sub entities filter "hacked" because folder filter should not be applied there, so even in "only folders" mode characters show up - subEntities = entitiesFilter.applyFilters(subEntities, { clearScoreCache: false, tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED } }); + subEntities = entitiesFilter.applyFilters(subEntities, { clearScoreCache: false, tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED }, clearFuzzySearchCaches: false }); } if (doSort) { sortEntitiesList(subEntities); @@ -1636,11 +1634,11 @@ export function getEntitiesList({ doFilter = false, doSort = true } = {}) { // Second run filters, hiding whatever should be filtered later if (doFilter) { const beforeFinalEntities = filterByTagState(entities, { globalDisplayFilters: true }); - entities = entitiesFilter.applyFilters(beforeFinalEntities); + entities = entitiesFilter.applyFilters(beforeFinalEntities, { clearFuzzySearchCaches: false }); // Magic for folder filter. If that one is enabled, and no folders are display anymore, we remove that filter to actually show the characters. if (isFilterState(entitiesFilter.getFilterData(FILTER_TYPES.FOLDER), FILTER_STATES.SELECTED) && entities.filter(x => x.type == 'tag').length == 0) { - entities = entitiesFilter.applyFilters(beforeFinalEntities, { tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED } }); + entities = entitiesFilter.applyFilters(beforeFinalEntities, { tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED }, clearFuzzySearchCaches: false }); } } @@ -1656,6 +1654,7 @@ export function getEntitiesList({ doFilter = false, doSort = true } = {}) { if (doSort) { sortEntitiesList(entities); } + entitiesFilter.clearFuzzySearchCaches(); return entities; } @@ -1751,6 +1750,7 @@ export async function getCharacters() { } await getGroups(); + // clearFuzzySearchCaches(); await printCharacters(true); } } diff --git a/public/scripts/filters.js b/public/scripts/filters.js index adc27b349..2d01e45e3 100644 --- a/public/scripts/filters.js +++ b/public/scripts/filters.js @@ -55,6 +55,19 @@ export function isFilterState(a, b) { return aKey === bKey; } +/** + * The fuzzy search categories + * @type {{ characters: string, worldInfo: string, personas: string, tags: string, groups: string }} + */ +export const fuzzySearchCategories = Object.freeze({ + characters: 'characters', + worldInfo: 'worldInfo', + personas: 'personas', + tags: 'tags', + groups: 'groups', +}); + + /** * Helper class for filtering data. * @example @@ -72,6 +85,12 @@ export class FilterHelper { */ scoreCache; + /** + * Cache for fuzzy search results per category. + * @type {Object. }>} + */ + fuzzySearchCaches; + /** * Creates a new FilterHelper * @param {Function} onDataChanged Callback to trigger when the filter data changes @@ -79,6 +98,13 @@ export class FilterHelper { constructor(onDataChanged) { this.onDataChanged = onDataChanged; this.scoreCache = new Map(); + this.fuzzySearchCaches = { + [fuzzySearchCategories.characters]: { resultMap: new Map() }, + [fuzzySearchCategories.worldInfo]: { resultMap: new Map() }, + [fuzzySearchCategories.personas]: { resultMap: new Map() }, + [fuzzySearchCategories.tags]: { resultMap: new Map() }, + [fuzzySearchCategories.groups]: { resultMap: new Map() }, + }; } /** @@ -151,7 +177,7 @@ export class FilterHelper { return data; } - const fuzzySearchResults = fuzzySearchWorldInfo(data, term); + const fuzzySearchResults = fuzzySearchWorldInfo(data, term, this.fuzzySearchCaches); this.cacheScores(FILTER_TYPES.WORLD_INFO_SEARCH, new Map(fuzzySearchResults.map(i => [i.item?.uid, i.score]))); const filteredData = data.filter(entity => fuzzySearchResults.find(x => x.item === entity)); @@ -170,7 +196,7 @@ export class FilterHelper { return data; } - const fuzzySearchResults = fuzzySearchPersonas(data, term); + const fuzzySearchResults = fuzzySearchPersonas(data, term, this.fuzzySearchCaches); this.cacheScores(FILTER_TYPES.PERSONA_SEARCH, new Map(fuzzySearchResults.map(i => [i.item.key, i.score]))); const filteredData = data.filter(name => fuzzySearchResults.find(x => x.item.key === name)); @@ -289,9 +315,9 @@ export class FilterHelper { // Save fuzzy search results and scores if enabled if (power_user.fuzzy_search) { - const fuzzySearchCharactersResults = fuzzySearchCharacters(searchValue); - const fuzzySearchGroupsResults = fuzzySearchGroups(searchValue); - const fuzzySearchTagsResult = fuzzySearchTags(searchValue); + const fuzzySearchCharactersResults = fuzzySearchCharacters(searchValue, this.fuzzySearchCaches); + const fuzzySearchGroupsResults = fuzzySearchGroups(searchValue, this.fuzzySearchCaches); + const fuzzySearchTagsResult = fuzzySearchTags(searchValue, this.fuzzySearchCaches); this.cacheScores(FILTER_TYPES.SEARCH, new Map(fuzzySearchCharactersResults.map(i => [`character.${i.refIndex}`, i.score]))); this.cacheScores(FILTER_TYPES.SEARCH, new Map(fuzzySearchGroupsResults.map(i => [`group.${i.item.id}`, i.score]))); this.cacheScores(FILTER_TYPES.SEARCH, new Map(fuzzySearchTagsResult.map(i => [`tag.${i.item.id}`, i.score]))); @@ -343,11 +369,14 @@ export class FilterHelper { * @param {object} options - Optional call parameters * @param {boolean} [options.clearScoreCache=true] - Whether the score cache should be cleared. * @param {Object.} [options.tempOverrides={}] - Temporarily override specific filters for this filter application + * @param {boolean} [options.clearFuzzySearchCaches=true] - Whether the fuzzy search caches should be cleared. * @returns {any[]} The filtered data. */ - applyFilters(data, { clearScoreCache = true, tempOverrides = {} } = {}) { + applyFilters(data, { clearScoreCache = true, tempOverrides = {}, clearFuzzySearchCaches = true } = {}) { if (clearScoreCache) this.clearScoreCache(); + if (clearFuzzySearchCaches) this.clearFuzzySearchCaches(); + // Save original filter states const originalStates = {}; for (const key in tempOverrides) { @@ -411,4 +440,20 @@ export class FilterHelper { this.scoreCache = new Map(); } } + + /** + * Clears fuzzy search caches + * @param {keyof typeof fuzzySearchCategories} [type] Optional cache type to clear. If not provided, clears all caches + */ + clearFuzzySearchCaches(type = null) { + if (type && this.fuzzySearchCaches[type]) { + this.fuzzySearchCaches[type].resultMap.clear(); + console.log(`Fuzzy search cache cleared for: ${type}`); + } else { + for (const cache of Object.values(this.fuzzySearchCaches)) { + cache.resultMap.clear(); + } + console.log('All fuzzy search caches cleared'); + } + } } diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 5b64fcee8..0a36952f2 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -53,6 +53,7 @@ import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandE import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js'; import { POPUP_TYPE, callGenericPopup } from './popup.js'; import { loadSystemPrompts } from './sysprompt.js'; +import { fuzzySearchCategories } from './filters.js'; export { loadPowerUserSettings, @@ -328,22 +329,6 @@ const contextControls = [ let browser_has_focus = true; const debug_functions = []; -const fuzzySearchCaches = { - characters: { resultMap: new Map() }, - worldInfo: { resultMap: new Map() }, - personas: { resultMap: new Map() }, - tags: { resultMap: new Map() }, - groups: { resultMap: new Map() }, -}; - -const fuzzySearchCategories = { - characters: 'characters', - worldInfo: 'worldInfo', - personas: 'personas', - tags: 'tags', - groups: 'groups', -}; - const setHotswapsDebounced = debounce(favsToHotswap); function playMessageSound() { @@ -1845,19 +1830,26 @@ async function loadContextSettings() { }); } + /** * Common function to perform fuzzy search with caching * @param {string} type - Type of search from fuzzySearchCategories * @param {any[]} data - Data array to search in * @param {Array<{name: string, weight: number, getFn?: Function}>} keys - Fuse.js keys configuration * @param {string} searchValue - The search term + * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -function performFuzzySearch(type, data, keys, searchValue) { +function performFuzzySearch(type, data, keys, searchValue, fuzzySearchCaches) { + let startTime = performance.now(); const cache = fuzzySearchCaches[type]; // Check cache for existing results if (cache.resultMap.has(searchValue)) { + let endTime = performance.now(); + if (endTime - startTime > 1.0) { + console.log(`Fuzzy search for ${type} took ${endTime - startTime}ms (cached)`); + } return cache.resultMap.get(searchValue); } @@ -1872,26 +1864,20 @@ function performFuzzySearch(type, data, keys, searchValue) { const results = fuse.search(searchValue); cache.resultMap.set(searchValue, results); - return results; -} - - -/** - * Clears all fuzzy search caches - */ -export function clearFuzzySearchCaches() { - for (const cache of Object.values(fuzzySearchCaches)) { - cache.resultMap.clear(); + let endTime = performance.now(); + if (endTime - startTime > 1.0) { + console.log(`Fuzzy search for ${type} took ${endTime - startTime}ms`); } - console.log('Fuzzy search caches cleared'); + return results; } /** * Fuzzy search characters by a search term * @param {string} searchValue - The search term + * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -export function fuzzySearchCharacters(searchValue) { +export function fuzzySearchCharacters(searchValue, fuzzySearchCaches) { const keys = [ { name: 'data.name', weight: 20 }, { name: '#tags', weight: 10, getFn: (character) => getTagsList(character.avatar).map(x => x.name).join('||') }, @@ -1906,16 +1892,17 @@ export function fuzzySearchCharacters(searchValue) { { name: 'data.alternate_greetings', weight: 1 }, ]; - return performFuzzySearch(fuzzySearchCategories.characters, characters, keys, searchValue); + return performFuzzySearch(fuzzySearchCategories.characters, characters, keys, searchValue, fuzzySearchCaches); } /** * Fuzzy search world info entries by a search term * @param {*[]} data - WI items data array * @param {string} searchValue - The search term + * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -export function fuzzySearchWorldInfo(data, searchValue) { +export function fuzzySearchWorldInfo(data, searchValue, fuzzySearchCaches) { const keys = [ { name: 'key', weight: 20 }, { name: 'group', weight: 15 }, @@ -1926,16 +1913,17 @@ export function fuzzySearchWorldInfo(data, searchValue) { { name: 'automationId', weight: 1 }, ]; - return performFuzzySearch(fuzzySearchCategories.worldInfo, data, keys, searchValue); + return performFuzzySearch(fuzzySearchCategories.worldInfo, data, keys, searchValue, fuzzySearchCaches); } /** * Fuzzy search persona entries by a search term * @param {*[]} data - persona data array * @param {string} searchValue - The search term + * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -export function fuzzySearchPersonas(data, searchValue) { +export function fuzzySearchPersonas(data, searchValue, fuzzySearchCaches) { const mappedData = data.map(x => ({ key: x, name: power_user.personas[x] ?? '', @@ -1947,28 +1935,30 @@ export function fuzzySearchPersonas(data, searchValue) { { name: 'description', weight: 3 }, ]; - return performFuzzySearch(fuzzySearchCategories.personas, mappedData, keys, searchValue); + return performFuzzySearch(fuzzySearchCategories.personas, mappedData, keys, searchValue, fuzzySearchCaches); } /** * Fuzzy search tags by a search term * @param {string} searchValue - The search term + * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -export function fuzzySearchTags(searchValue) { +export function fuzzySearchTags(searchValue, fuzzySearchCaches) { const keys = [ { name: 'name', weight: 1 }, ]; - return performFuzzySearch(fuzzySearchCategories.tags, tags, keys, searchValue); + return performFuzzySearch(fuzzySearchCategories.tags, tags, keys, searchValue, fuzzySearchCaches); } /** * Fuzzy search groups by a search term * @param {string} searchValue - The search term + * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -export function fuzzySearchGroups(searchValue) { +export function fuzzySearchGroups(searchValue, fuzzySearchCaches) { const keys = [ { name: 'name', weight: 20 }, { name: 'members', weight: 15 }, @@ -1976,7 +1966,7 @@ export function fuzzySearchGroups(searchValue) { { name: 'id', weight: 1 }, ]; - return performFuzzySearch(fuzzySearchCategories.groups, groups, keys, searchValue); + return performFuzzySearch(fuzzySearchCategories.groups, groups, keys, searchValue, fuzzySearchCaches); } /** From 309157dd8932518d5f1cc4349e022bdbf832ec66 Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 26 Nov 2024 19:52:21 -0800 Subject: [PATCH 13/31] Remove unnecesary key only clearing for cache clearing --- public/scripts/filters.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/public/scripts/filters.js b/public/scripts/filters.js index 2d01e45e3..f07b4e33f 100644 --- a/public/scripts/filters.js +++ b/public/scripts/filters.js @@ -443,17 +443,11 @@ export class FilterHelper { /** * Clears fuzzy search caches - * @param {keyof typeof fuzzySearchCategories} [type] Optional cache type to clear. If not provided, clears all caches */ - clearFuzzySearchCaches(type = null) { - if (type && this.fuzzySearchCaches[type]) { - this.fuzzySearchCaches[type].resultMap.clear(); - console.log(`Fuzzy search cache cleared for: ${type}`); - } else { - for (const cache of Object.values(this.fuzzySearchCaches)) { - cache.resultMap.clear(); - } - console.log('All fuzzy search caches cleared'); + clearFuzzySearchCaches() { + for (const cache of Object.values(this.fuzzySearchCaches)) { + cache.resultMap.clear(); } + console.log('All fuzzy search caches cleared'); } } From f4ef9697e983a0bb0b3b0ab6388f5ecbfe37898e Mon Sep 17 00:00:00 2001 From: Joe Date: Tue, 26 Nov 2024 20:07:30 -0800 Subject: [PATCH 14/31] Account for optional cache and remove timing code --- public/script.js | 1 - public/scripts/power-user.js | 48 +++++++++++++++++------------------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/public/script.js b/public/script.js index 22b5f9eac..4d97e91b9 100644 --- a/public/script.js +++ b/public/script.js @@ -1750,7 +1750,6 @@ export async function getCharacters() { } await getGroups(); - // clearFuzzySearchCaches(); await printCharacters(true); } } diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 0a36952f2..931067333 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -1832,25 +1832,21 @@ async function loadContextSettings() { /** - * Common function to perform fuzzy search with caching + * Common function to perform fuzzy search with optional caching * @param {string} type - Type of search from fuzzySearchCategories * @param {any[]} data - Data array to search in * @param {Array<{name: string, weight: number, getFn?: Function}>} keys - Fuse.js keys configuration * @param {string} searchValue - The search term - * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches + * @param {Object. }>} [fuzzySearchCaches=null] - Optional fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -function performFuzzySearch(type, data, keys, searchValue, fuzzySearchCaches) { - let startTime = performance.now(); - const cache = fuzzySearchCaches[type]; - - // Check cache for existing results - if (cache.resultMap.has(searchValue)) { - let endTime = performance.now(); - if (endTime - startTime > 1.0) { - console.log(`Fuzzy search for ${type} took ${endTime - startTime}ms (cached)`); +function performFuzzySearch(type, data, keys, searchValue, fuzzySearchCaches = null) { + // Check cache if provided + if (fuzzySearchCaches) { + const cache = fuzzySearchCaches[type]; + if (cache?.resultMap.has(searchValue)) { + return cache.resultMap.get(searchValue); } - return cache.resultMap.get(searchValue); } // @ts-ignore @@ -1863,10 +1859,10 @@ function performFuzzySearch(type, data, keys, searchValue, fuzzySearchCaches) { }); const results = fuse.search(searchValue); - cache.resultMap.set(searchValue, results); - let endTime = performance.now(); - if (endTime - startTime > 1.0) { - console.log(`Fuzzy search for ${type} took ${endTime - startTime}ms`); + + // Store in cache if provided + if (fuzzySearchCaches) { + fuzzySearchCaches[type].resultMap.set(searchValue, results); } return results; } @@ -1874,10 +1870,10 @@ function performFuzzySearch(type, data, keys, searchValue, fuzzySearchCaches) { /** * Fuzzy search characters by a search term * @param {string} searchValue - The search term - * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches + * @param {Object. }>} [fuzzySearchCaches=null] - Optional fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -export function fuzzySearchCharacters(searchValue, fuzzySearchCaches) { +export function fuzzySearchCharacters(searchValue, fuzzySearchCaches = null) { const keys = [ { name: 'data.name', weight: 20 }, { name: '#tags', weight: 10, getFn: (character) => getTagsList(character.avatar).map(x => x.name).join('||') }, @@ -1899,10 +1895,10 @@ export function fuzzySearchCharacters(searchValue, fuzzySearchCaches) { * Fuzzy search world info entries by a search term * @param {*[]} data - WI items data array * @param {string} searchValue - The search term - * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches + * @param {Object. }>} [fuzzySearchCaches=null] - Optional fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -export function fuzzySearchWorldInfo(data, searchValue, fuzzySearchCaches) { +export function fuzzySearchWorldInfo(data, searchValue, fuzzySearchCaches = null) { const keys = [ { name: 'key', weight: 20 }, { name: 'group', weight: 15 }, @@ -1920,10 +1916,10 @@ export function fuzzySearchWorldInfo(data, searchValue, fuzzySearchCaches) { * Fuzzy search persona entries by a search term * @param {*[]} data - persona data array * @param {string} searchValue - The search term - * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches + * @param {Object. }>} [fuzzySearchCaches=null] - Optional fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -export function fuzzySearchPersonas(data, searchValue, fuzzySearchCaches) { +export function fuzzySearchPersonas(data, searchValue, fuzzySearchCaches = null) { const mappedData = data.map(x => ({ key: x, name: power_user.personas[x] ?? '', @@ -1941,10 +1937,10 @@ export function fuzzySearchPersonas(data, searchValue, fuzzySearchCaches) { /** * Fuzzy search tags by a search term * @param {string} searchValue - The search term - * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches + * @param {Object. }>} [fuzzySearchCaches=null] - Optional fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -export function fuzzySearchTags(searchValue, fuzzySearchCaches) { +export function fuzzySearchTags(searchValue, fuzzySearchCaches = null) { const keys = [ { name: 'name', weight: 1 }, ]; @@ -1955,10 +1951,10 @@ export function fuzzySearchTags(searchValue, fuzzySearchCaches) { /** * Fuzzy search groups by a search term * @param {string} searchValue - The search term - * @param {Object. }>} fuzzySearchCaches - Fuzzy search caches + * @param {Object. }>} [fuzzySearchCaches=null] - Optional fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score */ -export function fuzzySearchGroups(searchValue, fuzzySearchCaches) { +export function fuzzySearchGroups(searchValue, fuzzySearchCaches = null) { const keys = [ { name: 'name', weight: 20 }, { name: 'members', weight: 15 }, From ef35adb9e401a82426f75bcec5c219e439357f20 Mon Sep 17 00:00:00 2001 From: Karl-Johan Alm Date: Thu, 28 Nov 2024 12:45:05 +0900 Subject: [PATCH 15/31] tulu template: added \n to input_suffix and system_suffix to match model card --- default/content/presets/instruct/Tulu.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/default/content/presets/instruct/Tulu.json b/default/content/presets/instruct/Tulu.json index 7ac968507..14072f563 100644 --- a/default/content/presets/instruct/Tulu.json +++ b/default/content/presets/instruct/Tulu.json @@ -12,9 +12,9 @@ "activation_regex": "", "skip_examples": false, "output_suffix": "<|end_of_text|>\n", - "input_suffix": "", + "input_suffix": "\n", "system_sequence": "<|system|>\n", - "system_suffix": "", + "system_suffix": "\n", "user_alignment_message": "", "last_system_sequence": "", "system_same_as_user": false, From 8bfb6955363402a3191f686aa8d6ee67a033513c Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:38:10 +0000 Subject: [PATCH 16/31] Adjust documentation links --- public/index.html | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/public/index.html b/public/index.html index 7c2371604..c00ab84f7 100644 --- a/public/index.html +++ b/public/index.html @@ -3272,7 +3272,7 @@ Advanced Formatting -
+

@@ -3734,7 +3734,7 @@

Worlds/Lorebooks - +

@@ -3928,7 +3928,13 @@
-

User Settings

+

+ User Settings + + + + +

@@ -4261,9 +4267,6 @@ Message Sound - - -