Remove duplicated code
| @@ -328,6 +328,22 @@ const contextControls = [ | |||
| 328 | let browser_has_focus = true; | 328 | let browser_has_focus = true; |
| 329 | const debug_functions = []; | 329 | const debug_functions = []; |
| 330 | 330 | ||
| 331 | const fuzzySearchCaches = { | ||
| 332 | characters: { keyHash: null, resultMap: new Map() }, | ||
| 333 | worldInfo: { keyHash: null, resultMap: new Map() }, | ||
| 334 | personas: { keyHash: null, resultMap: new Map() }, | ||
| 335 | tags: { keyHash: null, resultMap: new Map() }, | ||
| 336 | groups: { keyHash: null, resultMap: new Map() }, | ||
| 337 | }; | ||
| 338 | |||
| 339 | const fuzzySearchCategories = { | ||
| 340 | characters: 'characters', | ||
| 341 | worldInfo: 'worldInfo', | ||
| 342 | personas: 'personas', | ||
| 343 | tags: 'tags', | ||
| 344 | groups: 'groups', | ||
| 345 | }; | ||
| 346 | |||
| 331 | const setHotswapsDebounced = debounce(favsToHotswap); | 347 | const setHotswapsDebounced = debounce(favsToHotswap); |
| 332 | 348 | ||
| 333 | function playMessageSound() { | 349 | function playMessageSound() { |
| @@ -1824,15 +1840,6 @@ async function loadContextSettings() { | |||
| 1824 | }); | 1840 | }); |
| 1825 | } | 1841 | } |
| 1826 | 1842 | ||
| 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 | |||
| 1836 | /** | 1843 | /** |
| 1837 | * Generates a hash of the Fuse configuration keys | 1844 | * Generates a hash of the Fuse configuration keys |
| 1838 | * @param {Array<{name: string, weight: number, getFn?: Function}>} keys | 1845 | * @param {Array<{name: string, weight: number, getFn?: Function}>} keys |
| @@ -1849,45 +1856,32 @@ function hashFuseKeys(keys) { | |||
| 1849 | } | 1856 | } |
| 1850 | 1857 | ||
| 1851 | /** | 1858 | /** |
| 1852 | * Fuzzy search characters by a search term with caching | 1859 | * Common function to perform fuzzy search with caching |
| 1860 | * @param {string} type - Type of search from fuzzySearchCategories | ||
| 1861 | * @param {any[]} data - Data array to search in | ||
| 1862 | * @param {Array<{name: string, weight: number, getFn?: Function}>} keys - Fuse.js keys configuration | ||
| 1853 | * @param {string} searchValue - The search term | 1863 | * @param {string} searchValue - The search term |
| 1854 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score | 1864 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score |
| 1855 | */ | 1865 | */ |
| 1856 | export function fuzzySearchCharacters(searchValue) { | 1866 | function performFuzzySearch(type, data, keys, searchValue) { |
| 1857 | const fuseKeys = [ | 1867 | const currentKeyHash = hashFuseKeys(keys); |
| 1858 | { name: 'data.name', weight: 20 }, | 1868 | const cache = fuzzySearchCaches[type]; |
| 1859 | { name: '#tags', weight: 10, getFn: (character) => getTagsList(character.avatar).map(x => x.name).join('||') }, | ||
| 1860 | { name: 'data.description', weight: 3 }, | ||
| 1861 | { name: 'data.mes_example', weight: 3 }, | ||
| 1862 | { name: 'data.scenario', weight: 2 }, | ||
| 1863 | { name: 'data.personality', weight: 2 }, | ||
| 1864 | { name: 'data.first_mes', weight: 2 }, | ||
| 1865 | { name: 'data.creator_notes', weight: 2 }, | ||
| 1866 | { name: 'data.creator', weight: 1 }, | ||
| 1867 | { name: 'data.tags', weight: 1 }, | ||
| 1868 | { name: 'data.alternate_greetings', weight: 1 }, | ||
| 1869 | ]; | ||
| 1870 | |||
| 1871 | // Generate hash of current keys configuration | ||
| 1872 | const currentKeyHash = hashFuseKeys(fuseKeys); | ||
| 1873 | const cache = fuzzySearchCaches.characters; | ||
| 1874 | 1869 | ||
| 1875 | // Check if we have a cached result for this search value | 1870 | // Check cache for existing results |
| 1876 | if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { | 1871 | if (cache.keyHash === currentKeyHash && cache.resultMap.has(searchValue)) { |
| 1877 | console.debug('Using cached fuzzy search results for ' + searchValue); | 1872 | console.log(`Using cached ${type} fuzzy search results for ${searchValue}`); |
| 1878 | return cache.resultMap.get(searchValue); | 1873 | return cache.resultMap.get(searchValue); |
| 1879 | } | 1874 | } |
| 1880 | 1875 | ||
| 1881 | // If key configuration changed, clear the cache | 1876 | // Clear cache if keys changed |
| 1882 | if (cache.keyHash !== currentKeyHash) { | 1877 | if (cache.keyHash !== currentKeyHash) { |
| 1883 | console.debug('Fuse keys changed, clearing cache'); | 1878 | console.log(`${type} Fuse keys changed, clearing cache`); |
| 1884 | cache.keyHash = currentKeyHash; | 1879 | cache.keyHash = currentKeyHash; |
| 1885 | cache.resultMap.clear(); | 1880 | cache.resultMap.clear(); |
| 1886 | } | 1881 | } |
| 1887 | 1882 | ||
| 1888 | // Create new Fuse instance and perform search | 1883 | const fuse = new Fuse(data, { |
| 1889 | const fuse = new Fuse(characters, { | 1884 | keys: keys, |
| 1890 | keys: fuseKeys, | ||
| 1891 | includeScore: true, | 1885 | includeScore: true, |
| 1892 | ignoreLocation: true, | 1886 | ignoreLocation: true, |
| 1893 | useExtendedSearch: true, | 1887 | useExtendedSearch: true, |
| @@ -1895,22 +1889,53 @@ export function fuzzySearchCharacters(searchValue) { | |||
| 1895 | }); | 1889 | }); |
| 1896 | 1890 | ||
| 1897 | const results = fuse.search(searchValue); | 1891 | const results = fuse.search(searchValue); |
| 1898 | |||
| 1899 | // Cache the results | ||
| 1900 | cache.resultMap.set(searchValue, results); | 1892 | cache.resultMap.set(searchValue, results); |
| 1901 | 1893 | ||
| 1902 | console.debug('Characters fuzzy search results for ' + searchValue, results); | 1894 | console.log(`${type} fuzzy search results for ${searchValue}`, results); |
| 1903 | return results; | 1895 | return results; |
| 1904 | } | 1896 | } |
| 1905 | 1897 | ||
| 1906 | /** | 1898 | /** |
| 1899 | * Clears all fuzzy search caches | ||
| 1900 | */ | ||
| 1901 | export function clearFuzzySearchCaches() { | ||
| 1902 | for (const cache of Object.values(fuzzySearchCaches)) { | ||
| 1903 | cache.keyHash = null; | ||
| 1904 | cache.resultMap.clear(); | ||
| 1905 | } | ||
| 1906 | } | ||
| 1907 | |||
| 1908 | /** | ||
| 1909 | * Fuzzy search characters by a search term | ||
| 1910 | * @param {string} searchValue - The search term | ||
| 1911 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score | ||
| 1912 | */ | ||
| 1913 | export function fuzzySearchCharacters(searchValue) { | ||
| 1914 | const keys = [ | ||
| 1915 | { name: 'data.name', weight: 20 }, | ||
| 1916 | { name: '#tags', weight: 10, getFn: (character) => getTagsList(character.avatar).map(x => x.name).join('||') }, | ||
| 1917 | { name: 'data.description', weight: 3 }, | ||
| 1918 | { name: 'data.mes_example', weight: 3 }, | ||
| 1919 | { name: 'data.scenario', weight: 2 }, | ||
| 1920 | { name: 'data.personality', weight: 2 }, | ||
| 1921 | { name: 'data.first_mes', weight: 2 }, | ||
| 1922 | { name: 'data.creator_notes', weight: 2 }, | ||
| 1923 | { name: 'data.creator', weight: 1 }, | ||
| 1924 | { name: 'data.tags', weight: 1 }, | ||
| 1925 | { name: 'data.alternate_greetings', weight: 1 }, | ||
| 1926 | ]; | ||
| 1927 | |||
| 1928 | return performFuzzySearch(fuzzySearchCategories.characters, characters, keys, searchValue); | ||
| 1929 | } | ||
| 1930 | |||
| 1931 | /** | ||
| 1907 | * Fuzzy search world info entries by a search term | 1932 | * Fuzzy search world info entries by a search term |
| 1908 | * @param {*[]} data - WI items data array | 1933 | * @param {*[]} data - WI items data array |
| 1909 | * @param {string} searchValue - The search term | 1934 | * @param {string} searchValue - The search term |
| 1910 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score | 1935 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score |
| 1911 | */ | 1936 | */ |
| 1912 | export function fuzzySearchWorldInfo(data, searchValue) { | 1937 | export function fuzzySearchWorldInfo(data, searchValue) { |
| 1913 | const fuseKeys = [ | 1938 | const keys = [ |
| 1914 | { name: 'key', weight: 20 }, | 1939 | { name: 'key', weight: 20 }, |
| 1915 | { name: 'group', weight: 15 }, | 1940 | { name: 'group', weight: 15 }, |
| 1916 | { name: 'comment', weight: 10 }, | 1941 | { name: 'comment', weight: 10 }, |
| @@ -1920,35 +1945,7 @@ export function fuzzySearchWorldInfo(data, searchValue) { | |||
| 1920 | { name: 'automationId', weight: 1 }, | 1945 | { name: 'automationId', weight: 1 }, |
| 1921 | ]; | 1946 | ]; |
| 1922 | 1947 | ||
| 1923 | const currentKeyHash = hashFuseKeys(fuseKeys); | 1948 | return performFuzzySearch(fuzzySearchCategories.worldInfo, data, keys, searchValue); |
| 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, | ||
| 1941 | includeScore: true, | ||
| 1942 | ignoreLocation: true, | ||
| 1943 | useExtendedSearch: true, | ||
| 1944 | threshold: 0.2, | ||
| 1945 | }); | ||
| 1946 | |||
| 1947 | const results = fuse.search(searchValue); | ||
| 1948 | cache.resultMap.set(searchValue, results); | ||
| 1949 | |||
| 1950 | console.debug('World Info fuzzy search results for ' + searchValue, results); | ||
| 1951 | return results; | ||
| 1952 | } | 1949 | } |
| 1953 | 1950 | ||
| 1954 | /** | 1951 | /** |
| @@ -1958,42 +1955,18 @@ export function fuzzySearchWorldInfo(data, searchValue) { | |||
| 1958 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score | 1955 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score |
| 1959 | */ | 1956 | */ |
| 1960 | export function fuzzySearchPersonas(data, searchValue) { | 1957 | export function fuzzySearchPersonas(data, searchValue) { |
| 1961 | data = data.map(x => ({ key: x, name: power_user.personas[x] ?? '', description: power_user.persona_descriptions[x]?.description ?? '' })); | 1958 | const mappedData = data.map(x => ({ |
| 1959 | key: x, | ||
| 1960 | name: power_user.personas[x] ?? '', | ||
| 1961 | description: power_user.persona_descriptions[x]?.description ?? '' | ||
| 1962 | })); | ||
| 1962 | 1963 | ||
| 1963 | const fuseKeys = [ | 1964 | const keys = [ |
| 1964 | { name: 'name', weight: 20 }, | 1965 | { name: 'name', weight: 20 }, |
| 1965 | { name: 'description', weight: 3 }, | 1966 | { name: 'description', weight: 3 }, |
| 1966 | ]; | 1967 | ]; |
| 1967 | 1968 | ||
| 1968 | const currentKeyHash = hashFuseKeys(fuseKeys); | 1969 | return performFuzzySearch(fuzzySearchCategories.personas, mappedData, keys, searchValue); |
| 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, | ||
| 1986 | includeScore: true, | ||
| 1987 | ignoreLocation: true, | ||
| 1988 | useExtendedSearch: true, | ||
| 1989 | threshold: 0.2, | ||
| 1990 | }); | ||
| 1991 | |||
| 1992 | const results = fuse.search(searchValue); | ||
| 1993 | cache.resultMap.set(searchValue, results); | ||
| 1994 | |||
| 1995 | console.debug('Personas fuzzy search results for ' + searchValue, results); | ||
| 1996 | return results; | ||
| 1997 | } | 1970 | } |
| 1998 | 1971 | ||
| 1999 | /** | 1972 | /** |
| @@ -2002,39 +1975,11 @@ export function fuzzySearchPersonas(data, searchValue) { | |||
| 2002 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score | 1975 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score |
| 2003 | */ | 1976 | */ |
| 2004 | export function fuzzySearchTags(searchValue) { | 1977 | export function fuzzySearchTags(searchValue) { |
| 2005 | const fuseKeys = [ | 1978 | const keys = [ |
| 2006 | { name: 'name', weight: 1 }, | 1979 | { name: 'name', weight: 1 }, |
| 2007 | ]; | 1980 | ]; |
| 2008 | 1981 | ||
| 2009 | const currentKeyHash = hashFuseKeys(fuseKeys); | 1982 | return performFuzzySearch(fuzzySearchCategories.tags, tags, keys, searchValue); |
| 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(); | ||
| 2023 | } | ||
| 2024 | |||
| 2025 | const fuse = new Fuse(tags, { | ||
| 2026 | keys: fuseKeys, | ||
| 2027 | includeScore: true, | ||
| 2028 | ignoreLocation: true, | ||
| 2029 | useExtendedSearch: true, | ||
| 2030 | threshold: 0.2, | ||
| 2031 | }); | ||
| 2032 | |||
| 2033 | const results = fuse.search(searchValue); | ||
| 2034 | cache.resultMap.set(searchValue, results); | ||
| 2035 | |||
| 2036 | console.debug('Tags fuzzy search results for ' + searchValue, results); | ||
| 2037 | return results; | ||
| 2038 | } | 1983 | } |
| 2039 | 1984 | ||
| 2040 | /** | 1985 | /** |
| @@ -2043,52 +1988,14 @@ export function fuzzySearchTags(searchValue) { | |||
| 2043 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score | 1988 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score |
| 2044 | */ | 1989 | */ |
| 2045 | export function fuzzySearchGroups(searchValue) { | 1990 | export function fuzzySearchGroups(searchValue) { |
| 2046 | const fuseKeys = [ | 1991 | const keys = [ |
| 2047 | { name: 'name', weight: 20 }, | 1992 | { name: 'name', weight: 20 }, |
| 2048 | { name: 'members', weight: 15 }, | 1993 | { name: 'members', weight: 15 }, |
| 2049 | { name: '#tags', weight: 10, getFn: (group) => getTagsList(group.id).map(x => x.name).join('||') }, | 1994 | { name: '#tags', weight: 10, getFn: (group) => getTagsList(group.id).map(x => x.name).join('||') }, |
| 2050 | { name: 'id', weight: 1 }, | 1995 | { name: 'id', weight: 1 }, |
| 2051 | ]; | 1996 | ]; |
| 2052 | 1997 | ||
| 2053 | const currentKeyHash = hashFuseKeys(fuseKeys); | 1998 | return performFuzzySearch(fuzzySearchCategories.groups, groups, keys, searchValue); |
| 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, | ||
| 2071 | includeScore: true, | ||
| 2072 | ignoreLocation: true, | ||
| 2073 | useExtendedSearch: true, | ||
| 2074 | threshold: 0.2, | ||
| 2075 | }); | ||
| 2076 | |||
| 2077 | const results = fuse.search(searchValue); | ||
| 2078 | cache.resultMap.set(searchValue, results); | ||
| 2079 | |||
| 2080 | console.debug('Groups fuzzy search results for ' + searchValue, results); | ||
| 2081 | return results; | ||
| 2082 | } | ||
| 2083 | |||
| 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 | } | 1999 | } |
| 2093 | 2000 | ||
| 2094 | /** | 2001 | /** |