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 { kai_settings, loadKoboldSettings, formatKoboldUrl, getKoboldGenerationData, canUseKoboldStopSequence, } from "./scripts/kai-settings.js"; import { textgenerationwebui_settings, loadTextGenSettings, generateTextGenWithStreaming, } from "./scripts/textgen-settings.js"; import { world_info_budget, world_info_data, world_info_depth, world_info, getWorldInfoPrompt, selectImportedWorldInfo, setWorldInfoSettings, deleteWorldInfo, world_info_recursive, } from "./scripts/world-info.js"; import { groups, selected_group, saveGroupChat, getGroups, generateGroupWrapper, deleteGroup, is_group_generating, printGroups, resetSelectedGroup, select_group_chats, regenerateGroup, group_generation_id, getGroupChat, renameGroupMember, createNewGroupChat, getGroupPastChats, getGroupAvatar, openGroupChat, editGroup, deleteGroupChat, renameGroupChat, importGroupChat, } from "./scripts/group-chats.js"; import { collapseNewlines, loadPowerUserSettings, playMessageSound, sortCharactersList, fixMarkdown, power_user, pygmalion_options, tokenizers, formatInstructModeChat, formatInstructStoryString, formatInstructModePrompt, } from "./scripts/power-user.js"; import { setOpenAIMessageExamples, setOpenAIMessages, prepareOpenAIMessages, sendOpenAIRequest, loadOpenAISettings, setOpenAIOnlineStatus, generateOpenAIPromptCache, oai_settings, is_get_status_openai, openai_messages_count, getTokenCountOpenAI, } from "./scripts/openai.js"; import { getNovelTier, loadNovelPreset, loadNovelSettings, nai_settings, } from "./scripts/nai-settings.js"; import { showBookmarksButtons } from "./scripts/bookmarks.js"; import { horde_settings, loadHordeSettings, generateHorde, checkHordeStatus, getHordeModels, adjustHordeGenerationParams, MIN_AMOUNT_GEN, } from "./scripts/horde.js"; import { poe_settings, loadPoeSettings, generatePoe, is_get_status_poe, setPoeOnlineStatus, } from "./scripts/poe.js"; import { debounce, delay, restoreCaretPosition, saveCaretPosition, end_trim_to_sentence, countOccurrences, isOdd } from "./scripts/utils.js"; import { extension_settings, loadExtensionSettings } from "./scripts/extensions.js"; import { executeSlashCommands, getSlashCommandsHelp, registerSlashCommand } from "./scripts/slash-commands.js"; import { tag_map, tags, loadTagsSettings, printTags, getTagsList, appendTagToList, createTagMapFromList, renameTagKey, } from "./scripts/tags.js"; import { SECRET_KEYS, readSecretState, secret_state, writeSecret } from "./scripts/secrets.js"; import uniqolor from "./scripts/uniqolor.js"; import { EventEmitter } from './scripts/eventemitter.js'; //exporting functions and vars for mods export { Generate, getSettings, saveSettings, saveSettingsDebounced, printMessages, clearChat, getChat, getCharacters, callPopup, substituteParams, sendSystemMessage, addOneMessage, deleteLastMessage, resetChatState, select_rm_info, setCharacterId, setCharacterName, setOnlineStatus, checkOnlineStatus, setEditedMessageId, setSendButtonState, selectRightMenuWithAnimation, setRightTabSelectedClass, openCharacterChat, saveChat, messageFormatting, getExtensionPrompt, showSwipeButtons, hideSwipeButtons, changeMainAPI, setGenerationProgress, updateChatMetadata, scrollChatToBottom, getTokenCount, isStreamingEnabled, getThumbnailUrl, getStoppingStrings, getStatus, reloadMarkdownProcessor, chat, this_chid, selected_button, menu_type, settings, characters, online_status, main_api, api_server, system_messages, nai_settings, token, name1, name2, is_send_press, api_server_textgenerationwebui, max_context, chat_metadata, streamingProcessor, default_avatar, system_message_types, talkativeness_default, default_ch_mes, extension_prompt_types, } // API OBJECT FOR EXTERNAL WIRING window["SillyTavern"] = {}; const gpt3 = new GPT3BrowserTokenizer({ type: 'gpt3' }); hljs.addPlugin({ "before:highlightElement": ({ el }) => { el.textContent = el.innerText } }); // Markdown converter let converter; reloadMarkdownProcessor(); // array for prompt token calculations console.log('initializing Prompt Itemization Array on Startup'); let itemizedPrompts = []; /* let bg_menu_toggle = false; */ export const systemUserName = "SillyTavern System"; let default_user_name = "You"; let name1 = default_user_name; let name2 = "SillyTavern System"; let chat = []; let safetychat = [ { name: systemUserName, is_user: false, is_name: true, create_date: 0, mes: "You deleted a character/chat and arrived back here for safety reasons! Pick another character!", }, ]; let chat_create_date = 0; const default_ch_mes = "Hello"; let count_view_mes = 0; let mesStr = ""; let generatedPromtCache = ""; let generation_started = new Date(); let characters = []; let this_chid; let backgrounds = []; const default_avatar = "img/ai4.png"; export const system_avatar = "img/five.png"; export let CLIENT_VERSION = 'SillyTavern:UNKNOWN:Cohee#1207'; // For Horde header let is_colab = false; let is_checked_colab = false; let is_mes_reload_avatar = false; let optionsPopper = Popper.createPopper(document.getElementById('send_form'), document.getElementById('options'), { placement: 'top-start' }); let exportPopper = Popper.createPopper(document.getElementById('export_button'), document.getElementById('export_format_popup'), { placement: 'left' }); let rawPromptPopper = Popper.createPopper(document.getElementById('dialogue_popup'), document.getElementById('rawPromptPopup'), { placement: 'right' }); let dialogueResolve = null; let chat_metadata = {}; let streamingProcessor = null; let crop_data = undefined; let is_delete_mode = false; let fav_ch_checked = false; //initialize global var for future cropped blobs let currentCroppedAvatar = ''; const durationSaveEdit = 500; const saveSettingsDebounced = debounce(() => saveSettings(), durationSaveEdit); const saveCharacterDebounced = debounce(() => $("#create_button").trigger('click'), durationSaveEdit); const getStatusDebounced = debounce(() => getStatus(), 90000); const saveChatDebounced = debounce(() => saveChatConditional(), 1000); const system_message_types = { HELP: "help", WELCOME: "welcome", GROUP: "group", EMPTY: "empty", GENERIC: "generic", BOOKMARK_CREATED: "bookmark_created", BOOKMARK_BACK: "bookmark_back", NARRATOR: "narrator", }; const extension_prompt_types = { AFTER_SCENARIO: 0, IN_CHAT: 1 }; const system_messages = { help: { name: systemUserName, force_avatar: system_avatar, is_user: false, is_system: true, is_name: true, mes: [ `Hi there! The following chat formatting commands are supported:
"' + p1.replace(/\"/g, "") + '"'; } else if (p2) { return '
“' + p2.replace(/\u201C|\u201D/g, "") + '”'; } else { return match; } }); mes = mes.replaceAll('\\begin{align*}', '$$'); mes = mes.replaceAll('\\end{align*}', '$$'); mes = converter.makeHtml(mes); mes = mes.replace(/{{(\*?.*\*?)}}/g, ""); mes = mes.replace(/\n/g, "
[\s\S]*?<\/code>/g, function (match) {
return match.replace(/&/g, '&');
});
}
// Hides bias from empty messages send with slash commands
if (isSystem) {
mes = mes.replace(/{{(\*?.*\*?)}}/g, "");
}
if (!power_user.allow_name2_display && ch_name && !isUser && !isSystem) {
mes = mes.replaceAll(`${ch_name}:`, "");
}
return mes;
}
function getMessageFromTemplate({ mesId, characterName, isUser, avatarImg, bias, isSystem, title, timerValue, timerTitle } = {}) {
const mes = $('#message_template .mes').clone();
mes.attr({ 'mesid': mesId, 'ch_name': characterName, 'is_user': isUser, 'is_system': !!isSystem });
mes.find('.avatar img').attr('src', avatarImg);
mes.find('.ch_name .name_text').text(characterName);
mes.find('.mes_bias').html(bias);
title && mes.attr('title', title);
timerValue && mes.find('.mes_timer').attr('title', timerTitle).text(timerValue);
return mes;
}
export function appendImageToMessage(mes, messageElement) {
if (mes.extra?.image) {
const image = messageElement.find('.mes_img');
const text = messageElement.find('.mes_text');
const isInline = !!mes.extra?.inline_image;
image.attr('src', mes.extra?.image);
image.attr('title', mes.extra?.title || mes.title || '');
messageElement.find(".mes_img_container").addClass("img_extra");
image.toggleClass("img_inline", isInline);
text.toggleClass('displayNone', !isInline);
}
}
function addCopyToCodeBlocks(messageElement) {
const codeBlocks = $(messageElement).find("pre code");
for (let i = 0; i < codeBlocks.length; i++) {
hljs.highlightElement(codeBlocks.get(i));
if (navigator.clipboard !== undefined) {
const copyButton = document.createElement('i');
copyButton.classList.add('fa-solid', 'fa-copy', 'code-copy');
copyButton.title = 'Copy code';
codeBlocks.get(i).appendChild(copyButton);
copyButton.addEventListener('pointerup', function (event) {
navigator.clipboard.writeText(codeBlocks.get(i).innerText);
const copiedMsg = document.createElement("div");
copiedMsg.classList.add('code-copied');
copiedMsg.innerText = "Copied!";
copiedMsg.style.top = `${event.clientY - 55}px`;
copiedMsg.style.left = `${event.clientX - 55}px`;
document.body.append(copiedMsg);
setTimeout(() => {
document.body.removeChild(copiedMsg);
}, 1000);
});
}
}
}
function addOneMessage(mes, { type = "normal", insertAfter = null, scroll = true } = {}) {
var messageText = mes["mes"];
if (mes.name === name1) {
var characterName = name1; //set to user's name by default
} else { var characterName = mes.name }
var avatarImg = "User Avatars/" + user_avatar;
const isSystem = mes.is_system;
const title = mes.title;
generatedPromtCache = "";
//for non-user mesages
if (!mes["is_user"]) {
if (mes.force_avatar) {
avatarImg = mes.force_avatar;
} else if (this_chid === undefined || this_chid === "invalid-safety-id") {
avatarImg = system_avatar;
} else {
if (characters[this_chid].avatar != "none") {
avatarImg = getThumbnailUrl('avatar', characters[this_chid].avatar);
if (is_mes_reload_avatar !== false) {
avatarImg += "&" + is_mes_reload_avatar;
}
} else {
avatarImg = default_avatar;
}
}
//old processing:
//if messge is from sytem, use the name provided in the message JSONL to proceed,
//if not system message, use name2 (char's name) to proceed
//characterName = mes.is_system || mes.force_avatar ? mes.name : name2;
}
if (count_view_mes == 0) {
messageText = substituteParams(messageText);
}
messageText = messageFormatting(
messageText,
characterName,
isSystem,
mes.is_user,
);
const bias = messageFormatting(mes.extra?.bias ?? "");
let params = {
mesId: count_view_mes,
characterName: characterName,
isUser: mes.is_user,
avatarImg: avatarImg,
bias: bias,
isSystem: isSystem,
title: title,
...formatGenerationTimer(mes.gen_started, mes.gen_finished),
};
const HTMLForEachMes = getMessageFromTemplate(params);
if (type !== 'swipe') {
if (!insertAfter) {
$("#chat").append(HTMLForEachMes);
}
else {
const target = $("#chat").find(`.mes[mesid="${insertAfter}"]`);
$(HTMLForEachMes).insertAfter(target);
$(HTMLForEachMes).find('.swipe_left').css('display', 'none');
$(HTMLForEachMes).find('.swipe_right').css('display', 'none');
}
}
const newMessage = $(`#chat [mesid="${count_view_mes}"]`);
newMessage.data("isSystem", isSystem);
if (isSystem) {
// newMessage.find(".mes_edit").hide();
newMessage.find(".mes_prompt").hide(); //don't need prompt button for sys
}
// don't need prompt button for user
if (params.isUser === true) {
newMessage.find(".mes_prompt").hide();
console.log(`hiding prompt for user mesID ${params.mesId}`);
}
//shows or hides the Prompt display button
let mesIdToFind = Number(newMessage.attr('mesId'));
if (itemizedPrompts.length !== 0) {
//console.log(`itemizedPrompt.length = ${itemizedPrompts.length}`)
for (var i = 0; i < itemizedPrompts.length; i++) {
if (itemizedPrompts[i].mesId === mesIdToFind) {
newMessage.find(".mes_prompt").show();
console.log(`showing prompt for mesID ${params.mesId} from ${params.characterName}`);
} else {
console.log(`no cache obj for mesID ${mesIdToFind}, hiding prompt button and continuing search`);
newMessage.find(".mes_prompt").hide();
console.log(itemizedPrompts);
}
}
} else if (params.isUser !== true) { //hide all when prompt cache is empty
console.log('saw empty prompt cache, hiding all prompt buttons');
$(".mes_prompt").hide();
//console.log(itemizedPrompts);
} else { console.log('skipping prompt data for User Message'); }
newMessage.find('.avatar img').on('error', function () {
$(this).hide();
$(this).parent().html(``);
});
if (type === 'swipe') {
$("#chat").find(`[mesid="${count_view_mes - 1}"]`).find('.mes_text').html('');
$("#chat").find(`[mesid="${count_view_mes - 1}"]`).find('.mes_text').append(messageText);
appendImageToMessage(mes, $("#chat").find(`[mesid="${count_view_mes - 1}"]`));
$("#chat").find(`[mesid="${count_view_mes - 1}"]`).attr('title', title);
if (mes.swipe_id == mes.swipes.length - 1) {
$("#chat").find(`[mesid="${count_view_mes - 1}"]`).find('.mes_timer').text(params.timerValue);
$("#chat").find(`[mesid="${count_view_mes - 1}"]`).find('.mes_timer').attr('title', params.timerTitle);
} else {
$("#chat").find(`[mesid="${count_view_mes - 1}"]`).find('.mes_timer').html('');
}
} else {
$("#chat").find(`[mesid="${count_view_mes}"]`).find('.mes_text').append(messageText);
appendImageToMessage(mes, newMessage);
hideSwipeButtons();
count_view_mes++;
}
addCopyToCodeBlocks(newMessage);
// Don't scroll if not inserting last
if (!insertAfter && scroll) {
$('#chat .mes').last().addClass('last_mes');
$('#chat .mes').eq(-2).removeClass('last_mes');
hideSwipeButtons();
showSwipeButtons();
scrollChatToBottom();
}
}
function formatGenerationTimer(gen_started, gen_finished) {
if (!gen_started || !gen_finished) {
return {};
}
const dateFormat = 'HH:mm:ss D MMM YYYY';
const start = moment(gen_started);
const finish = moment(gen_finished);
const seconds = finish.diff(start, 'seconds', true);
const timerValue = `${seconds.toFixed(1)}s`;
const timerTitle = [
`Generation queued: ${start.format(dateFormat)}`,
`Reply received: ${finish.format(dateFormat)}`,
`Time to generate: ${seconds} seconds`,
].join('\n');
return { timerValue, timerTitle };
}
function scrollChatToBottom() {
if (power_user.auto_scroll_chat_to_bottom) {
var $textchat = $("#chat");
$textchat.scrollTop(($textchat[0].scrollHeight));
}
}
function substituteParams(content, _name1, _name2) {
_name1 = _name1 ?? name1;
_name2 = _name2 ?? name2;
if (!content) {
return ''
}
content = content.replace(/{{user}}/gi, _name1);
content = content.replace(/{{char}}/gi, _name2);
content = content.replace(//gi, _name1);
content = content.replace(//gi, _name2);
return content;
}
function getStoppingStrings(isImpersonate, addSpace) {
const charString = `\n${name2}:`;
const youString = `\nYou:`;
const userString = `\n${name1}:`;
const result = isImpersonate ? [charString] : [youString];
result.push(userString);
// Add other group members as the stopping strings
if (selected_group) {
const group = groups.find(x => x.id === selected_group);
if (group && Array.isArray(group.members)) {
const names = group.members
.map(x => characters.find(y => y.avatar == x))
.filter(x => x && x.name !== name2)
.map(x => `\n${x.name}:`);
result.push(...names);
}
}
// Cohee: oobabooga's textgen always appends newline before the sequence as a stopping string
// But it's a problem for Metharme which doesn't use newlines to separate them.
const wrap = (s) => power_user.instruct.wrap ? '\n' + s : s;
if (power_user.instruct.enabled) {
if (power_user.instruct.input_sequence) {
result.push(wrap(power_user.instruct.input_sequence));
}
if (power_user.instruct.output_sequence) {
result.push(wrap(power_user.instruct.output_sequence));
}
}
return addSpace ? result.map(x => `${x} `) : result;
}
function processCommands(message, type) {
if (type == "regenerate" || type == "swipe" || type == 'quiet') {
return null;
}
const result = executeSlashCommands(message);
$("#send_textarea").val(result.newText).trigger('input');
// interrupt generation if the input was nothing but a command
if (message.length > 0 && result.newText.length === 0) {
return true;
}
return result.interrupt;
}
function sendSystemMessage(type, text, extra = {}) {
const systemMessage = system_messages[type];
if (!systemMessage) {
return;
}
const newMessage = { ...systemMessage, send_date: humanizedDateTime() };
if (text) {
newMessage.mes = text;
}
if (type == system_message_types.HELP) {
newMessage.mes += getSlashCommandsHelp();
}
if (!newMessage.extra) {
newMessage.extra = {};
}
newMessage.extra = Object.assign(newMessage.extra, extra);
newMessage.extra.type = type;
chat.push(newMessage);
addOneMessage(newMessage);
is_send_press = false;
}
export function extractMessageBias(message) {
if (!message) {
return null;
}
const found = [];
const rxp = /{{(\*?.+\*?)}}/g;
//const rxp = /{([^}]+)}/g;
let curMatch;
while ((curMatch = rxp.exec(message))) {
found.push(curMatch[1].trim());
}
return ` ${found.join(" ")} `;
}
function cleanGroupMessage(getMessage) {
const group = groups.find((x) => x.id == selected_group);
if (group && Array.isArray(group.members) && group.members) {
for (let member of group.members) {
const character = characters.find(x => x.avatar == member);
if (!character) {
continue;
}
const name = character.name;
// Skip current speaker.
if (name === name2) {
continue;
}
const indexOfMember = getMessage.indexOf(`${name}:`);
if (indexOfMember != -1) {
getMessage = getMessage.substr(0, indexOfMember);
}
}
}
return getMessage;
}
function getAllExtensionPrompts() {
const value = Object
.values(extension_prompts)
.filter(x => x.value)
.map(x => x.value.trim())
.join('\n');
return value.length ? substituteParams(value) : '';
}
function getExtensionPrompt(position = 0, depth = undefined, separator = "\n") {
let extension_prompt = Object.keys(extension_prompts)
.sort()
.map((x) => extension_prompts[x])
.filter(x => x.position == position && x.value && (depth === undefined || x.depth == depth))
.map(x => x.value.trim())
.join(separator);
if (extension_prompt.length && !extension_prompt.startsWith(separator)) {
extension_prompt = separator + extension_prompt;
}
if (extension_prompt.length && !extension_prompt.endsWith(separator)) {
extension_prompt = extension_prompt + separator;
}
if (extension_prompt.length) {
extension_prompt = substituteParams(extension_prompt);
}
return extension_prompt;
}
function baseChatReplace(value, name1, name2) {
if (value !== undefined && value.length > 0) {
if (is_pygmalion) {
value = value.replace(/{{user}}:/gi, 'You:');
value = value.replace(/:/gi, 'You:');
}
value = substituteParams(value, name1, name2);
if (power_user.collapse_newlines) {
value = collapseNewlines(value);
}
}
return value;
}
function appendToStoryString(value, prefix) {
if (value !== undefined && value.length > 0) {
return prefix + value + '\n';
}
return '';
}
function isStreamingEnabled() {
return ((main_api == 'openai' && oai_settings.stream_openai)
|| (main_api == 'poe' && poe_settings.streaming)
|| (main_api == 'textgenerationwebui' && textgenerationwebui_settings.streaming))
&& !isMultigenEnabled(); // Multigen has a quasi-streaming mode which breaks the real streaming
}
class StreamingProcessor {
showStopButton(messageId) {
if (messageId == -1) {
return;
}
$(`#chat .mes[mesid="${messageId}"] .mes_stop`).css({ 'display': 'block' });
$(`#chat .mes[mesid="${messageId}"] .mes_buttons`).css({ 'display': 'none' });
}
hideStopButton(messageId) {
if (messageId == -1) {
return;
}
$(`#chat .mes[mesid="${messageId}"] .mes_stop`).css({ 'display': 'none' });
$(`#chat .mes[mesid="${messageId}"] .mes_buttons`).css({ 'display': 'block' });
}
onStartStreaming(text) {
let messageId = -1;
if (this.type == "impersonate") {
$('#send_textarea').val('').trigger('input');
}
else {
saveReply(this.type, text);
messageId = count_view_mes - 1;
this.showStopButton(messageId);
}
hideSwipeButtons();
scrollChatToBottom();
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, isFinal) {
const isImpersonate = this.type == "impersonate";
text = this.removePrefix(text);
let processedText = cleanUpMessage(text, isImpersonate, !isFinal);
let result = extractNameFromMessage(processedText, this.force_name2, isImpersonate);
let isName = result.this_mes_is_name;
processedText = result.getMessage;
// Predict unbalanced asterisks during streaming
if (!isFinal && isOdd(countOccurrences(processedText, '*'))) {
// Add asterisk at the end to balance it
processedText = processedText.trimEnd() + '*';
}
if (isImpersonate) {
$('#send_textarea').val(processedText).trigger('input');
}
else {
let currentTime = new Date();
const timePassed = formatGenerationTimer(this.timeStarted, currentTime);
chat[messageId]['is_name'] = isName;
chat[messageId]['mes'] = processedText;
chat[messageId]['gen_started'] = this.timeStarted;
chat[messageId]['gen_finished'] = currentTime;
if (this.type == 'swipe' && Array.isArray(chat[messageId]['swipes'])) {
chat[messageId]['swipes'][chat[messageId]['swipe_id']] = processedText;
}
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);
this.setFirstSwipe(messageId);
}
scrollChatToBottom();
}
onFinishStreaming(messageId, text) {
this.hideStopButton(this.messageId);
this.onProgressStreaming(messageId, text, true);
addCopyToCodeBlocks($(`#chat .mes[mesid="${messageId}"]`));
saveChatConditional();
activateSendButtons();
showSwipeButtons();
setGenerationProgress(0);
$('.mes_buttons:last').show();
generatedPromtCache = '';
console.log("Generated text size:", text.length, text)
if (power_user.auto_swipe) {
function containsBlacklistedWords(str, blacklist, threshold) {
const regex = new RegExp(`\\b(${blacklist.join('|')})\\b`, 'gi');
const matches = str.match(regex) || [];
return matches.length >= threshold;
}
const generatedTextFiltered = (text) => {
if (text) {
if (power_user.auto_swipe_minimum_length) {
if (text.length < power_user.auto_swipe_minimum_length && text.length !== 0) {
console.log("Generated text size too small")
return true
}
}
if (power_user.auto_swipe_blacklist_threshold) {
if (containsBlacklistedWords(text, power_user.auto_swipe_blacklist, power_user.auto_swipe_blacklist_threshold)) {
console.log("Generated text has blacklisted words")
return true
}
}
}
return false
}
if (generatedTextFiltered(text)) {
swipe_right()
return
}
}
playMessageSound();
}
onErrorStreaming() {
this.hideStopButton(this.messageId);
$("#send_textarea").removeAttr('disabled');
is_send_press = false;
activateSendButtons();
setGenerationProgress(0);
showSwipeButtons();
}
setFirstSwipe(messageId) {
if (this.type !== 'swipe' && this.type !== 'impersonate') {
if (Array.isArray(chat[messageId]['swipes']) && chat[messageId]['swipes'].length === 1 && chat[messageId]['swipe_id'] === 0) {
chat[messageId]['swipes'][0] = chat[messageId]['mes'];
}
}
}
onStopStreaming() {
this.onErrorStreaming();
}
nullStreamingGeneration() {
throw new Error('Generation function for streaming is not hooked up');
}
constructor(type, force_name2) {
this.result = "";
this.messageId = -1;
this.type = type;
this.force_name2 = force_name2;
this.isStopped = false;
this.isFinished = false;
this.generator = this.nullStreamingGeneration;
this.abortController = new AbortController();
this.firstMessageText = '...';
this.timeStarted = new Date();
}
async generate() {
if (this.messageId == -1) {
this.messageId = this.onStartStreaming(this.firstMessageText);
await delay(1); // delay for message to be rendered
}
for await (const text of this.generator()) {
if (this.isStopped) {
this.onStopStreaming();
return;
}
try {
this.result = text;
this.onProgressStreaming(this.messageId, message_already_generated + text);
}
catch (err) {
console.error(err);
this.onErrorStreaming();
this.isStopped = true;
return;
}
}
this.isFinished = true;
return this.result;
}
}
async function Generate(type, { automatic_trigger, force_name2, resolve, reject, quiet_prompt, force_chid } = {}) {
//console.log('Generate entered');
setGenerationProgress(0);
tokens_already_generated = 0;
generation_started = new Date();
const isImpersonate = type == "impersonate";
const isInstruct = power_user.instruct.enabled;
message_already_generated = isImpersonate ? `${name1}: ` : `${name2}: `;
// Name for the multigen prefix
const magName = isImpersonate ? (is_pygmalion ? 'You' : name1) : name2;
if (isInstruct) {
message_already_generated = formatInstructModePrompt(magName, isImpersonate);
} else {
message_already_generated = `${magName}: `;
}
// To trim after multigen ended
const magFirst = message_already_generated;
const interruptedByCommand = processCommands($("#send_textarea").val(), type);
if (interruptedByCommand) {
$("#send_textarea").val('').trigger('input');
is_send_press = false;
return;
}
if (main_api == 'textgenerationwebui' && textgenerationwebui_settings.streaming && !textgenerationwebui_settings.streaming_url) {
callPopup('Streaming URL is not set. Look it up in the console window when starting TextGen Web UI', 'text');
is_send_press = false;
return;
}
if (isHordeGenerationNotAllowed()) {
is_send_press = false;
return;
}
streamingProcessor = isStreamingEnabled() ? new StreamingProcessor(type, force_name2) : false;
// Hide swipes on either multigen or real streaming
if (isStreamingEnabled() || isMultigenEnabled()) {
hideSwipeButtons();
}
// Set empty promise resolution functions
if (typeof resolve !== 'function') {
resolve = () => { };
}
if (typeof reject !== 'function') {
reject = () => { };
}
if (selected_group && !is_group_generating) {
generateGroupWrapper(false, type, { resolve, reject, quiet_prompt, force_chid });
return;
}
if (online_status != 'no_connection' && this_chid != undefined && this_chid !== 'invalid-safety-id') {
let textareaText;
if (type !== 'regenerate' && type !== "swipe" && type !== 'quiet' && !isImpersonate) {
is_send_press = true;
textareaText = $("#send_textarea").val();
$("#send_textarea").val('').trigger('input');
} else {
textareaText = "";
if (chat.length && chat[chat.length - 1]['is_user']) {
//do nothing? why does this check exist?
}
else if (type !== 'quiet' && type !== "swipe" && !isImpersonate) {
chat.length = chat.length - 1;
count_view_mes -= 1;
$('#chat').children().last().hide(500, function () {
$(this).remove();
});
}
}
deactivateSendButtons();
let { messageBias, promptBias } = getBiasStrings(textareaText);
//*********************************
//PRE FORMATING STRING
//*********************************
//for normal messages sent from user..
if (textareaText != "" && !automatic_trigger && type !== 'quiet') {
// If user message contains no text other than bias - send as a system message
if (messageBias && replaceBiasMarkup(textareaText).trim().length === 0) {
sendSystemMessage(system_message_types.GENERIC, ' ', { bias: messageBias });
}
else {
sendMessageAsUser(textareaText, messageBias);
}
}
////////////////////////////////////
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('')) {
mesExamples = '\n' + mesExamples.trim();
}
if (mesExamples.replace(//gi, '').trim().length === 0) {
mesExamples = '';
}
const blockHeading =
main_api === 'openai' ? '' : // OpenAI handler always expects it
power_user.custom_chat_separator ? power_user.custom_chat_separator :
power_user.disable_examples_formatting ? '' :
is_pygmalion ? '' : `This is how ${name2} should talk`;
let mesExamplesArray = mesExamples.split(//gi).slice(1).map(block => `${blockHeading}\n${block.trim()}\n`);
// First message in fresh 1-on-1 chat reacts to user/character settings changes
if (chat.length) {
chat[0].mes = substituteParams(chat[0].mes);
}
// Collect messages with usable content
let coreChat = chat.filter(x => !x.is_system);
if (type === 'swipe') {
coreChat.pop();
}
console.log(`Core/all messages: ${coreChat.length}/${chat.length}`);
if (main_api === 'openai') {
message_already_generated = ''; // OpenAI doesn't have multigen
setOpenAIMessages(coreChat);
setOpenAIMessageExamples(mesExamplesArray);
}
let storyString = "";
if (is_pygmalion) {
storyString += appendToStoryString(charDescription, power_user.disable_description_formatting ? '' : name2 + "'s Persona: ");
storyString += appendToStoryString(charPersonality, power_user.disable_personality_formatting ? '' : 'Personality: ');
storyString += appendToStoryString(Scenario, power_user.disable_scenario_formatting ? '' : 'Scenario: ');
} else {
storyString += appendToStoryString(charDescription, '');
storyString += appendToStoryString(charPersonality, power_user.disable_personality_formatting ? '' : name2 + "'s personality: ");
storyString += appendToStoryString(Scenario, power_user.disable_scenario_formatting ? '' : 'Circumstances and context of the dialogue: ');
}
// Pygmalion does that anyway
if (promptBias || (power_user.always_force_name2 && !is_pygmalion)) {
force_name2 = true;
}
if (isImpersonate) {
force_name2 = false;
}
if (isInstruct) {
storyString = formatInstructStoryString(storyString);
}
//////////////////////////////////
let chat2 = [];
for (let i = coreChat.length - 1, j = 0; i >= 0; i--, j++) {
// For OpenAI it's only used in WI
if (main_api == 'openai' && !world_info) {
console.log('No WI, skipping chat2 for OAI');
break;
}
chat2[i] = formatMessageHistoryItem(coreChat[j], isInstruct);
}
// Determine token limit
let this_max_context = getMaxContextSize();
// Adjust token limit for Horde
let adjustedParams;
if (main_api == 'kobold' && horde_settings.use_horde && (horde_settings.auto_adjust_context_length || horde_settings.auto_adjust_response_length)) {
try {
adjustedParams = await adjustHordeGenerationParams(max_context, amount_gen);
}
catch {
activateSendButtons();
return;
}
if (horde_settings.auto_adjust_context_length) {
this_max_context = (adjustedParams.maxContextLength - adjustedParams.maxLength);
}
}
// Extension added strings
const allAnchors = getAllExtensionPrompts();
const afterScenarioAnchor = getExtensionPrompt(extension_prompt_types.AFTER_SCENARIO);
let zeroDepthAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, 0, ' ');
let { worldInfoString, worldInfoBefore, worldInfoAfter } = getWorldInfoPrompt(chat2);
// hack for regeneration of the first message
if (chat2.length == 0) {
chat2.push('');
}
let examplesString = '';
let chatString = '';
function canFitMessages() {
const encodeString = [
worldInfoString,
storyString,
examplesString,
chatString,
allAnchors,
quiet_prompt,
].join('').replace(/\r/gm, '');
return getTokenCount(encodeString, power_user.token_padding) < this_max_context;
}
// Force pinned examples into the context
let pinExmString;
if (power_user.pin_examples) {
pinExmString = examplesString = mesExamplesArray.join('');
}
// Collect enough messages to fill the context
let arrMes = [];
for (let item of chat2) {
// not needed for OAI prompting
if (main_api == 'openai') {
break;
}
chatString = item + chatString;
if (canFitMessages()) {
arrMes[arrMes.length] = item;
} else {
break;
}
// Prevent UI thread lock on tokenization
await delay(1);
}
if (main_api !== 'openai') {
setInContextMessages(arrMes.length, type);
}
// Estimate how many unpinned example messages fit in the context
let count_exm_add = 0;
if (!power_user.pin_examples) {
for (let example of mesExamplesArray) {
examplesString += example;
if (canFitMessages()) {
count_exm_add++;
} else {
break;
}
await delay(1);
}
}
let mesSend = [];
console.log('calling runGenerate');
await runGenerate();
async function runGenerate(cycleGenerationPromt = '') {
is_send_press = true;
generatedPromtCache += cycleGenerationPromt;
if (generatedPromtCache.length == 0) {
if (main_api === 'openai') {
generateOpenAIPromptCache();
}
console.log('generating prompt');
chatString = "";
arrMes = arrMes.reverse();
arrMes.forEach(function (item, i, arr) {//For added anchors and others
// OAI doesn't need all of this
if (main_api === 'openai') {
return;
}
if (i === arrMes.length - 1 && !item.trim().startsWith(name1 + ":")) {
if (textareaText == "") {
// Cohee: I think this was added to allow the model to continue
// where it left off by removing the trailing newline at the end
// that was added by chat2 generator. This causes problems with
// instruct mode that could not have a trailing newline. So we're
// removing a newline ONLY at the end of the string if it exists.
item = item.replace(/\n?$/, '');
//item = item.substr(0, item.length - 1);
}
}
if (is_pygmalion && !isInstruct) {
if (i === arrMes.length - 1 && item.trim().startsWith(name1 + ":")) {//for add name2 when user sent
item = item + name2 + ":";
}
if (i === arrMes.length - 1 && !item.trim().startsWith(name1 + ":")) {//for add name2 when continue
if (textareaText == "") {
item = item + '\n' + name2 + ":";
}
}
if (item.trim().startsWith(name1)) {
item = item.replace(name1 + ':', 'You:');
}
}
if (i === 0) {
// Process those that couldn't get that far
for (let upperDepth = 100; upperDepth >= arrMes.length; upperDepth--) {
const upperAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, upperDepth);
if (upperAnchor && upperAnchor.length) {
item = upperAnchor + item;
}
}
}
const anchorDepth = Math.abs(i - arrMes.length + 1);
const extensionAnchor = getExtensionPrompt(extension_prompt_types.IN_CHAT, anchorDepth);
if (anchorDepth > 0 && extensionAnchor && extensionAnchor.length) {
item += extensionAnchor;
}
mesSend[mesSend.length] = item;
});
}
let mesExmString = '';
let mesSendString = '';
function setPromtString() {
if (main_api == 'openai') {
return;
}
console.log('--setting Prompt string');
mesExmString = pinExmString ?? mesExamplesArray.slice(0, count_exm_add).join('');
mesSendString = '';
for (let j = 0; j < mesSend.length; j++) {
const isBottom = j === mesSend.length - 1;
mesSendString += mesSend[j];
if (isBottom) {
mesSendString = modifyLastPromptLine(mesSendString);
}
}
}
function modifyLastPromptLine(mesSendString) {
// Add quiet generation prompt at depth 0
if (quiet_prompt && quiet_prompt.length) {
const name = is_pygmalion ? 'You' : name1;
const quietAppend = isInstruct ? formatInstructModeChat(name, quiet_prompt, false, true, false) : `\n${name}: ${quiet_prompt}`;
mesSendString += quietAppend;
}
// Get instruct mode line
if (isInstruct && tokens_already_generated === 0) {
const name = isImpersonate ? (is_pygmalion ? 'You' : name1) : name2;
mesSendString += formatInstructModePrompt(name, isImpersonate);
}
// Get non-instruct impersonation line
if (!isInstruct && isImpersonate && tokens_already_generated === 0) {
const name = is_pygmalion ? 'You' : name1;
if (!mesSendString.endsWith('\n')) {
mesSendString += '\n';
}
mesSendString += name + ':';
}
// Add character's name
if (force_name2 && tokens_already_generated === 0) {
if (!mesSendString.endsWith('\n')) {
mesSendString += '\n';
}
mesSendString += (`${name2}:${promptBias || ''}`);
}
return mesSendString;
}
function checkPromtSize() {
console.log('---checking Prompt size');
setPromtString();
const prompt = [
worldInfoString,
storyString,
mesExmString,
mesSendString,
generatedPromtCache,
allAnchors,
quiet_prompt,
].join('').replace(/\r/gm, '');
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..
count_exm_add--; // remove the example messages...
checkPromtSize(); // and try agin...
} else if (mesSend.length > 0) { // if the chat history is longer than 0
mesSend.shift(); // remove the first (oldest) chat entry..
checkPromtSize(); // and check size again..
} else {
//end
console.log(`---mesSend.length = ${mesSend.length}`);
}
}
}
if (generatedPromtCache.length > 0 && main_api !== 'openai') {
console.log('---Generated Prompt Cache length: ' + generatedPromtCache.length);
checkPromtSize();
} else {
console.log('---calling setPromtString ' + generatedPromtCache.length)
setPromtString();
}
// add a custom dingus (if defined)
mesSendString = adjustChatsSeparator(mesSendString);
let finalPromt =
worldInfoBefore +
storyString +
worldInfoAfter +
afterScenarioAnchor +
mesExmString +
mesSendString +
generatedPromtCache;
if (zeroDepthAnchor && zeroDepthAnchor.length) {
if (!isMultigenEnabled() || tokens_already_generated == 0) {
finalPromt = appendZeroDepthAnchor(force_name2, zeroDepthAnchor, finalPromt);
}
}
finalPromt = finalPromt.replace(/\r/gm, '');
if (power_user.collapse_newlines) {
finalPromt = collapseNewlines(finalPromt);
}
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]];
if (isMultigenEnabled() && type !== 'quiet') {
// if nothing has been generated yet..
this_amount_gen = getMultigenAmount();
}
let thisPromptBits = [];
if (main_api == 'kobold' && horde_settings.use_horde && horde_settings.auto_adjust_response_length) {
this_amount_gen = Math.min(this_amount_gen, adjustedParams.maxLength);
this_amount_gen = Math.max(this_amount_gen, MIN_AMOUNT_GEN); // prevent validation errors
}
let generate_data;
if (main_api == 'kobold') {
generate_data = {
prompt: finalPromt,
gui_settings: true,
max_length: amount_gen,
temperature: kai_settings.temp,
max_context_length: max_context,
singleline: kai_settings.single_line,
};
if (preset_settings != 'gui' || horde_settings.use_horde) {
const maxContext = horde_settings.use_horde && horde_settings.auto_adjust_context_length ? adjustedParams.maxContextLength : max_context;
generate_data = getKoboldGenerationData(finalPromt, this_settings, this_amount_gen, maxContext, isImpersonate);
}
}
else if (main_api == 'textgenerationwebui') {
generate_data = getTextGenGenerationData(finalPromt, this_amount_gen, isImpersonate);
}
else if (main_api == 'novel') {
const this_settings = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]];
generate_data = getNovelGenerationData(finalPromt, this_settings);
}
else if (main_api == 'openai') {
let [prompt, counts] = await prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldInfoAfter, afterScenarioAnchor, promptBias, type, quiet_prompt);
generate_data = { prompt: prompt };
// counts will return false if the user has not enabled the token breakdown feature
if (counts) {
parseTokenCounts(counts, thisPromptBits);
}
setInContextMessages(openai_messages_count, type);
} else if (main_api == 'poe') {
generate_data = { prompt: finalPromt };
}
if (power_user.console_log_prompts) {
console.log(generate_data.prompt);
}
let generate_url = getGenerateUrl();
console.log('rungenerate calling API');
if (main_api == 'openai') {
if (isStreamingEnabled() && type !== 'quiet') {
streamingProcessor.generator = await sendOpenAIRequest(type, generate_data.prompt, streamingProcessor.abortController.signal);
}
else {
sendOpenAIRequest(type, generate_data.prompt).then(onSuccess).catch(onError);
}
}
else if (main_api == 'kobold' && horde_settings.use_horde) {
generateHorde(finalPromt, generate_data).then(onSuccess).catch(onError);
}
else if (main_api == 'poe') {
if (isStreamingEnabled() && type !== 'quiet') {
streamingProcessor.generator = await generatePoe(type, finalPromt, streamingProcessor.abortController.signal);
}
else {
generatePoe(type, finalPromt).then(onSuccess).catch(onError);
}
}
else if (main_api == 'textgenerationwebui' && isStreamingEnabled() && type !== 'quiet') {
streamingProcessor.generator = await generateTextGenWithStreaming(generate_data, streamingProcessor.abortController.signal);
}
else {
jQuery.ajax({
type: 'POST', //
url: generate_url, //
data: JSON.stringify(generate_data),
beforeSend: () => { },
cache: false,
dataType: "json",
contentType: "application/json",
success: onSuccess,
error: onError
}); //end of "if not data error"
}
//set array object for prompt token itemization of this message
let currentArrayEntry = Number(thisPromptBits.length - 1);
let additionalPromptStuff = {
...thisPromptBits[currentArrayEntry],
rawPrompt: generate_data.prompt,
mesId: Number(count_view_mes),
worldInfoBefore: worldInfoBefore,
allAnchors: allAnchors,
summarizeString: (extension_prompts['1_memory']?.value || ''),
authorsNoteString: (extension_prompts['2_floating_prompt']?.value || ''),
worldInfoString: worldInfoString,
storyString: storyString,
worldInfoAfter: worldInfoAfter,
afterScenarioAnchor: afterScenarioAnchor,
examplesString: examplesString,
mesSendString: mesSendString,
generatedPromtCache: generatedPromtCache,
promptBias: promptBias,
finalPromt: finalPromt,
charDescription: charDescription,
charPersonality: charPersonality,
scenarioText: scenarioText,
this_max_context: this_max_context,
padding: power_user.token_padding,
main_api: main_api,
};
thisPromptBits = additionalPromptStuff;
//console.log(thisPromptBits);
itemizedPrompts.push(thisPromptBits);
//console.log(`pushed prompt bits to itemizedPrompts array. Length is now: ${itemizedPrompts.length}`);
if (isStreamingEnabled() && type !== 'quiet') {
hideSwipeButtons();
let getMessage = await streamingProcessor.generate();
if (streamingProcessor && !streamingProcessor.isStopped && streamingProcessor.isFinished) {
streamingProcessor.onFinishStreaming(streamingProcessor.messageId, getMessage);
streamingProcessor = null;
}
}
function onSuccess(data) {
is_send_press = false;
if (!data.error) {
//const getData = await response.json();
let getMessage = extractMessageFromData(data);
let title = extractTitleFromData(data);
//Pygmalion run again
// to make it continue generating so long as it's under max_amount and hasn't signaled
// an end to the character's response via typing "You:" or adding ""
if (isMultigenEnabled() && type !== 'quiet') {
message_already_generated += getMessage;
promptBias = '';
let this_mes_is_name;
({ this_mes_is_name, getMessage } = extractNameFromMessage(getMessage, force_name2, isImpersonate));
if (!isImpersonate) {
if (tokens_already_generated == 0) {
console.log("New message");
({ type, getMessage } = saveReply(type, getMessage, this_mes_is_name, title));
}
else {
console.log("Should append message");
({ type, getMessage } = saveReply('append', getMessage, this_mes_is_name, title));
}
} else {
let chunk = cleanUpMessage(message_already_generated, true, true);
let extract = extractNameFromMessage(chunk, force_name2, isImpersonate);
$('#send_textarea').val(extract.getMessage).trigger('input');
}
if (shouldContinueMultigen(getMessage, isImpersonate)) {
hideSwipeButtons();
tokens_already_generated += this_amount_gen; // add new gen amt to any prev gen counter..
getMessage = message_already_generated;
runGenerate(getMessage);
console.log('returning to make generate again');
return;
}
getMessage = message_already_generated.substring(magFirst.length);
}
//Formating
getMessage = cleanUpMessage(getMessage, isImpersonate);
let this_mes_is_name;
({ this_mes_is_name, getMessage } = extractNameFromMessage(getMessage, force_name2, isImpersonate));
if (getMessage.length > 0) {
if (isImpersonate) {
$('#send_textarea').val(getMessage).trigger('input');
generatedPromtCache = "";
}
else if (type == 'quiet') {
resolve(getMessage);
}
else {
if (!isMultigenEnabled()) {
({ type, getMessage } = saveReply(type, getMessage, this_mes_is_name, title));
}
else {
({ type, getMessage } = saveReply('appendFinal', getMessage, this_mes_is_name, title));
}
}
activateSendButtons();
if (type !== 'quiet') {
playMessageSound();
}
generate_loop_counter = 0;
} else {
++generate_loop_counter;
if (generate_loop_counter > MAX_GENERATION_LOOPS) {
throwCircuitBreakerError();
}
// regenerate with character speech reenforced
// to make sure we leave on swipe type while also adding the name2 appendage
setTimeout(() => {
Generate(type, { automatic_trigger, force_name2: true, resolve, reject, quiet_prompt, force_chid });
}, generate_loop_counter * 1000);
}
} else {
activateSendButtons();
//console.log('runGenerate calling showSwipeBtns');
showSwipeButtons();
}
console.log('/savechat called by /Generate');
saveChatConditional();
activateSendButtons();
showSwipeButtons();
setGenerationProgress(0);
$('.mes_buttons:last').show();
if (type !== 'quiet') {
resolve();
}
};
function onError(jqXHR, exception) {
reject(exception);
$("#send_textarea").removeAttr('disabled');
is_send_press = false;
activateSendButtons();
setGenerationProgress(0);
console.log(exception);
console.log(jqXHR);
};
} //rungenerate ends
} else { //generate's primary loop ends, after this is error handling for no-connection or safety-id
if (this_chid === undefined || this_chid === 'invalid-safety-id') {
toastr.warning('Сharacter is not selected');
}
is_send_press = false;
}
//console.log('generate ending');
} //generate ends
function getBiasStrings(textareaText) {
let promptBias = '';
let messageBias = extractMessageBias(textareaText);
// gets bias of the latest message where it was applied
for (let mes of chat.slice().reverse()) {
if (mes && mes.extra && (mes.is_user || mes.is_system || mes.extra.type === system_message_types.NARRATOR)) {
if (mes.extra.bias && mes.extra.bias.trim().length > 0) {
promptBias = mes.extra.bias;
}
break;
}
}
promptBias = messageBias || promptBias || '';
return { messageBias, promptBias };
}
function formatMessageHistoryItem(chatItem, isInstruct) {
const isNarratorType = chatItem?.extra?.type === system_message_types.NARRATOR;
const characterName = (selected_group || chatItem.force_avatar) ? chatItem.name : name2;
const itemName = chatItem.is_user ? chatItem['name'] : characterName;
const shouldPrependName = (chatItem.is_name || chatItem.force_avatar || selected_group) && !isNarratorType;
let textResult = shouldPrependName ? `${itemName}: ${chatItem.mes}\n` : `${chatItem.mes}\n`;
if (isInstruct) {
textResult = formatInstructModeChat(itemName, chatItem.mes, chatItem.is_user, isNarratorType, chatItem.force_avatar);
}
textResult = replaceBiasMarkup(textResult);
return textResult;
}
export function replaceBiasMarkup(str) {
return (str ?? '').replace(/{{(\*?.*\*?)}}/g, '');
}
function sendMessageAsUser(textareaText, messageBias) {
chat[chat.length] = {};
chat[chat.length - 1]['name'] = name1;
chat[chat.length - 1]['is_user'] = true;
chat[chat.length - 1]['is_name'] = true;
chat[chat.length - 1]['send_date'] = humanizedDateTime();
chat[chat.length - 1]['mes'] = textareaText;
chat[chat.length - 1]['extra'] = {};
if (messageBias) {
console.log('checking bias');
chat[chat.length - 1]['extra']['bias'] = messageBias;
}
addOneMessage(chat[chat.length - 1]);
}
function getMaxContextSize() {
let this_max_context = 1487;
if (main_api == 'kobold' || main_api == 'textgenerationwebui') {
this_max_context = (max_context - amount_gen);
}
if (main_api == 'novel') {
if (novel_tier === 1) {
this_max_context = 1024;
} else {
this_max_context = 2048 - 60; //fix for fat tokens
if (nai_settings.model_novel == 'krake-v2') {
this_max_context -= 160;
}
}
}
if (main_api == 'openai') {
this_max_context = oai_settings.openai_max_context;
}
if (main_api == 'poe') {
this_max_context = Number(max_context);
}
return this_max_context;
}
function parseTokenCounts(counts, thisPromptBits) {
const total = Object.values(counts).filter(x => !Number.isNaN(x)).reduce((acc, val) => acc + val, 0);
thisPromptBits.push({
oaiStartTokens: Object.entries(counts)[0][1],
oaiPromptTokens: Object.entries(counts)[1][1],
oaiBiasTokens: Object.entries(counts)[2][1],
oaiNudgeTokens: Object.entries(counts)[3][1],
oaiJailbreakTokens: Object.entries(counts)[4][1],
oaiImpersonateTokens: Object.entries(counts)[5][1],
oaiExamplesTokens: Object.entries(counts)[6][1],
oaiConversationTokens: Object.entries(counts)[7][1],
oaiTotalTokens: total,
});
}
function adjustChatsSeparator(mesSendString) {
if (power_user.custom_chat_separator && power_user.custom_chat_separator.length) {
mesSendString = power_user.custom_chat_separator + '\n' + mesSendString;
}
// if chat start formatting is disabled
else if (power_user.disable_start_formatting) {
mesSendString = mesSendString;
}
// add non-pygma dingus
else if (!is_pygmalion) {
mesSendString = '\nThen the roleplay chat between ' + name1 + ' and ' + name2 + ' begins.\n' + mesSendString;
}
// add pygma
else {
mesSendString = '\n' + mesSendString;
//mesSendString = mesSendString; //This edit simply removes the first "" that is prepended to all context prompts
}
return mesSendString;
}
function appendZeroDepthAnchor(force_name2, zeroDepthAnchor, finalPromt) {
const trimBothEnds = !force_name2 && !is_pygmalion;
let trimmedPrompt = (trimBothEnds ? zeroDepthAnchor.trim() : zeroDepthAnchor.trimEnd());
if (trimBothEnds && !finalPromt.endsWith('\n')) {
finalPromt += '\n';
}
finalPromt += trimmedPrompt;
if (force_name2 || is_pygmalion) {
finalPromt += ' ';
}
return finalPromt;
}
function getMultigenAmount() {
let this_amount_gen = parseInt(amount_gen);
if (tokens_already_generated === 0) {
// if the max gen setting is > 50...(
if (parseInt(amount_gen) >= power_user.multigen_first_chunk) {
// then only try to make 50 this cycle..
this_amount_gen = power_user.multigen_first_chunk;
}
else {
// otherwise, make as much as the max amount request.
this_amount_gen = parseInt(amount_gen);
}
}
// if we already received some generated text...
else {
// if the remaining tokens to be made is less than next potential cycle count
if (parseInt(amount_gen) - tokens_already_generated < power_user.multigen_next_chunks) {
// subtract already generated amount from the desired max gen amount
this_amount_gen = parseInt(amount_gen) - tokens_already_generated;
}
else {
// otherwise make the standard cycle amount (first 50, and 30 after that)
this_amount_gen = power_user.multigen_next_chunks;
}
}
return this_amount_gen;
}
function promptItemize(itemizedPrompts, requestedMesId) {
var incomingMesId = Number(requestedMesId);
console.log(`looking for MesId ${incomingMesId}`);
var thisPromptSet = undefined;
for (var i = 0; i < itemizedPrompts.length; i++) {
if (itemizedPrompts[i].mesId === incomingMesId) {
thisPromptSet = i;
PromptArrayItemForRawPromptDisplay = Number(i);
}
}
if (thisPromptSet === undefined) {
console.log(`couldnt find the right mesId. looked for ${incomingMesId}`);
console.log(itemizedPrompts);
return null;
}
//these happen regardless of API
var charPersonalityTokens = getTokenCount(itemizedPrompts[thisPromptSet].charPersonality);
var charDescriptionTokens = getTokenCount(itemizedPrompts[thisPromptSet].charDescription);
var scenarioTextTokens = getTokenCount(itemizedPrompts[thisPromptSet].scenarioText);
var allAnchorsTokens = getTokenCount(itemizedPrompts[thisPromptSet].allAnchors);
var summarizeStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].summarizeString);
var authorsNoteStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].authorsNoteString);
var afterScenarioAnchorTokens = getTokenCount(itemizedPrompts[thisPromptSet].afterScenarioAnchor);
var zeroDepthAnchorTokens = getTokenCount(itemizedPrompts[thisPromptSet].afterScenarioAnchor);
var worldInfoStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].worldInfoString);
var thisPrompt_max_context = itemizedPrompts[thisPromptSet].this_max_context;
var thisPrompt_padding = itemizedPrompts[thisPromptSet].padding;
var promptBiasTokens = getTokenCount(itemizedPrompts[thisPromptSet].promptBias);
var this_main_api = itemizedPrompts[thisPromptSet].main_api;
if (this_main_api == 'openai') {
//for OAI API
//console.log('-- Counting OAI Tokens');
//var finalPromptTokens = itemizedPrompts[thisPromptSet].oaiTotalTokens;
var oaiStartTokens = itemizedPrompts[thisPromptSet].oaiStartTokens;
var oaiPromptTokens = itemizedPrompts[thisPromptSet].oaiPromptTokens;
var ActualChatHistoryTokens = itemizedPrompts[thisPromptSet].oaiConversationTokens;
var examplesStringTokens = itemizedPrompts[thisPromptSet].oaiExamplesTokens;
var oaiBiasTokens = itemizedPrompts[thisPromptSet].oaiBiasTokens;
var oaiJailbreakTokens = itemizedPrompts[thisPromptSet].oaiJailbreakTokens;
var oaiNudgeTokens = itemizedPrompts[thisPromptSet].oaiNudgeTokens;
var oaiImpersonateTokens = itemizedPrompts[thisPromptSet].oaiImpersonateTokens;
var finalPromptTokens =
oaiBiasTokens +
oaiImpersonateTokens +
oaiJailbreakTokens +
oaiNudgeTokens +
oaiPromptTokens +
ActualChatHistoryTokens +
charDescriptionTokens +
charPersonalityTokens +
allAnchorsTokens +
worldInfoStringTokens +
examplesStringTokens;
// OAI doesn't use padding
thisPrompt_padding = 0;
// Max context size - max completion tokens
thisPrompt_max_context = (oai_settings.openai_max_context - oai_settings.openai_max_tokens);
} else {
//for non-OAI APIs
//console.log('-- Counting non-OAI Tokens');
var finalPromptTokens = getTokenCount(itemizedPrompts[thisPromptSet].finalPromt);
var storyStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].storyString);
var examplesStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].examplesString);
var mesSendStringTokens = getTokenCount(itemizedPrompts[thisPromptSet].mesSendString)
var ActualChatHistoryTokens = mesSendStringTokens - allAnchorsTokens + power_user.token_padding;
var totalTokensInPrompt =
storyStringTokens + //chardefs total
worldInfoStringTokens +
ActualChatHistoryTokens + //chat history
allAnchorsTokens + // AN and/or legacy anchors
//afterScenarioAnchorTokens + //only counts if AN is set to 'after scenario'
//zeroDepthAnchorTokens + //same as above, even if AN not on 0 depth
promptBiasTokens; //{{}}
//- thisPrompt_padding; //not sure this way of calculating is correct, but the math results in same value as 'finalPromt'
}
if (this_main_api == 'openai') {
//console.log('-- applying % on OAI tokens');
var oaiStartTokensPercentage = ((oaiStartTokens / (finalPromptTokens)) * 100).toFixed(2);
var storyStringTokensPercentage = ((oaiPromptTokens / (finalPromptTokens)) * 100).toFixed(2);
var ActualChatHistoryTokensPercentage = ((ActualChatHistoryTokens / (finalPromptTokens)) * 100).toFixed(2);
var promptBiasTokensPercentage = ((oaiBiasTokens / (finalPromptTokens)) * 100).toFixed(2);
var worldInfoStringTokensPercentage = ((worldInfoStringTokens / (finalPromptTokens)) * 100).toFixed(2);
var allAnchorsTokensPercentage = ((allAnchorsTokens / (finalPromptTokens)) * 100).toFixed(2);
var selectedTokenizer = `tiktoken (${oai_settings.openai_model})`;
var oaiSystemTokens = oaiImpersonateTokens + oaiJailbreakTokens + oaiNudgeTokens + oaiStartTokens;
var oaiSystemTokensPercentage = ((oaiSystemTokens / (finalPromptTokens)) * 100).toFixed(2);
} else {
//console.log('-- applying % on non-OAI tokens');
var storyStringTokensPercentage = ((storyStringTokens / (totalTokensInPrompt)) * 100).toFixed(2);
var ActualChatHistoryTokensPercentage = ((ActualChatHistoryTokens / (totalTokensInPrompt)) * 100).toFixed(2);
var promptBiasTokensPercentage = ((promptBiasTokens / (totalTokensInPrompt)) * 100).toFixed(2);
var worldInfoStringTokensPercentage = ((worldInfoStringTokens / (totalTokensInPrompt)) * 100).toFixed(2);
var allAnchorsTokensPercentage = ((allAnchorsTokens / (totalTokensInPrompt)) * 100).toFixed(2);
var selectedTokenizer = $("#tokenizer").find(':selected').text();
}
if (this_main_api == 'openai') {
//console.log('-- calling popup for OAI tokens');
callPopup(
`
Prompt Itemization
Tokenizer: TikToken
API Used: ${this_main_api}
Only the white numbers really matter. All numbers are estimates.
Grey color items may not have been included in the context due to certain prompt format settings.
System Info:
${oaiSystemTokens}
-- Chat Start:
${oaiStartTokens}
-- Jailbreak:
${oaiJailbreakTokens}
-- NSFW:
??
-- Nudge:
${oaiNudgeTokens}
-- Impersonate:
${oaiImpersonateTokens}
Prompt Tokens:
${oaiPromptTokens}
-- Description:
${charDescriptionTokens}
-- Personality:
${charPersonalityTokens}
-- Scenario:
${scenarioTextTokens}
-- Examples:
${examplesStringTokens}
World Info:
${worldInfoStringTokens}
Chat History:
${ActualChatHistoryTokens}
Extensions:
${allAnchorsTokens}
-- Summarize:
${summarizeStringTokens}
-- Author's Note:
${authorsNoteStringTokens}
{{}} Bias:${oaiBiasTokens}
Total Tokens in Prompt: ${finalPromptTokens}
Max Context (Context Size - Response Length):${thisPrompt_max_context}
`, 'text'
);
} else {
//console.log('-- calling popup for non-OAI tokens');
callPopup(
`
Prompt Itemization
Tokenizer: ${selectedTokenizer}
API Used: ${this_main_api}
Only the white numbers really matter. All numbers are estimates.
Grey color items may not have been included in the context due to certain prompt format settings.
Character Definitions:
${storyStringTokens}
-- Description:
${charDescriptionTokens}
-- Personality:
${charPersonalityTokens}
-- Scenario:
${scenarioTextTokens}
-- Examples:
${examplesStringTokens}
World Info:
${worldInfoStringTokens}
Chat History:
${ActualChatHistoryTokens}
Extensions:
${allAnchorsTokens}
-- Summarize:
${summarizeStringTokens}
-- Author's Note:
${authorsNoteStringTokens}
{{}} Bias:${promptBiasTokens}
Total Tokens in Prompt: ${totalTokensInPrompt}
Max Context:${thisPrompt_max_context}
- Padding: ${thisPrompt_padding}
Actual Max Context Allowed:${thisPrompt_max_context - thisPrompt_padding}
`, 'text'
);
}
}
function setInContextMessages(lastmsg, type) {
$("#chat .mes").removeClass('lastInContext');
if (type === 'swipe' || type === 'regenerate') {
lastmsg++;
}
$('#chat .mes:not([is_system="true"])').eq(-lastmsg).addClass('lastInContext');
}
// TODO: move to textgen-settings.js
function getTextGenGenerationData(finalPromt, this_amount_gen, isImpersonate) {
return {
'prompt': finalPromt,
'max_new_tokens': this_amount_gen,
'do_sample': textgenerationwebui_settings.do_sample,
'temperature': textgenerationwebui_settings.temp,
'top_p': textgenerationwebui_settings.top_p,
'typical_p': textgenerationwebui_settings.typical_p,
'repetition_penalty': textgenerationwebui_settings.rep_pen,
'encoder_repetition_penalty': textgenerationwebui_settings.encoder_rep_pen,
'top_k': textgenerationwebui_settings.top_k,
'min_length': textgenerationwebui_settings.min_length,
'no_repeat_ngram_size': textgenerationwebui_settings.no_repeat_ngram_size,
'num_beams': textgenerationwebui_settings.num_beams,
'penalty_alpha': textgenerationwebui_settings.penalty_alpha,
'length_penalty': textgenerationwebui_settings.length_penalty,
'early_stopping': textgenerationwebui_settings.early_stopping,
'seed': textgenerationwebui_settings.seed,
'add_bos_token': textgenerationwebui_settings.add_bos_token,
'stopping_strings': getStoppingStrings(isImpersonate, false),
'truncation_length': max_context,
'ban_eos_token': textgenerationwebui_settings.ban_eos_token,
'skip_special_tokens': textgenerationwebui_settings.skip_special_tokens,
};
}
// TODO: move to nai-settings.js
function getNovelGenerationData(finalPromt, this_settings) {
return {
"input": finalPromt,
"model": nai_settings.model_novel,
"use_string": true,
"temperature": parseFloat(nai_settings.temp_novel),
"max_length": this_settings.max_length,
"min_length": this_settings.min_length,
"tail_free_sampling": this_settings.tail_free_sampling,
"repetition_penalty": parseFloat(nai_settings.rep_pen_novel),
"repetition_penalty_range": parseInt(nai_settings.rep_pen_size_novel),
"repetition_penalty_frequency": this_settings.repetition_penalty_frequency,
"repetition_penalty_presence": this_settings.repetition_penalty_presence,
//"stop_sequences": {{187}},
//bad_words_ids = {{50256}, {0}, {1}};
//generate_until_sentence = true;
"use_cache": false,
//use_string = true;
"return_full_text": false,
"prefix": "vanilla",
"order": this_settings.order
};
}
function getGenerateUrl() {
let generate_url = '';
if (main_api == 'kobold') {
generate_url = '/generate';
} else if (main_api == 'textgenerationwebui') {
generate_url = '/generate_textgenerationwebui';
} else if (main_api == 'novel') {
generate_url = '/generate_novelai';
}
return generate_url;
}
function shouldContinueMultigen(getMessage, isImpersonate) {
if (power_user.instruct.enabled && power_user.instruct.stop_sequence) {
if (message_already_generated.indexOf(power_user.instruct.stop_sequence) !== -1) {
return false;
}
}
// stopping name string
const nameString = isImpersonate ? `${name2}:` : (is_pygmalion ? 'You:' : `${name1}:`);
// if there is no 'You:' in the response msg
const doesNotContainName = message_already_generated.indexOf(nameString) === -1;
//if there is no stamp in the response msg
const isNotEndOfText = message_already_generated.indexOf('<|endoftext|>') === -1;
//if the gen'd msg is less than the max response length..
const notReachedMax = tokens_already_generated < parseInt(amount_gen);
//if we actually have gen'd text at all...
const msgHasText = getMessage.length > 0;
return doesNotContainName && isNotEndOfText && notReachedMax && msgHasText;
}
function extractNameFromMessage(getMessage, force_name2, isImpersonate) {
const nameToTrim = isImpersonate ? name1 : name2;
let this_mes_is_name = true;
if (getMessage.startsWith(nameToTrim + ":")) {
getMessage = getMessage.replace(nameToTrim + ':', '');
getMessage = getMessage.trimStart();
} else {
this_mes_is_name = false;
}
// Like OAI, Poe is very unlikely to send you an incomplete message.
// But it doesn't send "name:" either, so we assume that we always have a name
// prepend to have clearer logs when building up a prompt context.
if (force_name2 || main_api == 'poe')
this_mes_is_name = true;
if (isImpersonate) {
getMessage = getMessage.trim();
}
return { this_mes_is_name, getMessage };
}
function throwCircuitBreakerError() {
callPopup(`Could not extract reply in ${MAX_GENERATION_LOOPS} attempts. Try generating again`, 'text');
generate_loop_counter = 0;
$("#send_textarea").removeAttr('disabled');
is_send_press = false;
activateSendButtons();
setGenerationProgress(0);
showSwipeButtons();
$('.mes_buttons:last').show();
throw new Error('Generate circuit breaker interruption');
}
function extractTitleFromData(data) {
if (main_api == 'kobold' && horde_settings.use_horde) {
return data.workerName;
}
return undefined;
}
function extractMessageFromData(data) {
let getMessage = "";
if (main_api == 'kobold' && !horde_settings.use_horde) {
getMessage = data.results[0].text;
}
if (main_api == 'kobold' && horde_settings.use_horde) {
getMessage = data.text;
}
if (main_api == 'textgenerationwebui') {
getMessage = data.results[0].text;
if (getMessage == null || data.error) {
activateSendButtons();
callPopup('Got empty response from Text generation web UI. Try restarting the API with recommended options.
', 'text');
return;
}
}
if (main_api == 'novel') {
getMessage = data.output;
}
if (main_api == 'openai' || main_api == 'poe') {
getMessage = data;
}
return getMessage;
}
function cleanUpMessage(getMessage, isImpersonate, displayIncompleteSentences = false) {
if (!displayIncompleteSentences && power_user.trim_sentences) {
getMessage = end_trim_to_sentence(getMessage, power_user.include_newline);
}
if (power_user.collapse_newlines) {
getMessage = collapseNewlines(getMessage);
}
getMessage = $.trim(getMessage);
// trailing invisible whitespace before every newlines, on a multiline string
// "trailing whitespace on newlines \nevery line of the string \n?sample text" ->
// "trailing whitespace on newlines\nevery line of the string\nsample text"
getMessage = getMessage.replace(/[^\S\r\n]+$/gm, "");
if (is_pygmalion) {
getMessage = getMessage.replace(//g, name1);
getMessage = getMessage.replace(//g, name2);
getMessage = getMessage.replace(/You:/g, name1 + ':');
}
let nameToTrim = isImpersonate ? name2 : name1;
if (isImpersonate) {
nameToTrim = power_user.allow_name2_display ? '' : name2;
}
else {
nameToTrim = power_user.allow_name1_display ? '' : name1;
}
if (nameToTrim && getMessage.indexOf(`${nameToTrim}:`) == 0) {
getMessage = getMessage.substr(0, getMessage.indexOf(`${nameToTrim}:`));
}
if (nameToTrim && getMessage.indexOf(`\n${nameToTrim}:`) > 0) {
getMessage = getMessage.substr(0, getMessage.indexOf(`\n${nameToTrim}:`));
}
if (getMessage.indexOf('<|endoftext|>') != -1) {
getMessage = getMessage.substr(0, getMessage.indexOf('<|endoftext|>'));
}
if (power_user.instruct.enabled && power_user.instruct.stop_sequence) {
if (getMessage.indexOf(power_user.instruct.stop_sequence) != -1) {
getMessage = getMessage.substring(0, getMessage.indexOf(power_user.instruct.stop_sequence));
}
}
if (power_user.instruct.enabled && power_user.instruct.input_sequence && isImpersonate) {
getMessage = getMessage.replaceAll(power_user.instruct.input_sequence, '');
}
if (power_user.instruct.enabled && power_user.instruct.output_sequence && !isImpersonate) {
getMessage = getMessage.replaceAll(power_user.instruct.output_sequence, '');
}
// clean-up group message from excessive generations
if (selected_group) {
getMessage = cleanGroupMessage(getMessage);
}
if (isImpersonate) {
getMessage = getMessage.trim();
}
const stoppingStrings = getStoppingStrings(isImpersonate, false);
//console.log('stopping on these strings: ');
//console.log(stoppingStrings);
for (const stoppingString of stoppingStrings) {
if (stoppingString.length) {
for (let j = stoppingString.length - 1; j > 0; j--) {
if (getMessage.slice(-j) === stoppingString.slice(0, j)) {
getMessage = getMessage.slice(0, -j);
break;
}
}
}
}
if (power_user.auto_fix_generated_markdown) {
getMessage = fixMarkdown(getMessage);
}
return getMessage;
}
function saveReply(type, getMessage, this_mes_is_name, title) {
if (type != 'append' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined ||
chat[chat.length - 1]['is_user'])) {
type = 'normal';
}
const generationFinished = new Date();
const img = extractImageFromMessage(getMessage);
getMessage = img.getMessage;
if (type === 'swipe') {
chat[chat.length - 1]['swipes'].length++;
if (chat[chat.length - 1]['swipe_id'] === chat[chat.length - 1]['swipes'].length - 1) {
chat[chat.length - 1]['title'] = title;
chat[chat.length - 1]['mes'] = getMessage;
chat[chat.length - 1]['gen_started'] = generation_started;
chat[chat.length - 1]['gen_finished'] = generationFinished;
addOneMessage(chat[chat.length - 1], { type: 'swipe' });
} else {
chat[chat.length - 1]['mes'] = getMessage;
}
} else if (type === 'append') {
console.log("Trying to append.")
chat[chat.length - 1]['title'] = title;
chat[chat.length - 1]['mes'] += getMessage;
chat[chat.length - 1]['gen_started'] = generation_started;
chat[chat.length - 1]['gen_finished'] = generationFinished;
addOneMessage(chat[chat.length - 1], { type: 'swipe' });
} else if (type === 'appendFinal') {
console.log("Trying to appendFinal.")
chat[chat.length - 1]['title'] = title;
chat[chat.length - 1]['mes'] = getMessage;
chat[chat.length - 1]['gen_started'] = generation_started;
chat[chat.length - 1]['gen_finished'] = generationFinished;
addOneMessage(chat[chat.length - 1], { type: 'swipe' });
} else {
console.log('entering chat update routine for non-swipe post');
chat[chat.length] = {};
chat[chat.length - 1]['extra'] = {};
chat[chat.length - 1]['name'] = name2;
chat[chat.length - 1]['is_user'] = false;
chat[chat.length - 1]['is_name'] = this_mes_is_name;
chat[chat.length - 1]['send_date'] = humanizedDateTime();
getMessage = $.trim(getMessage);
chat[chat.length - 1]['mes'] = getMessage;
chat[chat.length - 1]['title'] = title;
chat[chat.length - 1]['gen_started'] = generation_started;
chat[chat.length - 1]['gen_finished'] = generationFinished;
if (selected_group) {
console.log('entering chat update for groups');
let avatarImg = 'img/ai4.png';
if (characters[this_chid].avatar != 'none') {
avatarImg = getThumbnailUrl('avatar', characters[this_chid].avatar);
}
chat[chat.length - 1]['is_name'] = true;
chat[chat.length - 1]['force_avatar'] = avatarImg;
chat[chat.length - 1]['original_avatar'] = characters[this_chid].avatar;
chat[chat.length - 1]['extra']['gen_id'] = group_generation_id;
}
saveImageToMessage(img, chat[chat.length - 1]);
addOneMessage(chat[chat.length - 1]);
}
const item = chat[chat.length - 1];
if (item['swipe_id'] !== undefined) {
item['swipes'][item['swipes'].length - 1] = item['mes'];
} else {
item['swipe_id'] = 0;
item['swipes'] = [];
item['swipes'][0] = chat[chat.length - 1]['mes'];
}
return { type, getMessage };
}
function saveImageToMessage(img, mes) {
if (mes && img.image) {
if (typeof mes.extra !== 'object') {
mes.extra = {};
}
mes.extra.image = img.image;
mes.extra.title = img.title;
}
}
function extractImageFromMessage(getMessage) {
const regex = /
/g;
const results = regex.exec(getMessage);
const image = results ? results[1] : '';
const title = results ? results[2] : '';
getMessage = getMessage.replace(regex, '');
return { getMessage, image, title };
}
export function isMultigenEnabled() {
return power_user.multigen && (main_api == 'textgenerationwebui' || main_api == 'kobold' || main_api == 'novel');
}
function activateSendButtons() {
is_send_press = false;
$("#send_but").css("display", "flex");
$("#loading_mes").css("display", "none");
$("#send_textarea").attr("disabled", false);
}
function deactivateSendButtons() {
$("#send_but").css("display", "none");
$("#loading_mes").css("display", "flex");
}
function resetChatState() {
//unsets expected chid before reloading (related to getCharacters/printCharacters from using old arrays)
this_chid = "invalid-safety-id";
// replaces deleted charcter name with system user since it will be displayed next.
name2 = systemUserName;
// sets up system user to tell user about having deleted a character
chat = [...safetychat];
// resets chat metadata
chat_metadata = {};
// resets the characters array, forcing getcharacters to reset
characters.length = 0;
}
export function setMenuType(value) {
menu_type = value;
}
function setCharacterId(value) {
this_chid = value;
}
function setCharacterName(value) {
name2 = value;
}
function setOnlineStatus(value) {
online_status = value;
}
function setEditedMessageId(value) {
this_edit_mes_id = value;
}
function setSendButtonState(value) {
is_send_press = value;
}
function resultCheckStatusNovel() {
is_api_button_press_novel = false;
checkOnlineStatus();
$("#api_loading_novel").css("display", "none");
$("#api_button_novel").css("display", "inline-block");
}
async function renameCharacter() {
const oldAvatar = characters[this_chid].avatar;
const newValue = await callPopup('New name:
', 'input', characters[this_chid].name);
if (newValue && newValue !== characters[this_chid].name) {
const body = JSON.stringify({ avatar_url: oldAvatar, new_name: newValue });
const response = await fetch('/renamecharacter', {
method: 'POST',
headers: getRequestHeaders(),
body,
});
try {
if (response.ok) {
const data = await response.json();
const newAvatar = data.avatar;
// Replace tags list
renameTagKey(oldAvatar, newAvatar);
// Reload characters list
await getCharacters();
// Find newly renamed character
const newChId = characters.findIndex(c => c.avatar == data.avatar);
if (newChId !== -1) {
// Select the character after the renaming
this_chid = -1;
$(`.character_select[chid="${newChId}"]`).click();
// Async delay to update UI
await delay(1);
if (this_chid === -1) {
throw new Error('New character not selected');
}
// Also rename as a group member
await renameGroupMember(oldAvatar, newAvatar, newValue);
callPopup('Character renamed!
Sprites folder (if any) should be renamed manually.', 'text');
}
else {
throw new Error('Newly renamed character was lost?');
}
}
else {
throw new Error('Could not rename the character');
}
}
catch {
// Reloading to prevent data corruption
await callPopup('Something went wrong. The page will be reloaded.', 'text');
location.reload();
}
}
}
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.');
throw new Error('Group chat saved from saveChat');
}
/*
if (item.is_user) {
//var str = item.mes.replace(`${name1}:`, `${name1}:`);
//chat[i].mes = str;
//chat[i].name = name1;
} else if (i !== chat.length - 1 && chat[i].swipe_id !== undefined) {
// delete chat[i].swipes;
// delete chat[i].swipe_id;
}
*/
});
var save_chat = [
{
user_name: name1,
character_name: name2,
create_date: chat_create_date,
chat_metadata: metadata,
},
...chat,
];
return jQuery.ajax({
type: "POST",
url: "/savechat",
data: JSON.stringify({
ch_name: characters[this_chid].name,
file_name: file_name,
chat: save_chat,
avatar_url: characters[this_chid].avatar,
}),
beforeSend: function () {
},
cache: false,
dataType: "json",
contentType: "application/json",
success: function (data) { },
error: function (jqXHR, exception) {
console.log(exception);
console.log(jqXHR);
},
});
}
async function read_avatar_load(input) {
if (input.files && input.files[0]) {
if (selected_button == "create") {
create_save_avatar = input.files;
}
const e = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = resolve;
reader.onerror = reject;
reader.readAsDataURL(input.files[0]);
})
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
const croppedImage = await callPopup(getCropPopup(e.target.result), 'avatarToCrop');
$("#avatar_load_preview").attr("src", croppedImage || e.target.result);
if (menu_type == "create") {
return;
}
$("#create_button").trigger('click');
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',
cache: 'no-cache',
headers: {
'pragma': 'no-cache',
'cache-control': 'no-cache',
}
});
console.log('Avatar refreshed');
}
}
function getCropPopup(src) {
return `Set the crop position of the avatar image and click Ok to confirm.
`;
}
function getThumbnailUrl(type, file) {
return `/thumbnail?type=${type}&file=${encodeURIComponent(file)}`;
}
async function getChat() {
//console.log('/getchat -- entered for -- ' + characters[this_chid].name);
try {
const response = await $.ajax({
type: 'POST',
url: '/getchat',
data: JSON.stringify({
ch_name: characters[this_chid].name,
file_name: characters[this_chid].chat,
avatar_url: characters[this_chid].avatar
}),
dataType: 'json',
contentType: 'application/json',
});
if (response[0] !== undefined) {
chat.push(...response);
chat_create_date = chat[0]['create_date'];
chat_metadata = chat[0]['chat_metadata'] ?? {};
chat.shift();
} else {
chat_create_date = humanizedDateTime();
}
getChatResult();
saveChat();
setTimeout(function () {
$('#send_textarea').click();
$('#send_textarea').focus();
}, 200);
} catch (error) {
getChatResult();
console.log(error);
}
}
function getChatResult() {
name2 = characters[this_chid].name;
if (chat.length > 1) {
for (let i = 0; i < chat.length; i++) {
const item = chat[i];
if (item["is_user"]) {
//item['mes'] = item['mes'].replace(default_user_name + ':', name1 + ':');
//item['name'] = name1;
}
}
} else {
const firstMes = characters[this_chid].first_mes || default_ch_mes;
chat[0] = {
name: name2,
is_user: false,
is_name: true,
send_date: humanizedDateTime(),
mes: firstMes
};
}
printMessages();
select_selected_character(this_chid);
}
async function openCharacterChat(file_name) {
characters[this_chid]["chat"] = file_name;
clearChat();
chat.length = 0;
chat_metadata = {};
await getChat();
$("#selected_chat_pole").val(file_name);
$("#create_button").click();
}
////////// OPTIMZED MAIN API CHANGE FUNCTION ////////////
function changeMainAPI() {
const selectedVal = $("#main_api").val();
//console.log(selectedVal);
const apiElements = {
"kobold": {
apiSettings: $("#kobold_api-settings"),
apiConnector: $("#kobold_api"),
apiPresets: $('#kobold_api-presets'),
apiRanges: $("#range_block"),
maxContextElem: $("#max_context_block"),
amountGenElem: $("#amount_gen_block"),
softPromptElem: $("#softprompt_block")
},
"textgenerationwebui": {
apiSettings: $("#textgenerationwebui_api-settings"),
apiConnector: $("#textgenerationwebui_api"),
apiPresets: $('#textgenerationwebui_api-presets'),
apiRanges: $("#range_block_textgenerationwebui"),
maxContextElem: $("#max_context_block"),
amountGenElem: $("#amount_gen_block"),
softPromptElem: $("#softprompt_block")
},
"novel": {
apiSettings: $("#novel_api-settings"),
apiConnector: $("#novel_api"),
apiPresets: $('#novel_api-presets'),
apiRanges: $("#range_block_novel"),
maxContextElem: $("#max_context_block"),
amountGenElem: $("#amount_gen_block"),
softPromptElem: $("#softprompt_block")
},
"openai": {
apiSettings: $("#openai_settings"),
apiConnector: $("#openai_api"),
apiPresets: $('#openai_api-presets'),
apiRanges: $("#range_block_openai"),
maxContextElem: $("#max_context_block"),
amountGenElem: $("#amount_gen_block"),
softPromptElem: $("#softprompt_block"),
},
"poe": {
apiSettings: $("#poe_settings"),
apiConnector: $("#poe_api"),
apiPresets: $("#poe_api-presets"),
apiRanges: $("#range_block_poe"),
maxContextElem: $("#max_context_block"),
amountGenElem: $("#amount_gen_block"),
softPromptElem: $("#softprompt_block"),
}
};
//console.log('--- apiElements--- ');
//console.log(apiElements);
for (const apiName in apiElements) {
const apiObj = apiElements[apiName];
const isCurrentApi = selectedVal === apiName;
apiObj.apiSettings.css("display", isCurrentApi ? "block" : "none");
apiObj.apiConnector.css("display", isCurrentApi ? "block" : "none");
apiObj.apiRanges.css("display", isCurrentApi ? "block" : "none");
apiObj.apiPresets.css("display", isCurrentApi ? "block" : "none");
if (isCurrentApi && apiName === "openai") {
apiObj.apiPresets.css("display", "flex");
}
if (isCurrentApi && apiName === "kobold") {
//console.log("enabling SP for kobold");
$("#softprompt_block").css("display", "block");
}
if (isCurrentApi && (apiName === "textgenerationwebui" || apiName === "novel")) {
console.log("enabling amount_gen for ooba/novel");
apiObj.amountGenElem.find('input').prop("disabled", false);
apiObj.amountGenElem.css("opacity", 1.0);
}
// Hide common settings for OpenAI
if (selectedVal == "openai") {
$("#common-gen-settings-block").css("display", "none");
} else {
$("#common-gen-settings-block").css("display", "block");
}
// Hide amount gen for poe
if (selectedVal == "poe") {
$("#amount_gen_block").css("display", "none");
} else {
$("#amount_gen_block").css("display", "flex");
}
}
main_api = selectedVal;
online_status = "no_connection";
if (main_api == "kobold" && horde_settings.use_horde) {
is_get_status = true;
getStatus();
getHordeModels();
}
}
////////////////////////////////////////////////////
async function getUserAvatars() {
$("#user_avatar_block").html(""); //RossAscends: necessary to avoid doubling avatars each refresh.
$("#user_avatar_block").append('+');
const response = await fetch("/getuseravatars", {
method: "POST",
headers: getRequestHeaders(),
body: JSON.stringify({
"": "",
}),
});
if (response.ok === true) {
const getData = await response.json();
//background = getData;
//console.log(getData.length);
for (var i = 0; i < getData.length; i++) {
//console.log(1);
appendUserAvatar(getData[i]);
}
//var aa = JSON.parse(getData[0]);
//const load_ch_coint = Object.getOwnPropertyNames(getData);
}
}
function highlightSelectedAvatar() {
$("#user_avatar_block").find(".avatar").removeClass("selected");
$("#user_avatar_block")
.find(`.avatar[imgfile='${user_avatar}']`)
.addClass("selected");
}
function appendUserAvatar(name) {
$("#user_avatar_block").append(
`
`
);
highlightSelectedAvatar();
}
function reloadUserAvatar() {
$(".mes").each(function () {
if ($(this).attr("is_user") == 'true') {
$(this)
.find(".avatar img")
.attr("src", `User Avatars/${user_avatar}`);
}
});
}
//***************SETTINGS****************//
///////////////////////////////////////////
async function getSettings(type) {
//timer
//console.log('getSettings() pinging server for settings request');
jQuery.ajax({
type: "POST",
url: "/getsettings",
data: JSON.stringify({}),
beforeSend: function () { },
cache: false,
dataType: "json",
contentType: "application/json",
//processData: false,
success: function (data) {
if (data.result != "file not find" && data.settings) {
settings = JSON.parse(data.settings);
if (settings.username !== undefined) {
if (settings.username !== "") {
name1 = settings.username;
$("#your_name").val(name1);
}
}
//Load which API we are using
if (settings.main_api != undefined) {
main_api = settings.main_api;
$("#main_api option[value=" + main_api + "]").attr(
"selected",
"true"
);
changeMainAPI();
}
//Load KoboldAI settings
koboldai_setting_names = data.koboldai_setting_names;
koboldai_settings = data.koboldai_settings;
koboldai_settings.forEach(function (item, i, arr) {
koboldai_settings[i] = JSON.parse(item);
});
let arr_holder = {};
$("#settings_perset").empty(); //RossAscends: uncommented this to prevent settings selector from doubling preset list on refresh
$("#settings_perset").append(
''
); //adding in the GUI settings, since it is not loaded dynamically
koboldai_setting_names.forEach(function (item, i, arr) {
arr_holder[item] = i;
$("#settings_perset").append(``);
//console.log('loading preset #'+i+' -- '+item);
});
koboldai_setting_names = {};
koboldai_setting_names = arr_holder;
preset_settings = settings.preset_settings;
if (preset_settings == "gui") {
selectKoboldGuiPreset();
} else {
if (typeof koboldai_setting_names[preset_settings] !== "undefined") {
$(`#settings_perset option[value=${koboldai_setting_names[preset_settings]}]`)
.attr("selected", "true");
} else {
preset_settings = "gui";
selectKoboldGuiPreset();
}
}
novelai_setting_names = data.novelai_setting_names;
novelai_settings = data.novelai_settings;
novelai_settings.forEach(function (item, i, arr) {
novelai_settings[i] = JSON.parse(item);
});
arr_holder = {};
$("#settings_perset_novel").empty();
novelai_setting_names.forEach(function (item, i, arr) {
arr_holder[item] = i;
$("#settings_perset_novel").append(``);
});
novelai_setting_names = {};
novelai_setting_names = arr_holder;
nai_settings.preset_settings_novel = settings.preset_settings_novel;
$(
`#settings_perset_novel option[value=${novelai_setting_names[nai_settings.preset_settings_novel]}]`
).attr("selected", "true");
//Load AI model config settings
amount_gen = settings.amount_gen;
if (settings.max_context !== undefined)
max_context = parseInt(settings.max_context);
swipes = settings.swipes !== undefined ? !!settings.swipes : true; // enable swipes by default
$('#swipes-checkbox').prop('checked', swipes); /// swipecode
hideSwipeButtons();
showSwipeButtons();
// Kobold
loadKoboldSettings(settings);
// Novel
loadNovelSettings(settings);
// TextGen
loadTextGenSettings(data, settings);
// OpenAI
loadOpenAISettings(data, settings);
// Horde
loadHordeSettings(settings);
// Poe
loadPoeSettings(settings);
// Load power user settings
loadPowerUserSettings(settings, data);
// Load- character tags
loadTagsSettings(settings);
// Set context size after loading power user (may override the max value)
$("#max_context").val(max_context);
$("#max_context_counter").text(`${max_context}`);
$("#amount_gen").val(amount_gen);
$("#amount_gen_counter").text(`${amount_gen}`);
//Enable GUI deference settings if GUI is selected for Kobold
if (main_api === "kobold") {
}
//Load User's Name and Avatar
user_avatar = settings.user_avatar;
reloadUserAvatar();
highlightSelectedAvatar();
//Load the API server URL from settings
api_server = settings.api_server;
$("#api_url_text").val(api_server);
setWorldInfoSettings(settings, data);
if (data.enable_extensions) {
const src = "scripts/extensions.js";
if ($(`script[src="${src}"]`).length === 0) {
const script = document.createElement("script");
script.type = "module";
script.src = src;
$("body").append(script);
}
loadExtensionSettings(settings);
}
api_server_textgenerationwebui =
settings.api_server_textgenerationwebui;
$("#textgenerationwebui_api_url_text").val(
api_server_textgenerationwebui
);
selected_button = settings.selected_button;
}
if (!is_checked_colab) isColab();
},
error: function (jqXHR, exception) {
console.log(exception);
console.log(jqXHR);
},
});
}
function selectKoboldGuiPreset() {
$("#settings_perset option[value=gui]")
.attr("selected", "true")
.trigger("change");
}
async function saveSettings(type) {
//console.log('Entering settings with name1 = '+name1);
return jQuery.ajax({
type: "POST",
url: "/savesettings",
data: JSON.stringify({
username: name1,
api_server: api_server,
api_server_textgenerationwebui: api_server_textgenerationwebui,
preset_settings: preset_settings,
user_avatar: user_avatar,
amount_gen: amount_gen,
max_context: max_context,
main_api: main_api,
world_info: world_info,
world_info_depth: world_info_depth,
world_info_budget: world_info_budget,
world_info_recursive: world_info_recursive,
textgenerationwebui_settings: textgenerationwebui_settings,
swipes: swipes,
horde_settings: horde_settings,
power_user: power_user,
poe_settings: poe_settings,
extension_settings: extension_settings,
tags: tags,
tag_map: tag_map,
...nai_settings,
...kai_settings,
...oai_settings,
}, null, 4),
beforeSend: function () {
if (type == "change_name") {
//let nameBeforeChange = name1;
name1 = $("#your_name").val();
//$(`.mes[ch_name="${nameBeforeChange}"]`).attr('ch_name' === name1);
//console.log('beforeSend name1 = ' + nameBeforeChange);
//console.log('new name: ' + name1);
}
},
cache: false,
dataType: "json",
contentType: "application/json",
//processData: false,
success: function (data) {
//online_status = data.result;
if (type == "change_name") {
clearChat();
printMessages();
}
},
error: function (jqXHR, exception) {
console.log(exception);
console.log(jqXHR);
},
});
}
function messageEditAuto(div) {
let mesBlock = div.closest(".mes_block");
var text = mesBlock.find(".edit_textarea").val().trim();
const bias = extractMessageBias(text);
const mes = chat[this_edit_mes_id];
mes["mes"] = text;
if (mes["swipe_id"] !== undefined) {
mes["swipes"][mes["swipe_id"]] = text;
}
// editing old messages
if (!mes["extra"]) {
mes["extra"] = {};
}
if (mes.is_system || mes.is_user || mes.extra.type === system_message_types.NARRATOR) {
mes.extra.bias = bias ?? null;
}
else {
mes.extra.bias = null;
}
mesBlock.find(".mes_text").val('');
mesBlock.find(".mes_text").val(messageFormatting(
text,
this_edit_mes_chname,
mes.is_system,
mes.is_user,
));
saveChatDebounced();
}
function messageEditDone(div) {
let mesBlock = div.closest(".mes_block");
var text = mesBlock.find(".edit_textarea").val().trim();
const bias = extractMessageBias(text);
const mes = chat[this_edit_mes_id];
mes["mes"] = text;
if (mes["swipe_id"] !== undefined) {
mes["swipes"][mes["swipe_id"]] = text;
}
// editing old messages
if (!mes.extra) {
mes.extra = {};
}
if (mes.is_system || mes.is_user || mes.extra.type === system_message_types.NARRATOR) {
mes.extra.bias = bias ?? null;
}
else {
mes.extra.bias = null;
}
mesBlock.find(".mes_text").empty();
mesBlock.find(".mes_edit_buttons").css("display", "none");
mesBlock.find(".mes_buttons").css("display", "inline-block");
mesBlock.find(".mes_text").append(
messageFormatting(
text,
this_edit_mes_chname,
mes.is_system,
mes.is_user,
)
);
mesBlock.find(".mes_bias").empty();
mesBlock.find(".mes_bias").append(messageFormatting(bias));
appendImageToMessage(mes, div.closest(".mes"));
addCopyToCodeBlocks(div.closest(".mes"));
this_edit_mes_id = undefined;
saveChatConditional();
}
async function getPastCharacterChats() {
const response = await fetch("/getallchatsofcharacter", {
method: 'POST',
body: JSON.stringify({ avatar_url: characters[this_chid].avatar }),
headers: getRequestHeaders(),
});
if (!response.ok) {
return;
}
let data = await response.json();
data = Object.values(data);
data = data.sort((a, b) => a["file_name"].localeCompare(b["file_name"])).reverse();
return data;
}
export async function displayPastChats() {
$("#select_chat_div").empty();
const group = selected_group ? groups.find(x => x.id === selected_group) : null;
const data = await (selected_group ? getGroupPastChats(selected_group) : getPastCharacterChats());
const currentChat = selected_group ? group?.chat_id : characters[this_chid]["chat"];
const displayName = selected_group ? group?.name : characters[this_chid].name;
const avatarImg = selected_group ? group?.avatar_url : getThumbnailUrl('avatar', characters[this_chid]['avatar']);
$("#load_select_chat_div").css("display", "none");
$("#ChatHistoryCharName").text(displayName);
for (const key in data) {
let strlen = 300;
let mes = data[key]["mes"];
if (mes !== undefined) {
if (mes.length > strlen) {
mes = "..." + mes.substring(mes.length - strlen);
}
const chat_items = data[key]["chat_items"];
const file_size = data[key]["file_size"];
const fileName = data[key]['file_name'];
const template = $('#past_chat_template .select_chat_block_wrapper').clone();
template.find('.select_chat_block').attr('file_name', fileName);
template.find('.avatar img').attr('src', avatarImg);
template.find('.select_chat_block_filename').text(fileName);
template.find('.chat_file_size').text(" (" + file_size + ")");
template.find('.chat_messages_num').text(" (" + chat_items + " messages)");
template.find('.select_chat_block_mes').text(mes);
template.find('.PastChat_cross').attr('file_name', fileName);
if (selected_group) {
template.find('.avatar img').replaceWith(getGroupAvatar(group));
}
$("#select_chat_div").append(template);
if (currentChat === fileName.toString().replace(".jsonl", "")) {
$("#select_chat_div").find(".select_chat_block:last").attr("highlight", true);
}
}
}
}
//************************************************************
//************************Novel.AI****************************
//************************************************************
async function getStatusNovel() {
if (is_get_status_novel) {
const data = {};
jQuery.ajax({
type: "POST", //
url: "/getstatus_novelai", //
data: JSON.stringify(data),
beforeSend: function () {
},
cache: false,
dataType: "json",
contentType: "application/json",
success: function (data) {
if (data.error != true) {
novel_tier = data.tier;
online_status = getNovelTier(novel_tier);
}
resultCheckStatusNovel();
},
error: function (jqXHR, exception) {
online_status = "no_connection";
console.log(exception);
console.log(jqXHR);
resultCheckStatusNovel();
},
});
} else {
if (is_get_status != true && is_get_status_openai != true && is_get_status_poe != true) {
online_status = "no_connection";
}
}
}
function selectRightMenuWithAnimation(selectedMenuId) {
const displayModes = {
'rm_info_block': 'flex',
'rm_group_chats_block': 'flex',
'rm_api_block': 'grid',
'rm_characters_block': 'flex',
};
document.querySelectorAll('#right-nav-panel .right_menu').forEach((menu) => {
$(menu).css('display', 'none');
if (selectedMenuId && selectedMenuId.replace('#', '') === menu.id) {
const mode = displayModes[menu.id] ?? 'block';
$(menu).css('display', mode);
$(menu).css("opacity", 0.0);
$(menu).transition({
opacity: 1.0,
duration: animation_duration,
easing: animation_easing,
complete: function () { },
});
}
})
}
function setRightTabSelectedClass(selectedButtonId) {
document.querySelectorAll('#right-nav-panel-tabs .right_menu_button').forEach((button) => {
button.classList.remove('selected-right-tab');
if (selectedButtonId && selectedButtonId.replace('#', '') === button.id) {
button.classList.add('selected-right-tab');
}
});
}
function select_rm_info(type, charId, previousCharId = null) {
if (!type) {
toastr.error(`Invalid process (no 'type')`);
return;
}
if (type === 'char_delete') {
toastr.warning(`Character Deleted: ${charId}`);
}
if (type === 'char_create') {
toastr.success(`Character Created: ${charId}`);
}
if (type === 'char_import') {
toastr.success(`Character Imported: ${charId}`);
}
selectRightMenuWithAnimation('rm_characters_block');
if (type === 'char_import' || type === 'char_create') {
//$(`#rm_characters_block [title="${charId + '.png'}"]`).scrollIntoView({ behavior: "smooth", block: "end" });
const element = $(`#rm_characters_block [title="${charId + '.png'}"]`).get(0);
element.scrollIntoView({ behavior: 'smooth', block: 'end' });
$(`#rm_characters_block [title="${charId + '.png'}"]`).parent().addClass('flash animated');
setTimeout(function () {
$(`#rm_characters_block [title="${charId + '.png'}"]`).parent().removeClass('flash animated');
}, 5000);
}
setRightTabSelectedClass();
if (previousCharId) {
const newId = characters.findIndex((x) => x.avatar == previousCharId);
if (newId >= 0) {
this_chid = newId;
}
}
}
export function select_selected_character(chid) {
//character select
//console.log('select_selected_character() -- starting with input of -- '+chid+' (name:'+characters[chid].name+')');
select_rm_create();
menu_type = "character_edit";
$("#delete_button").css("display", "flex");
$("#export_button").css("display", "flex");
setRightTabSelectedClass('rm_button_selected_ch');
var display_name = characters[chid].name;
//create text poles
$("#rm_button_back").css("display", "none");
//$("#character_import_button").css("display", "none");
$("#create_button").attr("value", "Save"); // what is the use case for this?
$("#create_button_label").css("display", "none");
// Don't update the navbar name if we're peeking the group member defs
if (!selected_group) {
$("#rm_button_selected_ch").children("h2").text(display_name);
}
$("#add_avatar_button").val("");
$("#character_popup_text_h3").text(characters[chid].name);
$("#character_name_pole").val(characters[chid].name);
$("#description_textarea").val(characters[chid].description);
$("#personality_textarea").val(characters[chid].personality);
$("#firstmessage_textarea").val(characters[chid].first_mes);
$("#scenario_pole").val(characters[chid].scenario);
$("#talkativeness_slider").val(characters[chid].talkativeness ?? talkativeness_default);
$("#mes_example_textarea").val(characters[chid].mes_example);
$("#selected_chat_pole").val(characters[chid].chat);
$("#create_date_pole").val(characters[chid].create_date);
$("#avatar_url_pole").val(characters[chid].avatar);
$("#chat_import_avatar_url").val(characters[chid].avatar);
$("#chat_import_character_name").val(characters[chid].name);
let this_avatar = default_avatar;
if (characters[chid].avatar != "none") {
this_avatar = getThumbnailUrl('avatar', characters[chid].avatar);
}
updateFavButtonState(characters[chid].fav == "true");
$("#avatar_load_preview").attr("src", this_avatar);
$("#name_div").removeClass('displayBlock');
$("#name_div").addClass('displayNone');
$("#renameCharButton").css("display", "");
$("#form_create").attr("actiontype", "editcharacter");
saveSettingsDebounced();
}
function select_rm_create() {
menu_type = "create";
//console.log('select_rm_Create() -- selected button: '+selected_button);
if (selected_button == "create") {
if (create_save_avatar != "") {
$("#add_avatar_button").get(0).files = create_save_avatar;
read_avatar_load($("#add_avatar_button").get(0));
}
}
selectRightMenuWithAnimation('rm_ch_create_block');
setRightTabSelectedClass();
$("#delete_button_div").css("display", "none");
$("#delete_button").css("display", "none");
$("#export_button").css("display", "none");
$("#create_button_label").css("display", "");
$("#create_button").attr("value", "Create");
//RossAscends: commented this out as part of the auto-loading token counter
//$('#result_info').html(' ');
//create text poles
$("#rm_button_back").css("display", "");
$("#character_import_button").css("display", "");
$("#character_popup_text_h3").text("Create character");
$("#character_name_pole").val(create_save_name);
$("#description_textarea").val(create_save_description);
$("#personality_textarea").val(create_save_personality);
$("#firstmessage_textarea").val(create_save_first_message);
$("#talkativeness_slider").val(create_save_talkativeness);
$("#scenario_pole").val(create_save_scenario);
if ($.trim(create_save_mes_example).length == 0) {
$("#mes_example_textarea").val("");
} else {
$("#mes_example_textarea").val(create_save_mes_example);
}
$("#avatar_div").css("display", "flex");
$("#avatar_load_preview").attr("src", default_avatar);
$("#renameCharButton").css('display', 'none');
$("#name_div").removeClass('displayNone');
$("#name_div").addClass('displayBlock');
updateFavButtonState(false);
$("#form_create").attr("actiontype", "createcharacter");
}
function select_rm_characters() {
menu_type = "characters";
selectRightMenuWithAnimation('rm_characters_block');
setRightTabSelectedClass('rm_button_characters');
}
function setExtensionPrompt(key, value, position, depth) {
extension_prompts[key] = { value, position, depth };
}
function updateChatMetadata(newValues, reset) {
chat_metadata = reset ? { ...newValues } : { ...chat_metadata, ...newValues };
}
function updateFavButtonState(state) {
fav_ch_checked = 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 = '') {
if (type) {
popup_type = type;
}
$("#dialogue_popup_cancel").css("display", "inline-block");
switch (popup_type) {
case "avatarToCrop":
$("#dialogue_popup_ok").text("Ok");
$("#dialogue_popup_cancel").css("display", "none");
case "text":
case "char_not_selected":
$("#dialogue_popup_ok").text("Ok");
$("#dialogue_popup_cancel").css("display", "none");
break;
case "world_imported":
case "new_chat":
case "confirm":
$("#dialogue_popup_ok").text("Yes");
break;
case "del_world":
case "del_group":
case "rename_chat":
case "del_chat":
default:
$("#dialogue_popup_ok").text("Delete");
}
$("#dialogue_popup_input").val(inputValue);
if (popup_type == 'input') {
$("#dialogue_popup_input").css("display", "block");
$("#dialogue_popup_ok").text("Save");
}
else {
$("#dialogue_popup_input").css("display", "none");
}
$("#dialogue_popup_text").html(text);
$("#shadow_popup").css("display", "block");
if (popup_type == 'input') {
$("#dialogue_popup_input").focus();
}
if (popup_type == 'avatarToCrop') {
// unset existing data
crop_data = undefined;
$('#avatarToCrop').cropper({
aspectRatio: 2 / 3,
autoCropArea: 1,
rotatable: false,
crop: function (event) {
crop_data = event.detail;
}
});
}
$("#shadow_popup").transition({
opacity: 1,
duration: 200,
easing: animation_easing,
});
return new Promise((resolve) => {
dialogueResolve = resolve;
});
}
function read_bg_load(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$("#bg_load_preview")
.attr("src", e.target.result)
.width(103)
.height(83);
var formData = new FormData($("#form_bg_download").get(0));
//console.log(formData);
jQuery.ajax({
type: "POST",
url: "/downloadbackground",
data: formData,
beforeSend: function () {
//$('#create_button').attr('value','Creating...');
},
cache: false,
contentType: false,
processData: false,
success: function (html) {
setBackground(html);
$("#bg1").css(
"background-image",
`url("${e.target.result}")`
);
$("#form_bg_download").after(
`
`
);
},
error: function (jqXHR, exception) {
console.log(exception);
console.log(jqXHR);
},
});
};
reader.readAsDataURL(input.files[0]);
}
}
function showSwipeButtons() {
if (chat.length === 0) {
return;
}
if (
chat[chat.length - 1].is_system ||
!swipes ||
$('.mes:last').attr('mesid') <= 0 ||
chat[chat.length - 1].is_user ||
chat[chat.length - 1].extra?.image ||
count_view_mes <= 1 ||
(selected_group && is_group_generating)
) { return; }
//had to add this to make the swipe counter work
//(copied from the onclick functions for swipe buttons..
//don't know why the array isn't set for non-swipe messsages in Generate or addOneMessage..)
if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array
chat[chat.length - 1]['swipe_id'] = 0; // set it to id 0
chat[chat.length - 1]['swipes'] = []; // empty the array
chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat
}
const currentMessage = $("#chat").children().filter(`[mesid="${count_view_mes - 1}"]`);
const swipeId = chat[chat.length - 1].swipe_id;
var swipesCounterHTML = (`${(swipeId + 1)}/${(chat[chat.length - 1].swipes.length)}`);
if (swipeId !== undefined && swipeId != 0) {
currentMessage.children('.swipe_left').css('display', 'flex');
}
//only show right when generate is off, or when next right swipe would not make a generate happen
if (is_send_press === false || chat[chat.length - 1].swipes.length >= swipeId) {
currentMessage.children('.swipe_right').css('display', 'flex');
currentMessage.children('.swipe_right').css('opacity', '0.3');
}
//console.log((chat[chat.length - 1]));
if ((chat[chat.length - 1].swipes.length - swipeId) === 1) {
//console.log('highlighting R swipe');
currentMessage.children('.swipe_right').css('opacity', '0.7');
}
//console.log(swipesCounterHTML);
$(".swipes-counter").html(swipesCounterHTML);
//console.log(swipeId);
//console.log(chat[chat.length - 1].swipes.length);
}
function hideSwipeButtons() {
//console.log('hideswipebuttons entered');
$("#chat").children().filter(`[mesid="${count_view_mes - 1}"]`).children('.swipe_right').css('display', 'none');
$("#chat").children().filter(`[mesid="${count_view_mes - 1}"]`).children('.swipe_left').css('display', 'none');
}
async function saveMetadata() {
if (selected_group) {
await editGroup(selected_group, true, false);
}
else {
await saveChat();
}
}
export async function saveChatConditional() {
if (selected_group) {
await saveGroupChat(selected_group, true);
}
else {
await saveChat();
}
}
async function importCharacterChat(formData) {
await jQuery.ajax({
type: "POST",
url: "/importchat",
data: formData,
beforeSend: function () {
},
cache: false,
contentType: false,
processData: false,
success: async function (data) {
if (data.res) {
await displayPastChats();
}
},
error: function () {
$("#create_button").removeAttr("disabled");
},
});
}
function updateViewMessageIds() {
$('#chat').find(".mes").each(function (index, element) {
$(element).attr("mesid", index);
});
$('#chat .mes').removeClass('last_mes');
$('#chat .mes').last().addClass('last_mes');
updateEditArrowClasses();
}
function updateEditArrowClasses() {
$("#chat .mes .mes_edit_up").removeClass("disabled");
$("#chat .mes .mes_edit_down").removeClass("disabled");
if (this_edit_mes_id !== undefined) {
const down = $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_down`);
const up = $(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_up`);
const lastId = Number($("#chat .mes").last().attr("mesid"));
const firstId = Number($("#chat .mes").first().attr("mesid"));
if (lastId == Number(this_edit_mes_id)) {
down.addClass("disabled");
}
if (firstId == Number(this_edit_mes_id)) {
up.addClass("disabled");
}
}
}
function closeMessageEditor() {
if (this_edit_mes_id) {
$(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_cancel`).click();
}
}
function setGenerationProgress(progress) {
if (!progress) {
$('#send_textarea').css({ 'background': '', 'transition': '' });
}
else {
$('#send_textarea').css({
'background': `linear-gradient(90deg, #008000d6 ${progress}%, transparent ${progress}%)`,
'transition': '0.25s ease-in-out'
});
}
}
function isHordeGenerationNotAllowed() {
if (main_api == "kobold" && horde_settings.use_horde && preset_settings == "gui") {
callPopup('GUI Settings preset is not supported for Horde. Please select another preset.', 'text');
return true;
}
return false;
}
export function cancelTtsPlay() {
if ('speechSynthesis' in window) {
speechSynthesis.cancel();
}
}
async function deleteMessageImage() {
const value = await callPopup("Delete image from message?
This action can't be undone.
", 'confirm');
if (!value) {
return;
}
const mesBlock = $(this).closest('.mes');
const mesId = mesBlock.attr('mesid');
const message = chat[mesId];
delete message.extra.image;
delete message.extra.inline_image;
mesBlock.find('.mes_img_container').removeClass('img_extra');
mesBlock.find('.mes_img').attr('src', '');
saveChatConditional();
}
function enlargeMessageImage() {
const mesBlock = $(this).closest('.mes');
const mesId = mesBlock.attr('mesid');
const message = chat[mesId];
const imgSrc = message?.extra?.image;
if (!imgSrc) {
return;
}
const img = document.createElement('img');
img.classList.add('img_enlarged');
img.src = imgSrc;
$('#dialogue_popup').addClass('wide_dialogue_popup');
callPopup(img.outerHTML, 'text');
}
window["SillyTavern"].getContext = function () {
return {
chat: chat,
characters: characters,
groups: groups,
worldInfo: world_info_data,
name1: name1,
name2: name2,
characterId: this_chid,
groupId: selected_group,
chatId: selected_group
? groups.find(x => x.id == selected_group)?.chat_id
: (this_chid && characters[this_chid] && characters[this_chid].chat),
onlineStatus: online_status,
maxContext: Number(max_context),
chatMetadata: chat_metadata,
streamingProcessor,
eventSource: eventSource,
event_types: event_types,
addOneMessage: addOneMessage,
generate: Generate,
getTokenCount: getTokenCount,
extensionPrompts: extension_prompts,
setExtensionPrompt: setExtensionPrompt,
updateChatMetadata: updateChatMetadata,
saveChat: saveChatConditional,
saveMetadata: saveMetadata,
sendSystemMessage: sendSystemMessage,
activateSendButtons,
deactivateSendButtons,
saveReply,
registerSlashCommand: registerSlashCommand,
};
};
// when we click swipe right button
const swipe_right = () => {
if (chat.length - 1 === Number(this_edit_mes_id)) {
closeMessageEditor();
}
if (isHordeGenerationNotAllowed()) {
return;
}
const swipe_duration = 200;
const swipe_range = 700;
//console.log(swipe_range);
let run_generate = false;
let run_swipe_right = false;
if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array
chat[chat.length - 1]['swipe_id'] = 0; // set it to id 0
chat[chat.length - 1]['swipes'] = []; // empty the array
chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat
}
chat[chat.length - 1]['swipe_id']++; //make new slot in array
// if message has memory attached - remove it to allow regen
if (chat[chat.length - 1].extra && chat[chat.length - 1].extra.memory) {
delete chat[chat.length - 1].extra.memory;
}
//console.log(chat[chat.length-1]['swipes']);
if (parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { //if swipe id of last message is the same as the length of the 'swipes' array
delete chat[chat.length - 1].gen_started;
delete chat[chat.length - 1].gen_finished;
run_generate = true;
} else if (parseInt(chat[chat.length - 1]['swipe_id']) < chat[chat.length - 1]['swipes'].length) { //otherwise, if the id is less than the number of swipes
chat[chat.length - 1]['mes'] = chat[chat.length - 1]['swipes'][chat[chat.length - 1]['swipe_id']]; //load the last mes box with the latest generation
run_swipe_right = true; //then prepare to do normal right swipe to show next message
}
const currentMessage = $("#chat").children().filter(`[mesid="${count_view_mes - 1}"]`);
let this_div = currentMessage.children('.swipe_right');
let this_mes_div = this_div.parent();
if (chat[chat.length - 1]['swipe_id'] > chat[chat.length - 1]['swipes'].length) { //if we swipe right while generating (the swipe ID is greater than what we are viewing now)
chat[chat.length - 1]['swipe_id'] = chat[chat.length - 1]['swipes'].length; //show that message slot (will be '...' while generating)
}
if (run_generate) { //hide swipe arrows while generating
this_div.css('display', 'none');
}
// handles animated transitions when swipe right, specifically height transitions between messages
if (run_generate || run_swipe_right) {
let this_mes_block = this_mes_div.children('.mes_block').children('.mes_text');
const this_mes_div_height = this_mes_div[0].scrollHeight;
const this_mes_block_height = this_mes_block[0].scrollHeight;
this_mes_div.children('.swipe_left').css('display', 'flex');
this_mes_div.children('.mes_block').transition({ // this moves the div back and forth
x: '-' + swipe_range,
duration: swipe_duration,
easing: animation_easing,
queue: false,
complete: function () {
/*if (!selected_group) {
var typingIndicator = $("#typing_indicator_template .typing_indicator").clone();
typingIndicator.find(".typing_indicator_name").text(characters[this_chid].name);
} */
/* $("#chat").append(typingIndicator); */
const is_animation_scroll = ($('#chat').scrollTop() >= ($('#chat').prop("scrollHeight") - $('#chat').outerHeight()) - 10);
//console.log(parseInt(chat[chat.length-1]['swipe_id']));
//console.log(chat[chat.length-1]['swipes'].length);
if (run_generate && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) {
//console.log('showing ""..."');
/* if (!selected_group) {
} else { */
$("#chat")
.find('[mesid="' + (count_view_mes - 1) + '"]')
.find('.mes_text')
.html('...'); //shows "..." while generating
$("#chat")
.find('[mesid="' + (count_view_mes - 1) + '"]')
.find('.mes_timer')
.html(''); // resets the timer
/* } */
} else {
//console.log('showing previously generated swipe candidate, or "..."');
//console.log('onclick right swipe calling addOneMessage');
addOneMessage(chat[chat.length - 1], { type: 'swipe' });
}
let new_height = this_mes_div_height - (this_mes_block_height - this_mes_block[0].scrollHeight);
if (new_height < 103) new_height = 103;
this_mes_div.animate({ height: new_height + 'px' }, {
duration: 0, //used to be 100
queue: false,
progress: function () {
// Scroll the chat down as the message expands
if (is_animation_scroll) $("#chat").scrollTop($("#chat")[0].scrollHeight);
},
complete: function () {
this_mes_div.css('height', 'auto');
// Scroll the chat down to the bottom once the animation is complete
if (is_animation_scroll) $("#chat").scrollTop($("#chat")[0].scrollHeight);
}
});
this_mes_div.children('.mes_block').transition({
x: swipe_range,
duration: 0,
easing: animation_easing,
queue: false,
complete: function () {
this_mes_div.children('.mes_block').transition({
x: '0px',
duration: swipe_duration,
easing: animation_easing,
queue: false,
complete: function () {
if (run_generate && !is_send_press && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) {
console.log('caught here 2');
is_send_press = true;
$('.mes_buttons:last').hide();
Generate('swipe');
} else {
if (parseInt(chat[chat.length - 1]['swipe_id']) !== chat[chat.length - 1]['swipes'].length) {
saveChatConditional();
}
}
}
});
}
});
}
});
this_mes_div.children('.avatar').transition({ // moves avatar along with swipe
x: '-' + swipe_range,
duration: swipe_duration,
easing: animation_easing,
queue: false,
complete: function () {
this_mes_div.children('.avatar').transition({
x: swipe_range,
duration: 0,
easing: animation_easing,
queue: false,
complete: function () {
this_mes_div.children('.avatar').transition({
x: '0px',
duration: swipe_duration,
easing: animation_easing,
queue: false,
complete: function () {
}
});
}
});
}
});
}
}
$(document).ready(function () {
//////////INPUT BAR FOCUS-KEEPING LOGIC/////////////
let S_TAFocused = false;
let S_TAPreviouslyFocused = false;
$('#send_textarea').on('focusin focus click', () => {
S_TAFocused = true;
S_TAPreviouslyFocused = true;
});
$('#send_textarea').on('focusout blur', () => S_TAFocused = false);
$('#options_button, #send_but, #option_regenerate').on('click', () => {
if (S_TAPreviouslyFocused) {
$('#send_textarea').focus();
S_TAFocused = true;
}
});
$(document).click(event => {
if ($(':focus').attr('id') !== 'send_textarea') {
if (!$(event.target.id).is("#options_button, #send_but, #send_textarea, #option_regenerate")) {
S_TAFocused = false;
S_TAPreviouslyFocused = false;
}
} else {
S_TAFocused = true;
S_TAPreviouslyFocused = true;
}
});
/////////////////
$('#swipes-checkbox').change(function () {
swipes = !!$('#swipes-checkbox').prop('checked');
if (swipes) {
//console.log('toggle change calling showswipebtns');
showSwipeButtons();
} else {
hideSwipeButtons();
}
saveSettingsDebounced();
});
///// SWIPE BUTTON CLICKS ///////
$(document).on('click', '.swipe_right', swipe_right);
$(document).on('click', '.swipe_left', function () { // when we swipe left..but no generation.
if (chat.length - 1 === Number(this_edit_mes_id)) {
closeMessageEditor();
}
if (isStreamingEnabled() && streamingProcessor) {
streamingProcessor.isStopped = true;
}
const swipe_duration = 120;
const swipe_range = '700px';
chat[chat.length - 1]['swipe_id']--;
if (chat[chat.length - 1]['swipe_id'] >= 0) {
/*$(this).parent().children('swipe_right').css('display', 'flex');
if (chat[chat.length - 1]['swipe_id'] === 0) {
$(this).css('display', 'none');
}*/ // Just in case
let this_mes_div = $(this).parent();
let this_mes_block = $(this).parent().children('.mes_block').children('.mes_text');
const this_mes_div_height = this_mes_div[0].scrollHeight;
this_mes_div.css('height', this_mes_div_height);
const this_mes_block_height = this_mes_block[0].scrollHeight;
chat[chat.length - 1]['mes'] = chat[chat.length - 1]['swipes'][chat[chat.length - 1]['swipe_id']];
$(this).parent().children('.mes_block').transition({
x: swipe_range,
duration: swipe_duration,
easing: animation_easing,
queue: false,
complete: function () {
const is_animation_scroll = ($('#chat').scrollTop() >= ($('#chat').prop("scrollHeight") - $('#chat').outerHeight()) - 10);
//console.log('on left swipe click calling addOneMessage');
addOneMessage(chat[chat.length - 1], { type: 'swipe' });
let new_height = this_mes_div_height - (this_mes_block_height - this_mes_block[0].scrollHeight);
if (new_height < 103) new_height = 103;
this_mes_div.animate({ height: new_height + 'px' }, {
duration: 0, //used to be 100
queue: false,
progress: function () {
// Scroll the chat down as the message expands
if (is_animation_scroll) $("#chat").scrollTop($("#chat")[0].scrollHeight);
},
complete: function () {
this_mes_div.css('height', 'auto');
// Scroll the chat down to the bottom once the animation is complete
if (is_animation_scroll) $("#chat").scrollTop($("#chat")[0].scrollHeight);
}
});
$(this).parent().children('.mes_block').transition({
x: '-' + swipe_range,
duration: 0,
easing: animation_easing,
queue: false,
complete: function () {
$(this).parent().children('.mes_block').transition({
x: '0px',
duration: swipe_duration,
easing: animation_easing,
queue: false,
complete: function () {
saveChatConditional();
}
});
}
});
}
});
$(this).parent().children('.avatar').transition({
x: swipe_range,
duration: swipe_duration,
easing: animation_easing,
queue: false,
complete: function () {
$(this).parent().children('.avatar').transition({
x: '-' + swipe_range,
duration: 0,
easing: animation_easing,
queue: false,
complete: function () {
$(this).parent().children('.avatar').transition({
x: '0px',
duration: swipe_duration,
easing: animation_easing,
queue: false,
complete: function () {
}
});
}
});
}
});
}
if (chat[chat.length - 1]['swipe_id'] < 0) {
chat[chat.length - 1]['swipe_id'] = 0;
}
});
$("#character_search_bar").on("input", function () {
const selector = ['#rm_print_characters_block .character_select', '#rm_print_characters_block .group_select'].join(',');
const searchValue = $(this).val().trim().toLowerCase();
if (!searchValue) {
$(selector).removeClass('hiddenBySearch');
} else {
$(selector).each(function () {
const isValidSearch = $(this)
.find(".ch_name")
.text()
.toLowerCase()
.includes(searchValue);
$(this).toggleClass('hiddenBySearch', !isValidSearch);
});
}
});
$("#send_but").click(function () {
if (is_send_press == false) {
is_send_press = true;
Generate();
}
});
//menu buttons setup
$("#rm_button_settings").click(function () {
selected_button = "settings";
menu_type = "settings";
selectRightMenuWithAnimation('rm_api_block');
setRightTabSelectedClass('rm_button_settings');
});
$("#rm_button_characters").click(function () {
selected_button = "characters";
select_rm_characters();
});
$("#rm_button_back").click(function () {
selected_button = "characters";
select_rm_characters();
});
$("#rm_button_create").click(function () {
selected_button = "create";
select_rm_create();
});
$("#rm_button_selected_ch").click(function () {
if (selected_group) {
select_group_chats(selected_group);
} else {
selected_button = "character_edit";
select_selected_character(this_chid);
}
$("#character_search_bar").val("").trigger("input");
});
$(document).on("click", ".character_select", function () {
if (selected_group && is_group_generating) {
return;
}
if (this_chid !== $(this).attr("chid")) {
//if clicked on a different character from what was currently selected
if (!is_send_press) {
cancelTtsPlay();
resetSelectedGroup();
this_edit_mes_id = undefined;
selected_button = "character_edit";
this_chid = $(this).attr("chid");
clearChat();
chat.length = 0;
chat_metadata = {};
getChat();
}
} else {
//if clicked on character that was already selected
selected_button = "character_edit";
select_selected_character(this_chid);
}
});
$(document).on("input", ".edit_textarea", function () {
scroll_holder = $("#chat").scrollTop();
$(this).height(0).height(this.scrollHeight);
is_use_scroll_holder = true;
});
$("#chat").on("scroll", function () {
if (is_use_scroll_holder) {
$("#chat").scrollTop(scroll_holder);
is_use_scroll_holder = false;
}
});
$(document).on("click", ".mes", function () {
//when a 'delete message' parent div is clicked
// and we are in delete mode and del_checkbox is visible
if (!is_delete_mode || !$(this).children('.del_checkbox').is(':visible')) {
return;
}
$(".mes").children(".del_checkbox").each(function () {
$(this).prop("checked", false);
$(this).parent().css("background", css_mes_bg);
});
$(this).css("background", "#600"); //sets the bg of the mes selected for deletion
var i = $(this).attr("mesid"); //checks the message ID in the chat
this_del_mes = i;
while (i < chat.length) {
//as long as the current message ID is less than the total chat length
$(".mes[mesid='" + i + "']").css("background", "#600"); //sets the bg of the all msgs BELOW the selected .mes
$(".mes[mesid='" + i + "']")
.children(".del_checkbox")
.prop("checked", true);
i++;
//console.log(i);
}
});
$(document).on("click", "#user_avatar_block .avatar", function () {
user_avatar = $(this).attr("imgfile");
reloadUserAvatar();
saveSettingsDebounced();
highlightSelectedAvatar();
});
$(document).on("click", "#user_avatar_block .avatar_upload", function () {
$("#avatar_upload_file").click();
});
$("#avatar_upload_file").on("change", async function (e) {
const file = e.target.files[0];
if (!file) {
return;
}
const formData = new FormData($("#form_upload_avatar").get(0));
const dataUrl = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = resolve;
reader.onerror = reject;
reader.readAsDataURL(file);
});
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
await callPopup(getCropPopup(dataUrl.target.result), 'avatarToCrop');
let url = "/uploaduseravatar";
if (crop_data !== undefined) {
url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`;
}
jQuery.ajax({
type: "POST",
url: url,
data: formData,
beforeSend: () => { },
cache: false,
contentType: false,
processData: false,
success: function (data) {
if (data.path) {
appendUserAvatar(data.path);
}
crop_data = undefined;
},
error: (jqXHR, exception) => { },
});
// Will allow to select the same file twice in a row
$("#form_upload_avatar").trigger("reset");
});
$(document).on("click", ".bg_example", async function () {
//when user clicks on a BG thumbnail...
const this_bgfile = $(this).attr("bgfile"); // this_bgfile = whatever they clicked
const customBg = window.getComputedStyle(document.getElementById('bg_custom')).backgroundImage;
// custom background is set. Do not override the layer below
if (customBg !== 'none') {
return;
}
// if clicked on upload button
if (!this_bgfile) {
return;
}
const backgroundUrl = `backgrounds/${this_bgfile}`;
// fetching to browser memory to reduce flicker
fetch(backgroundUrl).then(() => {
$("#bg1").css(
"background-image",
`url("${backgroundUrl}")`
);
setBackground(this_bgfile);
}).catch(() => {
console.log('Background could not be set: ' + backgroundUrl);
});
});
$(document).on("click", ".bg_example_cross", function (e) {
e.stopPropagation();
bg_file_for_del = $(this);
//$(this).parent().remove();
//delBackground(this_bgfile);
popup_type = "del_bg";
callPopup("Delete the background?
");
});
$(document).on("click", ".PastChat_cross", function () {
chat_file_for_del = $(this).attr('file_name');
console.log('detected cross click for' + chat_file_for_del);
popup_type = "del_chat";
callPopup("Delete the Chat File?
");
});
$("#advanced_div").click(function () {
if (!is_advanced_char_open) {
is_advanced_char_open = true;
$("#character_popup").css("display", "grid");
$("#character_popup").css("opacity", 0.0);
$("#character_popup").transition({
opacity: 1.0,
duration: animation_duration,
easing: animation_easing,
});
} else {
is_advanced_char_open = false;
$("#character_popup").css("display", "none");
}
});
$("#character_cross").click(function () {
is_advanced_char_open = false;
$("#character_popup").transition({
opacity: 0,
duration: 200,
easing: animation_easing,
});
setTimeout(function () { $("#character_popup").css("display", "none"); }, 200);
//$("#character_popup").css("display", "none");
});
$("#character_popup_ok").click(function () {
is_advanced_char_open = false;
$("#character_popup").css("display", "none");
});
$("#dialogue_popup_ok").click(async function (e) {
$("#shadow_popup").transition({
opacity: 0,
duration: 200,
easing: animation_easing,
});
setTimeout(function () {
$("#shadow_popup").css("display", "none");
$("#dialogue_popup").removeClass('large_dialogue_popup');
$("#dialogue_popup").removeClass('wide_dialogue_popup');
}, 200);
// $("#shadow_popup").css("opacity:", 0.0);
if (popup_type == 'avatarToCrop') {
dialogueResolve($("#avatarToCrop").data('cropper').getCroppedCanvas().toDataURL('image/jpeg'));
};
if (popup_type == "del_bg") {
delBackground(bg_file_for_del.attr("bgfile"));
bg_file_for_del.parent().remove();
}
if (popup_type == "del_chat") {
//close past chat popup
$("#select_chat_cross").click();
if (selected_group) {
await deleteGroupChat(selected_group, chat_file_for_del);
} else {
await delChat(chat_file_for_del);
}
//open the history view again after 100ms
//hide option popup menu
setTimeout(function () {
$("#option_select_chat").click();
$("#options").hide();
}, 200);
}
if (popup_type == "del_ch") {
console.log(
"Deleting character -- ChID: " +
this_chid +
" -- Name: " +
characters[this_chid].name
);
var msg = jQuery("#form_create").serialize(); // ID form
jQuery.ajax({
method: "POST",
url: "/deletecharacter",
beforeSend: function () {
select_rm_info("char_delete", characters[this_chid].name);
//$('#create_button').attr('value','Deleting...');
},
data: msg,
cache: false,
success: function (html) {
//RossAscends: New handling of character deletion that avoids page refreshes and should have
// fixed char corruption due to cache problems.
//due to how it is handled with 'popup_type', i couldn't find a way to make my method completely
// modular, so keeping it in TAI-main.js as a new default.
//this allows for dynamic refresh of character list after deleting a character.
// closes advanced editing popup
$("#character_cross").click();
// unsets expected chid before reloading (related to getCharacters/printCharacters from using old arrays)
this_chid = "invalid-safety-id";
// resets the characters array, forcing getcharacters to reset
characters.length = 0;
name2 = systemUserName; // replaces deleted charcter name with system user since she will be displayed next.
chat = [...safetychat]; // sets up system user to tell user about having deleted a character
chat_metadata = {}; // resets chat metadata
setRightTabSelectedClass() // 'deselects' character's tab panel
$(document.getElementById("rm_button_selected_ch"))
.children("h2")
.text(""); // removes character name from nav tabs
clearChat(); // removes deleted char's chat
this_chid = undefined; // prevents getCharacters from trying to load an invalid char.
getCharacters(); // gets the new list of characters (that doesn't include the deleted one)
printMessages(); // prints out system user's 'deleted character' message
//console.log("#dialogue_popup_ok(del-char) >>>> saving");
saveSettingsDebounced(); // saving settings to keep changes to variables
},
});
}
if (popup_type === "world_imported") {
selectImportedWorldInfo();
}
if (popup_type === "del_world" && world_info) {
deleteWorldInfo(world_info);
}
if (popup_type === "del_group") {
const groupId = $("#dialogue_popup").data("group_id");
if (groupId) {
deleteGroup(groupId);
}
}
//Make a new chat for selected character
if (
popup_type == "new_chat" &&
(selected_group || this_chid !== undefined) &&
menu_type != "create"
) {
//Fix it; New chat doesn't create while open create character menu
clearChat();
chat.length = 0;
if (selected_group) {
createNewGroupChat(selected_group);
}
else {
//RossAscends: added character name to new chat filenames and replaced Date.now() with humanizedDateTime;
chat_metadata = {};
characters[this_chid].chat = name2 + " - " + humanizedDateTime();
$("#selected_chat_pole").val(characters[this_chid].chat);
saveCharacterDebounced();
getChat();
}
}
rawPromptPopper.update();
$('#rawPromptPopup').hide();
if (dialogueResolve) {
if (popup_type == 'input') {
dialogueResolve($("#dialogue_popup_input").val());
$("#dialogue_popup_input").val('');
}
else {
dialogueResolve(true);
}
dialogueResolve = null;
}
});
$("#dialogue_popup_cancel").click(function (e) {
$("#shadow_popup").transition({
opacity: 0,
duration: 200,
easing: animation_easing,
});
setTimeout(function () {
$("#shadow_popup").css("display", "none");
$("#dialogue_popup").removeClass('large_dialogue_popup');
}, 200);
//$("#shadow_popup").css("opacity:", 0.0);
popup_type = "";
if (dialogueResolve) {
dialogueResolve(false);
dialogueResolve = null;
}
});
$("#add_bg_button").change(function () {
read_bg_load(this);
});
$("#add_avatar_button").change(function () {
is_mes_reload_avatar = Date.now();
read_avatar_load(this);
});
$("#form_create").submit(function (e) {
$("#rm_info_avatar").html("");
let save_name = create_save_name;
var formData = new FormData($("#form_create").get(0));
formData.set('fav', fav_ch_checked);
if ($("#form_create").attr("actiontype") == "createcharacter") {
if ($("#character_name_pole").val().length > 0) {
//if the character name text area isn't empty (only posible when creating a new character)
let url = "/createcharacter";
if (crop_data != undefined) {
url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`;
}
jQuery.ajax({
type: "POST",
url: url,
data: formData,
beforeSend: function () {
$("#create_button").attr("disabled", true);
$("#create_button").attr("value", "⏳");
},
cache: false,
contentType: false,
processData: false,
success: async function (html) {
$("#character_cross").click(); //closes the advanced character editing popup
$("#character_name_pole").val("");
create_save_name = "";
$("#description_textarea").val("");
create_save_description = "";
$("#personality_textarea").val("");
create_save_personality = "";
$("#firstmessage_textarea").val("");
create_save_first_message = "";
$("#talkativeness_slider").val(talkativeness_default);
create_save_talkativeness = talkativeness_default;
$("#character_popup_text_h3").text("Create character");
$("#scenario_pole").val("");
create_save_scenario = "";
$("#mes_example_textarea").val("");
create_save_mes_example = "";
create_save_avatar = "";
$("#create_button").removeAttr("disabled");
$("#add_avatar_button").replaceWith(
$("#add_avatar_button").val("").clone(true)
);
$("#create_button").attr("value", "✅");
let oldSelectedChar = null;
if (this_chid != undefined && this_chid != "invalid-safety-id") {
oldSelectedChar = characters[this_chid].avatar;
}
console.log(`new avatar id: ${html}`);
createTagMapFromList("#tagList", html);
await getCharacters();
$("#rm_info_block").transition({ opacity: 0, duration: 0 });
var $prev_img = $("#avatar_div_div").clone();
$("#rm_info_avatar").append($prev_img);
select_rm_info(`char_create`, save_name, oldSelectedChar);
$("#rm_info_block").transition({ opacity: 1.0, duration: 2000 });
crop_data = undefined;
},
error: function (jqXHR, exception) {
$("#create_button").removeAttr("disabled");
},
});
} else {
$("#result_info").html("Name not entered");
}
} else {
let url = '/editcharacter';
if (crop_data != undefined) {
url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`;
}
jQuery.ajax({
type: "POST",
url: url,
data: formData,
beforeSend: function () {
//$("#create_button").attr("disabled", true);
$("#create_button").attr("value", "Save");
},
cache: false,
contentType: false,
processData: false,
success: async function (html) {
if (chat.length === 1) {
var this_ch_mes = default_ch_mes;
if ($("#firstmessage_textarea").val() != "") {
this_ch_mes = $("#firstmessage_textarea").val();
}
if (
this_ch_mes !=
$.trim(
$("#chat")
.children(".mes")
.children(".mes_block")
.children(".mes_text")
.text()
)
) {
clearChat();
chat.length = 0;
chat[0] = {};
chat[0]["name"] = name2;
chat[0]["is_user"] = false;
chat[0]["is_name"] = true;
chat[0]["mes"] = this_ch_mes;
add_mes_without_animation = true;
//console.log('form create submission calling addOneMessage');
addOneMessage(chat[0]);
}
}
$("#create_button").removeAttr("disabled");
await getCharacters();
$("#add_avatar_button").replaceWith(
$("#add_avatar_button").val("").clone(true)
);
$("#create_button").attr("value", "Save");
crop_data = undefined;
},
error: function (jqXHR, exception) {
$("#create_button").removeAttr("disabled");
$("#result_info").html("Error: no connection");
console.log('Cant use that name! Invalid or already exists.');
alert('Cant use that name! Invalid or already exists.');
},
});
}
});
$("#delete_button").click(function () {
popup_type = "del_ch";
callPopup(`
Delete the character?
THIS IS PERMANENT!
THIS WILL ALSO DELETE ALL
OF THE CHARACTER'S CHAT FILES.
`
);
});
$("#rm_info_button").click(function () {
$("#rm_info_avatar").html("");
select_rm_characters();
});
//////// OPTIMIZED ALL CHAR CREATION/EDITING TEXTAREA LISTENERS ///////////////
$("#character_name_pole").on("input", function () {
if (menu_type == "create") {
create_save_name = $("#character_name_pole").val();
}
});
$("#description_textarea, #personality_textarea, #scenario_pole, #mes_example_textarea, #firstmessage_textarea")
.on("input", function () {
if (menu_type == "create") {
create_save_description = $("#description_textarea").val();
create_save_personality = $("#personality_textarea").val();
create_save_scenario = $("#scenario_pole").val();
create_save_mes_example = $("#mes_example_textarea").val();
create_save_first_message = $("#firstmessage_textarea").val();
create_fav_chara = $("#fav_checkbox").val();
} else {
saveCharacterDebounced();
}
});
$("#favorite_button").on('click', function () {
updateFavButtonState(!fav_ch_checked);
if (menu_type != "create") {
saveCharacterDebounced();
}
});
$("#renameCharButton").on('click', renameCharacter);
$(document).on("click", ".renameChatButton", async function () {
const old_filenamefull = $(this).closest('.select_chat_block_wrapper').find('.select_chat_block_filename').text();
const old_filename = old_filenamefull.replace('.jsonl', '');
const popupText = `Enter the new name for the chat:
!!Using an existing filename will produce an error!!
This will break the link between bookmark chats.
No need to add '.jsonl' at the end.
`;
const newName = await callPopup(popupText, 'input', old_filename);
if (!newName || newName == old_filename) {
console.log('no new name found, aborting');
return;
}
const body = {
is_group: !!selected_group,
avatar_url: characters[this_chid]?.avatar,
original_file: `${old_filename}.jsonl`,
renamed_file: `${newName}.jsonl`,
}
try {
const response = await fetch('/renamechat', {
method: 'POST',
body: JSON.stringify(body),
headers: getRequestHeaders(),
});
if (!response.ok) {
throw new Error('Unsuccessful request.');
}
const data = response.json();
if (data.error) {
throw new Error('Server returned an error.');
}
if (selected_group) {
await renameGroupChat(selected_group, old_filename, newName);
}
else {
if (characters[this_chid].chat == old_filename) {
characters[this_chid].chat = newName;
saveCharacterDebounced();
}
}
reloadCurrentChat();
await delay(250);
$("#option_select_chat").trigger('click');
$("#options").hide();
} catch {
await delay(500);
await callPopup('An error has occurred. Chat was not renamed.', 'text');
}
});
$("#talkativeness_slider").on("input", function () {
if (menu_type == "create") {
create_save_talkativeness = $("#talkativeness_slider").val();
} else {
saveCharacterDebounced();
}
});
///////////////////////////////////////////////////////////////////////////////////
$("#api_button").click(function (e) {
e.stopPropagation();
if ($("#api_url_text").val() != "" && !horde_settings.use_horde) {
let value = formatKoboldUrl($.trim($("#api_url_text").val()));
if (!value) {
callPopup('Please enter a valid URL.', 'text');
return;
}
$("#api_url_text").val(value);
api_server = value;
$("#api_loading").css("display", "inline-block");
$("#api_button").css("display", "none");
main_api = "kobold";
saveSettingsDebounced();
is_get_status = true;
is_api_button_press = true;
getStatus();
clearSoftPromptsList();
getSoftPromptsList();
}
else if (horde_settings.use_horde) {
main_api = "kobold";
is_get_status = true;
getStatus();
clearSoftPromptsList();
}
});
$("#api_button_textgenerationwebui").click(function (e) {
e.stopPropagation();
if ($("#textgenerationwebui_api_url_text").val() != "") {
let value = formatKoboldUrl($("#textgenerationwebui_api_url_text").val().trim());
if (!value) {
callPopup('Please enter a valid URL.', 'text');
return;
}
$("#textgenerationwebui_api_url_text").val(value);
$("#api_loading_textgenerationwebui").css("display", "inline-block");
$("#api_button_textgenerationwebui").css("display", "none");
api_server_textgenerationwebui = value;
main_api = "textgenerationwebui";
saveSettingsDebounced();
is_get_status = true;
is_api_button_press = true;
getStatus();
}
});
$("body").click(function () {
if ($("#options").css("opacity") == 1.0) {
$("#options").transition({
opacity: 0.0,
duration: 100, //animation_duration,
easing: animation_easing,
complete: function () {
$("#options").css("display", "none");
},
});
}
});
$("#options_button").click(function () {
// this is the options button click function, shows the options menu if closed
if (
$("#options").css("display") === "none" &&
$("#options").css("opacity") == 0.0
) {
optionsPopper.update();
showBookmarksButtons();
$("#options").css("display", "block");
$("#options").transition({
opacity: 1.0, // the manual setting of CSS via JS is what allows the click-away feature to work
duration: 100,
easing: animation_easing,
complete: function () { optionsPopper.update(); },
});
}
});
///////////// OPTIMIZED LISTENERS FOR LEFT SIDE OPTIONS POPUP MENU //////////////////////
$("#options [id]").on("click", function () {
var id = $(this).attr("id");
if (id == "option_toggle_AN") {
if (selected_group || this_chid !== undefined && $("#floatingPrompt").css("display") === 'none') {
$("#floatingPrompt").css("display", "flex");
$("#floatingPrompt").css("opacity", 0.0);
$("#floatingPrompt").transition({
opacity: 1.0,
duration: animation_duration,
easing: animation_easing,
});
$("#ANBlockToggle").click();
} else {
$("#floatingPrompt").transition({
opacity: 0.0,
duration: 250,
easing: animation_easing,
});
setTimeout(function () { $("#floatingPrompt").hide(); }, 250);
}
}
if (id == "option_select_chat") {
if ((selected_group && !is_group_generating) || (this_chid !== undefined && !is_send_press)) {
displayPastChats();
$("#shadow_select_chat_popup").css("display", "block");
$("#shadow_select_chat_popup").css("opacity", 0.0);
$("#shadow_select_chat_popup").transition({
opacity: 1.0,
duration: animation_duration,
easing: animation_easing,
});
}
}
else if (id == "option_start_new_chat") {
if ((selected_group || this_chid !== undefined) && !is_send_press) {
popup_type = "new_chat";
callPopup("Start new chat?
");
}
}
else if (id == "option_regenerate") {
if (is_send_press == false) {
//hideSwipeButtons();
if (selected_group) {
regenerateGroup();
}
else {
is_send_press = true;
Generate("regenerate");
}
}
}
else if (id == "option_impersonate") {
if (is_send_press == false) {
is_send_press = true;
Generate("impersonate");
}
}
else if (id == "option_delete_mes") {
closeMessageEditor();
hideSwipeButtons();
if ((this_chid != undefined && !is_send_press) || (selected_group && !is_group_generating)) {
$("#dialogue_del_mes").css("display", "block");
$("#send_form").css("display", "none");
$(".del_checkbox").each(function () {
if ($(this).parent().attr("mesid") != 0) {
$(this).css("display", "block");
$(this).parent().children(".for_checkbox").css("display", "none");
}
});
}
is_delete_mode = true;
}
});
//////////////////////////////////////////////////////////////////////////////////////////////
//functionality for the cancel delete messages button, reverts to normal display of input form
$("#dialogue_del_mes_cancel").click(function () {
$("#dialogue_del_mes").css("display", "none");
$("#send_form").css("display", css_send_form_display);
$(".del_checkbox").each(function () {
$(this).css("display", "none");
$(this).parent().children(".for_checkbox").css("display", "block");
$(this).parent().css("background", css_mes_bg);
$(this).prop("checked", false);
});
this_del_mes = 0;
console.log('canceled del msgs, calling showswipesbtns');
showSwipeButtons();
is_delete_mode = false;
});
//confirms message delation with the "ok" button
$("#dialogue_del_mes_ok").click(function () {
$("#dialogue_del_mes").css("display", "none");
$("#send_form").css("display", css_send_form_display);
$(".del_checkbox").each(function () {
$(this).css("display", "none");
$(this).parent().children(".for_checkbox").css("display", "block");
$(this).parent().css("background", css_mes_bg);
$(this).prop("checked", false);
});
if (this_del_mes != 0) {
$(".mes[mesid='" + this_del_mes + "']")
.nextAll("div")
.remove();
$(".mes[mesid='" + this_del_mes + "']").remove();
chat.length = this_del_mes;
count_view_mes = this_del_mes;
saveChatConditional();
var $textchat = $("#chat");
$textchat.scrollTop($textchat[0].scrollHeight);
}
this_del_mes = 0;
$('#chat .mes').last().addClass('last_mes');
$('#chat .mes').eq(-2).removeClass('last_mes');
console.log('confirmed del msgs, calling showswipesbtns');
showSwipeButtons();
is_delete_mode = false;
});
$("#settings_perset").change(function () {
if ($("#settings_perset").find(":selected").val() != "gui") {
preset_settings = $("#settings_perset").find(":selected").text();
const preset = koboldai_settings[koboldai_setting_names[preset_settings]];
loadKoboldSettings(preset);
amount_gen = preset.genamt;
$("#amount_gen").val(amount_gen);
$("#amount_gen_counter").text(`${amount_gen}`);
max_context = preset.max_length;
$("#max_context").val(max_context);
$("#max_context_counter").text(`${max_context}`);
$("#range_block").find('input').prop("disabled", false);
$("#kobold-advanced-config").find('input').prop("disabled", false);
$("#kobold-advanced-config").css('opacity', 1.0);
$("#range_block").css("opacity", 1.0);
$("#amount_gen_block").find('input').prop("disabled", false);
$("#amount_gen_block").css("opacity", 1.0);
} else {
//$('.button').disableSelection();
preset_settings = "gui";
$("#range_block").find('input').prop("disabled", true);
$("#kobold-advanced-config").find('input').prop("disabled", true);
$("#kobold-advanced-config").css('opacity', 0.5);
$("#range_block").css("opacity", 0.5);
$("#amount_gen_block").find('input').prop("disabled", true);
$("#amount_gen_block").css("opacity", 0.45);
}
saveSettingsDebounced();
});
$("#settings_perset_novel").change(function () {
nai_settings.preset_settings_novel = $("#settings_perset_novel")
.find(":selected")
.text();
const preset = novelai_settings[novelai_setting_names[nai_settings.preset_settings_novel]];
loadNovelPreset(preset);
saveSettingsDebounced();
});
$("#main_api").change(function () {
is_pygmalion = false;
is_get_status = false;
is_get_status_novel = false;
setOpenAIOnlineStatus(false);
setPoeOnlineStatus(false);
online_status = "no_connection";
clearSoftPromptsList();
checkOnlineStatus();
changeMainAPI();
saveSettingsDebounced();
});
$("#softprompt").change(async function () {
if (!api_server) {
return;
}
const selected = $("#softprompt").find(":selected").val();
const response = await fetch("/setsoftprompt", {
method: "POST",
headers: getRequestHeaders(),
body: JSON.stringify({ name: selected, api_server: api_server }),
});
if (!response.ok) {
console.error("Couldn't change soft prompt");
}
});
////////////////// OPTIMIZED RANGE SLIDER LISTENERS////////////////
const sliders = [
{
sliderId: "#amount_gen",
counterId: "#amount_gen_counter",
format: (val) => `${val}`,
setValue: (val) => { amount_gen = Number(val); },
},
{
sliderId: "#max_context",
counterId: "#max_context_counter",
format: (val) => `${val}`,
setValue: (val) => { max_context = Number(val); },
}
];
sliders.forEach(slider => {
$(document).on("input", slider.sliderId, function () {
const value = $(this).val();
const formattedValue = slider.format(value);
slider.setValue(value);
$(slider.counterId).text(formattedValue);
console.log('saving');
saveSettingsDebounced();
});
});
//////////////////////////////////////////////////////////////
$("#select_chat_cross").click(function () {
$("#shadow_select_chat_popup").transition({
opacity: 0,
duration: 200,
easing: animation_easing,
});
setTimeout(function () { $("#shadow_select_chat_popup").css("display", "none"); }, 200);
//$("#shadow_select_chat_popup").css("display", "none");
$("#load_select_chat_div").css("display", "block");
});
if (navigator.clipboard === undefined) {
// No clipboard support
$(".mes_copy").remove();
}
else {
$(document).on("pointerup", ".mes_copy", function () {
if (this_chid !== undefined || selected_group) {
const message = $(this).closest(".mes");
if (message.data("isSystem")) {
return;
}
try {
var edit_mes_id = $(this).closest(".mes").attr("mesid");
var text = chat[edit_mes_id]["mes"];
navigator.clipboard.writeText(text);
const copiedMsg = document.createElement("div");
copiedMsg.classList.add('code-copied');
copiedMsg.innerText = "Copied!";
copiedMsg.style.top = `${event.clientY - 55}px`;
copiedMsg.style.left = `${event.clientX - 55}px`;
document.body.append(copiedMsg);
setTimeout(() => {
document.body.removeChild(copiedMsg);
}, 1000);
} catch (err) {
console.error('Failed to copy: ', err);
}
}
});
}
$(document).on("pointerup", ".mes_prompt", function () {
let mesIdForItemization = $(this).closest('.mes').attr('mesId');
if (itemizedPrompts.length !== undefined && itemizedPrompts.length !== 0) {
promptItemize(itemizedPrompts, mesIdForItemization);
}
})
$(document).on("pointerup", "#showRawPrompt", function () {
//console.log(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt);
console.log(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt);
let rawPrompt = itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt;
let rawPromptValues = rawPrompt;
if (Array.isArray(rawPrompt)) {
rawPromptValues = rawPrompt.map(x => x.content).join('\n');
}
//let DisplayStringifiedPrompt = JSON.stringify(itemizedPrompts[PromptArrayItemForRawPromptDisplay].rawPrompt).replace(/\n+/g, '
');
$("#rawPromptWrapper").text(rawPromptValues);
rawPromptPopper.update();
$('#rawPromptPopup').toggle();
})
//********************
//***Message Editor***
$(document).on("click", ".mes_edit", function () {
if (this_chid !== undefined || selected_group) {
// Previously system messages we're allowed to be edited
/*const message = $(this).closest(".mes");
if (message.data("isSystem")) {
return;
}*/
let chatScrollPosition = $("#chat").scrollTop();
if (this_edit_mes_id !== undefined) {
let mes_edited = $("#chat")
.children()
.filter('[mesid="' + this_edit_mes_id + '"]')
.find(".mes_block")
.find(".mes_edit_done");
if (edit_mes_id == count_view_mes - 1) { //if the generating swipe (...)
if (chat[edit_mes_id]['swipe_id'] !== undefined) {
if (chat[edit_mes_id]['swipes'].length === chat[edit_mes_id]['swipe_id']) {
run_edit = false;
}
}
if (run_edit) {
hideSwipeButtons();
}
}
messageEditDone(mes_edited);
}
$(this).closest(".mes_block").find(".mes_text").empty();
$(this).closest(".mes_block").find(".mes_buttons").css("display", "none");
$(this).closest(".mes_block").find(".mes_edit_buttons").css("display", "inline-flex");
var edit_mes_id = $(this).closest(".mes").attr("mesid");
this_edit_mes_id = edit_mes_id;
var text = chat[edit_mes_id]["mes"];
if (chat[edit_mes_id]["is_user"]) {
this_edit_mes_chname = name1;
} else if (chat[edit_mes_id]["force_avatar"]) {
this_edit_mes_chname = chat[edit_mes_id]["name"];
} else {
this_edit_mes_chname = name2;
}
text = text.trim();
$(this)
.closest(".mes_block")
.find(".mes_text")
.append(
``
);
let edit_textarea = $(this)
.closest(".mes_block")
.find(".edit_textarea");
edit_textarea.height(0);
edit_textarea.height(edit_textarea[0].scrollHeight);
edit_textarea.focus();
edit_textarea[0].setSelectionRange( //this sets the cursor at the end of the text
edit_textarea.val().length,
edit_textarea.val().length
);
if (this_edit_mes_id == count_view_mes - 1) {
$("#chat").scrollTop(chatScrollPosition);
}
updateEditArrowClasses();
}
});
$(document).on('input', '#curEditTextarea', function () {
if (power_user.auto_save_msg_edits === true) {
messageEditAuto($(this));
}
})
$(document).on("click", ".mes_edit_cancel", function () {
let text = chat[this_edit_mes_id]["mes"];
$(this).closest(".mes_block").find(".mes_text").empty();
$(this).closest(".mes_edit_buttons").css("display", "none");
$(this).closest(".mes_block").find(".mes_buttons").css("display", "inline-block");
$(this)
.closest(".mes_block")
.find(".mes_text")
.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;
});
$(document).on("click", ".mes_edit_up", function () {
if (is_send_press || this_edit_mes_id <= 0) {
return;
}
hideSwipeButtons();
const targetId = Number(this_edit_mes_id) - 1;
const target = $(`#chat .mes[mesid="${targetId}"]`);
const root = $(this).closest('.mes');
if (root.length === 0 || target.length === 0) {
return;
}
root.insertBefore(target);
target.attr("mesid", this_edit_mes_id);
root.attr("mesid", targetId);
const temp = chat[targetId];
chat[targetId] = chat[this_edit_mes_id];
chat[this_edit_mes_id] = temp;
this_edit_mes_id = targetId;
updateViewMessageIds();
saveChatConditional();
showSwipeButtons();
});
$(document).on("click", ".mes_edit_down", function () {
if (is_send_press || this_edit_mes_id >= chat.length - 1) {
return;
}
hideSwipeButtons();
const targetId = Number(this_edit_mes_id) + 1;
const target = $(`#chat .mes[mesid="${targetId}"]`);
const root = $(this).closest('.mes');
if (root.length === 0 || target.length === 0) {
return;
}
root.insertAfter(target);
target.attr("mesid", this_edit_mes_id);
root.attr("mesid", targetId);
const temp = chat[targetId];
chat[targetId] = chat[this_edit_mes_id];
chat[this_edit_mes_id] = temp;
this_edit_mes_id = targetId;
updateViewMessageIds();
saveChatConditional();
showSwipeButtons();
});
$(document).on("click", ".mes_edit_copy", function () {
if (!confirm('Create a copy of this message?')) {
return;
}
hideSwipeButtons();
let oldScroll = $('#chat')[0].scrollTop;
const clone = JSON.parse(JSON.stringify(chat[this_edit_mes_id])); // quick and dirty clone
clone.send_date = Date.now();
clone.mes = $(this).closest(".mes").find('.edit_textarea').val().trim();
chat.splice(Number(this_edit_mes_id) + 1, 0, clone);
addOneMessage(clone, { insertAfter: this_edit_mes_id });
updateViewMessageIds();
saveChatConditional();
$('#chat')[0].scrollTop = oldScroll;
showSwipeButtons();
});
$(document).on("click", ".mes_edit_delete", function () {
if (!confirm("Are you sure you want to delete this message?")) {
return;
}
const mes = $(this).closest(".mes");
if (!mes) {
return;
}
chat.splice(this_edit_mes_id, 1);
this_edit_mes_id = undefined;
mes.remove();
count_view_mes--;
updateViewMessageIds();
saveChatConditional();
hideSwipeButtons();
showSwipeButtons();
});
$(document).on("click", ".mes_edit_done", function () {
messageEditDone($(this));
});
$("#your_name_button").click(function () {
if (!is_send_press) {
name1 = $("#your_name").val();
if (name1 === undefined || name1 == "") name1 = default_user_name;
console.log(name1);
saveSettings("change_name");
}
});
//Select chat
$("#api_button_novel").on('click', async function (e) {
e.stopPropagation();
const api_key_novel = $("#api_key_novel").val().trim();
if (api_key_novel.length) {
await writeSecret(SECRET_KEYS.NOVEL, api_key_novel);
}
if (!secret_state[SECRET_KEYS.NOVEL]) {
console.log('No secret key saved for NovelAI');
return;
}
$("#api_loading_novel").css("display", "inline-block");
$("#api_button_novel").css("display", "none");
is_get_status_novel = true;
is_api_button_press_novel = true;
});
//**************************CHARACTER IMPORT EXPORT*************************//
$("#character_import_button").click(function () {
$("#character_import_file").click();
});
$("#character_import_file").on("change", function (e) {
$("#rm_info_avatar").html("");
if (!e.target.files.length) {
return;
}
for (const file of e.target.files) {
var ext = file.name.match(/\.(\w+)$/);
if (
!ext ||
(ext[1].toLowerCase() != "json" && ext[1].toLowerCase() != "png" && ext[1] != "webp")
) {
continue;
}
var format = ext[1].toLowerCase();
$("#character_import_file_type").val(format);
var formData = new FormData();
formData.append('avatar', file);
formData.append('file_type', format);
jQuery.ajax({
type: "POST",
url: "/importcharacter",
data: formData,
async: false,
beforeSend: function () {
},
cache: false,
contentType: false,
processData: false,
success: async function (data) {
if (data.file_name !== undefined) {
$("#rm_info_block").transition({ opacity: 0, duration: 0 });
var $prev_img = $("#avatar_div_div").clone();
$prev_img
.children("img")
.attr("src", "characters/" + data.file_name + ".png");
$("#rm_info_avatar").append($prev_img);
let oldSelectedChar = null;
if (this_chid != undefined && this_chid != "invalid-safety-id") {
oldSelectedChar = characters[this_chid].avatar;
}
await getCharacters();
select_rm_info(`char_import`, data.file_name, oldSelectedChar);
$("#rm_info_block").transition({ opacity: 1, duration: 1000 });
}
},
error: function (jqXHR, exception) {
$("#create_button").removeAttr("disabled");
},
});
}
});
$("#export_button").click(function (e) {
$('#export_format_popup').toggle();
exportPopper.update();
});
$(document).on('click', '.export_format', async function () {
const format = $(this).data('format');
if (!format) {
return;
}
const body = { format, avatar_url: characters[this_chid].avatar };
const response = await fetch('/exportcharacter', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify(body),
});
if (response.ok) {
const filename = characters[this_chid].avatar.replace('.png', `.${format}`);
const blob = await response.blob();
const a = document.createElement("a");
a.href = URL.createObjectURL(blob);
a.setAttribute("download", filename);
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
$('#export_format_popup').hide();
});
//**************************CHAT IMPORT EXPORT*************************//
$("#chat_import_button").click(function () {
$("#chat_import_file").click();
});
$("#chat_import_file").on("change", async function (e) {
var file = e.target.files[0];
if (!file) {
return;
}
var ext = file.name.match(/\.(\w+)$/);
if (
!ext ||
(ext[1].toLowerCase() != "json" && ext[1].toLowerCase() != "jsonl")
) {
return;
}
if (selected_group && file.name.endsWith('.json')) {
toastr.warning("Only SillyTavern's own format is supported for group chat imports. Sorry!");
return;
}
var format = ext[1].toLowerCase();
$("#chat_import_file_type").val(format);
var formData = new FormData($("#form_import_chat").get(0));
$("#select_chat_div").html("");
$("#load_select_chat_div").css("display", "block");
if (selected_group) {
await importGroupChat(formData);
} else {
await importCharacterChat(formData);
}
});
$("#rm_button_group_chats").click(function () {
selected_button = "group_chats";
select_group_chats();
});
$("#rm_button_back_from_group").click(function () {
selected_button = "characters";
select_rm_characters();
});
$(document).on("click", ".select_chat_block, .bookmark_link", async function () {
let file_name = $(this).attr("file_name").replace(".jsonl", "");
if (selected_group) {
await openGroupChat(selected_group, file_name);
} else {
await openCharacterChat(file_name);
}
$("#shadow_select_chat_popup").css("display", "none");
$("#load_select_chat_div").css("display", "block");
});
$(document).on("click", ".mes_stop", function () {
if (streamingProcessor) {
streamingProcessor.abortController.abort();
streamingProcessor.isStopped = true;
streamingProcessor.onStopStreaming();
streamingProcessor = null;
}
});
$('.drawer-toggle').click(function () {
var icon = $(this).find('.drawer-icon');
var drawer = $(this).parent().find('.drawer-content');
var drawerWasOpenAlready = $(this).parent().find('.drawer-content').hasClass('openDrawer');
let targetDrawerID = $(this).parent().find('.drawer-content').attr('id');
const pinnedDrawerClicked = drawer.hasClass('pinnedOpen');
if (!drawerWasOpenAlready) {
$('.openDrawer').not('.pinnedOpen').slideToggle(200, "swing");
$('.openIcon').toggleClass('closedIcon openIcon');
$('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer');
icon.toggleClass('openIcon closedIcon');
drawer.toggleClass('openDrawer closedDrawer');
//console.log(targetDrawerID);
if (targetDrawerID === 'right-nav-panel') {
$(this).closest('.drawer').find('.drawer-content').slideToggle({
duration: 200,
easing: "swing",
start: function () {
jQuery(this).css('display', 'flex');
}
})
} else {
$(this).closest('.drawer').find('.drawer-content').slideToggle(200, "swing");
}
} else if (drawerWasOpenAlready) {
icon.toggleClass('closedIcon openIcon');
if (pinnedDrawerClicked) {
$(drawer).slideToggle(200, "swing");
}
else {
$('.openDrawer').not('.pinnedOpen').slideToggle(200, "swing");
}
drawer.toggleClass('closedDrawer openDrawer');
}
});
$("html").on('touchstart mousedown', function (e) {
var clickTarget = $(e.target);
if ($('#export_format_popup').is(':visible')
&& clickTarget.closest('#export_button').length == 0
&& clickTarget.closest('#export_format_popup').length == 0) {
$('#export_format_popup').hide();
}
const forbiddenTargets = [
'#character_cross',
'#avatar-and-name-block',
'#shadow_popup',
'#world_popup',
'.ui-widget',
'.text_pole',
];
for (const id of forbiddenTargets) {
if (clickTarget.closest(id).length > 0) {
return;
}
}
var targetParentHasOpenDrawer = clickTarget.parents('.openDrawer').length;
if (clickTarget.hasClass('drawer-icon') == false && !clickTarget.hasClass('openDrawer')) {
if (jQuery.find('.openDrawer').length !== 0) {
if (targetParentHasOpenDrawer === 0) {
//console.log($('.openDrawer').not('.pinnedOpen').length);
$('.openDrawer').not('.pinnedOpen').slideToggle(200, "swing");
$('.openIcon').toggleClass('closedIcon openIcon');
$('.openDrawer').not('.pinnedOpen').toggleClass('closedDrawer openDrawer');
}
}
}
});
$(document).on('click', '.inline-drawer-toggle', function (e) {
if ($(e.target).hasClass('text_pole')) {
return;
};
var icon = $(this).find('.inline-drawer-icon');
icon.toggleClass('down up');
icon.toggleClass('fa-circle-chevron-down fa-circle-chevron-up');
$(this).closest('.inline-drawer').find('.inline-drawer-content').slideToggle();
});
$(document).on('click', '.mes .avatar', function () {
//if (window.innerWidth > 1000 || $('body').hasClass('waifuMode')) {
let thumbURL = $(this).children('img').attr('src');
let charsPath = '/characters/'
let targetAvatarImg = thumbURL.substring(thumbURL.lastIndexOf("=") + 1);
let avatarSrc = charsPath + targetAvatarImg;
console.log(avatarSrc);
if ($(this).parent().parent().attr('is_user') == 'true') { //handle user avatars
$("#zoomed_avatar").attr('src', thumbURL);
} else if ($(this).parent().parent().attr('is_system') == 'true') { //handle system avatars
$("#zoomed_avatar").attr('src', thumbURL);
} else if ($(this).parent().parent().attr('is_user') == 'false') { //handle char avatars
$("#zoomed_avatar").attr('src', avatarSrc);
}
$('#avatar_zoom_popup').toggle();
//} else { return; }
});
$(document).on('click', '#OpenAllWIEntries', function () {
$("#world_popup_entries_list").children().find('.down').click()
});
$(document).on('click', '#CloseAllWIEntries', function () {
$("#world_popup_entries_list").children().find('.up').click()
});
$(document).keyup(function (e) {
if (e.key === "Escape") {
if (power_user.auto_save_msg_edits === false) {
closeMessageEditor();
$("#send_textarea").focus();
}
if (power_user.auto_save_msg_edits === true) {
$(`#chat .mes[mesid="${this_edit_mes_id}"] .mes_edit_done`).click()
$("#send_textarea").focus();
}
}
});
$("#bg-filter").on("input", function () {
const filterValue = $(this).val().toLowerCase();
$("#bg_menu_content > div").each(function () {
const $bgContent = $(this);
if ($bgContent.attr("title").toLowerCase().includes(filterValue)) {
$bgContent.show();
} else {
$bgContent.hide();
}
});
});
$('#chat').on('scroll', () => {
$('.code-copied').css({ 'display': 'none' });
});
$(document).on('click', '.mes_img_enlarge', enlargeMessageImage);
$(document).on('click', '.mes_img_delete', deleteMessageImage);
$(window).on('beforeunload', () => {
cancelTtsPlay();
if (streamingProcessor) {
console.log('Page reloaded. Aborting streaming...');
streamingProcessor.abortController.abort();
}
});
$(document).on('input', '.range-block-counter div[contenteditable="true"]', function () {
const caretPosition = saveCaretPosition($(this).get(0));
const myText = $(this).text().trim();
$(this).text(myText); // trim line breaks and spaces
const masterSelector = $(this).data('for');
const masterElement = document.getElementById(masterSelector);
if (masterElement == null) {
console.error('Master input element not found for the editable label', masterSelector);
return;
}
const myValue = Number(myText);
if (Number.isNaN(myValue)) {
console.warn('Label input is not a valid number. Resetting the value', myText);
$(masterElement).trigger('input');
restoreCaretPosition($(this).get(0), caretPosition);
return;
}
const masterMin = Number($(masterElement).attr('min'));
const masterMax = Number($(masterElement).attr('max'));
if (myValue < masterMin) {
console.warn('Label input is less than minimum.', myText, '<', masterMin);
restoreCaretPosition($(this).get(0), caretPosition);
return;
}
if (myValue > masterMax) {
console.warn('Label input is more than maximum.', myText, '>', masterMax);
restoreCaretPosition($(this).get(0), caretPosition);
return;
}
console.log('Label value OK, setting to the master input control', myText);
$(masterElement).val(myValue).trigger('input');
restoreCaretPosition($(this).get(0), caretPosition);
});
})