This commit is contained in:
Cohee1207
2023-05-06 15:12:19 +03:00
12 changed files with 756 additions and 261 deletions

View File

@@ -417,6 +417,21 @@
</div>
</div>
</div>
<div class="range-block">
<div class="range-block-title">
Top-p
</div>
<div class="range-block-range-and-counter">
<div class="range-block-range">
<input type="range" id="top_p_openai" name="volume" min="0" max="1" step="0.01">
</div>
<div class="range-block-counter">
<div contenteditable="true" data-for="top_p_openai" id="top_p_counter_openai">
select
</div>
</div>
</div>
</div>
</div>
<div id="range_block_poe">
<div class="range-block">
@@ -1185,6 +1200,15 @@
<option value="3">Sentencepiece (LLaMA)</option>
</select>
</div>
<div class="range-block">
<div class="range-block-title justifyLeft">
Token Padding
<a href="/notes#tokenpadding" class="notes-link" target="_blank">
<span class="note-link-span">?</span>
</a>
</div>
<input id="token_padding" class="text_pole" type="number" min="-2048" max="2048" />
</div>
<label class="checkbox_label" for="always-force-name2-checkbox">
<input id="always-force-name2-checkbox" type="checkbox" />
Always add character's name to prompt
@@ -1323,54 +1347,6 @@
<div name="UI Customization" class="flex-container drawer25pWidth">
<div class="ui-settings">
<h4>UI Customization</h4>
<div id="font-blur-UIpresets-block" class="flex-container flexFlowColumn">
<div id="font-scale-block" class="range-block">
<div class="range-block-title">
Font Scale
</div>
<div class="range-block-range-and-counter">
<div class="range-block-range">
<input type="range" id="font_scale" name="font_scale" min="0.8" max="1.2" step="0.05">
</div>
<div class="range-block-counter">
<div contenteditable="true" data-for="font_scale" id="font_scale_counter">
select
</div>
</div>
</div>
</div>
<div id="blur-strength-block" class="range-block">
<div class="range-block-title">
Blur Strength
</div>
<div class="range-block-range-and-counter">
<div class="range-block-range">
<input type="range" id="blur_strength" name="blur_strength" min="0" max="30" step="1">
</div>
<div class="range-block-counter">
<div contenteditable="true" data-for="blur_strength" id="blur_strength_counter">
select
</div>
</div>
</div>
</div>
<div id="shadow-width-block" class="range-block">
<div class="range-block-title">
Text Shadow Width
</div>
<div class="range-block-range-and-counter">
<div class="range-block-range">
<input type="range" id="shadow_width" name="shadow_width" min="0" max="5" step="1">
</div>
<div class="range-block-counter">
<div contenteditable="true" data-for="shadow_width" id="shadow_width_counter">
select
</div>
</div>
</div>
</div>
</div>
<div>
Avatar Style:<br>
<label>
@@ -1418,6 +1394,16 @@
♡ Waifu Mode ♡
</label>
<label for="messageTimerEnabled" class="checkbox_label">
<input id="messageTimerEnabled" type="checkbox" />
Message Timer
</label>
<label for="hotswapEnabled" class="checkbox_label">
<input id="hotswapEnabled" type="checkbox" />
Characters Hotswap
</label>
<label for="movingUImode" class="checkbox_label">
<input id="movingUImode" type="checkbox" />
Movable UI Panels
@@ -1455,6 +1441,53 @@
<toolcool-color-picker id="blur-tint-color-picker"></toolcool-color-picker>
Blur Tint
</div>
<div id="font-blur-UIpresets-block" class="flex-container flexFlowColumn">
<div id="font-scale-block" class="range-block">
<div class="range-block-title">
Font Scale
</div>
<div class="range-block-range-and-counter">
<div class="range-block-range">
<input type="range" id="font_scale" name="font_scale" min="0.8" max="1.2" step="0.05">
</div>
<div class="range-block-counter">
<div contenteditable="true" data-for="font_scale" id="font_scale_counter">
select
</div>
</div>
</div>
</div>
<div id="blur-strength-block" class="range-block">
<div class="range-block-title">
Blur Strength
</div>
<div class="range-block-range-and-counter">
<div class="range-block-range">
<input type="range" id="blur_strength" name="blur_strength" min="0" max="30" step="1">
</div>
<div class="range-block-counter">
<div contenteditable="true" data-for="blur_strength" id="blur_strength_counter">
select
</div>
</div>
</div>
</div>
<div id="shadow-width-block" class="range-block">
<div class="range-block-title">
Text Shadow Width
</div>
<div class="range-block-range-and-counter">
<div class="range-block-range">
<input type="range" id="shadow_width" name="shadow_width" min="0" max="5" step="1">
</div>
<div class="range-block-counter">
<div contenteditable="true" data-for="shadow_width" id="shadow_width_counter">
select
</div>
</div>
</div>
</div>
</div>
<div id="UI-presets-block" class="flex-container flexFlowColumn">
<h4>
UI Theme Preset
@@ -1501,6 +1534,10 @@
<input id="auto_fix_generated_markdown" type="checkbox" />
Auto-fix Markdown
</label>
<label class="checkbox_label" for="allow_name2_display">
<input id="allow_name2_display" type="checkbox" />
Allow {{char}}: display in bot messages
</label>
<label for="auto_scroll_chat_to_bottom">
<input id="auto_scroll_chat_to_bottom" type="checkbox" />
Auto-scroll Chat
@@ -1619,6 +1656,8 @@
<div class="fa-solid checked fa-lock" alt=""></div>
</label>
</div>
<div class="hotswap flex-container justifyCenter">
</div>
<div id="right-nav-panel-tabs">
<div class="right_menu_button fa-solid fa-list-ul" id="rm_button_characters" title="Select/Create Characters"></div>
<div class="right_menu_button" id="rm_button_selected_ch">
@@ -1627,8 +1666,7 @@
</div>
</div>
<div id="rm_ch_create_block" class="right_menu flex-container flexFlowColumn" style="display: none;">
<div name="Solo Char Create/Edit Panel" id="rm_ch_create_block" class="right_menu flex-container flexFlowColumn" style="display: none;">
<form id="form_create" action="javascript:void(null);" method="post" enctype="multipart/form-data">
<div id="avatar-and-name-block">
@@ -1705,68 +1743,103 @@
<!-- now back to normal divs for display purposes-->
</form>
</div>
<div id="rm_group_chats_block" class="right_menu">
<div id="rm_group_top_bar">
<div id="rm_button_back_from_group" class="menu_button fa-solid fa-left-long"></div>
<div name="Group Chat Edit Panel" id="rm_group_chats_block" class="right_menu flex-container flexNoGap">
<div class="inline-drawer wide100p flexFlowColumn">
<div id="groupControlsToggle" class="inline-drawer-toggle inline-drawer-header">
Group Controls
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
</div>
<div class="inline-drawer-content">
<div name="group-metadata-controls" class="marginTopBot5">
<input id="rm_group_chat_name" class="text_pole" type="text" name="chat_name" placeholder="Chat Name (Optional)" maxlength="100" />
<div id="group_favorite_button" class="menu_button fa-solid fa-star" title="Add to Favorites"></div>
<input id="rm_group_fav" type="hidden" />
<div id="rm_group_submit" class="menu_button fa-solid fa-check" title="Create"></div>
<div id="rm_group_delete" class="menu_button fa-solid fa-trash-can" title="Delete"></div>
</div>
<div id="rm_group_buttons">
<div class="flex1">
<h5>
Group reply strategy
<a href="/notes#replyorderstrategies" class="notes-link" target="_blank">
<span class="note-link-span">?</span>
</a>
</h5>
<label class="checkbox_label">
<input type="radio" name="rm_group_activation_strategy" value="0" />
Natural order
</label>
<label class="checkbox_label">
<input type="radio" name="rm_group_activation_strategy" value="1" />
List order
</label>
</div>
<div class="flex1">
<label class="checkbox_label">
<input id="rm_group_allow_self_responses" type="checkbox" />
Allow self responses
</label>
<label id="rm_group_automode_label" class="checkbox_label">
<input id="rm_group_automode" type="checkbox" />
Auto Mode
</label>
</div>
</div>
<div id="group_tags_div" class="wide100p">
<div class="tag_controls">
<input id="groupTagInput" class="text_pole tag_input flex1" placeholder="Search / Create tags" maxlength="25" />
<div class="tags_view menu_button fa-solid fa-tags" title="View all tags"></div>
</div>
<div id="groupTagList" class="tags"></div>
<div id="groupTagList" class="tags paddingTopBot5"></div>
</div>
<div id="rm_group_top_bar" class="flex-container spaceEvenly width100p">
<div name="GroupStragegyAndOrder" id="rm_group_buttons" class="fontsize80p flex-container paddingLeftRight5">
<div class="">
<div class="flex-container flexnowrap width100p whitespacenowrap">
Group reply strategy
<a href="/notes#replyorderstrategies" class="notes-link" target="_blank">
<span class="note-link-span">?</span>
</a>
</div>
<label class="checkbox_label flexnowrap whitespacenowrap">
<input type="radio" name="rm_group_activation_strategy" value="0" />
Natural order
</label>
<label class="checkbox_label flexnowrap whitespacenowrap">
<input type="radio" name="rm_group_activation_strategy" value="1" />
List order
</label>
</div>
<div class="">
<label class="checkbox_label whitespacenowrap">
<input id="rm_group_allow_self_responses" type="checkbox" />
Allow self responses
</label>
<label id="rm_group_automode_label" class="checkbox_label whitespacenowrap">
<input id="rm_group_automode" type="checkbox" />
Auto Mode
</label>
</div>
</div>
<div name="GroupFavDelOkBack" class="flex-container flexGap5 spaceEvenly">
<div id="rm_button_back_from_group" class="heightFitContent margin0 menu_button fa-solid fa-left-long"></div>
<div id="rm_group_scenario" class="heightFitContent margin0 menu_button fa-solid fa-scroll" title="Set a group chat scenario"></div>
<div id="group_favorite_button" class="heightFitContent margin0 menu_button fa-solid fa-star" title="Add to Favorites"></div>
<input id="rm_group_fav" type="hidden" />
<div id="rm_group_submit" class="heightFitContent margin0 menu_button fa-solid fa-check" title="Create"></div>
<div id="rm_group_delete" class="heightFitContent margin0 menu_button fa-solid fa-trash-can" title="Delete"></div>
</div>
</div>
</div>
</div>
</div>
<div class="inline-drawer wide100p flexFlowColumn">
<div id="groupAddMemberListToggle" class="inline-drawer-toggle inline-drawer-header">
Add Members
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
</div>
<div class="inline-drawer-content">
<div name="Unadded Char List" class="flex-container flexFlowColumn overflowYAuto flex1">
<div id="rm_group_add_members_header">
<h3>Add Members</h3>
<input id="rm_group_filter" class="text_pole" type="search" placeholder="Filter..." maxlength="100" />
<div id="group_fav_filter" class="menu_button fa-solid fa-ranking-star" title="Show only favorites"></div>
</div>
<div class="flex-container flexFlowColumn flexNoGap overflowYAuto wide100p flexGrow">
<div id="rm_group_add_members"></div>
<h3>Current Members</h3>
<div id="rm_group_members"></div>
<div id="rm_group_add_members" class="overflowYAuto flex-container"></div>
</div>
</div>
</div>
<div class="inline-drawer wide100p flexFlowColumn">
<div id="groupCurrentMemberListToggle" class="inline-drawer-toggle inline-drawer-header">
Current Members
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
</div>
<div class="inline-drawer-content">
<div name="Current Group Members" class="flex-container flexFlowColumn overflowYAuto flex1">
<div id="rm_group_members" class="overflowYAuto flex-container"></div>
</div>
</div>
</div>
</div>
<div id="rm_character_import" class="right_menu" style="display: none;">
<form id="form_import" action="javascript:void(null);" method="post" enctype="multipart/form-data">
<input multiple type="file" id="character_import_file" accept=".json, image/png, image/webp" name="avatar">
<input id="character_import_file_type" name="file_type" class="text_pole" maxlength="999" size="2" value="" autocomplete="off">
</form>
</div>
<div id="rm_characters_block" class="right_menu">
<div name="Character List Panel" id="rm_characters_block" class="right_menu">
<div id="charListFixedTop">
<div class="form_create_bottom_buttons_block">
<div id="rm_button_create" title="Create New Character" class="menu_button fa-solid fa-user-plus "></div>
@@ -1945,6 +2018,21 @@
<!-- templates for JS to reuse when needed -->
<div id="group_scenario_template" class="template_element">
<div class="group_scenario range-block flexFlowColumn flex-container">
<div class="range-block-title title_restorable">
<h3>Group Chat Scenario Override</h3>
<div title="Remove" class="menu_button fa-solid fa-trash-can remove_scenario_override"></div>
</div>
<div class="range-block-counter justifyLeft flex-container flexFlowColumn">
All group members will use the following scenario text instead of what is specified in their character cards.
</div>
<div class="range-block-range wide100p">
<textarea class="wide100p group_chat_scenario" class="text_pole" rows="5" placeholder="Type here..."></textarea>
</div>
</div>
</div>
<div id="past_chat_template" class="template_element">
<div class="select_chat_block_wrapper">
<div class="select_chat_block" file_name="">
@@ -2203,6 +2291,12 @@
</div>
</div>
<div id="hotswap_template" class="template_element">
<div class="hotswapAvatar">
<img src="/img/ai4.png">
</div>
</div>
<!-- chat and input bar -->
<div id="typing_indicator_template" class="template_element">
<div class="typing_indicator"><span class="typing_indicator_name">CHAR</span> is typing</div>

