From c6797a59ce48ae405b915a3ffb34b396e8b3a06e Mon Sep 17 00:00:00 2001 From: somebody Date: Fri, 6 Jan 2023 18:08:39 -0600 Subject: [PATCH 01/12] Localize variables Stop the leaking! --- static/koboldai.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/static/koboldai.js b/static/koboldai.js index af8b8909..5485c22e 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -2890,8 +2890,9 @@ function save_bias(item) { function sync_to_server(item) { //get value - value = null; - name = null; + let value = null; + let name = null; + if ((item.tagName.toLowerCase() === 'checkbox') || (item.tagName.toLowerCase() === 'input') || (item.tagName.toLowerCase() === 'select') || (item.tagName.toLowerCase() == 'textarea')) { if (item.getAttribute("type") == "checkbox") { value = item.checked; From 8e24d91f6dd1c5fe0dcaf3a4cc14feb5ff4007f2 Mon Sep 17 00:00:00 2001 From: somebody Date: Fri, 6 Jan 2023 19:21:15 -0600 Subject: [PATCH 02/12] Biasing ui update --- static/koboldai.css | 59 ++++++++++++++++------------------ static/koboldai.js | 55 +++++++++++++++++-------------- templates/settings flyout.html | 10 ++---- templates/templates.html | 40 +++++++++++++---------- 4 files changed, 83 insertions(+), 81 deletions(-) diff --git a/static/koboldai.css b/static/koboldai.css index 750a82e4..7eb7609f 100644 --- a/static/koboldai.css +++ b/static/koboldai.css @@ -235,11 +235,6 @@ border-top-right-radius: var(--tabs_rounding); margin: 2px; } -#biasing { - margin-left: 5px; - margin-right: 5px; -} - .setting_container.var_sync_alt_system_alt_gen[system_alt_gen="true"] { display: none; } @@ -664,40 +659,40 @@ border-top-right-radius: var(--tabs_rounding); } /* Bias */ -#biases_label { - cursor: pointer; +#biasing { + padding: 0px 10px; } -.bias { - display: grid; - grid-template-areas: "phrase percent max"; - grid-template-columns: auto 100px 100px; +.bias_card { + background-color: var(--setting_background); + padding: 8px; +} + +.bias_top { + display: flex; + justify-content: space-between; +} + +.bias_top > .close_button { + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + margin-left: 7px; +} + +.bias_card input { + width: 100%; + border: none; } .bias_phrase { - grid-area: phrase; - margin-right: 5px; + height: 36px; } -.bias_phrase input { - width: 100%; -} - -.bias_score { - grid-area: percent; - margin-right: 5px; -} - -.bias_comp_threshold { - grid-area: max; - margin-right: 5px; -} - -.bias_slider { - display: grid; - grid-template-areas: "bar bar bar" - "min cur max"; - grid-template-columns: 33px 34px 33px; +.bias_slider_labels { + display: flex; + justify-content: space-between; } .bias_slider_bar { diff --git a/static/koboldai.js b/static/koboldai.js index 5485c22e..ead78017 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -3633,42 +3633,49 @@ function options_on_right(data) { } } +function makeBiasCard(phrase, score, compThreshold) { + function updateLabel(input) { + input.closest(".bias_slider").querySelector(".bias_slider_cur").innerText = input.value; + } + + const biasContainer = $el("#biasing"); + const biasCard = $el(".bias_card.template").cloneNode(true); + biasCard.classList.remove("template"); + + const phraseInput = biasCard.querySelector(".bias_phrase"); + const scoreInput = biasCard.querySelector(".bias_score input"); + const compThresholdInput = biasCard.querySelector(".bias_comp_threshold input"); + + phraseInput.value = phrase; + + scoreInput.value = score; + scoreInput.addEventListener("input", function() { updateLabel(this) }); + updateLabel(scoreInput); + + compThresholdInput.value = compThreshold; + compThresholdInput.addEventListener("input", function() { updateLabel(this) }); + updateLabel(compThresholdInput); + + biasContainer.appendChild(biasCard); +} + function do_biases(data) { - //console.log(data); //clear out our old bias lines - let bias_list = Object.assign([], document.getElementsByClassName("bias")); - for (item of bias_list) { - //console.log(item); + for (item of document.getElementsByClassName("bias_card")) { + if (item.classList.contains("template")) continue; item.parentNode.removeChild(item); } //add our bias lines for (const [key, value] of Object.entries(data.value)) { - bias_line = document.getElementById("empty_bias").cloneNode(true); - bias_line.id = ""; - bias_line.classList.add("bias"); - bias_line.querySelector(".bias_phrase").querySelector("input").value = key; - bias_line.querySelector(".bias_score").querySelector("input").value = value[0]; - update_bias_slider_value(bias_line.querySelector(".bias_score").querySelector("input")); - bias_line.querySelector(".bias_comp_threshold").querySelector("input").value = value[1]; - update_bias_slider_value(bias_line.querySelector(".bias_comp_threshold").querySelector("input")); - document.getElementById('biasing').append(bias_line); + makeBiasCard(key, value[0], value[1]); } //add another bias line if this is the phrase and it's not blank - bias_line = document.getElementById("empty_bias").cloneNode(true); - bias_line.id = ""; - bias_line.classList.add("bias"); - bias_line.querySelector(".bias_phrase").querySelector("input").value = ""; - bias_line.querySelector(".bias_phrase").querySelector("input").id = "empty_bias_phrase"; - bias_line.querySelector(".bias_score").querySelector("input").value = 1; - bias_line.querySelector(".bias_comp_threshold").querySelector("input").value = 50; - document.getElementById('biasing').append(bias_line); + const templateBiasCard = makeBiasCard("", 1, 50); + // bias_line.querySelector(".bias_phrase").querySelector("input").id = "empty_bias_phrase"; } -function update_bias_slider_value(slider) { - slider.parentElement.parentElement.querySelector(".bias_slider_cur").textContent = slider.value; -} function distortColor(rgb) { // rgb are 0..255, NOT NORMALIZED!!!!!! diff --git a/templates/settings flyout.html b/templates/settings flyout.html index 1eb85110..a4576113 100644 --- a/templates/settings flyout.html +++ b/templates/settings flyout.html @@ -242,14 +242,8 @@
Influence the likelihood for the AI to output certain phrases.
-
-
Phrase
-
Score
-
- Completion Threshold - help_icon -
-
+ +
diff --git a/templates/templates.html b/templates/templates.html index 8a60b7b7..01d7a598 100644 --- a/templates/templates.html +++ b/templates/templates.html @@ -112,29 +112,35 @@ -
-
- +
+
+ + close
-
-
-
- -
+ + Score +
+
+ +
+
-50
0
50
-
-
-
- -
+ + + Completion Threshold + help_icon + +
+
+ +
+
0
10
10
From 73f85a1a9e22d8db6155456226f5b9c6ab068e1b Mon Sep 17 00:00:00 2001 From: somebody Date: Sat, 7 Jan 2023 00:43:53 -0600 Subject: [PATCH 03/12] More work on front end Its extra shiny --- static/koboldai.css | 47 ++++++--------------- static/koboldai.js | 90 +++++++++++++++++++++++++++++++++++----- templates/templates.html | 54 ++++++++++++++---------- 3 files changed, 124 insertions(+), 67 deletions(-) diff --git a/static/koboldai.css b/static/koboldai.css index 7eb7609f..406cca4d 100644 --- a/static/koboldai.css +++ b/static/koboldai.css @@ -693,51 +693,30 @@ border-top-right-radius: var(--tabs_rounding); .bias_slider_labels { display: flex; justify-content: space-between; + position: relative; } -.bias_slider_bar { - grid-area: bar; -} - -.bias_slider_min { - grid-area: min; +.bias_slider_min, .bias_slider_max{ font-size: calc(0.8em + var(--font_size_adjustment)); - margin-right: 5px; - margin-left: 5px; + user-select: none; } .bias_slider_cur { - grid-area: cur; text-align: center; + outline: none; } -.bias_slider_max { - grid-area: max; - font-size: calc(0.8em + var(--font_size_adjustment)); - text-align: right; - margin-right: 5px; - margin-left: 5px; +.bias_score, .bias_top { + margin-bottom: 12px; } -.bias_header { - display: grid; - grid-template-areas: "phrase percent max"; - grid-template-columns: auto 100px 100px; -} - -.bias_header_phrase { - grid-area: phrase; - font-size: calc(1.1em + var(--font_size_adjustment)); -} - -.bias_header_score { - grid-area: percent; - font-size: calc(1.1em + var(--font_size_adjustment)); -} - -.bias_header_max { - grid-area: max; - font-size: calc(1.1em + var(--font_size_adjustment)); +.bias_slider_centerlayer { + /* Yeah its a bit of a hack */ + position: absolute; + left: 0px; + width: 100%; + display: flex; + justify-content: center; } /* Theme */ diff --git a/static/koboldai.js b/static/koboldai.js index ead78017..4b441bb7 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -2862,8 +2862,7 @@ function save_as_story(response) { if (response === "overwrite?") openPopup("save-confirm"); } -function save_bias(item) { - +function save_bias() { var have_blank = false; var biases = {}; //get all of our biases @@ -3634,8 +3633,15 @@ function options_on_right(data) { } function makeBiasCard(phrase, score, compThreshold) { - function updateLabel(input) { - input.closest(".bias_slider").querySelector(".bias_slider_cur").innerText = input.value; + function updateBias(origin, input, save=true) { + const textInput = input.closest(".bias_slider").querySelector(".bias_slider_cur"); + let value = (origin === "slider") ? input.value : parseFloat(textInput.innerText); + textInput.innerText = value; + input.value = value; + + // Only save on "commitful" actions like blur or mouseup to not spam + // the poor server + if (save) console.warn("saving") } const biasContainer = $el("#biasing"); @@ -3647,14 +3653,78 @@ function makeBiasCard(phrase, score, compThreshold) { const compThresholdInput = biasCard.querySelector(".bias_comp_threshold input"); phraseInput.value = phrase; - scoreInput.value = score; - scoreInput.addEventListener("input", function() { updateLabel(this) }); - updateLabel(scoreInput); - compThresholdInput.value = compThreshold; - compThresholdInput.addEventListener("input", function() { updateLabel(this) }); - updateLabel(compThresholdInput); + + for (const input of [scoreInput, compThresholdInput]) { + // Init sync + updateBias("slider", input, false); + + // Visual update on each value change + input.addEventListener("input", function() { updateBias("slider", this, false) }); + + // Only when we leave do we sync to server (might come back to bite us) + input.addEventListener("mouseup", function() { updateBias("slider", this) }); + input.addEventListener("blur", function() { updateBias("slider", this) }); + + // Personally I don't want to press a key 100 times to add one + const nudge = parseFloat(input.getAttribute("keyboard-step") ?? input.getAttribute("step")); + const min = parseFloat(input.getAttribute("min")); + const max = parseFloat(input.getAttribute("max")); + + const currentHitbox = input.closest(".hitbox"); + const currentLabel = input.closest(".bias_slider").querySelector(".bias_slider_cur"); + currentLabel.addEventListener("keydown", function(event) { + // Nothing special for numbers + if ([".", "-"].includes(event.key) || parseInt(event.key)) return; + + // Either we are special keys or forbidden keys + event.preventDefault(); + + switch (event.key) { + case "Enter": + currentLabel.blur(); + break; + // This feels very nice :^) + case "ArrowDown": + case "ArrowUp": + let delta = (event.key === "ArrowUp") ? nudge : -nudge; + let currentValue = parseFloat(currentLabel.innerText); + + event.preventDefault(); + if (!currentValue && currentValue !== 0) return; + + // toFixed because 1.1 + 0.1 !== 1.2 yay rounding errors. + // Although the added decimal place(s) look cleaner now + // that I think about it. + let value = Math.min(max, Math.max(min, currentValue + delta)); + currentLabel.innerText = value.toFixed(2); + + updateBias("text", input, false); + break; + } + }); + + currentHitbox.addEventListener("wheel", function(event) { + // Only when focused! (May drop this requirement later, browsers seem to behave when scrolling :] ) + if (currentLabel !== document.activeElement) return; + if (event.deltaY === 0) return; + + let delta = (event.deltaY > 0) ? nudge : -nudge; + let currentValue = parseFloat(currentLabel.innerText); + + event.preventDefault(); + if (!currentValue && currentValue !== 0) return; + let value = Math.min(max, Math.max(min, currentValue + delta)); + currentLabel.innerText = value.toFixed(2); + + updateBias("text", input, false); + }); + + currentLabel.addEventListener("blur", function(event) { + updateBias("text", input); + }); + } biasContainer.appendChild(biasCard); } diff --git a/templates/templates.html b/templates/templates.html index 01d7a598..a5e26fde 100644 --- a/templates/templates.html +++ b/templates/templates.html @@ -118,32 +118,40 @@ close
- Score -
-
- -
-
-
-50
-
0
-
50
+
+ Bias Amount +
+
+ +
+
+ -50 +
+ 0 +
+
50
+
- - Completion Threshold - help_icon - -
-
- -
-
-
0
-
10
-
10
+
+ + Completion Threshold + help_icon + +
+
+ +
+
+
0
+
+ 10 +
+
10
+
From 14b14e26ec63baab6b7105d52e3d33dee0f69221 Mon Sep 17 00:00:00 2001 From: ebolam Date: Sat, 7 Jan 2023 20:30:17 -0500 Subject: [PATCH 04/12] Fix for Javascript error on playing last action's TTS audio --- static/koboldai.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/static/koboldai.js b/static/koboldai.js index 042e3e61..4c58293b 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -3293,7 +3293,9 @@ function finished_tts() { } else { action = document.getElementById("Selected Text Chunk "+(next_action-1)); } - action.classList.remove("tts_playing"); + if (action) { + action.classList.remove("tts_playing"); + } if (next_action <= action_count) { document.getElementById("reader").src = "/audio?id="+next_action; document.getElementById("reader").setAttribute("action_id", next_action); @@ -3311,7 +3313,9 @@ function tts_playing() { } else { action = document.getElementById("Selected Text Chunk "+action_id); } - action.classList.add("tts_playing"); + if (action) { + action.classList.add("tts_playing"); + } } function view_selection_probabilities() { From 5f2bcce11a3cdd3ab9dae7a560f7544be408053c Mon Sep 17 00:00:00 2001 From: somebody Date: Sat, 7 Jan 2023 20:11:42 -0600 Subject: [PATCH 05/12] Functional updates (mostly) --- static/koboldai.css | 15 ++++++ static/koboldai.js | 88 ++++++++++++++++++++++++---------- templates/settings flyout.html | 4 +- templates/templates.html | 6 +-- 4 files changed, 81 insertions(+), 32 deletions(-) diff --git a/static/koboldai.css b/static/koboldai.css index 406cca4d..8b9d1c5d 100644 --- a/static/koboldai.css +++ b/static/koboldai.css @@ -666,6 +666,7 @@ border-top-right-radius: var(--tabs_rounding); .bias_card { background-color: var(--setting_background); padding: 8px; + margin-bottom: 12px; } .bias_top { @@ -719,6 +720,20 @@ border-top-right-radius: var(--tabs_rounding); justify-content: center; } +#bias-add { + width: 100%; + cursor: pointer; + display: flex; + justify-content: center; + align-items: center; + padding: 4px; +} + +#bias-add:hover { + width: 100%; + background-color: rgba(255, 255, 255, 0.05); +} + /* Theme */ .collapsable_header .material-icons-outlined { diff --git a/static/koboldai.js b/static/koboldai.js index 4b441bb7..ba1082c5 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -56,6 +56,7 @@ var shift_down = false; var world_info_data = {}; var world_info_folder_data = {}; var saved_settings = {}; +var biases_data = {}; var finder_selection_index = -1; var colab_cookies = null; var wi_finder_data = []; @@ -2863,28 +2864,35 @@ function save_as_story(response) { } function save_bias() { - var have_blank = false; var biases = {}; //get all of our biases - for (bias of document.getElementsByClassName("bias")) { + + for (const biasCard of document.getElementsByClassName("bias_card")) { //phrase - var phrase = bias.querySelector(".bias_phrase").querySelector("input").value; + var phrase = biasCard.querySelector(".bias_phrase").value; + if (!phrase) continue; //Score - var percent = parseFloat(bias.querySelector(".bias_score").querySelector("input").value); + var score = parseFloat(biasCard.querySelector(".bias_score input").value); //completion threshold - var comp_threshold = parseInt(bias.querySelector(".bias_comp_threshold").querySelector("input").value); + var compThreshold = parseInt(biasCard.querySelector(".bias_comp_threshold input").value); - if (phrase != "") { - biases[phrase] = [percent, comp_threshold]; - } - bias.classList.add("pulse"); + biases[phrase] = [score, compThreshold]; } - + + // Because of course JS couldn't just support comparison in a core type + // that would be silly and foolish + if (JSON.stringify(biases) === JSON.stringify(biases_data)) { + // No changes. :( + return; + } + + biases_data = biases; + console.info("saving biases", biases) + //send the biases to the backend socket.emit("phrase_bias_update", biases); - } function sync_to_server(item) { @@ -3632,7 +3640,7 @@ function options_on_right(data) { } } -function makeBiasCard(phrase, score, compThreshold) { +function makeBiasCard(phrase="", score=0, compThreshold=10) { function updateBias(origin, input, save=true) { const textInput = input.closest(".bias_slider").querySelector(".bias_slider_cur"); let value = (origin === "slider") ? input.value : parseFloat(textInput.innerText); @@ -3641,14 +3649,29 @@ function makeBiasCard(phrase, score, compThreshold) { // Only save on "commitful" actions like blur or mouseup to not spam // the poor server - if (save) console.warn("saving") + if (save) save_bias(); } - const biasContainer = $el("#biasing"); + const biasContainer = $el("#bias-container"); const biasCard = $el(".bias_card.template").cloneNode(true); biasCard.classList.remove("template"); + const closeButton = biasCard.querySelector(".close_button"); + closeButton.addEventListener("click", function(event) { + biasCard.remove(); + + // We just deleted the last bias, we probably don't want to keep seeing + // them pop up + if (!biasContainer.firstChild) biasContainer.setAttribute( + "please-stop-adding-biases-whenever-i-delete-them", + "i mean it" + ); + save_bias(); + }); + const phraseInput = biasCard.querySelector(".bias_phrase"); + phraseInput.addEventListener("change", save_bias); + const scoreInput = biasCard.querySelector(".bias_score input"); const compThresholdInput = biasCard.querySelector(".bias_comp_threshold input"); @@ -3663,9 +3686,8 @@ function makeBiasCard(phrase, score, compThreshold) { // Visual update on each value change input.addEventListener("input", function() { updateBias("slider", this, false) }); - // Only when we leave do we sync to server (might come back to bite us) - input.addEventListener("mouseup", function() { updateBias("slider", this) }); - input.addEventListener("blur", function() { updateBias("slider", this) }); + // Only when we leave do we sync to server + input.addEventListener("change", function() { updateBias("slider", this) }); // Personally I don't want to press a key 100 times to add one const nudge = parseFloat(input.getAttribute("keyboard-step") ?? input.getAttribute("step")); @@ -3727,23 +3749,37 @@ function makeBiasCard(phrase, score, compThreshold) { } biasContainer.appendChild(biasCard); + return biasCard; } +$el("#bias-add").addEventListener("click", function(event) { + const card = makeBiasCard(); + card.querySelector(".bias_phrase").focus(); +}); function do_biases(data) { - //clear out our old bias lines - for (item of document.getElementsByClassName("bias_card")) { - if (item.classList.contains("template")) continue; - item.parentNode.removeChild(item); + console.info("Taking inventory of biases") + biases_data = data.value; + + // Clear out our old bias cards, weird recursion because remove sometimes + // doesn't work (???) + const biasContainer = $el("#bias-container"); + for (let i=0;i<10000;i++) { + if (!biasContainer.firstChild) break; + biasContainer.firstChild.remove(); } - + if(biasContainer.firstChild) reportError("We are doomed", "Undead zombie bias, please report this"); + //add our bias lines for (const [key, value] of Object.entries(data.value)) { makeBiasCard(key, value[0], value[1]); } - - //add another bias line if this is the phrase and it's not blank - const templateBiasCard = makeBiasCard("", 1, 50); - // bias_line.querySelector(".bias_phrase").querySelector("input").id = "empty_bias_phrase"; + + // Add seed card if we have no bias cards and we didn't just delete the + // last bias card + if ( + !biasContainer.firstChild && + !biasContainer.getAttribute("please-stop-adding-biases-whenever-i-delete-them") + ) makeBiasCard(); } diff --git a/templates/settings flyout.html b/templates/settings flyout.html index a4576113..3665c53c 100644 --- a/templates/settings flyout.html +++ b/templates/settings flyout.html @@ -242,8 +242,8 @@
Influence the likelihood for the AI to output certain phrases.
- -
+
+
add
diff --git a/templates/templates.html b/templates/templates.html index a5e26fde..78aa4b14 100644 --- a/templates/templates.html +++ b/templates/templates.html @@ -122,8 +122,7 @@ Bias Amount
- +
-50 @@ -142,8 +141,7 @@
- +
0
From 76c13989172970142ac333a6b1dc3168b6b03edd Mon Sep 17 00:00:00 2001 From: somebody Date: Sat, 7 Jan 2023 20:19:31 -0600 Subject: [PATCH 06/12] Small cleanup with imports and unused threading code --- aiserver.py | 27 +-------------------------- koboldai_settings.py | 5 +---- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/aiserver.py b/aiserver.py index 46b1a56a..11fe3664 100644 --- a/aiserver.py +++ b/aiserver.py @@ -40,7 +40,6 @@ import packaging import packaging.version import contextlib import traceback -import threading import markdown import bleach import itertools @@ -63,7 +62,6 @@ import sys import gc import lupa -import importlib # KoboldAI import fileops @@ -83,7 +81,7 @@ import transformers.generation_utils # Text2img import base64 -from PIL import Image, ImageFont, ImageDraw, ImageFilter, ImageOps, PngImagePlugin +from PIL import Image from io import BytesIO global tpu_mtj_backend @@ -7847,7 +7845,6 @@ def final_startup(): return utils.decodenewlines(tokenizer.decode([25678, 559])) tokenizer.encode(utils.encodenewlines("eunoia")) - #threading.Thread(target=__preempt_tokenizer).start() tpool.execute(__preempt_tokenizer) # Load soft prompt specified by the settings file, if applicable @@ -7865,18 +7862,6 @@ def final_startup(): if(koboldai_vars.use_colab_tpu or koboldai_vars.model in ("TPUMeshTransformerGPTJ", "TPUMeshTransformerGPTNeoX")): soft_tokens = tpumtjgetsofttokens() if(koboldai_vars.dynamicscan or (not koboldai_vars.nogenmod and koboldai_vars.has_genmod)): - #threading.Thread( - # target=tpu_mtj_backend.infer_dynamic, - # args=(np.tile(np.uint32((23403, 727, 20185)), (koboldai_vars.numseqs, 1)),), - # kwargs={ - # "soft_embeddings": koboldai_vars.sp, - # "soft_tokens": soft_tokens, - # "gen_len": 1, - # "use_callback": False, - # "numseqs": koboldai_vars.numseqs, - # "excluded_world_info": list(set() for _ in range(koboldai_vars.numseqs)), - # }, - #).start() tpool.execute(tpu_mtj_backend.infer_dynamic, np.tile(np.uint32((23403, 727, 20185)), (koboldai_vars.numseqs, 1)), soft_embeddings= koboldai_vars.sp, soft_tokens= soft_tokens, @@ -7886,16 +7871,6 @@ def final_startup(): excluded_world_info= list(set() for _ in range(koboldai_vars.numseqs)) ) else: - #threading.Thread( - # target=tpu_mtj_backend.infer_static, - # args=(np.uint32((23403, 727, 20185)),), - # kwargs={ - # "soft_embeddings": koboldai_vars.sp, - # "soft_tokens": soft_tokens, - # "gen_len": 1, - # "numseqs": koboldai_vars.numseqs, - # }, - #).start() tpool.execute( tpu_mtj_backend.infer_static, np.uint32((23403, 727, 20185)), diff --git a/koboldai_settings.py b/koboldai_settings.py index 4a77ad38..e24e949e 100644 --- a/koboldai_settings.py +++ b/koboldai_settings.py @@ -7,15 +7,12 @@ import shutil from typing import List, Union from io import BytesIO from flask import has_request_context, session -from flask_socketio import SocketIO, join_room, leave_room +from flask_socketio import join_room, leave_room from collections import OrderedDict import multiprocessing from logger import logger -import eventlet import torch import numpy as np -import inspect -import ctypes import random serverstarted = False From f6c4bfb3908949cfe3ac5139f72cd6c23280165f Mon Sep 17 00:00:00 2001 From: somebody Date: Sat, 7 Jan 2023 23:59:46 -0600 Subject: [PATCH 07/12] New bias token control (and lack thereof) Allows square bracket syntax for using token ids, curly bracket syntax for strict phrasing, and normal now biases alternative phrases with space prefixes --- aiserver.py | 90 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 14 deletions(-) diff --git a/aiserver.py b/aiserver.py index 11fe3664..df8af18b 100644 --- a/aiserver.py +++ b/aiserver.py @@ -2218,28 +2218,90 @@ def patch_transformers(): # There were no matches, so just begin at the beginning. return 0 + def _allow_leftwards_tampering(self, phrase: str) -> bool: + """Determines if a phrase should be tampered with from the left in + the "soft" token encoding mode.""" + + if phrase[0] in [".", "?", "!", ";", ":", "\n"]: + return False + return True + + def _get_token_sequence(self, phrase: str) -> List[List]: + """Convert the phrase string into a list of encoded biases, each + one being a list of tokens. How this is done is determined by the + phrase's format: + + - If the phrase is surrounded by square brackets ([]), the tokens + will be the phrase split by commas (,). If a "token" isn't + actually a number, it will be skipped. NOTE: Tokens output by + this may not be in the model's vocabulary, and such tokens + should be ignored later in the pipeline. + - If the phrase is surrounded by curly brackets ({}), the phrase + will be directly encoded with no synonym biases and no fancy + tricks. + - Otherwise, the phrase will be encoded, with close deviations + being included as synonym biases. + """ + + # TODO: Cache these tokens, invalidate when model or bias is + # changed. + + # Handle direct token id input + if phrase.startswith("[") and phrase.endswith("]"): + no_brackets = phrase[1:-1] + ret = [] + for token_id in no_brackets.split(","): + try: + ret.append(int(token_id)) + except ValueError: + # Ignore non-numbers. Rascals! + pass + return [ret] + + # Handle direct phrases + if phrase.startswith("{") and phrase.endswith("}"): + no_brackets = phrase[1:-1] + return [tokenizer.encode(no_brackets)] + + # Handle untamperable phrases + if not self._allow_leftwards_tampering(phrase): + return [tokenizer.encode(phrase)] + + # Handle slight alterations to original phrase + phrase = phrase.strip(" ") + ret = [] + + for alt_phrase in [phrase, f" {phrase}"]: + ret.append(tokenizer.encode(alt_phrase)) + + return ret + def _get_biased_tokens(self, input_ids: List) -> Dict: # TODO: Different "bias slopes"? ret = {} for phrase, _bias in koboldai_vars.biases.items(): bias_score, completion_threshold = _bias - # TODO: Cache these tokens, invalidate when model or bias is - # changed. - token_seq = tokenizer.encode(phrase) - bias_index = self._find_intersection(input_ids, token_seq) + token_seqs = self._get_token_sequence(phrase) + variant_deltas = {} + for token_seq in token_seqs: + bias_index = self._find_intersection(input_ids, token_seq) - # Ensure completion after completion_threshold tokens - # Only provide a positive bias when the base bias score is positive. - if bias_score > 0 and bias_index + 1 > completion_threshold: - bias_score = 999 + # Ensure completion after completion_threshold tokens + # Only provide a positive bias when the base bias score is positive. + if bias_score > 0 and bias_index + 1 > completion_threshold: + bias_score = 999 - token_to_bias = token_seq[bias_index] - # If multiple phrases bias the same token, add the modifiers together. - if token_to_bias in ret: - ret[token_to_bias] += bias_score - else: - ret[token_to_bias] = bias_score + token_to_bias = token_seq[bias_index] + variant_deltas[token_to_bias] = bias_score + + # If multiple phrases bias the same token, add the modifiers + # together. This should NOT be applied to automatic variants + for token_to_bias, bias_score in variant_deltas.items(): + if token_to_bias in ret: + ret[token_to_bias] += bias_score + else: + ret[token_to_bias] = bias_score return ret def __call__(self, input_ids: torch.LongTensor, scores: torch.FloatTensor) -> torch.FloatTensor: From 62de50509c9d64984b3387010f1ac1013b34e030 Mon Sep 17 00:00:00 2001 From: somebody Date: Sun, 8 Jan 2023 01:02:17 -0600 Subject: [PATCH 08/12] UI Fixes --- static/koboldai.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/static/koboldai.js b/static/koboldai.js index ba1082c5..c4716f7b 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -3698,7 +3698,11 @@ function makeBiasCard(phrase="", score=0, compThreshold=10) { const currentLabel = input.closest(".bias_slider").querySelector(".bias_slider_cur"); currentLabel.addEventListener("keydown", function(event) { // Nothing special for numbers - if ([".", "-"].includes(event.key) || parseInt(event.key)) return; + if ( + [".", "-", "ArrowLeft", "ArrowRight", "Backspace", "Delete"].includes(event.key) + || event.ctrlKey + || (parseInt(event.key) || parseInt(event.key) === 0) + ) return; // Either we are special keys or forbidden keys event.preventDefault(); @@ -3732,7 +3736,7 @@ function makeBiasCard(phrase="", score=0, compThreshold=10) { if (currentLabel !== document.activeElement) return; if (event.deltaY === 0) return; - let delta = (event.deltaY > 0) ? nudge : -nudge; + let delta = (event.deltaY > 0) ? -nudge : nudge; let currentValue = parseFloat(currentLabel.innerText); event.preventDefault(); From bb3afdf46e8f451f60be2887383d0909737dddb8 Mon Sep 17 00:00:00 2001 From: somebody Date: Sun, 8 Jan 2023 01:11:52 -0600 Subject: [PATCH 09/12] Don't allow characters pasted in there! Get out! --- static/koboldai.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/static/koboldai.js b/static/koboldai.js index c4716f7b..bb5d97d6 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -3696,6 +3696,10 @@ function makeBiasCard(phrase="", score=0, compThreshold=10) { const currentHitbox = input.closest(".hitbox"); const currentLabel = input.closest(".bias_slider").querySelector(".bias_slider_cur"); + + // TODO: Prevent paste of just non-number characters + currentLabel.addEventListener("paste", function(event) { event.preventDefault(); }) + currentLabel.addEventListener("keydown", function(event) { // Nothing special for numbers if ( From e2b82b9e17993e8c72f86e34b8b1831a661920bc Mon Sep 17 00:00:00 2001 From: Henk Date: Sun, 8 Jan 2023 15:31:12 +0100 Subject: [PATCH 10/12] ROCm Dependency Fixes --- environments/huggingface.yml | 4 ++-- environments/rocm.yml | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/environments/huggingface.yml b/environments/huggingface.yml index 9fd2ce5f..485ac338 100644 --- a/environments/huggingface.yml +++ b/environments/huggingface.yml @@ -22,7 +22,6 @@ dependencies: - loguru - termcolor - Pillow - - diffusers - psutil - pip: - flask-cloudflared @@ -40,4 +39,5 @@ dependencies: - ijson - bitsandbytes - ftfy - - pydub \ No newline at end of file + - pydub + - diffusers diff --git a/environments/rocm.yml b/environments/rocm.yml index ad39a3a6..a0e23177 100644 --- a/environments/rocm.yml +++ b/environments/rocm.yml @@ -19,12 +19,10 @@ dependencies: - loguru - termcolor - Pillow - - diffusers - psutil - pip: - --extra-index-url https://download.pytorch.org/whl/rocm5.1.1 - - torch - - torchvision + - torch==1.11.* - flask-cloudflared - flask-ngrok - lupa==1.10 @@ -38,3 +36,4 @@ dependencies: - ijson - ftfy - pydub + - diffusers From 857476ef6b22df42a3e275948ff627fa8cebfa09 Mon Sep 17 00:00:00 2001 From: Henk Date: Sun, 8 Jan 2023 17:10:59 +0100 Subject: [PATCH 11/12] ROCm torch version pin --- environments/rocm.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/environments/rocm.yml b/environments/rocm.yml index f47dd6c1..b79615c2 100644 --- a/environments/rocm.yml +++ b/environments/rocm.yml @@ -21,8 +21,7 @@ dependencies: - psutil - pip: - --extra-index-url https://download.pytorch.org/whl/rocm5.1.1 - - torch - - torchvision + - torch==1.11.* - flask-cloudflared - flask-ngrok - lupa==1.10 From ac5c001fc3637d6178e005a440002c43b413ec10 Mon Sep 17 00:00:00 2001 From: somebody Date: Sun, 8 Jan 2023 18:27:23 -0600 Subject: [PATCH 12/12] Fix image retry --- aiserver.py | 9 ++++++--- static/koboldai.js | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/aiserver.py b/aiserver.py index 46b1a56a..046489c5 100644 --- a/aiserver.py +++ b/aiserver.py @@ -9629,6 +9629,12 @@ def log_image_generation( with open(db_path, "w") as file: json.dump(j, file, indent="\t") +@socketio.on("retry_generated_image") +@logger.catch +def UI2_retry_generated_image(): + eventlet.sleep(0) + generate_story_image(koboldai_vars.picture_prompt) + def generate_story_image( prompt: str, file_prefix: str = "image", @@ -9678,9 +9684,6 @@ def generate_story_image( b64_data = base64.b64encode(buffer.getvalue()).decode("ascii") koboldai_vars.picture = b64_data - - - def generate_image(prompt: str) -> Optional[Image.Image]: if koboldai_vars.img_gen_priority == 4: diff --git a/static/koboldai.js b/static/koboldai.js index af8b8909..1981582b 100644 --- a/static/koboldai.js +++ b/static/koboldai.js @@ -6672,7 +6672,7 @@ function imgGenRetry() { const image = $el(".action_image"); if (!image) return; $el("#image-loading").classList.remove("hidden"); - socket.emit("generate_image", {'action_id': image.getAttribute("chunk")}); + socket.emit("retry_generated_image"); } /* Genres */