Add Userscripts menu into GUI

This commit is contained in:
Gnome Ann 2021-12-13 01:03:26 -05:00
parent 5d13339a52
commit d2f5544468
6 changed files with 288 additions and 15 deletions

View File

@ -105,6 +105,7 @@ class vars:
lua_kobold = None # `kobold` from` bridge.lua
lua_koboldcore = None # `koboldcore` from bridge.lua
lua_warper = None # Transformers logits warper controllable from Lua
userscripts = [] # List of userscripts 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
@ -941,23 +942,51 @@ def download():
return(save)
#============================ LUA API =============================#
#============================ LUA API =============================#
if(path.exists("settings/" + getmodelname().replace('/', '_') + ".settings")):
file = open("settings/" + getmodelname().replace('/', '_') + ".settings", "r")
js = json.load(file)
if("userscripts" in js):
vars.userscripts = []
for userscript in js["userscripts"]:
if type(userscript) is not str:
continue
userscript = userscript.strip()
if len(userscript) != 0 and all(q not in userscript for q in ("..", ":")) and all(userscript[0] not in q for q in ("/", "\\")) and os.path.exists(fileops.uspath(userscript)):
vars.userscripts.append(userscript)
file.close()
#==================================================================#
# Event triggered when a userscript is loaded
#==================================================================#
def load_callback(filename):
print(colors.PURPLE + f"Loading Userscript [USERPLACEHOLDER] <{filename}>" + colors.END)
def load_callback(filename, modulename):
print(colors.PURPLE + f"Loading Userscript [{modulename}] <{filename}>" + colors.END)
#==================================================================#
# Load all Lua scripts
#==================================================================#
def load_lua_scripts():
print(colors.PURPLE + "Loading Core Script [COREPLACEHOLDER] <default.lua>" + colors.END)
filenames = []
modulenames = []
descriptions = []
lst = fileops.getusfiles(long_desc=True)
filenames_dict = {ob["filename"]: i for i, ob in enumerate(lst)}
for filename in vars.userscripts:
if filename in filenames_dict:
i = filenames_dict[filename]
filenames.append(filename)
modulenames.append(lst[i]["modulename"])
descriptions.append(lst[i]["description"])
try:
vars.lua_koboldbridge.obliterate_multiverse()
vars.lua_koboldbridge.load_corescript("default.lua")
vars.lua_koboldbridge.load_userscripts([], [], [])
vars.lua_koboldbridge.load_userscripts(filenames, modulenames, descriptions)
except lupa.LuaError as e:
print(e, file=sys.stderr)
exit(1)
@ -1534,6 +1563,21 @@ def get_message(msg):
getloadlist()
elif(msg['cmd'] == 'splistrequest'):
getsplist()
elif(msg['cmd'] == 'uslistrequest'):
getuslist()
elif(msg['cmd'] == 'usloaded'):
vars.userscripts = []
for userscript in msg['data']:
if type(userscript) is not str:
continue
userscript = userscript.strip()
if len(userscript) != 0 and all(q not in userscript for q in ("..", ":")) and all(userscript[0] not in q for q in ("/", "\\")) and os.path.exists(fileops.uspath(userscript)):
vars.userscripts.append(userscript)
settingschanged()
elif(msg['cmd'] == 'usload'):
load_lua_scripts()
elif(msg['cmd'] == 'usload'):
getuslist()
elif(msg['cmd'] == 'loadselect'):
vars.loadselect = msg["data"]
elif(msg['cmd'] == 'spselect'):
@ -1630,6 +1674,8 @@ def savesettings():
js["adventure"] = vars.adventure
js["dynamicscan"] = vars.dynamicscan
js["userscripts"] = vars.userscripts
# Write it
if not os.path.exists('settings'):
os.mkdir('settings')
@ -1682,6 +1728,15 @@ def loadsettings():
if("dynamicscan" in js):
vars.dynamicscan = js["dynamicscan"]
if("userscripts" in js):
vars.userscripts = []
for userscript in js["userscripts"]:
if type(userscript) is not str:
continue
userscript = userscript.strip()
if len(userscript) != 0 and all(q not in userscript for q in ("..", ":")) and all(userscript[0] not in q for q in ("/", "\\")) and os.path.exists(fileops.uspath(userscript)):
vars.userscripts.append(userscript)
file.close()
#==================================================================#
@ -3213,6 +3268,21 @@ def getsplist():
if(vars.allowsp):
emit('from_server', {'cmd': 'buildsp', 'data': fileops.getspfiles(vars.modeldim)})
#==================================================================#
# Show list of userscripts
#==================================================================#
def getuslist():
files = {i: v for i, v in enumerate(fileops.getusfiles())}
loaded = []
unloaded = []
userscripts = set(vars.userscripts)
for i in range(len(files)):
if files[i]["filename"] in userscripts:
loaded.append(files[i])
else:
unloaded.append(files[i])
emit('from_server', {'cmd': 'buildus', 'data': {"unloaded": unloaded, "loaded": loaded}})
#==================================================================#
# Load a saved story via file browser
#==================================================================#
@ -3659,11 +3729,6 @@ def randomGameRequest(topic):
# Final startup commands to launch Flask app
#==================================================================#
if __name__ == "__main__":
# Load settings from client.settings
loadmodelsettings()
loadsettings()
# Start Flask/SocketIO (Blocking, so this must be last method!)
#socketio.run(app, host='0.0.0.0', port=5000)

