From a580f18a14d663a0162f7eaf41422498af486506 Mon Sep 17 00:00:00 2001 From: Gnome Ann <> Date: Fri, 31 Dec 2021 16:56:44 -0500 Subject: [PATCH 1/5] Override the `__close` metamethod of `FILE*` objects This enables the use of a Lua 5.4 feature where you can have Lua auto-close a file when exiting a block. For example: ``` do local f = kobold.get_config_file() end ``` If we exit from the `do` block under any circumstances, including via an error or return statement, the `FILE*` `f` automatically closes right before that happens. --- bridge.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/bridge.lua b/bridge.lua index 922d4401..3c720951 100644 --- a/bridge.lua +++ b/bridge.lua @@ -279,6 +279,7 @@ return function(_python, _bridged) end end debug.getmetatable(io.stdout).__index.close = _new_close(io.stdout.close) + debug.getmetatable(io.stdout).__close = _new_close(io.stdout.close) ---@param filename string ---@return boolean From 724118840881ecbce2afc6867ccf104afd24c811 Mon Sep 17 00:00:00 2001 From: Gnome Ann <> Date: Fri, 31 Dec 2021 17:13:11 -0500 Subject: [PATCH 2/5] Make sure tokenizer is initialized when used in read-only mode --- aiserver.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aiserver.py b/aiserver.py index 0ce0ca80..d27f6cae 100644 --- a/aiserver.py +++ b/aiserver.py @@ -2333,6 +2333,11 @@ def calcsubmitbudget(actionlen, winfo, mem, anotetxt, actions, submission=None, lnsp = vars.sp.shape[0] if vars.sp is not None else 0 + if("tokenizer" not in globals()): + from transformers import GPT2TokenizerFast + global tokenizer + tokenizer = GPT2TokenizerFast.from_pretrained("gpt2", cache_dir="cache/") + # Calculate token budget prompttkns = tokenizer.encode(vars.comregex_ai.sub('', vars.prompt), max_length=int(2e9), truncation=True) lnprompt = len(prompttkns) From ccfafe4f0a5df41760e7fb9cf69a7eec9b618eaa Mon Sep 17 00:00:00 2001 From: Gnome Ann <> Date: Fri, 31 Dec 2021 18:28:03 -0500 Subject: [PATCH 3/5] Lua API fixes for deleting/editing story chunks --- aiserver.py | 16 +++++++++------- bridge.lua | 6 +++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/aiserver.py b/aiserver.py index d27f6cae..7d730ec5 100644 --- a/aiserver.py +++ b/aiserver.py @@ -1249,7 +1249,7 @@ def lua_get_numseqs(): def lua_set_numseqs(numseqs): assert type(numseqs) in (int, float) and numseqs >= 1 print(colors.GREEN + f"{lua_log_format_name(vars.lua_koboldbridge.logging_name)} set numseqs to {int(numseqs)}" + colors.END) - vars.genamt = int(numseqs) + vars.numseqs = int(numseqs) #==================================================================# # Check if a setting exists with the given name @@ -1410,8 +1410,8 @@ def lua_set_chunk(k, v): chunk = int(k) if(vars.lua_koboldbridge.userstate == "genmod"): del vars._actions[chunk-1] - vars.lua_deleted.add(chunk) - if(vars._actions is not vars.actions): + vars.lua_deleted.add(chunk) + if(not hasattr(vars, "_actions") or vars._actions is not vars.actions): del vars.actions[chunk-1] else: if(k == 0): @@ -1422,12 +1422,12 @@ def lua_set_chunk(k, v): if(chunk == 0): if(vars.lua_koboldbridge.userstate == "genmod"): vars._prompt = v - vars.lua_edited.add(chunk) + vars.lua_edited.add(chunk) vars.prompt = v else: if(vars.lua_koboldbridge.userstate == "genmod"): vars._actions[chunk-1] = v - vars.lua_edited.add(chunk) + vars.lua_edited.add(chunk) vars.actions[chunk-1] = v #==================================================================# @@ -3118,7 +3118,8 @@ def inlineedit(chunk, data): return vars.prompt = data else: - vars.actions[chunk-1] = data + if(chunk-1 in vars.actions): + vars.actions[chunk-1] = data update_story_chunk(chunk) emit('from_server', {'cmd': 'texteffect', 'data': chunk}, broadcast=True) @@ -3137,7 +3138,8 @@ def inlinedelete(chunk): emit('from_server', {'cmd': 'errmsg', 'data': "Cannot delete the prompt."}) emit('from_server', {'cmd': 'editmode', 'data': 'false'}, broadcast=True) else: - del vars.actions[chunk-1] + if(chunk-1 in vars.actions): + del vars.actions[chunk-1] remove_story_chunk(chunk) emit('from_server', {'cmd': 'editmode', 'data': 'false'}, broadcast=True) diff --git a/bridge.lua b/bridge.lua index 3c720951..a80b1da6 100644 --- a/bridge.lua +++ b/bridge.lua @@ -1916,6 +1916,9 @@ return function(_python, _bridged) koboldbridge.generating = true koboldbridge.generated_cols = 0 koboldbridge.generated = {} + if koboldbridge.inmod ~= nil then + r = koboldbridge.inmod() + end for i = 1, kobold.settings.numseqs do koboldbridge.generated[i] = {} end @@ -1923,9 +1926,6 @@ return function(_python, _bridged) for i = 1, kobold.num_outputs do koboldbridge.outputs[i] = {} end - if koboldbridge.inmod ~= nil then - r = koboldbridge.inmod() - end return r end From b88d49e359e2eed0499cbb7de641f51c2092c0ab Mon Sep 17 00:00:00 2001 From: Gnome Ann <> Date: Fri, 31 Dec 2021 21:22:51 -0500 Subject: [PATCH 4/5] Make all WI commands use UIDs instead of nums --- aiserver.py | 83 +++++++++++++++++++++++-------------------- static/application.js | 16 ++++----- templates/index.html | 2 +- 3 files changed, 53 insertions(+), 48 deletions(-) diff --git a/aiserver.py b/aiserver.py index 7d730ec5..80de124e 100644 --- a/aiserver.py +++ b/aiserver.py @@ -134,7 +134,7 @@ class vars: corescript = "default.lua" # Filename of corescript to load # badwords = [] # Array of str/chr values that should be removed from output badwordsids = [[13460], [6880], [50256], [42496], [4613], [17414], [22039], [16410], [27], [29], [38430], [37922], [15913], [24618], [28725], [58], [47175], [36937], [26700], [12878], [16471], [37981], [5218], [29795], [13412], [45160], [3693], [49778], [4211], [20598], [36475], [33409], [44167], [32406], [29847], [29342], [42669], [685], [25787], [7359], [3784], [5320], [33994], [33490], [34516], [43734], [17635], [24293], [9959], [23785], [21737], [28401], [18161], [26358], [32509], [1279], [38155], [18189], [26894], [6927], [14610], [23834], [11037], [14631], [26933], [46904], [22330], [25915], [47934], [38214], [1875], [14692], [41832], [13163], [25970], [29565], [44926], [19841], [37250], [49029], [9609], [44438], [16791], [17816], [30109], [41888], [47527], [42924], [23984], [49074], [33717], [31161], [49082], [30138], [31175], [12240], [14804], [7131], [26076], [33250], [3556], [38381], [36338], [32756], [46581], [17912], [49146]] # Tokenized array of badwords used to prevent AI artifacting - deletewi = -1 # Temporary storage for index to delete + deletewi = None # Temporary storage for UID to delete wirmvwhtsp = False # Whether to remove leading whitespace from WI entries widepth = 3 # How many historical actions to scan for WI hits mode = "play" # Whether the interface is in play, memory, or edit mode @@ -3205,19 +3205,24 @@ def addwifolder(): addwiitem(folder_uid=uid) #==================================================================# -# Move the WI entry with number src so that it immediately precedes -# the WI entry with number dst +# Move the WI entry with UID src so that it immediately precedes +# the WI entry with UID dst #==================================================================# def movewiitem(dst, src): - if(vars.worldinfo[src]["folder"] is not None): - for i, e in enumerate(vars.wifolders_u[vars.worldinfo[src]["folder"]]): - if(e is vars.worldinfo[src]): - vars.wifolders_u[vars.worldinfo[src]["folder"]].pop(i) + if(vars.worldinfo_u[src]["folder"] is not None): + for i, e in enumerate(vars.wifolders_u[vars.worldinfo_u[src]["folder"]]): + if(e is vars.worldinfo_u[src]): + vars.wifolders_u[vars.worldinfo_u[src]["folder"]].pop(i) break - if(vars.worldinfo[dst]["folder"] is not None): - vars.wifolders_u[vars.worldinfo[dst]["folder"]].append(vars.worldinfo[src]) - vars.worldinfo[src]["folder"] = vars.worldinfo[dst]["folder"] - vars.worldinfo.insert(dst - (dst >= src), vars.worldinfo.pop(src)) + if(vars.worldinfo_u[dst]["folder"] is not None): + vars.wifolders_u[vars.worldinfo_u[dst]["folder"]].append(vars.worldinfo_u[src]) + vars.worldinfo_u[src]["folder"] = vars.worldinfo_u[dst]["folder"] + for i, e in enumerate(vars.worldinfo): + if(e is vars.worldinfo_u[src]): + _src = i + elif(e is vars.worldinfo_u[dst]): + _dst = i + vars.worldinfo.insert(_dst - (_dst >= _src), vars.worldinfo.pop(_src)) sendwi() #==================================================================# @@ -3299,38 +3304,38 @@ def stablesortwi(): #==================================================================# def commitwi(ar): for ob in ar: - vars.worldinfo[ob["num"]]["key"] = ob["key"] - vars.worldinfo[ob["num"]]["keysecondary"] = ob["keysecondary"] - vars.worldinfo[ob["num"]]["content"] = ob["content"] - vars.worldinfo[ob["num"]]["comment"] = ob.get("comment", "") - vars.worldinfo[ob["num"]]["folder"] = ob.get("folder", None) - vars.worldinfo[ob["num"]]["selective"] = ob["selective"] - vars.worldinfo[ob["num"]]["constant"] = ob.get("constant", False) - # Was this a deletion request? If so, remove the requested index - if(vars.deletewi >= 0): - if(vars.worldinfo[vars.deletewi]["folder"] is not None): - for i, e in enumerate(vars.wifolders_u[vars.worldinfo[vars.deletewi]["folder"]]): - if(e is vars.worldinfo[vars.deletewi]): - vars.wifolders_u[vars.worldinfo[vars.deletewi]["folder"]].pop(i) - del vars.worldinfo_u[vars.worldinfo[vars.deletewi]["uid"]] - del vars.worldinfo[vars.deletewi] - # Send the new WI array structure - sendwi() - # And reset deletewi index - vars.deletewi = -1 - else: - stablesortwi() - vars.worldinfo_i = [wi for wi in vars.worldinfo if wi["init"]] + ob["uid"] = int(ob["uid"]) + vars.worldinfo_u[ob["uid"]]["key"] = ob["key"] + vars.worldinfo_u[ob["uid"]]["keysecondary"] = ob["keysecondary"] + vars.worldinfo_u[ob["uid"]]["content"] = ob["content"] + vars.worldinfo_u[ob["uid"]]["comment"] = ob.get("comment", "") + vars.worldinfo_u[ob["uid"]]["folder"] = ob.get("folder", None) + vars.worldinfo_u[ob["uid"]]["selective"] = ob["selective"] + vars.worldinfo_u[ob["uid"]]["constant"] = ob.get("constant", False) + stablesortwi() + vars.worldinfo_i = [wi for wi in vars.worldinfo if wi["init"]] #==================================================================# # #==================================================================# -def deletewi(num): - if(num < len(vars.worldinfo)): - # Store index of deletion request - vars.deletewi = num - # Get contents of WI HTML inputs - requestwi() +def deletewi(uid): + if(uid in vars.worldinfo_u): + # Store UID of deletion request + vars.deletewi = uid + if(vars.deletewi is not None): + if(vars.worldinfo_u[vars.deletewi]["folder"] is not None): + for i, e in enumerate(vars.wifolders_u[vars.worldinfo_u[vars.deletewi]["folder"]]): + if(e is vars.worldinfo_u[vars.deletewi]): + vars.wifolders_u[vars.worldinfo_u[vars.deletewi]["folder"]].pop(i) + for i, e in enumerate(vars.worldinfo): + if(e is vars.worldinfo_u[vars.deletewi]): + del vars.worldinfo[i] + break + del vars.worldinfo_u[vars.deletewi] + # Send the new WI array structure + sendwi() + # And reset deletewi + vars.deletewi = None #==================================================================# # diff --git a/static/application.js b/static/application.js index a827ef13..4d9ab676 100644 --- a/static/application.js +++ b/static/application.js @@ -224,7 +224,7 @@ function addWiLine(ob) { var current_wifolder_element = ob.folder === null ? $(".wisortable-body:not([folder-uid])").last() : $(".wisortable-body[folder-uid="+ob.folder+"]"); if(ob.init) { if(ob.selective){ - current_wifolder_element.append("
\ + current_wifolder_element.append("
\
\ \
\ @@ -262,7 +262,7 @@ function addWiLine(ob) {
\
"); } else { - current_wifolder_element.append("
\ + current_wifolder_element.append("
\
\ \
\ @@ -311,7 +311,7 @@ function addWiLine(ob) { }); } else { // Show WI line item with form fields hidden (uninitialized) - current_wifolder_element.append("
\ + current_wifolder_element.append("
\
\ \
\ @@ -391,7 +391,7 @@ function addWiLine(ob) { hideWiDeleteConfirm(ob.num); }); $("#btn_widel"+ob.num).on("click", function () { - socket.send({'cmd': 'widelete', 'data': ob.num}); + socket.send({'cmd': 'widelete', 'data': ob.uid}); }); $("#selective-key-"+ob.num).on("click", function () { var element = $("#selective-key-"+ob.num); @@ -773,7 +773,7 @@ function returnWiList(ar) { } else { folder = parseInt(folder); } - var ob = {"key": "", "keysecondary": "", "content": "", "comment": "", "folder": null, "num": ar[i], "selective": false, "constant": false}; + var ob = {"key": "", "keysecondary": "", "content": "", "comment": "", "folder": null, "uid": parseInt($("#wilistitem"+ar[i]).attr("uid")), "selective": false, "constant": false}; ob.selective = $("#wikeyprimary"+ar[i]).css("display") != "none" ob.key = ob.selective ? $("#wikeyprimary"+ar[i]).val() : $("#wikey"+ar[i]).val(); ob.keysecondary = $("#wikeysecondary"+ar[i]).val(); @@ -1205,16 +1205,16 @@ function sortableOnStop(event, ui) { // entry was dropped and which WI entry comes immediately after the // dropped position so that the server can internally move around // the WI entries - var next_sibling = ui.item.next(".wilistitem").attr("num"); + var next_sibling = ui.item.next(".wilistitem").attr("uid"); if(next_sibling === undefined) { - next_sibling = ui.item.next().next().attr("num"); + next_sibling = ui.item.next().next().attr("uid"); } next_sibling = parseInt(next_sibling); if(Number.isNaN(next_sibling)) { $(this).sortable("cancel"); return; } - socket.send({'cmd': 'wimoveitem', 'destination': next_sibling, 'data': parseInt(ui.item.attr("num"))}); + socket.send({'cmd': 'wimoveitem', 'destination': next_sibling, 'data': parseInt(ui.item.attr("uid"))}); } else { // Do the same thing for WI folders var next_sibling = ui.item.next(".wisortable-container").attr("folder-uid"); diff --git a/templates/index.html b/templates/index.html index 72dcb784..41a81293 100644 --- a/templates/index.html +++ b/templates/index.html @@ -17,7 +17,7 @@ - + From 3a243f9eed9d4649ac57b8f42747bef72e712247 Mon Sep 17 00:00:00 2001 From: Gnome Ann <> Date: Fri, 31 Dec 2021 22:02:24 -0500 Subject: [PATCH 5/5] Passthrough userscript loading errors --- bridge.lua | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/bridge.lua b/bridge.lua index a80b1da6..db1843ca 100644 --- a/bridge.lua +++ b/bridge.lua @@ -1860,8 +1860,13 @@ return function(_python, _bridged) bridged.load_callback(filename, modulenames[i]) koboldbridge.logging_name = modulenames[i] koboldbridge.filename = filename + local f, err = old_loadfile(join_folder_and_filename(bridged.userscript_path, filename), "t", koboldbridge.get_universe(filename)) + if err ~= nil then + error(err) + return + end ---@type KoboldUserScript - local _userscript = old_loadfile(join_folder_and_filename(bridged.userscript_path, filename), "t", koboldbridge.get_universe(filename))() + local _userscript = f() koboldbridge.logging_name = nil koboldbridge.filename = nil local userscript = deepcopy(KoboldUserScriptModule) @@ -1900,8 +1905,13 @@ return function(_python, _bridged) ---@return nil function koboldbridge.load_corescript(filename) + local f, err = old_loadfile(join_folder_and_filename(bridged.corescript_path, filename), "t", koboldbridge.get_universe(0)) + if err ~= nil then + error(err) + return + end ---@type KoboldCoreScript - local corescript = old_loadfile(join_folder_and_filename(bridged.corescript_path, filename), "t", koboldbridge.get_universe(0))() + local corescript = f() koboldbridge.inmod = corescript.inmod koboldbridge.genmod = corescript.genmod koboldbridge.outmod = corescript.outmod