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 @@