Presets and Remaining time updates

This commit is contained in:
ebolam
2022-06-27 18:36:22 -04:00
parent 057f3dd92d
commit 0ffaa1bfcf
7 changed files with 480 additions and 223 deletions

View File

@@ -1024,8 +1024,12 @@ def get_model_info(model, directory=""):
breakmodel = False
else:
breakmodel = True
if path.exists("settings/{}.breakmodel".format(model.replace("/", "_"))):
with open("settings/{}.breakmodel".format(model.replace("/", "_")), "r") as file:
if model in ["NeoCustom", "GPT2Custom"]:
filename = os.path.basename(os.path.normpath(directory))
else:
filename = "settings/{}.breakmodel".format(model.replace("/", "_"))
if path.exists(filename):
with open(filename, "r") as file:
data = file.read().split("\n")[:2]
if len(data) < 2:
data.append("0")
@@ -1034,10 +1038,6 @@ def get_model_info(model, directory=""):
else:
break_values = [layer_count]
break_values += [0] * (gpu_count - len(break_values))
#print("Model_info: {}".format({'cmd': 'selected_model_info', 'key_value': key_value, 'key':key,
# 'gpu':gpu, 'layer_count':layer_count, 'breakmodel':breakmodel,
# 'break_values': break_values, 'gpu_count': gpu_count,
# 'url': url, 'gpu_names': gpu_names}))
emit('from_server', {'cmd': 'selected_model_info', 'key_value': key_value, 'key':key,
'gpu':gpu, 'layer_count':layer_count, 'breakmodel':breakmodel,
'disk_break_value': disk_blocks, 'accelerate': utils.HAS_ACCELERATE,
@@ -1341,10 +1341,10 @@ def patch_transformers():
scores: torch.FloatTensor,
**kwargs,
) -> bool:
story_settings.generated_tkns += 1
if(system_settings.lua_koboldbridge.generated_cols and story_settings.generated_tkns != system_settings.lua_koboldbridge.generated_cols):
raise RuntimeError(f"Inconsistency detected between KoboldAI Python and Lua backends ({story_settings.generated_tkns} != {system_settings.lua_koboldbridge.generated_cols})")
if(system_settings.abort or story_settings.generated_tkns >= model_settings.genamt):
model_settings.generated_tkns += 1
if(system_settings.lua_koboldbridge.generated_cols and model_settings.generated_tkns != system_settings.lua_koboldbridge.generated_cols):
raise RuntimeError(f"Inconsistency detected between KoboldAI Python and Lua backends ({model_settings.generated_tkns} != {system_settings.lua_koboldbridge.generated_cols})")
if(system_settings.abort or model_settings.generated_tkns >= model_settings.genamt):
self.regeneration_required = False
self.halt = False
return True
@@ -1356,11 +1356,11 @@ def patch_transformers():
system_settings.lua_koboldbridge.regeneration_required = False
for i in range(model_settings.numseqs):
system_settings.lua_koboldbridge.generated[i+1][story_settings.generated_tkns] = int(input_ids[i, -1].item())
system_settings.lua_koboldbridge.generated[i+1][model_settings.generated_tkns] = int(input_ids[i, -1].item())
if(not story_settings.dynamicscan):
return self.regeneration_required or self.halt
tail = input_ids[..., -story_settings.generated_tkns:]
tail = input_ids[..., -model_settings.generated_tkns:]
for i, t in enumerate(tail):
decoded = utils.decodenewlines(tokenizer.decode(t))
_, found = checkworldinfo(decoded, force_use_txt=True, actions=story_settings._actions)
@@ -1970,17 +1970,17 @@ def load_model(use_gpu=True, gpu_layers=None, disk_layers=None, initial_load=Fal
return scores
def tpumtjgenerate_stopping_callback(generated, n_generated, excluded_world_info) -> Tuple[List[set], bool, bool]:
story_settings.generated_tkns += 1
model_settings.generated_tkns += 1
assert len(excluded_world_info) == len(generated)
regeneration_required = system_settings.lua_koboldbridge.regeneration_required
halt = system_settings.abort or not system_settings.lua_koboldbridge.generating or story_settings.generated_tkns >= model_settings.genamt
halt = system_settings.abort or not system_settings.lua_koboldbridge.generating or model_settings.generated_tkns >= model_settings.genamt
system_settings.lua_koboldbridge.regeneration_required = False
global past
for i in range(model_settings.numseqs):
system_settings.lua_koboldbridge.generated[i+1][story_settings.generated_tkns] = int(generated[i, tpu_mtj_backend.params["seq"] + n_generated - 1].item())
system_settings.lua_koboldbridge.generated[i+1][model_settings.generated_tkns] = int(generated[i, tpu_mtj_backend.params["seq"] + n_generated - 1].item())
if(not story_settings.dynamicscan or halt):
return excluded_world_info, regeneration_required, halt
@@ -2067,7 +2067,16 @@ def load_model(use_gpu=True, gpu_layers=None, disk_layers=None, initial_load=Fal
setStartState()
sendsettings()
refresh_settings()
#Let's load the presets
with open('settings/preset/official.presets') as f:
presets = json.load(f)
if model_settings.model in presets:
model_settings.presets = presets[model_settings.model]
elif model_settings.model.replace("/", "_") in presets:
model_settings.presets = presets[model_settings.model.replace("/", "_")]
else:
model_settings.presets = {}
# Set up Flask routes
@app.route('/')
@@ -2770,6 +2779,9 @@ def do_connect():
return
join_room("UI_{}".format(request.args.get('ui')))
print("Joining Room UI_{}".format(request.args.get('ui')))
if request.args.get("ui") == 2:
ui2_connect()
return
#Send all variables to client
model_settings.send_to_ui()
story_settings.send_to_ui()
@@ -3808,9 +3820,9 @@ def _generate(txt, minimum, maximum, found_entries):
break
assert genout.ndim >= 2
assert genout.shape[0] == model_settings.numseqs
if(system_settings.lua_koboldbridge.generated_cols and story_settings.generated_tkns != system_settings.lua_koboldbridge.generated_cols):
if(system_settings.lua_koboldbridge.generated_cols and model_settings.generated_tkns != system_settings.lua_koboldbridge.generated_cols):
raise RuntimeError("Inconsistency detected between KoboldAI Python and Lua backends")
if(already_generated != story_settings.generated_tkns):
if(already_generated != model_settings.generated_tkns):
raise RuntimeError("WI scanning error")
for r in range(model_settings.numseqs):
for c in range(already_generated):
@@ -3850,7 +3862,7 @@ def _generate(txt, minimum, maximum, found_entries):
def generate(txt, minimum, maximum, found_entries=None):
story_settings.generated_tkns = 0
model_settings.generated_tkns = 0
if(found_entries is None):
found_entries = set()
@@ -3886,7 +3898,7 @@ def generate(txt, minimum, maximum, found_entries=None):
return
for i in range(model_settings.numseqs):
system_settings.lua_koboldbridge.generated[i+1][story_settings.generated_tkns] = int(genout[i, -1].item())
system_settings.lua_koboldbridge.generated[i+1][model_settings.generated_tkns] = int(genout[i, -1].item())
system_settings.lua_koboldbridge.outputs[i+1] = utils.decodenewlines(tokenizer.decode(genout[i, -already_generated:]))
execute_outmod()
@@ -4086,7 +4098,7 @@ def sendtocolab(txt, min, max):
# Send text to TPU mesh transformer backend
#==================================================================#
def tpumtjgenerate(txt, minimum, maximum, found_entries=None):
story_settings.generated_tkns = 0
model_settings.generated_tkns = 0
if(found_entries is None):
found_entries = set()
@@ -4173,7 +4185,7 @@ def tpumtjgenerate(txt, minimum, maximum, found_entries=None):
past = genout
for i in range(model_settings.numseqs):
system_settings.lua_koboldbridge.generated[i+1] = system_settings.lua_state.table(*genout[i].tolist())
system_settings.lua_koboldbridge.generated_cols = story_settings.generated_tkns = genout[0].shape[-1]
system_settings.lua_koboldbridge.generated_cols = model_settings.generated_tkns = genout[0].shape[-1]
except Exception as e:
if(issubclass(type(e), lupa.LuaError)):
@@ -5196,6 +5208,7 @@ def loadRequest(loadpath, filename=None):
# Leave Edit/Memory mode before continuing
exitModes()
# Read file contents into JSON object
if(isinstance(loadpath, str)):
with open(loadpath, "r") as file:
@@ -5206,107 +5219,115 @@ def loadRequest(loadpath, filename=None):
js = loadpath
if(filename is None):
filename = "untitled.json"
# Copy file contents to vars
story_settings.gamestarted = js["gamestarted"]
story_settings.prompt = js["prompt"]
story_settings.memory = js["memory"]
story_settings.worldinfo = []
story_settings.worldinfo = []
story_settings.worldinfo_u = {}
story_settings.wifolders_d = {int(k): v for k, v in js.get("wifolders_d", {}).items()}
story_settings.wifolders_l = js.get("wifolders_l", [])
story_settings.wifolders_u = {uid: [] for uid in story_settings.wifolders_d}
story_settings.lastact = ""
story_settings.submission = ""
story_settings.lastctx = ""
story_settings.genseqs = []
js['v1_loadpath'] = loadpath
js['v1_filename'] = filename
loadJSON(js)
del story_settings.actions
story_settings.actions = koboldai_settings.KoboldStoryRegister()
actions = collections.deque(js["actions"])
if "actions_metadata" in js:
if type(js["actions_metadata"]) == dict:
temp = js["actions_metadata"]
story_settings.actions_metadata = {}
#we need to redo the numbering of the actions_metadata since the actions list doesn't preserve it's number on saving
if len(temp) > 0:
counter = 0
temp = {int(k):v for k,v in temp.items()}
for i in range(max(temp)+1):
if i in temp:
story_settings.actions_metadata[counter] = temp[i]
counter += 1
del temp
else:
#fix if we're using the old metadata format
story_settings.actions_metadata = {}
i = 0
for text in js['actions']:
story_settings.actions_metadata[i] = {'Selected Text': text, 'Alternative Text': []}
i+=1
def loadJSON(json_text_or_dict):
if isinstance(json_text_or_dict, str):
json_data = json.loads(json_text_or_dict)
else:
json_data = json_text_or_dict
if "file_version" in json_data:
if json_data['file_version'] == 2:
load_story_v2(json_data)
else:
load_story_v1(json_data)
else:
load_story_v1(json_data)
def load_story_v1(js):
loadpath = js['v1_loadpath']
filename = js['v1_filename']
# Copy file contents to vars
story_settings.gamestarted = js["gamestarted"]
story_settings.prompt = js["prompt"]
story_settings.memory = js["memory"]
story_settings.worldinfo = []
story_settings.worldinfo = []
story_settings.worldinfo_u = {}
story_settings.wifolders_d = {int(k): v for k, v in js.get("wifolders_d", {}).items()}
story_settings.wifolders_l = js.get("wifolders_l", [])
story_settings.wifolders_u = {uid: [] for uid in story_settings.wifolders_d}
story_settings.lastact = ""
story_settings.submission = ""
story_settings.lastctx = ""
story_settings.genseqs = []
del story_settings.actions
story_settings.actions = koboldai_settings.KoboldStoryRegister()
actions = collections.deque(js["actions"])
if "actions_metadata" in js:
if type(js["actions_metadata"]) == dict:
temp = js["actions_metadata"]
story_settings.actions_metadata = {}
#we need to redo the numbering of the actions_metadata since the actions list doesn't preserve it's number on saving
if len(temp) > 0:
counter = 0
temp = {int(k):v for k,v in temp.items()}
for i in range(max(temp)+1):
if i in temp:
story_settings.actions_metadata[counter] = temp[i]
counter += 1
del temp
else:
#fix if we're using the old metadata format
story_settings.actions_metadata = {}
i = 0
for text in js['actions']:
story_settings.actions_metadata[i] = {'Selected Text': text, 'Alternative Text': []}
i+=1
if(len(story_settings.prompt.strip()) == 0):
while(len(actions)):
action = actions.popleft()
if(len(action.strip()) != 0):
story_settings.prompt = action
break
else:
story_settings.gamestarted = False
if(story_settings.gamestarted):
for s in actions:
story_settings.actions.append(s)
else:
story_settings.actions_metadata = {}
i = 0
# Try not to break older save files
if("authorsnote" in js):
story_settings.authornote = js["authorsnote"]
else:
story_settings.authornote = ""
if("anotetemplate" in js):
story_settings.authornotetemplate = js["anotetemplate"]
else:
story_settings.authornotetemplate = "[Author's note: <|>]"
if("worldinfo" in js):
num = 0
for wi in js["worldinfo"]:
story_settings.worldinfo.append({
"key": wi["key"],
"keysecondary": wi.get("keysecondary", ""),
"content": wi["content"],
"comment": wi.get("comment", ""),
"folder": wi.get("folder", None),
"num": num,
"init": True,
"selective": wi.get("selective", False),
"constant": wi.get("constant", False),
"uid": None,
})
while(True):
uid = int.from_bytes(os.urandom(4), "little", signed=True)
if(uid not in story_settings.worldinfo_u):
break
story_settings.worldinfo_u[uid] = story_settings.worldinfo[-1]
story_settings.worldinfo[-1]["uid"] = uid
if(story_settings.worldinfo[-1]["folder"] is not None):
story_settings.wifolders_u[story_settings.worldinfo[-1]["folder"]].append(story_settings.worldinfo[-1])
num += 1
for text in js['actions']:
story_settings.actions_metadata[i] = {'Selected Text': text, 'Alternative Text': []}
i+=1
for uid in story_settings.wifolders_l + [None]:
story_settings.worldinfo.append({"key": "", "keysecondary": "", "content": "", "comment": "", "folder": uid, "num": None, "init": False, "selective": False, "constant": False, "uid": None})
if(len(story_settings.prompt.strip()) == 0):
while(len(actions)):
action = actions.popleft()
if(len(action.strip()) != 0):
story_settings.prompt = action
break
else:
story_settings.gamestarted = False
if(story_settings.gamestarted):
for s in actions:
story_settings.actions.append(s)
# Try not to break older save files
if("authorsnote" in js):
story_settings.authornote = js["authorsnote"]
else:
story_settings.authornote = ""
if("anotetemplate" in js):
story_settings.authornotetemplate = js["anotetemplate"]
else:
story_settings.authornotetemplate = "[Author's note: <|>]"
if("worldinfo" in js):
num = 0
for wi in js["worldinfo"]:
story_settings.worldinfo.append({
"key": wi["key"],
"keysecondary": wi.get("keysecondary", ""),
"content": wi["content"],
"comment": wi.get("comment", ""),
"folder": wi.get("folder", None),
"num": num,
"init": True,
"selective": wi.get("selective", False),
"constant": wi.get("constant", False),
"uid": None,
})
while(True):
uid = int.from_bytes(os.urandom(4), "little", signed=True)
if(uid not in story_settings.worldinfo_u):
@@ -5315,32 +5336,49 @@ def loadRequest(loadpath, filename=None):
story_settings.worldinfo[-1]["uid"] = uid
if(story_settings.worldinfo[-1]["folder"] is not None):
story_settings.wifolders_u[story_settings.worldinfo[-1]["folder"]].append(story_settings.worldinfo[-1])
stablesortwi()
story_settings.worldinfo_i = [wi for wi in story_settings.worldinfo if wi["init"]]
num += 1
# Save path for save button
system_settings.savedir = loadpath
# Clear loadselect var
user_settings.loadselect = ""
# Refresh game screen
_filename = filename
if(filename.endswith('.json')):
_filename = filename[:-5]
user_settings.laststory = _filename
emit('from_server', {'cmd': 'setstoryname', 'data': user_settings.laststory}, broadcast=True, room="UI_1")
setgamesaved(True)
sendwi()
emit('from_server', {'cmd': 'setmemory', 'data': story_settings.memory}, broadcast=True, room="UI_1")
emit('from_server', {'cmd': 'setanote', 'data': story_settings.authornote}, broadcast=True, room="UI_1")
emit('from_server', {'cmd': 'setanotetemplate', 'data': story_settings.authornotetemplate}, broadcast=True, room="UI_1")
refresh_story()
emit('from_server', {'cmd': 'setgamestate', 'data': 'ready'}, broadcast=True, room="UI_1")
emit('from_server', {'cmd': 'hidegenseqs', 'data': ''}, broadcast=True, room="UI_1")
print("{0}Story loaded from {1}!{2}".format(colors.GREEN, filename, colors.END))
send_debug()
for uid in story_settings.wifolders_l + [None]:
story_settings.worldinfo.append({"key": "", "keysecondary": "", "content": "", "comment": "", "folder": uid, "num": None, "init": False, "selective": False, "constant": False, "uid": None})
while(True):
uid = int.from_bytes(os.urandom(4), "little", signed=True)
if(uid not in story_settings.worldinfo_u):
break
story_settings.worldinfo_u[uid] = story_settings.worldinfo[-1]
story_settings.worldinfo[-1]["uid"] = uid
if(story_settings.worldinfo[-1]["folder"] is not None):
story_settings.wifolders_u[story_settings.worldinfo[-1]["folder"]].append(story_settings.worldinfo[-1])
stablesortwi()
story_settings.worldinfo_i = [wi for wi in story_settings.worldinfo if wi["init"]]
# Save path for save button
system_settings.savedir = loadpath
# Clear loadselect var
user_settings.loadselect = ""
# Refresh game screen
_filename = filename
if(filename.endswith('.json')):
_filename = filename[:-5]
user_settings.laststory = _filename
#set the story_name
story_settings.story_name = _filename
emit('from_server', {'cmd': 'setstoryname', 'data': user_settings.laststory}, broadcast=True, room="UI_1")
setgamesaved(True)
sendwi()
emit('from_server', {'cmd': 'setmemory', 'data': story_settings.memory}, broadcast=True, room="UI_1")
emit('from_server', {'cmd': 'setanote', 'data': story_settings.authornote}, broadcast=True, room="UI_1")
emit('from_server', {'cmd': 'setanotetemplate', 'data': story_settings.authornotetemplate}, broadcast=True, room="UI_1")
refresh_story()
emit('from_server', {'cmd': 'setgamestate', 'data': 'ready'}, broadcast=True, room="UI_1")
emit('from_server', {'cmd': 'hidegenseqs', 'data': ''}, broadcast=True, room="UI_1")
print("{0}Story loaded from {1}!{2}".format(colors.GREEN, filename, colors.END))
send_debug()
def load_story_v2(js):
story_settings.from_json(js)
#==================================================================#
# Import an AIDungon game exported with Mimi's tool
@@ -5769,11 +5807,23 @@ def send_debug():
emit('from_server', {'cmd': 'debug_info', 'data': debug_info}, broadcast=True, room="UI_1")
#==================================================================#
# UI V2 CODE
#==================================================================#
@app.route('/new_ui')
def new_ui_index():
return render_template('index_new.html', settings=gensettings.gensettingstf if model_settings.model != "InferKit" else gensettings.gensettingsik )
def ui2_connect():
pass
#==================================================================#
# Event triggered when browser SocketIO detects a variable change
#==================================================================#
@socketio.on('var_change')
def UI_2_var_change(data):
print(data)
classname = data['ID'].split("_")[0]
name = data['ID'][len(classname)+1:]
classname += "_settings"
@@ -5793,15 +5843,24 @@ def UI_2_var_change(data):
print("{} {} = {}".format(classname, name, value))
setattr(globals()[classname], name, value)
#Now let's save except for story changes
if classname != "story_settings":
with open("settings/{}.v2_settings".format(classname), "w") as settings_file:
settings_file.write(globals()[classname].to_json())
#==================================================================#
# UI V2 CODE
# Saving Story
#==================================================================#
@app.route('/new_ui')
def new_ui_index():
return render_template('index_new.html', settings=gensettings.gensettingstf if model_settings.model != "InferKit" else gensettings.gensettingsik )
@socketio.on('save_story')
def UI_2_save_story(data):
json_data = story_settings.to_json()
save_name = story_settings.story_name if story_settings.story_name is not None else "untitled"
with open("stories/{}_v2.json".format(save_name), "w") as settings_file:
settings_file.write(story_settings.to_json())
story_settings.gamesaved = True
#==================================================================#
# Event triggered when Selected Text is edited, Option is Selected, etc
#==================================================================#
@@ -5824,10 +5883,7 @@ def UI_2_submit(data):
#==================================================================#
@socketio.on('Pinning')
def UI_2_Pinning(data):
if data['set']:
story_settings.actions.set_pin(int(data['chunk']), int(data['option']))
else:
story_settings.actions.unset_pin(int(data['chunk']), int(data['option']))
story_settings.actions.toggle_pin(int(data['chunk']), int(data['option']))
#==================================================================#
# Event triggered when user clicks the back button
@@ -5870,6 +5926,10 @@ def UI_2_relay(data):
def show_actions():
return story_settings.actions.actions
@app.route("/story")
def show_story():
return story_settings.to_json()
#==================================================================#
@@ -5952,3 +6012,4 @@ else:
model_settings.model = "ReadOnly"
load_model(initial_load=True)
print("{0}\nServer started in WSGI mode!{1}".format(colors.GREEN, colors.END), flush=True)

View File

@@ -1,6 +1,7 @@
from flask_socketio import emit, join_room, leave_room, rooms
import os, re, time, threading
import os, re, time, threading, json, pickle, base64, copy, tqdm, datetime
import socketio as socketio_client
from io import BytesIO
socketio = None
main_thread_id = threading.get_ident()
@@ -47,8 +48,50 @@ def process_variable_changes(classname, name, value, old_value, debug_message=No
else:
socketio.emit("var_changed", {"classname": classname, "name": name, "old_value": clean_var_for_emit(old_value), "value": clean_var_for_emit(value)}, include_self=True, broadcast=True, room="UI_2")
class settings(object):
def to_json(self):
json_data = {'file_version': 2}
for (name, value) in vars(self).items():
if name not in self.no_save_variables:
json_data[name] = value
def to_base64(data):
if isinstance(data, KoboldStoryRegister):
return data.to_json()
output = BytesIO()
pickle.dump(data, output)
output.seek(0)
return "base64:{}".format(base64.encodebytes(output.read()).decode())
return json.dumps(json_data, default=to_base64)
def from_json(self, data):
if isinstance(data, str):
json_data = json.loads(data)
else:
json_data = data
for key, value in data.items():
if key in self.__dict__:
if isinstance(value, str):
if value[:7] == 'base64:':
value = pickle.loads(base64.b64decode(value[7:]))
#Need to fix the data type of value to match the module
if type(getattr(self, key)) == int:
value = int(value)
elif type(getattr(self, key)) == float:
value = float(value)
elif type(getattr(self, key)) == bool:
value = bool(value)
elif type(getattr(self, key)) == str:
value = str(value)
if isinstance(getattr(self, key), KoboldStoryRegister):
self.actions.load_json(value)
else:
setattr(self, key, value)
def send_to_ui(self):
if socketio is not None:
for (name, value) in vars(self).items():
@@ -58,7 +101,8 @@ class settings(object):
class model_settings(settings):
local_only_variables = ['badwordsids', 'apikey', '_class_init']
local_only_variables = ['badwordsids', 'apikey', '_class_init', 'tqdm']
no_save_variables = ['tqdm']
settings_name = "model"
def __init__(self):
self.model = "" # Model ID string chosen at startup
@@ -79,6 +123,9 @@ class model_settings(settings):
self.tfs = 1.0 # Default generator tfs (tail-free sampling)
self.typical = 1.0 # Default generator typical sampling threshold
self.numseqs = 1 # Number of sequences to ask the generator to create
self.generated_tkns = 0 # If using a backend that supports Lua generation modifiers, how many tokens have already been generated, otherwise 0
self.tqdm = tqdm.tqdm(total=self.genamt, file=self.ignore_tqdm()) # tqdm agent for generating tokens. This will allow us to calculate the remaining time
self.tqdm_rem_time = 0 # tqdm calculated reemaining time
self.badwordsids = []
self.fp32_model = False # Whether or not the most recently loaded HF model was in fp32 format
self.url = "https://api.inferkit.com/v1/models/standard/generate" # InferKit API URL
@@ -96,20 +143,35 @@ class model_settings(settings):
self.selected_preset = ""
#dummy class to eat the tqdm output
class ignore_tqdm(object):
def write(self, bar):
pass
def __setattr__(self, name, value):
old_value = getattr(self, name, None)
super().__setattr__(name, value)
#Put variable change actions here
#Setup TQDP
if name == "generated_tkns" and 'tqdm' in self.__dict__:
if value == 0:
self.tqdm.reset(total=self.genamt)
else:
self.tqdm.update(1)
self.tqdm_rem_time = str(datetime.timedelta(seconds=int(float(self.genamt-self.generated_tkns)/self.tqdm.format_dict['rate'])))
if name not in self.local_only_variables and name[0] != "_":
process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
class story_settings(settings):
#local_only_variables = ['generated_tkns']
local_only_variables = []
no_save_variables = []
settings_name = "story"
def __init__(self):
self.story_name = None # Title of the story
self.lastact = "" # The last action received from the user
self.submission = "" # Same as above, but after applying input formatting
self.lastctx = "" # The last context submitted to the generator
@@ -136,7 +198,6 @@ class story_settings(settings):
self.wifolders_u = {} # Dictionary of pairs of folder UID - list of WI UID
self.lua_edited = set() # Set of chunk numbers that were edited from a Lua generation modifier
self.lua_deleted = set() # Set of chunk numbers that were deleted from a Lua generation modifier
self.generated_tkns = 0 # If using a backend that supports Lua generation modifiers, how many tokens have already been generated, otherwise 0
self.deletewi = None # Temporary storage for UID to delete
self.mode = "play" # Whether the interface is in play, memory, or edit mode
self.editln = 0 # Which line was last selected in Edit Mode
@@ -159,9 +220,14 @@ class story_settings(settings):
#Put variable change actions here
if name not in self.local_only_variables and name[0] != "_":
process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
#We want to automatically set gamesaved to false if something happens to the actions list (pins, redos, generations, text, etc)
#To do that we need to give the actions list a copy of this data so it can set the gamesaved variable as needed
if name == 'actions':
self.actions.story_settings = self
class user_settings(settings):
local_only_variables = []
no_save_variables = []
settings_name = "user"
def __init__(self):
self.wirmvwhtsp = False # Whether to remove leading whitespace from WI entries
@@ -190,9 +256,9 @@ class user_settings(settings):
if name not in self.local_only_variables and name[0] != "_":
process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
class system_settings(settings):
local_only_variables = ['lua_state', 'lua_logname', 'lua_koboldbridge', 'lua_kobold', 'lua_koboldcore', 'regex_sl', 'acregex_ai', 'acregex_ui', 'comregex_ai', 'comregex_ui']
no_save_variables = []
settings_name = "system"
def __init__(self):
self.noai = False # Runs the script without starting up the transformers pipeline
@@ -248,7 +314,6 @@ class system_settings(settings):
if name not in self.local_only_variables and name[0] != "_":
process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
class KoboldStoryRegister(object):
def __init__(self, sequence=[]):
self.actions = {}
@@ -290,6 +355,7 @@ class KoboldStoryRegister(object):
old_text = None
self.actions[i] = {"Selected Text": text, "Options": []}
process_variable_changes("actions", "Selected Text", {"id": i, "text": text}, {"id": i, "text": old_text})
self.set_game_saved()
def __len__(self):
return self.action_count+1 if self.action_count >=0 else 0
@@ -317,6 +383,7 @@ class KoboldStoryRegister(object):
self.action_count = json_data['action_count']
self.actions = temp
self.set_game_saved()
def get_action(self, action_id):
if action_id not in actions:
@@ -342,15 +409,17 @@ class KoboldStoryRegister(object):
else:
self.actions[self.action_count] = {"Selected Text": text, "Options": []}
process_variable_changes("actions", "Selected Text", {"id": self.action_count, "text": text}, None)
self.set_game_saved()
def append_options(self, option_list):
if self.action_count+1 in self.actions:
old_options = self.actions[self.action_count+1]["Options"].copy()
old_options = copy.deepcopy(self.actions[self.action_count+1]["Options"])
self.actions[self.action_count+1]['Options'].extend([{"text": x, "Pinned": False, "Previous Selection": False, "Edited": False} for x in option_list])
else:
old_options = None
self.actions[self.action_count+1] = {"Selected Text": "", "Options": [{"text": x, "Pinned": False, "Previous Selection": False, "Edited": False} for x in option_list]}
process_variable_changes("actions", "Options", {"id": self.action_count+1, "options": self.actions[self.action_count+1]["Options"]}, {"id": self.action_count+1, "options": old_options})
self.set_game_saved()
def clear_unused_options(self, pointer=None):
new_options = []
@@ -358,10 +427,11 @@ class KoboldStoryRegister(object):
if pointer is None:
pointer = self.action_count+1
if pointer in self.actions:
old_options = self.actions[pointer]["Options"].copy()
old_options = copy.deepcopy(self.actions[pointer]["Options"])
self.actions[pointer]["Options"] = [x for x in self.actions[pointer]["Options"] if x["Pinned"] or x["Previous Selection"] or x["Edited"]]
new_options = self.actions[pointer]["Options"]
process_variable_changes("actions", "Options", {"id": pointer, "options": new_options}, {"id": pointer, "options": old_options})
self.set_game_saved()
def toggle_pin(self, action_step, option_number):
if action_step in self.actions:
@@ -374,22 +444,32 @@ class KoboldStoryRegister(object):
def set_pin(self, action_step, option_number):
if action_step in self.actions:
if option_number < len(self.actions[action_step]['Options']):
old_options = self.actions[action_step]["Options"].copy()
old_options = copy.deepcopy(self.actions[action_step]["Options"])
self.actions[action_step]['Options'][option_number]['Pinned'] = True
process_variable_changes("actions", "Options", {"id": action_step, "options": self.actions[action_step]["Options"]}, {"id": action_step, "options": old_options})
self.set_game_saved()
def unset_pin(self, action_step, option_number):
if action_step in self.actions:
old_options = self.actions[action_step]["Options"].copy()
old_options = copy.deepcopy(self.actions[action_step]["Options"])
if option_number < len(self.actions[action_step]['Options']):
self.actions[action_step]['Options'][option_number]['Pinned'] = False
process_variable_changes("actions", "Options", {"id": action_step, "options": self.actions[action_step]["Options"]}, {"id": action_step, "options": old_options})
self.set_game_saved()
def toggle_pin(self, action_step, option_number):
if action_step in self.actions:
old_options = copy.deepcopy(self.actions[action_step]["Options"])
if option_number < len(self.actions[action_step]['Options']):
self.actions[action_step]['Options'][option_number]['Pinned'] = not self.actions[action_step]['Options'][option_number]['Pinned']
process_variable_changes("actions", "Options", {"id": action_step, "options": self.actions[action_step]["Options"]}, {"id": action_step, "options": old_options})
self.set_game_saved()
def use_option(self, option_number, action_step=None):
if action_step is None:
action_step = self.action_count+1
if action_step in self.actions:
old_options = self.actions[action_step]["Options"].copy()
old_options = copy.deepcopy(self.actions[action_step]["Options"])
old_text = self.actions[action_step]["Selected Text"]
if option_number < len(self.actions[action_step]['Options']):
self.actions[action_step]["Selected Text"] = self.actions[action_step]['Options'][option_number]['text']
@@ -400,22 +480,25 @@ class KoboldStoryRegister(object):
socketio.emit("var_changed", {"classname": "actions", "name": "Action Count", "old_value": None, "value":self.action_count}, broadcast=True, room="UI_2")
process_variable_changes("actions", "Options", {"id": action_step, "options": self.actions[action_step]["Options"]}, {"id": action_step, "options": old_options})
process_variable_changes("actions", "Selected Text", {"id": action_step, "text": self.actions[action_step]["Selected Text"]}, {"id": action_step, "Selected Text": old_text})
self.set_game_saved()
def delete_action(self, action_id):
if action_id in self.actions:
old_options = self.actions[action_id]["Options"].copy()
old_options = copy.deepcopy(self.actions[action_id]["Options"])
old_text = self.actions[action_id]["Selected Text"]
self.actions[action_id]["Options"].append({"text": self.actions[action_id]["Selected Text"], "Pinned": False, "Previous Selection": True, "Edited": False})
self.actions[action_id]["Selected Text"] = ""
self.action_count -= 1
process_variable_changes("actions", "Selected Text", {"id": action_id, "text": None}, {"id": action_id, "text": old_text})
process_variable_changes("actions", "Options", {"id": action_id, "options": self.actions[action_id]["Options"]}, {"id": action_id, "options": old_options})
self.set_game_saved()
def pop(self):
if self.action_count >= 0:
text = self.actions[self.action_count]
self.delete_action(self.action_count)
process_variable_changes("actions", "Selected Text", {"id": self.action_count, "text": None}, {"id": self.action_count, "text": text})
self.set_game_saved()
return text
else:
return None
@@ -493,7 +576,10 @@ class KoboldStoryRegister(object):
return [x for x in self.actions[self.action_count+1]['Options'] if x['Pinned'] or x['Previous Selection']]
else:
return []
def set_game_saved(self):
if 'story_settings' in self.__dict__:
self.story_settings.gamesaved = False
def __setattr__(self, name, value):
old_value = getattr(self, name, None)
super().__setattr__(name, value)

View File

@@ -0,0 +1,95 @@
{"EleutherAI_gpt-neo-1.3B":
{
"Storywriter": {
"temp": 0.72,
"genamt": 40,
"rep_pen": 1.2,
"top_p": 0.725,
"top_k": 0,
"tfs": 1,
"rep_pen_slope": 2048,
"rep_pen_range": 0.18,
"typical": 1,
"top_a": 0,
"description": "Optimized settings for relevant output."
},
"Coherent Creativity": {
"temp": 0.51,
"genamt": 40,
"rep_pen": 1.2,
"top_p": 1,
"top_k": 0,
"tfs": 0.9,
"rep_pen_slope": 2048,
"rep_pen_range": 0,
"typical": 1,
"top_a": 0,
"description": "A good balance between coherence, creativity, and quality of prose."
},
"Luna Moth": {
"temp": 2,
"genamt": 40,
"rep_pen": 1.2,
"top_p": 0.235,
"top_k": 85,
"tfs": 1,
"rep_pen_slope": 2048,
"rep_pen_range": 0,
"typical": 1,
"top_a": 0,
"description": "A great degree of creativity without losing coherency."
},
"Sphinx Moth": {
"temp": 2,
"genamt": 40,
"rep_pen": 1.2,
"top_p": 0.175,
"top_k": 30,
"tfs": 1,
"rep_pen_slope": 2048,
"rep_pen_range": 0,
"typical": 1,
"top_a": 0,
"description": "Maximum randomness while still being plot relevant. Like Sphinx riddles!"
},
"Emperor Moth": {
"temp": 1.25,
"genamt": 40,
"rep_pen": 1.2,
"top_p": 0.235,
"top_k": 0,
"tfs": 1,
"rep_pen_slope": 2048,
"rep_pen_range": 0,
"typical": 1,
"top_a": 0,
"description": "Medium randomness with a decent bit of creative writing."
},
"Best Guess": {
"temp": 0.8,
"genamt": 40,
"rep_pen": 1.2,
"top_p": 0.9,
"top_k": 100,
"tfs": 1,
"rep_pen_slope": 512,
"rep_pen_range": 3.33,
"typical": 1,
"top_a": 0,
"description": "A subtle change with alternative context settings."
},
"Pleasing Results": {
"temp": 0.44,
"genamt": 40,
"rep_pen": 1.2,
"top_p": 1,
"top_k": 0,
"tfs": 0.9,
"rep_pen_slope": 1024,
"rep_pen_range": 6.75,
"typical": 1,
"top_a": 0,
"description": "Expectable output with alternative context settings."
}
}
}

View File

@@ -327,6 +327,8 @@ td.server_vars {
}
/* ---------------------------- OVERALL PAGE CONFIG ------------------------------*/
body {
background-color: var(--background);
@@ -336,7 +338,7 @@ body {
.main-grid {
transition: margin-left .5s;
display: grid;
min-height: 98vh;
height: 98vh;
margin-left: var(--flyout_menu_closed_width);
/* grid-template-areas: "menuicon gamescreen lefticon"
"menuicon actions lefticon"
@@ -371,6 +373,13 @@ body {
margin-top: auto;
padding-bottom: 1px;
vertical-align: bottom;
overflow-y: scroll;
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
/* Hide scrollbar for Chrome, Safari and Opera */
.gametext::-webkit-scrollbar {
display: none;
}
[contenteditable="true"]:active,
@@ -384,6 +393,7 @@ body {
margin-top: 10px;
grid-area: options;
background-color: var(--gamescreen_background);
overflow-y: scroll;
}
table.sequence {
@@ -446,14 +456,14 @@ td.sequence:hover {
color: var(--text);
}
.inputrow .submit[server_value=false] {
.inputrow .submit[system_aibusy=false] {
grid-area: submit;
height: 100%;
width: 100%;
text-align: center;
overflow: hidden;
}
.inputrow .submit[server_value=true] {
.inputrow .submit[system_aibusy=true] {
grid-area: submit;
height: 100%;
width: 100%;
@@ -462,7 +472,7 @@ td.sequence:hover {
display: none;
}
.inputrow .submited[server_value=false] {
.inputrow .submited[system_aibusy=false] {
grid-area: submit;
height: 100%;
width: 100%;
@@ -470,7 +480,7 @@ td.sequence:hover {
overflow: hidden;
display: none;
}
.inputrow .submited[server_value=true] {
.inputrow .submited[system_aibusy=true] {
grid-area: submit;
height: 100%;
width: 100%;

View File

@@ -12,6 +12,7 @@ socket.on('var_changed', function(data){var_changed(data);});
var backend_vars = {};
var presets = {}
var ai_busy_start = Date.now();
//-----------------------------------Server to UI Functions-----------------------------------------------
function connect() {
console.log("connected");
@@ -54,14 +55,11 @@ function create_options(data) {
var chunk = children[i];
if (chunk.id == "Select Options Chunk " + current_chunk) {
chunk.classList.remove("hidden");
console.log(current_chunk);
} else {
chunk.classList.add("hidden");
}
}
console.log(current_chunk);
console.log(data);
if (document.getElementById("Select Options Chunk "+data.value.id)) {
var option_chunk = document.getElementById("Select Options Chunk "+data.value.id)
} else {
@@ -77,37 +75,6 @@ function create_options(data) {
var table = document.createElement("table");
table.classList.add("sequence");
table.style = "border-spacing: 0;";
//Add pins
i=0;
for (item of data.value.options) {
if (item.Pinned) {
var row = document.createElement("tr");
row.classList.add("sequence");
var textcell = document.createElement("td");
textcell.textContent = item.text;
textcell.classList.add("sequence");
textcell.setAttribute("option_id", i);
textcell.setAttribute("option_chunk", data.value.id);
var iconcell = document.createElement("td");
iconcell.setAttribute("option_id", i);
iconcell.setAttribute("option_chunk", data.value.id);
var icon = document.createElement("span");
icon.id = "Pin_"+i;
icon.classList.add("oi");
icon.setAttribute('data-glyph', "pin");
iconcell.append(icon);
textcell.onclick = function () {
socket.emit("Set Selected Text", {"chunk": this.getAttribute("option_chunk"), "option": this.getAttribute("option_id")});
};
iconcell.onclick = function () {
socket.emit("Pinning", {"chunk": this.getAttribute("option_chunk"), "option": this.getAttribute("option_id"), "set": false});
};
row.append(textcell);
row.append(iconcell);
table.append(row);
}
i+=1;
}
//Add Redo options
i=0;
for (item of data.value.options) {
@@ -139,7 +106,7 @@ function create_options(data) {
//Add general options
i=0;
for (item of data.value.options) {
if (!(item.Edited) && !(item.Pinned) && !(item['Previous Selection'])) {
if (!(item.Edited) && !(item['Previous Selection'])) {
var row = document.createElement("tr");
row.classList.add("sequence");
var textcell = document.createElement("td");
@@ -154,10 +121,12 @@ function create_options(data) {
icon.id = "Pin_"+i;
icon.classList.add("oi");
icon.setAttribute('data-glyph', "pin");
icon.setAttribute('style', "filter: brightness(50%);");
if (!(item.Pinned)) {
icon.setAttribute('style', "filter: brightness(50%);");
}
iconcell.append(icon);
iconcell.onclick = function () {
socket.emit("Pinning", {"chunk": this.getAttribute("option_chunk"), "option": this.getAttribute("option_id"), "set": true});
socket.emit("Pinning", {"chunk": this.getAttribute("option_chunk"), "option": this.getAttribute("option_id")});
};
textcell.onclick = function () {
socket.emit("Set Selected Text", {"chunk": this.getAttribute("option_chunk"), "option": this.getAttribute("option_id")});
@@ -193,6 +162,7 @@ function do_story_text_updates(data) {
}
function do_presets(data) {
console.log(data);
var select = document.getElementById('presets');
//clear out the preset list
while (select.firstChild) {
@@ -203,11 +173,11 @@ function do_presets(data) {
option.value="";
option.text="presets";
select.append(option);
for (item of data.value) {
presets[item.preset] = item;
for (const [key, value] of Object.entries(data.value)) {
presets[key] = value;
var option = document.createElement("option");
option.value=item.preset;
option.text=item.preset;
option.value=key;
option.text=key;
select.append(option);
}
}
@@ -251,6 +221,20 @@ function update_status_bar(data) {
document.title = "KoboldAI Client Generating (" + percent_complete + "%)";
}
}
function do_ai_busy(data) {
if (data.value) {
ai_busy_start = Date.now();
favicon.start_swap()
} else {
runtime = Date.now() - ai_busy_start;
if (document.getElementById("Execution Time")) {
document.getElementById("Execution Time").textContent = Math.round(runtime/1000).toString().toHHMMSS();
}
favicon.stop_swap()
}
}
function var_changed(data) {
//Special Case for Story Text
if ((data.classname == "actions") && (data.name == "Selected Text")) {
@@ -276,22 +260,18 @@ function var_changed(data) {
//alternative syncing method
var elements_to_change = document.getElementsByClassName("var_sync_alt_"+data.classname.replace(" ", "_")+"_"+data.name.replace(" ", "_"));
for (item of elements_to_change) {
item.setAttribute("server_value", fix_text(data.value));
item.setAttribute(data.classname.replace(" ", "_")+"_"+data.name.replace(" ", "_"), fix_text(data.value));
}
}
//if we're updating generated tokens, let's show that in our status bar
if ((data.classname == 'story') && (data.name == 'generated_tkns')) {
if ((data.classname == 'model') && (data.name == 'generated_tkns')) {
update_status_bar(data);
}
//If we have ai_busy, start the favicon swapping
if ((data.classname == 'system') && (data.name == 'aibusy')) {
if (data.value) {
favicon.start_swap()
} else {
favicon.stop_swap()
}
do_ai_busy(data);
}
}
@@ -299,6 +279,18 @@ function var_changed(data) {
//--------------------------------------------General UI Functions------------------------------------
String.prototype.toHHMMSS = function () {
var sec_num = parseInt(this, 10); // don't forget the second param
var hours = Math.floor(sec_num / 3600);
var minutes = Math.floor((sec_num - (hours * 3600)) / 60);
var seconds = sec_num - (hours * 3600) - (minutes * 60);
if (hours < 10) {hours = "0"+hours;}
if (minutes < 10) {minutes = "0"+minutes;}
if (seconds < 10) {seconds = "0"+seconds;}
return hours+':'+minutes+':'+seconds;
}
function toggle_flyout(x) {
if (document.getElementById("SideMenu").classList.contains("open")) {
x.classList.remove("change");

View File

@@ -34,7 +34,7 @@
<!------------ Game Text Screen--------------------->
<div class="gamescreen" id="gamescreen">
<div class="gametext">
<span id="prompt" class="var_sync_story_prompt rawtext"></span>
<span id="story_prompt" class="var_sync_story_prompt rawtext" contenteditable=true onblur="socket.emit('var_change', {'ID': this.id, 'value': this.textContent});"></span>
<span id="Selected Text" class="rawtext"></span>
</div>
</div>
@@ -44,8 +44,8 @@
<!------------ Input Area--------------------->
<div class="inputrow" id="inputrow_container">
<textarea id="input_text" placeholder="Enter text here"></textarea>
<div class="statusbar_outer">
<div class="statusbar_inner" style="width:25%">25%</div>
<div class="statusbar_outer hidden">
<div class="statusbar_inner" style="width:0%">0%</div>
</div><br>
<button type="button" class="btn action_button submit var_sync_alt_system_aibusy" id="btnsend" onclick="socket.emit('submit', {'data': document.getElementById('input_text').value});">Submit</button>
<button type="button" class="btn action_button submited var_sync_alt_system_aibusy" id="btnsend"><img src="static/thinking.gif" class="force_center"></button>
@@ -58,9 +58,8 @@
</div>
<!------------ Right Flyout Menu--------------------->
<div id="rightSideMenu" class="rightSideMenu"> Status:<hr>
<div id="rightSideMenu" class="rightSideMenu">
{% include 'story flyout.html' %}
</div>
</body>
</html>

View File

@@ -10,6 +10,16 @@
#Model_Info {
width: 100%;
}
#Story_Info {
width: 100%;
}
#save_story[story_gamesaved="true"] {
text: var(--disabled_button_text);
background-color: var(--disabled_button_background_color);
border-color: var(--disabled_button_border_color);
filter: brightness(85%);
}
</style>
<!-- top menu bar-->
<div class="flex settings_menu">
@@ -17,7 +27,7 @@
<button class="menu_button" onclick="show_setting_menu('story');">Story</button>
<button class="menu_button" onclick="show_setting_menu('user');">User</button>
<button class="menu_button" onclick="show_setting_menu('system');">System</button>
<select id=presets class="var_sync_model_selected_preset" onchange='socket.emit("var_change", {"ID": "model_selected_preset", "value": this.value});'><option>Preset</option></select>
<select id=presets class="var_sync_model_selected_preset settings_select" onchange='socket.emit("var_change", {"ID": "model_selected_preset", "value": this.value});'><option>Preset</option></select>
</div>
<div id="setting_menu_model" class="settings_category_area">
@@ -30,6 +40,10 @@
{% endwith %}
</div>
<div id="setting_menu_story" class="hidden settings_category_area">
<div id="Story_Info">
<div>Story Name: <span class="var_sync_story_story_name"></span></div>
<div><button id="save_story" class="btn action_button var_sync_alt_story_gamesaved" onclick='socket.emit("save_story", "Story123");'>Save Story</button></div>
</div>
{% with menu='Story' %}
{% include 'settings item.html' %}
{% endwith %}