diff --git a/public/script.js b/public/script.js index 7dc3001e6..517cad511 100644 --- a/public/script.js +++ b/public/script.js @@ -153,6 +153,7 @@ import { isValidUrl, ensureImageFormatSupported, flashHighlight, + debounce_timeout, } from './scripts/utils.js'; import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, loadExtensionSettings, renderExtensionTemplate, renderExtensionTemplateAsync, runGenerationInterceptors, saveMetadataDebounced, writeExtensionField } from './scripts/extensions.js'; @@ -541,7 +542,8 @@ let fav_ch_checked = false; let scrollLock = false; export let abortStatusCheck = new AbortController(); -const durationSaveEdit = 1000; +/** @type {number} The debounce timeout used for chat/settings save. debounce_timeout.long: 1.000 ms */ +const durationSaveEdit = debounce_timeout.relaxed; const saveSettingsDebounced = debounce(() => saveSettings(), durationSaveEdit); export const saveCharacterDebounced = debounce(() => $('#create_button').trigger('click'), durationSaveEdit); @@ -551,7 +553,7 @@ export const saveCharacterDebounced = debounce(() => $('#create_button').trigger * * The printing will also always reprint all filter options of the global list, to keep them up to date. */ -const printCharactersDebounced = debounce(() => { printCharacters(false); }, 100); +const printCharactersDebounced = debounce(() => { printCharacters(false); }, debounce_timeout.quick); /** * @enum {string} System message types @@ -849,7 +851,7 @@ export let active_character = ''; export let active_group = ''; export const entitiesFilter = new FilterHelper(printCharactersDebounced); -export const personasFilter = new FilterHelper(debounce(getUserAvatars, 100)); +export const personasFilter = new FilterHelper(debounce(getUserAvatars, debounce_timeout.quick)); export function getRequestHeaders() { return { @@ -6712,7 +6714,7 @@ export async function displayPastChats() { const debouncedDisplay = debounce((searchQuery) => { displayChats(searchQuery); - }, 300); + }); // Define the search input listener $('#select_chat_search').on('input', function () { diff --git a/public/scripts/PromptManager.js b/public/scripts/PromptManager.js index 91f873c81..152a45177 100644 --- a/public/scripts/PromptManager.js +++ b/public/scripts/PromptManager.js @@ -4,7 +4,7 @@ import { callPopup, event_types, eventSource, is_send_press, main_api, substitut import { is_group_generating } from './group-chats.js'; import { Message, TokenHandler } from './openai.js'; import { power_user } from './power-user.js'; -import { debounce, waitUntilCondition, escapeHtml } from './utils.js'; +import { debounce, waitUntilCondition, escapeHtml, debounce_timeout } from './utils.js'; function debouncePromise(func, delay) { let timeoutId; @@ -294,7 +294,7 @@ class PromptManager { this.handleCharacterReset = () => { }; /** Debounced version of render */ - this.renderDebounced = debounce(this.render.bind(this), 1000); + this.renderDebounced = debounce(this.render.bind(this), debounce_timeout.relaxed); } diff --git a/public/scripts/RossAscends-mods.js b/public/scripts/RossAscends-mods.js index 7c12d5763..90b7b4fc9 100644 --- a/public/scripts/RossAscends-mods.js +++ b/public/scripts/RossAscends-mods.js @@ -32,7 +32,7 @@ import { SECRET_KEYS, secret_state, } from './secrets.js'; -import { debounce, getStringHash, isValidUrl } from './utils.js'; +import { debounce, debounce_timeout, getStringHash, isValidUrl } from './utils.js'; import { chat_completion_sources, oai_settings } from './openai.js'; import { getTokenCountAsync } from './tokenizers.js'; import { textgen_types, textgenerationwebui_settings as textgen_settings, getTextGenServer } from './textgen-settings.js'; @@ -54,7 +54,7 @@ var retry_delay = 500; let counterNonce = Date.now(); const observerConfig = { childList: true, subtree: true }; -const countTokensDebounced = debounce(RA_CountCharTokens, 1000); +const countTokensDebounced = debounce(RA_CountCharTokens, debounce_timeout.relaxed); const observer = new MutationObserver(function (mutations) { mutations.forEach(function (mutation) { diff --git a/public/scripts/authors-note.js b/public/scripts/authors-note.js index fbc249aa2..9e23317b4 100644 --- a/public/scripts/authors-note.js +++ b/public/scripts/authors-note.js @@ -10,7 +10,7 @@ import { import { selected_group } from './group-chats.js'; import { extension_settings, getContext, saveMetadataDebounced } from './extensions.js'; import { registerSlashCommand } from './slash-commands.js'; -import { getCharaFilename, debounce, delay } from './utils.js'; +import { getCharaFilename, debounce, delay, debounce_timeout } from './utils.js'; import { getTokenCountAsync } from './tokenizers.js'; export { MODULE_NAME as NOTE_MODULE_NAME }; @@ -84,9 +84,9 @@ function updateSettings() { setFloatingPrompt(); } -const setMainPromptTokenCounterDebounced = debounce(async (value) => $('#extension_floating_prompt_token_counter').text(await getTokenCountAsync(value)), 1000); -const setCharaPromptTokenCounterDebounced = debounce(async (value) => $('#extension_floating_chara_token_counter').text(await getTokenCountAsync(value)), 1000); -const setDefaultPromptTokenCounterDebounced = debounce(async (value) => $('#extension_floating_default_token_counter').text(await getTokenCountAsync(value)), 1000); +const setMainPromptTokenCounterDebounced = debounce(async (value) => $('#extension_floating_prompt_token_counter').text(await getTokenCountAsync(value)), debounce_timeout.relaxed); +const setCharaPromptTokenCounterDebounced = debounce(async (value) => $('#extension_floating_chara_token_counter').text(await getTokenCountAsync(value)), debounce_timeout.relaxed); +const setDefaultPromptTokenCounterDebounced = debounce(async (value) => $('#extension_floating_default_token_counter').text(await getTokenCountAsync(value)), debounce_timeout.relaxed); async function onExtensionFloatingPromptInput() { chat_metadata[metadata_keys.prompt] = $(this).val(); diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index 1ebc24010..ef179088f 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -3,7 +3,7 @@ import { dragElement, isMobile } from '../../RossAscends-mods.js'; import { getContext, getApiUrl, modules, extension_settings, ModuleWorkerWrapper, doExtrasFetch, renderExtensionTemplateAsync } from '../../extensions.js'; import { loadMovingUIState, power_user } from '../../power-user.js'; import { registerSlashCommand } from '../../slash-commands.js'; -import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence } from '../../utils.js'; +import { onlyUnique, debounce, getCharaFilename, trimToEndSentence, trimToStartSentence, debounce_timeout } from '../../utils.js'; import { hideMutedSprites } from '../../group-chats.js'; import { isJsonSchemaSupported } from '../../textgen-settings.js'; export { MODULE_NAME }; @@ -94,7 +94,7 @@ async function forceUpdateVisualNovelMode() { } } -const updateVisualNovelModeDebounced = debounce(forceUpdateVisualNovelMode, 100); +const updateVisualNovelModeDebounced = debounce(forceUpdateVisualNovelMode, debounce_timeout.quick); async function updateVisualNovelMode(name, expression) { const container = $('#visual-novel-wrapper'); diff --git a/public/scripts/extensions/memory/index.js b/public/scripts/extensions/memory/index.js index cb6bf95d5..87af1f904 100644 --- a/public/scripts/extensions/memory/index.js +++ b/public/scripts/extensions/memory/index.js @@ -1,4 +1,4 @@ -import { getStringHash, debounce, waitUntilCondition, extractAllWords } from '../../utils.js'; +import { getStringHash, debounce, waitUntilCondition, extractAllWords, debounce_timeout } from '../../utils.js'; import { getContext, getApiUrl, extension_settings, doExtrasFetch, modules, renderExtensionTemplateAsync } from '../../extensions.js'; import { activateSendButtons, @@ -46,7 +46,7 @@ const formatMemoryValue = function (value) { } }; -const saveChatDebounced = debounce(() => getContext().saveChat(), 2000); +const saveChatDebounced = debounce(() => getContext().saveChat(), debounce_timeout.relaxed); const summary_sources = { 'extras': 'extras', diff --git a/public/scripts/extensions/token-counter/index.js b/public/scripts/extensions/token-counter/index.js index d9231dac1..1b8f32c61 100644 --- a/public/scripts/extensions/token-counter/index.js +++ b/public/scripts/extensions/token-counter/index.js @@ -2,7 +2,7 @@ import { callPopup, main_api } from '../../../script.js'; import { getContext } from '../../extensions.js'; import { registerSlashCommand } from '../../slash-commands.js'; import { getFriendlyTokenizerName, getTextTokens, getTokenCountAsync, tokenizers } from '../../tokenizers.js'; -import { resetScrollHeight, debounce } from '../../utils.js'; +import { resetScrollHeight, debounce, debounce_timeout } from '../../utils.js'; function rgb2hex(rgb) { rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i); @@ -58,7 +58,7 @@ async function doTokenCounter() { resetScrollHeight($('#token_counter_textarea')); resetScrollHeight($('#token_counter_ids')); - }, 1000); + }, debounce_timeout.relaxed); dialog.find('#token_counter_textarea').on('input', () => countDebounced()); $('#dialogue_popup').addClass('wide_dialogue_popup'); diff --git a/public/scripts/extensions/vectors/index.js b/public/scripts/extensions/vectors/index.js index ca2ddbdeb..6279b83ab 100644 --- a/public/scripts/extensions/vectors/index.js +++ b/public/scripts/extensions/vectors/index.js @@ -22,7 +22,7 @@ import { import { collapseNewlines } from '../../power-user.js'; import { SECRET_KEYS, secret_state, writeSecret } from '../../secrets.js'; import { getDataBankAttachments, getFileAttachment } from '../../chats.js'; -import { debounce, getStringHash as calculateHash, waitUntilCondition, onlyUnique, splitRecursive } from '../../utils.js'; +import { debounce, getStringHash as calculateHash, waitUntilCondition, onlyUnique, splitRecursive, debounce_timeout } from '../../utils.js'; import { getSortedEntries } from '../../world-info.js'; const MODULE_NAME = 'vectors'; @@ -561,7 +561,7 @@ function getPromptText(queriedMessages) { window['vectors_rearrangeChat'] = rearrangeChat; -const onChatEvent = debounce(async () => await moduleWorker.update(), 500); +const onChatEvent = debounce(async () => await moduleWorker.update()); /** * Gets the text to query from the chat diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js index 2396116d8..3556e04fe 100644 --- a/public/scripts/group-chats.js +++ b/public/scripts/group-chats.js @@ -11,6 +11,7 @@ import { getBase64Async, resetScrollHeight, initScrollHeight, + debounce_timeout, } from './utils.js'; import { RA_CountCharTokens, humanizedDateTime, dragElement, favsToHotswap, getMessageTimeStamp } from './RossAscends-mods.js'; import { power_user, loadMovingUIState, sortEntitiesList } from './power-user.js'; @@ -118,9 +119,9 @@ export const group_generation_mode = { const DEFAULT_AUTO_MODE_DELAY = 5; -export const groupCandidatesFilter = new FilterHelper(debounce(printGroupCandidates, 100)); +export const groupCandidatesFilter = new FilterHelper(debounce(printGroupCandidates, debounce_timeout.quick)); let autoModeWorker = null; -const saveGroupDebounced = debounce(async (group, reload) => await _save(group, reload), 500); +const saveGroupDebounced = debounce(async (group, reload) => await _save(group, reload), debounce_timeout.relaxed); function setAutoModeWorker() { clearInterval(autoModeWorker); diff --git a/public/scripts/logprobs.js b/public/scripts/logprobs.js index 3b811a3cb..90050b4d1 100644 --- a/public/scripts/logprobs.js +++ b/public/scripts/logprobs.js @@ -475,7 +475,7 @@ function convertTokenIdLogprobsToText(input) { } export function initLogprobs() { - const debouncedRender = debounce(renderAlternativeTokensView, 500); + const debouncedRender = debounce(renderAlternativeTokensView); $('#logprobsViewerClose').click(onToggleLogprobsPanel); $('#option_toggle_logprobs').click(onToggleLogprobsPanel); eventSource.on(event_types.CHAT_CHANGED, debouncedRender); diff --git a/public/scripts/personas.js b/public/scripts/personas.js index aa2aadb3b..b1673c846 100644 --- a/public/scripts/personas.js +++ b/public/scripts/personas.js @@ -18,7 +18,7 @@ import { } from '../script.js'; import { persona_description_positions, power_user } from './power-user.js'; import { getTokenCountAsync } from './tokenizers.js'; -import { debounce, delay, download, parseJsonFile } from './utils.js'; +import { debounce, debounce_timeout, delay, download, parseJsonFile } from './utils.js'; const GRID_STORAGE_KEY = 'Personas_GridView'; @@ -175,7 +175,7 @@ const countPersonaDescriptionTokens = debounce(async () => { const description = String($('#persona_description').val()); const count = await getTokenCountAsync(description); $('#persona_description_token_count').text(String(count)); -}, 1000); +}, debounce_timeout.relaxed); export function setPersonaDescription() { if (power_user.persona_description_position === persona_description_positions.AFTER_CHAR) { diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 7056638c9..e190c9866 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -325,7 +325,7 @@ const contextControls = [ let browser_has_focus = true; const debug_functions = []; -const setHotswapsDebounced = debounce(favsToHotswap, 500); +const setHotswapsDebounced = debounce(favsToHotswap); export function switchSimpleMode() { $('[data-newbie-hidden]').each(function () { diff --git a/public/scripts/utils.js b/public/scripts/utils.js index fa4fb0e46..53d236ccc 100644 --- a/public/scripts/utils.js +++ b/public/scripts/utils.js @@ -18,6 +18,21 @@ export const navigation_option = { previous: -1000, }; +/** + * Common debounce timeout values to use with `debounce` calls. + * @enum {number} + */ +export const debounce_timeout = { + /** [100 ms] For ultra-fast responses, typically for keypresses or executions that might happen multiple times in a loop or recursion. */ + quick: 100, + /** [300 ms] Default time for general use, good balance between responsiveness and performance. */ + standard: 300, + /** [1.000 ms] For situations where the function triggers more intensive tasks. */ + relaxed: 1000, + /** [5 sec] For delayed tasks, like auto-saving or completing batch operations that need a significant pause. */ + extended: 5000, +} + export function escapeHtml(str) { return String(str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"'); } @@ -256,10 +271,10 @@ export function getStringHash(str, seed = 0) { /** * Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked. * @param {function} func The function to debounce. - * @param {number} [timeout=300] The timeout in milliseconds. + * @param {debounce_timeout|number} [timeout=debounce_timeout.default] The timeout based on the common enum values, or in milliseconds. * @returns {function} The debounced function. */ -export function debounce(func, timeout = 300) { +export function debounce(func, timeout = debounce_timeout.standard) { let timer; return (...args) => { clearTimeout(timer); diff --git a/public/scripts/world-info.js b/public/scripts/world-info.js index 52c0e8455..6590c895f 100644 --- a/public/scripts/world-info.js +++ b/public/scripts/world-info.js @@ -1,5 +1,5 @@ import { saveSettings, callPopup, substituteParams, getRequestHeaders, chat_metadata, this_chid, characters, saveCharacterDebounced, menu_type, eventSource, event_types, getExtensionPromptByName, saveMetadata, getCurrentChatId, extension_prompt_roles } from '../script.js'; -import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight } from './utils.js'; +import { download, debounce, initScrollHeight, resetScrollHeight, parseJsonFile, extractDataFromPng, getFileBuffer, getCharaFilename, getSortableDelay, escapeRegex, PAGINATION_TEMPLATE, navigation_option, waitUntilCondition, isTrueBoolean, setValueByPath, flashHighlight, debounce_timeout } from './utils.js'; import { extension_settings, getContext } from './extensions.js'; import { NOTE_MODULE_NAME, metadata_keys, shouldWIAddPrompt } from './authors-note.js'; import { registerSlashCommand } from './slash-commands.js'; @@ -58,11 +58,11 @@ let world_info_case_sensitive = false; let world_info_match_whole_words = false; let world_info_character_strategy = world_info_insertion_strategy.character_first; let world_info_budget_cap = 0; -const saveWorldDebounced = debounce(async (name, data) => await _save(name, data), 1000); +const saveWorldDebounced = debounce(async (name, data) => await _save(name, data), debounce_timeout.relaxed); const saveSettingsDebounced = debounce(() => { Object.assign(world_info, { globalSelect: selected_world_info }); saveSettings(); -}, 1000); +}, debounce_timeout.relaxed); const sortFn = (a, b) => b.order - a.order; let updateEditor = (navigation) => { console.debug('Triggered WI navigation', navigation); }; @@ -1231,7 +1231,7 @@ function getWorldEntry(name, data, entry) { const countTokensDebounced = debounce(async function (counter, value) { const numberOfTokens = await getTokenCountAsync(value); $(counter).text(numberOfTokens); - }, 1000); + }, debounce_timeout.relaxed); const contentInput = template.find('textarea[name="content"]'); contentInput.data('uid', entry.uid); @@ -3040,7 +3040,7 @@ jQuery(() => { const debouncedWISearch = debounce((searchQuery) => { worldInfoFilter.setFilterData(FILTER_TYPES.WORLD_INFO_SEARCH, searchQuery); - }, 300); + }); $('#world_info_search').on('input', function () { const searchQuery = $(this).val(); debouncedWISearch(searchQuery);