b04c974407
* feat(ui): add popup to jump to a specific swipe Adds a new "Jump to swipe history" button to message actions and makes the swipe counter clickable on the latest message. This opens a searchable popup allowing users to quickly find and jump to a specific alternate swipe without having to click through them sequentially. - Adds a searchable swipe picker popup menu - Makes the swipe counter interactive when multiple swipes exist - Adds a dedicated swipe picker button to message controls * fix(ui): hide swipe picker when there are no swipes Ensures the newly added swipe picker button is only shown when a message has multiple swipes available. It explicitly hides the button for non-swipeable messages or messages with a single swipe. * feat(ui): redesign swipe picker with direct id input Replace text-based search with a numeric input for direct swipe navigation. Update popup layout with a sticky header and improved scrolling behavior. Sync input value with the currently selected swipe in the list. Refactor styling to align with chat selection components. * feat(ui): allow branching from specific swipes via picker - Enable swipe picker for historical messages to inspect alternate swipes - Add branch button to picker entries to create new chats from specific swipes - Update saveChat and createBranch to accept chat snapshots - Restrict swipe jumping to the active message only * refactor(logic): consolidate swipe sync logic and simplify helpers Update `syncSwipeToMes` to accept a target message object, enabling its use in the bookmarks module and removing the duplicate `applySwipeToSnapshot` function. Also simplify `canOpenSwipePickerForMessage` and `canJumpToSwipeForMessage` signatures by removing the redundant message parameter. * refactor(a11y): support dynamic roles via classes Introduce a managed role system in the accessibility script to handle elements that dynamically gain or lose interactive states. The mutation observer now watches for class attribute changes and automatically applies or clears roles (e.g., `role="button"`) using active selectors. Updated the swipe counter to rely on this centralized system by toggling an `.interactable` class instead of manually modifying tabindex and role attributes. Removed the redundant 'Enter' keydown handler for the swipe counter to prevent duplicate trigger events. * fix(ui): compute missing token counts in swipe picker Update renderSwipeList to asynchronously calculate token counts when missing from swipe metadata. Introduce SWIPE_SOURCE.SWIPE_PICKER to correctly identify swipes triggered from the picker and bypass generation checks. * feat(ui): enable deleting specific swipes via swipe picker - Adds a delete button to swipe picker entries, allowing removal of specific message versions. - Refactors deletion logic to handle removing non-current swipes without triggering animations and correctly updates indices. - Includes confirmation dialogs and improves input focus behavior. * refactor:Delete process inline to button click processor * feat: universal swipe inspection and picker improvements - Permit opening the swipe browser on any chat entry to review past generations. - Parallelize the retrieval of token statistics to speed up list rendering. - Format message metrics (length and tokens) into a single, concise string. - Update the `getBranchChatSnapshot` API to accept an options object. - Register swipe list items as interactable elements for keyboard control. - Apply styling to prevent text highlighting on picker entries. * fix:remove unused CSS * fix: fix disabled styling for swipe delete button Remove tooltips and prevent hover animations or glow effects when the delete button is disabled in the swipe picker. Update CSS to enforce default cursor and fixed opacity on hover for the disabled state. * remove: Unused CSS * Extract swipe-picker.js module * Revert to manual ARIA role management * Avoid scrollIntoView and scroll on open * Fix keyboard interaction in past chats menu * Fix a11y attribute * fix: call refreshSwipeButtons when deleting not selected swipe --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>
191 lines
4.8 KiB
JavaScript
191 lines
4.8 KiB
JavaScript
/**
|
|
* Common debounce timeout values to use with `debounce` calls.
|
|
* @readonly
|
|
* @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,
|
|
/** [200 ms] Slightly slower than quick, but still very responsive. */
|
|
short: 200,
|
|
/** [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,
|
|
};
|
|
|
|
/**
|
|
* Used as an ephemeral key in message extra metadata.
|
|
* When set, the message will be excluded from generation
|
|
* prompts without affecting the number of chat messages,
|
|
* which is needed to preserve world info timed effects.
|
|
*/
|
|
export const IGNORE_SYMBOL = Symbol.for('ignore');
|
|
|
|
/**
|
|
* Common video file extensions. Should be the same as supported by Gemini.
|
|
* https://ai.google.dev/gemini-api/docs/video-understanding#supported-formats
|
|
*/
|
|
export const VIDEO_EXTENSIONS = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', '3gp', 'mkv', 'mpg'];
|
|
|
|
/**
|
|
* Known generation triggers that can be passed to Generate function.
|
|
*/
|
|
export const GENERATION_TYPE_TRIGGERS = [
|
|
'normal',
|
|
'continue',
|
|
'impersonate',
|
|
'swipe',
|
|
'regenerate',
|
|
'quiet',
|
|
];
|
|
|
|
/**
|
|
* Known injection IDs and helper functions for system extensions handling.
|
|
*/
|
|
export const inject_ids = {
|
|
STORY_STRING: '__STORY_STRING__',
|
|
QUIET_PROMPT: 'QUIET_PROMPT',
|
|
DEPTH_PROMPT: 'DEPTH_PROMPT',
|
|
DEPTH_PROMPT_INDEX: (index) => `DEPTH_PROMPT_${index}`,
|
|
CUSTOM_WI_DEPTH: 'customDepthWI',
|
|
CUSTOM_WI_DEPTH_ROLE: (depth, role) => `customDepthWI_${depth}_${role}`,
|
|
CUSTOM_WI_OUTLET: (key) => `customWIOutlet_${key}`,
|
|
};
|
|
|
|
export const COMETAPI_IGNORE_PATTERNS = [
|
|
// Image generation models
|
|
'dall-e', 'dalle', 'midjourney', 'mj_', 'stable-diffusion', 'sd-',
|
|
'flux-', 'playground-v', 'ideogram', 'recraft-', 'black-forest-labs',
|
|
'/recraft-v3', 'recraftv3', 'stability-ai/', 'sdxl',
|
|
// Audio generation models
|
|
'suno_', 'tts', 'whisper',
|
|
// Video generation models
|
|
'runway', 'luma_', 'luma-', 'veo', 'kling_', 'minimax_video', 'hunyuan-t1',
|
|
// Utility models
|
|
'embedding', 'search-gpts', 'files_retrieve', 'moderation',
|
|
];
|
|
|
|
/**
|
|
* @readonly
|
|
* @enum {string}
|
|
*/
|
|
export const MEDIA_SOURCE = {
|
|
API: 'api',
|
|
UPLOAD: 'upload',
|
|
GENERATED: 'generated',
|
|
CAPTIONED: 'captioned',
|
|
};
|
|
|
|
/**
|
|
* @readonly
|
|
* @enum {string}
|
|
*/
|
|
export const MEDIA_DISPLAY = {
|
|
LIST: 'list',
|
|
GALLERY: 'gallery',
|
|
};
|
|
|
|
/**
|
|
* @readonly
|
|
* @enum {string}
|
|
*/
|
|
export const IMAGE_OVERSWIPE = {
|
|
GENERATE: 'generate',
|
|
ROLLOVER: 'rollover',
|
|
};
|
|
|
|
/**
|
|
* @readonly
|
|
*/
|
|
export const MEDIA_TYPE = {
|
|
getFromMime: (/** @type {string} */ mimeType) => {
|
|
if (mimeType.startsWith('image/')) {
|
|
return MEDIA_TYPE.IMAGE;
|
|
}
|
|
if (mimeType.startsWith('video/')) {
|
|
return MEDIA_TYPE.VIDEO;
|
|
}
|
|
if (mimeType.startsWith('audio/')) {
|
|
return MEDIA_TYPE.AUDIO;
|
|
}
|
|
return null;
|
|
},
|
|
IMAGE: 'image',
|
|
VIDEO: 'video',
|
|
AUDIO: 'audio',
|
|
};
|
|
|
|
/**
|
|
* Bitwise flag-style media request types.
|
|
* @readonly
|
|
* @enum {number}
|
|
*/
|
|
export const MEDIA_REQUEST_TYPE = {
|
|
IMAGE: 0b001,
|
|
VIDEO: 0b010,
|
|
AUDIO: 0b100,
|
|
};
|
|
|
|
/**
|
|
* Scroll behavior options when appending media to messages.
|
|
* @readonly
|
|
* @enum {string}
|
|
*/
|
|
export const SCROLL_BEHAVIOR = {
|
|
NONE: 'none',
|
|
KEEP: 'keep',
|
|
ADJUST: 'adjust',
|
|
};
|
|
|
|
/**
|
|
* @readonly
|
|
* @enum {string}
|
|
*/
|
|
export const OVERSWIPE_BEHAVIOR = {
|
|
/** The overswipe right chevron will not be displayed. */
|
|
NONE: 'none',
|
|
/** An overswipe will loop to the first swipe. */
|
|
LOOP: 'loop',
|
|
/** Pristine greetings will loop, and chevrons will always be shown: https://github.com/SillyTavern/SillyTavern/pull/4712#issuecomment-3557893373 */
|
|
PRISTINE_GREETING: 'pristine_greeting',
|
|
/** If chat tree is enabled, then an overswipe will allow the user to edit the message before starting a new generation. */
|
|
EDIT_GENERATE: 'edit_generate',
|
|
/** This is the default behavior on character messages. */
|
|
REGENERATE: 'regenerate',
|
|
};
|
|
|
|
/**
|
|
* @readonly
|
|
* @enum {string}
|
|
*/
|
|
export const SWIPE_DIRECTION = {
|
|
LEFT: 'left',
|
|
RIGHT: 'right',
|
|
};
|
|
|
|
/**
|
|
* @readonly
|
|
* @enum {string}
|
|
*/
|
|
export const SWIPE_SOURCE = {
|
|
DELETE: 'delete',
|
|
KEYBOARD: 'keyboard',
|
|
BACK: 'back',
|
|
AUTO_SWIPE: 'auto_swipe',
|
|
SLASH_COMMAND: 'slash_command',
|
|
SWIPE_PICKER: 'swipe_picker',
|
|
};
|
|
|
|
/**
|
|
* @readonly
|
|
* @enum {string}
|
|
*/
|
|
export const SWIPE_STATE = {
|
|
NONE: 'none',
|
|
SWIPING: 'swiping',
|
|
EDITING: 'editing',
|
|
};
|