Handle stale cache
| @@ -330,12 +330,6 @@ const debug_functions = []; | ||
| 330 | 330 | |
| 331 | 331 | const setHotswapsDebounced = debounce(favsToHotswap); |
| 332 | 332 | |
| 333 | -const fuzzySearchCharactersCache = new Map(); | |
| 334 | -const fuzzySearchWorldInfoCache = new Map(); | |
| 335 | -const fuzzySearchPersonasCache = new Map(); | |
| 336 | -const fuzzySearchTagsCache = new Map(); | |
| 337 | -const fuzzySearchGroupsCache = new Map(); | |
| 338 | - | |
| 339 | 333 | function playMessageSound() { |
| 340 | 334 | if (!power_user.play_message_sound) { |
| 341 | 335 | return; |
| @@ -1830,20 +1824,37 @@ async function loadContextSettings() { | ||
| 1830 | 1824 | }); |
| 1831 | 1825 | } |
| 1832 | 1826 | |
| 1827 | +// Create separate caches for each type of fuzzy search | |
| 1828 | +const fuzzySearchCaches = { | |
| 1829 | + characters: { keyHash: null, resultMap: new Map() }, | |
| 1830 | + worldInfo: { keyHash: null, resultMap: new Map() }, | |
| 1831 | + personas: { keyHash: null, resultMap: new Map() }, | |
| 1832 | + tags: { keyHash: null, resultMap: new Map() }, | |
| 1833 | + groups: { keyHash: null, resultMap: new Map() }, | |
| 1834 | +}; | |
| 1835 | + | |
| 1833 | 1836 | /** |
| 1834 | 1837 | * FuzzyGenerates searcha charactershash byof athe searchFuse termconfiguration keys |
| 1835 | 1838 | * @param {Array<{name: string}, searchValueweight: -number, ThegetFn?: searchFunction}>} termkeys |
| 1836 | - * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score | |
| 1839 | + * @returns {number} Hash of the keys configuration | |
| 1837 | 1840 | */ |
| 1838 | 1841 | export function fuzzySearchCharactershashFuseKeys(searchValuekeys) { |
| 1842 | + // Convert keys to a stable string representation | |
| 1843 | + const keyString = keys.map(k => { | |
| 1844 | + const getFnString = k.getFn ? k.getFn.toString() : ''; | |
| 1845 | + return `${k.name}:${k.weight}:${getFnString}`; | |
| 1846 | + }).join('|'); | |
| 1839 | 1847 | |
| 1840 | - if (fuzzySearchCharactersCache.has(searchValue)) { | |
| 1848 | + return getStringHash(keyString); | |
| 1841 | - return fuzzySearchCharactersCache.get(searchValue); | |
| 1842 | 1849 | } |
| 1843 | 1850 | |
| 1844 | - // @ts-ignore | |
| 1851 | +/** | |
| 1845 | - const fuse = new Fuse(characters, { | |
| 1852 | + * Fuzzy search characters by a search term with caching | |
| 1846 | - keys: [ | |
| 1853 | + * @param {string} searchValue - The search term | |
| 1854 | + * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score | |
| 1855 | + */ | |
| 1856 | +export function fuzzySearchCharacters(searchValue) { | |
| 1857 | + const fuseKeys = [ | |
| 1847 | 1858 | { name: 'data.name', weight: 20 }, |
| 1848 | 1859 | { name: '#tags', weight: 10, getFn: (character) => getTagsList(character.avatar).map(x => x.name).join('||') }, |
| 1849 | 1860 | { name: 'data.description', weight: 3 }, |
| @@ -1855,7 +1866,28 @@ export function fuzzySearchCharacters(searchValue) { | ||
| 1855 | 1866 | { name: 'data.creator', weight: 1 }, |
| 1856 | 1867 | { name: 'data.tags', weight: 1 }, |
| 1857 | 1868 | { name: 'data.alternate_greetings', weight: 1 }, |
| 1858 | - ], | |
| 1869 | + ]; | |
| 1870 | + | |
| 1871 | + // Generate hash of current keys configuration | |
| 1872 | + const currentKeyHash = hashFuseKeys(fuseKeys); | |
| 1873 | + const cache = fuzzySearchCaches.characters; | |
| 1874 | + | |
| 1875 | + // Check if we have a cached result for this search value | |
| 1876 | + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { | |
| 1877 | + console.debug('Using cached fuzzy search results for ' + searchValue); | |
| 1878 | + return cache.resultMap.get(searchValue); | |
| 1879 | + } | |
| 1880 | + | |
| 1881 | + // If key configuration changed, clear the cache | |
| 1882 | + if (cache.keyHash !== currentKeyHash) { | |
| 1883 | + console.debug('Fuse keys changed, clearing cache'); | |
| 1884 | + cache.keyHash = currentKeyHash; | |
| 1885 | + cache.resultMap.clear(); | |
| 1886 | + } | |
| 1887 | + | |
| 1888 | + // Create new Fuse instance and perform search | |
| 1889 | + const fuse = new Fuse(characters, { | |
| 1890 | + keys: fuseKeys, | |
| 1859 | 1891 | includeScore: true, |
| 1860 | 1892 | ignoreLocation: true, |
| 1861 | 1893 | useExtendedSearch: true, |
| @@ -1863,8 +1895,11 @@ export function fuzzySearchCharacters(searchValue) { | ||
| 1863 | 1895 | }); |
| 1864 | 1896 | |
| 1865 | 1897 | const results = fuse.search(searchValue); |
| 1898 | + | |
| 1899 | + // Cache the results | |
| 1900 | + cache.resultMap.set(searchValue, results); | |
| 1901 | + | |
| 1866 | 1902 | console.debug('Characters fuzzy search results for ' + searchValue, results); |
| 1867 | - fuzzySearchCharactersCache.set(searchValue, results); | |
| 1868 | 1903 | return results; |
| 1869 | 1904 | } |
| 1870 | 1905 | |
| @@ -1875,13 +1910,7 @@ export function fuzzySearchCharacters(searchValue) { | ||
| 1875 | 1910 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score |
| 1876 | 1911 | */ |
| 1877 | 1912 | export function fuzzySearchWorldInfo(data, searchValue) { |
| 1878 | - if (fuzzySearchWorldInfoCache.has(searchValue)) { | |
| 1913 | + const fuseKeys = [ | |
| 1879 | - return fuzzySearchWorldInfoCache.get(searchValue); | |
| 1880 | - } | |
| 1881 | - | |
| 1882 | - // @ts-ignore | |
| 1883 | - const fuse = new Fuse(data, { | |
| 1884 | - keys: [ | |
| 1885 | 1914 | { name: 'key', weight: 20 }, |
| 1886 | 1915 | { name: 'group', weight: 15 }, |
| 1887 | 1916 | { name: 'comment', weight: 10 }, |
| @@ -1889,7 +1918,26 @@ export function fuzzySearchWorldInfo(data, searchValue) { | ||
| 1889 | 1918 | { name: 'content', weight: 3 }, |
| 1890 | 1919 | { name: 'uid', weight: 1 }, |
| 1891 | 1920 | { name: 'automationId', weight: 1 }, |
| 1892 | - ], | |
| 1921 | + ]; | |
| 1922 | + | |
| 1923 | + const currentKeyHash = hashFuseKeys(fuseKeys); | |
| 1924 | + const cache = fuzzySearchCaches.worldInfo; | |
| 1925 | + | |
| 1926 | + // Check cache for existing results | |
| 1927 | + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { | |
| 1928 | + console.debug('Using cached WI fuzzy search results for ' + searchValue); | |
| 1929 | + return cache.resultMap.get(searchValue); | |
| 1930 | + } | |
| 1931 | + | |
| 1932 | + // Clear cache if keys changed | |
| 1933 | + if (cache.keyHash !== currentKeyHash) { | |
| 1934 | + console.debug('WI Fuse keys changed, clearing cache'); | |
| 1935 | + cache.keyHash = currentKeyHash; | |
| 1936 | + cache.resultMap.clear(); | |
| 1937 | + } | |
| 1938 | + | |
| 1939 | + const fuse = new Fuse(data, { | |
| 1940 | + keys: fuseKeys, | |
| 1893 | 1941 | includeScore: true, |
| 1894 | 1942 | ignoreLocation: true, |
| 1895 | 1943 | useExtendedSearch: true, |
| @@ -1897,8 +1945,9 @@ export function fuzzySearchWorldInfo(data, searchValue) { | ||
| 1897 | 1945 | }); |
| 1898 | 1946 | |
| 1899 | 1947 | const results = fuse.search(searchValue); |
| 1948 | + cache.resultMap.set(searchValue, results); | |
| 1949 | + | |
| 1900 | 1950 | console.debug('World Info fuzzy search results for ' + searchValue, results); |
| 1901 | - fuzzySearchWorldInfoCache.set(searchValue, results); | |
| 1902 | 1951 | return results; |
| 1903 | 1952 | } |
| 1904 | 1953 | |
| @@ -1909,17 +1958,31 @@ export function fuzzySearchWorldInfo(data, searchValue) { | ||
| 1909 | 1958 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score |
| 1910 | 1959 | */ |
| 1911 | 1960 | export function fuzzySearchPersonas(data, searchValue) { |
| 1912 | - if (fuzzySearchPersonasCache.has(searchValue)) { | |
| 1913 | - return fuzzySearchPersonasCache.get(searchValue); | |
| 1914 | - } | |
| 1915 | - | |
| 1916 | 1961 | data = data.map(x => ({ key: x, name: power_user.personas[x] ?? '', description: power_user.persona_descriptions[x]?.description ?? '' })); |
| 1917 | - // @ts-ignore | |
| 1962 | + | |
| 1918 | 1963 | const fusefuseKeys = new Fuse(data, {[ |
| 1919 | - keys: [ | |
| 1920 | 1964 | { name: 'name', weight: 20 }, |
| 1921 | 1965 | { name: 'description', weight: 3 }, |
| 1922 | - ], | |
| 1966 | + ]; | |
| 1967 | + | |
| 1968 | + const currentKeyHash = hashFuseKeys(fuseKeys); | |
| 1969 | + const cache = fuzzySearchCaches.personas; | |
| 1970 | + | |
| 1971 | + // Check cache for existing results | |
| 1972 | + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { | |
| 1973 | + console.debug('Using cached personas fuzzy search results for ' + searchValue); | |
| 1974 | + return cache.resultMap.get(searchValue); | |
| 1975 | + } | |
| 1976 | + | |
| 1977 | + // Clear cache if keys changed | |
| 1978 | + if (cache.keyHash !== currentKeyHash) { | |
| 1979 | + console.debug('Personas Fuse keys changed, clearing cache'); | |
| 1980 | + cache.keyHash = currentKeyHash; | |
| 1981 | + cache.resultMap.clear(); | |
| 1982 | + } | |
| 1983 | + | |
| 1984 | + const fuse = new Fuse(data, { | |
| 1985 | + keys: fuseKeys, | |
| 1923 | 1986 | includeScore: true, |
| 1924 | 1987 | ignoreLocation: true, |
| 1925 | 1988 | useExtendedSearch: true, |
| @@ -1927,8 +1990,9 @@ export function fuzzySearchPersonas(data, searchValue) { | ||
| 1927 | 1990 | }); |
| 1928 | 1991 | |
| 1929 | 1992 | const results = fuse.search(searchValue); |
| 1993 | + cache.resultMap.set(searchValue, results); | |
| 1994 | + | |
| 1930 | 1995 | console.debug('Personas fuzzy search results for ' + searchValue, results); |
| 1931 | - fuzzySearchPersonasCache.set(searchValue, results); | |
| 1932 | 1996 | return results; |
| 1933 | 1997 | } |
| 1934 | 1998 | |
| @@ -1938,15 +2002,28 @@ export function fuzzySearchPersonas(data, searchValue) { | ||
| 1938 | 2002 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score |
| 1939 | 2003 | */ |
| 1940 | 2004 | export function fuzzySearchTags(searchValue) { |
| 1941 | - if (fuzzySearchTagsCache.has(searchValue)) { | |
| 2005 | + const fuseKeys = [ | |
| 1942 | - return fuzzySearchTagsCache.get(searchValue); | |
| 2006 | + { name: 'name', weight: 1 }, | |
| 2007 | + ]; | |
| 2008 | + | |
| 2009 | + const currentKeyHash = hashFuseKeys(fuseKeys); | |
| 2010 | + const cache = fuzzySearchCaches.tags; | |
| 2011 | + | |
| 2012 | + // Check cache for existing results | |
| 2013 | + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { | |
| 2014 | + console.debug('Using cached tags fuzzy search results for ' + searchValue); | |
| 2015 | + return cache.resultMap.get(searchValue); | |
| 2016 | + } | |
| 2017 | + | |
| 2018 | + // Clear cache if keys changed | |
| 2019 | + if (cache.keyHash !== currentKeyHash) { | |
| 2020 | + console.debug('Tags Fuse keys changed, clearing cache'); | |
| 2021 | + cache.keyHash = currentKeyHash; | |
| 2022 | + cache.resultMap.clear(); | |
| 1943 | 2023 | } |
| 1944 | 2024 | |
| 1945 | - // @ts-ignore | |
| 1946 | 2025 | const fuse = new Fuse(tags, { |
| 1947 | 2026 | keys: [fuseKeys, |
| 1948 | - { name: 'name', weight: 1 }, | |
| 1949 | - ], | |
| 1950 | 2027 | includeScore: true, |
| 1951 | 2028 | ignoreLocation: true, |
| 1952 | 2029 | useExtendedSearch: true, |
| @@ -1954,8 +2031,9 @@ export function fuzzySearchTags(searchValue) { | ||
| 1954 | 2031 | }); |
| 1955 | 2032 | |
| 1956 | 2033 | const results = fuse.search(searchValue); |
| 2034 | + cache.resultMap.set(searchValue, results); | |
| 2035 | + | |
| 1957 | 2036 | console.debug('Tags fuzzy search results for ' + searchValue, results); |
| 1958 | - fuzzySearchTagsCache.set(searchValue, results); | |
| 1959 | 2037 | return results; |
| 1960 | 2038 | } |
| 1961 | 2039 | |
| @@ -1965,18 +2043,31 @@ export function fuzzySearchTags(searchValue) { | ||
| 1965 | 2043 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score |
| 1966 | 2044 | */ |
| 1967 | 2045 | export function fuzzySearchGroups(searchValue) { |
| 1968 | - if (fuzzySearchGroupsCache.has(searchValue)) { | |
| 2046 | + const fuseKeys = [ | |
| 1969 | - return fuzzySearchGroupsCache.get(searchValue); | |
| 1970 | - } | |
| 1971 | - | |
| 1972 | - // @ts-ignore | |
| 1973 | - const fuse = new Fuse(groups, { | |
| 1974 | - keys: [ | |
| 1975 | 2047 | { name: 'name', weight: 20 }, |
| 1976 | 2048 | { name: 'members', weight: 15 }, |
| 1977 | 2049 | { name: '#tags', weight: 10, getFn: (group) => getTagsList(group.id).map(x => x.name).join('||') }, |
| 1978 | 2050 | { name: 'id', weight: 1 }, |
| 1979 | - ], | |
| 2051 | + ]; | |
| 2052 | + | |
| 2053 | + const currentKeyHash = hashFuseKeys(fuseKeys); | |
| 2054 | + const cache = fuzzySearchCaches.groups; | |
| 2055 | + | |
| 2056 | + // Check cache for existing results | |
| 2057 | + if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { | |
| 2058 | + console.debug('Using cached groups fuzzy search results for ' + searchValue); | |
| 2059 | + return cache.resultMap.get(searchValue); | |
| 2060 | + } | |
| 2061 | + | |
| 2062 | + // Clear cache if keys changed | |
| 2063 | + if (cache.keyHash !== currentKeyHash) { | |
| 2064 | + console.debug('Groups Fuse keys changed, clearing cache'); | |
| 2065 | + cache.keyHash = currentKeyHash; | |
| 2066 | + cache.resultMap.clear(); | |
| 2067 | + } | |
| 2068 | + | |
| 2069 | + const fuse = new Fuse(groups, { | |
| 2070 | + keys: fuseKeys, | |
| 1980 | 2071 | includeScore: true, |
| 1981 | 2072 | ignoreLocation: true, |
| 1982 | 2073 | useExtendedSearch: true, |
| @@ -1984,12 +2075,23 @@ export function fuzzySearchGroups(searchValue) { | ||
| 1984 | 2075 | }); |
| 1985 | 2076 | |
| 1986 | 2077 | const results = fuse.search(searchValue); |
| 2078 | + cache.resultMap.set(searchValue, results); | |
| 2079 | + | |
| 1987 | 2080 | console.debug('Groups fuzzy search results for ' + searchValue, results); |
| 1988 | - fuzzySearchGroupsCache.set(searchValue, results); | |
| 1989 | 2081 | return results; |
| 1990 | 2082 | } |
| 1991 | 2083 | |
| 1992 | 2084 | /** |
| 2085 | + * Clears all fuzzy search caches | |
| 2086 | + */ | |
| 2087 | +export function clearFuzzySearchCaches() { | |
| 2088 | + for (const cache of Object.values(fuzzySearchCaches)) { | |
| 2089 | + cache.keyHash = null; | |
| 2090 | + cache.resultMap.clear(); | |
| 2091 | + } | |
| 2092 | +} | |
| 2093 | + | |
| 2094 | +/** | |
| 1993 | 2095 | * Renders a story string template with the given parameters. |
| 1994 | 2096 | * @param {object} params Template parameters. |
| 1995 | 2097 | * @returns {string} The rendered story string. |