View File

@ -1550,7 +1550,7 @@ return function(_python, _bridged)
koboldbridge.userscripts = {}
koboldbridge.num_userscripts = 0
for i, filename in _python.enumerate(filenames) do
bridged.load_callback(filename)
bridged.load_callback(filename, modulenames[i])
---@type KoboldUserScript
local _userscript = old_loadfile(join_folder_and_filename(bridged.userscript_path, filename), "t", koboldbridge.get_universe(filename))()
local userscript = deepcopy(KoboldUserScriptModule)

View File

@ -69,6 +69,12 @@ def storypath(name):
def sppath(filename):
return path.join(path.dirname(path.realpath(__file__)), "softprompts", filename)
#==================================================================#
# Returns the path (as a string) to the given username by its filename
#==================================================================#
def uspath(filename):
return path.join(path.dirname(path.realpath(__file__)), "userscripts", filename)
#==================================================================#
# Returns an array of dicts containing story files in /stories
#==================================================================#
@ -158,6 +164,53 @@ def getspfiles(model_dimension: int):
lst.append(ob)
return lst
#==================================================================#
# Returns an array of dicts containing userscript files in /userscripts
#==================================================================#
def getusfiles(long_desc=False):
lst = []
for file in listdir(path.dirname(path.realpath(__file__))+"/userscripts"):
if file.endswith(".lua"):
ob = {}
ob["filename"] = file
description = []
multiline = False
with open(uspath(file)) as f:
ob["modulename"] = f.readline().strip().replace("\033", "")
if ob["modulename"][:2] != "--":
ob["modulename"] = file
else:
ob["modulename"] = ob["modulename"][2:]
if ob["modulename"][:2] == "[[":
ob["modulename"] = ob["modulename"][2:]
multiline = True
ob["modulename"] = ob["modulename"].lstrip("-").strip()
for line in f:
line = line.strip().replace("\033", "")
if multiline:
index = line.find("]]")
if index > -1:
description.append(line[:index])
if index != len(line) - 2:
break
multiline = False
else:
description.append(line)
else:
if line[:2] != "--":
break
line = line[2:]
if line[:2] == "[[":
multiline = True
line = line[2:]
description.append(line.strip())
ob["description"] = "\n".join(description)
if not long_desc:
if len(ob["description"]) > 250:
ob["description"] = ob["description"][:247] + "..."
lst.append(ob)
return lst
#==================================================================#
# Returns True if json file exists with requested save name
#==================================================================#

View File

