mirror of
https://github.com/LostRuins/koboldcpp.git
synced 2025-09-10 17:14:36 +00:00
Allow override config for gguf files when reloading in admin mode, updated lite, fixed typo (+1 squashed commits)
Squashed commits: [fe14845cc] Allow override config for gguf files when reloading in admin mode, updated lite (+2 squashed commit) Squashed commit: [9ded66aa5] Allow override config for gguf files when reloading in admin mode [9597f6a34] update lite
This commit is contained in:
parent
bfb47cbcd8
commit
238be98efa
2 changed files with 387 additions and 26 deletions
382
klite.embd
382
klite.embd
|
@ -12,7 +12,7 @@ Current version indicated by LITEVER below.
|
|||
-->
|
||||
|
||||
<script>
|
||||
const LITEVER = 252;
|
||||
const LITEVER = 253;
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
var localflag = urlParams.get('local'); //this will be replaced automatically in embedded kcpp
|
||||
const STORAGE_PREFIX = (localflag?"e_":"")+"kaihordewebui_";
|
||||
|
@ -2206,6 +2206,18 @@ Current version indicated by LITEVER below.
|
|||
.color_pink {
|
||||
color: #ffbdbd;
|
||||
}
|
||||
.color_wordsearch_target
|
||||
{
|
||||
color: violet;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: violet;
|
||||
}
|
||||
.color_wordsearch_surrounding
|
||||
{
|
||||
color: yellow;
|
||||
text-decoration: underline;
|
||||
text-decoration-color: yellow;
|
||||
}
|
||||
|
||||
.bg_black {
|
||||
background-color: #202020;
|
||||
|
@ -3085,6 +3097,7 @@ Current version indicated by LITEVER below.
|
|||
const HD_RES_PX = 768;
|
||||
const VHD_RES_PX = 960;
|
||||
const NO_HD_RES_PX = 512;
|
||||
const PREVIEW_RES_PX = 200;
|
||||
const AVATAR_PX = 384;
|
||||
const SAVE_SLOTS = 10;
|
||||
const num_regex_rows = 4;
|
||||
|
@ -3367,6 +3380,7 @@ Current version indicated by LITEVER below.
|
|||
websearch_multipass: false,
|
||||
websearch_retain: false,
|
||||
websearch_template: "",
|
||||
wordsearch_enabled: false,
|
||||
|
||||
max_context_length: (localflag?4096:2048),
|
||||
max_length: (localflag?512:256),
|
||||
|
@ -11150,6 +11164,7 @@ Current version indicated by LITEVER below.
|
|||
el.value = values[i];
|
||||
dropdown.appendChild(el);
|
||||
}
|
||||
change_admin_config_selection();
|
||||
document.getElementById("admincontainer").classList.remove("hidden");
|
||||
}
|
||||
else
|
||||
|
@ -11175,6 +11190,36 @@ Current version indicated by LITEVER below.
|
|||
}
|
||||
}
|
||||
|
||||
function change_admin_config_selection()
|
||||
{
|
||||
let targetfile = document.getElementById("adminconfigdropdown").value;
|
||||
if(targetfile && targetfile.endsWith(".gguf"))
|
||||
{
|
||||
let overridedropdown = document.getElementById("adminconfigoverridedropdown");
|
||||
overridedropdown.classList.remove("hidden");
|
||||
var dropdown = document.getElementById("adminconfigdropdown");
|
||||
for (var i = overridedropdown.options.length; i >= 0; i--) {
|
||||
var option = overridedropdown.options[i];
|
||||
overridedropdown.remove(option);
|
||||
}
|
||||
var el = document.createElement("option");
|
||||
el.textContent = "Default Config";
|
||||
el.value = "";
|
||||
overridedropdown.appendChild(el);
|
||||
for(var i=0;i<dropdown.options.length;++i)
|
||||
{
|
||||
let str = dropdown.options[i].value;
|
||||
if(str.endsWith(".gguf") || str=="unload_model")
|
||||
{continue;}
|
||||
var el = document.createElement("option");
|
||||
el.textContent = str;
|
||||
el.value = str;
|
||||
overridedropdown.appendChild(el);
|
||||
}
|
||||
}else{
|
||||
document.getElementById("adminconfigoverridedropdown").classList.add("hidden");
|
||||
}
|
||||
}
|
||||
var adminrebootflag = 0;
|
||||
function trigger_admin_reload()
|
||||
{
|
||||
|
@ -11185,7 +11230,14 @@ Current version indicated by LITEVER below.
|
|||
msgbox("No config file was selected.");
|
||||
return;
|
||||
}
|
||||
|
||||
let header = {'Content-Type': 'application/json'};
|
||||
let payload = {"filename": targetfile};
|
||||
if(!document.getElementById("adminconfigoverridedropdown").classList.contains("hidden"))
|
||||
{
|
||||
payload["overrideconfig"] = document.getElementById("adminconfigoverridedropdown").value;
|
||||
}
|
||||
|
||||
if(last_admin_key!="")
|
||||
{
|
||||
header['Authorization'] = 'Bearer ' + last_admin_key;
|
||||
|
@ -11193,9 +11245,7 @@ Current version indicated by LITEVER below.
|
|||
fetch(custom_kobold_endpoint + koboldcpp_admin_reload_endpoint, {
|
||||
method: 'POST',
|
||||
headers: header,
|
||||
body: JSON.stringify({
|
||||
"filename": targetfile
|
||||
})
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
.then(x => x.json())
|
||||
.then(values => {
|
||||
|
@ -12353,6 +12403,7 @@ Current version indicated by LITEVER below.
|
|||
document.getElementById("run_in_background").checked = run_in_background;
|
||||
document.getElementById("auto_ctxlen").checked = localsettings.auto_ctxlen;
|
||||
document.getElementById("auto_genamt").checked = localsettings.auto_genamt;
|
||||
document.getElementById("wordsearch_toggle").checked = localsettings.wordsearch_enabled;
|
||||
if(localflag)
|
||||
{
|
||||
document.getElementById("auto_ctxlen_panel").classList.add("hidden");
|
||||
|
@ -12943,6 +12994,7 @@ Current version indicated by LITEVER below.
|
|||
localsettings.voice_langcode = document.getElementById("voice_langcode").value;
|
||||
localsettings.auto_ctxlen = (document.getElementById("auto_ctxlen").checked ? true : false);
|
||||
localsettings.auto_genamt = (document.getElementById("auto_genamt").checked ? true : false);
|
||||
localsettings.wordsearch_enabled = (document.getElementById("wordsearch_toggle").checked ? true : false);
|
||||
|
||||
localsettings.image_styles = document.getElementById("imagestyleinput").value;
|
||||
localsettings.image_negprompt = document.getElementById("negpromptinput").value;
|
||||
|
@ -13240,9 +13292,20 @@ Current version indicated by LITEVER below.
|
|||
function toggle_uistyle()
|
||||
{
|
||||
//show or hide the 'Customize UI' button based on whether the Aesthetic Instruct UI Mode is active or not.
|
||||
if (document.getElementById('gui_type').value==2) { document.getElementById('btn_aesthetics').classList.remove('hidden'); }
|
||||
else { document.getElementById('btn_aesthetics').classList.add('hidden'); }
|
||||
if (document.getElementById('gui_type').value == 2) {
|
||||
document.getElementById('btn_aesthetics').classList.remove('hidden');
|
||||
}
|
||||
else {
|
||||
document.getElementById('btn_aesthetics').classList.add('hidden');
|
||||
}
|
||||
document.getElementById("guitypedesc").innerText = get_theme_desc(document.getElementById('gui_type').value);
|
||||
|
||||
if (document.getElementById('gui_type').value == 0) {
|
||||
document.getElementById('classicmodeoptions').classList.remove('hidden');
|
||||
}
|
||||
else {
|
||||
document.getElementById('classicmodeoptions').classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function select_welcome_ui()
|
||||
|
@ -13345,8 +13408,12 @@ Current version indicated by LITEVER below.
|
|||
document.getElementById('gui_type').value = 0;
|
||||
}
|
||||
|
||||
if (document.getElementById('gui_type').value==2) { document.getElementById('btn_aesthetics').classList.remove('hidden'); }
|
||||
else { document.getElementById('btn_aesthetics').classList.add('hidden'); }
|
||||
if (document.getElementById('gui_type').value == 2) {
|
||||
document.getElementById('btn_aesthetics').classList.remove('hidden');
|
||||
}
|
||||
else {
|
||||
document.getElementById('btn_aesthetics').classList.add('hidden');
|
||||
}
|
||||
|
||||
toggle_uistyle();
|
||||
}
|
||||
|
@ -13642,6 +13709,17 @@ Current version indicated by LITEVER below.
|
|||
}
|
||||
}
|
||||
|
||||
function simplecssexample()
|
||||
{
|
||||
let simplemodscript = `/* This custom CSS changes all buttons to yellow */
|
||||
.btn-primary {
|
||||
color: black!important;
|
||||
background-color: yellow!important;
|
||||
border-color: black!important;
|
||||
}
|
||||
`;
|
||||
document.getElementById("inputboxcontainerinputarea").value = simplemodscript;
|
||||
}
|
||||
function simplemodexample()
|
||||
{
|
||||
let simplemodscript = `// This mod changes your top menu to a yellow gradient, then displays the current temperature setting as a popup\n`
|
||||
|
@ -13665,7 +13743,7 @@ Current version indicated by LITEVER below.
|
|||
}
|
||||
}
|
||||
} catch (e) { }
|
||||
let txt = `Here, you can apply third-party mod scripts shared by other users.<br><br><span class='color_red'>Caution: This mod will have full access to your story and API keys, so only run third-party mods that you trust!<br><br>Mods must always be manually applied every time unless 'Apply Mod On Startup' is selected. If a startup mod breaks KoboldAI Lite, add ?resetmod=1 to the url to uninstall it.</span><br><br>Want to start modding? <a href='#' class='color_blueurl' onclick='simplemodexample()'>Click here</a> to load a simple example mod.<br><br><div><span>Apply Mod On Startup? (Extreme Caution!) </span><input type='checkbox' id='apply_mod_on_start' style='vertical-align: top;' ${applyonstart?'checked':''}></div>`;
|
||||
let txt = `Here, you can apply third-party mod scripts shared by other users.<br><br><span class='color_red'>Caution: This mod will have full access to your story and API keys, so only run third-party mods that you trust!<br><br>Mods must always be manually applied every time unless 'Apply Mod On Startup' is selected. If a startup mod breaks KoboldAI Lite, add ?resetmod=1 to the url to uninstall it.</span><br><br>Want to start modding? <a href='#' class='color_blueurl' onclick='simplemodexample()'>Click here</a> to load a simple example mod.<br><br><div><span>Apply Mod On Startup? (Extreme Caution!) </span><input type='checkbox' id='apply_mod_on_start' style='vertical-align: top;' ${applyonstart?'checked':''}></div><div><button type="button" class="btn btn-primary" onclick="load_inputbox_from_file()">Import UserMod From File</button></div>`;
|
||||
inputBoxOkCancel(txt,"Apply Third-Party Mod",currmod,"Paste Mod Script Here",()=>{
|
||||
let userinput = getInputBoxValue().trim();
|
||||
applyonstart = (document.getElementById("apply_mod_on_start").checked?true:false);
|
||||
|
@ -13683,18 +13761,42 @@ Current version indicated by LITEVER below.
|
|||
});
|
||||
});
|
||||
}
|
||||
function load_inputbox_from_file()
|
||||
{
|
||||
promptUserForLocalFile((fileDetails) => {
|
||||
try {
|
||||
let { file, fileName, ext, content, plaintext } = fileDetails;
|
||||
if(plaintext && plaintext!="")
|
||||
{
|
||||
if(document.getElementById("inputboxcontainerinputarea").classList.contains("hidden"))
|
||||
{
|
||||
document.getElementById("inputboxcontainerinput").value = plaintext;
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById("inputboxcontainerinputarea").value = plaintext;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
console.log("Load Inputbox File Failed: " + e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sanitize_css(input)
|
||||
{
|
||||
input = input.replace(/<\s*\/?\s*\w+\s*[^>]*>/gi, ""); //replace html tags
|
||||
input = input.replace(/</g, ""); // Remove any remaining `<` characters
|
||||
input = input.replace(/(?:javascript|data|vbscript|file):/gi, "");
|
||||
input = input.replace(/<\s*\/?\s*\w+\s*[^>]*>/gi, "");
|
||||
input = input.replace(/</g, "");
|
||||
input = input.replace(/(?:javascript|vbscript|file):/gi, "");
|
||||
//remove all data elements that aren't jpg, png, gif, webp;base64
|
||||
input = input.replace(/data:(?!image\/(jpeg|png|gif|webp);base64,)[^)'";\s]*/gi, "");
|
||||
return input;
|
||||
}
|
||||
function apply_custom_css()
|
||||
{
|
||||
indexeddb_load("savedcustomcss","").then(currcss=>{
|
||||
inputBoxOkCancel("Here, you can apply third-party custom CSS styles shared by other users.<br><br><span class='color_red'>Caution: This will modify the existing document, so only use third-party CSS styles that you trust! Custom CSS is persistent, but can be reset in this menu.</span><br><br>You can return to default styles by clearing the box below. If you get stuck, add ?resetcss=1 to the URL to clear custom styles.","Apply Custom CSS Styles",currcss,"Paste CSS Styles Here",()=>{
|
||||
inputBoxOkCancel(`Here, you can apply third-party custom CSS styles shared by other users.<br><br><span class='color_red'>Caution: This will modify the existing document, so only use third-party CSS styles that you trust! Custom CSS is persistent, but can be reset in this menu.</span><br><br>Need help? <a href='#' class='color_blueurl' onclick='simplecssexample()'>Click here</a> to load a simple example CSS theme. You can return to default styles by clearing the box below. If you get stuck, add ?resetcss=1 to the URL to clear custom styles. <div><button type="button" class="btn btn-primary" onclick="load_inputbox_from_file()">Import CSS From File</button></div>`,"Apply Custom CSS Styles",currcss,"Paste CSS Styles Here",()=>{
|
||||
let userinput = sanitize_css(getInputBoxValue().trim());
|
||||
indexeddb_save("savedcustomcss", userinput);
|
||||
let styleElement = document.getElementById('custom_css');
|
||||
|
@ -13783,6 +13885,8 @@ Current version indicated by LITEVER below.
|
|||
document.getElementById("input_text").value = "";
|
||||
document.getElementById("corpo_cht_inp").value = "";
|
||||
document.getElementById("cht_inp").value = "";
|
||||
let wsresultsContainer = document.getElementById("wordsearch_results");
|
||||
if(wsresultsContainer){wsresultsContainer.innerHTML="";}
|
||||
chat_resize_input();
|
||||
image_db = {};
|
||||
interrogation_db = {};
|
||||
|
@ -17378,7 +17482,7 @@ Current version indicated by LITEVER below.
|
|||
}
|
||||
|
||||
function render_image_html(data, pend_txt = "", siclass="storyimgfloat") {
|
||||
var dim = (localsettings.opmode == 2 ? 160 : 180); //adventure mode has smaller pictures
|
||||
var dim = PREVIEW_RES_PX; //image preview. adventure mode has smaller pictures
|
||||
dimW = dim;
|
||||
dimH = dim;
|
||||
let reinvertcolor = localsettings.invert_colors?" invert_colors":"";
|
||||
|
@ -19792,6 +19896,14 @@ Current version indicated by LITEVER below.
|
|||
{
|
||||
document.getElementById("searchingtxt").classList.add("hidden");
|
||||
}
|
||||
|
||||
if(localsettings.wordsearch_enabled)
|
||||
{
|
||||
document.getElementById("wordsearch_panel").classList.remove("hidden");
|
||||
}else
|
||||
{
|
||||
document.getElementById("wordsearch_panel").classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function render_corpo_welcome()
|
||||
|
@ -21702,7 +21814,7 @@ Current version indicated by LITEVER below.
|
|||
}
|
||||
|
||||
this.code_block_background = 'rgb(0, 0, 0)';
|
||||
this.code_block_foreground = 'rgb(180, 35, 40)';
|
||||
this.code_block_foreground = 'rgb(210, 50, 50)';
|
||||
}
|
||||
|
||||
padding() { return `${this.background_padding[2]}px ${this.background_padding[1]}px ${this.background_padding[3]}px ${this.background_padding[0]}px`; }
|
||||
|
@ -22005,6 +22117,11 @@ Current version indicated by LITEVER below.
|
|||
`<style>
|
||||
.you-portrait-image`+classSuffixStr+` {margin: 10px 6px; background:url(`+ as.you_portrait +`); background-clip: content-box; background-position: 50% 50%; background-size: 100% 100%; background-origin: content-box; background-repeat: no-repeat; border:none;}
|
||||
.AI-portrait-image`+classSuffixStr+` {margin: 10px 6px; background:url(`+ (as.AI_portrait!="default"?as.AI_portrait:niko_square) +`); background-clip: content-box; background-position: 50% 50%; background-size: 100% 100%; background-origin: content-box; background-repeat: no-repeat; border:none;}
|
||||
code
|
||||
{
|
||||
color: ${as.code_block_foreground};
|
||||
background-color: ${as.code_block_background};
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
|
||||
|
@ -22167,7 +22284,7 @@ Current version indicated by LITEVER below.
|
|||
});
|
||||
}
|
||||
else {
|
||||
blocks[i] = blocks[i].replaceAll('```', '`').replaceAll('``', '`').replace(/`(.*?)`/g, function (m,m2) {return `<code style='background-color:black'>${m2.replace(/[“”]/g, "\"")}</code>`;}); //remove fancy quotes too
|
||||
blocks[i] = blocks[i].replaceAll('```', '`').replaceAll('``', '`').replace(/`(.*?)`/g, function (m,m2) {return `<code>${m2.replace(/[“”]/g, "\"")}</code>`;}); //remove fancy quotes too
|
||||
}
|
||||
}
|
||||
return [blocks.join(''),codestashes];
|
||||
|
@ -22194,7 +22311,7 @@ Current version indicated by LITEVER below.
|
|||
}
|
||||
|
||||
function updateTextPreview() {
|
||||
let preview = `You are Mikago, a prestigious bot that's a supervillain.\n\nRoleplay in first person, be prestigious, don't be a bot. This is a fantasy world.\n\nCode blocks should be wrapped in triple backticks, like so:\n\`\`\`\n<Some_\n-- multiline\n--- code here$\n\`\`\`\n[AI_REPLY]\n*takes my hat off to greet the squad* "Greetings, I am Mikago, the prestigious!" *bows to the crew*\n*clears my throat* "Now, I'm sure there are many questions, but all will be answered in due time." *deep breath*\n[USER_REPLY]\n*draws my sword* "Yes. You should know the code to calculate the factorial of a number."\nThe crew also draws their weapons and point them at you, not giving you any space.\n[AI_REPLY]\n*backs off* "Woah, easy there.." *makes some steps backwards, but then stops*\n"I would normally take this as an insult to my prestige, but I understand your caution.." *takes a deep breath*\n"Well, if it's to prove myself, here goes the python code to calculate the factorial of a number.."\n\nMikago opens a live-code-portal with his magic and writes the code that was requested.\n\`\`\`\ndef factorial(n):\n if n == 0:\n return 1\n else:\n return n * factorial(n-1)\n\`\`\`\n*looks at you, getting impatient* "Are we ok now.. or do you want me to write the code of a game next?"\n[USER_REPLY]\n*sheathes my sword and approaches for a hug* "Oh, Mikago, my old friend, it is really you!"`;
|
||||
let preview = `You are Mikago, a prestigious bot that's a supervillain.\n\nRoleplay in first person, be prestigious, don't be a bot. This is a fantasy world.\n\nCode blocks should be wrapped in triple backticks, like so:\n\`\`\`\n-- multiline\n--- code here\n\`\`\`\n[AI_REPLY]\n*takes my hat off to greet the squad* "Greetings, I am Mikago, the prestigious!" *bows to the crew*\n*clears my throat* "Now, I'm sure there are many questions, but all will be answered in due time." *deep breath*\n[USER_REPLY]\n*draws my sword* "Yes. You should know the code to calculate the factorial of a number."\nThe crew also draws their weapons and point them at you, not giving you any space.\n[AI_REPLY]\n*backs off* "Woah, easy there.." *makes some steps backwards, but then stops*\n"I would normally take this as an insult to my prestige, but I understand your caution.." *takes a deep breath*\n"Well, if it's to prove myself, here goes the python code to calculate the factorial of a number.."\n\nMikago opens a live-code-portal with his magic and writes the code that was requested.\n\`\`\`\ndef factorial(n):\n if n == 0:\n return 1\n else:\n return n * factorial(n-1)\n\`\`\`\n*looks at you, getting impatient* "Are we ok now.. or do you want me to write the code of a game next?"\n[USER_REPLY]\n*sheathes my sword and approaches for a hug* "Oh, Mikago, my old friend, it is really you!"`;
|
||||
|
||||
if(localsettings.opmode==3)
|
||||
{
|
||||
|
@ -22654,6 +22771,209 @@ Current version indicated by LITEVER below.
|
|||
return searchResults;
|
||||
}
|
||||
});
|
||||
|
||||
/** Inspired by My Ghost Writer from trincadev - https://github.com/trincadev/my_ghost_writer */
|
||||
//scan through full context to ngram a possible set of candidates
|
||||
function trigger_wordsearch_candidates() {
|
||||
const searchBox = document.getElementById("wordsearch_input");
|
||||
const resultsContainer = document.getElementById("wordsearch_results");
|
||||
const sortByFreq = document.getElementById("wordsearch_sort").value=="0";
|
||||
const query = searchBox.value.trim();
|
||||
resultsContainer.innerHTML = "";
|
||||
|
||||
let ngramParser = function (text, n) {
|
||||
const words = text.split(/ +/).filter(word => word.length > 0);
|
||||
const ngrams = {};
|
||||
let prevNgram = null;
|
||||
|
||||
for (let i = 0; i <= words.length - n; i++) {
|
||||
let ngram = words.slice(i, i + n).join(' ');
|
||||
//strip leading and trailing punctuation
|
||||
ngram = ngram.replace(/^[,\.?!()\[\]{}\`:;\-\'\"—]+|[,\.?!()\[\]{}\`:;\-\'\"—]+$/g, '');
|
||||
if (ngram === prevNgram) continue; // skip duplicate overlaps
|
||||
prevNgram = ngram;
|
||||
|
||||
if (ngrams[ngram]) {
|
||||
ngrams[ngram]++;
|
||||
} else {
|
||||
ngrams[ngram] = 1;
|
||||
}
|
||||
}
|
||||
const sortedNgrams = Object.entries(ngrams).sort((a, b) => b[1] - a[1]);
|
||||
return sortedNgrams.map(entry => ({ ng: entry[0], cnt: entry[1] }));
|
||||
};
|
||||
|
||||
let prepare_candidates_from_text = function(query) {
|
||||
const fullgametext = concat_gametext(true, "").toLowerCase();
|
||||
let querylc = query.toLowerCase();
|
||||
let candidateDict = {};
|
||||
|
||||
let textrows = fullgametext.split("\n").filter(x=>x);
|
||||
|
||||
for(let l=0;l<textrows.length;++l)
|
||||
{
|
||||
for(let i=1;i<=3;++i) //ngram of 3
|
||||
{
|
||||
let res = ngramParser(textrows[l],i);
|
||||
if(querylc!="")
|
||||
{
|
||||
res = res.filter(x=>x.ng.toLowerCase().includes(querylc));
|
||||
}
|
||||
let lim = Math.min(res.length,250);
|
||||
for(let j=0;j<lim;++j)
|
||||
{
|
||||
if (!candidateDict[res[j].ng]) {
|
||||
candidateDict[res[j].ng] = res[j].cnt;
|
||||
} else {
|
||||
candidateDict[res[j].ng] += res[j].cnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//todo: counts are not correct because of substrings. let's manually count each item for now
|
||||
for(let key in candidateDict)
|
||||
{
|
||||
candidateDict[key] = (fullgametext.split(key).length - 1);
|
||||
}
|
||||
|
||||
if(querylc!="")
|
||||
{
|
||||
let basecount = (fullgametext.split(querylc).length - 1); //count of the pure substring
|
||||
candidateDict[query] = basecount;
|
||||
}
|
||||
|
||||
return candidateDict;
|
||||
}
|
||||
|
||||
let candidateDict = prepare_candidates_from_text(query);
|
||||
var candidateItems = Object.keys(candidateDict).map(function(key) {
|
||||
return [key, candidateDict[key]];
|
||||
});
|
||||
|
||||
if(sortByFreq)
|
||||
{
|
||||
candidateItems.sort(function(first, second) {
|
||||
return second[1] - first[1];
|
||||
});
|
||||
}else
|
||||
{
|
||||
//sort alphabetically
|
||||
candidateItems.sort(function(first, second) {
|
||||
if (first[0] < second[0]) {
|
||||
return -1;
|
||||
}
|
||||
if (first[0] > second[0]) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
for(let i=0;i<candidateItems.length;++i)
|
||||
{
|
||||
let key = candidateItems[i][0];
|
||||
let count = candidateItems[i][1];
|
||||
const btn = document.createElement("div");
|
||||
btn.style.border = "1px solid #646464";
|
||||
btn.innerHTML = `<a href="#"><span class="color_wordsearch_surrounding">${key} (${count})</span></a>`;
|
||||
let searchstr = key;
|
||||
btn.onclick = () => {
|
||||
trigger_wordsearch_results(searchstr);
|
||||
};
|
||||
resultsContainer.appendChild(btn);
|
||||
}
|
||||
}
|
||||
function trigger_wordsearch_candidates_key()
|
||||
{
|
||||
if (event.key === 'Enter') {
|
||||
trigger_wordsearch_candidates();
|
||||
}
|
||||
}
|
||||
|
||||
function trigger_wordsearch_results(query) {
|
||||
const resultsContainer = document.getElementById("wordsearch_results");
|
||||
const gametext = document.getElementById("gametext");
|
||||
query = query.trim();
|
||||
resultsContainer.innerHTML = "";
|
||||
if (!query) return;
|
||||
|
||||
let extract_surrounding_text = function(range, contextLength) {
|
||||
const textNode = range.startContainer;
|
||||
if (textNode.nodeType !== Node.TEXT_NODE) return;
|
||||
const textContent = textNode.textContent;
|
||||
const startOffset = range.startOffset;
|
||||
const endOffset = range.endOffset;
|
||||
// Compute raw bounds
|
||||
let start = Math.max(0, startOffset - contextLength);
|
||||
let end = Math.min(textContent.length, endOffset + contextLength);
|
||||
// Clamp to word boundaries
|
||||
start = textContent.lastIndexOf(' ', start);
|
||||
end = textContent.indexOf(' ', end);
|
||||
if (start === -1) start = 0;
|
||||
if (end === -1) end = textContent.length;
|
||||
const before = textContent.slice(start, startOffset);
|
||||
const middle = textContent.slice(startOffset, endOffset);
|
||||
const after = textContent.slice(endOffset,end);
|
||||
return {"before":before, "middle":middle, "after":after, "full":`${before}${middle}${after}`};
|
||||
}
|
||||
|
||||
let search_text_for_strings = function(query) { //search text nodes for all instances of query
|
||||
const gametext = document.getElementById("gametext");
|
||||
let matchRanges = [];
|
||||
const walker = document.createTreeWalker(gametext, NodeFilter.SHOW_TEXT, null, false);
|
||||
|
||||
while (walker.nextNode()) {
|
||||
const node = walker.currentNode;
|
||||
const text = node.nodeValue;
|
||||
let idx = 0;
|
||||
while ((idx = text.toLowerCase().indexOf(query.toLowerCase(), idx)) !== -1) {
|
||||
const range = document.createRange();
|
||||
range.setStart(node, idx);
|
||||
range.setEnd(node, idx + query.length);
|
||||
matchRanges.push({ range, preview: text.substr(idx, query.length) });
|
||||
idx += query.length;
|
||||
}
|
||||
}
|
||||
return matchRanges;
|
||||
}
|
||||
|
||||
let matchRanges = search_text_for_strings(query);
|
||||
|
||||
const topper = document.createElement("div");
|
||||
topper.style.border = "1px solid #646464";
|
||||
topper.innerText = `${matchRanges.length} results`;
|
||||
resultsContainer.appendChild(topper);
|
||||
matchRanges.forEach(({ range, preview }, i) => {
|
||||
const btn = document.createElement("div");
|
||||
btn.style.border = "1px solid #646464";
|
||||
let nearbytext = extract_surrounding_text(range, 8); //8 chars clamped to word bounds
|
||||
btn.innerHTML = `<a href="#"><span class="color_wordsearch_surrounding">${nearbytext.before}</span><span class="color_wordsearch_target">${nearbytext.middle}</span><span class="color_wordsearch_surrounding">${nearbytext.after}</span></a>`;
|
||||
btn.onclick = () => {
|
||||
const sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
|
||||
// Scroll the container
|
||||
const rect = range.getBoundingClientRect();
|
||||
const containerRect = gametext.getBoundingClientRect();
|
||||
if (rect.top < containerRect.top || rect.bottom > containerRect.bottom) {
|
||||
if (range.startContainer && range.startContainer.nodeType === Node.TEXT_NODE) {
|
||||
const span = document.createElement("span");
|
||||
span.style.display = "inline";
|
||||
span.style.background = "transparent";
|
||||
span.id = "temp-scroll-target";
|
||||
range.insertNode(span); // Insert a temporary marker, then scroll to it
|
||||
document.querySelector("#temp-scroll-target").scrollIntoView({ behavior: "smooth", block: "center" });
|
||||
span.remove(); //remove temp marker
|
||||
}
|
||||
}
|
||||
};
|
||||
resultsContainer.appendChild(btn);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
</head>
|
||||
|
@ -22770,6 +23090,20 @@ Current version indicated by LITEVER below.
|
|||
<p id="tempgtloadtxt">Loading...</p>
|
||||
<noscript><style>#tempgtloadtxt { display: none; } #gametext { white-space: normal!important; }</style><p>Sorry, KoboldAI Lite requires Javascript to function.</p></noscript>
|
||||
</span>
|
||||
<div class="hidden" id="wordsearch_panel" style="flex:250px">
|
||||
<div style="display:flex; padding:6px">
|
||||
<input title="Word Search Input" class="form-control menuinput_inline" style="width: calc(100% - 34px); margin-right:2px;" type="text" placeholder="WordSearch" value="" onkeyup="trigger_wordsearch_candidates_key();" id="wordsearch_input">
|
||||
<button title="Perform WordSearch" type="button" class="btn btn-primary" style="width:30px;padding:4px 4px;" onclick="trigger_wordsearch_candidates();">🔎</button>
|
||||
</div>
|
||||
<div style="display:flex; padding:6px">
|
||||
<p style="margin-right:6px">Sort: </p>
|
||||
<select title="Sort" style="padding:2px; font-size:14px; height:24px; width: calc(100% - 50px);" class="form-control" id="wordsearch_sort">
|
||||
<option value="0">Frequency</option>
|
||||
<option value="1">Alphabetical</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="wordsearch_results" style="height:calc(100% - 98px);overflow-y: auto;"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -22883,6 +23217,8 @@ Current version indicated by LITEVER below.
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="popupcontainer flex hidden" id="memorycontainer">
|
||||
|
@ -23129,6 +23465,10 @@ Current version indicated by LITEVER below.
|
|||
<option id="uipicker_corpo" value="3">Corpo Theme</option>
|
||||
</select>
|
||||
<button type="button" class="btn btn-primary" id="btn_aesthetics" onclick="openAestheticUISettingsMenu()" style="border-color: #bbbbbb; width:100%; height:30px; padding:0px 8px; margin: 3px 0 3px 0;">⚙️ Customize</button>
|
||||
<div id="classicmodeoptions" style="margin:4px;" class="settinglabel hidden">
|
||||
<div class="justifyleft settingsmall">Word Frequency Analysis <span class="helpicon">?<span class="helptext">Shows a tool that displays word frequency and locations, inspired by trincadev MyGhostWriter. Counts across newlines may be inaccurate.</span></span></div>
|
||||
<input title="WordSearch Tool" type="checkbox" id="wordsearch_toggle" style="margin:0px 0px 0px 0px;">
|
||||
</div>
|
||||
<div id="guitypedesc" class="settingsdesctxt"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -24925,7 +25265,9 @@ Current version indicated by LITEVER below.
|
|||
<div>
|
||||
<b class="color_white" style="padding: 5px;">Change Loaded Model / Config:</b><br>
|
||||
<div style="display:flex;padding: 5px;">
|
||||
<select title="Select New Config" style="padding:4px; width:calc(100% - 150px)" class="form-control" id="adminconfigdropdown">
|
||||
<select title="Select New Config" style="padding:4px; width:100%" class="form-control" id="adminconfigdropdown" onchange="change_admin_config_selection()">
|
||||
</select>
|
||||
<select title="Override Config" style="padding:4px; width:100%" class="form-control hidden" id="adminconfigoverridedropdown">
|
||||
</select>
|
||||
<button type="button" style="margin-left:2px;width:146px" class="btn btn-primary" onclick="trigger_admin_reload()">Reload KoboldCpp</button>
|
||||
</div>
|
||||
|
@ -25246,7 +25588,7 @@ Current version indicated by LITEVER below.
|
|||
|
||||
<div class="popupcontainer flex hidden" id="inputboxcontainer">
|
||||
<div class="popupbg flex"></div>
|
||||
<div class="nspopup flexsize moderate">
|
||||
<div class="nspopup flexsize higher">
|
||||
<div class="popuptitlebar">
|
||||
<div class="popuptitletext" id="inputboxcontainertitle"></div>
|
||||
</div>
|
||||
|
@ -25282,7 +25624,7 @@ Current version indicated by LITEVER below.
|
|||
|
||||
<div class="popupcontainer flex hidden" id="msgboxcontainer">
|
||||
<div class="popupbg flex"></div>
|
||||
<div class="nspopup flexsizesmall moderate">
|
||||
<div class="nspopup flexsizesmall higher">
|
||||
<div class="popuptitlebar">
|
||||
<div class="popuptitletext" id="msgboxtitle"></div>
|
||||
</div>
|
||||
|
|
31
koboldcpp.py
31
koboldcpp.py
|
@ -59,7 +59,7 @@ dry_seq_break_max = 128
|
|||
KcppVersion = "1.93.2"
|
||||
showdebug = True
|
||||
kcpp_instance = None #global running instance
|
||||
global_memory = {"tunnel_url": "", "restart_target":"", "input_to_exit":False, "load_complete":False}
|
||||
global_memory = {"tunnel_url": "", "restart_target":"", "input_to_exit":False, "load_complete":False, "restart_override_config_target":""}
|
||||
using_gui_launcher = False
|
||||
|
||||
handle = None
|
||||
|
@ -3464,22 +3464,31 @@ Change Mode<br>
|
|||
resp = {"success": False}
|
||||
if global_memory and args.admin and args.admindir and os.path.exists(args.admindir) and self.check_header_password(args.adminpassword):
|
||||
targetfile = ""
|
||||
overrideconfig = ""
|
||||
try:
|
||||
tempbody = json.loads(body)
|
||||
if isinstance(tempbody, dict):
|
||||
targetfile = tempbody.get('filename', "")
|
||||
overrideconfig = tempbody.get('overrideconfig', "")
|
||||
except Exception:
|
||||
targetfile = ""
|
||||
if targetfile and targetfile!="":
|
||||
if targetfile=="unload_model": #special request to simply unload model
|
||||
print("Admin: Received request to unload model")
|
||||
global_memory["restart_target"] = "unload_model"
|
||||
global_memory["restart_override_config_target"] = ""
|
||||
resp = {"success": True}
|
||||
else:
|
||||
dirpath = os.path.abspath(args.admindir)
|
||||
targetfilepath = os.path.join(dirpath, targetfile)
|
||||
opts = [f for f in os.listdir(dirpath) if (f.lower().endswith(".kcpps") or f.lower().endswith(".kcppt") or f.lower().endswith(".gguf")) and os.path.isfile(os.path.join(dirpath, f))]
|
||||
if targetfile in opts and os.path.exists(targetfilepath):
|
||||
global_memory["restart_override_config_target"] = ""
|
||||
if targetfile.lower().endswith(".gguf") and overrideconfig:
|
||||
overrideconfigfilepath = os.path.join(dirpath, overrideconfig)
|
||||
if overrideconfig and overrideconfig in opts and os.path.exists(overrideconfigfilepath):
|
||||
print(f"Admin: Override config set to {overrideconfig}")
|
||||
global_memory["restart_override_config_target"] = overrideconfig
|
||||
print(f"Admin: Received request to reload config to {targetfile}")
|
||||
global_memory["restart_target"] = targetfile
|
||||
resp = {"success": True}
|
||||
|
@ -4981,7 +4990,7 @@ def show_gui():
|
|||
sdvaeitem2.grid()
|
||||
sdvaeitem3.grid()
|
||||
makecheckbox(images_tab, "Use TAE SD (AutoFix Broken VAE)", sd_vaeauto_var, 32,command=toggletaesd,tooltiptxt="Replace VAE with TAESD. May fix bad VAE.")
|
||||
makecheckbox(images_tab, "No VAE Tiling", sd_notile_var, 24,tooltiptxt="Disables VAE tiling, may not work for large images.")
|
||||
makecheckbox(images_tab, "No VAE Tiling", sd_notile_var, 34,tooltiptxt="Disables VAE tiling, may not work for large images.")
|
||||
|
||||
# audio tab
|
||||
audio_tab = tabcontent["Audio"]
|
||||
|
@ -6258,7 +6267,7 @@ def main(launch_args, default_args):
|
|||
input()
|
||||
else: # manager command queue for admin mode
|
||||
with multiprocessing.Manager() as mp_manager:
|
||||
global_memory = mp_manager.dict({"tunnel_url": "", "restart_target":"", "input_to_exit":False, "load_complete":False})
|
||||
global_memory = mp_manager.dict({"tunnel_url": "", "restart_target":"", "input_to_exit":False, "load_complete":False, "restart_override_config_target":""})
|
||||
|
||||
if args.remotetunnel and not args.prompt and not args.benchmark and not args.cli:
|
||||
setuptunnel(global_memory, True if args.sdmodel else False)
|
||||
|
@ -6275,6 +6284,7 @@ def main(launch_args, default_args):
|
|||
while True: # keep the manager alive
|
||||
try:
|
||||
restart_target = ""
|
||||
restart_override_config_target = ""
|
||||
if not kcpp_instance or not kcpp_instance.is_alive():
|
||||
if fault_recovery_mode:
|
||||
#attempt to recover
|
||||
|
@ -6289,20 +6299,25 @@ def main(launch_args, default_args):
|
|||
kcpp_instance.daemon = True
|
||||
kcpp_instance.start()
|
||||
global_memory["restart_target"] = ""
|
||||
global_memory["restart_override_config_target"] = ""
|
||||
time.sleep(3)
|
||||
else:
|
||||
break # kill the program
|
||||
if fault_recovery_mode and global_memory["load_complete"]:
|
||||
fault_recovery_mode = False
|
||||
restart_target = global_memory["restart_target"]
|
||||
restart_override_config_target = global_memory["restart_override_config_target"]
|
||||
if restart_target!="":
|
||||
print(f"Reloading new model/config: {restart_target}")
|
||||
overridetxt = ("" if not restart_override_config_target else f" with override config {restart_override_config_target}")
|
||||
print(f"Reloading new model/config: {restart_target}{overridetxt}")
|
||||
global_memory["restart_target"] = ""
|
||||
global_memory["restart_override_config_target"] = ""
|
||||
time.sleep(0.5) #sleep for 0.5s then restart
|
||||
if args.admin and args.admindir:
|
||||
dirpath = os.path.abspath(args.admindir)
|
||||
targetfilepath = os.path.join(dirpath, restart_target)
|
||||
if os.path.exists(targetfilepath) or restart_target=="unload_model":
|
||||
targetfilepath2 = os.path.join(dirpath, restart_override_config_target)
|
||||
if (os.path.exists(targetfilepath) or restart_target=="unload_model") and (restart_override_config_target=="" or os.path.exists(targetfilepath2)):
|
||||
print("Terminating old process...")
|
||||
global_memory["load_complete"] = False
|
||||
kcpp_instance.terminate()
|
||||
|
@ -6315,15 +6330,19 @@ def main(launch_args, default_args):
|
|||
args.model_param = None
|
||||
args.model = None
|
||||
args.nomodel = True
|
||||
elif targetfilepath.endswith(".gguf"):
|
||||
elif targetfilepath.endswith(".gguf") and restart_override_config_target=="":
|
||||
reload_from_new_args(vars(default_args))
|
||||
args.model_param = targetfilepath
|
||||
elif targetfilepath.endswith(".gguf") and restart_override_config_target!="":
|
||||
reload_new_config(targetfilepath2)
|
||||
args.model_param = targetfilepath
|
||||
else:
|
||||
reload_new_config(targetfilepath)
|
||||
kcpp_instance = multiprocessing.Process(target=kcpp_main_process,kwargs={"launch_args": args, "g_memory": global_memory, "gui_launcher": False})
|
||||
kcpp_instance.daemon = True
|
||||
kcpp_instance.start()
|
||||
global_memory["restart_target"] = ""
|
||||
global_memory["restart_override_config_target"] = ""
|
||||
time.sleep(3)
|
||||
else:
|
||||
time.sleep(0.2)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue