From 1951ccd2ce62d7dec9c8974f15645b6a5018ef3f Mon Sep 17 00:00:00 2001 From: Gnome Ann <> Date: Tue, 18 Jan 2022 16:30:09 -0500 Subject: [PATCH 1/2] Show author and SP length in soft prompt menu --- aiserver.py | 3 ++- fileops.py | 1 + static/application.js | 15 +++++++++------ static/custom.css | 1 + templates/index.html | 4 ++-- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/aiserver.py b/aiserver.py index 11760cc4..540b25e6 100644 --- a/aiserver.py +++ b/aiserver.py @@ -4156,7 +4156,8 @@ def spRequest(filename): tensor = np.float32(tensor) assert not np.isinf(tensor).any() and not np.isnan(tensor).any() - vars.sp_length = tensor.shape[0] + vars.sp_length = tensor.shape[-2] + vars.spmeta["n_tokens"] = vars.sp_length if(vars.model in ("TPUMeshTransformerGPTJ",)): rows = tensor.shape[0] diff --git a/fileops.py b/fileops.py index e5697553..50f1e94f 100644 --- a/fileops.py +++ b/fileops.py @@ -161,6 +161,7 @@ def getspfiles(model_dimension: int): ob = {} z.close() ob["filename"] = file + ob["n_tokens"] = shape[-2] lst.append(ob) return lst diff --git a/static/application.js b/static/application.js index e8a3202f..8b6a2380 100644 --- a/static/application.js +++ b/static/application.js @@ -972,11 +972,14 @@ function buildSPList(ar) { showSPPopup(); ar.push({filename: '', name: "[None]"}) for(var i = 0; i < ar.length; i++) { - var supported = !ar[i].supported + var author = !ar[i].author ? '' - : Object.prototype.toString.call(ar[i].supported) === "[object Array]" - ? "[" + ar[i].supported.join(', ') + "]" - : "[" + ar[i].supported.toString() + "]"; + : ar[i].author.constructor === Array + ? ar[i].author.join(', ') + : ar[i].author; + var n_tokens = !ar[i].n_tokens || !Number.isSafeInteger(ar[i].n_tokens) || ar[i].n_tokens < 1 + ? '' + : "(" + ar[i].n_tokens + " tokens)"; var filename = ar[i].filename.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/(?=\r|\n)\r?\n?/g, '
'); var name = ar[i].name || ar[i].filename; name = name.length > 120 ? name.slice(0, 117) + '...' : name; @@ -992,7 +995,7 @@ function buildSPList(ar) { \
\
"+desc+"
\ -
"+supported+"
\ +
" + author + "
" + n_tokens + "
\
\ \ "); @@ -1108,7 +1111,7 @@ function updateSPStatItems(items) { stat_sp.closest(".statusicon").removeClass("active"); stat_spactive.html(""); } else { - stat_sp.html("Active soft prompt:"); + stat_sp.html("Active soft prompt (" + items[key].n_tokens + " tokens):"); stat_sp.closest(".statusicon").addClass("active"); stat_spactive.html((items[key].name || key)+" <"+key+">"); } diff --git a/static/custom.css b/static/custom.css index ce9c23d4..da30c6ed 100644 --- a/static/custom.css +++ b/static/custom.css @@ -1312,6 +1312,7 @@ body.connected .popupfooter, .popupfooter.always-available { .splistitemsub { color: #ba9; + text-align: right; } .splistitem:hover { diff --git a/templates/index.html b/templates/index.html index f4d67f83..1f13ed8d 100644 --- a/templates/index.html +++ b/templates/index.html @@ -9,7 +9,7 @@ - + @@ -17,7 +17,7 @@ - + From 3018322963494677e9d3ce34e6ea90dc2cbdfb09 Mon Sep 17 00:00:00 2001 From: Gnome Ann <> Date: Tue, 18 Jan 2022 17:20:45 -0500 Subject: [PATCH 2/2] Detect and show properly when story is unsaved --- aiserver.py | 42 +++++++++++++++++++++++++++++++++++++++++- static/application.js | 32 +++++++++++++++++++++++++++++++- templates/index.html | 2 +- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/aiserver.py b/aiserver.py index 540b25e6..ec932163 100644 --- a/aiserver.py +++ b/aiserver.py @@ -105,6 +105,7 @@ class vars: tfs = 1.0 # Default generator tfs (tail-free sampling) numseqs = 1 # Number of sequences to ask the generator to create gamestarted = False # Whether the game has started (disables UI elements) + gamesaved = True # Whether or not current game is saved serverstarted = False # Whether or not the Flask server has started prompt = "" # Prompt memory = "" # Text submitted to memory field @@ -1646,6 +1647,7 @@ def lua_is_custommodel(): # #==================================================================# def execute_inmod(): + setgamesaved(False) vars.lua_logname = ... vars.lua_edited = set() vars.lua_deleted = set() @@ -1665,6 +1667,7 @@ def execute_genmod(): vars.lua_koboldbridge.execute_genmod() def execute_outmod(): + setgamesaved(False) emit('from_server', {'cmd': 'hidemsg', 'data': ''}, broadcast=True) try: tpool.execute(vars.lua_koboldbridge.execute_outmod) @@ -1732,7 +1735,7 @@ def do_connect(): print("{0}Client connected!{1}".format(colors.GREEN, colors.END)) emit('from_server', {'cmd': 'setchatname', 'data': vars.chatname}) emit('from_server', {'cmd': 'setanotetemplate', 'data': vars.authornotetemplate}) - emit('from_server', {'cmd': 'connected', 'smandelete': vars.smandelete, 'smanrename': vars.smanrename}) + emit('from_server', {'cmd': 'connected', 'smandelete': vars.smandelete, 'smanrename': vars.smanrename, 'modelname': getmodelname()}) if(vars.remote): emit('from_server', {'cmd': 'runs_remotely'}) if(vars.allowsp): @@ -1772,6 +1775,8 @@ def do_connect(): elif(vars.mode == "wi"): emit('from_server', {'cmd': 'wimode', 'data': 'true'}) + emit('from_server', {'cmd': 'gamesaved', 'data': vars.gamesaved}, broadcast=True) + #==================================================================# # Event triggered when browser SocketIO sends data to the server #==================================================================# @@ -1936,6 +1941,7 @@ def get_message(msg): togglewimode() elif(msg['cmd'] == 'wiinit'): if(int(msg['data']) < len(vars.worldinfo)): + setgamesaved(False) vars.worldinfo[msg['data']]["init"] = True addwiitem(folder_uid=msg['folder']) elif(msg['cmd'] == 'wifolderinit'): @@ -1950,17 +1956,22 @@ def get_message(msg): deletewifolder(msg['data']) elif(msg['cmd'] == 'wiexpand'): assert 0 <= int(msg['data']) < len(vars.worldinfo) + setgamesaved(False) emit('from_server', {'cmd': 'wiexpand', 'data': msg['data']}, broadcast=True) elif(msg['cmd'] == 'wiexpandfolder'): assert 0 <= int(msg['data']) < len(vars.worldinfo) + setgamesaved(False) emit('from_server', {'cmd': 'wiexpandfolder', 'data': msg['data']}, broadcast=True) elif(msg['cmd'] == 'wifoldercollapsecontent'): + setgamesaved(False) vars.wifolders_d[msg['data']]['collapsed'] = True emit('from_server', {'cmd': 'wifoldercollapsecontent', 'data': msg['data']}, broadcast=True) elif(msg['cmd'] == 'wifolderexpandcontent'): + setgamesaved(False) vars.wifolders_d[msg['data']]['collapsed'] = False emit('from_server', {'cmd': 'wifolderexpandcontent', 'data': msg['data']}, broadcast=True) elif(msg['cmd'] == 'wiupdate'): + setgamesaved(False) num = int(msg['num']) fields = ("key", "keysecondary", "content", "comment") for field in fields: @@ -1968,6 +1979,7 @@ def get_message(msg): vars.worldinfo[num][field] = msg['data'][field] emit('from_server', {'cmd': 'wiupdate', 'num': msg['num'], 'data': {field: vars.worldinfo[num][field] for field in fields}}, broadcast=True) elif(msg['cmd'] == 'wifolderupdate'): + setgamesaved(False) uid = int(msg['uid']) fields = ("name", "collapsed") for field in fields: @@ -1975,15 +1987,19 @@ def get_message(msg): vars.wifolders_d[uid][field] = msg['data'][field] emit('from_server', {'cmd': 'wifolderupdate', 'uid': msg['uid'], 'data': {field: vars.wifolders_d[uid][field] for field in fields}}, broadcast=True) elif(msg['cmd'] == 'wiselon'): + setgamesaved(False) vars.worldinfo[msg['data']]["selective"] = True emit('from_server', {'cmd': 'wiselon', 'data': msg['data']}, broadcast=True) elif(msg['cmd'] == 'wiseloff'): + setgamesaved(False) vars.worldinfo[msg['data']]["selective"] = False emit('from_server', {'cmd': 'wiseloff', 'data': msg['data']}, broadcast=True) elif(msg['cmd'] == 'wiconstanton'): + setgamesaved(False) vars.worldinfo[msg['data']]["constant"] = True emit('from_server', {'cmd': 'wiconstanton', 'data': msg['data']}, broadcast=True) elif(msg['cmd'] == 'wiconstantoff'): + setgamesaved(False) vars.worldinfo[msg['data']]["constant"] = False emit('from_server', {'cmd': 'wiconstantoff', 'data': msg['data']}, broadcast=True) elif(msg['cmd'] == 'sendwilist'): @@ -2279,6 +2295,15 @@ def settingschanged(): print("{0}Saving settings!{1}".format(colors.GREEN, colors.END)) savesettings() +#==================================================================# +# Set value of gamesaved +#==================================================================# +def setgamesaved(gamesaved): + assert type(gamesaved) is bool + if(gamesaved != vars.gamesaved): + emit('from_server', {'cmd': 'gamesaved', 'data': gamesaved}, broadcast=True) + vars.gamesaved = gamesaved + #==================================================================# # Take input text from SocketIO and decide what to do with it #==================================================================# @@ -3330,6 +3355,7 @@ def inlineedit(chunk, data): if(chunk-1 in vars.actions): vars.actions[chunk-1] = data + setgamesaved(False) update_story_chunk(chunk) emit('from_server', {'cmd': 'texteffect', 'data': chunk}, broadcast=True) emit('from_server', {'cmd': 'editmode', 'data': 'false'}, broadcast=True) @@ -3349,6 +3375,7 @@ def inlinedelete(chunk): else: if(chunk-1 in vars.actions): del vars.actions[chunk-1] + setgamesaved(False) remove_story_chunk(chunk) emit('from_server', {'cmd': 'editmode', 'data': 'false'}, broadcast=True) @@ -3418,6 +3445,7 @@ def addwifolder(): # the WI entry with UID dst #==================================================================# def movewiitem(dst, src): + setgamesaved(False) 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]): @@ -3439,6 +3467,7 @@ def movewiitem(dst, src): # the WI folder with UID dst #==================================================================# def movewifolder(dst, src): + setgamesaved(False) vars.wifolders_l.remove(src) if(dst is None): # If dst is None, that means we should move src to be the last folder @@ -3662,6 +3691,8 @@ def memsubmit(data): emit('from_server', {'cmd': 'setinputtext', 'data': data}, broadcast=True) # Maybe check for length at some point # For now just send it to storage + if(data != vars.memory): + setgamesaved(False) vars.memory = data vars.mode = "play" emit('from_server', {'cmd': 'memmode', 'data': 'false'}, broadcast=True) @@ -3676,6 +3707,8 @@ def anotesubmit(data, template=""): assert type(data) is str and type(template) is str # Maybe check for length at some point # For now just send it to storage + if(data != vars.authornote): + setgamesaved(False) vars.authornote = data if(vars.authornotetemplate != template): @@ -3963,6 +3996,7 @@ def saveRequest(savpath): filename = filename[:-5] vars.laststory = filename emit('from_server', {'cmd': 'setstoryname', 'data': vars.laststory}, broadcast=True) + setgamesaved(True) print("{0}Story saved to {1}!{2}".format(colors.GREEN, path.basename(savpath), colors.END)) #==================================================================# @@ -4112,6 +4146,7 @@ def loadRequest(loadpath, filename=None): _filename = filename[:-5] vars.laststory = _filename emit('from_server', {'cmd': 'setstoryname', 'data': vars.laststory}, broadcast=True) + setgamesaved(True) sendwi() emit('from_server', {'cmd': 'setmemory', 'data': vars.memory}, broadcast=True) emit('from_server', {'cmd': 'setanote', 'data': vars.authornote}, broadcast=True) @@ -4319,6 +4354,7 @@ def importgame(): # Refresh game screen vars.laststory = None emit('from_server', {'cmd': 'setstoryname', 'data': vars.laststory}, broadcast=True) + setgamesaved(False) sendwi() emit('from_server', {'cmd': 'setmemory', 'data': vars.memory}, broadcast=True) emit('from_server', {'cmd': 'setanote', 'data': vars.authornote}, broadcast=True) @@ -4399,6 +4435,7 @@ def importAidgRequest(id): # Refresh game screen vars.laststory = None emit('from_server', {'cmd': 'setstoryname', 'data': vars.laststory}, broadcast=True) + setgamesaved(False) sendwi() emit('from_server', {'cmd': 'setmemory', 'data': vars.memory}, broadcast=True) emit('from_server', {'cmd': 'setanote', 'data': vars.authornote}, broadcast=True) @@ -4456,6 +4493,7 @@ def wiimportrequest(): print("{0}".format(vars.worldinfo[0])) # Refresh game screen + setgamesaved(False) sendwi() #==================================================================# @@ -4488,6 +4526,7 @@ def newGameRequest(): # Refresh game screen vars.laststory = None emit('from_server', {'cmd': 'setstoryname', 'data': vars.laststory}, broadcast=True) + setgamesaved(True) sendwi() emit('from_server', {'cmd': 'setmemory', 'data': vars.memory}, broadcast=True) emit('from_server', {'cmd': 'setanote', 'data': vars.authornote}, broadcast=True) @@ -4501,6 +4540,7 @@ def randomGameRequest(topic, memory=""): vars.recentrng = topic vars.recentrngm = memory newGameRequest() + setgamesaved(False) _memory = memory if(len(memory) > 0): _memory = memory.rstrip() + "\n\n" diff --git a/static/application.js b/static/application.js index 8b6a2380..14d7de37 100644 --- a/static/application.js +++ b/static/application.js @@ -93,6 +93,8 @@ var sman_allow_rename = false; var allowsp = false; var remote = false; var gamestate = ""; +var gamesaved = true; +var modelname = null; // This is true iff [we're in macOS and the browser is Safari] or [we're in iOS] var using_webkit_patch = true; @@ -169,6 +171,23 @@ function addSetting(ob) { } } +function refreshTitle() { + var title = gamesaved ? "" : "\u2731 "; + if(storyname !== null) { + title += storyname + " \u2014 "; + } + title += "KoboldAI Client"; + if(modelname !== null) { + title += " (" + modelname + ")"; + } + document.title = title; +} + +function setGameSaved(state) { + gamesaved = !!state; + refreshTitle(); +} + function addFormat(ob) { // Check if we need to make a new column for this button if(formatcount == 0) { @@ -1780,6 +1799,10 @@ $(document).ready(function(){ sman_allow_delete = msg.hasOwnProperty("smandelete") && msg.smandelete; sman_allow_rename = msg.hasOwnProperty("smanrename") && msg.smanrename; connected = true; + if(msg.hasOwnProperty("modelname")) { + modelname = msg.modelname; + } + refreshTitle(); connect_status.html("Connected to KoboldAI Process!"); connect_status.removeClass("color_orange"); connect_status.addClass("color_green"); @@ -1911,6 +1934,7 @@ $(document).ready(function(){ } } else if(msg.cmd == "setstoryname") { storyname = msg.data; + refreshTitle(); } else if(msg.cmd == "editmode") { // Enable or Disable edit mode if(msg.data == "true") { @@ -2141,6 +2165,8 @@ $(document).ready(function(){ } else if(msg.cmd == "saveas") { // Show Save As prompt showSaveAsPopup(); + } else if(msg.cmd == "gamesaved") { + setGameSaved(msg.data); } else if(msg.cmd == "hidesaveas") { // Hide Save As prompt hideSaveAsPopup(); @@ -2537,8 +2563,12 @@ $(document).ready(function(){ } }); + $([input_text, anote_input, $("#gamescreen")]).map($.fn.toArray).on("input", function() { + setGameSaved(false); + }); + $(window).on("beforeunload", function() { - if(gamestarted || memorytext.length > 0 || $("#anoteinput").val().length > 0 || $(".wilistitem").length > 1) { + if(!gamesaved) { return true; } }); diff --git a/templates/index.html b/templates/index.html index 1f13ed8d..be53a03d 100644 --- a/templates/index.html +++ b/templates/index.html @@ -17,7 +17,7 @@ - +