Merge branch 'staging' into whitelist-hosts

8fded7506938e28c3a850c3941f1abdaf4102ab2

Cohee <18619528+Cohee1207@users.noreply.github.com>

16 files changed, +221 -167Ignore whitespace
public/index.html+7 -7
@@ -4153,7 +4153,7 @@
41534153 </div>
41544154 <div id="UI-language-block" class="flex-container alignItemsBaseline">
41554155 <span data-i18n="UI Language">Language:</span>
41564156 <select id="ui_language_select" class="flex1 margin0 text_pole">
41574157 <option value="" data-i18n="Default">Default</option>
41584158 <option value="en">English</option>
41594159 </select>
@@ -5388,17 +5388,17 @@
53885388 </div>
53895389 </div>
53905390 <div id="GroupFavDelOkBack" class="flex-container flexGap5 spaceEvenly flex1">
53915391 <div id="rm_button_back_from_group" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-left-long"></div>
53925392 <div id="rm_group_scenario" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-scroll" title="Set a group chat scenario" data-i18n="[title]Set a group chat scenario"></div>
53935393 <div id="group_favorite_button" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div>
53945394 <input id="rm_group_fav" type="hidden" />
53955395 <div id="group_open_media_overrides" class="heightFitContent margin0 menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this group." data-i18n="[title]Click to allow/forbid the use of external media for this group.">
53965396 <i id="group_media_allowed_icon" class="fa-solid fa-fw fa-link"></i>
53975397 <i id="group_media_forbidden_icon" class="fa-solid fa-fw fa-link-slash"></i>
53985398 </div>
53995399 <div id="rm_group_submit" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-check" title="Create" data-i18n="[title]Create"></div>
54005400 <div id="rm_group_restore_avatar" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-images" title="Restore collage avatar" data-i18n="[title]Restore collage avatar"></div>
54015401 <div id="rm_group_delete" class="heightFitContent margin0 menu_button fa-solid fa-fw fa-trash-can" title="Delete" data-i18n="[title]Delete"></div>
54025402 <div class="flex1">
54035403 <label class="checkbox_label whitespacenowrap">
54045404 <input id="rm_group_allow_self_responses" type="checkbox" />
public/script.js+42 -15
@@ -553,6 +553,10 @@ let generatedPromptCache = '';
553553let generation_started = new Date();
554554/** @type {import('./scripts/char-data.js').v1CharData[]} */
555555export let characters = [];
556+/**
557+ * Stringified index of a currently chosen entity in the characters array.
558+ * @type {string|undefined} Yes, we hate it as much as you do.
559+ */
556560export let this_chid;
557561let saveCharactersPage = 0;
558562export const default_avatar = 'img/ai4.png';
@@ -1378,7 +1382,7 @@ export async function selectCharacterById(id) {
13781382 return;
13791383 }
13801384
13811385 if (selected_group || String(this_chid) !== String(id)) {
13821386 //if clicked on a different character from what was currently selected
13831387 if (!is_send_press) {
13841388 await clearChat();
@@ -1386,7 +1390,7 @@ export async function selectCharacterById(id) {
13861390 resetSelectedGroup();
13871391 this_edit_mes_id = undefined;
13881392 selected_button = 'character_edit';
1389- this_chid = id;
1393+ setCharacterId(id);
13901394 chat.length = 0;
13911395 chat_metadata = {};
13921396 await getChat();
@@ -5309,7 +5313,7 @@ function addChatsSeparator(mesSendString) {
53095313}
53105314
53115315async function duplicateCharacter() {
53125316 if (this_chid === undefined || !characters[this_chid]) {
53135317 toastr.warning(t`You must first select a character to duplicate!`);
53145318 return '';
53155319 }
@@ -6210,7 +6214,7 @@ export function resetChatState() {
62106214 // replaces deleted charcter name with system user since it will be displayed next.
62116215 name2 = (this_chid === undefined && neutralCharacterName) ? neutralCharacterName : systemUserName;
62126216 //unsets expected chid before reloading (related to getCharacters/printCharacters from using old arrays)
6213- this_chid = undefined;
6217+ setCharacterId(undefined);
62146218 // sets up system user to tell user about having deleted a character
62156219 chat.splice(0, chat.length, ...SAFETY_CHAT);
62166220 // resets chat metadata
@@ -6233,8 +6237,29 @@ export function setExternalAbortController(controller) {
62336237 abortController = controller;
62346238}
62356239
6240+/**
6241+ * Sets a character array index.
6242+ * @param {number|string|undefined} value
6243+ */
62366244export function setCharacterId(value) {
6237- this_chid = value;
6245+ switch (typeof value) {
6246+ case 'bigint':
6247+ case 'number':
6248+ this_chid = String(value);
6249+ break;
6250+ case 'string':
6251+ this_chid = !isNaN(parseInt(value)) ? value : undefined;
6252+ break;
6253+ case 'object':
6254+ this_chid = characters.indexOf(value) !== -1 ? String(characters.indexOf(value)) : undefined;
6255+ break;
6256+ case 'undefined':
6257+ this_chid = undefined;
6258+ break;
6259+ default:
6260+ console.error('Invalid character ID type:', value);
6261+ break;
6262+ }
62386263}
62396264
62406265export function setCharacterName(value) {
@@ -6350,13 +6375,13 @@ export async function renameCharacter(name = null, { silent = false, renameChats
63506375
63516376 if (newChId !== -1) {
63526377 // Select the character after the renaming
6353- this_chid = -1;
6378+ setCharacterId(undefined);
63546379 await selectCharacterById(newChId);
63556380
63566381 // Async delay to update UI
63576382 await delay(1);
63586383
63596384 if (this_chid === -1undefined) {
63606385 throw new Error('New character not selected');
63616386 }
63626387
@@ -7658,7 +7683,7 @@ export function select_rm_info(type, charId, previousCharId = null) {
76587683 if (previousCharId) {
76597684 const newId = characters.findIndex((x) => x.avatar == previousCharId);
76607685 if (newId >= 0) {
7661- this_chid = newId;
7686+ setCharacterId(newId);
76627687 }
76637688 }
76647689}
@@ -7678,6 +7703,7 @@ export function select_selected_character(chid) {
76787703 $('#create_button').attr('value', 'Save'); // what is the use case for this?
76797704 $('#dupe_button').show();
76807705 $('#create_button_label').css('display', 'none');
7706+ $('#char_connections_button').show();
76817707
76827708 // Hide the chat scenario button if we're peeking the group member defs
76837709 $('#set_chat_scenario').toggle(!selected_group);
@@ -7762,6 +7788,7 @@ function select_rm_create() {
77627788 $('#create_button_label').css('display', '');
77637789 $('#create_button').attr('value', 'Create');
77647790 $('#dupe_button').hide();
7791+ $('#char_connections_button').hide();
77657792
77667793 //create text poles
77677794 $('#rm_button_back').css('display', '');
@@ -7791,8 +7818,8 @@ function select_rm_create() {
77917818 $('#renameCharButton').css('display', 'none');
77927819 $('#name_div').removeClass('displayNone');
77937820 $('#name_div').addClass('displayBlock');
77947821 $('.open_alternate_greetings').data('chid', undefined-1);
77957822 $('#set_character_world').data('chid', undefined-1);
77967823 setWorldInfoButtonClass(undefined, !!create_save.world);
77977824 updateFavButtonState(false);
77987825 checkEmbeddedWorld();
@@ -7883,7 +7910,7 @@ function updateFavButtonState(state) {
78837910}
78847911
78857912export async function setScenarioOverride() {
78867913 if (!selected_group && (this_chid === undefined || !characters[this_chid])) {
78877914 console.warn('setScenarioOverride() -- no selected group or character');
78887915 return;
78897916 }
@@ -8248,7 +8275,7 @@ function updateAlternateGreetingsHintVisibility(root) {
82488275function openCharacterWorldPopup() {
82498276 const chid = $('#set_character_world').data('chid');
82508277
82518278 if (menu_type != 'create' && chid === undefined) {
82528279 toastr.error('Does not have an Id for this character in world select menu.');
82538280 return;
82548281 }
@@ -8380,7 +8407,7 @@ function openAlternateGreetings() {
83808407 return;
83818408 } else {
83828409 // If the character does not have alternate greetings, create an empty array
83838410 if (characters[chid] && !Array.isArray(characters[chid].data.alternate_greetings) == false) {
83848411 characters[chid].data.alternate_greetings = [];
83858412 }
83868413 }
@@ -8567,7 +8594,7 @@ async function createOrEditCharacter(e) {
85678594
85688595 formData.delete('alternate_greetings');
85698596 const chid = $('.open_alternate_greetings').data('chid');
85708597 if (characters[chid] && Array.isArray(characters[chid]?.data?.alternate_greetings)) {
85718598 for (const value of characters[chid].data.alternate_greetings) {
85728599 formData.append('alternate_greetings', value);
85738600 }
@@ -10283,7 +10310,7 @@ jQuery(async function () {
1028310310 $('#form_create').submit(createOrEditCharacter);
1028410311
1028510312 $('#delete_button').on('click', async function () {
1028610313 if (this_chid === undefined || !characters[this_chid]) {
1028710314 toastr.warning('No character selected.');
1028810315 return;
1028910316 }
public/scripts/BulkEditOverlay.js+2 -2
@@ -395,7 +395,7 @@ class BulkEditOverlay {
395395
396396 /**
397397 * @typedef {object} LastSelected - An object noting the last selected character and its state.
398398 * @property {stringnumber} [characterId] - The character id of the last selected character.
399399 * @property {boolean} [select] - The selected state of the last selected character. <c>true</c> if it was selected, <c>false</c> if it was deselected.
400400 */
401401
@@ -675,7 +675,7 @@ class BulkEditOverlay {
675675 const characterId = Number(currentCharacter.getAttribute('data-chid'));
676676 const select = !this.selectedCharacters.includes(characterId);
677677
678678 if (this.lastSelected.characterId >= 0 && this.lastSelected.select !== undefined) {
679679 // Only if select state and the last select state match we execute the range select
680680 if (select === this.lastSelected.select) {
681681 this.toggleCharactersInRange(currentCharacter, select);
public/scripts/authors-note.js+41 -41
@@ -299,7 +299,7 @@ function loadSettings() {
299299 $('#extension_floating_role').val(chat_metadata[metadata_keys.role]);
300300 $(`input[name="extension_floating_position"][value="${chat_metadata[metadata_keys.position]}"]`).prop('checked', true);
301301
302302 if (extension_settings.note.chara && getContext().characterId !== undefined) {
303303 const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename());
304304
305305 $('#extension_floating_chara').val(charaNote ? charaNote.prompt : '');
@@ -389,49 +389,49 @@ export function setFloatingPrompt() {
389389}
390390
391391function onANMenuItemClick() {
392392 if (!selected_group ||&& this_chid === undefined) {
393- //show AN if it's hidden
393+ toastr.warning(t`Select a character before trying to use Author's Note`, '', { timeOut: 2000 });
394- if ($('#floatingPrompt').css('display') !== 'flex') {
394+ return;
395- $('#floatingPrompt').addClass('resizing');
395+ }
396- $('#floatingPrompt').css('display', 'flex');
396+
397- $('#floatingPrompt').css('opacity', 0.0);
397+ //show AN if it's hidden
398- $('#floatingPrompt').transition({
398+ if ($('#floatingPrompt').css('display') !== 'flex') {
399- opacity: 1.0,
399+ $('#floatingPrompt').addClass('resizing');
400- duration: animation_duration,
400+ $('#floatingPrompt').css('display', 'flex');
401- }, async function () {
401+ $('#floatingPrompt').css('opacity', 0.0);
402- await delay(50);
402+ $('#floatingPrompt').transition({
403- $('#floatingPrompt').removeClass('resizing');
403+ opacity: 1.0,
404- });
404+ duration: animation_duration,
405-
405+ }, async function () {
406- //auto-open the main AN inline drawer
406+ await delay(50);
407407 if ($('#ANBlockTogglefloatingPrompt').removeClass('resizing');
408- .siblings('.inline-drawer-content')
408+ });
409- .css('display') !== 'block') {
410- $('#floatingPrompt').addClass('resizing');
411- $('#ANBlockToggle').click();
412- }
413- } else {
414- //hide AN if it's already displayed
415- $('#floatingPrompt').addClass('resizing');
416- $('#floatingPrompt').transition({
417- opacity: 0.0,
418- duration: animation_duration,
419- },
420- async function () {
421- await delay(50);
422- $('#floatingPrompt').removeClass('resizing');
423- });
424- setTimeout(function () {
425- $('#floatingPrompt').hide();
426- }, animation_duration);
427409
410+ //auto-open the main AN inline drawer
411+ if ($('#ANBlockToggle')
412+ .siblings('.inline-drawer-content')
413+ .css('display') !== 'block') {
414+ $('#floatingPrompt').addClass('resizing');
415+ $('#ANBlockToggle').click();
428416 }
429- //duplicate options menu close handler from script.js
430- //because this listener takes priority
431- $('#options').stop().fadeOut(animation_duration);
432417 } else {
433- toastr.warning(t`Select a character before trying to use Author's Note`, '', { timeOut: 2000 });
418+ //hide AN if it's already displayed
419+ $('#floatingPrompt').addClass('resizing');
420+ $('#floatingPrompt').transition({
421+ opacity: 0.0,
422+ duration: animation_duration,
423+ }, async function () {
424+ await delay(50);
425+ $('#floatingPrompt').removeClass('resizing');
426+ });
427+ setTimeout(function () {
428+ $('#floatingPrompt').hide();
429+ }, animation_duration);
434430 }
431+
432+ //duplicate options menu close handler from script.js
433+ //because this listener takes priority
434+ $('#options').stop().fadeOut(animation_duration);
435435}
436436
437437async function onChatChanged() {
@@ -446,7 +446,7 @@ async function onChatChanged() {
446446 $('#extension_floating_prompt_token_counter').text(tokenCounter1);
447447
448448 let tokenCounter2;
449449 if (extension_settings.note.chara && context.characterId !== undefined) {
450450 const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename());
451451
452452 if (charaNote) {
public/scripts/cfg-scale.js+56 -57
@@ -40,7 +40,7 @@ function setCharCfg(tempValue, setting) {
4040 name: avatarName,
4141 };
4242
4343 switch (setting) {
4444 case settingType.guidance_scale:
4545 tempCharaCfg['guidance_scale'] = Number(tempValue);
4646 break;
@@ -69,8 +69,7 @@ function setCharCfg(tempValue, setting) {
6969 if (!existingCharaCfg.useChara &&
7070 (tempAssign.guidance_scale ?? 1.00) === 1.00 &&
7171 (tempAssign.negative_prompt?.length ?? 0) === 0 &&
7272 (tempAssign.positive_prompt?.length ?? 0) === 0) {
73- {
7473 extension_settings.cfg.chara.splice(existingCharaCfgIndex, 1);
7574 }
7675 } else if (avatarName && tempValue.length > 0) {
@@ -92,7 +91,7 @@ function setCharCfg(tempValue, setting) {
9291}
9392
9493function setChatCfg(tempValue, setting) {
9594 switch (setting) {
9695 case settingType.guidance_scale:
9796 chat_metadata[metadataKeys.guidance_scale] = tempValue;
9897 break;
@@ -113,49 +112,49 @@ function setChatCfg(tempValue, setting) {
113112
114113// TODO: Only change CFG when character is selected
115114function onCfgMenuItemClick() {
116115 if (!selected_group ||&& this_chid === undefined) {
117- //show CFG config if it's hidden
116+ toastr.warning('Select a character before trying to configure CFG', '', { timeOut: 2000 });
118- if ($('#cfgConfig').css('display') !== 'flex') {
117+ return;
119- $('#cfgConfig').addClass('resizing');
118+ }
120- $('#cfgConfig').css('display', 'flex');
119+
121- $('#cfgConfig').css('opacity', 0.0);
120+ //show CFG config if it's hidden
122- $('#cfgConfig').transition({
121+ if ($('#cfgConfig').css('display') !== 'flex') {
123- opacity: 1.0,
122+ $('#cfgConfig').addClass('resizing');
124- duration: animation_duration,
123+ $('#cfgConfig').css('display', 'flex');
125- }, async function () {
124+ $('#cfgConfig').css('opacity', 0.0);
126- await delay(50);
125+ $('#cfgConfig').transition({
127- $('#cfgConfig').removeClass('resizing');
126+ opacity: 1.0,
128- });
127+ duration: animation_duration,
129-
128+ }, async function () {
130- //auto-open the main AN inline drawer
129+ await delay(50);
131130 if ($('#CFGBlockTogglecfgConfig').removeClass('resizing');
132- .siblings('.inline-drawer-content')
131+ });
133- .css('display') !== 'block') {
134- $('#floatingPrompt').addClass('resizing');
135- $('#CFGBlockToggle').click();
136- }
137- } else {
138- //hide AN if it's already displayed
139- $('#cfgConfig').addClass('resizing');
140- $('#cfgConfig').transition({
141- opacity: 0.0,
142- duration: animation_duration,
143- },
144- async function () {
145- await delay(50);
146- $('#cfgConfig').removeClass('resizing');
147- });
148- setTimeout(function () {
149- $('#cfgConfig').hide();
150- }, animation_duration);
151132
133+ //auto-open the main AN inline drawer
134+ if ($('#CFGBlockToggle')
135+ .siblings('.inline-drawer-content')
136+ .css('display') !== 'block') {
137+ $('#floatingPrompt').addClass('resizing');
138+ $('#CFGBlockToggle').click();
152139 }
153- //duplicate options menu close handler from script.js
154- //because this listener takes priority
155- $('#options').stop().fadeOut(animation_duration);
156140 } else {
157- toastr.warning('Select a character before trying to configure CFG', '', { timeOut: 2000 });
141+ //hide AN if it's already displayed
142+ $('#cfgConfig').addClass('resizing');
143+ $('#cfgConfig').transition({
144+ opacity: 0.0,
145+ duration: animation_duration,
146+ }, async function () {
147+ await delay(50);
148+ $('#cfgConfig').removeClass('resizing');
149+ });
150+ setTimeout(function () {
151+ $('#cfgConfig').hide();
152+ }, animation_duration);
153+
158154 }
155+ //duplicate options menu close handler from script.js
156+ //because this listener takes priority
157+ $('#options').stop().fadeOut(animation_duration);
159158}
160159
161160async function onChatChanged() {
@@ -288,7 +287,7 @@ export function initCfg() {
288287 setTimeout(function () { $('#cfgConfig').hide(); }, animation_duration);
289288 });
290289
291290 $('#chat_cfg_guidance_scale').on('input', function () {
292291 const numberValue = Number($(this).val());
293292 const success = setChatCfg(numberValue, settingType.guidance_scale);
294293 if (success) {
@@ -296,15 +295,15 @@ export function initCfg() {
296295 }
297296 });
298297
299298 $('#chat_cfg_negative_prompt').on('input', function () {
300299 setChatCfg($(this).val(), settingType.negative_prompt);
301300 });
302301
303302 $('#chat_cfg_positive_prompt').on('input', function () {
304303 setChatCfg($(this).val(), settingType.positive_prompt);
305304 });
306305
307306 $('#chara_cfg_guidance_scale').on('input', function () {
308307 const value = $(this).val();
309308 const success = setCharCfg(value, settingType.guidance_scale);
310309 if (success) {
@@ -312,34 +311,34 @@ export function initCfg() {
312311 }
313312 });
314313
315314 $('#chara_cfg_negative_prompt').on('input', function () {
316315 setCharCfg($(this).val(), settingType.negative_prompt);
317316 });
318317
319318 $('#chara_cfg_positive_prompt').on('input', function () {
320319 setCharCfg($(this).val(), settingType.positive_prompt);
321320 });
322321
323322 $('#global_cfg_guidance_scale').on('input', function () {
324323 extension_settings.cfg.global.guidance_scale = Number($(this).val());
325324 $('#global_cfg_guidance_scale_counter').val(extension_settings.cfg.global.guidance_scale.toFixed(2));
326325 saveSettingsDebounced();
327326 });
328327
329328 $('#global_cfg_negative_prompt').on('input', function () {
330329 extension_settings.cfg.global.negative_prompt = $(this).val();
331330 saveSettingsDebounced();
332331 });
333332
334333 $('#global_cfg_positive_prompt').on('input', function () {
335334 extension_settings.cfg.global.positive_prompt = $(this).val();
336335 saveSettingsDebounced();
337336 });
338337
339338 $('input[name="cfg_prompt_combine"]').on('input', function () {
340339 const values = $('#cfgConfig').find('input[name="cfg_prompt_combine"]')
341340 .filter(':checked')
342341 .map(function () { return Number($(this).val()); })
343342 .get()
344343 .filter((e) => !Number.isNaN(e)) || [];
345344
@@ -347,17 +346,17 @@ export function initCfg() {
347346 saveMetadataDebounced();
348347 });
349348
350349 $('#cfg_prompt_insertion_depth').on('input', function () {
351350 chat_metadata[metadataKeys.prompt_insertion_depth] = Number($(this).val());
352351 saveMetadataDebounced();
353352 });
354353
355354 $('#cfg_prompt_separator').on('input', function () {
356355 chat_metadata[metadataKeys.prompt_separator] = $(this).val();
357356 saveMetadataDebounced();
358357 });
359358
360359 $('#groupchat_cfg_use_chara').on('input', function () {
361360 const checked = !!$(this).prop('checked');
362361 chat_metadata[metadataKeys.groupchat_individual_chars] = checked;
363362
public/scripts/extensions/expressions/index.js+1 -1
@@ -624,7 +624,7 @@ function getFolderNameByMessage(message) {
624624 if (context.groupId) {
625625 avatarPath = message.original_avatar || context.characters.find(x => message.force_avatar && message.force_avatar.includes(encodeURIComponent(x.avatar)))?.avatar;
626626 }
627627 else if (context.characterId !== undefined) {
628628 avatarPath = getCharaFilename();
629629 }
630630
public/scripts/extensions/gallery/index.js+4 -4
@@ -169,9 +169,9 @@ async function showCharGallery() {
169169
170170 try {
171171 let url = selected_group || this_chid;
172172 if (!selected_group && this_chid !== undefined) {
173173 const char = characters[this_chid];
174174 url = char.avatar.replace('.png', '')name;
175175 }
176176
177177 const items = await getGalleryItems(url);
@@ -455,9 +455,9 @@ SlashCommandParser.addCommandObject(SlashCommand.fromProps({
455455async function listGalleryCommand(args) {
456456 try {
457457 let url = args.char ?? (args.group ? groups.find(it => it.name == args.group)?.id : null) ?? (selected_group || this_chid);
458458 if (!args.char && !args.group && !selected_group && this_chid !== undefined) {
459459 const char = characters[this_chid];
460460 url = char.avatar.replace('.png', '')name;
461461 }
462462
463463 const items = await getGalleryItems(url);
public/scripts/extensions/memory/index.js+20 -18
@@ -378,6 +378,23 @@ function getIndexOfLatestChatSummary(chat) {
378378 return -1;
379379}
380380
381+/**
382+ * Check if something is changed during the summarization process.
383+ * @param {{ groupId: any; chatId: any; characterId: any; }} context
384+ * @returns {boolean} True if the context has changed and the summary should be discarded
385+ */
386+function isContextChanged(context) {
387+ const newContext = getContext();
388+ if (newContext.groupId !== context.groupId
389+ || newContext.chatId !== context.chatId
390+ || (!newContext.groupId && (newContext.characterId !== context.characterId))) {
391+ console.log('Context changed, summary discarded');
392+ return true;
393+ }
394+
395+ return false;
396+}
397+
381398function onChatChanged() {
382399 const context = getContext();
383400 const latestMemory = getLatestMemoryFromChat(context.chat);
@@ -626,7 +643,6 @@ async function summarizeChatWebLLM(context, force) {
626643 try {
627644 inApiCall = true;
628645 const summary = await generateWebLlmChatPrompt(messages, params);
629- const newContext = getContext();
630646
631647 if (!summary) {
632648 console.warn('Empty summary received');
@@ -634,10 +650,7 @@ async function summarizeChatWebLLM(context, force) {
634650 }
635651
636652 // something changed during summarization request
637- if (newContext.groupId !== context.groupId ||
653+ if (isContextChanged(context)) {
638- newContext.chatId !== context.chatId ||
639- (!newContext.groupId && (newContext.characterId !== context.characterId))) {
640- console.log('Context changed, summary discarded');
641654 return;
642655 }
643656
@@ -701,13 +714,7 @@ async function summarizeChatMain(context, force, skipWIAN) {
701714 return;
702715 }
703716
704- const newContext = getContext();
717+ if (isContextChanged(context)) {
705-
706- // something changed during summarization request
707- if (newContext.groupId !== context.groupId
708- || newContext.chatId !== context.chatId
709- || (!newContext.groupId && (newContext.characterId !== context.characterId))) {
710- console.log('Context changed, summary discarded');
711718 return;
712719 }
713720
@@ -833,18 +840,13 @@ async function summarizeChatExtras(context) {
833840 try {
834841 inApiCall = true;
835842 const summary = await callExtrasSummarizeAPI(resultingString);
836- const newContext = getContext();
837843
838844 if (!summary) {
839845 console.warn('Empty summary received');
840846 return;
841847 }
842848
843- // something changed during summarization request
849+ if (isContextChanged(context)) {
844- if (newContext.groupId !== context.groupId
845- || newContext.chatId !== context.chatId
846- || (!newContext.groupId && (newContext.characterId !== context.characterId))) {
847- console.log('Context changed, summary discarded');
848850 return;
849851 }
850852
public/scripts/extensions/stable-diffusion/index.js+2 -2
@@ -783,7 +783,7 @@ async function onCharacterNegativePromptInput() {
783783}
784784
785785function getCharacterPrefix() {
786786 if (!this_chid === undefined || selected_group) {
787787 return '';
788788 }
789789
@@ -797,7 +797,7 @@ function getCharacterPrefix() {
797797}
798798
799799function getCharacterNegativePrefix() {
800800 if (!this_chid === undefined || selected_group) {
801801 return '';
802802 }
803803
public/scripts/extensions/tts/system.js+2 -0
@@ -51,6 +51,8 @@ var speechUtteranceChunker = function (utt, settings, callback) {
5151 }
5252 newUtt.lang = utt.lang;
5353 newUtt.voice = utt.voice;
54+ newUtt.rate = utt.rate;
55+ newUtt.pitch = utt.pitch;
5456 newUtt.addEventListener('end', function () {
5557 if (speechUtteranceChunker.cancel) {
5658 speechUtteranceChunker.cancel = false;
public/scripts/horde.js+2 -0
@@ -406,6 +406,8 @@ jQuery(function () {
406406 } else {
407407 $('#adjustedHordeParams').text('Context: --, Response: --');
408408 }
409+
410+ saveSettingsDebounced();
409411 });
410412
411413 $('#horde_auto_adjust_response_length').on('input', function () {
public/scripts/i18n.js+6 -2
@@ -132,10 +132,14 @@ async function getLocaleData(language) {
132132 return data;
133133}
134134
135+/**
136+ * Gets a language object for the given language code.
137+ * @param {string} language Language code
138+ */
135139function findLang(language) {
136140 varconst supportedLang = langs.find(x => x.lang === language);
137141
138142 if (!supportedLang && language !== 'en') {
139143 console.warn(`Unsupported language: ${language}`);
140144 }
141145 return supportedLang;
public/scripts/logprobs.js+5 -1
@@ -496,9 +496,13 @@ function getMessageHash(message) {
496496/**
497497 * getActiveMessageLogprobData returns the logprobs data for the active chat
498498 * message.
499499 * @returns {MessageLogprobData || null}
500500 */
501501function getActiveMessageLogprobData() {
502+ if (chat.length === 0) {
503+ return null;
504+ }
505+
502506 const hash = getMessageHash(chat[chat.length - 1]);
503507 return state.messageLogprobs.get(hash) || null;
504508}
public/scripts/st-context.js+4 -0
@@ -45,6 +45,8 @@ import {
4545 this_chid,
4646 updateChatMetadata,
4747 updateMessageBlock,
48+ printMessages,
49+ clearChat,
4850} from '../script.js';
4951import {
5052 extension_settings,
@@ -203,6 +205,8 @@ export function getContext() {
203205 extractMessageFromData,
204206 getPresetManager,
205207 getChatCompletionModel,
208+ printMessages,
209+ clearChat,
206210 };
207211}
208212
public/scripts/tags.js+1 -1
@@ -410,7 +410,7 @@ function getInlineListSelector() {
410410 return `.group_select[grid="${selected_group}"] .tags`;
411411 }
412412
413413 if (this_chid !== undefined && menu_type === 'character_edit') {
414414 return `.character_select[chid="${this_chid}"] .tags`;
415415 }
416416
public/scripts/world-info.js+26 -16
@@ -4732,7 +4732,7 @@ export function setWorldInfoButtonClass(chid, forceValue = undefined) {
47324732 return;
47334733 }
47344734
47354735 if (!chid === undefined) {
47364736 return;
47374737 }
47384738
@@ -4749,7 +4749,7 @@ export function checkEmbeddedWorld(chid) {
47494749 }
47504750
47514751 if (characters[chid]?.data?.character_book) {
47524752 $('#import_character_info').data('data-chid', chid).show();
47534753
47544754 // Only show the alert once per character
47554755 const checkKey = `AlertWI_${characters[chid].avatar}`;
@@ -4783,9 +4783,15 @@ export function checkEmbeddedWorld(chid) {
47834783}
47844784
47854785export async function importEmbeddedWorldInfo(skipPopup = false) {
47864786 const chid = $('#import_character_info').data('data-chid');
47874787
47884788 if (chid === undefined || chid === -1) {
4789+ return;
4790+ }
4791+
4792+ const hasEmbed = checkEmbeddedWorld(chid);
4793+
4794+ if (!hasEmbed) {
47894795 return;
47904796 }
47914797
@@ -5167,20 +5173,24 @@ jQuery(() => {
51675173 });
51685174
51695175 $('#world_button').on('click', async function (event) {
5176+ const openSetWorldMenu = () => $('#char-management-dropdown').val($('#set_character_world').val()).trigger('change');
51705177 const chid = $('#set_character_world').data('chid');
51715178
51725179 if (chid === -1) {
5173- const worldName = characters[chid]?.data?.extensions?.world;
5180+ openSetWorldMenu();
5174- const hasEmbed = checkEmbeddedWorld(chid);
5181+ return;
5175- if (worldName && world_names.includes(worldName) && !event.shiftKey) {
5182+ }
5176- openWorldInfoEditor(worldName);
5183+
5177- } else if (hasEmbed && !event.shiftKey) {
5184+ const worldName = characters[chid]?.data?.extensions?.world;
5178- await importEmbeddedWorldInfo();
5185+ const hasEmbed = checkEmbeddedWorld(chid);
5179- saveCharacterDebounced();
5186+ if (worldName && world_names.includes(worldName) && !event.shiftKey) {
5180- }
5187+ openWorldInfoEditor(worldName);
5181- else {
5188+ } else if (hasEmbed && !event.shiftKey) {
5182- $('#char-management-dropdown').val($('#set_character_world').val()).trigger('change');
5189+ await importEmbeddedWorldInfo();
5183- }
5190+ saveCharacterDebounced();
5191+ }
5192+ else {
5193+ openSetWorldMenu();
51845194 }
51855195 });
51865196