mirror of
https://github.com/KoboldAI/KoboldAI-Client.git
synced 2025-06-05 21:59:24 +02:00
Merge branch 'UI2' of https://github.com/ebolam/KoboldAI into ui2-gen-isolate
This commit is contained in:
221
aiserver.py
221
aiserver.py
@@ -6,6 +6,7 @@
|
||||
#==================================================================#
|
||||
|
||||
# External packages
|
||||
from dataclasses import dataclass
|
||||
import eventlet
|
||||
eventlet.monkey_patch(all=True, thread=False, os=False)
|
||||
import os
|
||||
@@ -239,6 +240,189 @@ class Send_to_socketio(object):
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
@dataclass
|
||||
class ImportBuffer:
|
||||
# Singleton!!!
|
||||
prompt: Optional[str] = None
|
||||
memory: Optional[str] = None
|
||||
authors_note: Optional[str] = None
|
||||
notes: Optional[str] = None
|
||||
world_infos: Optional[dict] = None
|
||||
|
||||
@dataclass
|
||||
class PromptPlaceholder:
|
||||
id: str
|
||||
order: Optional[int] = None
|
||||
default: Optional[str] = None
|
||||
title: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
value: Optional[str] = None
|
||||
|
||||
def to_json(self) -> dict:
|
||||
return {key: getattr(self, key) for key in [
|
||||
"id",
|
||||
"order",
|
||||
"default",
|
||||
"title",
|
||||
"description"
|
||||
]}
|
||||
|
||||
def request_client_configuration(self, placeholders: List[PromptPlaceholder]) -> None:
|
||||
emit("request_prompt_config", [x.to_json() for x in placeholders], broadcast=False, room="UI_2")
|
||||
|
||||
def extract_placeholders(self, text: str) -> List[PromptPlaceholder]:
|
||||
placeholders = []
|
||||
|
||||
for match in re.finditer(r"\${(.*?)}", text):
|
||||
ph_text = match.group(1)
|
||||
|
||||
try:
|
||||
ph_order, ph_text = ph_text.split("#")
|
||||
except ValueError:
|
||||
ph_order = None
|
||||
|
||||
if "[" not in ph_text:
|
||||
ph_id = ph_text
|
||||
|
||||
# Already have it!
|
||||
if any([x.id == ph_id for x in placeholders]):
|
||||
continue
|
||||
|
||||
# Apparently, none of these characters are supported:
|
||||
# "${}[]#:@^|", however I have found some prompts using these,
|
||||
# so they will be allowed.
|
||||
for char in "${}[]":
|
||||
if char in ph_text:
|
||||
print("[eph] Weird char")
|
||||
print(f"Char: {char}")
|
||||
print(f"Ph_id: {ph_id}")
|
||||
return
|
||||
|
||||
placeholders.append(self.PromptPlaceholder(
|
||||
id=ph_id,
|
||||
order=int(ph_order) if ph_order else None,
|
||||
))
|
||||
continue
|
||||
|
||||
ph_id, _ = ph_text.split("[")
|
||||
ph_text = ph_text.replace(ph_id, "", 1)
|
||||
|
||||
# Already have it!
|
||||
if any([x.id == ph_id for x in placeholders]):
|
||||
continue
|
||||
|
||||
# Match won't match it for some reason (???), so we use finditer and next()
|
||||
try:
|
||||
default_match = next(re.finditer(r"\[(.*?)\]", ph_text))
|
||||
except StopIteration:
|
||||
print("[eph] Weird brackets")
|
||||
return placeholders
|
||||
|
||||
ph_default = default_match.group(1)
|
||||
ph_text = ph_text.replace(default_match.group(0), "")
|
||||
|
||||
try:
|
||||
ph_title, ph_desc = ph_text.split(":")
|
||||
except ValueError:
|
||||
ph_title = ph_text or None
|
||||
ph_desc=None
|
||||
|
||||
placeholders.append(self.PromptPlaceholder(
|
||||
id=ph_id,
|
||||
order=int(ph_order) if ph_order else None,
|
||||
default=ph_default,
|
||||
title=ph_title,
|
||||
description=ph_desc
|
||||
))
|
||||
return placeholders
|
||||
|
||||
def _replace_placeholders(self, text: str, ph_ids: dict):
|
||||
for ph_id, value in ph_ids.items():
|
||||
pattern = "\${(?:\d#)?%s.*?}" % re.escape(ph_id)
|
||||
for ph_text in re.findall(pattern, text):
|
||||
text = text.replace(ph_text, value)
|
||||
return text
|
||||
|
||||
def replace_placeholders(self, ph_ids: dict):
|
||||
self.prompt = self._replace_placeholders(self.prompt, ph_ids)
|
||||
self.memory = self._replace_placeholders(self.memory, ph_ids)
|
||||
self.authors_note = self._replace_placeholders(self.authors_note, ph_ids)
|
||||
|
||||
for i in range(len(self.world_infos)):
|
||||
for key in ["content", "comment"]:
|
||||
self.world_infos[i][key] = self._replace_placeholders(self.world_infos[i][key])
|
||||
|
||||
def from_club(self, club_id):
|
||||
# Maybe it is a better to parse the NAI Scenario (if available), it has more data
|
||||
r = requests.get(f"https://aetherroom.club/api/{club_id}")
|
||||
|
||||
if not r.ok:
|
||||
# TODO: Show error message on client
|
||||
print(f"[import] Got {r.status_code} on request to club :^(")
|
||||
return
|
||||
|
||||
j = r.json()
|
||||
|
||||
self.prompt = j["promptContent"]
|
||||
self.memory = j["memory"]
|
||||
self.authors_note = j["authorsNote"]
|
||||
self.notes = j["description"]
|
||||
|
||||
self.world_infos = []
|
||||
|
||||
for wi in j["worldInfos"]:
|
||||
self.world_infos.append({
|
||||
"key_list": wi["keysList"],
|
||||
"keysecondary": [],
|
||||
"content": wi["entry"],
|
||||
"comment": "",
|
||||
"folder": wi.get("folder", None),
|
||||
"num": 0,
|
||||
"init": True,
|
||||
"selective": wi.get("selective", False),
|
||||
"constant": wi.get("constant", False),
|
||||
"uid": None,
|
||||
})
|
||||
|
||||
placeholders = self.extract_placeholders(self.prompt)
|
||||
if not placeholders:
|
||||
self.commit()
|
||||
else:
|
||||
self.request_client_configuration(placeholders)
|
||||
|
||||
def commit(self):
|
||||
# Push buffer story to actual story
|
||||
exitModes()
|
||||
|
||||
koboldai_vars.create_story("")
|
||||
koboldai_vars.gamestarted = True
|
||||
koboldai_vars.prompt = self.prompt
|
||||
koboldai_vars.memory = self.memory or ""
|
||||
koboldai_vars.authornote = self.authors_note or ""
|
||||
koboldai_vars.notes = self.notes
|
||||
|
||||
for wi in self.world_infos:
|
||||
koboldai_vars.worldinfo_v2.add_item(
|
||||
wi["key_list"][0],
|
||||
wi["key_list"],
|
||||
wi.get("keysecondary", []),
|
||||
wi.get("folder", "root"),
|
||||
wi.get("constant", False),
|
||||
wi["content"],
|
||||
wi.get("comment", "")
|
||||
)
|
||||
|
||||
# Reset current save
|
||||
koboldai_vars.savedir = getcwd()+"\\stories"
|
||||
|
||||
# Refresh game screen
|
||||
koboldai_vars.laststory = None
|
||||
setgamesaved(False)
|
||||
sendwi()
|
||||
refresh_story()
|
||||
|
||||
import_buffer = ImportBuffer()
|
||||
|
||||
# Set logging level to reduce chatter from Flask
|
||||
import logging
|
||||
@@ -286,6 +470,16 @@ def emit(*args, **kwargs):
|
||||
except AttributeError:
|
||||
return socketio.emit(*args, **kwargs)
|
||||
|
||||
#replacement for tpool.execute to maintain request contexts
|
||||
def replacement_tpool_execute(function, *args, **kwargs):
|
||||
temp = {}
|
||||
socketio.start_background_task(tpool.execute_2, function, temp, *args, **kwargs).join()
|
||||
print(temp)
|
||||
return temp[1]
|
||||
|
||||
def replacement_tpool_execute_2(function, temp, *args, **kwargs):
|
||||
temp[1] = function(*args, **kwargs)
|
||||
|
||||
# marshmallow/apispec setup
|
||||
from apispec import APISpec
|
||||
from apispec.ext.marshmallow import MarshmallowPlugin
|
||||
@@ -1181,6 +1375,7 @@ def get_model_info(model, directory=""):
|
||||
default_url = None
|
||||
models_on_url = False
|
||||
multi_online_models = False
|
||||
show_online_model_select=False
|
||||
gpu_count = torch.cuda.device_count()
|
||||
gpu_names = []
|
||||
for i in range(gpu_count):
|
||||
@@ -1189,6 +1384,7 @@ def get_model_info(model, directory=""):
|
||||
url = True
|
||||
elif model == 'CLUSTER':
|
||||
models_on_url = True
|
||||
show_online_model_select=True
|
||||
url = True
|
||||
key = True
|
||||
default_url = 'https://koboldai.net'
|
||||
@@ -1206,6 +1402,7 @@ def get_model_info(model, directory=""):
|
||||
default_url = js['oaiurl']
|
||||
get_cluster_models({'model': model, 'key': key_value, 'url': default_url})
|
||||
elif model in [x[1] for x in model_menu['apilist']]:
|
||||
show_online_model_select=True
|
||||
if path.exists("settings/{}.v2_settings".format(model)):
|
||||
with open("settings/{}.v2_settings".format(model), "r") as file:
|
||||
# Check if API key exists
|
||||
@@ -1254,7 +1451,7 @@ def get_model_info(model, directory=""):
|
||||
'gpu':gpu, 'layer_count':layer_count, 'breakmodel':breakmodel, 'multi_online_models': multi_online_models, 'default_url': default_url,
|
||||
'disk_break_value': disk_blocks, 'disk_break': utils.HAS_ACCELERATE,
|
||||
'break_values': break_values, 'gpu_count': gpu_count,
|
||||
'url': url, 'gpu_names': gpu_names, 'models_on_url': models_on_url}, broadcast=False, room="UI_2")
|
||||
'url': url, 'gpu_names': gpu_names, 'models_on_url': models_on_url, 'show_online_model_select': show_online_model_select}, broadcast=False, room="UI_2")
|
||||
|
||||
|
||||
|
||||
@@ -1927,6 +2124,7 @@ def load_model(use_gpu=True, gpu_layers=None, disk_layers=None, initial_load=Fal
|
||||
if not utils.HAS_ACCELERATE:
|
||||
disk_layers = None
|
||||
koboldai_vars.reset_model()
|
||||
koboldai_vars.cluster_requested_models = online_model
|
||||
koboldai_vars.noai = False
|
||||
if not use_breakmodel_args:
|
||||
set_aibusy(True)
|
||||
@@ -1990,7 +2188,7 @@ def load_model(use_gpu=True, gpu_layers=None, disk_layers=None, initial_load=Fal
|
||||
koboldai_vars.configname = f"{koboldai_vars.model}_{online_model.replace('/', '_')}"
|
||||
if path.exists(get_config_filename()):
|
||||
changed=False
|
||||
with open("settings/{}.v2_settings".format(koboldai_vars.model), "r") as file:
|
||||
with open(get_config_filename(), "r") as file:
|
||||
# Check if API key exists
|
||||
js = json.load(file)
|
||||
if 'online_model' in js:
|
||||
@@ -5134,6 +5332,7 @@ def sendtoapi(txt, min, max):
|
||||
errmsg = "KoboldAI API Error: Failed to get a reply from the server. Please check the console."
|
||||
print("{0}{1}{2}".format(colors.RED, json.dumps(js, indent=2), colors.END))
|
||||
emit('from_server', {'cmd': 'errmsg', 'data': errmsg}, broadcast=True)
|
||||
emit("error", errmsg, broadcast=True, room="UI_2")
|
||||
set_aibusy(0)
|
||||
return
|
||||
|
||||
@@ -6986,6 +7185,7 @@ def ui2_connect():
|
||||
#Send all variables to client
|
||||
koboldai_vars.send_to_ui()
|
||||
UI_2_load_cookies()
|
||||
UI_2_theme_list_refresh(None)
|
||||
pass
|
||||
|
||||
#==================================================================#
|
||||
@@ -7271,6 +7471,11 @@ def get_files_sorted(path, sort, desc=False):
|
||||
return [key[0] for key in sorted(data.items(), key=lambda kv: (kv[1], kv[0]), reverse=desc)]
|
||||
|
||||
|
||||
@socketio.on("configure_prompt")
|
||||
def UI_2_configure_prompt(data):
|
||||
import_buffer.replace_placeholders(data)
|
||||
import_buffer.commit()
|
||||
|
||||
#==================================================================#
|
||||
# Event triggered when browser SocketIO detects a variable change
|
||||
#==================================================================#
|
||||
@@ -7538,7 +7743,7 @@ def get_story_listing_data(item_full_path, item, valid_selection):
|
||||
if js.get("file_version", 1) == 1:
|
||||
return [title, action_count, last_loaded]
|
||||
|
||||
action_count = 0 if js['actions']['action_count'] == -1 else js['actions']['action_count']
|
||||
action_count = js['actions']['action_count']+1
|
||||
|
||||
return [title, action_count, last_loaded]
|
||||
|
||||
@@ -7929,7 +8134,8 @@ def UI_2_unload_userscripts(data):
|
||||
def UI_2_load_aidg_club(data):
|
||||
if koboldai_vars.debug:
|
||||
print("Load aidg.club: {}".format(data))
|
||||
importAidgRequest(data)
|
||||
import_buffer.from_club(data)
|
||||
# importAidgRequest(data)
|
||||
|
||||
|
||||
#==================================================================#
|
||||
@@ -8033,6 +8239,13 @@ def get_model_size(model_name):
|
||||
elif "1.3B" in model_name:
|
||||
return "1.3B"
|
||||
|
||||
#==================================================================#
|
||||
# Save New Preset
|
||||
#==================================================================#
|
||||
@socketio.on('save_revision')
|
||||
def UI_2_save_revision(data):
|
||||
koboldai_vars.save_revision()
|
||||
|
||||
#==================================================================#
|
||||
# Test
|
||||
#==================================================================#
|
||||
|
@@ -23,7 +23,7 @@ dependencies:
|
||||
- flask-cloudflared
|
||||
- flask-ngrok
|
||||
- lupa==1.10
|
||||
- transformers>=4.20.1
|
||||
- transformers==4.21.3
|
||||
- accelerate
|
||||
- flask-session
|
||||
- python-socketio[client]
|
@@ -78,10 +78,12 @@ class koboldai_vars(object):
|
||||
with open("settings/system_settings.v2_settings", "w") as settings_file:
|
||||
settings_file.write(self._system_settings.to_json())
|
||||
|
||||
|
||||
def save_story(self):
|
||||
self._story_settings['default'].save_story()
|
||||
|
||||
def save_revision(self):
|
||||
self._story_settings['default'].save_revision()
|
||||
|
||||
def create_story(self, story_name, json_data=None):
|
||||
#Story name here is intended for multiple users on multiple stories. Now always uses default
|
||||
#If we can figure out a way to get flask sessions into/through the lua bridge we could re-enable
|
||||
@@ -91,7 +93,7 @@ class koboldai_vars(object):
|
||||
else:
|
||||
self._story_settings[story_name] = story_settings(self.socketio)
|
||||
if json_data is not None:
|
||||
self.load_story(sotry_name, json_data)
|
||||
self.load_story(story_name, json_data)
|
||||
self._story_settings['default'].send_to_ui()
|
||||
|
||||
def story_list(self):
|
||||
@@ -198,7 +200,7 @@ class koboldai_vars(object):
|
||||
authors_note_final = self.authornotetemplate.replace("<|>", self.authornote)
|
||||
used_all_tokens = False
|
||||
for i in range(len(self.actions)-1, -1, -1):
|
||||
if len(self.actions) - i == self.andepth and self.authornote != "":
|
||||
if len(self.actions) - i - 1 == self.andepth and self.authornote != "":
|
||||
game_text = "{}{}".format(authors_note_final, game_text)
|
||||
game_context.insert(0, {"type": "authors_note", "text": authors_note_final})
|
||||
if self.actions.actions[i]["Selected Text Length"]+used_tokens <= token_budget and not used_all_tokens:
|
||||
@@ -440,6 +442,8 @@ class model_settings(settings):
|
||||
self.selected_preset = ""
|
||||
self.uid_presets = []
|
||||
self.default_preset = {}
|
||||
self.cluster_requested_models = [] # The models which we allow to generate during cluster mode
|
||||
|
||||
|
||||
#dummy class to eat the tqdm output
|
||||
class ignore_tqdm(object):
|
||||
@@ -504,7 +508,7 @@ class model_settings(settings):
|
||||
process_variable_changes(self.socketio, self.__class__.__name__.replace("_settings", ""), name, value, old_value)
|
||||
|
||||
class story_settings(settings):
|
||||
local_only_variables = ['socketio', 'tokenizer', 'koboldai_vars', 'no_save']
|
||||
local_only_variables = ['socketio', 'tokenizer', 'koboldai_vars', 'no_save', 'revisions']
|
||||
no_save_variables = ['socketio', 'tokenizer', 'koboldai_vars', 'context', 'no_save']
|
||||
settings_name = "story"
|
||||
def __init__(self, socketio, koboldai_vars, tokenizer=None):
|
||||
@@ -567,6 +571,7 @@ class story_settings(settings):
|
||||
self.prompt_in_ai = False
|
||||
self.context = []
|
||||
self.last_story_load = None
|
||||
self.revisions = []
|
||||
|
||||
#must be at bottom
|
||||
self.no_save = False #Temporary disable save (doesn't save with the file)
|
||||
@@ -594,6 +599,12 @@ class story_settings(settings):
|
||||
settings_file.write(self.to_json())
|
||||
self.gamesaved = True
|
||||
|
||||
def save_revision(self):
|
||||
game = json.loads(self.to_json())
|
||||
del game['revisions']
|
||||
self.revisions.append(game)
|
||||
self.gamesaved = False
|
||||
|
||||
def reset(self):
|
||||
self.no_save = True
|
||||
self.socketio.emit("reset_story", {}, broadcast=True, room="UI_2")
|
||||
|
@@ -1114,6 +1114,7 @@ body {
|
||||
grid-template-columns: 30px auto var(--story_options_size) 30px;
|
||||
grid-template-rows: auto min-content 100px;
|
||||
}
|
||||
|
||||
.main-grid.settings_pinned {
|
||||
margin-left: var(--flyout_menu_width);
|
||||
grid-template-columns: 30px auto var(--story_options_size) 30px;
|
||||
@@ -1180,6 +1181,7 @@ body {
|
||||
padding: 0px 5px 10px 10px;
|
||||
vertical-align: bottom;
|
||||
overflow-y: scroll;
|
||||
outline: none;
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
@@ -1326,10 +1328,10 @@ body {
|
||||
}
|
||||
|
||||
#themetext{
|
||||
grid-area: textarea;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
grid-area: textarea;
|
||||
border-radius: var(--radius_inputbox);
|
||||
}
|
||||
|
||||
@@ -1853,7 +1855,8 @@ body {
|
||||
/* Finder */
|
||||
|
||||
#finder-container,
|
||||
#debug-file-container {
|
||||
#debug-file-container,
|
||||
#prompt-config-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@@ -2059,6 +2062,66 @@ body {
|
||||
background-color: rgb(158, 2, 2);
|
||||
}
|
||||
|
||||
/* Prompt Config */
|
||||
#prompt-config {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
background-color: var(--popup_background_color);
|
||||
width: 25%;
|
||||
height: 75%;
|
||||
}
|
||||
|
||||
#prompt-config-header {
|
||||
/* HACK: Need to add (or use) a theme color for this! */
|
||||
background-color: #212a33;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
#prompt-config-header > h3 {
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#prompt-config-placeholders {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 16px;
|
||||
overflow-y: scroll;
|
||||
padding: 7px;
|
||||
padding-left: 14px
|
||||
}
|
||||
|
||||
.prompt-config-title {
|
||||
display: block;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.prompt-config-value {
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
#prompt-config-done {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
width: 100px;
|
||||
height: 32px;
|
||||
|
||||
position: absolute;
|
||||
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
|
||||
|
||||
cursor: pointer;
|
||||
color: var(--button_text);
|
||||
background-color: var(--button_background);
|
||||
border-radius: var(--radius_settings_button);
|
||||
}
|
||||
|
||||
/*---------------------------------- Global ------------------------------------------------*/
|
||||
.hidden {
|
||||
display: none;
|
||||
@@ -2289,6 +2352,21 @@ h2 .material-icons-outlined {
|
||||
}
|
||||
}
|
||||
|
||||
.horde_trigger[model_model="ReadOnly"] {
|
||||
.horde_trigger[model_model="ReadOnly"],
|
||||
.horde_trigger[model_model="CLUSTER"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.preset_area {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preset_area .settings_button {
|
||||
transform: translateY(6px);
|
||||
}
|
||||
|
||||
input[type='range'] {
|
||||
border: none !important;
|
||||
}
|
@@ -28,6 +28,7 @@ socket.on("error", function(data){show_error_message(data);});
|
||||
socket.on('load_cookies', function(data){load_cookies(data)});
|
||||
socket.on('load_tweaks', function(data){load_tweaks(data);});
|
||||
socket.on("wi_results", updateWISearchListings);
|
||||
socket.on("request_prompt_config", configurePrompt);
|
||||
//socket.onAny(function(event_name, data) {console.log({"event": event_name, "class": data.classname, "data": data});});
|
||||
|
||||
var presets = {};
|
||||
@@ -115,13 +116,16 @@ function reset_story() {
|
||||
while (story_area.lastChild.id != 'story_prompt') {
|
||||
story_area.removeChild(story_area.lastChild);
|
||||
}
|
||||
dummy_span = document.createElement("span");
|
||||
dummy_span = document.createElement("div");
|
||||
dummy_span.id = "Delete Me";
|
||||
dummy_span.classList.add("noselect");
|
||||
document.getElementById("Selected Text").setAttribute("contenteditable", "false");
|
||||
text = "";
|
||||
for (i=0;i<154;i++) {
|
||||
text += "\xa0 ";
|
||||
}
|
||||
dummy_span.textContent = text;
|
||||
dummy_span.setAttribute("contenteditable", false);
|
||||
story_area.append(dummy_span);
|
||||
var option_area = document.getElementById("Select Options");
|
||||
while (option_area.firstChild) {
|
||||
@@ -310,6 +314,8 @@ function do_prompt(data) {
|
||||
if (document.getElementById("Delete Me")) {
|
||||
document.getElementById("Delete Me").remove();
|
||||
}
|
||||
//enable editing
|
||||
document.getElementById("Selected Text").setAttribute("contenteditable", "true");
|
||||
} else {
|
||||
document.getElementById('input_text').placeholder = "Enter Prompt Here (shift+enter for new line)";
|
||||
document.getElementById('input_text').disabled = false;
|
||||
@@ -1062,6 +1068,7 @@ function show_model_menu(data) {
|
||||
document.getElementById("modelurl").classList.add("hidden");
|
||||
document.getElementById("use_gpu_div").classList.add("hidden");
|
||||
document.getElementById("modellayers").classList.add("hidden");
|
||||
document.getElementById("oaimodel").classList.add("hidden");
|
||||
var model_layer_bars = document.getElementById('model_layer_bars');
|
||||
while (model_layer_bars.firstChild) {
|
||||
model_layer_bars.removeChild(model_layer_bars.firstChild);
|
||||
@@ -1169,15 +1176,27 @@ function selected_model_info(data) {
|
||||
document.getElementById("modelurl").classList.add("hidden");
|
||||
}
|
||||
|
||||
//default URL loading
|
||||
if (data.default_url != null) {
|
||||
document.getElementById("modelurl").value = data.default_url;
|
||||
}
|
||||
|
||||
//change model loading on url if needed
|
||||
if (data.models_on_url) {
|
||||
document.getElementById("modelurl").onchange = function () {socket.emit('get_cluster_models', {'key': document.getElementById("modelkey").value, 'url': this.value});};
|
||||
document.getElementById("modelkey").onchange = function () {socket.emit('get_cluster_models', {'key': this.value, 'url': document.getElementById("modelurl").value});};
|
||||
document.getElementById("modelurl").onchange = function () {socket.emit('get_cluster_models', {'model': document.getElementById('btn_loadmodelaccept').getAttribute('selected_model'), 'key': document.getElementById("modelkey").value, 'url': this.value});};
|
||||
document.getElementById("modelkey").onchange = function () {socket.emit('get_cluster_models', {'model': document.getElementById('btn_loadmodelaccept').getAttribute('selected_model'), 'key': this.value, 'url': document.getElementById("modelurl").value});};
|
||||
} else {
|
||||
document.getElementById("modelkey").ochange = function () {socket.emit('OAI_Key_Update', {'model': document.getElementById('btn_loadmodelaccept').getAttribute('selected_model'), 'key': this.value});};
|
||||
document.getElementById("modelurl").ochange = null;
|
||||
}
|
||||
|
||||
//show model select for APIs
|
||||
if (data.show_online_model_select) {
|
||||
document.getElementById("oaimodel").classList.remove("hidden");
|
||||
} else {
|
||||
document.getElementById("oaimodel").classList.add("hidden");
|
||||
}
|
||||
|
||||
//Multiple Model Select?
|
||||
if (data.multi_online_models) {
|
||||
document.getElementById("oaimodel").setAttribute("multiple", "");
|
||||
@@ -1372,15 +1391,28 @@ function load_model() {
|
||||
var path = "";
|
||||
}
|
||||
|
||||
let selected_models = [];
|
||||
for (item of document.getElementById("oaimodel").selectedOptions) {
|
||||
selected_models.push(item.value);
|
||||
}
|
||||
if (selected_models == []) {
|
||||
selected_models = "";
|
||||
} else if (selected_models.length == 1) {
|
||||
selected_models = selected_models[0];
|
||||
}
|
||||
|
||||
message = {'model': model, 'path': path, 'use_gpu': document.getElementById("use_gpu").checked,
|
||||
'key': document.getElementById('modelkey').value, 'gpu_layers': gpu_layers.join(),
|
||||
'disk_layers': disk_layers, 'url': document.getElementById("modelurl").value,
|
||||
'online_model': document.getElementById("oaimodel").value};
|
||||
'online_model': selected_models};
|
||||
socket.emit("load_model", message);
|
||||
document.getElementById("loadmodelcontainer").classList.add("hidden");
|
||||
}
|
||||
|
||||
function world_info_entry_used_in_game(data) {
|
||||
if (!(data.uid in world_info_data)) {
|
||||
world_info_data[data.uid] = {};
|
||||
}
|
||||
world_info_data[data.uid]['used_in_game'] = data['used_in_game'];
|
||||
world_info_card = document.getElementById("world_info_"+data.uid);
|
||||
if (data.used_in_game) {
|
||||
@@ -2087,34 +2119,54 @@ function select_game_text(event) {
|
||||
if (document.selection) {
|
||||
if (document.selection.createRange().parentElement().id == 'story_prompt') {
|
||||
new_selected_game_chunk = document.selection.createRange().parentElement();
|
||||
} else if (document.selection.createRange().parentElement().id == 'gamescreen') {
|
||||
new_selected_game_chunk = null;
|
||||
console.log("Do nothing");
|
||||
} else {
|
||||
new_selected_game_chunk = document.selection.createRange().parentElement().parentElement();
|
||||
}
|
||||
} else {
|
||||
if (window.getSelection().anchorNode.parentNode.id == 'story_prompt') {
|
||||
new_selected_game_chunk = window.getSelection().anchorNode.parentNode;
|
||||
if(window.getSelection().anchorNode.parentNode) {
|
||||
if (window.getSelection().anchorNode.parentNode.id == 'story_prompt') {
|
||||
new_selected_game_chunk = window.getSelection().anchorNode.parentNode;
|
||||
} else if (window.getSelection().anchorNode.parentNode.id == "gamescreen") {
|
||||
new_selected_game_chunk = null;
|
||||
console.log("Do nothing");
|
||||
} else {
|
||||
new_selected_game_chunk = window.getSelection().anchorNode.parentNode.parentNode;
|
||||
}
|
||||
} else {
|
||||
new_selected_game_chunk = window.getSelection().anchorNode.parentNode.parentNode;
|
||||
new_selected_game_chunk = null;
|
||||
}
|
||||
}
|
||||
//if we've moved to a new game chunk we need to save the old chunk
|
||||
if ((new_selected_game_chunk != selected_game_chunk) && (selected_game_chunk != null)) {
|
||||
edit_game_text();
|
||||
}
|
||||
if (new_selected_game_chunk != selected_game_chunk) {
|
||||
selected_game_chunk = new_selected_game_chunk
|
||||
}
|
||||
|
||||
//set editting class
|
||||
for (item of document.getElementsByClassName("editing")) {
|
||||
item.classList.remove("editing");
|
||||
//Check to see if new selection is a game chunk or something else
|
||||
|
||||
if ((new_selected_game_chunk == null) || (((new_selected_game_chunk.id == "story_prompt") || (new_selected_game_chunk.id.slice(0,20) == "Selected Text Chunk ")) && (document.activeElement.isContentEditable))) {
|
||||
if (new_selected_game_chunk != selected_game_chunk) {
|
||||
for (item of document.getElementsByClassName("editing")) {
|
||||
item.classList.remove("editing");
|
||||
}
|
||||
selected_game_chunk = new_selected_game_chunk;
|
||||
selected_game_chunk.classList.add("editing");
|
||||
}
|
||||
|
||||
} else {
|
||||
selected_game_chunk = null;
|
||||
for (item of document.getElementsByClassName("editing")) {
|
||||
item.classList.remove("editing");
|
||||
}
|
||||
window.getSelection().removeAllRanges()
|
||||
}
|
||||
selected_game_chunk.classList.add("editing");
|
||||
}
|
||||
}
|
||||
|
||||
function edit_game_text() {
|
||||
if ((selected_game_chunk != null) && (selected_game_chunk.textContent != selected_game_chunk.original_text)) {
|
||||
if ((selected_game_chunk != null) && (selected_game_chunk.textContent != selected_game_chunk.original_text) && (selected_game_chunk != document.getElementById("Delete Me"))) {
|
||||
if (selected_game_chunk.id == "story_prompt") {
|
||||
sync_to_server(selected_game_chunk);
|
||||
} else {
|
||||
@@ -2125,28 +2177,6 @@ function edit_game_text() {
|
||||
}
|
||||
}
|
||||
|
||||
function clear_edit_game_text_tag() {
|
||||
let id = null;
|
||||
if (document.selection) {
|
||||
if (document.selection.createRange().parentElement().id == 'story_prompt') {
|
||||
id = document.selection.createRange().parentElement().id;
|
||||
} else {
|
||||
id = document.selection.createRange().parentElement().parentElement().id;
|
||||
}
|
||||
} else {
|
||||
if (window.getSelection().anchorNode.parentNode.id == 'story_prompt') {
|
||||
id = window.getSelection().anchorNode.parentNode.id;
|
||||
} else {
|
||||
id = window.getSelection().anchorNode.parentNode.parentNode.id;
|
||||
}
|
||||
}
|
||||
if ((id != 'story_prompt') && (id.slice(0, 20) != "Selected Text Chunk ")) {
|
||||
for (item of document.getElementsByClassName("editing")) {
|
||||
item.classList.remove("editing");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function save_preset() {
|
||||
socket.emit("save_new_preset", {"preset": document.getElementById("new_preset_name").value, "description": document.getElementById("new_preset_description").value});
|
||||
document.getElementById('save_preset').classList.add('hidden');
|
||||
@@ -3398,6 +3428,51 @@ async function downloadDebugFile(redact=true) {
|
||||
downloadString(JSON.stringify(debug_info, null, 4), "kobold_debug.json");
|
||||
}
|
||||
|
||||
function configurePrompt(placeholderData) {
|
||||
console.log(placeholderData);
|
||||
const container = document.querySelector("#prompt-config-container");
|
||||
container.classList.remove("hidden");
|
||||
|
||||
const placeholders = document.querySelector("#prompt-config-placeholders");
|
||||
|
||||
for (const phData of placeholderData) {
|
||||
let placeholder = $e("div", placeholders, {classes: ["prompt-config-ph"]});
|
||||
|
||||
|
||||
// ${character.name} is an AI Dungeon thing, although I believe NAI
|
||||
// supports it as well. Many prompts use it. I think this is the only
|
||||
// hardcoded thing like this.
|
||||
let titleText = phData.title || phData.id;
|
||||
if (titleText === "character.name") titleText = "Character Name";
|
||||
|
||||
let title = $e("span", placeholder, {classes: ["prompt-config-title"], innerText: titleText});
|
||||
|
||||
if (phData.description) $e("span", placeholder, {
|
||||
classes: ["prompt-config-desc", "help_text"],
|
||||
innerText: phData.description
|
||||
});
|
||||
|
||||
let input = $e("input", placeholder, {
|
||||
classes: ["prompt-config-value"],
|
||||
value: phData.default || "",
|
||||
placeholder: phData.default || "",
|
||||
"placeholder-id": phData.id
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function sendPromptConfiguration() {
|
||||
let data = {};
|
||||
for (const configInput of document.querySelectorAll(".prompt-config-value")) {
|
||||
data[configInput.getAttribute("placeholder-id")] = configInput.value;
|
||||
}
|
||||
|
||||
socket.emit("configure_prompt", data);
|
||||
|
||||
document.querySelector("#prompt-config-container").classList.add("hidden");
|
||||
$(".prompt-config-ph").remove();
|
||||
}
|
||||
|
||||
function loadNAILorebook(data, filename) {
|
||||
let lorebookVersion = data.lorebookVersion;
|
||||
let wi_data = {folders: {[filename]: []}, entries: {}};
|
||||
|
@@ -47,9 +47,10 @@
|
||||
<!------------ Game Text Screen--------------------->
|
||||
<div class="gamescreen" id="gamescreen">
|
||||
<div id="disconnect_message"><center><h1>Disconnected</h1></center></div>
|
||||
<div class="gametext" id="Selected Text" contenteditable=true onblur="edit_game_text();selected_game_chunk = null;clear_edit_game_text_tag();" onclick="select_game_text(null);" onkeyup="select_game_text(event);">
|
||||
<div class="gametext" id="Selected Text" contenteditable=false onblur="select_game_text(null);" onclick="select_game_text(null);" onkeyup="select_game_text(event);">
|
||||
<span id="story_prompt" class="var_sync_story_prompt var_sync_alt_story_prompt_length var_sync_alt_story_prompt_in_ai rawtext"></span>
|
||||
<span id="Delete Me">
|
||||
<div id="Delete Me" class="noselect" contenteditable=false>
|
||||
<span>
|
||||
|
||||
|
||||
|
||||
@@ -57,12 +58,15 @@
|
||||
|
||||
|
||||
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!------------ Sequences --------------------->
|
||||
<div id="action_count" class="var_sync_actions_Action_Count hidden"></div>
|
||||
<div id="Select Options" class="sequence_area"></div>
|
||||
|
||||
<!------------ Theme Area--------------------->
|
||||
<div class="themerow" id="themerow">
|
||||
<div class="tabrow nomenu_icon">
|
||||
|
@@ -113,7 +113,7 @@
|
||||
<input autocomplete="off" class="form-control" type="text" placeholder="Prompt Number (4-digit number at the end of aetherroom.club URL)" id="aidgpromptnum">
|
||||
</div>
|
||||
<div class="popup_load_cancel">
|
||||
<button type="button" class="btn btn-primary popup_load_cancel_button" onclick="socket.emit('load_aidg_club', document.getElementById('aidgpromptnum').value); this.parentElement.parentElement.classList.add('hidden');">Accept</button>
|
||||
<button type="button" class="btn btn-primary popup_load_cancel_button" onclick="socket.emit('load_aidg_club', document.getElementById('aidgpromptnum').value); $('.popup').addClass('hidden');">Accept</button>
|
||||
<button type="button" class="btn btn-primary popup_load_cancel_button" onclick="this.parentElement.parentElement.classList.add('hidden');">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -192,4 +192,18 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!---------------- Prompt Config ------------------->
|
||||
<div id="prompt-config-container" class="hidden">
|
||||
<div id="prompt-config">
|
||||
<div id="prompt-config-header">
|
||||
<h3 class="noselect">Prompt Configuration</h3>
|
||||
<span class="help_text">This prompt has placeholders you need to fill in before starting.</span>
|
||||
</div>
|
||||
|
||||
<!-- Order, default, title, description -->
|
||||
<div id="prompt-config-placeholders"></div>
|
||||
<div id="prompt-config-done" onclick="sendPromptConfiguration();">Done</div>
|
||||
</div>
|
||||
</div>
|
@@ -107,12 +107,12 @@
|
||||
<span id="debug-dump" class="cursor" onclick="document.getElementById('debug-file-container').classList.remove('hidden');">Download debug dump</span>
|
||||
</div>
|
||||
<div id="setting_menu_settings" class="hidden settings_category_area tab-target tab-target-settings">
|
||||
<div class="force_center">
|
||||
<select class="var_sync_model_selected_preset settings_select presets" onchange='sync_to_server(this)'><option>Preset</option></select>
|
||||
<div class="preset_area">
|
||||
<button class="settings_button" onclick="show_save_preset();">
|
||||
<span class="material-icons-outlined cursor" title="Save Preset">save</span>
|
||||
<span class="button_label">Save Preset</span>
|
||||
</button>
|
||||
<select class="var_sync_model_selected_preset settings_select presets" onchange='sync_to_server(this)'><option>Preset</option></select>
|
||||
</div>
|
||||
{% with menu='Settings' %}
|
||||
<div class="collapsable_header" onclick="toggle_setting_category(this);">
|
||||
|
@@ -171,7 +171,7 @@
|
||||
--radius_wi_card: 10px;
|
||||
--radius_palette_card: 10px;
|
||||
--radius_settings_button: 5px;
|
||||
--tabs_rounding: 6px;
|
||||
--tabs_rounding: 5px;
|
||||
|
||||
|
||||
|
||||
|
@@ -170,7 +170,7 @@
|
||||
--radius_wi_card: 5px;
|
||||
--radius_palette_card: 5px;
|
||||
--radius_settings_button: 2px;
|
||||
--tabs_rounding: 6px;
|
||||
--tabs_rounding: 2px;
|
||||
|
||||
|
||||
|
||||
|
194
themes/Nostalgia.css
Normal file
194
themes/Nostalgia.css
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
Name: Nostalgia
|
||||
Author: LightSaveUs
|
||||
Version: 0.1
|
||||
Description: A theme inspired by the previous KoboldAI interface.
|
||||
*/
|
||||
|
||||
:root {
|
||||
/*----------------Palette Theme--------------------*/
|
||||
--primary_palette: #000000;
|
||||
--on_primary_palette: #000000;
|
||||
--primary_container_palette: #000000;
|
||||
--on_primary_container_palette: #000000;
|
||||
|
||||
--secondary_palette: #000000;
|
||||
--on_secondary_palette: #000000;
|
||||
--secondary_container_palette: #000000;
|
||||
--on_secondary_container_palette: #000000;
|
||||
|
||||
--tertiary_palette: #000000;
|
||||
--on_tertiary_palette: #000000;
|
||||
--tertiary_container_palette: #000000;
|
||||
--on_tertiary_container_palette: #000000;
|
||||
|
||||
--background_palette: #000000;
|
||||
--on_background_palette:#000000;
|
||||
--layer1_palette: #000000;
|
||||
--layer2_palette: #000000;
|
||||
--layer3_palette: #000000;
|
||||
--layer4_palette: #000000;
|
||||
--outline_palette: #000000;
|
||||
|
||||
--middle_palette: #000000;
|
||||
--on_middle_palette: #000000;
|
||||
--surface_palette: #000000;
|
||||
--on_surface_palette: #000000;
|
||||
|
||||
/*----------------Advanced Theme--------------------*/
|
||||
/*General*/
|
||||
--background: #303030;
|
||||
--gamescreen_background: #262626;
|
||||
--input_background: #404040;
|
||||
|
||||
--text: #fff;
|
||||
--text_to_ai_color: #cdd9e0;
|
||||
--text_edit: #cdf;
|
||||
|
||||
--statusbar_color: #6c6c6e99;
|
||||
--statusbar_text_color: #ffffff;
|
||||
--scrollbar-color: #74747400;
|
||||
|
||||
/*Buttons*/
|
||||
/*General*/
|
||||
--enabled_button_text: #ffffff;
|
||||
--enabled_button_background_color: #337ab7;
|
||||
--enabled_button_border_color: #2e6da4;
|
||||
|
||||
--disabled_button_text: #303030;
|
||||
--disabled_button_background_color: #495762;
|
||||
--disabled_button_border_color: #686c68;
|
||||
|
||||
/*Home Tab*/
|
||||
--button_text: #ffffff;
|
||||
--button_background: #285f90;
|
||||
|
||||
/*Alternate Button*/
|
||||
--alternate_button_text: #ffffff;
|
||||
--alternate_button_background: #285f90;
|
||||
|
||||
|
||||
/*Sequence, AKA Gens Per Action*/
|
||||
--sequence_area_background: #303030;
|
||||
--sequence_background: #262626;
|
||||
--sequence_text: #ffffff;
|
||||
|
||||
/*Side Menus*/
|
||||
--tab_color: #337ab7;
|
||||
|
||||
--flyout_background: #212122;
|
||||
--flyout_background_pinned: #212122;
|
||||
|
||||
--setting_background: #295071;
|
||||
--setting_text: #ffffff;
|
||||
|
||||
--sample_order_select_color: #98bcdb;
|
||||
--sample_order_select_color_text: #23527c;
|
||||
|
||||
--dropdown_text: #ffffff;
|
||||
--dropdown_background: #337ab7;
|
||||
|
||||
--rangeslider_background_color: #ffffff;
|
||||
--rangeslider_color: #005dc8;
|
||||
--rangeslider_circle_color: #0077ff;
|
||||
|
||||
--help_icon: #ffffff;/*--tooltip_text: #000000;
|
||||
--tooltip_background: #000000;*/
|
||||
--setting_category_help_text_color: #3bf723;
|
||||
|
||||
--setting_footer_border_color: grey;
|
||||
--setting_footer_text_color: #ffffff;
|
||||
--setting_footer_background_color: #212122;
|
||||
|
||||
/*Palette Card*/
|
||||
--palette_card_background: #295071;
|
||||
--palette_card_text: #ffffff;
|
||||
--palette_table_border: #12324f;
|
||||
|
||||
/*World Info*/
|
||||
--wi_card_border_color: #12324f;
|
||||
--wi_card_border_color_to_ai: #eeeeeead;
|
||||
|
||||
--wi_card_bg_color: #395c7c;
|
||||
--wi_card_text_color: #ffffff;
|
||||
|
||||
--wi_card_tag_bg_color: #295071;
|
||||
--wi_card_tag_text_color: #ffffff;
|
||||
|
||||
--wi_tag_color: #3379b7;
|
||||
--wi_tag_text_color: #ffffff;
|
||||
|
||||
/*Popup*/
|
||||
--popup_background_color: #333;
|
||||
--popup_title_bar_color: #337ab7;
|
||||
--popup_title_bar_color_text: #ffffff;
|
||||
|
||||
--popup_item_color: #333333;
|
||||
--popup_item_color_text: #ffffff;
|
||||
|
||||
--popup_hover_color: #688f1f;
|
||||
--popup_hover_color_text: #ffffff;
|
||||
--popup_selected_color: #688f1f;
|
||||
--popup_selected_color_text: #ffffff;
|
||||
|
||||
--popup_button_color: #337ab7;
|
||||
--popup_button_color_text: #ffffff;
|
||||
--popup_cancel_button_color: #337ab7;
|
||||
--popup_cancel_button_color_text: #ffffff;
|
||||
|
||||
--error: #ffb4ab;
|
||||
--error_text: #690005;
|
||||
--error_title: #93000a;
|
||||
--error_title_text: #ffdad6;
|
||||
|
||||
/*Context Bar Colors*/
|
||||
--context_colors_memory: #295071;
|
||||
--context_colors_authors_notes: #337ab7;
|
||||
--context_colors_world_info: #98bcdb;
|
||||
--context_colors_prompt: #3bf723;
|
||||
--context_colors_game_text: #688f1f;
|
||||
--context_colors_submit: #ededed;
|
||||
--context_colors_unused: #ffffff24;
|
||||
--context_colors_soft_prompt: #262626;
|
||||
|
||||
/*Parameters*/
|
||||
--scrollbar-size: 6px;
|
||||
--palette_card_shadow: 0;
|
||||
--wi_card_shadow: 0;
|
||||
--light_shadow_value: 0;
|
||||
--left_menu_strong_shadow: 0;
|
||||
--right_menu_light_shadow: 0;
|
||||
--right_menu_strong_shadow: 0;
|
||||
--radius_inputbox: 5px;
|
||||
--radius_unpinned_menu: 5px;
|
||||
--radius_sequence: 5px;
|
||||
--radius_settings_background: 5px;
|
||||
--radius_button: 5px;
|
||||
--radius_alternate_button: 5px;
|
||||
--radius_item_popup: 5px;
|
||||
--radius_wi_card: 5px;
|
||||
--radius_palette_card: 5px;
|
||||
--radius_settings_button: 5px;
|
||||
--tabs_rounding: 5px;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*----------------VARIABLES--------------------*/
|
||||
--flyout_menu_closed_width: 0px;
|
||||
--setting_menu_closed_width_no_pins_width: 0px;
|
||||
--story_options_size: 30%;
|
||||
--story_pinned_areas_left:"menuicon options gamescreen lefticon"
|
||||
"menuicon theme theme lefticon"
|
||||
"menuicon inputrow inputrow lefticon";
|
||||
--story_pinned_areas_right:"menuicon gamescreen options lefticon"
|
||||
"menuicon theme theme lefticon"
|
||||
"menuicon inputrow inputrow lefticon";
|
||||
--story_pinned_area_widths_left: 30pxvar(--story_options_size) auto 30px;
|
||||
--story_pinned_area_widths_right: 30pxautovar(--story_options_size) 30px;
|
||||
--story_pinned_areas:var(--story_pinned_areas_left);
|
||||
--story_pinned_area_widths:var(--story_pinned_area_widths_left);
|
||||
--font_size_adjustment: 0px;
|
||||
--game_screen_font_size_adjustment: 1;}
|
@@ -178,7 +178,7 @@
|
||||
--radius_wi_card: 10px;
|
||||
--radius_palette_card: 10px;
|
||||
--radius_settings_button: 10px;
|
||||
--tabs_rounding: 6px;
|
||||
--tabs_rounding: 10px;
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user