mirror of
https://github.com/KoboldAI/KoboldAI-Client.git
synced 2025-04-26 15:58:47 +02:00
Added Formatting options
Added Bootstrap toggle library for UI Added injection points for input/output modification
This commit is contained in:
parent
0e0947d93a
commit
b55266a7c8
110
aiserver.py
110
aiserver.py
@ -4,15 +4,18 @@
|
|||||||
# By: KoboldAIDev
|
# By: KoboldAIDev
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
|
|
||||||
|
# External packages
|
||||||
from os import path, getcwd
|
from os import path, getcwd
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from tkinter import messagebox
|
from tkinter import messagebox
|
||||||
import json
|
import json
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
|
# KoboldAI
|
||||||
import fileops
|
import fileops
|
||||||
import gensettings
|
import gensettings
|
||||||
from utils import debounce
|
from utils import debounce
|
||||||
|
import utils
|
||||||
|
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
# Variables & Storage
|
# Variables & Storage
|
||||||
@ -69,6 +72,7 @@ class vars:
|
|||||||
hascuda = False # Whether torch has detected CUDA on the system
|
hascuda = False # Whether torch has detected CUDA on the system
|
||||||
usegpu = False # Whether to launch pipeline with GPU support
|
usegpu = False # Whether to launch pipeline with GPU support
|
||||||
custmodpth = "" # Filesystem location of custom model to run
|
custmodpth = "" # Filesystem location of custom model to run
|
||||||
|
formatoptns = {} # Container for state of formatting options
|
||||||
|
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
# Function to get model selection at startup
|
# Function to get model selection at startup
|
||||||
@ -349,6 +353,23 @@ def get_message(msg):
|
|||||||
vars.andepth = int(msg['data'])
|
vars.andepth = int(msg['data'])
|
||||||
emit('from_server', {'cmd': 'setlabelanotedepth', 'data': msg['data']})
|
emit('from_server', {'cmd': 'setlabelanotedepth', 'data': msg['data']})
|
||||||
settingschanged()
|
settingschanged()
|
||||||
|
# Format - Trim incomplete sentences
|
||||||
|
elif(msg['cmd'] == 'frmttriminc'):
|
||||||
|
if('frmttriminc' in vars.formatoptns):
|
||||||
|
vars.formatoptns["frmttriminc"] = msg['data']
|
||||||
|
settingschanged()
|
||||||
|
elif(msg['cmd'] == 'frmtrmblln'):
|
||||||
|
if('frmtrmblln' in vars.formatoptns):
|
||||||
|
vars.formatoptns["frmtrmblln"] = msg['data']
|
||||||
|
settingschanged()
|
||||||
|
elif(msg['cmd'] == 'frmtrmspch'):
|
||||||
|
if('frmtrmspch' in vars.formatoptns):
|
||||||
|
vars.formatoptns["frmtrmspch"] = msg['data']
|
||||||
|
settingschanged()
|
||||||
|
elif(msg['cmd'] == 'frmtadsnsp'):
|
||||||
|
if('frmtadsnsp' in vars.formatoptns):
|
||||||
|
vars.formatoptns["frmtadsnsp"] = msg['data']
|
||||||
|
settingschanged()
|
||||||
|
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
#
|
#
|
||||||
@ -368,6 +389,13 @@ def sendsettings():
|
|||||||
else:
|
else:
|
||||||
for set in gensettings.gensettingsik:
|
for set in gensettings.gensettingsik:
|
||||||
emit('from_server', {'cmd': 'addsetting', 'data': set})
|
emit('from_server', {'cmd': 'addsetting', 'data': set})
|
||||||
|
|
||||||
|
# Send formatting options
|
||||||
|
for frm in gensettings.formatcontrols:
|
||||||
|
emit('from_server', {'cmd': 'addformat', 'data': frm})
|
||||||
|
# Add format key to vars if it wasn't loaded with client.settings
|
||||||
|
if(not frm["id"] in vars.formatoptns):
|
||||||
|
vars.formatoptns[frm["id"]] = False;
|
||||||
|
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
#
|
#
|
||||||
@ -375,14 +403,15 @@ def sendsettings():
|
|||||||
def savesettings():
|
def savesettings():
|
||||||
# Build json to write
|
# Build json to write
|
||||||
js = {}
|
js = {}
|
||||||
js["apikey"] = vars.apikey
|
js["apikey"] = vars.apikey
|
||||||
js["andepth"] = vars.andepth
|
js["andepth"] = vars.andepth
|
||||||
js["temp"] = vars.temp
|
js["temp"] = vars.temp
|
||||||
js["top_p"] = vars.top_p
|
js["top_p"] = vars.top_p
|
||||||
js["rep_pen"] = vars.rep_pen
|
js["rep_pen"] = vars.rep_pen
|
||||||
js["genamt"] = vars.genamt
|
js["genamt"] = vars.genamt
|
||||||
js["max_length"] = vars.max_length
|
js["max_length"] = vars.max_length
|
||||||
js["ikgen"] = vars.ikgen
|
js["ikgen"] = vars.ikgen
|
||||||
|
js["formatoptns"] = vars.formatoptns
|
||||||
|
|
||||||
# Write it
|
# Write it
|
||||||
file = open("client.settings", "w")
|
file = open("client.settings", "w")
|
||||||
@ -417,6 +446,8 @@ def loadsettings():
|
|||||||
vars.max_length = js["max_length"]
|
vars.max_length = js["max_length"]
|
||||||
if("ikgen" in js):
|
if("ikgen" in js):
|
||||||
vars.ikgen = js["ikgen"]
|
vars.ikgen = js["ikgen"]
|
||||||
|
if("formatoptns" in js):
|
||||||
|
vars.formatoptns = js["formatoptns"]
|
||||||
|
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
@ -436,14 +467,22 @@ def actionsubmit(data):
|
|||||||
return
|
return
|
||||||
set_aibusy(1)
|
set_aibusy(1)
|
||||||
if(not vars.gamestarted):
|
if(not vars.gamestarted):
|
||||||
vars.gamestarted = True # Start the game
|
# Start the game
|
||||||
vars.prompt = data # Save this first action as the prompt
|
vars.gamestarted = True
|
||||||
emit('from_server', {'cmd': 'updatescreen', 'data': 'Please wait, generating story...'}) # Clear the startup text from game screen
|
# Save this first action as the prompt
|
||||||
|
vars.prompt = data
|
||||||
|
# Clear the startup text from game screen
|
||||||
|
emit('from_server', {'cmd': 'updatescreen', 'data': 'Please wait, generating story...'})
|
||||||
calcsubmit(data) # Run the first action through the generator
|
calcsubmit(data) # Run the first action through the generator
|
||||||
else:
|
else:
|
||||||
# Dont append submission if it's a blank/continue action
|
# Dont append submission if it's a blank/continue action
|
||||||
if(data != ""):
|
if(data != ""):
|
||||||
|
# Apply input formatting & scripts before sending to tokenizer
|
||||||
|
data = applyinputformatting(data)
|
||||||
|
# Store the result in the Action log
|
||||||
vars.actions.append(data)
|
vars.actions.append(data)
|
||||||
|
|
||||||
|
# Off to the tokenizer!
|
||||||
calcsubmit(data)
|
calcsubmit(data)
|
||||||
|
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
@ -594,7 +633,12 @@ def generate(txt, min, max):
|
|||||||
temperature=vars.temp
|
temperature=vars.temp
|
||||||
)[0]["generated_text"]
|
)[0]["generated_text"]
|
||||||
print("{0}{1}{2}".format(colors.CYAN, genout, colors.END))
|
print("{0}{1}{2}".format(colors.CYAN, genout, colors.END))
|
||||||
vars.actions.append(getnewcontent(genout))
|
|
||||||
|
# Format output before continuing
|
||||||
|
genout = applyoutputformatting(getnewcontent(genout))
|
||||||
|
|
||||||
|
# Add formatted text to Actions array and refresh the game screen
|
||||||
|
vars.actions.append(genout)
|
||||||
refresh_story()
|
refresh_story()
|
||||||
emit('from_server', {'cmd': 'texteffect', 'data': len(vars.actions)})
|
emit('from_server', {'cmd': 'texteffect', 'data': len(vars.actions)})
|
||||||
|
|
||||||
@ -611,7 +655,7 @@ def formatforhtml(txt):
|
|||||||
return txt.replace("\\r", "<br/>").replace("\\n", "<br/>").replace('\n', '<br/>').replace('\r', '<br/>')
|
return txt.replace("\\r", "<br/>").replace("\\n", "<br/>").replace('\n', '<br/>').replace('\r', '<br/>')
|
||||||
|
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
# Strips submitted text from the text returned by the AI
|
# Strips submitted text from the text returned by the AI
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
def getnewcontent(txt):
|
def getnewcontent(txt):
|
||||||
ln = len(vars.actions)
|
ln = len(vars.actions)
|
||||||
@ -622,6 +666,35 @@ def getnewcontent(txt):
|
|||||||
|
|
||||||
return (txt.split(delim)[-1])
|
return (txt.split(delim)[-1])
|
||||||
|
|
||||||
|
#==================================================================#
|
||||||
|
# Applies chosen formatting options to text submitted to AI
|
||||||
|
#==================================================================#
|
||||||
|
def applyinputformatting(txt):
|
||||||
|
# Add sentence spacing
|
||||||
|
if(vars.formatoptns["frmtadsnsp"]):
|
||||||
|
txt = utils.addsentencespacing(txt, vars.actions)
|
||||||
|
|
||||||
|
return txt
|
||||||
|
|
||||||
|
#==================================================================#
|
||||||
|
# Applies chosen formatting options to text returned from AI
|
||||||
|
#==================================================================#
|
||||||
|
def applyoutputformatting(txt):
|
||||||
|
# Use standard quotes and apostrophes
|
||||||
|
txt = utils.fixquotes(txt)
|
||||||
|
|
||||||
|
# Trim incomplete sentences
|
||||||
|
if(vars.formatoptns["frmttriminc"]):
|
||||||
|
txt = utils.trimincompletesentence(txt)
|
||||||
|
# Replace blank lines
|
||||||
|
if(vars.formatoptns["frmtrmblln"]):
|
||||||
|
txt = utils.replaceblanklines(txt)
|
||||||
|
# Remove special characters
|
||||||
|
if(vars.formatoptns["frmtrmspch"]):
|
||||||
|
txt = utils.removespecialchars(txt)
|
||||||
|
|
||||||
|
return txt
|
||||||
|
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
# Sends the current story content to the Game Screen
|
# Sends the current story content to the Game Screen
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
@ -637,6 +710,9 @@ def refresh_story():
|
|||||||
# Sends the current generator settings to the Game Menu
|
# Sends the current generator settings to the Game Menu
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
def refresh_settings():
|
def refresh_settings():
|
||||||
|
# Suppress toggle change events while loading state
|
||||||
|
emit('from_server', {'cmd': 'allowtoggle', 'data': False})
|
||||||
|
|
||||||
if(vars.model != "InferKit"):
|
if(vars.model != "InferKit"):
|
||||||
emit('from_server', {'cmd': 'updatetemp', 'data': vars.temp})
|
emit('from_server', {'cmd': 'updatetemp', 'data': vars.temp})
|
||||||
emit('from_server', {'cmd': 'updatetopp', 'data': vars.top_p})
|
emit('from_server', {'cmd': 'updatetopp', 'data': vars.top_p})
|
||||||
@ -649,6 +725,14 @@ def refresh_settings():
|
|||||||
emit('from_server', {'cmd': 'updateikgen', 'data': vars.ikgen})
|
emit('from_server', {'cmd': 'updateikgen', 'data': vars.ikgen})
|
||||||
|
|
||||||
emit('from_server', {'cmd': 'updateanotedepth', 'data': vars.andepth})
|
emit('from_server', {'cmd': 'updateanotedepth', 'data': vars.andepth})
|
||||||
|
|
||||||
|
emit('from_server', {'cmd': 'updatefrmttriminc', 'data': vars.formatoptns["frmttriminc"]})
|
||||||
|
emit('from_server', {'cmd': 'updatefrmtrmblln', 'data': vars.formatoptns["frmtrmblln"]})
|
||||||
|
emit('from_server', {'cmd': 'updatefrmtrmspch', 'data': vars.formatoptns["frmtrmspch"]})
|
||||||
|
emit('from_server', {'cmd': 'updatefrmtadsnsp', 'data': vars.formatoptns["frmtadsnsp"]})
|
||||||
|
|
||||||
|
# Allow toggle events again
|
||||||
|
emit('from_server', {'cmd': 'allowtoggle', 'data': True})
|
||||||
|
|
||||||
#==================================================================#
|
#==================================================================#
|
||||||
# Sets the logical and display states for the AI Busy condition
|
# Sets the logical and display states for the AI Busy condition
|
||||||
|
@ -86,4 +86,25 @@ gensettingsik =[{
|
|||||||
"step": 2,
|
"step": 2,
|
||||||
"default": 200,
|
"default": 200,
|
||||||
"tooltip": "Number of characters the AI should generate."
|
"tooltip": "Number of characters the AI should generate."
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
formatcontrols = [{
|
||||||
|
"label": "Trim incomplete sentences",
|
||||||
|
"id": "frmttriminc",
|
||||||
|
"tooltip": "Remove text after last sentence closure. If no closure is found, all tokens will be returned."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Remove blank lines",
|
||||||
|
"id": "frmtrmblln",
|
||||||
|
"tooltip": "Replace double newlines (\\n\\n) with single newlines to avoid blank lines."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Remove special characters",
|
||||||
|
"id": "frmtrmspch",
|
||||||
|
"tooltip": "Remove special characters (@,#,%,^, etc)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Add sentence spacing",
|
||||||
|
"id": "frmtadsnsp",
|
||||||
|
"tooltip": "If the last action ended with punctuation, add a space to the beginning of the next action."
|
||||||
|
}]
|
@ -11,6 +11,7 @@ var button_newgame;
|
|||||||
var button_save;
|
var button_save;
|
||||||
var button_load;
|
var button_load;
|
||||||
var button_settings;
|
var button_settings;
|
||||||
|
var button_format;
|
||||||
var button_send;
|
var button_send;
|
||||||
var button_actedit;
|
var button_actedit;
|
||||||
var button_actmem;
|
var button_actmem;
|
||||||
@ -21,6 +22,7 @@ var game_text;
|
|||||||
var input_text;
|
var input_text;
|
||||||
var message_text;
|
var message_text;
|
||||||
var settings_menu;
|
var settings_menu;
|
||||||
|
var format_menu;
|
||||||
var anote_menu;
|
var anote_menu;
|
||||||
var anote_input;
|
var anote_input;
|
||||||
var anote_labelcur;
|
var anote_labelcur;
|
||||||
@ -30,6 +32,10 @@ var anote_slider;
|
|||||||
var shift_down = false;
|
var shift_down = false;
|
||||||
var do_clear_ent = false;
|
var do_clear_ent = false;
|
||||||
|
|
||||||
|
// Display vars
|
||||||
|
var allowtoggle = false;
|
||||||
|
var formatcount = 0;
|
||||||
|
|
||||||
//=================================================================//
|
//=================================================================//
|
||||||
// METHODS
|
// METHODS
|
||||||
//=================================================================//
|
//=================================================================//
|
||||||
@ -58,16 +64,44 @@ function addSetting(ob) {
|
|||||||
</div>\
|
</div>\
|
||||||
</div>");
|
</div>");
|
||||||
// Set references to HTML objects
|
// Set references to HTML objects
|
||||||
refin = $("#"+ob.id);
|
var refin = $("#"+ob.id);
|
||||||
reflb = $("#"+ob.id+"cur");
|
var reflb = $("#"+ob.id+"cur");
|
||||||
window["setting_"+ob.id] = refin;
|
window["setting_"+ob.id] = refin; // Is this still needed?
|
||||||
window["label_"+ob.id] = reflb;
|
window["label_"+ob.id] = reflb; // Is this still needed?
|
||||||
// Add event function to input
|
// Add event function to input
|
||||||
refin.on("input", function () {
|
refin.on("input", function () {
|
||||||
socket.send({'cmd': $(this).attr('id'), 'data': $(this).val()});
|
socket.send({'cmd': $(this).attr('id'), 'data': $(this).val()});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addFormat(ob) {
|
||||||
|
// Check if we need to make a new column for this button
|
||||||
|
if(formatcount == 0) {
|
||||||
|
format_menu.append("<div class=\"formatcolumn\"></div>");
|
||||||
|
}
|
||||||
|
// Get reference to the last child column
|
||||||
|
var ref = $("#formatmenu > div").last();
|
||||||
|
// Add format block to Format Menu
|
||||||
|
ref.append("<div class=\"formatrow\">\
|
||||||
|
<input type=\"checkbox\" data-toggle=\"toggle\" data-onstyle=\"success\" id=\""+ob.id+"\">\
|
||||||
|
<span class=\"formatlabel\">"+ob.label+" </span>\
|
||||||
|
<span class=\"helpicon\">?<span class=\"helptext\">"+ob.tooltip+"</span></span>\
|
||||||
|
</div>");
|
||||||
|
// Tell Bootstrap-Toggle to render the new checkbox
|
||||||
|
$("input[type=checkbox]").bootstrapToggle();
|
||||||
|
// Add event to input
|
||||||
|
$("#"+ob.id).on("change", function () {
|
||||||
|
if(allowtoggle) {
|
||||||
|
socket.send({'cmd': $(this).attr('id'), 'data': $(this).prop('checked')});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Increment display variable
|
||||||
|
formatcount++;
|
||||||
|
if(formatcount == 2) {
|
||||||
|
formatcount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function enableButtons(refs) {
|
function enableButtons(refs) {
|
||||||
for(i=0; i<refs.length; i++) {
|
for(i=0; i<refs.length; i++) {
|
||||||
refs[i].prop("disabled",false);
|
refs[i].prop("disabled",false);
|
||||||
@ -207,6 +241,7 @@ $(document).ready(function(){
|
|||||||
button_save = $('#btn_save');
|
button_save = $('#btn_save');
|
||||||
button_load = $('#btn_load');
|
button_load = $('#btn_load');
|
||||||
button_settings = $('#btn_settings');
|
button_settings = $('#btn_settings');
|
||||||
|
button_format = $('#btn_format');
|
||||||
button_send = $('#btnsend');
|
button_send = $('#btnsend');
|
||||||
button_actedit = $('#btn_actedit');
|
button_actedit = $('#btn_actedit');
|
||||||
button_actmem = $('#btn_actmem');
|
button_actmem = $('#btn_actmem');
|
||||||
@ -217,6 +252,7 @@ $(document).ready(function(){
|
|||||||
input_text = $('#input_text');
|
input_text = $('#input_text');
|
||||||
message_text = $('#messagefield');
|
message_text = $('#messagefield');
|
||||||
settings_menu = $("#settingsmenu");
|
settings_menu = $("#settingsmenu");
|
||||||
|
format_menu = $('#formatmenu');
|
||||||
anote_menu = $('#anoterowcontainer');
|
anote_menu = $('#anoterowcontainer');
|
||||||
anote_input = $('#anoteinput');
|
anote_input = $('#anoteinput');
|
||||||
anote_labelcur = $('#anotecur');
|
anote_labelcur = $('#anotecur');
|
||||||
@ -233,6 +269,7 @@ $(document).ready(function(){
|
|||||||
connect_status.addClass("color_green");
|
connect_status.addClass("color_green");
|
||||||
// Reset Settings Menu
|
// Reset Settings Menu
|
||||||
settings_menu.html("");
|
settings_menu.html("");
|
||||||
|
format_menu.html("");
|
||||||
} else if(msg.cmd == "updatescreen") {
|
} else if(msg.cmd == "updatescreen") {
|
||||||
// Send game content to Game Screen
|
// Send game content to Game Screen
|
||||||
game_text.html(msg.data);
|
game_text.html(msg.data);
|
||||||
@ -340,6 +377,24 @@ $(document).ready(function(){
|
|||||||
} else if(msg.cmd == "addsetting") {
|
} else if(msg.cmd == "addsetting") {
|
||||||
// Add setting controls
|
// Add setting controls
|
||||||
addSetting(msg.data);
|
addSetting(msg.data);
|
||||||
|
} else if(msg.cmd == "addformat") {
|
||||||
|
// Add setting controls
|
||||||
|
addFormat(msg.data);
|
||||||
|
} else if(msg.cmd == "updatefrmttriminc") {
|
||||||
|
// Update toggle state
|
||||||
|
$("#frmttriminc").prop('checked', msg.data).change()
|
||||||
|
} else if(msg.cmd == "updatefrmtrmblln") {
|
||||||
|
// Update toggle state
|
||||||
|
$("#frmtrmblln").prop('checked', msg.data).change()
|
||||||
|
} else if(msg.cmd == "updatefrmtrmspch") {
|
||||||
|
// Update toggle state
|
||||||
|
$("#frmtrmspch").prop('checked', msg.data).change()
|
||||||
|
} else if(msg.cmd == "updatefrmtadsnsp") {
|
||||||
|
// Update toggle state
|
||||||
|
$("#frmtadsnsp").prop('checked', msg.data).change()
|
||||||
|
} else if(msg.cmd == "allowtoggle") {
|
||||||
|
// Allow toggle change states to propagate
|
||||||
|
allowtoggle = msg.data;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -390,6 +445,10 @@ $(document).ready(function(){
|
|||||||
$('#settingsmenu').slideToggle("slow");
|
$('#settingsmenu').slideToggle("slow");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
button_format.on("click", function(ev) {
|
||||||
|
$('#formatmenu').slideToggle("slow");
|
||||||
|
});
|
||||||
|
|
||||||
$("#btn_savesettings").on("click", function(ev) {
|
$("#btn_savesettings").on("click", function(ev) {
|
||||||
socket.send({'cmd': 'savesettings', 'data': ''});
|
socket.send({'cmd': 'savesettings', 'data': ''});
|
||||||
});
|
});
|
||||||
|
28
static/bootstrap-toggle.min.css
vendored
Normal file
28
static/bootstrap-toggle.min.css
vendored
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
/*! ========================================================================
|
||||||
|
* Bootstrap Toggle: bootstrap-toggle.css v2.2.0
|
||||||
|
* http://www.bootstraptoggle.com
|
||||||
|
* ========================================================================
|
||||||
|
* Copyright 2014 Min Hur, The New York Times Company
|
||||||
|
* Licensed under MIT
|
||||||
|
* ======================================================================== */
|
||||||
|
.checkbox label .toggle,.checkbox-inline .toggle{margin-left:-20px;margin-right:5px}
|
||||||
|
.toggle{position:relative;overflow:hidden}
|
||||||
|
.toggle input[type=checkbox]{display:none}
|
||||||
|
.toggle-group{position:absolute;width:200%;top:0;bottom:0;left:0;transition:left .35s;-webkit-transition:left .35s;-moz-user-select:none;-webkit-user-select:none}
|
||||||
|
.toggle.off .toggle-group{left:-100%}
|
||||||
|
.toggle-on{position:absolute;top:0;bottom:0;left:0;right:50%;margin:0;border:0;border-radius:0}
|
||||||
|
.toggle-off{position:absolute;top:0;bottom:0;left:50%;right:0;margin:0;border:0;border-radius:0}
|
||||||
|
.toggle-handle{position:relative;margin:0 auto;padding-top:0;padding-bottom:0;height:100%;width:0;border-width:0 1px}
|
||||||
|
.toggle.btn{min-width:59px;min-height:34px}
|
||||||
|
.toggle-on.btn{padding-right:24px}
|
||||||
|
.toggle-off.btn{padding-left:24px}
|
||||||
|
.toggle.btn-lg{min-width:79px;min-height:45px}
|
||||||
|
.toggle-on.btn-lg{padding-right:31px}
|
||||||
|
.toggle-off.btn-lg{padding-left:31px}
|
||||||
|
.toggle-handle.btn-lg{width:40px}
|
||||||
|
.toggle.btn-sm{min-width:50px;min-height:30px}
|
||||||
|
.toggle-on.btn-sm{padding-right:20px}
|
||||||
|
.toggle-off.btn-sm{padding-left:20px}
|
||||||
|
.toggle.btn-xs{min-width:35px;min-height:22px}
|
||||||
|
.toggle-on.btn-xs{padding-right:12px}
|
||||||
|
.toggle-off.btn-xs{padding-left:12px}
|
9
static/bootstrap-toggle.min.js
vendored
Normal file
9
static/bootstrap-toggle.min.js
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
/*! ========================================================================
|
||||||
|
* Bootstrap Toggle: bootstrap-toggle.js v2.2.0
|
||||||
|
* http://www.bootstraptoggle.com
|
||||||
|
* ========================================================================
|
||||||
|
* Copyright 2014 Min Hur, The New York Times Company
|
||||||
|
* Licensed under MIT
|
||||||
|
* ======================================================================== */
|
||||||
|
+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.toggle"),f="object"==typeof b&&b;e||d.data("bs.toggle",e=new c(this,f)),"string"==typeof b&&e[b]&&e[b]()})}var c=function(b,c){this.$element=a(b),this.options=a.extend({},this.defaults(),c),this.render()};c.VERSION="2.2.0",c.DEFAULTS={on:"On",off:"Off",onstyle:"primary",offstyle:"default",size:"normal",style:"",width:null,height:null},c.prototype.defaults=function(){return{on:this.$element.attr("data-on")||c.DEFAULTS.on,off:this.$element.attr("data-off")||c.DEFAULTS.off,onstyle:this.$element.attr("data-onstyle")||c.DEFAULTS.onstyle,offstyle:this.$element.attr("data-offstyle")||c.DEFAULTS.offstyle,size:this.$element.attr("data-size")||c.DEFAULTS.size,style:this.$element.attr("data-style")||c.DEFAULTS.style,width:this.$element.attr("data-width")||c.DEFAULTS.width,height:this.$element.attr("data-height")||c.DEFAULTS.height}},c.prototype.render=function(){this._onstyle="btn-"+this.options.onstyle,this._offstyle="btn-"+this.options.offstyle;var b="large"===this.options.size?"btn-lg":"small"===this.options.size?"btn-sm":"mini"===this.options.size?"btn-xs":"",c=a('<label class="btn">').html(this.options.on).addClass(this._onstyle+" "+b),d=a('<label class="btn">').html(this.options.off).addClass(this._offstyle+" "+b+" active"),e=a('<span class="toggle-handle btn btn-default">').addClass(b),f=a('<div class="toggle-group">').append(c,d,e),g=a('<div class="toggle btn" data-toggle="toggle">').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.outerWidth(),d.outerWidth())+e.outerWidth()/2,i=this.options.height||Math.max(c.outerHeight(),d.outerHeight());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),void(a||this.trigger()))},c.prototype.off=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),void(a||this.trigger()))},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){var c=a(this).find("input[type=checkbox]");c.bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
|
||||||
|
//# sourceMappingURL=bootstrap-toggle.min.js.map
|
@ -22,6 +22,12 @@ chunk {
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#formatmenu {
|
||||||
|
display:none;
|
||||||
|
background-color: #295071;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
#connectstatusdiv {
|
#connectstatusdiv {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
@ -99,7 +105,7 @@ chunk {
|
|||||||
|
|
||||||
#waitanim {
|
#waitanim {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
top:10px;
|
top:18px;
|
||||||
left:5px;
|
left:5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,6 +172,26 @@ chunk {
|
|||||||
color: #ff0000;
|
color: #ff0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.formatcolumn {
|
||||||
|
width: 25%;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formatcolumn > div:first-child {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.formatrow {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.formatlabel {
|
||||||
|
color: #ffffff;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
@ -8,8 +8,10 @@
|
|||||||
<script src="static/socket.io.min.js"></script>
|
<script src="static/socket.io.min.js"></script>
|
||||||
<script src="static/application.js"></script>
|
<script src="static/application.js"></script>
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
|
||||||
|
<script src="static/bootstrap-toggle.min.js"></script>
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
|
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
|
||||||
|
<link rel="stylesheet" href="static/bootstrap-toggle.min.css">
|
||||||
<link rel="stylesheet" href="static/custom.css">
|
<link rel="stylesheet" href="static/custom.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@ -22,6 +24,7 @@
|
|||||||
<button type="button" class="btn btn-primary" id="btn_load">Load</button>
|
<button type="button" class="btn btn-primary" id="btn_load">Load</button>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<button type="button" class="btn btn-primary" id="btn_settings">Settings</button>
|
<button type="button" class="btn btn-primary" id="btn_settings">Settings</button>
|
||||||
|
<button type="button" class="btn btn-primary" id="btn_format">Formatting</button>
|
||||||
</div>
|
</div>
|
||||||
<div id="connectstatusdiv">
|
<div id="connectstatusdiv">
|
||||||
<span id="connectstatus" class="color_orange">Waiting for connection...</span>
|
<span id="connectstatus" class="color_orange">Waiting for connection...</span>
|
||||||
@ -30,6 +33,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="row" id="settingsmenu">
|
<div class="row" id="settingsmenu">
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row" id="formatmenu">
|
||||||
|
</div>
|
||||||
<div class="row" id="gamescreen">
|
<div class="row" id="gamescreen">
|
||||||
<span id="gametext">...</span>
|
<span id="gametext">...</span>
|
||||||
</div>
|
</div>
|
||||||
|
66
utils.py
66
utils.py
@ -1,5 +1,10 @@
|
|||||||
from threading import Timer
|
from threading import Timer
|
||||||
|
import re
|
||||||
|
|
||||||
|
#==================================================================#
|
||||||
|
# Decorator to prevent a function's actions from being run until
|
||||||
|
# at least x seconds have passed without the function being called
|
||||||
|
#==================================================================#
|
||||||
def debounce(wait):
|
def debounce(wait):
|
||||||
def decorator(fun):
|
def decorator(fun):
|
||||||
def debounced(*args, **kwargs):
|
def debounced(*args, **kwargs):
|
||||||
@ -16,4 +21,63 @@ def debounce(wait):
|
|||||||
|
|
||||||
return debounced
|
return debounced
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
#==================================================================#
|
||||||
|
# Replace fancy quotes and apostrope's with standard ones
|
||||||
|
#==================================================================#
|
||||||
|
def fixquotes(txt):
|
||||||
|
txt = txt.replace("“", '"')
|
||||||
|
txt = txt.replace("”", '"')
|
||||||
|
txt = txt.replace("’", "'")
|
||||||
|
txt = txt.replace("`", "'")
|
||||||
|
return txt
|
||||||
|
|
||||||
|
#==================================================================#
|
||||||
|
#
|
||||||
|
#==================================================================#
|
||||||
|
def trimincompletesentence(txt):
|
||||||
|
# Cache length of text
|
||||||
|
ln = len(txt)
|
||||||
|
# Find last instance of punctuation (Borrowed from Clover-Edition by cloveranon)
|
||||||
|
lastpunc = max(txt.rfind("."), txt.rfind("!"), txt.rfind("?"))
|
||||||
|
# Is this the end of a quote?
|
||||||
|
if(lastpunc < ln-1):
|
||||||
|
if(txt[lastpunc+1] == '"'):
|
||||||
|
lastpunc = lastpunc + 1
|
||||||
|
if(lastpunc >= 0):
|
||||||
|
txt = txt[:lastpunc+1]
|
||||||
|
return txt
|
||||||
|
|
||||||
|
#==================================================================#
|
||||||
|
#
|
||||||
|
#==================================================================#
|
||||||
|
def replaceblanklines(txt):
|
||||||
|
txt = txt.replace("\n\n", "\n")
|
||||||
|
return txt
|
||||||
|
|
||||||
|
#==================================================================#
|
||||||
|
#
|
||||||
|
#==================================================================#
|
||||||
|
def removespecialchars(txt):
|
||||||
|
txt = re.sub(r"[#/@%<>{}+=~|\^]", "", txt)
|
||||||
|
return txt
|
||||||
|
|
||||||
|
#==================================================================#
|
||||||
|
# If the next action follows a sentence closure, add a space
|
||||||
|
#==================================================================#
|
||||||
|
def addsentencespacing(txt, acts):
|
||||||
|
# Get last character of last action
|
||||||
|
lastchar = acts[-1][-1]
|
||||||
|
if(lastchar == "." or lastchar == "!" or lastchar == "?"):
|
||||||
|
txt = " " + txt
|
||||||
|
return txt
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user