View File

@@ -422,6 +422,8 @@ To import Character.AI chats, use this tool: [https://github.com/0x000011b/chara
## Tokenizer
**Important: This section doesn't apply to OpenAI API. SillyTavern will always use a matching tokenizer for OpenAI models.**
A tokenizer is a tool that breaks down a piece of text into smaller units called tokens. These tokens can be individual words or even parts of words, such as prefixes, suffixes, or punctuation. A rule of thumb is that one token generally corresponds to 3~4 characters of text.
SillyTavern can use the following tokenizers while forming a request to the AI backend:
@@ -431,6 +433,18 @@ SillyTavern can use the following tokenizers while forming a request to the AI b
3. (Legacy) GPT-2/3 tokenizer. Used by original TavernAI. **Pick this if you're unsure.** More info: [gpt-2-3-tokenizer](https://github.com/josephrocca/gpt-2-3-tokenizer).
4. Sentencepiece tokenizer. Used by LLaMA model family: Alpaca, Vicuna, Koala, etc. **Pick if you use a LLaMA model.**
## Token Padding
**Important: This section doesn't apply to OpenAI API. SillyTavern will always use a matching tokenizer for OpenAI models.**
SillyTavern cannot use a proper tokenizer provided by the model running on a remote instance of KoboldAI or Oobabooga's TextGen, so all token counts assumed during prompt generation are estimated based on the selected [tokenizer](#Tokenizer) type.
Since the results of tokenization can be inaccurate on context sizes close to the model-defined maximum, some parts of the prompt may be trimmed or dropped, which may negatively affect the coherence of character definitions.
To prevent this, SillyTavern allocates a portion of the context size as padding to avoid adding more chat items than the model can accommodate. If you find that some part of the prompt is trimmed even with the most-matching tokenizer selected, adjust the padding so the description is not truncated.
You can input negative values for reverse padding, which allows allocating more than the set maximum amount of tokens.
## Advanced Formatting
The settings provided in this section allow for more control over the prompt building strategy. Most specifics of the prompt building depend on whether a Pygmalion model is selected or special formatting is force-enabled. The core differences between the formatting schemas are listed below.

View File

@@ -1,4 +1,4 @@
import { humanizedDateTime } from "./scripts/RossAscends-mods.js";
import { humanizedDateTime, favsToHotswap } from "./scripts/RossAscends-mods.js";
import { encode } from "../scripts/gpt-2-3-tokenizer/mod.js";
import { GPT3BrowserTokenizer } from "../scripts/gpt-3-tokenizer/gpt3-tokenizer.js";
import {
@@ -143,7 +143,7 @@ export {
setRightTabSelectedClass,
openCharacterChat,
saveChat,
messageFormating,
messageFormatting,
getExtensionPrompt,
showSwipeButtons,
hideSwipeButtons,
@@ -240,7 +240,7 @@ window.filterByFav = false;
const durationSaveEdit = 200;
const saveSettingsDebounced = debounce(() => saveSettings(), durationSaveEdit);
const saveCharacterDebounced = debounce(() => $("#create_button").click(), durationSaveEdit);
const saveCharacterDebounced = debounce(() => $("#create_button").trigger('click'), durationSaveEdit);
const getStatusDebounced = debounce(() => getStatus(), 90000);
const saveChatDebounced = debounce(() => saveChatConditional(), 1000);
@@ -472,7 +472,6 @@ var preset_settings = "gui";
var user_avatar = "you.png";
var amount_gen = 80; //default max length of AI generated responses
var max_context = 2048;
let padding_tokens = 64; // reserved tokens to prevent prompt overflow
var is_pygmalion = false;
var tokens_already_generated = 0;
@@ -734,9 +733,10 @@ function printCharacters() {
// Add to the list
$("#rm_print_characters_block").append(template);
});
$("#rm_print_characters_block").prepend(`<hr>`);
printTags();
printGroups();
favsToHotswap();
sortCharactersList();
}
@@ -931,7 +931,7 @@ export async function reloadCurrentChat() {
}
}
function messageFormating(mes, ch_name, isSystem, forceAvatar) {
function messageFormatting(mes, ch_name, isSystem, isUser) {
if (!mes) {
mes = '';
}
@@ -967,9 +967,9 @@ function messageFormating(mes, ch_name, isSystem, forceAvatar) {
});
}
/* if (ch_name && (forceAvatar || ch_name !== name1)) {
mes = mes.replaceAll(ch_name + ":", "");
} */
if (!power_user.allow_name2_display && ch_name && !isUser && !isSystem) {
mes = mes.replaceAll(`${ch_name}:`, "");
}
return mes;
}
@@ -1057,13 +1057,13 @@ function addOneMessage(mes, { type = "normal", insertAfter = null, scroll = true
if (count_view_mes == 0) {
messageText = substituteParams(messageText);
}
messageText = messageFormating(
messageText = messageFormatting(
messageText,
characterName,
isSystem,
mes.force_avatar
mes.is_user,
);
const bias = messageFormating(mes.extra?.bias ?? "");
const bias = messageFormatting(mes.extra?.bias ?? "");
let params = {
mesId: count_view_mes,
@@ -1356,6 +1356,8 @@ function applyFavFilter(enabled) {
}
}
class StreamingProcessor {
showStopButton(messageId) {
if (messageId == -1) {
@@ -1392,8 +1394,24 @@ class StreamingProcessor {
return messageId;
}
removePrefix(text) {
const name1Marker = `${name1}: `;
const name2Marker = `${name2}: `;
if (text) {
if (text.startsWith(name1Marker)) {
text = text.replace(name1Marker, '');
}
if (text.startsWith(name2Marker)) {
text = text.replace(name2Marker, '');
}
}
return text;
}
onProgressStreaming(messageId, text) {
const isImpersonate = this.type == "impersonate";
text = this.removePrefix(text);
let processedText = cleanUpMessage(text, isImpersonate);
let result = extractNameFromMessage(processedText, this.force_name2, isImpersonate);
let isName = result.this_mes_is_name;
@@ -1414,7 +1432,12 @@ class StreamingProcessor {
chat[messageId]['swipes'][chat[messageId]['swipe_id']] = processedText;
}
let formattedText = messageFormating(processedText, chat[messageId].name, chat[messageId].is_system, chat[messageId].force_avatar);
let formattedText = messageFormatting(
processedText,
chat[messageId].name,
chat[messageId].is_system,
chat[messageId].is_user,
);
const mesText = $(`#chat .mes[mesid="${messageId}"] .mes_text`);
mesText.html(formattedText);
$(`#chat .mes[mesid="${messageId}"] .mes_timer`).text(timePassed.timerValue).attr('title', timePassed.timerTitle);
@@ -1627,10 +1650,11 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
addOneMessage(chat[chat.length - 1]);
}
////////////////////////////////////
let charDescription = baseChatReplace($.trim(characters[this_chid].description), name1, name2);
let charPersonality = baseChatReplace($.trim(characters[this_chid].personality), name1, name2);
let Scenario = baseChatReplace($.trim(characters[this_chid].scenario), name1, name2);
let mesExamples = baseChatReplace($.trim(characters[this_chid].mes_example), name1, name2);
const scenarioText = chat_metadata['scenario'] || characters[this_chid].scenario;
let charDescription = baseChatReplace(characters[this_chid].description.trim(), name1, name2);
let charPersonality = baseChatReplace(characters[this_chid].personality.trim(), name1, name2);
let Scenario = baseChatReplace(scenarioText.trim(), name1, name2);
let mesExamples = baseChatReplace(characters[this_chid].mes_example.trim(), name1, name2);
// Parse example messages
if (!mesExamples.startsWith('<START>')) {
@@ -1777,7 +1801,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
allAnchors,
quiet_prompt,
].join('').replace(/\r/gm, '');
return getTokenCount(encodeString, padding_tokens) < this_max_context;
return getTokenCount(encodeString, power_user.token_padding) < this_max_context;
}
// Force pinned examples into the context
@@ -1834,7 +1858,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
arrMes = arrMes.reverse();
arrMes.forEach(function (item, i, arr) {//For added anchors and others
if (i === arrMes.length - 1 && $.trim(item).substr(0, (name1 + ":").length) != name1 + ":") {
if (i === arrMes.length - 1 && !item.trim().startsWith(name1 + ":")) {
if (textareaText == "") {
item = item.substr(0, item.length - 1);
}
@@ -1844,24 +1868,26 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
//anchorAndPersonality = "[Genre: roleplay chat][Tone: very long messages with descriptions]";
let personalityAndAnchor = [charPersonality, anchorTop].filter(x => x).join(' ');
if (personalityAndAnchor) {
item += "[" + personalityAndAnchor + ']\n';
item += "[" + personalityAndAnchor + "]\n";
}
}
if (i === arrMes.length - 1 && coreChat.length > bottomAnchorThreshold && $.trim(item).substr(0, (name1 + ":").length) == name1 + ":" && !is_pygmalion) {//For add anchor in end
item = item.substr(0, item.length - 1);
if (i === arrMes.length - 1 && coreChat.length > bottomAnchorThreshold && item.trim().startsWith(name1 + ":") && !is_pygmalion) {//For add anchor in end
//chatString+=postAnchor+"\n";//"[Writing style: very long messages]\n";
item = item + anchorBottom + "\n";
if (anchorBottom) {
item = item.replace(/\n$/, " ");
item += anchorBottom + "\n";
}
}
if (is_pygmalion) {
if (i === arrMes.length - 1 && $.trim(item).substr(0, (name1 + ":").length) == name1 + ":") {//for add name2 when user sent
if (i === arrMes.length - 1 && item.trim().startsWith(name1 + ":")) {//for add name2 when user sent
item = item + name2 + ":";
}
if (i === arrMes.length - 1 && $.trim(item).substr(0, (name1 + ":").length) != name1 + ":") {//for add name2 when continue
if (i === arrMes.length - 1 && !item.trim().startsWith(name1 + ":")) {//for add name2 when continue
if (textareaText == "") {
item = item + '\n' + name2 + ":";
}
}
if ($.trim(item).indexOf(name1) === 0) {
if (item.trim().startsWith(name1)) {
item = item.replace(name1 + ':', 'You:');
}
}
@@ -1930,7 +1956,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
allAnchors,
quiet_prompt,
].join('').replace(/\r/gm, '');
let thisPromtContextSize = getTokenCount(prompt, padding_tokens);
let thisPromtContextSize = getTokenCount(prompt, power_user.token_padding);
if (thisPromtContextSize > this_max_context) { //if the prepared prompt is larger than the max context size...
if (count_exm_add > 0) { // ..and we have example mesages..
@@ -2007,7 +2033,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
if (power_user.collapse_newlines) {
finalPromt = collapseNewlines(finalPromt);
}
//console.log(`---Calculated Prompt Tokens: ${getTokenCount(finalPromt, padding_tokens)}`);
let this_amount_gen = parseInt(amount_gen); // how many tokens the AI will be requested to generate
let this_settings = koboldai_settings[koboldai_setting_names[preset_settings]];
@@ -2338,7 +2363,7 @@ function shouldContinueMultigen(getMessage) {
function extractNameFromMessage(getMessage, force_name2, isImpersonate) {
const nameToTrim = isImpersonate ? name1 : name2;
let this_mes_is_name = true;
if (getMessage.indexOf(nameToTrim + ":") === 0) {
if (getMessage.startsWith(nameToTrim + ":")) {
getMessage = getMessage.replace(nameToTrim + ':', '');
getMessage = getMessage.trimStart();
} else {
@@ -2671,6 +2696,8 @@ async function renameCharacter() {
async function saveChat(chat_name, withMetadata) {
const metadata = { ...chat_metadata, ...(withMetadata || {}) };
let file_name = chat_name ?? characters[this_chid].chat;
characters[this_chid]['date_last_chat'] = Date.now();
sortCharactersList();
chat.forEach(function (item, i) {
if (item["is_group"]) {
alert('Trying to save group chat with regular saveChat function. Aborting to prevent corruption.');
@@ -2719,33 +2746,49 @@ async function saveChat(chat_name, withMetadata) {
});
}
function read_avatar_load(input) {
async function read_avatar_load(input) {
if (input.files && input.files[0]) {
const reader = new FileReader();
if (selected_button == "create") {
create_save_avatar = input.files;
}
reader.onload = function (e) {
if (selected_button == "character_edit") {
saveCharacterDebounced();
}
reader.onload = async function (e) {
$("#avatar_load_preview").attr("src", e.target.result);
//.width(103)
//.height(83);
//console.log(e.target.result.name);
};
reader.readAsDataURL(input.files[0]);
if (menu_type != "create") {
$("#create_button").trigger('click');
if (this_chid) {
fetch(getThumbnailUrl('avatar', characters[this_chid].avatar), {
const formData = new FormData($("#form_create").get(0));
$(".mes").each(async function () {
if ($(this).attr("is_system") == 'true') {
return;
}
if ($(this).attr("is_user") == 'true') {
return;
}
if ($(this).attr("ch_name") == formData.get('ch_name')) {
const previewSrc = $("#avatar_load_preview").attr("src");
const avatar = $(this).find(".avatar img");
avatar.attr('src', default_avatar);
await delay(1);
avatar.attr('src', previewSrc);
}
});
await delay(durationSaveEdit);
await fetch(getThumbnailUrl('avatar', formData.get('avatar_url')), {
method: 'GET',
headers: {
'pragma': 'no-cache',
'cache-control': 'no-cache',
}
}).then(() => console.log('Avatar refreshed'));
});
console.log('Avatar refreshed');
}
};
reader.readAsDataURL(input.files[0]);
}
}
@@ -3238,6 +3281,9 @@ function messageEditAuto(div) {
var text = mesBlock.find(".edit_textarea").val().trim();
const bias = extractMessageBias(text);
chat[this_edit_mes_id]["mes"] = text;
if (chat[this_edit_mes_id]["swipe_id"] !== undefined) {
chat[this_edit_mes_id]["swipes"][chat[this_edit_mes_id]["swipe_id"]] = text;
}
// editing old messages
if (!chat[this_edit_mes_id]["extra"]) {
@@ -3245,7 +3291,12 @@ function messageEditAuto(div) {
}
chat[this_edit_mes_id]["extra"]["bias"] = bias ?? null;
mesBlock.find(".mes_text").val('');
mesBlock.find(".mes_text").val(messageFormating(text, this_edit_mes_chname, chat[this_edit_mes_id].is_system, chat[this_edit_mes_id].force_avatar));
mesBlock.find(".mes_text").val(messageFormatting(
text,
this_edit_mes_chname,
chat[this_edit_mes_id].is_system,
chat[this_edit_mes_id].is_user,
));
saveChatDebounced();
}
@@ -3254,6 +3305,9 @@ function messageEditDone(div) {
var text = mesBlock.find(".edit_textarea").val().trim();
const bias = extractMessageBias(text);
chat[this_edit_mes_id]["mes"] = text;
if (chat[this_edit_mes_id]["swipe_id"] !== undefined) {
chat[this_edit_mes_id]["swipes"][chat[this_edit_mes_id]["swipe_id"]] = text;
}
// editing old messages
if (!chat[this_edit_mes_id]["extra"]) {
@@ -3266,10 +3320,15 @@ function messageEditDone(div) {
mesBlock.find(".mes_edit_buttons").css("display", "none");
mesBlock.find(".mes_edit").css("display", "inline-block");
mesBlock.find(".mes_text").append(
messageFormating(text, this_edit_mes_chname, chat[this_edit_mes_id].is_system, chat[this_edit_mes_id].force_avatar)
messageFormatting(
text,
this_edit_mes_chname,
chat[this_edit_mes_id].is_system,
chat[this_edit_mes_id].is_user,
)
);
mesBlock.find(".mes_bias").empty();
mesBlock.find(".mes_bias").append(messageFormating(bias));
mesBlock.find(".mes_bias").append(messageFormatting(bias));
appendImageToMessage(chat[this_edit_mes_id], div.closest(".mes"));
addCopyToCodeBlocks(div.closest(".mes"));
this_edit_mes_id = undefined;
@@ -3396,7 +3455,13 @@ function selectRightMenuWithAnimation(selectedMenuId) {
easing: animation_easing,
complete: function () { },
});
// $(menu).find('#groupCurrentMemberListToggle').click();
}
})
}
@@ -3554,6 +3619,7 @@ function updateFavButtonState(state) {
$("#fav_checkbox").val(fav_ch_checked);
$("#favorite_button").toggleClass('fav_on', fav_ch_checked);
$("#favorite_button").toggleClass('fav_off', !fav_ch_checked);
}
function callPopup(text, type, inputValue = '') {
@@ -3818,8 +3884,11 @@ window["SillyTavern"].getContext = function () {
};
};
$(document).ready(function () {
//////////INPUT BAR FOCUS-KEEPING LOGIC/////////////
let S_TAFocused = false;
@@ -4602,25 +4671,7 @@ $(document).ready(function () {
cache: false,
contentType: false,
processData: false,
success: function (html) {
/* Cohee: Not needed, since the rename routine forcefully reloads the chat
//currently this updates the displayed H2 name regardless of soft errors, doesn't detect actual errors.
let h2text = $("#character_name_pole").val();
console.log('about to change name! in h2');
$("#rm_button_selected_ch").children("h2").text(h2text);
*/
$(".mes").each(function () {
if ($(this).attr("is_system") == 'true') {
return;
}
if ($(this).attr("ch_name") != name1) {
$(this)
.children(".avatar")
.children("img")
.attr("src", $("#avatar_load_preview").attr("src"));
}
});
success: async function (html) {
if (chat.length === 1) {
var this_ch_mes = default_ch_mes;
if ($("#firstmessage_textarea").val() != "") {
@@ -4649,7 +4700,7 @@ $(document).ready(function () {
}
}
$("#create_button").removeAttr("disabled");
getCharacters();
await getCharacters();
$("#add_avatar_button").replaceWith(
$("#add_avatar_button").val("").clone(true)
@@ -4704,6 +4755,7 @@ $(document).ready(function () {
updateFavButtonState(!fav_ch_checked);
if (menu_type != "create") {
saveCharacterDebounced();
}
});
@@ -5204,7 +5256,12 @@ $(document).ready(function () {
$(this)
.closest(".mes_block")
.find(".mes_text")
.append(messageFormating(text, this_edit_mes_chname, chat[this_edit_mes_id].is_system, chat[this_edit_mes_id].force_avatar));
.append(messageFormatting(
text,
this_edit_mes_chname,
chat[this_edit_mes_id].is_system,
chat[this_edit_mes_id].is_user,
));
appendImageToMessage(chat[this_edit_mes_id], $(this).closest(".mes"));
addCopyToCodeBlocks($(this).closest(".mes"));
this_edit_mes_id = undefined;
@@ -5532,7 +5589,7 @@ $(document).ready(function () {
icon.toggleClass('openIcon closedIcon');
drawer.toggleClass('openDrawer closedDrawer');
console.log(targetDrawerID);
//console.log(targetDrawerID);
if (targetDrawerID === 'right-nav-panel') {
$(this).closest('.drawer').find('.drawer-content').slideToggle({
duration: 200,

View File

@@ -12,16 +12,24 @@ import {
is_send_press,
getTokenCount,
menu_type,
selectRightMenuWithAnimation,
select_selected_character,
setCharacterId,
} from "../script.js";
import {
select_group_chats,
} from "./group-chats.js";
import {
power_user,
send_on_enter_options,
} from "./power-user.js";
import { LoadLocal, SaveLocal, ClearLocal, CheckLocal, LoadLocalBool } from "./f-localStorage.js";
import { selected_group, is_group_generating } from "./group-chats.js";
import { selected_group, is_group_generating, getGroupAvatar, groups } from "./group-chats.js";
import { oai_settings } from "./openai.js";
import { poe_settings } from "./poe.js";
@@ -255,42 +263,74 @@ export function RA_CountCharTokens() {
//Auto Load Last Charcter -- (fires when active_character is defined and auto_load_chat is true)
async function RA_autoloadchat() {
if (document.getElementById('CharID0') !== null) {
//console.log('char list loaded! clicking activeChar');
var CharToAutoLoad = document.getElementById('CharID' + LoadLocal('ActiveChar'));
//console.log(CharToAutoLoad);
let autoLoadGroup = document.querySelector(`.group_select[grid="${LoadLocal('ActiveGroup')}"]`);
//console.log(autoLoadGroup);
if (CharToAutoLoad != null) {
var charToAutoLoad = document.getElementById('CharID' + LoadLocal('ActiveChar'));
let groupToAutoLoad = document.querySelector(`.group_select[grid="${LoadLocal('ActiveGroup')}"]`);
if (charToAutoLoad != null) { $(charToAutoLoad).click(); }
else if (groupToAutoLoad != null) { $(groupToAutoLoad).click(); }
// if the charcter list hadn't been loaded yet, try again.
} else { setTimeout(RA_autoloadchat, 100); }
}
// console.log('--ALC - clicking character');
CharToAutoLoad.click();
CharToAutoLoad.click();
export async function favsToHotswap() {
const selector = ['#rm_print_characters_block .character_select', '#rm_print_characters_block .group_select'].join(',');
const container = $('#rm_PinAndTabs .hotswap');
const template = $('#hotswap_template .hotswapAvatar');
container.empty();
const maxCount = 6;
let count = 0;
$(selector).each(function () {
if ($(this).hasClass('is_fav') && count < maxCount) {
const isCharacter = $(this).hasClass('character_select');
const isGroup = $(this).hasClass('group_select');
const grid = Number($(this).attr('grid'));
const chid = Number($(this).attr('chid'));
let thisHotSwapSlot = template.clone();
thisHotSwapSlot.toggleClass('character_select', isCharacter);
thisHotSwapSlot.toggleClass('group_select', isGroup);
thisHotSwapSlot.attr('grid', isGroup ? grid : '');
thisHotSwapSlot.attr('chid', isCharacter ? chid : '');
thisHotSwapSlot.data('id', isGroup ? grid : chid);
if (isGroup) {
const group = groups.find(x => x.id === grid);
const avatar = getGroupAvatar(group);
$(thisHotSwapSlot).find('img').replaceWith(avatar);
}
else if (autoLoadGroup != null) {
//console.log('--ALC - clicking group');
autoLoadGroup.click();
autoLoadGroup.click();
if (isCharacter) {
const avatarUrl = $(this).find('img').attr('src');
$(thisHotSwapSlot).find('img').attr('src', avatarUrl);
}
else {
console.log(CharToAutoLoad + ' ActiveChar local var - not found: ' + LoadLocal('ActiveChar'));
$(thisHotSwapSlot).css('cursor', 'pointer');
container.append(thisHotSwapSlot);
count++;
}
});
//console.log('about to check for leftover selectors...')
// there are 6 slots in total,
if (count < maxCount) { //if any are left over
let leftOverSlots = maxCount - count;
for (let i = 1; i <= leftOverSlots; i++) {
container.append(template.clone());
}
RestoreNavTab();
} else {
//console.log('no char list yet..');
setTimeout(RA_autoloadchat, 100); // if the charcter list hadn't been loaded yet, try again.
//console.log(`count was ${count} so no need to knock off any selectors!`);
}
}
//only triggers when AutoLoadChat is enabled, consider adding this as an independent feature later.
function RestoreNavTab() {
if ($('#rm_button_selected_ch').children("h2").text() !== '') { //check for a change in the character edit tab name
//console.log('detected ALC char finished loaded, proceeding to restore tab.');
$(SelectedNavTab).click(); //click to restore saved tab when name has changed (signalling char load is done)
/* function RestoreNavTab() {
if ($('#rm_button_selected_ch').children("h2").text() !== '') {
$(SelectedNavTab).click();
} else {
setTimeout(RestoreNavTab, 100); //if not changed yet, check again after 100ms
setTimeout(RestoreNavTab, 100);
}
}
} */
//changes input bar and send button display depending on connection status
function RA_checkOnlineStatus() {
if (online_status == "no_connection") {
@@ -376,7 +416,7 @@ function isUrlOrAPIKey(string) {
function OpenNavPanels() {
//auto-open R nav if locked and previously open
if (LoadLocalBool("NavLockOn") == true && LoadLocalBool("NavOpened") == true) {
console.log("RA -- clicking right nav to open");
//console.log("RA -- clicking right nav to open");
$("#rightNavDrawerIcon").click();
} else {
/* console.log('didnt see reason to open right nav on load: R-nav locked? ' +
@@ -555,7 +595,11 @@ $("document").ready(function () {
$(AutoConnectCheckbox).prop("checked", LoadLocalBool("AutoConnectEnabled"));
$(AutoLoadChatCheckbox).prop("checked", LoadLocalBool("AutoLoadChatEnabled"));
setTimeout(function () {
if (LoadLocalBool('AutoLoadChatEnabled') == true) { RA_autoloadchat(); }
}, 200);
//Autoconnect on page load if enabled, or when api type is changed
if (LoadLocalBool("AutoConnectEnabled") == true) { RA_autoconnect(); }
$("#main_api").change(function () {
@@ -568,10 +612,10 @@ $("document").ready(function () {
$(RPanelPin).on("click", function () {
SaveLocal("NavLockOn", $(RPanelPin).prop("checked"));
if ($(RPanelPin).prop("checked") == true) {
console.log('adding pin class to right nav');
//console.log('adding pin class to right nav');
$(RightNavPanel).addClass('pinnedOpen');
} else {
console.log('removing pin class from right nav');
//console.log('removing pin class from right nav');
$(RightNavPanel).removeClass('pinnedOpen');
if ($(RightNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {
@@ -584,10 +628,10 @@ $("document").ready(function () {
$(LPanelPin).on("click", function () {
SaveLocal("LNavLockOn", $(LPanelPin).prop("checked"));
if ($(LPanelPin).prop("checked") == true) {
console.log('adding pin class to Left nav');
//console.log('adding pin class to Left nav');
$(LeftNavPanel).addClass('pinnedOpen');
} else {
console.log('removing pin class from Left nav');
//console.log('removing pin class from Left nav');
$(LeftNavPanel).removeClass('pinnedOpen');
if ($(LeftNavPanel).hasClass('openDrawer') && $('.openDrawer').length > 1) {
@@ -651,10 +695,7 @@ $("document").ready(function () {
$(AutoLoadChatCheckbox).on("change", function () { SaveLocal("AutoLoadChatEnabled", $(AutoLoadChatCheckbox).prop("checked")); });
$(SelectedCharacterTab).click(function () { SaveLocal('SelectedNavTab', 'rm_button_selected_ch'); });
$("#rm_button_characters").click(function () { //if char list is clicked, in addition to saving it...
SaveLocal('SelectedNavTab', 'rm_button_characters');
characters.sort(Intl.Collator().compare); // we sort the list
});
$("#rm_button_characters").click(function () { SaveLocal('SelectedNavTab', 'rm_button_characters'); });
// when a char is selected from the list, save them as the auto-load character for next page load
$(document).on("click", ".character_select", function () {

View File

@@ -160,7 +160,7 @@ async function connectToApi(baseUrl) {
if (getExtensionsResult.ok) {
const data = await getExtensionsResult.json();
modules = data.modules;
activateExtensions();
await activateExtensions();
}
updateStatus(getExtensionsResult.ok);
@@ -273,12 +273,15 @@ async function loadExtensionSettings(settings) {
}
$("#extensions_url").val(extension_settings.apiUrl);
$("#extensions_autoconnect").prop('checked', extension_settings.autoConnect).trigger('input');
$("#extensions_autoconnect").prop('checked', extension_settings.autoConnect);
// Activate offline extensions
extensionNames = await discoverExtensions();
manifests = await getManifests(extensionNames)
activateExtensions();
await activateExtensions();
if (extension_settings.autoConnect && extension_settings.apiUrl) {
await connectToApi(extension_settings.apiUrl);
}
}
$(document).ready(async function () {

View File

@@ -1,5 +1,6 @@
import { callPopup, saveSettingsDebounced } from '../../../script.js'
import { callPopup, is_send_press, saveSettingsDebounced } from '../../../script.js'
import { extension_settings, getContext } from '../../extensions.js'
import { is_group_generating } from '../../group-chats.js'
import { getStringHash } from '../../utils.js'
import { ElevenLabsTtsProvider } from './elevenlabs.js'
import { SileroTtsProvider } from './silerotts.js'
@@ -43,6 +44,11 @@ async function moduleWorker() {
return
}
// Message is currently being generated
if (is_send_press || is_group_generating) {
return;
}
// Chat/character/group changed
if (
(context.groupId && lastGroupId !== context.groupId) ||
@@ -115,7 +121,7 @@ async function playAudioData(audioBlob) {
window['tts_preview'] = function (id) {
const audio = document.getElementById(id)
if (!audio.hidden) {
if (!$(audio).data('disabled')) {
audio.play()
}
else {
@@ -131,7 +137,7 @@ async function onTtsVoicesClick() {
for (const voice of voiceIds) {
popupText += `<div class="voice_preview"><span class="voice_lang">${voice.lang || ''}</span> <b class="voice_name">${voice.name}</b> <i onclick="tts_preview('${voice.voice_id}')" class="fa-solid fa-play"></i></div>`
popupText += `<audio id="${voice.voice_id}" src="${voice.preview_url}" hidden="${!!voice.preview_url}"></audio>`
popupText += `<audio id="${voice.voice_id}" src="${voice.preview_url}" data-disabled="${voice.preview_url == false}"></audio>`
}
} catch {
popupText = 'Could not load voices list. Check your API key.'
@@ -235,7 +241,7 @@ async function processTtsQueue() {
console.debug('New message found, running TTS')
currentTtsJob = ttsJobQueue.shift()
const text = currentTtsJob.mes.replaceAll('*', '...')
const text = currentTtsJob.mes.replaceAll('*', '')
const char = currentTtsJob.name
try {

View File

@@ -87,7 +87,7 @@ class SystemTtsProvider {
return speechSynthesis
.getVoices()
.sort((a, b) => a.lang.localeCompare(b.lang) || a.name.localeCompare(b.name))
.map(x => ({ name: x.name, voice_id: x.voiceURI, preview_url: '', lang: x.lang }));
.map(x => ({ name: x.name, voice_id: x.voiceURI, preview_url: false, lang: x.lang }));
}
previewTtsVoice(voiceId) {

View File

@@ -5,7 +5,7 @@ import {
delay,
} from './utils.js';
import { RA_CountCharTokens, humanizedDateTime } from "./RossAscends-mods.js";
import { sortCharactersList } from './power-user.js';
import { sortCharactersList, sortGroupMembers } from './power-user.js';
import {
chat,
@@ -191,6 +191,7 @@ function resetSelectedGroup() {
async function saveGroupChat(groupId, shouldSaveGroup) {
const group = groups.find(x => x.id == groupId);
const chat_id = group.chat_id;
group['date_last_chat'] = Date.now();
const response = await fetch("/savegroupchat", {
method: "POST",
headers: getRequestHeaders(),
@@ -200,6 +201,7 @@ async function saveGroupChat(groupId, shouldSaveGroup) {
if (shouldSaveGroup && response.ok) {
await editGroup(groupId);
}
sortCharactersList();
}
export async function renameGroupMember(oldAvatar, newAvatar, newName) {
@@ -449,11 +451,11 @@ async function generateGroupWrapper(by_auto_mode, type = null, force_chid = null
const resolveOriginal = params.resolve;
const rejectOriginal = params.reject;
params.resolve = function() {
params.resolve = function () {
isQuietGenDone = true;
resolveOriginal.apply(this, arguments);
};
params.reject = function() {
params.reject = function () {
isQuietGenDone = true;
rejectOriginal.apply(this, arguments);
}
@@ -898,7 +900,7 @@ function select_group_chats(groupId, skipAnimation) {
}
}
sortCharactersList("#rm_group_add_members .group_member");
sortGroupMembers("#rm_group_add_members .group_member");
filterMembersByFavorites(false);
const groupHasMembers = !!$("#rm_group_members").children().length;
@@ -909,9 +911,11 @@ function select_group_chats(groupId, skipAnimation) {
if (groupId) {
$("#rm_group_submit").hide();
$("#rm_group_delete").show();
$("#rm_group_scenario").show();
} else {
$("#rm_group_submit").show();
$("#rm_group_delete").hide();
$("#rm_group_scenario").hide();
}
$("#rm_group_delete").off();
@@ -986,7 +990,7 @@ function select_group_chats(groupId, skipAnimation) {
}
}
sortCharactersList("#rm_group_add_members .group_member");
sortGroupMembers("#rm_group_add_members .group_member");
});
}
@@ -1192,10 +1196,12 @@ export async function openGroupChat(groupId, chatId) {
group.past_metadata[previousChat] = Object.assign({}, chat_metadata);
group.chat_id = chatId;
group.chat_metadata = group.past_metadata[chatId] || {};
group['date_last_chat'] = Date.now();
updateChatMetadata(group.chat_metadata, true);
await editGroup(groupId, true);
await getGroupChat(groupId);
sortCharactersList();
}
export async function renameGroupChat(groupId, oldChatId, newChatId) {
@@ -1264,11 +1270,35 @@ export async function saveGroupBookmarkChat(groupId, name, metadata) {
});
}
function setGroupScenario() {
if (!selected_group) {
return;
}
const template = $('#group_scenario_template .group_scenario').clone();
const metadataValue = chat_metadata['scenario'] || '';
template.find('.group_chat_scenario').text(metadataValue);
callPopup(template.get(0).outerHTML, 'text');
}
function onGroupScenarioInput() {
const value = $(this).val();
const metadata = { scenario: value, };
updateChatMetadata(metadata, false);
}
function onGroupScenarioRemoveClick() {
$(this).closest('.group_scenario').find('.group_chat_scenario').val('').trigger('input');
}
jQuery(() => {
$(document).on("click", ".group_select", selectGroup);
$(document).on("input", ".group_chat_scenario", onGroupScenarioInput);
$(document).on("click", ".remove_scenario_override", onGroupScenarioRemoveClick);
$("#rm_group_filter").on("input", filterGroupMembers);
$("#group_fav_filter").on("click", toggleFilterByFavorites);
$("#rm_group_submit").on("click", createGroup);
$("#rm_group_scenario").on("click", setGroupScenario);
$("#rm_group_automode").on("input", function () {
const value = $(this).prop("checked");
is_group_automode_enabled = value;

View File

@@ -25,6 +25,7 @@ import {
} from "./power-user.js";
import {
delay,
download,
getStringHash,
parseJsonFile,
@@ -79,6 +80,7 @@ const default_settings = {
temp_openai: 0.9,
freq_pen_openai: 0.7,
pres_pen_openai: 0.7,
top_p_openai: 1.0,
stream_openai: false,
openai_max_context: gpt3_max,
openai_max_tokens: 300,
@@ -103,6 +105,7 @@ const oai_settings = {
temp_openai: 1.0,
freq_pen_openai: 0,
pres_pen_openai: 0,
top_p_openai: 1.0,
stream_openai: false,
openai_max_context: gpt3_max,
openai_max_tokens: 300,
@@ -204,9 +207,11 @@ function generateOpenAIPromptCache(charPersonality, topAnchorDepth, anchorTop, b
item = `[${name2} is ${personalityAndAnchor}]\n${item}`;
}
}
if (i === openai_msgs.length - 1 && openai_msgs.length > bottomAnchorThreshold && $.trim(item).substr(0, (name1 + ":").length) == name1 + ":") {//For add anchor in end
if (i === openai_msgs.length - 1 && openai_msgs.length > bottomAnchorThreshold && msg.role === "user") {//For add anchor in end
if (anchorBottom) {
item = anchorBottom + "\n" + item;
}
}
msg["content"] = item;
openai_msgs[i] = msg;
@@ -238,14 +243,14 @@ function parseExampleIntoIndividual(messageExampleString) {
let cur_str = tmp[i];
// if it's the user message, switch into user mode and out of bot mode
// yes, repeated code, but I don't care
if (cur_str.indexOf(name1 + ":") === 0) {
if (cur_str.startsWith(name1 + ":")) {
in_user = true;
// we were in the bot mode previously, add the message
if (in_bot) {
add_msg(name2, "system", "example_assistant");
}
in_bot = false;
} else if (cur_str.indexOf(name2 + ":") === 0) {
} else if (cur_str.startsWith(name2 + ":")) {
in_bot = true;
// we were in the user mode previously, add the message
if (in_user) {
@@ -306,12 +311,15 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
// todo: static value, maybe include in the initial context calculation
let new_chat_msg = { "role": "system", "content": "[Start a new chat]" };
let start_chat_count = countTokens([new_chat_msg], true);
await delay(1);
let total_count = countTokens([prompt_msg], true) + start_chat_count;
await delay(1);
if (bias && bias.trim().length) {
let bias_msg = { "role": "system", "content": bias.trim() };
openai_msgs.push(bias_msg);
total_count += countTokens([bias_msg], true);
await delay(1);
}
if (selected_group) {
@@ -328,11 +336,13 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
// add a group nudge count
let group_nudge_count = countTokens([group_nudge], true);
await delay(1);
total_count += group_nudge_count;
// recount tokens for new start message
total_count -= start_chat_count
start_chat_count = countTokens([new_chat_msg], true);
await delay(1);
total_count += start_chat_count;
}
@@ -341,6 +351,7 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
openai_msgs.push(jailbreakMessage);
total_count += countTokens([jailbreakMessage], true);
await delay(1);
}
if (isImpersonate) {
@@ -348,6 +359,7 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
openai_msgs.push(impersonateMessage);
total_count += countTokens([impersonateMessage], true);
await delay(1);
}
// The user wants to always have all example messages in the context
@@ -370,10 +382,12 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
}
}
total_count += countTokens(examples_tosend, true);
await delay(1);
// go from newest message to oldest, because we want to delete the older ones from the context
for (let j = openai_msgs.length - 1; j >= 0; j--) {
let item = openai_msgs[j];
let item_count = countTokens(item, true);
await delay(1);
// If we have enough space for this message, also account for the max assistant reply size
if ((total_count + item_count) < (this_max_context - oai_settings.openai_max_tokens)) {
openai_msgs_tosend.push(item);
@@ -388,6 +402,7 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
for (let j = openai_msgs.length - 1; j >= 0; j--) {
let item = openai_msgs[j];
let item_count = countTokens(item, true);
await delay(1);
// If we have enough space for this message, also account for the max assistant reply size
if ((total_count + item_count) < (this_max_context - oai_settings.openai_max_tokens)) {
openai_msgs_tosend.push(item);
@@ -410,6 +425,7 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI
// add the block only if there is enough space for all its messages
const example_count = countTokens(example_block, true);
await delay(1);
if ((total_count + example_count) < (this_max_context - oai_settings.openai_max_tokens)) {
examples_tosend.push(...example_block)
total_count += example_count;
@@ -511,6 +527,7 @@ async function sendOpenAIRequest(type, openai_msgs_tosend, signal) {
"temperature": parseFloat(oai_settings.temp_openai),
"frequency_penalty": parseFloat(oai_settings.freq_pen_openai),
"presence_penalty": parseFloat(oai_settings.pres_pen_openai),
"top_p": parseFloat(oai_settings.top_p_openai),
"max_tokens": oai_settings.openai_max_tokens,
"stream": stream,
"reverse_proxy": oai_settings.reverse_proxy,
@@ -660,6 +677,7 @@ function loadOpenAISettings(data, settings) {
oai_settings.temp_openai = settings.temp_openai ?? default_settings.temp_openai;
oai_settings.freq_pen_openai = settings.freq_pen_openai ?? default_settings.freq_pen_openai;
oai_settings.pres_pen_openai = settings.pres_pen_openai ?? default_settings.pres_pen_openai;
oai_settings.top_p_openai = settings.top_p_openai ?? default_settings.top_p_openai;
oai_settings.stream_openai = settings.stream_openai ?? default_settings.stream_openai;
oai_settings.openai_max_context = settings.openai_max_context ?? default_settings.openai_max_context;
oai_settings.openai_max_tokens = settings.openai_max_tokens ?? default_settings.openai_max_tokens;
@@ -707,6 +725,9 @@ function loadOpenAISettings(data, settings) {
$('#pres_pen_openai').val(oai_settings.pres_pen_openai);
$('#pres_pen_counter_openai').text(Number(oai_settings.pres_pen_openai).toFixed(2));
$('#top_p_openai').val(oai_settings.top_p_openai);
$('#top_p_counter_openai').text(Number(oai_settings.top_p_openai).toFixed(2));
if (settings.reverse_proxy !== undefined) oai_settings.reverse_proxy = settings.reverse_proxy;
$('#openai_reverse_proxy').val(oai_settings.reverse_proxy);
@@ -792,6 +813,7 @@ async function saveOpenAIPreset(name, settings) {
temperature: settings.temp_openai,
frequency_penalty: settings.freq_pen_openai,
presence_penalty: settings.pres_pen_openai,
top_p: settings.top_p_openai,
openai_max_context: settings.openai_max_context,
openai_max_tokens: settings.openai_max_tokens,
nsfw_toggle: settings.nsfw_toggle,
@@ -1056,6 +1078,7 @@ function onSettingsPresetChange() {
temperature: ['#temp_openai', 'temp_openai', false],
frequency_penalty: ['#freq_pen_openai', 'freq_pen_openai', false],
presence_penalty: ['#pres_pen_openai', 'pres_pen_openai', false],
top_p: ['#top_p_openai', 'top_p_openai', false],
openai_model: ['#model_openai_select', 'openai_model', false],
openai_max_context: ['#openai_max_context', 'openai_max_context', false],
openai_max_tokens: ['#openai_max_tokens', 'openai_max_tokens', false],
@@ -1160,6 +1183,13 @@ $(document).ready(function () {
});
$(document).on('input', '#top_p_openai', function () {
oai_settings.top_p_openai = $(this).val();
$('#top_p_counter_openai').text(Number($(this).val()).toFixed(2));
saveSettingsDebounced();
});
$(document).on('input', '#openai_max_context', function () {
oai_settings.openai_max_context = parseInt($(this).val());
$('#openai_max_context_counter').text(`${$(this).val()}`);

View File

@@ -8,11 +8,15 @@ import {
reloadCurrentChat,
getRequestHeaders,
} from "../script.js";
import {
groups,
} from "./group-chats.js";
export {
loadPowerUserSettings,
collapseNewlines,
playMessageSound,
sortGroupMembers,
sortCharactersList,
fixMarkdown,
power_user,
@@ -57,6 +61,7 @@ const send_on_enter_options = {
let power_user = {
tokenizer: tokenizers.CLASSIC,
token_padding: 64,
collapse_newlines: false,
pygmalion_formatting: pygmalion_options.AUTO,
pin_examples: false,
@@ -100,6 +105,9 @@ let power_user = {
auto_fix_generated_markdown: true,
send_on_enter: send_on_enter_options.AUTO,
render_formulas: false,
allow_name2_display: false,
hotswap_enabled: true,
timer_enabled: true,
};
let themes = [];
@@ -123,6 +131,9 @@ const storage_keys = {
waifuMode: "TavernAI_waifuMode",
movingUI: "TavernAI_movingUI",
noShadows: "TavernAI_noShadows",
hotswap_enabled: 'HotswapEnabled',
timer_enabled: 'TimerEnabled',
};
let browser_has_focus = true;
@@ -179,6 +190,18 @@ function fixMarkdown(text) {
return newText;
}
function switchHotswap() {
const value = localStorage.getItem(storage_keys.hotswap_enabled);
power_user.hotswap_enabled = value === null ? true : value == "true";
$("body").toggleClass("no-hotswap", !power_user.hotswap_enabled);
}
function switchTimer() {
const value = localStorage.getItem(storage_keys.timer_enabled);
power_user.timer_enabled = value === null ? true : value == "true";
$("body").toggleClass("no-timer", !power_user.timer_enabled);
}
function switchUiMode() {
const fastUi = localStorage.getItem(storage_keys.fast_ui_mode);
power_user.fast_ui_mode = fastUi === null ? true : fastUi == "true";
@@ -321,6 +344,8 @@ applyChatDisplay();
switchWaifuMode()
switchMovingUI();
noShadows();
switchHotswap();
switchTimer();
function loadPowerUserSettings(settings, data) {
// Load from settings.json
@@ -337,10 +362,14 @@ function loadPowerUserSettings(settings, data) {
const waifuMode = localStorage.getItem(storage_keys.waifuMode);
const movingUI = localStorage.getItem(storage_keys.movingUI);
const noShadows = localStorage.getItem(storage_keys.noShadows);
const hotswap = localStorage.getItem(storage_keys.hotswap_enabled);
const timer = localStorage.getItem(storage_keys.timer_enabled);
power_user.fast_ui_mode = fastUi === null ? true : fastUi == "true";
power_user.waifuMode = waifuMode === null ? false : waifuMode == "true";
power_user.movingUI = movingUI === null ? false : movingUI == "true";
power_user.noShadows = noShadows === null ? false : noShadows == "true";
power_user.hotswap_enabled = hotswap === null ? true : hotswap == "true";
power_user.timer_enabled = timer === null ? true : timer == "true";
power_user.avatar_style = Number(localStorage.getItem(storage_keys.avatar_style) ?? avatar_styles.ROUND);
power_user.chat_display = Number(localStorage.getItem(storage_keys.chat_display) ?? chat_styles.DEFAULT);
power_user.sheld_width = Number(localStorage.getItem(storage_keys.sheld_width) ?? sheld_width.DEFAULT);
@@ -372,9 +401,13 @@ function loadPowerUserSettings(settings, data) {
$("#play_message_sound").prop("checked", power_user.play_message_sound);
$("#play_sound_unfocused").prop("checked", power_user.play_sound_unfocused);
$("#auto_save_msg_edits").prop("checked", power_user.auto_save_msg_edits);
$("#allow_name2_display").prop("checked", power_user.allow_name2_display);
$("#hotswapEnabled").prop("checked", power_user.hotswap_enabled);
$("#messageTimerEnabled").prop("checked", power_user.timer_enabled);
$(`input[name="avatar_style"][value="${power_user.avatar_style}"]`).prop("checked", true);
$(`input[name="chat_display"][value="${power_user.chat_display}"]`).prop("checked", true);
$(`input[name="sheld_width"][value="${power_user.sheld_width}"]`).prop("checked", true);
$("#token_padding").val(power_user.token_padding);
$("#font_scale").val(power_user.font_scale);
$("#font_scale_counter").text(power_user.font_scale);
@@ -405,9 +438,8 @@ function loadPowerUserSettings(settings, data) {
reloadMarkdownProcessor(power_user.render_formulas);
}
function sortCharactersList(selector = '.character_select') {
const sortFunc = (a, b) => power_user.sort_order == 'asc' ? compareFunc(a, b) : compareFunc(b, a);
const compareFunc = (first, second) => {
const sortFunc = (a, b) => power_user.sort_order == 'asc' ? compareFunc(a, b) : compareFunc(b, a);
const compareFunc = (first, second) => {
switch (power_user.sort_rule) {
case 'boolean':
return Number(first[power_user.sort_field] == "true") - Number(second[power_user.sort_field] == "true");
@@ -416,8 +448,36 @@ function sortCharactersList(selector = '.character_select') {
? first[power_user.sort_field].localeCompare(second[power_user.sort_field])
: first[power_user.sort_field] - second[power_user.sort_field];
}
};
};
function sortCharactersList() {
const arr1 = groups.map(x => ({
item: x,
id: x.id,
selector: '.group_select',
attribute: 'grid',
}))
const arr2 = characters.map((x, index) => ({
item: x,
id: index,
selector: '.character_select',
attribute: 'chid',
}));
const array = [...arr1, ...arr2];
if (power_user.sort_field == undefined || array.length === 0) {
return;
}
let orderedList = array.slice().sort((a, b) => sortFunc(a.item, b.item));
for (const item of array) {
$(`${item.selector}[${item.attribute}="${item.id}"]`).css({ 'order': orderedList.indexOf(item) });
}
}
function sortGroupMembers(selector) {
if (power_user.sort_field == undefined || characters.length === 0) {
return;
}
@@ -747,6 +807,31 @@ $(document).ready(() => {
saveSettingsDebounced();
})
$("#allow_name2_display").on("input", function () {
power_user.allow_name2_display = !!$(this).prop('checked');
reloadCurrentChat();
saveSettingsDebounced();
});
$("#token_padding").on("input", function () {
power_user.token_padding = Number($(this).val());
saveSettingsDebounced();
});
$("#messageTimerEnabled").on("input", function () {
const value = !!$(this).prop('checked');
power_user.timer_enabled = value;
localStorage.setItem(storage_keys.timer_enabled, power_user.timer_enabled);
switchTimer();
});
$("#hotswapEnabled").on("input", function () {
const value = !!$(this).prop('checked');
power_user.hotswap_enabled = value;
localStorage.setItem(storage_keys.hotswap_enabled, power_user.hotswap_enabled);
switchHotswap();
});
$(window).on('focus', function () {
browser_has_focus = true;
});

View File

@@ -558,12 +558,72 @@ code {
gap: 5px;
}
.avatar {
width: 50px;
height: 50px;
border-style: none;
}
.mes .avatar {
cursor: pointer;
}
.hotswap {
top: -5px;
}
.hotswapAvatar,
.hotswapAvatar .avatar {
width: 50px !important;
height: 50px !important;
border-style: none;
}
.hotswapAvatar {
opacity: 0.5;
transition: 250ms;
overflow: hidden;
padding: 0 !important;
order: 100;
}
.hotswapAvatar:hover {
opacity: 1;
background-color: transparent !important;
cursor: pointer;
}
.hotswapAvatar .avatar_collage,
.hotswapAvatar.group_select {
border-radius: 50% !important;
position: relative;
overflow: hidden;
min-width: 50px !important;
}
.hotswapAvatar.group_select .avatar img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
border: 1px solid var(--black30a);
/* border-radius: 10px; */
}
.hotswapAvatar .avatar {
width: 50px !important;
height: 50px !important;
object-fit: cover;
object-position: center center;
border-radius: 50% !important;
/* border: 1px solid var(--black30a); */
box-shadow: 0 0 5px var(--black50a);
}
.hotswapAvatar img,
.avatar img {
width: 50px;
height: 50px;
@@ -574,6 +634,14 @@ code {
box-shadow: 0 0 5px var(--black50a);
}
body.no-hotswap .hotswap {
display: none !important;
}
body.no-timer .mes_timer {
display: none !important;
}
body.big-avatars .avatar {
width: 60px;
height: 90px;
@@ -1857,6 +1925,7 @@ input[type='checkbox']:not(#nav-toggle):not(#rm_button_panel_pin) {
background-color: white;
box-shadow: inset 0 0 3px 0 var(--black70a);
cursor: pointer;
flex-shrink: 0;
}
/* the checkbox starts with a size 0 background of a checkmark */
@@ -2620,10 +2689,11 @@ body .ui-widget-content li:hover {
/* GROUP CHATS */
#rm_group_top_bar {
display: flex;
/* display: flex;
flex-direction: row;
width: 100%;
column-gap: 5px;
justify-content: space-evenly; */
}
#rm_button_group_chats h2 {
@@ -2639,10 +2709,11 @@ body .ui-widget-content li:hover {
#rm_group_chats_block {
display: none;
height: calc(100% - 45px);
flex-direction: column;
/* height: calc(100% - 45px);
flex-direction: column; */
align-items: flex-start;
padding: 0 5px;
overflow-y: auto;
}
#rm_group_chats_block h3,
@@ -2652,13 +2723,13 @@ body .ui-widget-content li:hover {
}
#rm_group_buttons {
display: flex;
/* display: flex;
flex-direction: row;
width: 100%;
align-items: center;
column-gap: 10px;
flex-wrap: wrap;
padding: 0 5px;
padding: 0 5px; */
}
#rm_group_buttons>div {
@@ -2689,13 +2760,6 @@ body .ui-widget-content li:hover {
#rm_group_add_members {
margin-top: 0.25rem;
margin-bottom: 0.5rem;
width: 100%;
flex: 1;
max-height: 40%;
min-height: 40%;
overflow: auto;
display: flex;
flex-direction: column;
border: 1px solid grey;
border-radius: 10px;
background-color: var(--black30a);
@@ -2755,10 +2819,11 @@ body .ui-widget-content li:hover {
}
.group_member_icon {
margin: 0 10px;
display: flex;
column-gap: 10px;
align-items: center;
justify-content: end;
flex-grow: 1;
}
.group_member {
@@ -3341,7 +3406,7 @@ label[for="extensions_autoconnect"] {
}
.inline-drawer {
padding-bottom: 10px;
/* padding-bottom: 10px; */
}
.code-copy {
@@ -3392,6 +3457,7 @@ label[for="extensions_autoconnect"] {
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 0;
}
.inline-drawer-content {
@@ -3417,7 +3483,7 @@ label[for="extensions_autoconnect"] {
position: absolute;
left: 0;
right: 0;
max-width: var(--sheldWidth);
/* max-width: var(--sheldWidth); */
margin: 35px auto 0 auto;
backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)));
-webkit-backdrop-filter: blur(calc(var(--SmartThemeBlurStrength)));
@@ -3479,10 +3545,6 @@ toolcool-color-picker {
flex-wrap: nowrap;
}
.flex1 {
flex: 1;
}
.alignitemscenter {
align-items: center;
}
@@ -3631,7 +3693,8 @@ toolcool-color-picker {
}
.openai_restorable,
.poe_restorable {
.poe_restorable,
.title_restorable {
display: flex;
flex-direction: row;
justify-content: space-between;
@@ -3841,6 +3904,51 @@ body.waifuMode #avatar_zoom_popup {
object-fit: cover;
}
.debug-red {
border: 1px solid red !important;
}
.debug-yellow {
border: 1px solid yellow !important;
}
.debug-green {
border: 1px solid green !important;
}
.debug-blue {
border: 1px solid blue !important;
}
.debug-purple {
border: 1px solid purple !important;
}
.fontsize80p {
font-size: calc(var(--mainFontSize) * 0.8) !important;
}
.fontsize60p {
font-size: calc(var(--mainFontSize) * 0.6) !important;
}
.paddingTopBot5 {
padding: 5px 0;
}
.paddingLeftRight5 {
padding: 0 5px;
}
.heightFitContent {
height: fit-content;
}
.flexGap5 {
gap: 5px;
}
/* ---------- @media queries must always go at the bottom ------------*/
/*will apply to anything 1000px or less. this catches ipads, horizontal phones, and vertical phones)*/

View File

@@ -1806,10 +1806,36 @@ app.post('/getgroups', jsonParser, (_, response) => {
}
const files = fs.readdirSync(directories.groups);
const chats = fs.readdirSync(directories.groupChats);
files.forEach(function (file) {
const fileContents = fs.readFileSync(path.join(directories.groups, file), 'utf8');
try {
const filePath = path.join(directories.groups, file);
const fileContents = fs.readFileSync(filePath, 'utf8');
const group = json5.parse(fileContents);
const groupStat = fs.statSync(filePath);
group['date_added'] = groupStat.birthtimeMs;
let chat_size = 0;
let date_last_chat = 0;
if (Array.isArray(group.chats) && Array.isArray(chats)) {
for (const chat of chats) {
if (group.chats.includes(path.parse(chat).name)) {
const chatStat = fs.statSync(path.join(directories.groupChats, chat));
chat_size += chatStat.size;
date_last_chat = Math.max(date_last_chat, chatStat.mtimeMs);
}
}
}
group['date_last_chat'] = date_last_chat;
group['chat_size'] = chat_size;
groups.push(group);
}
catch (error) {
console.error(error);
}
});
return response.send(groups);
@@ -2350,6 +2376,7 @@ app.post("/generate_openai", jsonParser, function (request, response_generate_op
"stream": request.body.stream,
"presence_penalty": request.body.presence_penalty,
"frequency_penalty": request.body.frequency_penalty,
"top_p": request.body.top_p,
"stop": request.body.stop,
"logit_bias": request.body.logit_bias
},