Add genre UI

This commit is contained in:
somebody
2022-12-04 21:18:45 -06:00
parent 80b55ef601
commit 9d228e6614
8 changed files with 585 additions and 6 deletions

View File

@@ -510,6 +510,9 @@ class ImportBuffer:
refresh_story()
import_buffer = ImportBuffer()
with open("data/genres.json", "r") as file:
genre_list = json.load(file)
# Set logging level to reduce chatter from Flask
import logging
@@ -9783,6 +9786,15 @@ def UI_2_privacy_mode(data):
if data['password'] == koboldai_vars.privacy_password:
koboldai_vars.privacy_mode = False
#==================================================================#
# Genres
#==================================================================#
@app.route("/genre_data.json", methods=["GET"])
def UI_2_get_applicable_genres():
return Response(json.dumps({
"list": genre_list,
"init": koboldai_vars.genres,
}))
#==================================================================#
# Test

307
data/genres.json Normal file
View File

@@ -0,0 +1,307 @@
[
"Absurdist",
"Action & Adventure",
"Adaptations & Pastiche",
"African American & Black/General",
"African American & Black/Christian",
"African American & Black/Erotica",
"African American & Black/Historical",
"African American & Black/Mystery & Detective",
"African American & Black/Urban & Street Lit",
"African American & Black/Women",
"Alternative History",
"Amish & Mennonite",
"Animals",
"Anthologies (multiple authors)",
"Asian American",
"Biographical",
"Buddhist",
"Christian/General",
"Christian/Biblical",
"Christian/Classic & Allegory",
"Christian/Collections & Anthologies",
"Christian/Contemporary",
"Christian/Fantasy",
"Christian/Futuristic",
"Christian/Historical",
"Christian/Romance/General",
"Christian/Romance/Historical",
"Christian/Romance/Suspense",
"Christian/Suspense",
"Christian/Western",
"City Life",
"Classics",
"Coming of Age",
"Crime",
"Cultural Heritage",
"Disabilities & Special Needs",
"Disaster",
"Dystopian",
"Epistolary",
"Erotica/General",
"Erotica/BDSM",
"Erotica/Collections & Anthologies",
"Erotica/Historical",
"Erotica/LGBTQ+/General",
"Erotica/LGBTQ+/Bisexual",
"Erotica/LGBTQ+/Gay",
"Erotica/LGBTQ+/Lesbian",
"Erotica/LGBTQ+/Transgender",
"Erotica/Science Fiction, Fantasy & Horror",
"Fairy Tales, Folk Tales, Legends & Mythology",
"Family Life/General",
"Family Life/Marriage & Divorce",
"Family Life/Siblings",
"Fantasy/General",
"Fantasy/Action & Adventure",
"Fantasy/Arthurian",
"Fantasy/Collections & Anthologies",
"Fantasy/Contemporary",
"Fantasy/Dark Fantasy",
"Fantasy/Dragons & Mythical Creatures",
"Fantasy/Epic",
"Fantasy/Gaslamp",
"Fantasy/Historical",
"Fantasy/Humorous",
"Fantasy/Military",
"Fantasy/Paranormal",
"Fantasy/Romance",
"Fantasy/Urban",
"Feminist",
"Friendship",
"Ghost",
"Gothic",
"Hispanic & Latino",
"Historical/General",
"Historical/Ancient",
"Historical/Civil War Era",
"Historical/Colonial America & Revolution",
"Historical/Medieval",
"Historical/Renaissance",
"Historical/World War I",
"Historical/World War II",
"Holidays",
"Horror",
"Humorous/General",
"Humorous/Black Humor",
"Indigenous",
"Jewish",
"Legal",
"LGBTQ+/General",
"LGBTQ+/Bisexual",
"LGBTQ+/Gay",
"LGBTQ+/Lesbian",
"LGBTQ+/Transgender",
"Literary",
"LitRPG (Literary Role-Playing Game) *",
"Magical Realism",
"Mashups",
"Media Tie-In",
"Medical",
"Multiple Timelines",
"Muslim",
"Mystery & Detective/General",
"Mystery & Detective/Amateur Sleuth",
"Mystery & Detective/Collections & Anthologies",
"Mystery & Detective/Cozy/General",
"Mystery & Detective/Cozy/Animals",
"Mystery & Detective/Cozy/Crafts",
"Mystery & Detective/Cozy/Culinary",
"Mystery & Detective/Cozy/Holidays & Vacation *",
"Mystery & Detective/Cozy/Paranormal *",
"Mystery & Detective/Hard-Boiled",
"Mystery & Detective/Historical",
"Mystery & Detective/International Crime & Mystery",
"Mystery & Detective/Jewish *",
"Mystery & Detective/Police Procedural",
"Mystery & Detective/Private Investigators",
"Mystery & Detective/Traditional",
"Mystery & Detective/Women Sleuths",
"Nature & the Environment",
"Noir",
"Occult & Supernatural",
"Own Voices",
"Political",
"Psychological",
"Religious",
"Romance/General",
"Romance/Action & Adventure",
"Romance/African American & Black",
"Romance/Billionaires",
"Romance/Clean & Wholesome",
"Romance/Collections & Anthologies",
"Romance/Contemporary",
"Romance/Erotic",
"Romance/Fantasy",
"Romance/Firefighters",
"Romance/Historical/General",
"Romance/Historical/American",
"Romance/Historical/Ancient World",
"Romance/Historical/Gilded Age",
"Romance/Historical/Medieval",
"Romance/Historical/Regency",
"Romance/Historical/Renaissance",
"Romance/Historical/Scottish",
"Romance/Historical/Tudor",
"Romance/Historical/20th Century",
"Romance/Historical/Victorian",
"Romance/Historical/Viking",
"Romance/Holiday",
"Romance/Later in Life",
"Romance/LGBTQ+/General",
"Romance/LGBTQ+/Bisexual",
"Romance/LGBTQ+/Gay",
"Romance/LGBTQ+/Lesbian",
"Romance/LGBTQ+/Transgender",
"Romance/Medical",
"Romance/Military",
"Romance/Multicultural & Interracial",
"Romance/New Adult",
"Romance/Paranormal/General",
"Romance/Paranormal/Shifters",
"Romance/Paranormal/Vampires",
"Romance/Paranormal/Witches",
"Romance/Police & Law Enforcement",
"Romance/Polyamory",
"Romance/Rock Stars",
"Romance/Romantic Comedy",
"Romance/Royalty",
"Romance/Science Fiction",
"Romance/Sports",
"Romance/Suspense",
"Romance/Time Travel",
"Romance/Western",
"Romance/Workplace",
"Sagas",
"Satire",
"Science Fiction/General",
"Science Fiction/Action & Adventure",
"Science Fiction/Alien Contact",
"Science Fiction/Apocalyptic & Post-Apocalyptic",
"Science Fiction/Collections & Anthologies",
"Science Fiction/Crime & Mystery",
"Science Fiction/Cyberpunk",
"Science Fiction/Genetic Engineering",
"Science Fiction/Hard Science Fiction",
"Science Fiction/Humorous",
"Science Fiction/Military",
"Science Fiction/Space Exploration",
"Science Fiction/Space Opera",
"Science Fiction/Steampunk",
"Science Fiction/Time Travel",
"Sea Stories",
"Short Stories (single author)",
"Small Town & Rural",
"Southern",
"Sports",
"Superheroes",
"Thrillers/General",
"Thrillers/Crime",
"Thrillers/Domestic",
"Thrillers/Espionage",
"Thrillers/Historical",
"Thrillers/Legal",
"Thrillers/Medical",
"Thrillers/Military",
"Thrillers/Political",
"Thrillers/Psychological",
"Thrillers/Supernatural",
"Thrillers/Suspense",
"Thrillers/Technological",
"Thrillers/Terrorism",
"Urban & Street Lit",
"Visionary & Metaphysical",
"War & Military",
"Westerns",
"Women",
"World Literature/Africa/General",
"World Literature/Africa/East Africa",
"World Literature/Africa/Nigeria",
"World Literature/Africa/Southern Africa",
"World Literature/Africa/West Africa",
"World Literature/American/General",
"World Literature/American/Colonial & Revolutionary Periods",
"World Literature/American/19th Century",
"World Literature/American/20th Century",
"World Literature/American/21st Century",
"World Literature/Argentina",
"World Literature/Asia (General)",
"World Literature/Australia",
"World Literature/Austria",
"World Literature/Brazil",
"World Literature/Canada/General",
"World Literature/Canada/Colonial & 19th Century",
"World Literature/Canada/20th Century",
"World Literature/Canada/21st Century",
"World Literature/Caribbean & West Indies",
"World Literature/Central America",
"World Literature/Chile",
"World Literature/China/General",
"World Literature/China/19th Century",
"World Literature/China/20th Century",
"World Literature/China/21st Century",
"World Literature/Colombia",
"World Literature/Czech Republic",
"World Literature/Denmark",
"World Literature/England/General",
"World Literature/England/Early & Medieval Periods",
"World Literature/England/16th & 17th Century",
"World Literature/England/18th Century",
"World Literature/England/19th Century",
"World Literature/England/20th Century",
"World Literature/England/21st Century",
"World Literature/Europe (General)",
"World Literature/Finland",
"World Literature/France/General",
"World Literature/France/18th Century",
"World Literature/France/19th Century",
"World Literature/France/20th Century",
"World Literature/France/21st Century",
"World Literature/Germany/General",
"World Literature/Germany/20th Century",
"World Literature/Germany/21st Century",
"World Literature/Greece",
"World Literature/Hungary",
"World Literature/India/General",
"World Literature/India/19th Century",
"World Literature/India/20th Century",
"World Literature/India/21st Century",
"World Literature/Ireland/General",
"World Literature/Ireland/19th Century",
"World Literature/Ireland/20th Century",
"World Literature/Ireland/21st Century",
"World Literature/Italy",
"World Literature/Japan",
"World Literature/Korea",
"World Literature/Mexico",
"World Literature/Middle East/General",
"World Literature/Middle East/Arabian Peninsula",
"World Literature/Middle East/Egypt & North Africa",
"World Literature/Middle East/Israel",
"World Literature/Netherlands",
"World Literature/New Zealand",
"World Literature/Norway",
"World Literature/Oceania",
"World Literature/Pakistan",
"World Literature/Peru",
"World Literature/Poland",
"World Literature/Portugal",
"World Literature/Russia/General",
"World Literature/Russia/19th Century",
"World Literature/Russia/20th Century",
"World Literature/Russia/21st Century",
"World Literature/Scotland/General",
"World Literature/Scotland/19th Century",
"World Literature/Scotland/20th Century",
"World Literature/Scotland/21st Century",
"World Literature/South America (General)",
"World Literature/Southeast Asia",
"World Literature/Spain/General",
"World Literature/Spain/19th Century",
"World Literature/Spain/20th Century",
"World Literature/Spain/21st Century",
"World Literature/Sweden",
"World Literature/Turkey",
"World Literature/Uruguay",
"World Literature/Wales"
]

