diff --git a/index.html b/index.html index a781817..5ef7031 100644 --- a/index.html +++ b/index.html @@ -4330,6 +4330,12 @@ dry_allowed_length: 2, dry_sequence_breakers: ["\n", ":", "\"", "*"], sampler_order: [6, 0, 1, 3, 4, 2, 5], + memsnippet_enabled: false, // Memory snippets off by default + memsnippet_numOfSnippets: 3, // Number of snippets to include defaults to 3 + memsnippet_minSignificance: 0.01, // Must have the bare minimum of significance to be included + memsnippet_searchRange: 300, // Tokens to include in search + memsnippet_chunkSize: 600, // Size of memory chunks / snippets + memsnippet_chunkOverlap: 200 // Overlap between chunks }; var defaultsettings = JSON.parse(JSON.stringify(localsettings)); @@ -10541,6 +10547,12 @@ logitbiasdict = {}; wi_searchdepth = 0; wi_insertlocation = 0; + localsettings.memsnippet_enabled = false; + localsettings.memsnippet_numOfSnippets = 3; + localsettings.memsnippet_minSignificance = 0.01; + localsettings.memsnippet_searchRange = 300; + localsettings.memsnippet_chunkSize = 600; + localsettings.memsnippet_chunkOverlap = 200; current_anotetemplate = "[Author's note: <|>]"; regexreplace_data = []; placeholder_tags_data = []; @@ -11291,6 +11303,34 @@ } } + function getMaxAllowedCharacters(content, amountToTrimForContext) + { + //this is a hack since we dont have a proper tokenizer, but we can estimate 1 token per 3 characters + let chars_per_token = 3.0; + + //we try to detect attempts at coding which tokenize poorly. This usually happens when the average word length is high. + let avgwordlen = (1.0+content.length)/(1.0+countWords(content)); + if(avgwordlen>=7.8) + { + chars_per_token = 2.7; + } + + if (current_memory == null || current_memory.trim() == "") + { + //if there is no memory, then we can be a lot of lenient with the character counts since the backend will truncate excess anyway + chars_per_token = 4.8; + } + + if(is_using_kcpp_with_added_memory()) //easily handle overflow + { + chars_per_token = 6; + } + + chars_per_token = chars_per_token * (localsettings.token_count_multiplier*0.01) + + return Math.max(1, Math.floor((amountToTrimForContext) * chars_per_token) - 12); + } + function submit_generation() { warn_on_quit = true; @@ -11463,25 +11503,7 @@ let truncated_context = concat_gametext(true, "","","",false,true); //no need to truncate if memory is empty truncated_context = truncated_context.replace(/\xA0/g,' '); //replace non breaking space nbsp - //this is a hack since we dont have a proper tokenizer, but we can estimate 1 token per 3 characters - let chars_per_token = 3.0; - //we try to detect attempts at coding which tokenize poorly. This usually happens when the average word length is high. - let avgwordlen = (1.0+truncated_context.length)/(1.0+countWords(truncated_context)); - if(avgwordlen>=7.8) - { - chars_per_token = 2.7; - } - if (current_memory == null || current_memory.trim() == "") - { - //if there is no memory, then we can be a lot of lenient with the character counts since the backend will truncate excess anyway - chars_per_token = 4.8; - } - if(is_using_kcpp_with_added_memory()) //easily handle overflow - { - chars_per_token = 6; - } - chars_per_token = chars_per_token * (localsettings.token_count_multiplier*0.01); - let max_allowed_characters = Math.max(1, Math.floor((maxctxlen-maxgenamt) * chars_per_token) - 12); + let max_allowed_characters = getMaxAllowedCharacters(truncated_context, (maxctxlen - maxgenamt)) //for adventure mode, inject hidden context, even more if there's nothing in memory if (localsettings.opmode == 2 && localsettings.adventure_context_mod) @@ -11771,6 +11793,24 @@ truncated_anote = ""; } + // [LTM][START] + if (localsettings.memsnippet_enabled) + { + // Finds the relevant memory fragments, formats them in a similar way to an authors note and inserts them before WI + let ltmSnippets = SimilarityUtils.getMemForLastResponse(localsettings.memsnippet_numOfSnippets, localsettings.memsnippet_minSignificance, (maxctxlen - maxgenamt)) + if (ltmSnippets.length === 0) + { + console.log("No memory fragments found either as history is too short or no relevant content found") + } + else + { + console.log("Memory fragments", ltmSnippets) + let ltmContent = ltmSnippets.map(snippet => snippet.snippet).join("|") + wistr = `\n\n[Chat history: ${ltmContent}]\n\n` + wistr + } + } + // [LTM][END] + if(wi_insertlocation>0) { truncated_anote = wistr + truncated_anote; @@ -15805,9 +15845,12 @@ document.getElementById("memory_tab").classList.remove("active"); document.getElementById("wi_tab").classList.remove("active"); document.getElementById("token_tab").classList.remove("active"); + document.getElementById("memsnippet_tab").classList.remove("active"); document.getElementById("memory_tab_container").classList.add("hidden"); document.getElementById("wi_tab_container").classList.add("hidden"); document.getElementById("token_tab_container").classList.add("hidden"); + document.getElementById("memsnippet_tab_container").classList.add("hidden"); + switch (newtab) { case 0: document.getElementById("memory_tab").classList.add("active"); @@ -15818,6 +15861,10 @@ document.getElementById("wi_tab_container").classList.remove("hidden"); break; case 2: + document.getElementById("memsnippet_tab").classList.add("active"); + document.getElementById("memsnippet_tab_container").classList.remove("hidden"); + break; + case 3: document.getElementById("token_tab").classList.add("active"); document.getElementById("token_tab_container").classList.remove("hidden"); break; @@ -15854,6 +15901,8 @@ start_editing_wi(); update_wi(); + load_memsnippet(); + populate_placeholder_tags(); populate_regex_replacers(); @@ -16158,6 +16207,47 @@ document.getElementById("wi_insertlocation").value = wi_insertlocation; } + function load_memsnippet() { + document.getElementById("memsnippet_enabled").checked = localsettings.memsnippet_enabled; + document.getElementById("memsnippet_numOfSnippets").value = localsettings.memsnippet_numOfSnippets; + document.getElementById("memsnippet_minSignificance").value = localsettings.memsnippet_minSignificance; + document.getElementById("memsnippet_searchRange").value = localsettings.memsnippet_searchRange; + document.getElementById("memsnippet_chunkSize").value = localsettings.memsnippet_chunkSize; + document.getElementById("memsnippet_chunkOverlap").value = localsettings.memsnippet_chunkOverlap; + } + + function save_memsnippet() { + localsettings.memsnippet_enabled = (document.getElementById("memsnippet_enabled").checked ? true : false); + localsettings.memsnippet_numOfSnippets = parseInt(document.getElementById("memsnippet_numOfSnippets").value); + localsettings.memsnippet_minSignificance = parseFloat(document.getElementById("memsnippet_minSignificance").value); + localsettings.memsnippet_searchRange = parseInt(document.getElementById("memsnippet_searchRange").value); + localsettings.memsnippet_chunkSize = parseInt(document.getElementById("memsnippet_chunkSize").value); + localsettings.memsnippet_chunkOverlap = parseInt(document.getElementById("memsnippet_chunkOverlap").value); + } + + function validateMemInput(input) { + const chunkInputs = ["memsnippet_chunkOverlap", "memsnippet_chunkSize"] + + let notValid + if (chunkInputs.includes(input.id)) + { + notValid = parseInt(document.getElementById("memsnippet_chunkOverlap").value) >= parseInt(document.getElementById("memsnippet_chunkSize").value); + if (notValid) + { + chunkInputs.map(id => document.getElementById(id)).forEach(elem => elem.setCustomValidity("Chunk overlap cannot be greater than chunk size")) + } + else + { + chunkInputs.map(id => document.getElementById(id)).forEach(elem => elem.setCustomValidity("")) + } + } + notValid = !input?.validity?.valid; + + document.getElementById("memoryOkButton").disabled = notValid; + document.getElementById("memoryOkButton").title = notValid ? `${input.title}: ${input.validationMessage}` : ""; + input.reportValidity(); + } + var backLongPressTimer = null; function btn_back_longpress_start() { @@ -18302,7 +18392,8 @@
@@ -18386,6 +18477,67 @@
+ +
+
+
+ Enable memory snippets
+ +
+ +
+
Amount of memory snippets to include ?Controls + how many snippets of text from the memory are included based on the automatic + search
+ +
+
+
Minimum significance required for inclusion ?Controls + the minimum threshold for snippets to be included based on the automatic search, ranging + from 0 (any significance) to 1, which is a high degree of significance +
+ +
+
+
Amount of text to search by?Controls + the amount of text used to search, essentially the last n characters +
+ +
+
+
Chunk size ?Controls the size of each snippet being searched for +
+ +
+
+
Chunk overlap ?Controls the amount of overlap between each snippet, helping to reduce issues of contextual understanding +
+ +
+
+
Extra Stopping Sequences ?Triggers the text generator to stop generating early if this sequence appears, in addition to default stop sequences. If you want multiple sequences, separate them with the following delimiter: ||$||
@@ -18461,7 +18613,7 @@
- +
@@ -18918,4 +19070,503 @@ } + + + + + + + + + +