From 11982c30d3a3e4ca454607a9604949815dfc5cac Mon Sep 17 00:00:00 2001 From: BlipRanger <1860540+BlipRanger@users.noreply.github.com> Date: Fri, 14 Jul 2023 01:12:13 -0400 Subject: [PATCH 01/39] Quick patch for overzealous checking --- server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.js b/server.js index 3d793f0b6..d20b69b65 100644 --- a/server.js +++ b/server.js @@ -1057,7 +1057,7 @@ app.post("/editcharacterattribute", jsonParser, async function (request, respons charaRead(avatarPath).then((char) => { char = JSON.parse(char); //check if the field exists - if (char[request.body.field] === undefined || char.data[request.body.field] === undefined) { + if (char[request.body.field] === undefined && char.data[request.body.field] === undefined) { console.error('Error: invalid field.'); response.status(400).send('Error: invalid field.'); return; From 5812e34dcbd6fc79342a64739438bdc600b50678 Mon Sep 17 00:00:00 2001 From: Cohee Date: Fri, 14 Jul 2023 13:12:46 +0300 Subject: [PATCH 02/39] Fix new chats with v2 imports --- server.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/server.js b/server.js index d20b69b65..9a1d40c91 100644 --- a/server.js +++ b/server.js @@ -761,7 +761,7 @@ function convertToV2(char) { tags: char.tags, }); - result.chat = char.chat; + result.chat = char.chat ?? humanizedISO8601DateTime(); result.create_date = char.create_date; return result; } @@ -820,6 +820,8 @@ function readFromV2(char) { char[charField] = v2Value; }); + char['chat'] = char['chat'] ?? humanizedISO8601DateTime(); + return char; } From 8987534403630366aec3a2cb9a044ad70c2f0ea1 Mon Sep 17 00:00:00 2001 From: Cohee Date: Fri, 14 Jul 2023 15:33:55 +0300 Subject: [PATCH 03/39] #709 Add extra type safety for token counting --- public/script.js | 4 ++++ public/scripts/utils.js | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/public/script.js b/public/script.js index ae4b1b185..232994772 100644 --- a/public/script.js +++ b/public/script.js @@ -552,6 +552,10 @@ async function getClientVersion() { } function getTokenCount(str, padding = undefined) { + if (typeof str !== 'string') { + return 0; + } + let tokenizerType = power_user.tokenizer; if (main_api === 'openai') { diff --git a/public/scripts/utils.js b/public/scripts/utils.js index 88a564b07..ff667b8b8 100644 --- a/public/scripts/utils.js +++ b/public/scripts/utils.js @@ -86,6 +86,10 @@ export async function parseJsonFile(file) { } export function getStringHash(str, seed = 0) { + if (typeof str !== 'string') { + return 0; + } + let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; for (let i = 0, ch; i < str.length; i++) { From 07c78391e1ea1a8cb00502558dbd90d6ce56ea15 Mon Sep 17 00:00:00 2001 From: Cohee Date: Fri, 14 Jul 2023 16:10:39 +0300 Subject: [PATCH 04/39] #708 Convert author's note to built-in function instead of extension --- public/index.html | 105 ++++++++++++++- public/script.js | 2 +- .../index.js => authors-note.js} | 126 ++---------------- public/scripts/extensions.js | 6 +- .../extensions/floating-prompt/manifest.json | 12 -- .../extensions/floating-prompt/style.css | 60 --------- public/scripts/world-info.js | 2 +- public/style.css | 61 +++++++++ 8 files changed, 179 insertions(+), 195 deletions(-) rename public/scripts/{extensions/floating-prompt/index.js => authors-note.js} (70%) delete mode 100644 public/scripts/extensions/floating-prompt/manifest.json delete mode 100644 public/scripts/extensions/floating-prompt/style.css diff --git a/public/index.html b/public/index.html index 30d9edf76..9f56e52c3 100644 --- a/public/index.html +++ b/public/index.html @@ -93,6 +93,7 @@ + SillyTavern @@ -3554,7 +3555,105 @@
CHAR is typing
-
+
+
+
+
+
+
+
+
+
+ Author's Note +
+
+
+ + Unique to this chat.
+ Bookmarks inherit the Note from their parent, and can be changed individually after that.
+
+ +
+ Tokens: 0 +
+ +
+ + +
+ + + + + (0 = Disable, 1 = Always) +
+ + User inputs until next insertion: (disabled) +
+
+
+
+
+ Character Author's Note +
+
+
+ Will be automatically added as the author's note for this character. Will be used in groups, but + can't be modified when a group chat is open. + + +
+ Tokens: 0 +
+ + +
+ + + +
+
+
+
+
+
+ Default Author's Note +
+
+
+ Will be automatically added as the Author's Note for all new chats. + + +
+ Tokens: 0 +
+
+
+
+
+
@@ -3580,6 +3679,10 @@ +
+
+
+
+
+
+
+
+
@@ -3847,4 +3856,4 @@ - \ No newline at end of file + diff --git a/public/script.js b/public/script.js index 88949952c..c6b546ce4 100644 --- a/public/script.js +++ b/public/script.js @@ -966,22 +966,25 @@ async function getBackgrounds() { const getData = await response.json(); //background = getData; //console.log(getData.length); + $("#bg_menu_content").empty(); for (const bg of getData) { - const thumbPath = getThumbnailUrl('bg', bg); - $("#bg_menu_content").append( - `
-
-
- ${bg - .replace('.png', '') - .replace('.jpg', '') - .replace('.webp', '')} -
-
` - ); + const template = getBackgroundFromTemplate(bg); + $("#bg_menu_content").append(template); } } } + +function getBackgroundFromTemplate(bg) { + const thumbPath = getThumbnailUrl('bg', bg); + const template = $('#background_template .bg_example').clone(); + template.attr('bgfile', bg); + template.attr('title', bg); + template.find('.bg_button').attr('bgfile', bg); + template.css('background-image', `url('${thumbPath}')`); + template.find('.BGSampleTitle').text(bg.slice(0, bg.lastIndexOf('.'))); + return template; +} + async function isColab() { is_checked_colab = true; const response = await fetch("/iscolab", { @@ -5673,11 +5676,7 @@ function read_bg_load(input) { "background-image", `url("${e.target.result}")` ); - $("#form_bg_download").after( - `
-
-
` - ); + $("#form_bg_download").after(getBackgroundFromTemplate(html)); }, error: function (jqXHR, exception) { console.log(exception); @@ -7074,6 +7073,41 @@ $(document).ready(function () { }); }); + + $(document).on('click', '.bg_example_edit', async function (e) { + e.stopPropagation(); + const old_bg = $(this).attr('bgfile'); + + if (!old_bg) { + console.debug('no bgfile'); + return; + } + + const fileExtension = old_bg.split('.').pop(); + const old_bg_extensionless = old_bg.replace(`.${fileExtension}`, ''); + const new_bg_extensionless = await callPopup('

Enter new background name:

', 'input', old_bg_extensionless); + const new_bg = `${new_bg_extensionless}.${fileExtension}`; + + if (old_bg_extensionless === new_bg_extensionless) { + console.debug('new_bg === old_bg'); + return; + } + + const data = { old_bg, new_bg }; + const response = await fetch('/renamebackground', { + method: 'POST', + headers:getRequestHeaders(), + body: JSON.stringify(data), + cache: 'no-cache', + }); + + if (response.ok) { + await getBackgrounds(); + } else { + toastr.warning('Failed to rename background'); + } + }); + $(document).on("click", ".bg_example_cross", function (e) { e.stopPropagation(); bg_file_for_del = $(this); diff --git a/public/style.css b/public/style.css index 4f9556170..fef8a876c 100644 --- a/public/style.css +++ b/public/style.css @@ -1626,6 +1626,7 @@ body.big-avatars .ch_description { cursor: pointer; aspect-ratio: 16/9; justify-content: flex-end; + position: relative; } .BGSampleTitle { @@ -1642,12 +1643,10 @@ body.big-avatars .ch_description { font-size: calc(var(--fontScale) * 0.9em); } -.bg_example_cross { +.bg_button { width: 15px; height: 15px; - position: relative; - /* float: right; */ - right: 10px; + position: absolute; top: 5px; cursor: pointer; opacity: 0.7; @@ -1658,6 +1657,19 @@ body.big-avatars .ch_description { padding: 0; margin: 0; filter: drop-shadow(0px 0px 3px white); + transition: opacity 0.2s ease-in-out; +} + +.bg_button:hover { + opacity: 1; +} + +.bg_example_cross { + right: 10px; +} + +.bg_example_edit { + left: 10px; } .no-border { @@ -5383,4 +5395,4 @@ body.waifuMode .zoomed_avatar { background-color: var(--SmartThemeBlurTintColor); text-align: center; line-height: 14px; -} \ No newline at end of file +} diff --git a/server.js b/server.js index e6e79cba8..96c34bbda 100644 --- a/server.js +++ b/server.js @@ -1338,6 +1338,27 @@ app.post("/delchat", jsonParser, function (request, response) { return response.send('ok'); }); +app.post('/renamebackground', jsonParser, function (request, response) { + if (!request.body) return response.sendStatus(400); + + const oldFileName = path.join('public/backgrounds/', sanitize(request.body.old_bg)); + const newFileName = path.join('public/backgrounds/', sanitize(request.body.new_bg)); + + if (!fs.existsSync(oldFileName)) { + console.log('BG file not found'); + return response.sendStatus(400); + } + + if (fs.existsSync(newFileName)) { + console.log('New BG file already exists'); + return response.sendStatus(400); + } + + fs.renameSync(oldFileName, newFileName); + invalidateThumbnail('bg', request.body.old_bg); + return response.send('ok'); +}); + app.post("/downloadbackground", urlencodedParser, function (request, response) { response_dw_bg = response; if (!request.body || !request.file) return response.sendStatus(400); From f8e2730fd6ea6ed822c257f9198f9a00cbb67d85 Mon Sep 17 00:00:00 2001 From: breathingmanually <136247862+breathingmanually@users.noreply.github.com> Date: Tue, 18 Jul 2023 00:57:17 -0300 Subject: [PATCH 35/39] Fix parameters not substituted when editing first message --- public/script.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/script.js b/public/script.js index c6b546ce4..7f0a9a44c 100644 --- a/public/script.js +++ b/public/script.js @@ -5165,7 +5165,10 @@ function messageEditAuto(div) { } async function messageEditDone(div) { - const { mesBlock, text, mes, bias } = updateMessage(div); + let { mesBlock, text, mes, bias } = updateMessage(div); + if (this_edit_mes_id == 0) { + text = substituteParams(text); + } mesBlock.find(".mes_text").empty(); mesBlock.find(".mes_edit_buttons").css("display", "none"); From eb90162579744d3ae5efe8327d81d310d9933af3 Mon Sep 17 00:00:00 2001 From: kingbri Date: Tue, 18 Jul 2023 00:13:51 -0400 Subject: [PATCH 36/39] Regex: Fix overlay for multiple occurrences If there are multiple occurrences of a prefix or suffix within the input string, remove them when overlaying. Signed-off-by: kingbri --- public/scripts/extensions/regex/engine.js | 35 ++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/public/scripts/extensions/regex/engine.js b/public/scripts/extensions/regex/engine.js index cab687c90..7b1042115 100644 --- a/public/scripts/extensions/regex/engine.js +++ b/public/scripts/extensions/regex/engine.js @@ -128,19 +128,46 @@ function substituteRegexParams(rawString, regexMatch, { characterOverride, repla finalString = substituteParams(finalString, undefined, characterOverride); let overlaidMatch = regexMatch; + // TODO: Maybe move the for loops into a separate function? if (replaceStrategy === regex_replace_strategy.OVERLAY) { const splitReplace = finalString.split("{{match}}"); // There's a prefix if (splitReplace[0]) { + // Fetch the prefix const splicedPrefix = spliceSymbols(splitReplace[0], false); - overlaidMatch = overlaidMatch.replace(splicedPrefix, "").trim(); + + // Sequentially remove all occurrences of prefix from start of split + const splitMatch = overlaidMatch.split(splicedPrefix); + let sliceNum = 0; + for (let index = 0; index < splitMatch.length; index++) { + if (splitMatch[index].length === 0) { + sliceNum++; + } else { + break; + } + } + + overlaidMatch = splitMatch.slice(sliceNum, splitMatch.length).join(splicedPrefix); } // There's a suffix if (splitReplace[1]) { + // Fetch the suffix const splicedSuffix = spliceSymbols(splitReplace[1], true); - overlaidMatch = overlaidMatch.replace(new RegExp(`${splicedSuffix}$`), "").trim(); + + // Sequential removal of all suffix occurrences from end of split + const splitMatch = overlaidMatch.split(splicedSuffix); + let sliceNum = 0; + for (let index = splitMatch.length - 1; index >= 0; index--) { + if (splitMatch[index].length === 0) { + sliceNum++; + } else { + break; + } + } + + overlaidMatch = splitMatch.slice(0, splitMatch.length - sliceNum).join(splicedSuffix); } } @@ -150,7 +177,7 @@ function substituteRegexParams(rawString, regexMatch, { characterOverride, repla return finalString; } -// Splices symbols and whitespace from the beginning and end of a string +// Splices common sentence symbols and whitespace from the beginning and end of a string // Using a for loop due to sequential ordering function spliceSymbols(rawString, isSuffix) { let offset = 0; @@ -163,5 +190,5 @@ function spliceSymbols(rawString, isSuffix) { } } - return isSuffix ? rawString.substring(0, rawString.length - offset) : rawString.substring(offset);; + return isSuffix ? rawString.substring(0, rawString.length - offset) : rawString.substring(offset); } From d61eba4cb4e0a29c446bbc3e80ea61169bc08e95 Mon Sep 17 00:00:00 2001 From: kingbri Date: Tue, 18 Jul 2023 01:09:00 -0400 Subject: [PATCH 37/39] Regex: Add script reordering The engine runs with a foreach, so the scripts run sequentially. Ideally, scripts should be one-liners, but if multiple scripts run in a chain, allow the user to reorder them. Signed-off-by: kingbri --- public/scripts/extensions/regex/index.js | 20 +++++++++++++++++++ .../extensions/regex/scriptTemplate.html | 1 + 2 files changed, 21 insertions(+) diff --git a/public/scripts/extensions/regex/index.js b/public/scripts/extensions/regex/index.js index cb84876ae..610fe5e09 100644 --- a/public/scripts/extensions/regex/index.js +++ b/public/scripts/extensions/regex/index.js @@ -236,5 +236,25 @@ jQuery(async () => { onRegexEditorOpenClick(false); }); + $('#saved_regex_scripts').sortable({ + stop: function () { + let newScripts = []; + $('#saved_regex_scripts').children().each(function () { + const scriptName = $(this).find(".regex_script_name").text(); + const existingScript = extension_settings.regex.find((e) => e.scriptName === scriptName); + if (existingScript) { + newScripts.push(existingScript); + } + }); + + extension_settings.regex = newScripts; + saveSettingsDebounced(); + + console.debug("Regex scripts reordered"); + // TODO: Maybe reload regex scripts after move + }, + }); + await loadRegexScripts(); + $("#saved_regex_scripts").sortable("enable"); }); diff --git a/public/scripts/extensions/regex/scriptTemplate.html b/public/scripts/extensions/regex/scriptTemplate.html index 382e20c48..6f2c758f8 100644 --- a/public/scripts/extensions/regex/scriptTemplate.html +++ b/public/scripts/extensions/regex/scriptTemplate.html @@ -1,4 +1,5 @@
+