From 4ab54016ad73af005e71ac019931bff3033d7ccd Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 25 Feb 2025 17:00:41 +0100 Subject: [PATCH 1/8] Utility func to sync all mes data to swipe --- public/script.js | 55 ++++++++++++++++++++++++++------ public/scripts/slash-commands.js | 4 +-- 2 files changed, 47 insertions(+), 12 deletions(-) diff --git a/public/script.js b/public/script.js index 9219e84eb..f0cf0ef80 100644 --- a/public/script.js +++ b/public/script.js @@ -6086,17 +6086,52 @@ export async function saveReply(type, getMessage, fromStreaming, title, swipes, return { type, getMessage }; } -export function syncCurrentSwipeInfoExtras() { +/** + * Syncs the current message and all its data into the swipe data at the given message ID (or the last message if no ID is given). + * + * If the swipe data is invalid in some way, this function will exit out without doing anything. + * @param {number?} [messageId=null] - The ID of the message to sync with the swipe data. If no ID is given, the last message is used. + * @returns {boolean} Whether the message was successfully synced + */ +export function syncMesToSwipe(messageId = null) { if (!chat.length) { - return; + return false; } - const currentMessage = chat[chat.length - 1]; - if (currentMessage && Array.isArray(currentMessage.swipe_info) && typeof currentMessage.swipe_id === 'number') { - const swipeInfo = currentMessage.swipe_info[currentMessage.swipe_id]; - if (swipeInfo && typeof swipeInfo === 'object') { - swipeInfo.extra = structuredClone(currentMessage.extra); - } + + const targetMessageId = messageId ?? chat.length - 1; + if (chat.length > targetMessageId) { + console.warn(`[syncMesToSwipe] Invalid message ID: ${messageId}`); + return false; } + + const targetMessage = chat[targetMessageId]; + + // No swipe data there yet, exit out + if (typeof targetMessage.swipe_id !== 'number') { + return false; + } + // If swipes structure is invalid, exit out (for now?) + if (!Array.isArray(targetMessage.swipe_info) || !Array.isArray(targetMessage.swipes)) { + return false; + } + // If the swipe is not present yet, exit out (will likely be copied later) + if (!targetMessage.swipes[targetMessage.swipe_id] || !targetMessage.swipe_info[targetMessage.swipe_id]) { + return false; + } + + const targetSwipeInfo = targetMessage.swipe_info[targetMessage.swipe_id]; + if (typeof targetSwipeInfo !== 'object') { + return false; + } + + targetMessage.swipes[targetMessage.swipe_id] = targetMessage.mes; + + targetSwipeInfo.send_date = targetMessage.send_date; + targetSwipeInfo.gen_started = targetMessage.gen_started; + targetSwipeInfo.gen_finished = targetMessage.gen_finished; + targetSwipeInfo.extra = structuredClone(targetMessage.extra); + + return true; } function saveImageToMessage(img, mes) { @@ -8568,7 +8603,7 @@ function swipe_left() { // when we swipe left..but no generation. } // Make sure ad-hoc changes to extras are saved before swiping away - syncCurrentSwipeInfoExtras(); + syncMesToSwipe(); const swipe_duration = 120; const swipe_range = '700px'; @@ -8706,7 +8741,7 @@ const swipe_right = () => { } // Make sure ad-hoc changes to extras are saved before swiping away - syncCurrentSwipeInfoExtras(); + syncMesToSwipe(); const swipe_duration = 200; const swipe_range = 700; diff --git a/public/scripts/slash-commands.js b/public/scripts/slash-commands.js index 42eb20f4a..9f0cb8f73 100644 --- a/public/scripts/slash-commands.js +++ b/public/scripts/slash-commands.js @@ -42,7 +42,7 @@ import { showMoreMessages, stopGeneration, substituteParams, - syncCurrentSwipeInfoExtras, + syncMesToSwipe, system_avatar, system_message_types, this_chid, @@ -2921,7 +2921,7 @@ async function addSwipeCallback(args, value) { if (isTrueBoolean(args.switch)) { // Make sure ad-hoc changes to extras are saved before swiping away - syncCurrentSwipeInfoExtras(); + syncMesToSwipe(); lastMessage.swipe_id = newSwipeId; lastMessage.mes = lastMessage.swipes[newSwipeId]; lastMessage.extra = structuredClone(lastMessage.swipe_info?.[newSwipeId]?.extra ?? lastMessage.extra ?? {}); From 8bdc00e0b9181fd7bfe8ca694b904af777261998 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 25 Feb 2025 17:10:13 +0100 Subject: [PATCH 2/8] Fix reasoning not always being synced to swipe --- public/scripts/reasoning.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/public/scripts/reasoning.js b/public/scripts/reasoning.js index 5851e87e4..8c59da101 100644 --- a/public/scripts/reasoning.js +++ b/public/scripts/reasoning.js @@ -1,7 +1,7 @@ import { moment, } from '../lib.js'; -import { chat, closeMessageEditor, event_types, eventSource, main_api, messageFormatting, saveChatConditional, saveChatDebounced, saveSettingsDebounced, substituteParams, updateMessageBlock } from '../script.js'; +import { chat, closeMessageEditor, event_types, eventSource, main_api, messageFormatting, saveChatConditional, saveChatDebounced, saveSettingsDebounced, substituteParams, syncMesToSwipe, updateMessageBlock } from '../script.js'; import { getRegexedString, regex_placement } from './extensions/regex/engine.js'; import { getCurrentLocale, t, translate } from './i18n.js'; import { MacrosParser } from './macros.js'; @@ -1046,8 +1046,10 @@ function registerReasoningAppEvents() { message.mes = parsedReasoning.content; } - // Find if a message already exists in DOM and must be updated if (contentUpdated) { + syncMesToSwipe(); + + // Find if a message already exists in DOM and must be updated const messageRendered = document.querySelector(`.mes[mesid="${idx}"]`) !== null; if (messageRendered) { console.debug('[Reasoning] Updating message block', idx); From d28f39d77a07d40c45886b3cbe7310ffa72a97aa Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Tue, 25 Feb 2025 17:23:12 +0100 Subject: [PATCH 3/8] Save chat on reasoning parse --- public/scripts/reasoning.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/scripts/reasoning.js b/public/scripts/reasoning.js index 8c59da101..d475ca3f9 100644 --- a/public/scripts/reasoning.js +++ b/public/scripts/reasoning.js @@ -1048,6 +1048,7 @@ function registerReasoningAppEvents() { if (contentUpdated) { syncMesToSwipe(); + saveChatDebounced(); // Find if a message already exists in DOM and must be updated const messageRendered = document.querySelector(`.mes[mesid="${idx}"]`) !== null; From 7def85a1740af7cb89307c34b3f632477d089136 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 25 Feb 2025 21:21:59 +0200 Subject: [PATCH 4/8] Add couple of extra type checks --- public/script.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/script.js b/public/script.js index f0cf0ef80..f1049c7c9 100644 --- a/public/script.js +++ b/public/script.js @@ -6099,7 +6099,7 @@ export function syncMesToSwipe(messageId = null) { } const targetMessageId = messageId ?? chat.length - 1; - if (chat.length > targetMessageId) { + if (chat.length > targetMessageId || targetMessageId < 0) { console.warn(`[syncMesToSwipe] Invalid message ID: ${messageId}`); return false; } @@ -6120,7 +6120,7 @@ export function syncMesToSwipe(messageId = null) { } const targetSwipeInfo = targetMessage.swipe_info[targetMessage.swipe_id]; - if (typeof targetSwipeInfo !== 'object') { + if (!targetSwipeInfo || typeof targetSwipeInfo !== 'object') { return false; } From eceaa9cacccebc8f08213230986e9254f1aa30cb Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 25 Feb 2025 21:32:39 +0200 Subject: [PATCH 5/8] Replace debounced save with regular --- public/scripts/reasoning.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/scripts/reasoning.js b/public/scripts/reasoning.js index d475ca3f9..80629d3da 100644 --- a/public/scripts/reasoning.js +++ b/public/scripts/reasoning.js @@ -998,7 +998,7 @@ function parseReasoningFromString(str, { strict = true } = {}) { } function registerReasoningAppEvents() { - const eventHandler = (/** @type {number} */ idx) => { + const eventHandler = async (/** @type {number} */ idx) => { if (!power_user.reasoning.auto_parse) { return; } @@ -1048,7 +1048,7 @@ function registerReasoningAppEvents() { if (contentUpdated) { syncMesToSwipe(); - saveChatDebounced(); + await saveChatConditional(); // Find if a message already exists in DOM and must be updated const messageRendered = document.querySelector(`.mes[mesid="${idx}"]`) !== null; From 5545a425eacc83cea40281d742f0e2567f73e434 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 25 Feb 2025 21:34:04 +0200 Subject: [PATCH 6/8] No double check --- public/script.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/script.js b/public/script.js index f1049c7c9..3ce46d9d0 100644 --- a/public/script.js +++ b/public/script.js @@ -6120,7 +6120,7 @@ export function syncMesToSwipe(messageId = null) { } const targetSwipeInfo = targetMessage.swipe_info[targetMessage.swipe_id]; - if (!targetSwipeInfo || typeof targetSwipeInfo !== 'object') { + if (typeof targetSwipeInfo !== 'object') { return false; } From 422517ec93520c19bbfb65d3a5b755639c216f40 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 25 Feb 2025 21:38:24 +0200 Subject: [PATCH 7/8] Cancel debounced chat save if regular save is performed --- public/script.js | 9 ++++++++- public/scripts/reasoning.js | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/public/script.js b/public/script.js index 3ce46d9d0..111b7dfae 100644 --- a/public/script.js +++ b/public/script.js @@ -6436,6 +6436,7 @@ export function saveChatDebounced() { if (chatSaveTimeout) { console.debug('Clearing chat save timeout'); clearTimeout(chatSaveTimeout); + chatSaveTimeout = null; } chatSaveTimeout = setTimeout(async () => { @@ -6452,7 +6453,7 @@ export function saveChatDebounced() { console.debug('Chat save timeout triggered'); await saveChatConditional(); console.debug('Chat saved'); - }, 1000); + }, DEFAULT_SAVE_EDIT_TIMEOUT); } export async function saveChat(chatName, withMetadata, mesId) { @@ -8067,6 +8068,12 @@ export async function saveChatConditional() { } try { + if (chatSaveTimeout) { + console.debug('Debounced chat save canceled'); + clearTimeout(chatSaveTimeout); + chatSaveTimeout = null; + } + isChatSaving = true; if (selected_group) { diff --git a/public/scripts/reasoning.js b/public/scripts/reasoning.js index 80629d3da..66a9ee967 100644 --- a/public/scripts/reasoning.js +++ b/public/scripts/reasoning.js @@ -1048,7 +1048,7 @@ function registerReasoningAppEvents() { if (contentUpdated) { syncMesToSwipe(); - await saveChatConditional(); + saveChatDebounced(); // Find if a message already exists in DOM and must be updated const messageRendered = document.querySelector(`.mes[mesid="${idx}"]`) !== null; From 8b135f9ca3c7d305662a844afc0effbcc28916a3 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Tue, 25 Feb 2025 21:52:03 +0200 Subject: [PATCH 8/8] Remove async from event handler --- public/scripts/reasoning.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/reasoning.js b/public/scripts/reasoning.js index 66a9ee967..d475ca3f9 100644 --- a/public/scripts/reasoning.js +++ b/public/scripts/reasoning.js @@ -998,7 +998,7 @@ function parseReasoningFromString(str, { strict = true } = {}) { } function registerReasoningAppEvents() { - const eventHandler = async (/** @type {number} */ idx) => { + const eventHandler = (/** @type {number} */ idx) => { if (!power_user.reasoning.auto_parse) { return; }