mirror of
https://github.com/KoboldAI/KoboldAI-Client.git
synced 2025-06-05 21:59:24 +02:00
Work on commentators
This commit is contained in:
29
aiserver.py
29
aiserver.py
@@ -7,6 +7,7 @@
|
||||
|
||||
# External packages
|
||||
from dataclasses import dataclass
|
||||
import random
|
||||
import shutil
|
||||
import eventlet
|
||||
eventlet.monkey_patch(all=True, thread=False, os=False)
|
||||
@@ -6261,6 +6262,8 @@ def generate(txt, minimum, maximum, found_entries=None):
|
||||
gc.collect()
|
||||
torch.cuda.empty_cache()
|
||||
|
||||
maybe_review_story()
|
||||
|
||||
set_aibusy(0)
|
||||
|
||||
#==================================================================#
|
||||
@@ -9930,13 +9933,19 @@ def UI_2_refresh_auto_memory(data):
|
||||
#==================================================================#
|
||||
# Story review zero-shot
|
||||
#==================================================================#
|
||||
@socketio.on("story_review")
|
||||
@logger.catch
|
||||
def UI_2_story_review(data):
|
||||
who = data["who"]
|
||||
template = data.get("template", "\n\n%s's thoughts on this situation:\n\"")
|
||||
prompt = template % who
|
||||
logger.info(prompt)
|
||||
def maybe_review_story():
|
||||
if not (
|
||||
koboldai_vars.commentary_characters
|
||||
and koboldai_vars.commentary_chance
|
||||
and koboldai_vars.commentary_enabled
|
||||
):
|
||||
return
|
||||
|
||||
if random.randrange(100) > koboldai_vars.commentary_chance:
|
||||
return
|
||||
|
||||
speaker_id, speaker_name = random.choice(list(koboldai_vars.commentary_characters.items()))
|
||||
prompt = "\n\n%s's thoughts on what just happened in this story: \"" % speaker_name
|
||||
|
||||
context = koboldai_vars.calc_ai_text(
|
||||
prompt,
|
||||
@@ -9949,10 +9958,8 @@ def UI_2_story_review(data):
|
||||
max_new=30,
|
||||
).decoded[0]
|
||||
|
||||
|
||||
out_text = re.sub(r"[\s\(\)]", " ", out_text)
|
||||
# Beware contractions!
|
||||
# out_text = re.sub(r"[\s!\.\?]'", " ", out_text)
|
||||
|
||||
while " " in out_text:
|
||||
out_text = out_text.replace(" ", " ")
|
||||
|
||||
@@ -9961,7 +9968,7 @@ def UI_2_story_review(data):
|
||||
|
||||
out_text = out_text.strip()
|
||||
out_text = utils.trimincompletesentence(out_text)
|
||||
emit("show_story_review", {"who": who, "review": out_text})
|
||||
emit("show_story_review", {"who": speaker_name, "review": out_text, "id": speaker_id})
|
||||
|
||||
#==================================================================#
|
||||
# Get next 100 actions for infinate scroll
|
||||
|
@@ -3,7 +3,7 @@ from dataclasses import dataclass
|
||||
import importlib
|
||||
import os, re, time, threading, json, pickle, base64, copy, tqdm, datetime, sys
|
||||
import shutil
|
||||
from typing import Union
|
||||
from typing import List, Union
|
||||
from io import BytesIO
|
||||
from flask import has_request_context, session
|
||||
from flask_socketio import SocketIO, join_room, leave_room
|
||||
@@ -898,6 +898,12 @@ class story_settings(settings):
|
||||
self.memory_attn_bias = 1
|
||||
self.an_attn_bias = 1
|
||||
self.chat_style = 0
|
||||
|
||||
# In percent!!!
|
||||
self.commentary_chance = 0
|
||||
# id: {name}
|
||||
self.commentary_characters = {}
|
||||
self.commentary_enabled = False
|
||||
|
||||
self.save_paths = SavePaths(os.path.join("stories", self.story_name or "Untitled"))
|
||||
|
||||
@@ -2443,6 +2449,10 @@ class SavePaths:
|
||||
@property
|
||||
def generated_images(self) -> str:
|
||||
return os.path.join(self.base, "generated_images")
|
||||
|
||||
@property
|
||||
def commentator_pictures(self) -> str:
|
||||
return os.path.join(self.base, "commentator_pictures")
|
||||
|
||||
default_rand_range = [0.1, 1, 2]
|
||||
default_creativity_range = [0.8, 1]
|
||||
|
@@ -183,6 +183,22 @@ border-top-right-radius: var(--tabs_rounding);
|
||||
}
|
||||
|
||||
|
||||
.dynamic-setting-container {
|
||||
background-color: var(--setting_background);
|
||||
color: var(--setting_text);
|
||||
border-radius: var(--radius_settings_background);
|
||||
padding: 2px;
|
||||
margin-bottom: 5px;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.dynamic-setting-bounds, .dynamic-setting-top {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
|
||||
.setting_container {
|
||||
display: grid;
|
||||
@@ -788,7 +804,7 @@ border-top-right-radius: var(--tabs_rounding);
|
||||
}
|
||||
|
||||
/* Tweaks */
|
||||
.tweak-container {
|
||||
.wide-boolean-setting {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@@ -1188,10 +1204,11 @@ body {
|
||||
margin-left: var(--setting_menu_closed_width_no_pins_width);
|
||||
margin-right: var(--flyout_menu_closed_width);
|
||||
grid-template-areas: "menuicon gamescreen options lefticon"
|
||||
"menuicon review review lefticon"
|
||||
"menuicon theme theme lefticon"
|
||||
"menuicon inputrow inputrow lefticon";
|
||||
grid-template-columns: 30px auto 30% 30px;
|
||||
grid-template-rows: auto min-content 100px;
|
||||
grid-template-rows: auto min-content min-content 100px;
|
||||
}
|
||||
.main-grid[option_length="0"][model_numseqs="1"] {
|
||||
grid-template-columns: 30px auto 0px 30px;
|
||||
@@ -2810,6 +2827,79 @@ body {
|
||||
|
||||
.genre-inner > .x:hover { opacity: 1; }
|
||||
|
||||
/* Story Commentary */
|
||||
|
||||
#story-review {
|
||||
grid-area: review;
|
||||
min-height: 52px;
|
||||
padding: 10px;
|
||||
background-color: var(--gamescreen_background);
|
||||
margin: 10px 0px;
|
||||
}
|
||||
|
||||
#story-review-img {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
object-fit: cover;
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#story-review-author {
|
||||
display: block;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#story-commentary-settings { width: 100%; }
|
||||
|
||||
.story-commentary-character {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.story-commentary-character > .image-container {
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: var(--setting_background);
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.story-commentary-character > .image-container > img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.story-commentary-character > .name {
|
||||
border: none;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.story-commentary-character > .close {
|
||||
float: right;
|
||||
color: white !important;
|
||||
transform: scale(1) !important;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
#story-commentary-settings > .add {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
transform: scale(1) !important;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
#story-commentary-settings > p {
|
||||
font-size: calc(1.1em + var(--font_size_adjustment));
|
||||
}
|
||||
|
||||
/*---------------------------------- Global ------------------------------------------------*/
|
||||
.hidden {
|
||||
@@ -3045,6 +3135,7 @@ h2 .material-icons-outlined {
|
||||
.help_text,
|
||||
.sample_order,
|
||||
.table-header-label,
|
||||
.disabled,
|
||||
.noselect {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
|
@@ -34,7 +34,6 @@ socket.on("log_message", function(data){process_log_message(data);});
|
||||
socket.on("debug_message", function(data){console.log(data);});
|
||||
socket.on("scratchpad_response", recieveScratchpadResponse);
|
||||
socket.on("show_error_notification", function(data) { reportError(data.title, data.text) });
|
||||
socket.on("show_story_review", showStoryReview);
|
||||
//socket.onAny(function(event_name, data) {console.log({"event": event_name, "class": data.classname, "data": data});});
|
||||
|
||||
// Must be done before any elements are made; we track their changes.
|
||||
@@ -69,6 +68,7 @@ var actions_data = {};
|
||||
var setup_wi_toggles = [];
|
||||
var scroll_trigger_element = undefined; //undefined means not currently set. If set to null, it's disabled.
|
||||
var drag_id = null;
|
||||
var story_commentary_characters = {};
|
||||
const on_colab = $el("#on_colab").textContent == "true";
|
||||
|
||||
// Each entry into this array should be an object that looks like:
|
||||
@@ -141,9 +141,9 @@ let context_menu_cache = [];
|
||||
const shortcuts = [
|
||||
{key: "s", desc: "Save Story", func: save_story},
|
||||
{key: "o", desc: "Open Story", func: load_story_list},
|
||||
{key: "z", desc: "Undoes last story action", func: () => socket.emit("back", {}), criteria: canNavigateStoryHistory},
|
||||
{key: "y", desc: "Redoes last story action", func: () => socket.emit("redo", {}), criteria: canNavigateStoryHistory},
|
||||
{key: "e", desc: "Retries last story action", func: () => socket.emit("retry", {}), criteria: canNavigateStoryHistory},
|
||||
{key: "z", desc: "Undoes last story action", func: storyBack, criteria: canNavigateStoryHistory},
|
||||
{key: "y", desc: "Redoes last story action", func: storyRedo, criteria: canNavigateStoryHistory},
|
||||
{key: "e", desc: "Retries last story action", func: storyRetry, criteria: canNavigateStoryHistory},
|
||||
{key: "m", desc: "Focuses Memory", func: () => focusEl("#memory")},
|
||||
{key: "u", desc: "Focuses Author's Note", func: () => focusEl("#authors_notes")}, // CTRL-N is reserved :^(
|
||||
{key: "g", desc: "Focuses game text", func: () => focusEl("#input_text")},
|
||||
@@ -221,6 +221,34 @@ function disconnect() {
|
||||
document.getElementById("disconnect_message").classList.remove("hidden");
|
||||
}
|
||||
|
||||
function storySubmit() {
|
||||
disruptStoryState();
|
||||
socket.emit('submit', {'data': document.getElementById('input_text').value, 'theme': document.getElementById('themetext').value});
|
||||
document.getElementById('input_text').value = '';
|
||||
document.getElementById('themetext').value = '';
|
||||
}
|
||||
|
||||
function storyBack() {
|
||||
disruptStoryState();
|
||||
socket.emit('back', {});
|
||||
}
|
||||
|
||||
function storyRedo() {
|
||||
disruptStoryState();
|
||||
socket.emit('redo', {});
|
||||
}
|
||||
|
||||
function storyRetry() {
|
||||
disruptStoryState();
|
||||
socket.emit('retry', {});
|
||||
}
|
||||
|
||||
function disruptStoryState() {
|
||||
// This function is responsible for wiping things away which are sensitive
|
||||
// to story state
|
||||
$el("#story-review").classList.add("hidden");
|
||||
}
|
||||
|
||||
function reset_story() {
|
||||
//console.log("Resetting story");
|
||||
clearTimeout(calc_token_usage_timeout);
|
||||
@@ -3117,7 +3145,7 @@ function retry_from_here() {
|
||||
action_count = parseInt(document.getElementById("action_count").textContent);
|
||||
//console.log(chunk);
|
||||
for (let i = 0; i < (action_count-chunk); i++) {
|
||||
socket.emit('back', {});
|
||||
storyBack();
|
||||
}
|
||||
socket.emit('submit', {'data': "", 'theme': ""});
|
||||
document.getElementById('input_text').value = '';
|
||||
@@ -6683,13 +6711,178 @@ function imgGenRetry() {
|
||||
|
||||
})();
|
||||
|
||||
function requestStoryReview(who, template=null) {
|
||||
let data = {who: who};
|
||||
if (template) data.template = template;
|
||||
socket.emit("story_review", data);
|
||||
(function() {
|
||||
const characterContainer = $el(".story-commentary-characters");
|
||||
const settingsContainer = $el("#story-commentary-settings");
|
||||
const storyReviewImg = $el("#story-review-img");
|
||||
|
||||
function syncCommentatorCards() {
|
||||
story_commentary_characters = {};
|
||||
for (const card of document.getElementsByClassName("story-commentary-character")) {
|
||||
let idString = card.getAttribute("commentator-id");
|
||||
story_commentary_characters[idString] = card.querySelector(".name").value;
|
||||
}
|
||||
|
||||
socket.emit("var_change", {
|
||||
ID: "story_commentary_characters",
|
||||
value: story_commentary_characters
|
||||
});
|
||||
}
|
||||
|
||||
sync_hooks.push({
|
||||
class: "story",
|
||||
name: "commentary_characters",
|
||||
func: function(commentators) {
|
||||
$(".story-commentary-character").remove();
|
||||
for (const [idString, name] of Object.entries(commentators)) {
|
||||
makeCommentatorCard(idString, name)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function makeCommentatorCard(idString=null, name=null) {
|
||||
|
||||
// String due to JS array keys and DOM attributes being strings. Sux!
|
||||
while (!idString || $el(`[commentator-id="${idString}"`)) {
|
||||
idString = Math.floor(Math.random() * 1_000_000_000).toString();
|
||||
}
|
||||
|
||||
let card = $e("div", characterContainer, {
|
||||
classes: ["story-commentary-character"],
|
||||
"commentator-id": idString,
|
||||
});
|
||||
let imageContainer = $e("div", card, {classes: ["image-container"]});
|
||||
let placeholderImage = $e("span", imageContainer, {
|
||||
classes: ["material-icons-outlined"],
|
||||
tooltip: "Upload a picture for this character",
|
||||
innerText: "add_a_photo"
|
||||
});
|
||||
let image = $e("img", imageContainer, {
|
||||
classes: ["hidden"],
|
||||
src: `/get_commentator_picture/${idString}`
|
||||
});
|
||||
|
||||
image.addEventListener("load", function() {
|
||||
image.classList.remove("hidden");
|
||||
placeholderImage.classList.add("hidden");
|
||||
});
|
||||
|
||||
let input = $e("input", card, {classes: ["name"], placeholder: "Character name"});
|
||||
if (name) input.value = name;
|
||||
input.addEventListener("change", syncCommentatorCards);
|
||||
|
||||
let deleteButton = $e("span", card, {
|
||||
classes: ["close", "material-icons-outlined"],
|
||||
tooltip: "Upload a picture for this character",
|
||||
innerText: "clear"
|
||||
});
|
||||
deleteButton.addEventListener("click", function() {
|
||||
card.remove();
|
||||
syncCommentatorCards();
|
||||
});
|
||||
|
||||
const imgInput = $e("input", null, {type: "file", accept: "image/png,image/x-png,image/gif,image/jpeg"});
|
||||
imgInput.addEventListener("change", async function() {
|
||||
const file = imgInput.files[0];
|
||||
if (file.type.split("/")[0] !== "image") {
|
||||
reportError("Unable to upload commentary image", `File type ${file.type} is not a compatible image type!`)
|
||||
return;
|
||||
}
|
||||
|
||||
let objectUrl = URL.createObjectURL(file);
|
||||
placeholderImage.classList.add("hidden");
|
||||
image.src = objectUrl;
|
||||
image.classList.remove("hidden");
|
||||
|
||||
let r = await fetch(`/set_commentator_picture/${idString}`, {
|
||||
method: "POST",
|
||||
body: file
|
||||
});
|
||||
});
|
||||
|
||||
imageContainer.addEventListener("click", function() {
|
||||
imgInput.click();
|
||||
});
|
||||
|
||||
characterContainer.scrollIntoView();
|
||||
}
|
||||
|
||||
$el("#story-commentary-settings > .add").addEventListener("click", () => makeCommentatorCard());
|
||||
|
||||
async function showStoryReview(data) {
|
||||
console.log(`${data.who}: ${data.review}`)
|
||||
storyReviewImg.src = `/get_commentator_picture/${data.id}`;
|
||||
$el("#story-review-author").innerText = data.who;
|
||||
$el("#story-review-content").innerText = data.review;
|
||||
|
||||
$el("#story-review").classList.remove("hidden");
|
||||
}
|
||||
socket.on("show_story_review", showStoryReview);
|
||||
|
||||
let x = $el("#story-commentary-enable").querySelector("input")
|
||||
console.log(x)
|
||||
|
||||
// Bootstrap toggle requires jQuery for events
|
||||
$($el("#story-commentary-enable").querySelector("input")).change(function() {
|
||||
socket.emit("var_change", {
|
||||
ID: "story_commentary_enabled",
|
||||
value: this.checked
|
||||
});
|
||||
});
|
||||
|
||||
sync_hooks.push({
|
||||
class: "story",
|
||||
name: "commentary_enabled",
|
||||
func: function(commentaryEnabled) {
|
||||
if (commentaryEnabled) {
|
||||
settingsContainer.classList.remove("disabled");
|
||||
} else {
|
||||
settingsContainer.classList.add("disabled");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
storyReviewImg.addEventListener("error", function() {
|
||||
if (storyReviewImg.src === "/static/default_pfp.png") {
|
||||
// Something has gone horribly wrong
|
||||
return;
|
||||
}
|
||||
storyReviewImg.src = "/static/default_pfp.png";
|
||||
});
|
||||
|
||||
$el("#story-review-img").addEventListener
|
||||
})();
|
||||
|
||||
for (const el of document.querySelectorAll("[sync-var]")) {
|
||||
let varName = el.getAttribute("sync-var");
|
||||
|
||||
el.addEventListener("change", function() {
|
||||
sync_to_server(this);
|
||||
});
|
||||
|
||||
const proxy = $el(`[sync-proxy-host="${varName}"]`);
|
||||
if (proxy) {
|
||||
el.addEventListener("input", function() {
|
||||
proxy.value = this.value;
|
||||
});
|
||||
}
|
||||
|
||||
let slug = varName.replaceAll(".", "_");
|
||||
el.classList.add("var_sync_" + slug);
|
||||
}
|
||||
|
||||
function showStoryReview(data) {
|
||||
console.log(`${data.who}: ${data.review}`)
|
||||
for (const proxy of document.querySelectorAll("[sync-proxy-host]")) {
|
||||
let varName = proxy.getAttribute("sync-proxy-host");
|
||||
const hostEl = $el(`[sync-var="${varName}"]`);
|
||||
if (!hostEl) {
|
||||
throw Error(`Bad sync proxy host ${varName}`)
|
||||
}
|
||||
|
||||
proxy.addEventListener("change", function() {
|
||||
hostEl.value = this.value;
|
||||
socket.emit("var_change", {
|
||||
ID: varName.replaceAll(".", "_"),
|
||||
value: this.value
|
||||
});
|
||||
});
|
||||
}
|
@@ -60,6 +60,13 @@
|
||||
<div id="action_count" class="var_sync_actions_Action_Count hidden"></div>
|
||||
<div id="Select Options" class="sequence_area"></div>
|
||||
|
||||
<!-- Story Review -->
|
||||
<div id="story-review" class="hidden">
|
||||
<img id="story-review-img">
|
||||
<span id="story-review-author">Bob McBobhead</span>
|
||||
<span id="story-review-content">Wow, this is a great story. And I mean that. It's positively stelar.</span>
|
||||
</div>
|
||||
|
||||
<!------------ Theme Area--------------------->
|
||||
<div class="themerow" id="themerow">
|
||||
<div class="tabrow nomenu_icon">
|
||||
@@ -102,13 +109,11 @@
|
||||
<button type="button" class="btn action_button" style="width: 30px; padding: 0px;" onclick='play_pause_tts()' aria-label="play"><span id="play_tts" class="material-icons-outlined" style="font-size: 1.4em;">play_arrow</span></button>
|
||||
<button type="button" class="btn action_button" style="width: 30px; padding: 0px;" onclick='stop_tts()' aria-label="play"><span id="stop_tts" class="material-icons-outlined" style="font-size: 1.4em;">stop</span></button>
|
||||
</span>
|
||||
<button type="button" class="btn action_button submit var_sync_alt_system_aibusy" system_aibusy=False id="btnsubmit"
|
||||
onclick="socket.emit('submit', {'data': document.getElementById('input_text').value, 'theme': document.getElementById('themetext').value});document.getElementById('input_text').value = '';document.getElementById('themetext').value = '';"
|
||||
>Submit</button>
|
||||
<button type="button" class="btn action_button submit var_sync_alt_system_aibusy" system_aibusy=False id="btnsubmit" onclick="storySubmit();">Submit</button>
|
||||
<button type="button" class="btn action_button submited var_sync_alt_system_aibusy" system_aibusy=False id="btnsent"><img id="thinking" src="static/thinking.gif" class="force_center" onclick="socket.emit('abort','');"></button>
|
||||
<button type="button" class="btn action_button back" onclick="socket.emit('back', {});" aria-label="undo"><span class="material-icons-outlined" style="font-size: 1.4em;">replay</span></button>
|
||||
<button type="button" class="btn action_button redo" onclick="socket.emit('redo', {});" aria-label="redo"><span class="material-icons-outlined" style="font-size: 1.4em;">arrow_forward</span></button>
|
||||
<button type="button" class="btn action_button retry" onclick="socket.emit('retry', {});" aria-label="retry"><span class="material-icons-outlined" style="font-size: 1.4em;">autorenew</span></button>
|
||||
<button type="button" class="btn action_button back" onclick="storyBack();" aria-label="undo"><span class="material-icons-outlined" style="font-size: 1.4em;">replay</span></button>
|
||||
<button type="button" class="btn action_button redo" onclick="storyRedo();" aria-label="redo"><span class="material-icons-outlined" style="font-size: 1.4em;">arrow_forward</span></button>
|
||||
<button type="button" class="btn action_button retry" onclick="storyRetry();" aria-label="retry"><span class="material-icons-outlined" style="font-size: 1.4em;">autorenew</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@@ -239,7 +239,7 @@
|
||||
<div class="collapsable_header" onclick="toggle_setting_category(this);">
|
||||
<h4 style="width:var(--flyout_menu_width);"><span class="material-icons-outlined cursor">expand_more</span> Biasing</h4>
|
||||
</div>
|
||||
<div id="biasing"class="biasing" ui_level=1>
|
||||
<div id="biasing" class="biasing" ui_level=1>
|
||||
<div class="help_text">Influence the likelihood for the AI to output certain phrases.</div>
|
||||
<div class="bias_header">
|
||||
<div class="bias_header_phrase">Phrase</div>
|
||||
@@ -250,6 +250,41 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Story Review Bot -->
|
||||
<div class="collapsable_header" onclick="toggle_setting_category(this);">
|
||||
<h4 style="width: var(--flyout_menu_width);"><span class="material-icons-outlined cursor">expand_more</span> Story Commentary</h4>
|
||||
</div>
|
||||
<div id="story-commentary" class="story-commentary setting_tile_area" ui_level=1>
|
||||
<div class="help_text">Allow custom characters to comment on the story.</div>
|
||||
<div id="story-commentary-enable" class="wide-boolean-setting">
|
||||
<span>Enable Story Commentary</span>
|
||||
<input type=checkbox class="setting_item_input" data-size="mini" data-onstyle="success" data-toggle="toggle">
|
||||
</div>
|
||||
|
||||
<div id="story-commentary-settings">
|
||||
<div class="dynamic-setting-container">
|
||||
<div class="dynamic-setting-top">
|
||||
<span class="setting_label"><span>Commentary Chance Percent</span></span>
|
||||
<input sync-proxy-host="story.commentary_chance" class="setting_value" inputmode="numeric" value="0">
|
||||
</div>
|
||||
|
||||
<span class="setting_item">
|
||||
<input type="range" sync-var="story.commentary_chance" class="setting_item_input" min="0" max="100" step="1" value="0">
|
||||
</span>
|
||||
|
||||
<div class="dynamic-setting-bounds">
|
||||
<span class="setting_minlabel">0</span>
|
||||
<span class="setting_maxlabel">100</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Commentators</p>
|
||||
<div class="story-commentary-characters"></div>
|
||||
<span class="add material-icons-outlined cursor" tooltip="Add Character">add</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="setting_menu_interface" class="hidden settings_category_area tab-target tab-target-settings">
|
||||
<div class="collapsable_header" onclick="toggle_setting_category(this);">
|
||||
@@ -427,19 +462,19 @@
|
||||
</div>
|
||||
<div class="setting_tile_area hidden" id="Tweaks">
|
||||
<div class="help_text">Small UI changes that can be mixed and matched.</div>
|
||||
<div class="tweak-container" tweak-path="hide-timing">
|
||||
<div class="wide-boolean-setting tweak-container" tweak-path="hide-timing">
|
||||
<span>Hide timing information</span>
|
||||
<input type=checkbox class="setting_item_input" data-size="mini" data-onstyle="success" data-toggle="toggle">
|
||||
</div>
|
||||
<div class="tweak-container" tweak-path="hide-token-bar">
|
||||
<div class="wide-boolean-setting tweak-container" tweak-path="hide-token-bar">
|
||||
<span>Hide token bar</span>
|
||||
<input type=checkbox class="setting_item_input" data-size="mini" data-onstyle="success" data-toggle="toggle">
|
||||
</div>
|
||||
<div class="tweak-container" tweak-path="hide-max-length">
|
||||
<div class="wide-boolean-setting tweak-container" tweak-path="hide-max-length">
|
||||
<span>Hide text highlighting</span>
|
||||
<input type=checkbox class="setting_item_input" data-size="mini" data-onstyle="success" data-toggle="toggle">
|
||||
</div>
|
||||
<div class="tweak-container" tweak-path="hide-welcome-logo">
|
||||
<div class="wide-boolean-setting tweak-container" tweak-path="hide-welcome-logo">
|
||||
<span>Hide welcome logo</span>
|
||||
<input type=checkbox class="setting_item_input" data-size="mini" data-onstyle="success" data-toggle="toggle">
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user