@ -19,6 +19,7 @@ var button_impaidg;
var button_settings;
var button_format;
var button_softprompt;
var button_userscripts;
var button_mode;
var button_mode_label;
var button_send;
@ -58,6 +59,10 @@ var sppopup;
var spcontent;
var sp_accept;
var sp_close;
var uspopup;
var uscontent;
var us_accept;
var us_close;
var nspopup;
var ns_accept;
var ns_close;
@ -851,6 +856,17 @@ function hideSPPopup() {
spcontent.html("");
}
function showUSPopup() {
uspopup.removeClass("hidden");
uspopup.addClass("flex");
}
function hideUSPopup() {
uspopup.removeClass("flex");
uspopup.addClass("hidden");
spcontent.html("");
}
function buildLoadList(ar) {
disableButtons([load_accept]);
loadcontent.html("");
@ -954,6 +970,33 @@ function buildSPList(ar) {
}
}
function buildUSList(unloaded, loaded) {
usunloaded.html("");
usloaded.html("");
showUSPopup();
var i;
var j;
var el = usunloaded;
var ar = unloaded;
for(j=0; j<2; j++) {
for(i=0; i<ar.length; i++) {
el.append("<div class=\"flex\">\
<div class=\"uslistitem flex-row-container\" name=\""+ar[i].filename+"\">\
<div class=\"flex-row\">\
<div>"+ar[i].modulename+"</div>\
<div class=\"flex-push-right uslistitemsub\">&lt;"+ar[i].filename+"&gt;</div>\
</div>\
<div class=\"flex-row\">\
<div>"+ar[i].description+"</div>\
</div>\
</div>\
</div>");
}
el = usloaded;
ar = loaded;
}
}
function highlightLoadLine(ref) {
$("#loadlistcontent > div > div.popuplistselected").removeClass("popuplistselected");
ref.addClass("popuplistselected");
@ -1521,6 +1564,7 @@ $(document).ready(function(){
button_settings = $('#btn_settings');
button_format = $('#btn_format');
button_softprompt = $("#btn_softprompt");
button_userscripts= $("#btn_userscripts");
button_mode = $('#btnmode')
button_mode_label = $('#btnmode_label')
button_send = $('#btnsend');
@ -1560,6 +1604,11 @@ $(document).ready(function(){
spcontent = $("#splistcontent");
sp_accept = $("#btn_spaccept");
sp_close = $("#btn_spclose");
uspopup = $("#uscontainer");
usunloaded = $("#uslistunloaded");
usloaded = $("#uslistloaded");
us_accept = $("#btn_usaccept");
us_close = $("#btn_usclose");
nspopup = $("#newgamecontainer");
ns_accept = $("#btn_nsaccept");
ns_close = $("#btn_nsclose");
@ -1928,6 +1977,8 @@ $(document).ready(function(){
buildLoadList(msg.data);
} else if(msg.cmd == "buildsp") {
buildSPList(msg.data);
} else if(msg.cmd == "buildus") {
buildUSList(msg.data.unloaded, msg.data.loaded);
} else if(msg.cmd == "askforoverwrite") {
// Show overwrite warning
show([$(".saveasoverwrite")]);
@ -2006,6 +2057,23 @@ $(document).ready(function(){
}, 2);
});
// Make the userscripts menu sortable
var us_sortable_settings = {
delay: 2,
cursor: "move",
tolerance: "pointer",
opacity: 0.21,
revert: 173,
scrollSensitivity: 64,
scrollSpeed: 10,
}
$(usunloaded).sortable($.extend({
connectWith: "#uslistloaded",
}, us_sortable_settings));
$(usloaded).sortable($.extend({
connectWith: "#uslistunloaded",
}, us_sortable_settings));
// Bind actions to UI buttons
button_send.on("click", function(ev) {
dosubmit();
@ -2124,6 +2192,10 @@ $(document).ready(function(){
button_softprompt.on("click", function(ev) {
socket.send({'cmd': 'splistrequest', 'data': ''});
});
button_userscripts.on("click", function(ev) {
socket.send({'cmd': 'uslistrequest', 'data': ''});
});
load_close.on("click", function(ev) {
hideLoadPopup();
@ -2143,6 +2215,17 @@ $(document).ready(function(){
socket.send({'cmd': 'sprequest', 'data': ''});
hideSPPopup();
});
us_close.on("click", function(ev) {
socket.send({'cmd': 'usloaded', 'data': usloaded.find(".uslistitem").map(function() { return $(this).attr("name"); }).toArray()});
hideUSPopup();
});
us_accept.on("click", function(ev) {
socket.send({'cmd': 'usloaded', 'data': usloaded.find(".uslistitem").map(function() { return $(this).attr("name"); }).toArray()});
socket.send({'cmd': 'usload', 'data': ''});
hideUSPopup();
});
button_newgame.on("click", function(ev) {
showNewStoryPopup();

View File

@ -316,13 +316,13 @@ chunk.editing, chunk.editing * {
}
#sppopup {
width: 500px;
width: 800px;
background-color: #262626;
margin-top: 100px;
}
@media (max-width: 768px) {
#loadpopup {
#sppopup {
width: 100%;
background-color: #262626;
margin-top: 100px;
@ -342,7 +342,33 @@ chunk.editing, chunk.editing * {
}
#splistcontent {
height: 325px;
height: 425px;
overflow-y: scroll;
overflow-wrap: anywhere;
}
#uspopup {
width: 800px;
background-color: #262626;
margin-top: 100px;
}
@media (max-width: 768px) {
#uspopup {
width: 100%;
background-color: #262626;
margin-top: 100px;
}
}
#uslistunloaded {
height: 425px;
overflow-y: scroll;
overflow-wrap: anywhere;
}
#uslistloaded {
height: 425px;
overflow-y: scroll;
overflow-wrap: anywhere;
}
@ -807,6 +833,11 @@ chunk.editing, chunk.editing * {
color: #fce94f
}
.uslistgrid {
display: grid;
grid-template-columns: 50% 50%;
}
.navbar .navbar-nav .nav-link:hover {
border-radius: 5px;
background-color: #98bcdb;
@ -1020,6 +1051,27 @@ chunk.editing, chunk.editing * {
background-color: #688f1f;
}
.uslistitem {
padding: 12px 10px 12px 10px;
display: flex;
flex-grow: 1;
color: #ffffff;
-moz-transition: background-color 0.25s ease-in;
-o-transition: background-color 0.25s ease-in;
-webkit-transition: background-color 0.25s ease-in;
transition: background-color 0.25s ease-in;
}
.uslistitemsub {
color: #ba9;
}
.uslistitem:hover {
cursor: move;
background-color: #688f1f;
}
.width-auto {
width: auto;
}

View File

@ -7,7 +7,7 @@
<script src="static/jquery-3.6.0.min.js"></script>
<script src="static/jquery-ui.sortable.min.js"></script>
<script src="static/socket.io.min.js"></script>
<script src="static/application.js?ver=1.16.4c"></script>
<script src="static/application.js?ver=1.16.4d"></script>
<script src="static/bootstrap.min.js"></script>
<script src="static/bootstrap-toggle.min.js"></script>
<script src="static/rangy-core.min.js"></script>
@ -15,7 +15,7 @@
<link rel="stylesheet" href="static/jquery-ui.sortable.min.css">
<link rel="stylesheet" href="static/bootstrap.min.css">
<link rel="stylesheet" href="static/bootstrap-toggle.min.css">
<link rel="stylesheet" href="static/custom.css?ver=1.16.4c">
<link rel="stylesheet" href="static/custom.css?ver=1.16.4d">
<link rel="stylesheet" href="static/open-iconic-bootstrap.min.css">
</head>
<body>
@ -70,6 +70,9 @@
<li class="nav-item">
<a class="nav-link" href="#" id="btn_format">Formatting</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#" id="btn_userscripts">Userscripts</a>
</li>
<li class="nav-item">
<a class="nav-link hidden" href="#" id="btn_softprompt">Soft Prompt</a>
</li>
@ -244,6 +247,23 @@
</div>
</div>
</div>
<div class="popupcontainer hidden" id="uscontainer">
<div id="uspopup">
<div class="popuptitlebar">
<div class="popuptitletext">Select userscripts to load; drag-and-drop to reorder</div>
</div>
<div class="uslistgrid">
<div id="uslistunloaded">
</div>
<div id="uslistloaded">
</div>
</div>
<div class="popupfooter">
<button type="button" class="btn btn-primary" id="btn_usaccept">Load</button>
<button type="button" class="btn btn-primary" id="btn_usclose">Cancel</button>
</div>
</div>
</div>
<div class="popupcontainer hidden" id="loadcontainerdelete">
<div id="loadpopupdelete">
<div class="popuptitlebar">