File diff suppressed because one or more lines are too long

View File

@@ -1975,6 +1975,7 @@ body {
.context-sp {background-color: var(--context_colors_soft_prompt);}
.context-genre {background-color: var(--context_colors_genre);}
.context-prompt {background-color: var(--context_colors_prompt);}
.context-wi {background-color: var(--context_colors_world_info);}
.context-memory {background-color: var(--context_colors_memory);}
@@ -2718,6 +2719,71 @@ body {
max-width: 99%;
}
/* Genres */
#genre-input {
height: 32px;
width: 100%;
}
#genre-suggestion-super-container { position: relative; }
#genre-suggestion-container {
position: absolute;
width: 100%;
left: 0px;
top: 0px;
background-color: var(--input_background);
z-index: 2;
max-height: calc((30px + 2px) * 5);
overflow-y: auto;
}
.genre-suggestion {
display: block;
text-align: center;
padding: 5px 0px;
background-color: var(--wi_tag_color);
margin-bottom: 2px;
}
.genre-suggestion.highlighted {
background-color: #151e28;
}
#genre-container {
max-height: 50vh;
overflow-y: auto;
background-color: #151e28;
}
.genre {
display: inline-flex;
align-items: center;
background-color: var(--wi_tag_color);
border-radius: var(--radius_wi_card);
padding: 4px 0px;
margin: 2px 2px;
}
.genre-inner {
display: flex;
justify-content: center;
position: relative;
width: 100%;
margin: 0px 10px;
top: 1px;
right: 2px;
}
.genre-inner > .x {
font-size: 16px;
cursor: pointer;
opacity: 0.7;
}
.genre-inner > .x:hover { opacity: 1; }
/*---------------------------------- Global ------------------------------------------------*/
.hidden {
display: none;

View File

@@ -70,6 +70,10 @@ var scroll_trigger_element = undefined; //undefined means not currently set. If
var drag_id = null;
const on_colab = $el("#on_colab").textContent == "true";
// Each entry into this array should be an object that looks like:
// {class: "class", key: "key", func: callback}
let sync_hooks = [];
// name, desc, icon, func
var finder_actions = [
{name: "Load Model", icon: "folder_open", type: "action", func: function() { socket.emit('load_model_button', {}); }},
@@ -760,6 +764,12 @@ function var_changed(data) {
//if (data.name == "sp") {
// console.log({"name": data.name, "data": data});
//}
for (const entry of sync_hooks) {
if (data.classname !== entry.class) continue;
if (data.name !== entry.name) continue;
entry.func(data.value);
}
if (data.name in vars_sync_time) {
if (vars_sync_time[data.name] > Date.parse(data.transmit_time)) {
@@ -767,7 +777,7 @@ function var_changed(data) {
}
}
vars_sync_time[data.name] = Date.parse(data.transmit_time);
if ((data.classname == 'actions') && (data.name == 'Action Count')) {
current_action = data.value;
if (current_action <= 0) {
@@ -3197,6 +3207,7 @@ function autoResize(element, min_size=200) {
function calc_token_usage(
soft_prompt_length,
genre_length,
memory_length,
authors_note_length,
prompt_length,
@@ -3209,6 +3220,7 @@ function calc_token_usage(
const data = [
{id: "soft_prompt_tokens", tokenCount: soft_prompt_length, label: "Soft Prompt"},
{id: "genre_tokens", tokenCount: genre_length, label: "Genre"},
{id: "memory_tokens", tokenCount: memory_length, label: "Memory"},
{id: "authors_notes_tokens", tokenCount: authors_note_length, label: "Author's Note"},
{id: "world_info_tokens", tokenCount: world_info_length, label: "World Info"},
@@ -3525,6 +3537,7 @@ function update_context(data) {
$(".context-block").remove();
let memory_length = 0;
let genre_length = 0;
let authors_notes_length = 0;
let prompt_length = 0;
let game_text_length = 0;
@@ -3542,10 +3555,12 @@ function update_context(data) {
for (const entry of data) {
console.info(entry)
let contextClass = "context-" + ({
soft_prompt: "sp",
prompt: "prompt",
world_info: "wi",
genre: "genre",
memory: "memory",
authors_note: "an",
action: "action",
@@ -3592,6 +3607,9 @@ function update_context(data) {
document.getElementById('world_info_'+entry.uid).classList.add("used_in_game");
}
break;
case 'memory':
genre_length += entry.tokens.length;
break;
case 'memory':
memory_length += entry.tokens.length;
break;
@@ -3616,6 +3634,7 @@ function update_context(data) {
calc_token_usage(
soft_prompt_length,
genre_length,
memory_length,
authors_notes_length,
prompt_length,
@@ -6455,4 +6474,136 @@ function imgGenRetry() {
if (!image) return;
$el("#image-loading").classList.remove("hidden");
socket.emit("retry_generated_image", {});
}
}
/* Genres */
(async function() {
const genreContainer = $el("#genre-container");
const genreInput = $el("#genre-input");
const genreSuggestionContainer = $el("#genre-suggestion-container");
let genreData = await (await fetch("/genre_data.json")).json();
let allGenres = genreData.list;
let genres = genreData.init;
let highlightIndex = -1;
sync_hooks.push({
class: "story",
name: "genres",
func: function(passedGenres) {
genres = passedGenres;
$(".genre").remove();
for (const g of genres) {
addGenreUI(g);
}
}
})
function addGenreUI(genre) {
let div = $e("div", genreContainer, {classes: ["genre"]});
let inner = $e("div", div, {classes: ["genre-inner"]});
let xIcon = $e("span", inner, {innerText: "clear", classes: ["x", "material-icons-outlined"]});
let label = $e("span", inner, {innerText: genre, classes: ["genre-label"]});
xIcon.addEventListener("click", function() {
div.remove();
genres = genres.filter(x => x !== genre);
socket.emit("var_change", {"ID": "story_genres", "value": genres});
});
}
for (const initGenre of genreData.init) {
addGenreUI(initGenre);
}
function nukeSuggestions() {
genreSuggestionContainer.innerHTML = "";
highlightIndex = -1;
}
document.addEventListener("click", function(event) {
// Listening for clicks all over the document kinda sucks but blur
// fires you can click a suggestion so...
if (!genreSuggestionContainer.children.length) return;
if (event.target === genreInput) return;
if (event.target.classList.contains("genre-suggestion")) return;
nukeSuggestions();
});
genreInput.addEventListener("keydown", function(event) {
switch (event.key) {
case "ArrowUp":
highlightIndex--;
break;
case "Tab":
highlightIndex += event.shiftKey ? -1 : 1;
break;
case "ArrowDown":
highlightIndex++;
break;
case "Enter":
genreSuggestionContainer.children[highlightIndex].click();
return;
case "Escape":
genreInput.value = "";
nukeSuggestions();
event.preventDefault();
event.stopPropagation();
return;
default:
return;
}
event.preventDefault();
if (!genreSuggestionContainer.children.length) return;
const oldHighlighted = $el(".genre-suggestion.highlighted");
if (oldHighlighted) oldHighlighted.classList.remove("highlighted");
// Wrap around
let maxIndex = genreSuggestionContainer.children.length - 1;
if (highlightIndex < 0) highlightIndex = maxIndex;
if (highlightIndex > maxIndex) highlightIndex = 0;
const highlighted = genreSuggestionContainer.children[highlightIndex];
highlighted.classList.add("highlighted");
highlighted.scrollIntoView({
behavior: "auto",
block: "center",
inline: "center"
});
});
genreInput.addEventListener("input", function() {
let showList = [];
let lowerMatch = genreInput.value.toLowerCase();
nukeSuggestions();
if (!lowerMatch) return;
for (const genre of allGenres) {
if (!genre.toLowerCase().includes(lowerMatch)) continue;
showList.push(genre);
}
for (const genre of showList) {
let suggestion = $e("span", genreSuggestionContainer, {
innerText: genre,
classes: ["genre-suggestion"]
});
suggestion.addEventListener("click", function() {
if (genres.includes(this.innerText)) return;
addGenreUI(this.innerText);
genreInput.value = "";
nukeSuggestions();
genres.push(this.innerText);
socket.emit("var_change", {"ID": "story_genres", "value": genres});
});
}
});
})()

View File

@@ -196,10 +196,11 @@
<span class="noselect">Key:</span>
<div>
<span class="noselect context-block-example context-sp">Soft Prompt</span>
<span class="noselect context-block-example context-prompt">Prompt</span>
<span class="noselect context-block-example context-wi">World Info</span>
<span class="noselect context-block-example context-genre">Genre</span>
<span class="noselect context-block-example context-memory">Memory</span>
<span class="noselect context-block-example context-wi">World Info</span>
<span class="noselect context-block-example context-an">Author's Note</span>
<span class="noselect context-block-example context-prompt">Prompt</span>
<span class="noselect context-block-example context-action">Action</span>
<span class="noselect context-block-example context-submit">Submit</span>
</div>

View File

@@ -50,6 +50,19 @@
<label for="authors_notes">Author's Notes:</label><br/>
<textarea autocomplete="off" rows=16 id="authors_notes" class="var_sync_story_authornote var_sync_alt_story_authornote_length fullwidth" oninput="autoResize(this)" onchange='sync_to_server(this);'></textarea><br/>
<h4 class="section_header">Genre</h4>
<div class="help_text">Styles the AI will attempt to imitate. Effectiveness depends on model.</div>
<input id="genre-input" class="fullwidth" autocomplete="off" spellcheck="false">
<div id="genre-suggestion-super-container">
<div id="genre-suggestion-container">
<span class="genre-suggestion">Animals</span>
<span class="genre-suggestion">Amish</span>
<span class="genre-suggestion">Asian</span>
<span class="genre-suggestion">Buddhist</span>
</div>
</div>
<div id="genre-container"></div>
<div id="An-Attention-Bias" class="var_sync_alt_system_experimental_features">
<h4 class="section_header"><label for="An-Attention-Bias">Attention Bias Test</label></h4>
<span class="help_text">See disclaimer in memory page.</span>
@@ -112,6 +125,7 @@
<div id="token-breakdown-container" class="settings_footer" style="padding-top: 10px;">
<div class="token_breakdown" onclick='socket.emit("update_tokens", document.getElementById("input_text").value);openPopup("context-viewer");'>
<div id="soft_prompt_tokens" style="width:0%; background-color: var(--context_colors_soft_prompt);"></div>
<div id="genre_tokens" style="width:40%; background-color: var(--context_colors_genre);"></div>
<div id="memory_tokens" style="width:40%; background-color: var(--context_colors_memory);"></div>
<div id="authors_notes_tokens" style="width:10%; background-color: var(--context_colors_authors_notes);"></div>
<div id="world_info_tokens" style="width:20%; background-color: var(--context_colors_world_info);"></div>

View File

@@ -151,6 +151,7 @@
--context_colors_submit: #ffffff00;
--context_colors_unused: #ffffff24;
--context_colors_soft_prompt: #141414;
--context_colors_genre: #2c5c88;
/*Parameters*/
--scrollbar-size: 6px;