From c3f988f246c80f80247941564f24ff787c6c3f00 Mon Sep 17 00:00:00 2001 From: Meus Artis <4709458+Meus-Artis@users.noreply.github.com> Date: Tue, 3 Dec 2024 01:09:41 -0500 Subject: [PATCH 01/29] Update users-public.js Better/more detailed console output for multi-user installs --- src/endpoints/users-public.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/endpoints/users-public.js b/src/endpoints/users-public.js index 5e6b60941..3d86fc619 100644 --- a/src/endpoints/users-public.js +++ b/src/endpoints/users-public.js @@ -67,17 +67,17 @@ router.post('/login', jsonParser, async (request, response) => { const user = await storage.getItem(toKey(request.body.handle)); if (!user) { - console.log('Login failed: User not found'); + console.log('Login failed: User', request.body.handle, 'not found'); return response.status(403).json({ error: 'Incorrect credentials' }); } if (!user.enabled) { - console.log('Login failed: User is disabled'); + console.log('Login failed: User', user.handle, 'is disabled'); return response.status(403).json({ error: 'User is disabled' }); } if (user.password && user.password !== getPasswordHash(request.body.password, user.salt)) { - console.log('Login failed: Incorrect password'); + console.log('Login failed: Incorrect password for', user.handle); return response.status(403).json({ error: 'Incorrect credentials' }); } @@ -88,7 +88,7 @@ router.post('/login', jsonParser, async (request, response) => { await loginLimiter.delete(ip); request.session.handle = user.handle; - console.log('Login successful:', user.handle, request.session); + console.log('Login successful:', user.handle, 'from', ip, 'at', request.session.touch); return response.json({ handle: user.handle }); } catch (error) { if (error instanceof RateLimiterRes) { @@ -115,12 +115,12 @@ router.post('/recover-step1', jsonParser, async (request, response) => { const user = await storage.getItem(toKey(request.body.handle)); if (!user) { - console.log('Recover step 1 failed: User not found'); + console.log('Recover step 1 failed: User', request.body.handle, 'not found'); return response.status(404).json({ error: 'User not found' }); } if (!user.enabled) { - console.log('Recover step 1 failed: User is disabled'); + console.log('Recover step 1 failed: User', user.handle, 'is disabled'); return response.status(403).json({ error: 'User is disabled' }); } @@ -153,12 +153,12 @@ router.post('/recover-step2', jsonParser, async (request, response) => { const ip = getIpFromRequest(request); if (!user) { - console.log('Recover step 2 failed: User not found'); + console.log('Recover step 2 failed: User', request.body.handle, 'not found'); return response.status(404).json({ error: 'User not found' }); } if (!user.enabled) { - console.log('Recover step 2 failed: User is disabled'); + console.log('Recover step 2 failed: User', user.handle, 'is disabled'); return response.status(403).json({ error: 'User is disabled' }); } From 4466da63bc27b0b7cb704e1bae978c9b208b1352 Mon Sep 17 00:00:00 2001 From: Meus Artis <4709458+Meus-Artis@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:56:40 -0500 Subject: [PATCH 02/29] Update users-public.js Replace session touch timestamp with Date() --- src/endpoints/users-public.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/endpoints/users-public.js b/src/endpoints/users-public.js index 3d86fc619..aa11199e0 100644 --- a/src/endpoints/users-public.js +++ b/src/endpoints/users-public.js @@ -88,7 +88,7 @@ router.post('/login', jsonParser, async (request, response) => { await loginLimiter.delete(ip); request.session.handle = user.handle; - console.log('Login successful:', user.handle, 'from', ip, 'at', request.session.touch); + console.log('Login successful:', user.handle, 'from', ip, 'at', Date().toLocaleString()); return response.json({ handle: user.handle }); } catch (error) { if (error instanceof RateLimiterRes) { From 41a3035a2ab31987ff2d76b3e97d20fa9d1aa1b6 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Wed, 4 Dec 2024 15:22:53 +0000 Subject: [PATCH 03/29] Use filter order in group candidates list --- public/script.js | 4 ++-- public/scripts/group-chats.js | 11 ++++++----- public/scripts/power-user.js | 6 +++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/public/script.js b/public/script.js index 5205a27cd..f803ac4f8 100644 --- a/public/script.js +++ b/public/script.js @@ -1637,7 +1637,7 @@ export function getEntitiesList({ doFilter = false, doSort = true } = {}) { subEntities = entitiesFilter.applyFilters(subEntities, { clearScoreCache: false, tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED }, clearFuzzySearchCaches: false }); } if (doSort) { - sortEntitiesList(subEntities); + sortEntitiesList(subEntities, false); } entity.entities = subEntities; entity.hidden = subCount - subEntities.length; @@ -1665,7 +1665,7 @@ export function getEntitiesList({ doFilter = false, doSort = true } = {}) { // Sort before returning if requested if (doSort) { - sortEntitiesList(entities); + sortEntitiesList(entities, false); } entitiesFilter.clearFuzzySearchCaches(); return entities; diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js index 0195b1d8d..0e106c3ea 100644 --- a/public/scripts/group-chats.js +++ b/public/scripts/group-chats.js @@ -1267,14 +1267,15 @@ function getGroupCharacters({ doFilter, onlyMembers } = {}) { .filter((x) => isGroupMember(thisGroup, x.avatar) == onlyMembers) .map((x, index) => ({ item: x, id: index, type: 'character' })); + if (doFilter) { + candidates = groupCandidatesFilter.applyFilters(candidates); + } + if (onlyMembers) { candidates.sort(sortMembersFn); } else { - sortEntitiesList(candidates); - } - - if (doFilter) { - candidates = groupCandidatesFilter.applyFilters(candidates); + const useFilterOrder = doFilter && !!$('#rm_group_filter').val(); + sortEntitiesList(candidates, useFilterOrder); } return candidates; diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index 504d53b13..e27a90fbc 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -60,7 +60,6 @@ export { loadMovingUIState, collapseNewlines, playMessageSound, - sortEntitiesList, fixMarkdown, power_user, send_on_enter_options, @@ -2080,8 +2079,9 @@ const compareFunc = (first, second) => { /** * Sorts an array of entities based on the current sort settings * @param {any[]} entities An array of objects with an `item` property + * @param {boolean} forceSearch Whether to force search sorting */ -function sortEntitiesList(entities) { +export function sortEntitiesList(entities, forceSearch) { if (power_user.sort_field == undefined || entities.length === 0) { return; } @@ -2091,7 +2091,7 @@ function sortEntitiesList(entities) { return; } - const isSearch = $('#character_sort_order option[data-field="search"]').is(':selected'); + const isSearch = forceSearch || $('#character_sort_order option[data-field="search"]').is(':selected'); entities.sort((a, b) => { // Sort tags/folders will always be at the top From 3d8f8d90c3b57bff817445c5d679d677a8476974 Mon Sep 17 00:00:00 2001 From: IceFog72 <164350516+IceFog72@users.noreply.github.com> Date: Thu, 5 Dec 2024 03:23:11 +0200 Subject: [PATCH 04/29] Update stable-diffusion/style.css #sd_dropdown backdrop-filter fix --- public/scripts/extensions/stable-diffusion/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/extensions/stable-diffusion/style.css b/public/scripts/extensions/stable-diffusion/style.css index d4bff383d..ef9507cc2 100644 --- a/public/scripts/extensions/stable-diffusion/style.css +++ b/public/scripts/extensions/stable-diffusion/style.css @@ -4,7 +4,7 @@ #sd_dropdown { z-index: 30000; - backdrop-filter: blur(--SmartThemeBlurStrength); + backdrop-filter: blur(calc(var(--SmartThemeBlurStrength))); } #sd_comfy_open_workflow_editor { From 960db2d59bcf64bb2b1b0e980476333be539a920 Mon Sep 17 00:00:00 2001 From: IceFog72 <164350516+IceFog72@users.noreply.github.com> Date: Thu, 5 Dec 2024 03:25:13 +0200 Subject: [PATCH 05/29] Update tts/style.css .at-settings-separator padding fix --- public/scripts/extensions/tts/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/extensions/tts/style.css b/public/scripts/extensions/tts/style.css index 960467c06..4d379a798 100644 --- a/public/scripts/extensions/tts/style.css +++ b/public/scripts/extensions/tts/style.css @@ -93,7 +93,7 @@ .at-settings-separator { margin-top: 10px; margin-bottom: 10px; - padding: 18x; + padding: 18px; font-weight: bold; border-top: 1px solid #e1e1e1; /* Grey line */ border-bottom: 1px solid #e1e1e1; /* Grey line */ From 373a0ad3211e30903668a49f7d49e6422200c59f Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:59:03 +0000 Subject: [PATCH 06/29] Add config.yaml value for cards cache capacity. --- default/config.yaml | 2 ++ src/endpoints/characters.js | 7 ++++--- src/util.js | 5 +++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/default/config.yaml b/default/config.yaml index 6f174e523..730ffa967 100644 --- a/default/config.yaml +++ b/default/config.yaml @@ -1,6 +1,8 @@ # -- DATA CONFIGURATION -- # Root directory for user data storage dataRoot: ./data +# The maximum amount of memory that parsed character cards can use in MB +cardsCacheCapacity: 100 # -- SERVER CONFIGURATION -- # Listen for incoming connections listen: false diff --git a/src/endpoints/characters.js b/src/endpoints/characters.js index b3be9d6f4..9c117cb31 100644 --- a/src/endpoints/characters.js +++ b/src/endpoints/characters.js @@ -14,7 +14,7 @@ import jimp from 'jimp'; import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js'; import { jsonParser, urlencodedParser } from '../express-common.js'; -import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap } from '../util.js'; +import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap, getConfigValue } from '../util.js'; import { TavernCardValidator } from '../validator/TavernCardValidator.js'; import { parse, write } from '../character-card-parser.js'; import { readWorldInfoFile } from './worldinfo.js'; @@ -23,8 +23,9 @@ import { importRisuSprites } from './sprites.js'; const defaultAvatarPath = './public/img/ai4.png'; // KV-store for parsed character data -// 100 MB limit. Would take roughly 3000 characters to reach this limit -const characterDataCache = new MemoryLimitedMap(1024 * 1024 * 100); +const cacheCapacity = Number(getConfigValue('cardsCacheCapacity', 100)); // MB +// With 100 MB limit it would take roughly 3000 characters to reach this limit +const characterDataCache = new MemoryLimitedMap(1024 * 1024 * cacheCapacity); // Some Android devices require tighter memory management const isAndroid = process.platform === 'android'; diff --git a/src/util.js b/src/util.js index 623626d3d..7b8445453 100644 --- a/src/util.js +++ b/src/util.js @@ -680,8 +680,9 @@ export class MemoryLimitedMap { * @param {number} maxMemoryInBytes - The maximum allowed memory in bytes for string values. */ constructor(maxMemoryInBytes) { - if (typeof maxMemoryInBytes !== 'number' || maxMemoryInBytes <= 0) { - throw new Error('maxMemoryInBytes must be a positive number'); + if (typeof maxMemoryInBytes !== 'number' || maxMemoryInBytes <= 0 || isNaN(maxMemoryInBytes)) { + console.warn('Invalid maxMemoryInBytes, using a fallback value of 1 GB.'); + maxMemoryInBytes = 1024 * 1024 * 1024; // 1 GB } this.maxMemory = maxMemoryInBytes; this.currentMemory = 0; From 23a10fdc227954128ccf1da74ad723b92dcab752 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:32:30 +0000 Subject: [PATCH 07/29] Optimize past swipe counters performance --- public/index.html | 2 +- public/script.js | 11 +++++------ public/scripts/power-user.js | 4 ++-- public/style.css | 10 ++++++++++ 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/public/index.html b/public/index.html index d8296c1fb..32723dd05 100644 --- a/public/index.html +++ b/public/index.html @@ -4183,7 +4183,7 @@ - Swipe # for All Messages + Swipe # for All Messages diff --git a/public/script.js b/public/script.js index f803ac4f8..c7744984e 100644 --- a/public/script.js +++ b/public/script.js @@ -98,7 +98,6 @@ import { resetMovableStyles, forceCharacterEditorTokenize, applyPowerUserSettings, - switchSwipeNumAllMessages, } from './scripts/power-user.js'; import { @@ -7660,14 +7659,12 @@ export function showSwipeButtons() { //allows for writing individual swipe counters for past messages const lastSwipeCounter = $('.last_mes .swipes-counter'); lastSwipeCounter.text(swipeCounterText).show(); - - switchSwipeNumAllMessages(); } export function hideSwipeButtons() { - $('#chat').find('.swipe_right').hide(); - $('#chat').find('.last_mes .swipes-counter').hide(); - $('#chat').find('.swipe_left').hide(); + chatElement.find('.swipe_right').hide(); + chatElement.find('.last_mes .swipes-counter').hide(); + chatElement.find('.swipe_left').hide(); } /** @@ -8538,6 +8535,8 @@ const swipe_right = () => { } if (run_generate) { //hide swipe arrows while generating this_div.css('display', 'none'); + const swipesCounter = currentMessage.find('.swipes-counter'); + swipesCounter.hide(); } // handles animated transitions when swipe right, specifically height transitions between messages if (run_generate || run_swipe_right) { diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index e27a90fbc..a2ee59e15 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -472,9 +472,9 @@ function switchCompactInputArea() { $('#compact_input_area').prop('checked', power_user.compact_input_area); } -export function switchSwipeNumAllMessages() { +function switchSwipeNumAllMessages() { $('#show_swipe_num_all_messages').prop('checked', power_user.show_swipe_num_all_messages); - $('.mes:not(.last_mes) .swipes-counter').css('opacity', '').toggle(power_user.show_swipe_num_all_messages); + $('body').toggleClass('swipeAllMessages', !!power_user.show_swipe_num_all_messages); } var originalSliderValues = []; diff --git a/public/style.css b/public/style.css index 69ff17b49..b147f9c87 100644 --- a/public/style.css +++ b/public/style.css @@ -1044,6 +1044,16 @@ body .panelControlBar { opacity: 0.3; } +body:not(.swipeAllMessages) .mes:not(.last_mes) .swipes-counter { + display: none; +} + +body.swipeAllMessages .mes:not(.last_mes) .swipes-counter { + /* Avoid expensive DOM queries */ + opacity: 0.3 !important; + display: flex !important; +} + .swipe_left { right: auto; left: 20px; From 3dd1e25a3bece79544caf2a376ed96b47c5a1fbe Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 5 Dec 2024 15:56:17 +0000 Subject: [PATCH 08/29] Hide past swipes with opacity --- public/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/style.css b/public/style.css index b147f9c87..4444d0080 100644 --- a/public/style.css +++ b/public/style.css @@ -1045,7 +1045,7 @@ body .panelControlBar { } body:not(.swipeAllMessages) .mes:not(.last_mes) .swipes-counter { - display: none; + opacity: 0; } body.swipeAllMessages .mes:not(.last_mes) .swipes-counter { From 63f9f33e204f3c63f6562c78da20990d1340dc27 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 5 Dec 2024 18:50:20 +0200 Subject: [PATCH 09/29] calc() is not needed --- public/scripts/extensions/stable-diffusion/style.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/extensions/stable-diffusion/style.css b/public/scripts/extensions/stable-diffusion/style.css index ef9507cc2..e0053f740 100644 --- a/public/scripts/extensions/stable-diffusion/style.css +++ b/public/scripts/extensions/stable-diffusion/style.css @@ -4,7 +4,7 @@ #sd_dropdown { z-index: 30000; - backdrop-filter: blur(calc(var(--SmartThemeBlurStrength))); + backdrop-filter: blur(var(--SmartThemeBlurStrength)); } #sd_comfy_open_workflow_editor { From e55748fe92aed43ab441130cb1bd4ab49a51c767 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 5 Dec 2024 18:55:17 +0200 Subject: [PATCH 10/29] Fix Date constructor call --- src/endpoints/users-public.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/endpoints/users-public.js b/src/endpoints/users-public.js index aa11199e0..4603be488 100644 --- a/src/endpoints/users-public.js +++ b/src/endpoints/users-public.js @@ -88,7 +88,7 @@ router.post('/login', jsonParser, async (request, response) => { await loginLimiter.delete(ip); request.session.handle = user.handle; - console.log('Login successful:', user.handle, 'from', ip, 'at', Date().toLocaleString()); + console.log('Login successful:', user.handle, 'from', ip, 'at', new Date().toLocaleString()); return response.json({ handle: user.handle }); } catch (error) { if (error instanceof RateLimiterRes) { From 4cf5d1535e72befb6509b77dd1d838f34d438dff Mon Sep 17 00:00:00 2001 From: Succubyss <87207237+Succubyss@users.noreply.github.com> Date: Thu, 5 Dec 2024 12:38:21 -0600 Subject: [PATCH 11/29] add /getpromptentry command --- public/scripts/slash-commands.js | 112 +++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index a36cdce2e..61fad2f0a 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -1698,6 +1698,49 @@ export function initDefaultSlashCommands() { ], helpString: 'Sets the model for the current API. Gets the current model name if no argument is provided.', })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'getpromptentry', + aliases: ['getpromptentries'], + callback: getPromptEntryCallback, + returns: 'true/false state of prompt(s)', + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'identifier', + description: 'Prompt entry identifier(s) to retrieve', + typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], + acceptsMultiple: true, + enumProvider: () => + promptManager.serviceSettings.prompts + .map(prompt => prompt.identifier) + .map(identifier => new SlashCommandEnumValue(identifier, identifier)), + }), + SlashCommandNamedArgument.fromProps({ + name: 'name', + description: 'Prompt entry name(s) to retrieve', + typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], + acceptsMultiple: true, + enumProvider: () => + promptManager.serviceSettings.prompts + .map(prompt => prompt.name) + .map(name => new SlashCommandEnumValue(name, name)), + }), + SlashCommandNamedArgument.fromProps({ + name: 'return', + description: 'Whether the return will be simple, a list, or a dict.', + typeList: [ARGUMENT_TYPE.STRING], + defaultValue: 'simple', + enumList: ['simple', 'list', 'dict'], + }), + ], + helpString: ` + + Gets the state of the specified prompt entries. + + + If return is simple (default) then the return will be a single value if only one value was retrieved; otherwise uses a dict (if the identifier parameter was used) or a list. + + `, + })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'setpromptentry', aliases: ['setpromptentries'], @@ -3786,6 +3829,75 @@ function modelCallback(args, model) { } } +/** + * Gets the state of prompt entries (toggles) either via identifier/uuid or name. + * @param {object} args Object containing arguments + * @param {string} args.identifier Select prompt entry using an identifier (uuid) + * @param {string} args.name Select prompt entry using name + * @returns {Object} An object containing the states of the requested prompt entries + */ +function getPromptEntryCallback(args) { + const promptManager = setupChatCompletionPromptManager(oai_settings); + const prompts = promptManager.serviceSettings.prompts; + let returnType = args.return ?? 'simple'; + + function parseArgs(arg) { + // Arg is already an array + if (Array.isArray(arg)) { + return arg; + } + const list = []; + try { + // Arg is a JSON-stringified array + const parsedArg = JSON.parse(arg); + list.push(...Array.isArray(parsedArg) ? parsedArg : [arg]); + } catch { + // Arg is a string + list.push(arg); + } + return list; + } + + let identifiersList = parseArgs(args.identifier); + let nameList = parseArgs(args.name); + + // Check if identifiers exists in prompt, else remove from list + if (identifiersList.length !== 0) { + identifiersList = identifiersList.filter(identifier => prompts.some(prompt => prompt.identifier === identifier)); + } + + if (nameList.length !== 0) { + nameList.forEach(name => { + let identifiers = prompts + .filter(entry => entry.name === name) + .map(entry => entry.identifier); + identifiersList = identifiersList.concat(identifiers); + }); + } + + // Get the state for each prompt entry + let promptStates = new Map(); + identifiersList.forEach(identifier => { + const promptOrderEntry = promptManager.getPromptOrderEntry(promptManager.activeCharacter, identifier); + if (promptOrderEntry) { + promptStates.set(identifier, promptOrderEntry.enabled); + } + }); + + // If return is simple (default) but more than one prompt state was retrieved, then change return type + if (returnType === 'simple' && promptStates.size > 1) { + returnType = args.identifier ? 'dict' : 'list'; + } + + const result = (() => { + if (returnType === 'list') return [...promptStates.values()]; + if (returnType === 'dict') return Object.fromEntries(promptStates); + return [...promptStates.values()][0]; + })(); + + return result; +} + /** * Sets state of prompt entries (toggles) either via identifier/uuid or name. * @param {object} args Object containing arguments From 7dfba69fc1804f3650d3285f85288fd06292b0a3 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 5 Dec 2024 22:06:16 +0200 Subject: [PATCH 12/29] Import promptManager from openai.js --- public/scripts/openai.js | 4 ++-- public/scripts/slash-commands.js | 11 ++++------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/public/scripts/openai.js b/public/scripts/openai.js index e4ba08ae0..1f5b4d8f9 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -379,8 +379,8 @@ export let selected_proxy = proxies[0]; let openai_setting_names; let openai_settings; - -let promptManager = null; +/** @type {import('./PromptManager.js').PromptManager} */ +export let promptManager = null; async function validateReverseProxy() { if (!oai_settings.reverse_proxy) { diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 61fad2f0a..23a36828f 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -52,7 +52,7 @@ import { hideChatMessageRange } from './chats.js'; import { getContext, saveMetadataDebounced } from './extensions.js'; import { getRegexedString, regex_placement } from './extensions/regex/engine.js'; import { findGroupMemberId, groups, is_group_generating, openGroupById, resetSelectedGroup, saveGroupChat, selected_group } from './group-chats.js'; -import { chat_completion_sources, oai_settings, setupChatCompletionPromptManager } from './openai.js'; +import { chat_completion_sources, oai_settings, promptManager } from './openai.js'; import { autoSelectPersona, retriggerFirstMessageOnEmptyChat, setPersonaLockState, togglePersonaLock, user_avatar } from './personas.js'; import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js'; import { SERVER_INPUTS, textgen_types, textgenerationwebui_settings } from './textgen-settings.js'; @@ -1712,7 +1712,7 @@ export function initDefaultSlashCommands() { enumProvider: () => promptManager.serviceSettings.prompts .map(prompt => prompt.identifier) - .map(identifier => new SlashCommandEnumValue(identifier, identifier)), + .map(identifier => new SlashCommandEnumValue(identifier)), }), SlashCommandNamedArgument.fromProps({ name: 'name', @@ -1722,7 +1722,7 @@ export function initDefaultSlashCommands() { enumProvider: () => promptManager.serviceSettings.prompts .map(prompt => prompt.name) - .map(name => new SlashCommandEnumValue(name, name)), + .map(name => new SlashCommandEnumValue(name)), }), SlashCommandNamedArgument.fromProps({ name: 'return', @@ -1752,7 +1752,6 @@ export function initDefaultSlashCommands() { typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], acceptsMultiple: true, enumProvider: () => { - const promptManager = setupChatCompletionPromptManager(oai_settings); const prompts = promptManager.serviceSettings.prompts; return prompts.map(prompt => new SlashCommandEnumValue(prompt.identifier, prompt.name, enumTypes.enum)); }, @@ -1763,7 +1762,6 @@ export function initDefaultSlashCommands() { typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], acceptsMultiple: true, enumProvider: () => { - const promptManager = setupChatCompletionPromptManager(oai_settings); const prompts = promptManager.serviceSettings.prompts; return prompts.map(prompt => new SlashCommandEnumValue(prompt.name, prompt.identifier, enumTypes.enum)); }, @@ -3834,10 +3832,10 @@ function modelCallback(args, model) { * @param {object} args Object containing arguments * @param {string} args.identifier Select prompt entry using an identifier (uuid) * @param {string} args.name Select prompt entry using name + * @param {string} args.return The type of return value to use (simple, list, dict) * @returns {Object} An object containing the states of the requested prompt entries */ function getPromptEntryCallback(args) { - const promptManager = setupChatCompletionPromptManager(oai_settings); const prompts = promptManager.serviceSettings.prompts; let returnType = args.return ?? 'simple'; @@ -3908,7 +3906,6 @@ function getPromptEntryCallback(args) { */ function setPromptEntryCallback(args, targetState) { // needs promptManager to manipulate prompt entries - const promptManager = setupChatCompletionPromptManager(oai_settings); const prompts = promptManager.serviceSettings.prompts; function parseArgs(arg) { From 3502bfcaa0aed1c00150f45e21e41e885241caa6 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 5 Dec 2024 22:57:02 +0200 Subject: [PATCH 13/29] Add {{groupNotMuted}} --- public/script.js | 10 +++++++--- public/scripts/templates/macros.html | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/public/script.js b/public/script.js index f803ac4f8..5ebc7592e 100644 --- a/public/script.js +++ b/public/script.js @@ -2607,15 +2607,18 @@ export function substituteParams(content, _name1, _name2, _original, _group, _re }; } - const getGroupValue = () => { + const getGroupValue = (includeMuted) => { if (typeof _group === 'string') { return _group; } if (selected_group) { const members = groups.find(x => x.id === selected_group)?.members; + /** @type {string[]} */ + const disabledMembers = groups.find(x => x.id === selected_group)?.disabled_members ?? []; + const isMuted = x => includeMuted ? true : !disabledMembers.includes(x); const names = Array.isArray(members) - ? members.map(m => characters.find(c => c.avatar === m)?.name).filter(Boolean).join(', ') + ? members.filter(isMuted).map(m => characters.find(c => c.avatar === m)?.name).filter(Boolean).join(', ') : ''; return names; } else { @@ -2639,7 +2642,8 @@ export function substituteParams(content, _name1, _name2, _original, _group, _re // Must be substituted last so that they're replaced inside {{description}} environment.user = _name1 ?? name1; environment.char = _name2 ?? name2; - environment.group = environment.charIfNotGroup = getGroupValue(); + environment.group = environment.charIfNotGroup = getGroupValue(true); + environment.groupNotMuted = getGroupValue(false); environment.model = getGeneratingModel(); if (additionalMacro && typeof additionalMacro === 'object') { diff --git a/public/scripts/templates/macros.html b/public/scripts/templates/macros.html index 38f6dec0c..84a163c4e 100644 --- a/public/scripts/templates/macros.html +++ b/public/scripts/templates/macros.html @@ -21,7 +21,8 @@ {{user}} – your current Persona username {{char}} – the Character's name {{char_version}} – the Character's version number - {{group}} – a comma-separated list of group member names or the character name in solo chats. Alias: {{charIfNotGroup}} + {{group}} – a comma-separated list of group member names (including muted) or the character name in solo chats. Alias: {{charIfNotGroup}} + {{groupNotMuted}} – the same as {{group}}, but excludes muted members {{model}} – a text generation model name for the currently selected API. Can be inaccurate! {{lastMessage}} – the text of the latest chat message. {{lastUserMessage}} – the text of the latest user chat message. From 77841dbc2169003bc78970958dc9c68fe55a1a08 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 16:41:26 +0200 Subject: [PATCH 14/29] Add types for SillyTavern.getContext --- .eslintrc.cjs | 1 + public/global.d.ts | 3 +- public/script.js | 151 +++++-------------------- public/scripts/extensions.js | 2 +- public/scripts/st-context.js | 170 +++++++++++++++++++++++++++++ public/scripts/textgen-settings.js | 17 ++- public/scripts/tokenizers.js | 30 +++-- 7 files changed, 228 insertions(+), 146 deletions(-) create mode 100644 public/scripts/st-context.js diff --git a/.eslintrc.cjs b/.eslintrc.cjs index f0b2085d6..42978485c 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -54,6 +54,7 @@ module.exports = { }, // These scripts are loaded in HTML; tell ESLint not to complain about them being undefined globals: { + globalThis: 'readonly', ePub: 'readonly', pdfjsLib: 'readonly', toastr: 'readonly', diff --git a/public/global.d.ts b/public/global.d.ts index cb459a97b..202d48443 100644 --- a/public/global.d.ts +++ b/public/global.d.ts @@ -1,4 +1,5 @@ import libs from './lib'; +import getContext from './scripts/st-context'; // Global namespace modules declare var ai; @@ -6,7 +7,7 @@ declare var pdfjsLib; declare var ePub; declare var SillyTavern: { - getContext(): any; + getContext(): typeof getContext; llm: any; libs: typeof libs; }; diff --git a/public/script.js b/public/script.js index 5ebc7592e..9f948c2a2 100644 --- a/public/script.js +++ b/public/script.js @@ -13,7 +13,7 @@ import { default as libs, } from './lib.js'; -import { humanizedDateTime, favsToHotswap, getMessageTimeStamp, dragElement, isMobile, initRossMods, shouldSendOnEnter } from './scripts/RossAscends-mods.js'; +import { humanizedDateTime, favsToHotswap, getMessageTimeStamp, dragElement, isMobile, initRossMods } from './scripts/RossAscends-mods.js'; import { userStatsHandler, statMesProcess, initStats } from './scripts/stats.js'; import { generateKoboldWithStreaming, @@ -37,8 +37,6 @@ import { parseTabbyLogprobs, } from './scripts/textgen-settings.js'; -const { MANCER, TOGETHERAI, OOBA, VLLM, APHRODITE, TABBY, OLLAMA, INFERMATICAI, DREAMGEN, OPENROUTER, FEATHERLESS } = textgen_types; - import { world_info, getWorldInfoPrompt, @@ -67,9 +65,7 @@ import { getGroupChat, renameGroupMember, createNewGroupChat, - getGroupPastChats, getGroupAvatar, - openGroupChat, editGroup, deleteGroupChat, renameGroupChat, @@ -174,8 +170,8 @@ import { } from './scripts/utils.js'; import { debounce_timeout } from './scripts/constants.js'; -import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, initExtensions, loadExtensionSettings, renderExtensionTemplate, renderExtensionTemplateAsync, runGenerationInterceptors, saveMetadataDebounced, writeExtensionField } from './scripts/extensions.js'; -import { COMMENT_NAME_DEFAULT, executeSlashCommands, executeSlashCommandsOnChatInput, executeSlashCommandsWithOptions, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, registerSlashCommand, stopScriptExecution } from './scripts/slash-commands.js'; +import { doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js'; +import { COMMENT_NAME_DEFAULT, executeSlashCommandsOnChatInput, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, stopScriptExecution } from './scripts/slash-commands.js'; import { tag_map, tags, @@ -242,11 +238,11 @@ import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels } from './scripts/textgen-models.js'; import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js'; import { getPresetManager, initPresetManager } from './scripts/preset-manager.js'; -import { MacrosParser, evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js'; +import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js'; import { currentUser, setUserControls } from './scripts/user.js'; import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js'; import { renderTemplate, renderTemplateAsync } from './scripts/templates.js'; -import { initScrapers, ScraperManager } from './scripts/scrapers.js'; +import { initScrapers } from './scripts/scrapers.js'; import { SlashCommandParser } from './scripts/slash-commands/SlashCommandParser.js'; import { SlashCommand } from './scripts/slash-commands/SlashCommand.js'; import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './scripts/slash-commands/SlashCommandArgument.js'; @@ -268,6 +264,13 @@ 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 { getContext } from './scripts/st-context.js'; + +// API OBJECT FOR EXTERNAL WIRING +globalThis.SillyTavern = { + libs, + getContext, +}; //exporting functions and vars for mods export { @@ -427,10 +430,6 @@ DOMPurify.addHook('uponSanitizeElement', (node, _, config) => { } }); -// API OBJECT FOR EXTERNAL WIRING -window['SillyTavern'] = {}; -window['SillyTavern'].libs = libs; - // Event source init export const event_types = { APP_READY: 'app_ready', @@ -812,7 +811,7 @@ export let menu_type = ''; export let selected_button = ''; //which button pressed //create pole save -let create_save = { +export let create_save = { name: '', description: '', creator_notes: '', @@ -864,7 +863,7 @@ export let amount_gen = 80; //default max length of AI generated responses export let max_context = 2048; var swipes = true; -let extension_prompts = {}; +export let extension_prompts = {}; export let main_api;// = "kobold"; //novel settings @@ -1175,7 +1174,7 @@ async function getStatusTextgen() { return resultCheckStatus(); } - if (textgen_settings.type == OOBA && textgen_settings.bypass_status_check) { + if (textgen_settings.type == textgen_types.OOBA && textgen_settings.bypass_status_check) { setOnlineStatus('Status check bypassed'); return resultCheckStatus(); } @@ -1193,34 +1192,34 @@ async function getStatusTextgen() { const data = await response.json(); - if (textgen_settings.type === MANCER) { + if (textgen_settings.type === textgen_types.MANCER) { loadMancerModels(data?.data); setOnlineStatus(textgen_settings.mancer_model); - } else if (textgen_settings.type === TOGETHERAI) { + } else if (textgen_settings.type === textgen_types.TOGETHERAI) { loadTogetherAIModels(data?.data); setOnlineStatus(textgen_settings.togetherai_model); - } else if (textgen_settings.type === OLLAMA) { + } else if (textgen_settings.type === textgen_types.OLLAMA) { loadOllamaModels(data?.data); setOnlineStatus(textgen_settings.ollama_model || 'Connected'); - } else if (textgen_settings.type === INFERMATICAI) { + } else if (textgen_settings.type === textgen_types.INFERMATICAI) { loadInfermaticAIModels(data?.data); setOnlineStatus(textgen_settings.infermaticai_model); - } else if (textgen_settings.type === DREAMGEN) { + } else if (textgen_settings.type === textgen_types.DREAMGEN) { loadDreamGenModels(data?.data); setOnlineStatus(textgen_settings.dreamgen_model); - } else if (textgen_settings.type === OPENROUTER) { + } else if (textgen_settings.type === textgen_types.OPENROUTER) { loadOpenRouterModels(data?.data); setOnlineStatus(textgen_settings.openrouter_model); - } else if (textgen_settings.type === VLLM) { + } else if (textgen_settings.type === textgen_types.VLLM) { loadVllmModels(data?.data); setOnlineStatus(textgen_settings.vllm_model); - } else if (textgen_settings.type === APHRODITE) { + } else if (textgen_settings.type === textgen_types.APHRODITE) { loadAphroditeModels(data?.data); setOnlineStatus(textgen_settings.aphrodite_model); - } else if (textgen_settings.type === FEATHERLESS) { + } else if (textgen_settings.type === textgen_types.FEATHERLESS) { loadFeatherlessModels(data?.data); setOnlineStatus(textgen_settings.featherless_model); - } else if (textgen_settings.type === TABBY) { + } else if (textgen_settings.type === textgen_types.TABBY) { loadTabbyModels(data?.data); setOnlineStatus(textgen_settings.tabby_model || data?.result); } else { @@ -5542,7 +5541,7 @@ function extractMultiSwipes(data, type) { return swipes; } - if (main_api === 'openai' || (main_api === 'textgenerationwebui' && [MANCER, VLLM, APHRODITE, TABBY, INFERMATICAI].includes(textgen_settings.type))) { + if (main_api === 'openai' || (main_api === 'textgenerationwebui' && [textgen_types.MANCER, textgen_types.VLLM, textgen_types.APHRODITE, textgen_types.TABBY, textgen_types.INFERMATICAI].includes(textgen_settings.type))) { if (!Array.isArray(data.choices)) { return swipes; } @@ -5705,7 +5704,7 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc return getMessage; } -async function saveReply(type, getMessage, fromStreaming, title, swipes) { +export async function saveReply(type, getMessage, fromStreaming, title, swipes) { if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined || chat[chat.length - 1]['is_user'])) { type = 'normal'; @@ -8237,102 +8236,6 @@ async function createOrEditCharacter(e) { } } -window['SillyTavern'].getContext = function () { - return { - chat: chat, - characters: characters, - groups: groups, - name1: name1, - name2: name2, - characterId: this_chid, - groupId: selected_group, - chatId: selected_group - ? groups.find(x => x.id == selected_group)?.chat_id - : (this_chid && characters[this_chid] && characters[this_chid].chat), - getCurrentChatId: getCurrentChatId, - getRequestHeaders: getRequestHeaders, - reloadCurrentChat: reloadCurrentChat, - renameChat: renameChat, - saveSettingsDebounced: saveSettingsDebounced, - onlineStatus: online_status, - maxContext: Number(max_context), - chatMetadata: chat_metadata, - streamingProcessor, - eventSource: eventSource, - eventTypes: event_types, - addOneMessage: addOneMessage, - generate: Generate, - sendStreamingRequest: sendStreamingRequest, - sendGenerationRequest: sendGenerationRequest, - stopGeneration: stopGeneration, - getTokenCount: getTokenCount, - extensionPrompts: extension_prompts, - setExtensionPrompt: setExtensionPrompt, - updateChatMetadata: updateChatMetadata, - saveChat: saveChatConditional, - openCharacterChat: openCharacterChat, - openGroupChat: openGroupChat, - saveMetadata: saveMetadata, - sendSystemMessage: sendSystemMessage, - activateSendButtons, - deactivateSendButtons, - saveReply, - substituteParams, - substituteParamsExtended, - SlashCommandParser, - SlashCommand, - SlashCommandArgument, - SlashCommandNamedArgument, - ARGUMENT_TYPE, - executeSlashCommandsWithOptions, - /** @deprecated Use SlashCommandParser.addCommandObject() instead */ - registerSlashCommand: registerSlashCommand, - /** @deprecated Use executeSlashCommandWithOptions instead */ - executeSlashCommands: executeSlashCommands, - timestampToMoment: timestampToMoment, - /** @deprecated Handlebars for extensions are no longer supported. */ - registerHelper: () => { }, - registerMacro: MacrosParser.registerMacro.bind(MacrosParser), - unregisterMacro: MacrosParser.unregisterMacro.bind(MacrosParser), - registerFunctionTool: ToolManager.registerFunctionTool.bind(ToolManager), - unregisterFunctionTool: ToolManager.unregisterFunctionTool.bind(ToolManager), - isToolCallingSupported: ToolManager.isToolCallingSupported.bind(ToolManager), - canPerformToolCalls: ToolManager.canPerformToolCalls.bind(ToolManager), - registerDebugFunction: registerDebugFunction, - /** @deprecated Use renderExtensionTemplateAsync instead. */ - renderExtensionTemplate: renderExtensionTemplate, - renderExtensionTemplateAsync: renderExtensionTemplateAsync, - registerDataBankScraper: ScraperManager.registerDataBankScraper, - /** @deprecated Use callGenericPopup or Popup instead. */ - callPopup: callPopup, - callGenericPopup: callGenericPopup, - showLoader: showLoader, - hideLoader: hideLoader, - mainApi: main_api, - extensionSettings: extension_settings, - ModuleWorkerWrapper: ModuleWorkerWrapper, - getTokenizerModel: getTokenizerModel, - generateQuietPrompt: generateQuietPrompt, - writeExtensionField: writeExtensionField, - getThumbnailUrl: getThumbnailUrl, - selectCharacterById: selectCharacterById, - messageFormatting: messageFormatting, - shouldSendOnEnter: shouldSendOnEnter, - isMobile: isMobile, - t: t, - translate: translate, - tags: tags, - tagMap: tag_map, - menuType: menu_type, - createCharacterData: create_save, - /** @deprecated Legacy snake-case naming, compatibility with old extensions */ - event_types: event_types, - Popup: Popup, - POPUP_TYPE: POPUP_TYPE, - POPUP_RESULT: POPUP_RESULT, - }; -}; - /** * Formats a counter for a swipe view. * @param {number} current The current number of items. diff --git a/public/scripts/extensions.js b/public/scripts/extensions.js index e9a45f540..9eeb98a24 100644 --- a/public/scripts/extensions.js +++ b/public/scripts/extensions.js @@ -5,6 +5,7 @@ import { showLoader } from './loader.js'; import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; import { renderTemplate, renderTemplateAsync } from './templates.js'; import { isSubsetOf, setValueByPath } from './utils.js'; +import { getContext } from './st-context.js'; export { getContext, getApiUrl, @@ -174,7 +175,6 @@ const extension_settings = { let modules = []; let activeExtensions = new Set(); -const getContext = () => window['SillyTavern'].getContext(); const getApiUrl = () => extension_settings.apiUrl; let connectedToApi = false; diff --git a/public/scripts/st-context.js b/public/scripts/st-context.js new file mode 100644 index 000000000..6d509ee09 --- /dev/null +++ b/public/scripts/st-context.js @@ -0,0 +1,170 @@ +import { + activateSendButtons, + addOneMessage, + callPopup, + characters, + chat, + chat_metadata, + create_save, + deactivateSendButtons, + event_types, + eventSource, + extension_prompts, + Generate, + generateQuietPrompt, + getCurrentChatId, + getRequestHeaders, + getThumbnailUrl, + main_api, + max_context, + menu_type, + messageFormatting, + name1, + name2, + online_status, + openCharacterChat, + reloadCurrentChat, + renameChat, + saveChatConditional, + saveMetadata, + saveReply, + saveSettingsDebounced, + selectCharacterById, + sendGenerationRequest, + sendStreamingRequest, + sendSystemMessage, + setExtensionPrompt, + stopGeneration, + streamingProcessor, + substituteParams, + substituteParamsExtended, + this_chid, + updateChatMetadata, +} from '../script.js'; +import { + extension_settings, + ModuleWorkerWrapper, + renderExtensionTemplate, + renderExtensionTemplateAsync, + writeExtensionField, +} from './extensions.js'; +import { groups, openGroupChat, selected_group } from './group-chats.js'; +import { t, translate } from './i18n.js'; +import { hideLoader, showLoader } from './loader.js'; +import { MacrosParser } from './macros.js'; +import { oai_settings } from './openai.js'; +import { callGenericPopup, Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js'; +import { registerDebugFunction } from './power-user.js'; +import { isMobile, shouldSendOnEnter } from './RossAscends-mods.js'; +import { ScraperManager } from './scrapers.js'; +import { executeSlashCommands, executeSlashCommandsWithOptions, registerSlashCommand } from './slash-commands.js'; +import { SlashCommand } from './slash-commands/SlashCommand.js'; +import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; +import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; +import { tag_map, tags } from './tags.js'; +import { textgenerationwebui_settings } from './textgen-settings.js'; +import { getTokenCount, getTokenCountAsync, getTokenizerModel } from './tokenizers.js'; +import { ToolManager } from './tool-calling.js'; +import { timestampToMoment } from './utils.js'; + +export function getContext() { + return { + chatCompletionSettings: oai_settings, + textCompletionSettings: textgenerationwebui_settings, + chat, + characters, + groups, + name1, + name2, + characterId: this_chid, + groupId: selected_group, + chatId: selected_group + ? groups.find(x => x.id == selected_group)?.chat_id + : (this_chid && characters[this_chid] && characters[this_chid].chat), + getCurrentChatId, + getRequestHeaders, + reloadCurrentChat, + renameChat, + saveSettingsDebounced, + onlineStatus: online_status, + maxContext: Number(max_context), + chatMetadata: chat_metadata, + streamingProcessor, + eventSource, + eventTypes: event_types, + addOneMessage, + generate: Generate, + sendStreamingRequest, + sendGenerationRequest, + stopGeneration, + /** @deprecated Use getTokenCountAsync instead */ + getTokenCount, + getTokenCountAsync, + extensionPrompts: extension_prompts, + setExtensionPrompt: setExtensionPrompt, + updateChatMetadata: updateChatMetadata, + saveChat: saveChatConditional, + openCharacterChat, + openGroupChat, + saveMetadata, + sendSystemMessage, + activateSendButtons, + deactivateSendButtons, + saveReply, + substituteParams, + substituteParamsExtended, + SlashCommandParser, + SlashCommand, + SlashCommandArgument, + SlashCommandNamedArgument, + ARGUMENT_TYPE, + executeSlashCommandsWithOptions, + /** @deprecated Use SlashCommandParser.addCommandObject() instead */ + registerSlashCommand, + /** @deprecated Use executeSlashCommandWithOptions instead */ + executeSlashCommands, + timestampToMoment, + /** @deprecated Handlebars for extensions are no longer supported. */ + registerHelper: () => { }, + registerMacro: MacrosParser.registerMacro.bind(MacrosParser), + unregisterMacro: MacrosParser.unregisterMacro.bind(MacrosParser), + registerFunctionTool: ToolManager.registerFunctionTool.bind(ToolManager), + unregisterFunctionTool: ToolManager.unregisterFunctionTool.bind(ToolManager), + isToolCallingSupported: ToolManager.isToolCallingSupported.bind(ToolManager), + canPerformToolCalls: ToolManager.canPerformToolCalls.bind(ToolManager), + registerDebugFunction: registerDebugFunction, + /** @deprecated Use renderExtensionTemplateAsync instead. */ + renderExtensionTemplate: renderExtensionTemplate, + renderExtensionTemplateAsync: renderExtensionTemplateAsync, + registerDataBankScraper: ScraperManager.registerDataBankScraper, + /** @deprecated Use callGenericPopup or Popup instead. */ + callPopup, + callGenericPopup, + showLoader, + hideLoader, + mainApi: main_api, + extensionSettings: extension_settings, + ModuleWorkerWrapper, + getTokenizerModel, + generateQuietPrompt, + writeExtensionField, + getThumbnailUrl, + selectCharacterById, + messageFormatting, + shouldSendOnEnter, + isMobile, + t, + translate, + tags, + tagMap: tag_map, + menuType: menu_type, + createCharacterData: create_save, + /** @deprecated Legacy snake-case naming, compatibility with old extensions */ + event_types: event_types, + Popup: Popup, + POPUP_TYPE, + POPUP_RESULT, + }; +} + +export default getContext; diff --git a/public/scripts/textgen-settings.js b/public/scripts/textgen-settings.js index 5f1c684d0..19c270e49 100644 --- a/public/scripts/textgen-settings.js +++ b/public/scripts/textgen-settings.js @@ -18,13 +18,6 @@ import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer } import { ENCODE_TOKENIZERS, TEXTGEN_TOKENIZERS, getTextTokens, tokenizers } from './tokenizers.js'; import { getSortableDelay, onlyUnique } from './utils.js'; -export { - settings as textgenerationwebui_settings, - loadTextGenSettings, - generateTextGenWithStreaming, - formatTextGenURL, -}; - export const textgen_types = { OOBA: 'ooba', MANCER: 'mancer', @@ -197,6 +190,10 @@ const settings = { featherless_model: '', }; +export { + settings as textgenerationwebui_settings, +}; + export let textgenerationwebui_banned_in_macros = []; export let textgenerationwebui_presets = []; @@ -327,7 +324,7 @@ async function selectPreset(name) { saveSettingsDebounced(); } -function formatTextGenURL(value) { +export function formatTextGenURL(value) { try { const noFormatTypes = [MANCER, TOGETHERAI, INFERMATICAI, DREAMGEN, OPENROUTER]; if (noFormatTypes.includes(settings.type)) { @@ -465,7 +462,7 @@ function calculateLogitBias() { return result; } -function loadTextGenSettings(data, loadedSettings) { +export function loadTextGenSettings(data, loadedSettings) { textgenerationwebui_presets = convertPresets(data.textgenerationwebui_presets); textgenerationwebui_preset_names = data.textgenerationwebui_preset_names ?? []; Object.assign(settings, loadedSettings.textgenerationwebui_settings ?? {}); @@ -889,7 +886,7 @@ function setSettingByName(setting, value, trigger) { * @returns {Promise<(function(): AsyncGenerator<{swipes: [], text: string, toolCalls: [], logprobs: {token: string, topLogprobs: Candidate[]}|null}, void, *>)|*>} * @throws {Error} - If the response status is not OK, or from within the generator */ -async function generateTextGenWithStreaming(generate_data, signal) { +export async function generateTextGenWithStreaming(generate_data, signal) { generate_data.stream = true; const response = await fetch('/api/backends/text-completions/generate', { diff --git a/public/scripts/tokenizers.js b/public/scripts/tokenizers.js index 846442895..c25075a0f 100644 --- a/public/scripts/tokenizers.js +++ b/public/scripts/tokenizers.js @@ -8,8 +8,6 @@ import { kai_flags } from './kai-settings.js'; import { textgen_types, textgenerationwebui_settings as textgen_settings, getTextGenServer, getTextGenModel } from './textgen-settings.js'; import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, openRouterModels } from './textgen-models.js'; -const { OOBA, TABBY, KOBOLDCPP, VLLM, APHRODITE, LLAMACPP, OPENROUTER, DREAMGEN } = textgen_types; - export const CHARACTERS_PER_TOKEN_RATIO = 3.35; export const TOKENIZER_WARNING_KEY = 'tokenizationWarningShown'; export const TOKENIZER_SUPPORTED_KEY = 'tokenizationSupported'; @@ -52,8 +50,12 @@ export const ENCODE_TOKENIZERS = [ //tokenizers.NERD2, ]; -// A list of Text Completion sources that support remote tokenization. -export const TEXTGEN_TOKENIZERS = [OOBA, TABBY, KOBOLDCPP, LLAMACPP, VLLM, APHRODITE]; +/** + * A list of Text Completion sources that support remote tokenization. + * Populated in initTokenziers due to circular dependencies. + * @type {string[]} + */ +export const TEXTGEN_TOKENIZERS = []; const TOKENIZER_URLS = { [tokenizers.GPT2]: { @@ -287,7 +289,7 @@ export function getTokenizerBestMatch(forApi) { const hasTokenizerError = sessionStorage.getItem(TOKENIZER_WARNING_KEY); const hasValidEndpoint = sessionStorage.getItem(TOKENIZER_SUPPORTED_KEY); const isConnected = online_status !== 'no_connection'; - const isTokenizerSupported = TEXTGEN_TOKENIZERS.includes(textgen_settings.type) && (textgen_settings.type !== OOBA || hasValidEndpoint); + const isTokenizerSupported = TEXTGEN_TOKENIZERS.includes(textgen_settings.type) && (textgen_settings.type !== textgen_types.OOBA || hasValidEndpoint); if (!hasTokenizerError && isConnected) { if (forApi === 'kobold' && kai_flags.can_use_tokenization) { @@ -297,10 +299,10 @@ export function getTokenizerBestMatch(forApi) { if (forApi === 'textgenerationwebui' && isTokenizerSupported) { return tokenizers.API_TEXTGENERATIONWEBUI; } - if (forApi === 'textgenerationwebui' && textgen_settings.type === OPENROUTER) { + if (forApi === 'textgenerationwebui' && textgen_settings.type === textgen_types.OPENROUTER) { return getCurrentOpenRouterModelTokenizer(); } - if (forApi === 'textgenerationwebui' && textgen_settings.type === DREAMGEN) { + if (forApi === 'textgenerationwebui' && textgen_settings.type === textgen_types.DREAMGEN) { return getCurrentDreamGenModelTokenizer(); } } @@ -576,7 +578,7 @@ export function getTokenizerModel() { // And for OpenRouter (if not a site model, then it's impossible to determine the tokenizer) if (main_api == 'openai' && oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER && oai_settings.openrouter_model || - main_api == 'textgenerationwebui' && textgen_settings.type === OPENROUTER && textgen_settings.openrouter_model) { + main_api == 'textgenerationwebui' && textgen_settings.type === textgen_types.OPENROUTER && textgen_settings.openrouter_model) { const model = main_api == 'openai' ? model_list.find(x => x.id === oai_settings.openrouter_model) : openRouterModels.find(x => x.id === textgen_settings.openrouter_model); @@ -652,7 +654,7 @@ export function getTokenizerModel() { return oai_settings.custom_model; } - if (oai_settings.chat_completion_source === chat_completion_sources.PERPLEXITY) { + if (oai_settings.chat_completion_source === chat_completion_sources.PERPLEXITY) { if (oai_settings.perplexity_model.includes('llama-3') || oai_settings.perplexity_model.includes('llama3')) { return llama3Tokenizer; } @@ -680,7 +682,7 @@ export function getTokenizerModel() { return yiTokenizer; } - if (oai_settings.chat_completion_source === chat_completion_sources.BLOCKENTROPY) { + if (oai_settings.chat_completion_source === chat_completion_sources.BLOCKENTROPY) { if (oai_settings.blockentropy_model.includes('llama3')) { return llama3Tokenizer; } @@ -1121,6 +1123,14 @@ export function decodeTextTokens(tokenizerType, ids) { } export async function initTokenizers() { + TEXTGEN_TOKENIZERS.push( + textgen_types.OOBA, + textgen_types.TABBY, + textgen_types.KOBOLDCPP, + textgen_types.LLAMACPP, + textgen_types.VLLM, + textgen_types.APHRODITE, + ); await loadTokenCache(); registerDebugFunction('resetTokenCache', 'Reset token cache', 'Purges the calculated token counts. Use this if you want to force a full re-tokenization of all chats or suspect the token counts are wrong.', resetTokenCache); } From 7b732edf616ac099f2ae540f9f724e58e6db07f4 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 16:59:39 +0200 Subject: [PATCH 15/29] Fix npm audit --- package-lock.json | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 93902fcff..4f1fde346 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3591,9 +3591,9 @@ "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "license": "MIT", "dependencies": { "accepts": "~1.3.8", @@ -3615,7 +3615,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -3630,6 +3630,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express/node_modules/cookie": { @@ -5725,9 +5729,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", "license": "MIT" }, "node_modules/peek-readable": { From 9c43999e4b3975455e4c73132412baf7df705eed Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 17:15:40 +0200 Subject: [PATCH 16/29] Fix /tools-unregister --- public/scripts/tool-calling.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/tool-calling.js b/public/scripts/tool-calling.js index 323e76fd0..deda15289 100644 --- a/public/scripts/tool-calling.js +++ b/public/scripts/tool-calling.js @@ -947,7 +947,7 @@ export class ToolManager { enumProvider: toolsEnumProvider, }), ], - callback: async (name) => { + callback: async (_, name) => { if (typeof name !== 'string' || !name) { throw new Error('The unnamed argument must be a non-empty string.'); } From 073b76a6939a85c6d643f9da13b7a90d637958f5 Mon Sep 17 00:00:00 2001 From: M0cho <77959408+M0ch0@users.noreply.github.com> Date: Sat, 7 Dec 2024 02:19:15 +0900 Subject: [PATCH 17/29] Support Gemini-exp-1206 --- public/index.html | 1 + public/scripts/extensions/caption/settings.html | 1 + public/scripts/openai.js | 2 +- src/endpoints/backends/chat-completions.js | 2 +- src/prompt-converters.js | 1 + 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/public/index.html b/public/index.html index d8296c1fb..b6ae3eb29 100644 --- a/public/index.html +++ b/public/index.html @@ -2987,6 +2987,7 @@ Gemini Experimental 2024-11-21 Gemini Experimental 2024-11-14 + Gemini Experimental 2024-12-06 Gemini 1.5 Pro Experiment 2024-08-01 Gemini 1.5 Pro Experiment 2024-08-27 Gemini 1.5 Pro [latest] diff --git a/public/scripts/extensions/caption/settings.html b/public/scripts/extensions/caption/settings.html index eee8894d4..79692d54a 100644 --- a/public/scripts/extensions/caption/settings.html +++ b/public/scripts/extensions/caption/settings.html @@ -62,6 +62,7 @@ gemini-1.5-flash-8b-exp-0924 gemini-exp-1114 gemini-exp-1121 + gemini-exp-1206 gemini-1.5-pro gemini-1.5-pro-latest gemini-1.5-pro-001 diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 1f5b4d8f9..332c4e1ed 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -4077,7 +4077,7 @@ async function onModelChange() { $('#openai_max_context').attr('max', max_2mil); } else if (value.includes('gemini-exp-1114') || value.includes('gemini-exp-1121')) { $('#openai_max_context').attr('max', max_32k); - } else if (value.includes('gemini-1.5-pro')) { + } else if (value.includes('gemini-1.5-pro') || value.includes('gemini-exp-1206')) { $('#openai_max_context').attr('max', max_2mil); } else if (value.includes('gemini-1.5-flash')) { $('#openai_max_context').attr('max', max_1mil); diff --git a/src/endpoints/backends/chat-completions.js b/src/endpoints/backends/chat-completions.js index aa15c7278..cbae42f3d 100644 --- a/src/endpoints/backends/chat-completions.js +++ b/src/endpoints/backends/chat-completions.js @@ -280,7 +280,7 @@ async function sendMakerSuiteRequest(request, response) { delete generationConfig.stopSequences; } - const should_use_system_prompt = (model.includes('gemini-1.5-flash') || model.includes('gemini-1.5-pro') || model.includes('gemini-exp-1114') || model.includes('gemini-exp-1121')) && request.body.use_makersuite_sysprompt; + const should_use_system_prompt = (model.includes('gemini-1.5-flash') || model.includes('gemini-1.5-pro') || model.startsWith("gemini-exp")) && request.body.use_makersuite_sysprompt; const prompt = convertGooglePrompt(request.body.messages, model, should_use_system_prompt, request.body.char_name, request.body.user_name); let body = { contents: prompt.contents, diff --git a/src/prompt-converters.js b/src/prompt-converters.js index 79db3965c..3f052c8c5 100644 --- a/src/prompt-converters.js +++ b/src/prompt-converters.js @@ -347,6 +347,7 @@ export function convertGooglePrompt(messages, model, useSysPrompt = false, charN 'gemini-1.5-flash-8b-exp-0924', 'gemini-exp-1114', 'gemini-exp-1121', + 'gemini-exp-1206', 'gemini-1.5-pro', 'gemini-1.5-pro-latest', 'gemini-1.5-pro-001', From dce63f52c0acc72f8d902853146bb64e94c9308e Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:21:01 +0200 Subject: [PATCH 18/29] Remove SD module worker --- .../scripts/extensions/stable-diffusion/index.js | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/public/scripts/extensions/stable-diffusion/index.js b/public/scripts/extensions/stable-diffusion/index.js index b175860c8..7a302f392 100644 --- a/public/scripts/extensions/stable-diffusion/index.js +++ b/public/scripts/extensions/stable-diffusion/index.js @@ -60,7 +60,6 @@ import { ToolManager } from '../../tool-calling.js'; export { MODULE_NAME }; const MODULE_NAME = 'sd'; -const UPDATE_INTERVAL = 1000; // This is a 1x1 transparent PNG const PNG_PIXEL = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; const CUSTOM_STOP_EVENT = 'sd_stop_generation'; @@ -3687,8 +3686,6 @@ async function addSDGenButtons() { const button = $('#sd_gen'); const dropdown = $('#sd_dropdown'); dropdown.hide(); - button.hide(); - messageButton.hide(); let popper = Popper.createPopper(button.get(0), dropdown.get(0), { placement: 'top', @@ -3770,18 +3767,6 @@ function isValidState() { } } -async function moduleWorker() { - if (isValidState()) { - $('#sd_gen').show(); - $('.sd_message_gen').show(); - } - else { - $('#sd_gen').hide(); - $('.sd_message_gen').hide(); - } -} - -setInterval(moduleWorker, UPDATE_INTERVAL); let buttonAbortController = null; async function sdMessageButton(e) { From d5221760a3ec572db1b69484e8af9221198c855f Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:24:22 +0200 Subject: [PATCH 19/29] Hide swipe counter with visibility --- public/style.css | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/public/style.css b/public/style.css index 4444d0080..6f935ec4c 100644 --- a/public/style.css +++ b/public/style.css @@ -1040,12 +1040,8 @@ body .panelControlBar { height: var(--swipeCounterHeight); } -.mes:not(.last_mes) .swipes-counter { - opacity: 0.3; -} - body:not(.swipeAllMessages) .mes:not(.last_mes) .swipes-counter { - opacity: 0; + visibility: hidden; } body.swipeAllMessages .mes:not(.last_mes) .swipes-counter { From 1a8e37d3a5f9a9d1d954a3d569f229eea6b2c329 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 20:54:45 +0200 Subject: [PATCH 20/29] Remove counter hide on right swipe --- public/script.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/public/script.js b/public/script.js index c7744984e..2311626b2 100644 --- a/public/script.js +++ b/public/script.js @@ -8535,8 +8535,6 @@ const swipe_right = () => { } if (run_generate) { //hide swipe arrows while generating this_div.css('display', 'none'); - const swipesCounter = currentMessage.find('.swipes-counter'); - swipesCounter.hide(); } // handles animated transitions when swipe right, specifically height transitions between messages if (run_generate || run_swipe_right) { From 22ea5f3c3c7e7534696ae093ed91c14f46a4ad90 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 21:30:05 +0200 Subject: [PATCH 21/29] Lint fix --- src/endpoints/backends/chat-completions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/endpoints/backends/chat-completions.js b/src/endpoints/backends/chat-completions.js index cbae42f3d..248596404 100644 --- a/src/endpoints/backends/chat-completions.js +++ b/src/endpoints/backends/chat-completions.js @@ -280,7 +280,7 @@ async function sendMakerSuiteRequest(request, response) { delete generationConfig.stopSequences; } - const should_use_system_prompt = (model.includes('gemini-1.5-flash') || model.includes('gemini-1.5-pro') || model.startsWith("gemini-exp")) && request.body.use_makersuite_sysprompt; + const should_use_system_prompt = (model.includes('gemini-1.5-flash') || model.includes('gemini-1.5-pro') || model.startsWith('gemini-exp')) && request.body.use_makersuite_sysprompt; const prompt = convertGooglePrompt(request.body.messages, model, should_use_system_prompt, request.body.char_name, request.body.user_name); let body = { contents: prompt.contents, From 192a1f40147451a5ab94581710bac4c1caa588b0 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 21:41:04 +0200 Subject: [PATCH 22/29] getContext: Simplify chatId access --- public/scripts/st-context.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/st-context.js b/public/scripts/st-context.js index 6d509ee09..487c502ee 100644 --- a/public/scripts/st-context.js +++ b/public/scripts/st-context.js @@ -80,7 +80,7 @@ export function getContext() { groupId: selected_group, chatId: selected_group ? groups.find(x => x.id == selected_group)?.chat_id - : (this_chid && characters[this_chid] && characters[this_chid].chat), + : (characters[this_chid]?.chat), getCurrentChatId, getRequestHeaders, reloadCurrentChat, From 3ae858113b53bfa4d7af02d57fd1662a8f1cee4f Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 21:50:08 +0200 Subject: [PATCH 23/29] Set strict function binds in jsconfig --- public/jsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/public/jsconfig.json b/public/jsconfig.json index 8ef6e356e..5fbb79a68 100644 --- a/public/jsconfig.json +++ b/public/jsconfig.json @@ -5,7 +5,8 @@ "module": "ESNext", "moduleResolution": "node", "allowUmdGlobalAccess": true, - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "strictBindCallApply": true }, "exclude": [ "**/node_modules/**", From 485e9e2eaa54701d97e582798b4eb4b56b4f24e3 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 21:54:07 +0200 Subject: [PATCH 24/29] Fix redundancy in getContext. Add power user settings --- public/scripts/st-context.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/public/scripts/st-context.js b/public/scripts/st-context.js index 487c502ee..4f0abdd8d 100644 --- a/public/scripts/st-context.js +++ b/public/scripts/st-context.js @@ -54,7 +54,7 @@ import { hideLoader, showLoader } from './loader.js'; import { MacrosParser } from './macros.js'; import { oai_settings } from './openai.js'; import { callGenericPopup, Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js'; -import { registerDebugFunction } from './power-user.js'; +import { power_user, registerDebugFunction } from './power-user.js'; import { isMobile, shouldSendOnEnter } from './RossAscends-mods.js'; import { ScraperManager } from './scrapers.js'; import { executeSlashCommands, executeSlashCommandsWithOptions, registerSlashCommand } from './slash-commands.js'; @@ -69,8 +69,6 @@ import { timestampToMoment } from './utils.js'; export function getContext() { return { - chatCompletionSettings: oai_settings, - textCompletionSettings: textgenerationwebui_settings, chat, characters, groups, @@ -101,8 +99,8 @@ export function getContext() { getTokenCount, getTokenCountAsync, extensionPrompts: extension_prompts, - setExtensionPrompt: setExtensionPrompt, - updateChatMetadata: updateChatMetadata, + setExtensionPrompt, + updateChatMetadata, saveChat: saveChatConditional, openCharacterChat, openGroupChat, @@ -132,11 +130,11 @@ export function getContext() { unregisterFunctionTool: ToolManager.unregisterFunctionTool.bind(ToolManager), isToolCallingSupported: ToolManager.isToolCallingSupported.bind(ToolManager), canPerformToolCalls: ToolManager.canPerformToolCalls.bind(ToolManager), - registerDebugFunction: registerDebugFunction, + registerDebugFunction, /** @deprecated Use renderExtensionTemplateAsync instead. */ - renderExtensionTemplate: renderExtensionTemplate, - renderExtensionTemplateAsync: renderExtensionTemplateAsync, - registerDataBankScraper: ScraperManager.registerDataBankScraper, + renderExtensionTemplate, + renderExtensionTemplateAsync, + registerDataBankScraper: ScraperManager.registerDataBankScraper.bind(ScraperManager), /** @deprecated Use callGenericPopup or Popup instead. */ callPopup, callGenericPopup, @@ -161,9 +159,12 @@ export function getContext() { createCharacterData: create_save, /** @deprecated Legacy snake-case naming, compatibility with old extensions */ event_types: event_types, - Popup: Popup, + Popup, POPUP_TYPE, POPUP_RESULT, + chatCompletionSettings: oai_settings, + textCompletionSettings: textgenerationwebui_settings, + powerUserSettings: power_user, }; } From 0849cfca987915e93f8f8d5bde02f71c045a0929 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 22:13:34 +0200 Subject: [PATCH 25/29] Remove unused imports --- public/script.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/script.js b/public/script.js index ddbaabe74..99f673f21 100644 --- a/public/script.js +++ b/public/script.js @@ -220,8 +220,8 @@ import { instruct_presets, selectContextPreset, } from './scripts/instruct-mode.js'; -import { initLocales, t, translate } from './scripts/i18n.js'; -import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, getTokenizerModel, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js'; +import { initLocales, t } from './scripts/i18n.js'; +import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js'; import { user_avatar, getUserAvatars, @@ -534,7 +534,7 @@ let displayVersion = 'SillyTavern'; let generatedPromptCache = ''; let generation_started = new Date(); -/** @type {import('scripts/char-data.js').v1CharData[]} */ +/** @type {import('./scripts/char-data.js').v1CharData[]} */ export let characters = []; export let this_chid; let saveCharactersPage = 0; From b8a9a552463d5e889f0e22a0255048f01b702c73 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 6 Dec 2024 23:04:18 +0200 Subject: [PATCH 26/29] Fix group candidates fuzzy filter --- public/scripts/char-data.js | 1 + public/scripts/group-chats.js | 5 +++-- public/scripts/power-user.js | 19 ++++++++++--------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/public/scripts/char-data.js b/public/scripts/char-data.js index 5859331f6..be28d8172 100644 --- a/public/scripts/char-data.js +++ b/public/scripts/char-data.js @@ -75,6 +75,7 @@ * @property {string} [source_url] - The source URL associated with the character. * @property {{full_path: string}} [chub] - The Chub-specific data associated with the character. * @property {{source: string[]}} [risuai] - The RisuAI-specific data associated with the character. + * @property {{positive: string, negative: string}} [sd_character_prompt] - SD-specific data associated with the character. */ /** diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js index 0e106c3ea..9784218ee 100644 --- a/public/scripts/group-chats.js +++ b/public/scripts/group-chats.js @@ -1265,7 +1265,7 @@ function getGroupCharacters({ doFilter, onlyMembers } = {}) { const thisGroup = openGroupId && groups.find((x) => x.id == openGroupId); let candidates = characters .filter((x) => isGroupMember(thisGroup, x.avatar) == onlyMembers) - .map((x, index) => ({ item: x, id: index, type: 'character' })); + .map((x) => ({ item: x, id: characters.indexOf(x), type: 'character' })); if (doFilter) { candidates = groupCandidatesFilter.applyFilters(candidates); @@ -1275,9 +1275,10 @@ function getGroupCharacters({ doFilter, onlyMembers } = {}) { candidates.sort(sortMembersFn); } else { const useFilterOrder = doFilter && !!$('#rm_group_filter').val(); - sortEntitiesList(candidates, useFilterOrder); + sortEntitiesList(candidates, useFilterOrder, groupCandidatesFilter); } + groupCandidatesFilter.clearFuzzySearchCaches(); return candidates; } diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index a2ee59e15..4c17b10de 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -1836,7 +1836,7 @@ async function loadContextSettings() { * 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 {Array<{name: string, weight: number, getFn?: (obj: any) => string}>} keys - Fuse.js keys configuration * @param {string} searchValue - The search term * @param {Object. }>} [fuzzySearchCaches=null] - Optional fuzzy search caches * @returns {import('fuse.js').FuseResult[]} Results as items with their score @@ -1850,7 +1850,6 @@ function performFuzzySearch(type, data, keys, searchValue, fuzzySearchCaches = n } } - // @ts-ignore const fuse = new Fuse(data, { keys: keys, includeScore: true, @@ -1924,7 +1923,7 @@ export function fuzzySearchPersonas(data, searchValue, fuzzySearchCaches = null) const mappedData = data.map(x => ({ key: x, name: power_user.personas[x] ?? '', - description: power_user.persona_descriptions[x]?.description ?? '' + description: power_user.persona_descriptions[x]?.description ?? '', })); const keys = [ @@ -2080,19 +2079,21 @@ const compareFunc = (first, second) => { * Sorts an array of entities based on the current sort settings * @param {any[]} entities An array of objects with an `item` property * @param {boolean} forceSearch Whether to force search sorting + * @param {import('./filters.js').FilterHelper} [filterHelper=null] Filter helper to use */ -export function sortEntitiesList(entities, forceSearch) { +export function sortEntitiesList(entities, forceSearch, filterHelper = null) { + filterHelper = filterHelper ?? entitiesFilter; if (power_user.sort_field == undefined || entities.length === 0) { return; } - if (power_user.sort_order === 'random') { + const isSearch = forceSearch || $('#character_sort_order option[data-field="search"]').is(':selected'); + + if (!isSearch && power_user.sort_order === 'random') { shuffle(entities); return; } - const isSearch = forceSearch || $('#character_sort_order option[data-field="search"]').is(':selected'); - entities.sort((a, b) => { // Sort tags/folders will always be at the top if (a.type === 'tag' && b.type !== 'tag') { @@ -2104,8 +2105,8 @@ export function sortEntitiesList(entities, forceSearch) { // If we have search sorting, we take scores and use those if (isSearch) { - const aScore = entitiesFilter.getScore(FILTER_TYPES.SEARCH, `${a.type}.${a.id}`); - const bScore = entitiesFilter.getScore(FILTER_TYPES.SEARCH, `${b.type}.${b.id}`); + const aScore = filterHelper.getScore(FILTER_TYPES.SEARCH, `${a.type}.${a.id}`); + const bScore = filterHelper.getScore(FILTER_TYPES.SEARCH, `${b.type}.${b.id}`); return (aScore - bScore); } From f6b9cd970d3446057b49216c2001e8f36dca4b54 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sat, 7 Dec 2024 14:36:53 +0200 Subject: [PATCH 27/29] Add gemini-exp-1206 to supported image prompt models --- public/scripts/openai.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 332c4e1ed..76232563b 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -4761,6 +4761,7 @@ export function isImageInliningSupported() { 'gemini-1.5-flash-8b-exp-0924', 'gemini-exp-1114', 'gemini-exp-1121', + 'gemini-exp-1206', 'gemini-1.0-pro-vision-latest', 'gemini-1.5-pro', 'gemini-1.5-pro-latest', From 8574a5dd27e3574c997d954ba166292c5cf7ba56 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sat, 7 Dec 2024 14:50:24 +0200 Subject: [PATCH 28/29] Improve KAI lite import --- src/endpoints/chats.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/endpoints/chats.js b/src/endpoints/chats.js index 65758ee03..2eb8c379e 100644 --- a/src/endpoints/chats.js +++ b/src/endpoints/chats.js @@ -203,19 +203,19 @@ function importKoboldLiteChat(_userName, _characterName, data) { /** @type {function(string): object} */ function processKoboldMessage(msg) { - const isUser = msg.includes(inputToken) || msg.includes(outputToken); + const isUser = msg.includes(inputToken); return { name: isUser ? header.user_name : header.character_name, is_user: isUser, - mes: msg.replace(inputToken, '').replace(outputToken, '').trim(), + mes: msg.replaceAll(inputToken, '').replaceAll(outputToken, '').trim(), send_date: Date.now(), }; } // Create the header const header = { - user_name: data.savedsettings.chatname, - character_name: data.savedsettings.chatopponent, + user_name: String(data.savedsettings.chatname), + character_name: String(data.savedsettings.chatopponent).split('||$||')[0], }; // Format messages const formattedMessages = data.actions.map(processKoboldMessage); From 54ca9477dde9a605a940df8ea6aa2f5001d979c3 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sat, 7 Dec 2024 14:53:13 +0200 Subject: [PATCH 29/29] Bump package version --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4f1fde346..2419fe002 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "sillytavern", - "version": "1.12.8", + "version": "1.12.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "sillytavern", - "version": "1.12.8", + "version": "1.12.9", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 56ddd3796..777d99076 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,7 @@ "type": "git", "url": "https://github.com/SillyTavern/SillyTavern.git" }, - "version": "1.12.8", + "version": "1.12.9", "scripts": { "start": "node server.js", "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js",
return
simple