import {
saveSettingsDebounced,
scrollChatToBottom,
characters,
callPopup,
getStatus,
reloadMarkdownProcessor,
reloadCurrentChat,
getRequestHeaders,
substituteParams,
updateVisibleDivs,
eventSource,
event_types,
getCurrentChatId,
printCharacters,
name1,
name2,
setCharacterId,
setEditedMessageId
} from "../script.js";
import { favsToHotswap, isMobile, initMovingUI } from "./RossAscends-mods.js";
import {
groups,
resetSelectedGroup,
selected_group,
} from "./group-chats.js";
import { registerSlashCommand } from "./slash-commands.js";
import { delay } from "./utils.js";
export {
loadPowerUserSettings,
loadMovingUIState,
collapseNewlines,
playMessageSound,
sortGroupMembers,
sortCharactersList,
fixMarkdown,
power_user,
pygmalion_options,
tokenizers,
send_on_enter_options,
};
export const MAX_CONTEXT_DEFAULT = 4096;
const MAX_CONTEXT_UNLOCKED = 65536;
const avatar_styles = {
ROUND: 0,
RECTANGULAR: 1,
}
export const chat_styles = {
DEFAULT: 0,
BUBBLES: 1,
DOCUMENT: 2,
}
const pygmalion_options = {
DISABLED: -1,
AUTO: 0,
ENABLED: 1,
}
const tokenizers = {
NONE: 0,
GPT3: 1,
CLASSIC: 2,
LLAMA: 3,
NERD: 4,
NERD2: 5,
API: 6,
BEST_MATCH: 99,
}
const send_on_enter_options = {
DISABLED: -1,
AUTO: 0,
ENABLED: 1,
}
export const persona_description_positions = {
BEFORE_CHAR: 0,
AFTER_CHAR: 1,
TOP_AN: 2,
BOTTOM_AN: 3,
}
let power_user = {
tokenizer: tokenizers.BEST_MATCH,
token_padding: 64,
collapse_newlines: false,
pygmalion_formatting: pygmalion_options.AUTO,
pin_examples: false,
disable_description_formatting: false,
disable_scenario_formatting: false,
disable_personality_formatting: false,
disable_examples_formatting: false,
disable_start_formatting: false,
trim_sentences: false,
include_newline: false,
always_force_name2: false,
user_prompt_bias: '',
show_user_prompt_bias: true,
multigen: false,
multigen_first_chunk: 50,
multigen_next_chunks: 30,
custom_chat_separator: '',
markdown_escape_strings: '',
fast_ui_mode: true,
avatar_style: avatar_styles.ROUND,
chat_display: chat_styles.DEFAULT,
chat_width: 50,
never_resize_avatars: false,
show_card_avatar_urls: false,
play_message_sound: false,
play_sound_unfocused: true,
auto_save_msg_edits: false,
confirm_message_delete: true,
sort_field: 'name',
sort_order: 'asc',
sort_rule: null,
font_scale: 1,
blur_strength: 10,
shadow_width: 2,
main_text_color: `${getComputedStyle(document.documentElement).getPropertyValue('--SmartThemeBodyColor').trim()}`,
italics_text_color: `${getComputedStyle(document.documentElement).getPropertyValue('--SmartThemeEmColor').trim()}`,
quote_text_color: `${getComputedStyle(document.documentElement).getPropertyValue('--SmartThemeQuoteColor').trim()}`,
blur_tint_color: `${getComputedStyle(document.documentElement).getPropertyValue('--SmartThemeBlurTintColor').trim()}`,
user_mes_blur_tint_color: `${getComputedStyle(document.documentElement).getPropertyValue('--SmartThemeUserMesBlurTintColor').trim()}`,
bot_mes_blur_tint_color: `${getComputedStyle(document.documentElement).getPropertyValue('--SmartThemeBotMesBlurTintColor').trim()}`,
shadow_color: `${getComputedStyle(document.documentElement).getPropertyValue('--SmartThemeShadowColor').trim()}`,
waifuMode: false,
movingUI: false,
movingUIState: {},
movingUIPreset: '',
noShadows: false,
theme: 'Default (Dark) 1.7.1',
auto_swipe: false,
auto_swipe_minimum_length: 0,
auto_swipe_blacklist: [],
auto_swipe_blacklist_threshold: 2,
auto_scroll_chat_to_bottom: true,
auto_fix_generated_markdown: true,
send_on_enter: send_on_enter_options.AUTO,
console_log_prompts: false,
render_formulas: false,
allow_name1_display: false,
allow_name2_display: false,
//removeXML: false,
hotswap_enabled: true,
timer_enabled: true,
timestamps_enabled: true,
mesIDDisplay_enabled: false,
max_context_unlocked: false,
prefer_character_prompt: true,
prefer_character_jailbreak: true,
continue_on_send: false,
trim_spaces: true,
relaxed_api_urls: false,
instruct: {
enabled: false,
wrap: true,
names: false,
system_prompt: "Below is an instruction that describes a task. Write a response that appropriately completes the request.\n\nWrite {{char}}'s next reply in a fictional roleplay chat between {{user}} and {{char}}. Write 1 reply only.",
system_sequence: '',
stop_sequence: '',
input_sequence: '### Instruction:',
output_sequence: '### Response:',
preset: 'Alpaca',
separator_sequence: '',
macro: false,
names_force_groups: true,
},
personas: {},
default_persona: null,
persona_descriptions: {},
persona_description: '',
persona_description_position: persona_description_positions.BEFORE_CHAR,
persona_show_notifications: true,
custom_stopping_strings: '',
custom_stopping_strings_macro: true,
fuzzy_search: false,
encode_tags: false,
lazy_load: 0,
};
let themes = [];
let movingUIPresets = [];
let instruct_presets = [];
const storage_keys = {
fast_ui_mode: "TavernAI_fast_ui_mode",
avatar_style: "TavernAI_avatar_style",
chat_display: "TavernAI_chat_display",
chat_width: "chat_width",
font_scale: "TavernAI_font_scale",
main_text_color: "TavernAI_main_text_color",
italics_text_color: "TavernAI_italics_text_color",
quote_text_color: "TavernAI_quote_text_color",
blur_tint_color: "TavernAI_blur_tint_color",
user_mes_blur_tint_color: "TavernAI_user_mes_blur_tint_color",
bot_mes_blur_tint_color: "TavernAI_bot_mes_blur_tint_color",
blur_strength: "TavernAI_blur_strength",
shadow_color: "TavernAI_shadow_color",
shadow_width: "TavernAI_shadow_width",
waifuMode: "TavernAI_waifuMode",
movingUI: "TavernAI_movingUI",
noShadows: "TavernAI_noShadows",
hotswap_enabled: 'HotswapEnabled',
timer_enabled: 'TimerEnabled',
timestamps_enabled: 'TimestampsEnabled',
mesIDDisplay_enabled: 'mesIDDisplayEnabled',
};
let browser_has_focus = true;
function playMessageSound() {
if (!power_user.play_message_sound) {
return;
}
if (power_user.play_sound_unfocused && browser_has_focus) {
return;
}
const audio = document.getElementById('audio_message_sound');
audio.volume = 0.8;
audio.pause();
audio.currentTime = 0;
audio.play();
}
function collapseNewlines(x) {
return x.replaceAll(/\n+/g, "\n");
}
function fixMarkdown(text) {
// fix formatting problems in markdown
// e.g.:
// "^example * text*\n" -> "^example *text*\n"
// "^*example * text\n" -> "^*example* text\n"
// "^example *text *\n" -> "^example *text*\n"
// "^* example * text\n" -> "^*example* text\n"
// take note that the side you move the asterisk depends on where its pairing is
// i.e. both of the following strings have the same broken asterisk ' * ',
// but you move the first to the left and the second to the right, to match the non-broken asterisk "^example * text*\n" "^*example * text\n"
// and you HAVE to handle the cases where multiple pairs of asterisks exist in the same line
// i.e. "^example * text* * harder problem *\n" -> "^example *text* *harder problem*\n"
// Find pairs of formatting characters and capture the text in between them
const format = /([\*_]{1,2})([\s\S]*?)\1/gm;
let matches = [];
let match;
while ((match = format.exec(text)) !== null) {
matches.push(match);
}
// Iterate through the matches and replace adjacent spaces immediately beside formatting characters
let newText = text;
for (let i = matches.length - 1; i >= 0; i--) {
let matchText = matches[i][0];
let replacementText = matchText.replace(/(\*|_)([\t \u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff]+)|([\t \u00a0\u1680\u2000-\u200a\u202f\u205f\u3000\ufeff]+)(\*|_)/g, '$1$4');
newText = newText.slice(0, matches[i].index) + replacementText + newText.slice(matches[i].index + matchText.length);
}
return newText;
}
function switchHotswap() {
const value = localStorage.getItem(storage_keys.hotswap_enabled);
power_user.hotswap_enabled = value === null ? true : value == "true";
$("body").toggleClass("no-hotswap", !power_user.hotswap_enabled);
$("#hotswapEnabled").prop("checked", power_user.hotswap_enabled);
}
function switchTimer() {
const value = localStorage.getItem(storage_keys.timer_enabled);
power_user.timer_enabled = value === null ? true : value == "true";
$("body").toggleClass("no-timer", !power_user.timer_enabled);
$("#messageTimerEnabled").prop("checked", power_user.timer_enabled);
}
function switchTimestamps() {
const value = localStorage.getItem(storage_keys.timestamps_enabled);
power_user.timestamps_enabled = value === null ? true : value == "true";
$("body").toggleClass("no-timestamps", !power_user.timestamps_enabled);
$("#messageTimestampsEnabled").prop("checked", power_user.timestamps_enabled);
}
function switchMesIDDisplay() {
const value = localStorage.getItem(storage_keys.mesIDDisplay_enabled);
power_user.mesIDDisplay_enabled = value === null ? true : value == "true";
$("body").toggleClass("no-mesIDDisplay", !power_user.mesIDDisplay_enabled);
$("#MesIDDisplayEnabled").prop("checked", power_user.mesIDDisplay_enabled);
}
function switchUiMode() {
const fastUi = localStorage.getItem(storage_keys.fast_ui_mode);
power_user.fast_ui_mode = fastUi === null ? true : fastUi == "true";
$("body").toggleClass("no-blur", power_user.fast_ui_mode);
$("#fast_ui_mode").prop("checked", power_user.fast_ui_mode);
}
function toggleWaifu() {
$("#waifuMode").trigger("click");
}
function switchWaifuMode() {
$("body").toggleClass("waifuMode", power_user.waifuMode);
$("#waifuMode").prop("checked", power_user.waifuMode);
scrollChatToBottom();
}
function switchSpoilerMode() {
if (power_user.spoiler_free_mode) {
$("#description_div").hide();
$("#description_textarea").hide();
$("#firstmessage_textarea").hide();
$("#first_message_div").hide();
$("#spoiler_free_desc").show();
}
else {
$("#description_div").show();
$("#description_textarea").show();
$("#firstmessage_textarea").show();
$("#first_message_div").show();
$("#spoiler_free_desc").hide();
}
}
function peekSpoilerMode() {
$("#description_div").toggle();
$("#description_textarea").toggle();
$("#firstmessage_textarea").toggle();
$("#first_message_div").toggle();
}
function switchMovingUI() {
const movingUI = localStorage.getItem(storage_keys.movingUI);
power_user.movingUI = movingUI === null ? false : movingUI == "true";
$("body").toggleClass("movingUI", power_user.movingUI);
if (power_user.movingUI === true) {
initMovingUI()
if (power_user.movingUIState) {
loadMovingUIState();
}
};
}
function noShadows() {
const noShadows = localStorage.getItem(storage_keys.noShadows);
power_user.noShadows = noShadows === null ? false : noShadows == "true";
$("body").toggleClass("noShadows", power_user.noShadows);
$("#noShadowsmode").prop("checked", power_user.noShadows);
scrollChatToBottom();
}
function applyAvatarStyle() {
power_user.avatar_style = Number(localStorage.getItem(storage_keys.avatar_style) ?? avatar_styles.ROUND);
$("body").toggleClass("big-avatars", power_user.avatar_style === avatar_styles.RECTANGULAR);
$(`input[name="avatar_style"][value="${power_user.avatar_style}"]`).prop("checked", true);
}
function applyChatDisplay() {
if (!power_user.chat_display === (null || undefined)) {
console.debug('applyChatDisplay: saw no chat display type defined')
return
}
console.debug(`applyChatDisplay: applying ${power_user.chat_display}`)
$(`#chat_display option[value=${power_user.chat_display}]`).attr("selected", true)
switch (power_user.chat_display) {
case 0: {
console.log('applying default chat')
$("body").removeClass("bubblechat");
$("body").removeClass("documentstyle");
break
}
case 1: {
console.log('applying bubblechat')
$("body").addClass("bubblechat");
$("body").removeClass("documentstyle");
break
}
case 2: {
console.log('applying document style')
$("body").removeClass("bubblechat");
$("body").addClass("documentstyle");
break
}
}
}
function applyChatWidth() {
power_user.chat_width = Number(localStorage.getItem(storage_keys.chat_width) ?? 50);
let r = document.documentElement;
r.style.setProperty('--sheldWidth', `${power_user.chat_width}vw`);
$('#chat_width_slider').val(power_user.chat_width);
}
async function applyThemeColor(type) {
if (type === 'main') {
document.documentElement.style.setProperty('--SmartThemeBodyColor', power_user.main_text_color);
}
if (type === 'italics') {
document.documentElement.style.setProperty('--SmartThemeEmColor', power_user.italics_text_color);
}
if (type === 'quote') {
document.documentElement.style.setProperty('--SmartThemeQuoteColor', power_user.quote_text_color);
}
/* if (type === 'fastUIBG') {
document.documentElement.style.setProperty('--SmartThemeFastUIBGColor', power_user.fastui_bg_color);
} */
if (type === 'blurTint') {
document.documentElement.style.setProperty('--SmartThemeBlurTintColor', power_user.blur_tint_color);
}
if (type === 'userMesBlurTint') {
document.documentElement.style.setProperty('--SmartThemeUserMesBlurTintColor', power_user.user_mes_blur_tint_color);
}
if (type === 'botMesBlurTint') {
document.documentElement.style.setProperty('--SmartThemeBotMesBlurTintColor', power_user.bot_mes_blur_tint_color);
}
if (type === 'shadow') {
document.documentElement.style.setProperty('--SmartThemeShadowColor', power_user.shadow_color);
}
}
async function applyBlurStrength() {
power_user.blur_strength = Number(localStorage.getItem(storage_keys.blur_strength) ?? 1);
document.documentElement.style.setProperty('--blurStrength', power_user.blur_strength);
$("#blur_strength_counter").text(power_user.blur_strength);
$("#blur_strength").val(power_user.blur_strength);
}
async function applyShadowWidth() {
power_user.shadow_width = Number(localStorage.getItem(storage_keys.shadow_width) ?? 2);
document.documentElement.style.setProperty('--shadowWidth', power_user.shadow_width);
$("#shadow_width_counter").text(power_user.shadow_width);
$("#shadow_width").val(power_user.shadow_width);
}
async function applyFontScale() {
power_user.font_scale = Number(localStorage.getItem(storage_keys.font_scale) ?? 1);
document.documentElement.style.setProperty('--fontScale', power_user.font_scale);
$("#font_scale_counter").text(power_user.font_scale);
$("#font_scale").val(power_user.font_scale);
}
async function applyTheme(name) {
const theme = themes.find(x => x.name == name);
if (!theme) {
return;
}
const themeProperties = [
{ key: 'main_text_color', selector: '#main-text-color-picker', type: 'main' },
{ key: 'italics_text_color', selector: '#italics-color-picker', type: 'italics' },
{ key: 'quote_text_color', selector: '#quote-color-picker', type: 'quote' },
{ key: 'blur_tint_color', selector: '#blur-tint-color-picker', type: 'blurTint' },
{ key: 'user_mes_blur_tint_color', selector: '#user-mes-blur-tint-color-picker', type: 'userMesBlurTint' },
{ key: 'bot_mes_blur_tint_color', selector: '#bot-mes-blur-tint-color-picker', type: 'botMesBlurTint' },
{ key: 'shadow_color', selector: '#shadow-color-picker', type: 'shadow' },
{
key: 'blur_strength',
action: async () => {
localStorage.setItem(storage_keys.blur_strength, power_user.blur_strength);
await applyBlurStrength();
}
},
{
key: 'shadow_width',
action: async () => {
localStorage.setItem(storage_keys.shadow_width, power_user.shadow_width);
await applyShadowWidth();
}
},
{
key: 'font_scale',
action: async () => {
localStorage.setItem(storage_keys.font_scale, power_user.font_scale);
await applyFontScale();
}
},
{
key: 'fast_ui_mode',
action: async () => {
localStorage.setItem(storage_keys.fast_ui_mode, power_user.fast_ui_mode);
switchUiMode();
}
},
{
key: 'waifuMode',
action: async () => {
localStorage.setItem(storage_keys.waifuMode, power_user.waifuMode);
switchWaifuMode();
}
},
{
key: 'chat_display',
action: async () => {
localStorage.setItem(storage_keys.chat_display, power_user.chat_display);
applyChatDisplay();
}
},
{
key: 'avatar_style',
action: async () => {
localStorage.setItem(storage_keys.avatar_style, power_user.avatar_style);
applyAvatarStyle();
}
},
{
key: 'noShadows',
action: async () => {
localStorage.setItem(storage_keys.noShadows, power_user.noShadows);
noShadows();
}
},
{
key: 'chat_width',
action: async () => {
// If chat width is not set, set it to 50
if (!power_user.chat_width) {
power_user.chat_width = 50;
}
localStorage.setItem(storage_keys.chat_width, power_user.chat_width);
applyChatWidth();
}
},
{
key: 'timer_enabled',
action: async () => {
localStorage.setItem(storage_keys.timer_enabled, power_user.timer_enabled);
switchTimer();
}
},
{
key: 'timestamps_enabled',
action: async () => {
localStorage.setItem(storage_keys.timestamps_enabled, power_user.timestamps_enabled);
switchTimestamps();
}
},
{
key: 'mesIDDisplay_enabled',
action: async () => {
localStorage.setItem(storage_keys.mesIDDisplay_enabled, power_user.mesIDDisplay_enabled);
switchMesIDDisplay();
}
},
{
key: 'hotswap_enabled',
action: async () => {
localStorage.setItem(storage_keys.hotswap_enabled, power_user.hotswap_enabled);
switchHotswap();
}
}
];
for (const { key, selector, type, action } of themeProperties) {
if (theme[key] !== undefined) {
power_user[key] = theme[key];
if (selector) $(selector).attr('color', power_user[key]);
if (type) await applyThemeColor(type);
if (action) await action();
} else {
if (selector) { $(selector).attr('color', 'rgba(0,0,0,0)') };
console.debug(`Empty theme key: ${key}`);
power_user[key] = '';
}
}
console.log('theme applied: ' + name);
}
async function applyMovingUIPreset(name) {
resetMovablePanels('quiet')
const movingUIPreset = movingUIPresets.find(x => x.name == name);
if (!movingUIPreset) {
return;
}
power_user.movingUIState = movingUIPreset.movingUIState;
console.log('MovingUI Preset applied: ' + name);
loadMovingUIState()
}
switchUiMode();
applyFontScale();
applyThemeColor();
applyChatWidth();
applyAvatarStyle();
applyBlurStrength();
applyShadowWidth();
switchMovingUI();
noShadows();
switchHotswap();
switchTimer();
switchTimestamps();
switchMesIDDisplay();
function loadPowerUserSettings(settings, data) {
// Load from settings.json
if (settings.power_user !== undefined) {
Object.assign(power_user, settings.power_user);
}
if (data.themes !== undefined) {
themes = data.themes;
}
if (data.movingUIPresets !== undefined) {
movingUIPresets = data.movingUIPresets;
}
if (data.instruct !== undefined) {
instruct_presets = data.instruct;
}
// These are still local storage
const fastUi = localStorage.getItem(storage_keys.fast_ui_mode);
const movingUI = localStorage.getItem(storage_keys.movingUI);
const noShadows = localStorage.getItem(storage_keys.noShadows);
const hotswap = localStorage.getItem(storage_keys.hotswap_enabled);
const timer = localStorage.getItem(storage_keys.timer_enabled);
const timestamps = localStorage.getItem(storage_keys.timestamps_enabled);
const mesIDDisplay = localStorage.getItem(storage_keys.mesIDDisplay_enabled);
power_user.fast_ui_mode = fastUi === null ? true : fastUi == "true";
power_user.movingUI = movingUI === null ? false : movingUI == "true";
power_user.noShadows = noShadows === null ? false : noShadows == "true";
power_user.hotswap_enabled = hotswap === null ? true : hotswap == "true";
power_user.timer_enabled = timer === null ? true : timer == "true";
power_user.timestamps_enabled = timestamps === null ? true : timestamps == "true";
power_user.mesIDDisplay_enabled = mesIDDisplay === null ? true : mesIDDisplay == "true";
power_user.avatar_style = Number(localStorage.getItem(storage_keys.avatar_style) ?? avatar_styles.ROUND);
//power_user.chat_display = Number(localStorage.getItem(storage_keys.chat_display) ?? chat_styles.DEFAULT);
power_user.chat_width = Number(localStorage.getItem(storage_keys.chat_width) ?? 50);
power_user.font_scale = Number(localStorage.getItem(storage_keys.font_scale) ?? 1);
power_user.blur_strength = Number(localStorage.getItem(storage_keys.blur_strength) ?? 10);
if (power_user.chat_display === '') {
power_user.chat_display = chat_styles.DEFAULT;
}
if (power_user.waifuMode === '') {
power_user.waifuMode = false;
}
if (power_user.chat_width === '') {
power_user.chat_width = 50;
}
$('#relaxed_api_urls').prop("checked", power_user.relaxed_api_urls);
$('#trim_spaces').prop("checked", power_user.trim_spaces);
$('#continue_on_send').prop("checked", power_user.continue_on_send);
$('#auto_swipe').prop("checked", power_user.auto_swipe);
$('#auto_swipe_minimum_length').val(power_user.auto_swipe_minimum_length);
$('#auto_swipe_blacklist').val(power_user.auto_swipe_blacklist.join(", "));
$('#auto_swipe_blacklist_threshold').val(power_user.auto_swipe_blacklist_threshold);
$('#custom_stopping_strings').val(power_user.custom_stopping_strings);
$("#custom_stopping_strings_macro").prop("checked", power_user.custom_stopping_strings_macro);
$('#fuzzy_search_checkbox').prop("checked", power_user.fuzzy_search);
$('#persona_show_notifications').prop("checked", power_user.persona_show_notifications);
$('#encode_tags').prop("checked", power_user.encode_tags);
$('#lazy_load').val(Number(power_user.lazy_load));
$("#console_log_prompts").prop("checked", power_user.console_log_prompts);
$('#auto_fix_generated_markdown').prop("checked", power_user.auto_fix_generated_markdown);
$('#auto_scroll_chat_to_bottom').prop("checked", power_user.auto_scroll_chat_to_bottom);
$(`#tokenizer option[value="${power_user.tokenizer}"]`).attr('selected', true);
$(`#pygmalion_formatting option[value=${power_user.pygmalion_formatting}]`).attr("selected", true);
$(`#send_on_enter option[value=${power_user.send_on_enter}]`).attr("selected", true);
$("#import_card_tags").prop("checked", power_user.import_card_tags);
$("#confirm_message_delete").prop("checked", power_user.confirm_message_delete !== undefined ? !!power_user.confirm_message_delete : true);
$("#spoiler_free_mode").prop("checked", power_user.spoiler_free_mode);
$("#collapse-newlines-checkbox").prop("checked", power_user.collapse_newlines);
$("#pin-examples-checkbox").prop("checked", power_user.pin_examples);
$("#disable-description-formatting-checkbox").prop("checked", power_user.disable_description_formatting);
$("#disable-scenario-formatting-checkbox").prop("checked", power_user.disable_scenario_formatting);
$("#disable-personality-formatting-checkbox").prop("checked", power_user.disable_personality_formatting);
$("#always-force-name2-checkbox").prop("checked", power_user.always_force_name2);
$("#disable-examples-formatting-checkbox").prop("checked", power_user.disable_examples_formatting);
$('#disable-start-formatting-checkbox').prop("checked", power_user.disable_start_formatting);
$("#trim_sentences_checkbox").prop("checked", power_user.trim_sentences);
$("#include_newline_checkbox").prop("checked", power_user.include_newline);
$('#render_formulas').prop("checked", power_user.render_formulas);
$("#custom_chat_separator").val(power_user.custom_chat_separator);
$("#markdown_escape_strings").val(power_user.markdown_escape_strings);
$("#fast_ui_mode").prop("checked", power_user.fast_ui_mode);
$("#waifuMode").prop("checked", power_user.waifuMode);
$("#movingUImode").prop("checked", power_user.movingUI);
$("#noShadowsmode").prop("checked", power_user.noShadows);
$("#start_reply_with").val(power_user.user_prompt_bias);
$("#chat-show-reply-prefix-checkbox").prop("checked", power_user.show_user_prompt_bias);
$("#multigen").prop("checked", power_user.multigen);
$("#multigen_first_chunk").val(power_user.multigen_first_chunk);
$("#multigen_next_chunks").val(power_user.multigen_next_chunks);
$("#play_message_sound").prop("checked", power_user.play_message_sound);
$("#play_sound_unfocused").prop("checked", power_user.play_sound_unfocused);
$("#never_resize_avatars").prop("checked", power_user.never_resize_avatars);
$("#show_card_avatar_urls").prop("checked", power_user.show_card_avatar_urls);
$("#auto_save_msg_edits").prop("checked", power_user.auto_save_msg_edits);
$("#allow_name1_display").prop("checked", power_user.allow_name1_display);
$("#allow_name2_display").prop("checked", power_user.allow_name2_display);
//$("#removeXML").prop("checked", power_user.removeXML);
$("#hotswapEnabled").prop("checked", power_user.hotswap_enabled);
$("#messageTimerEnabled").prop("checked", power_user.timer_enabled);
$("#messageTimestampsEnabled").prop("checked", power_user.timestamps_enabled);
$("#mesIDDisplayEnabled").prop("checked", power_user.mesIDDisplay_enabled);
$("#prefer_character_prompt").prop("checked", power_user.prefer_character_prompt);
$("#prefer_character_jailbreak").prop("checked", power_user.prefer_character_jailbreak);
$(`input[name="avatar_style"][value="${power_user.avatar_style}"]`).prop("checked", true);
$(`#chat_display option[value=${power_user.chat_display}]`).attr("selected", true).trigger('change');
$('#chat_width_slider').val(power_user.chat_width);
$("#token_padding").val(power_user.token_padding);
$("#font_scale").val(power_user.font_scale);
$("#font_scale_counter").text(power_user.font_scale);
$("#blur_strength").val(power_user.blur_strength);
$("#blur_strength_counter").text(power_user.blur_strength);
$("#shadow_width").val(power_user.shadow_width);
$("#shadow_width_counter").text(power_user.shadow_width);
$("#main-text-color-picker").attr('color', power_user.main_text_color);
$("#italics-color-picker").attr('color', power_user.italics_text_color);
$("#quote-color-picker").attr('color', power_user.quote_text_color);
//$("#fastui-bg-color-picker").attr('color', power_user.fastui_bg_color);
$("#blur-tint-color-picker").attr('color', power_user.blur_tint_color);
$("#user-mes-blur-tint-color-picker").attr('color', power_user.user_mes_blur_tint_color);
$("#bot-mes-blur-tint-color-picker").attr('color', power_user.bot_mes_blur_tint_color);
$("#shadow-color-picker").attr('color', power_user.shadow_color);
for (const theme of themes) {
const option = document.createElement('option');
option.value = theme.name;
option.innerText = theme.name;
option.selected = theme.name == power_user.theme;
$("#themes").append(option);
}
for (const movingUIPreset of movingUIPresets) {
const option = document.createElement('option');
option.value = movingUIPreset.name;
option.innerText = movingUIPreset.name;
option.selected = movingUIPreset.name == power_user.movingUIPreset;
$("#movingUIPresets").append(option);
}
$(`#character_sort_order option[data-order="${power_user.sort_order}"][data-field="${power_user.sort_field}"]`).prop("selected", true);
sortCharactersList();
reloadMarkdownProcessor(power_user.render_formulas);
loadInstructMode();
loadMaxContextUnlocked();
switchWaifuMode();
switchSpoilerMode();
loadMovingUIState();
loadCharListState();
}
async function loadCharListState() {
if (document.getElementById('CharID0') !== null) {
console.debug('setting charlist state to...')
if (power_user.charListGrid === true) {
console.debug('..to grid')
$("#charListGridToggle").trigger('click')
} else { console.debug('..to list') }
} else {
console.debug('charlist not ready yet')
await delay(100)
loadCharListState();
}
}
function loadMovingUIState() {
if (isMobile() === false
&& power_user.movingUIState
&& power_user.movingUI === true) {
console.debug('loading movingUI state')
for (var elmntName of Object.keys(power_user.movingUIState)) {
var elmntState = power_user.movingUIState[elmntName];
try {
var elmnt = $('#' + $.escapeSelector(elmntName));
if (elmnt.length) {
console.debug(`loading state for ${elmntName}`)
elmnt.css(elmntState);
} else {
console.debug(`skipping ${elmntName} because it doesn't exist in the DOM`)
}
} catch (err) {
console.debug(`error occurred while processing ${elmntName}: ${err}`)
}
}
} else {
console.debug('skipping movingUI state load')
return
}
}
function loadMaxContextUnlocked() {
$('#max_context_unlocked').prop('checked', power_user.max_context_unlocked);
$('#max_context_unlocked').on('change', function () {
power_user.max_context_unlocked = !!$(this).prop('checked');
switchMaxContextSize();
saveSettingsDebounced();
});
switchMaxContextSize();
}
function switchMaxContextSize() {
const element = $('#max_context');
const maxValue = power_user.max_context_unlocked ? MAX_CONTEXT_UNLOCKED : MAX_CONTEXT_DEFAULT;
element.attr('max', maxValue);
const value = Number(element.val());
if (value >= maxValue) {
element.val(maxValue).trigger('input');
}
}
function loadInstructMode() {
const controls = [
{ id: "instruct_enabled", property: "enabled", isCheckbox: true },
{ id: "instruct_wrap", property: "wrap", isCheckbox: true },
{ id: "instruct_system_prompt", property: "system_prompt", isCheckbox: false },
{ id: "instruct_system_sequence", property: "system_sequence", isCheckbox: false },
{ id: "instruct_separator_sequence", property: "separator_sequence", isCheckbox: false },
{ id: "instruct_input_sequence", property: "input_sequence", isCheckbox: false },
{ id: "instruct_output_sequence", property: "output_sequence", isCheckbox: false },
{ id: "instruct_stop_sequence", property: "stop_sequence", isCheckbox: false },
{ id: "instruct_names", property: "names", isCheckbox: true },
{ id: "instruct_macro", property: "macro", isCheckbox: true },
{ id: "instruct_names_force_groups", property: "names_force_groups", isCheckbox: true },
];
if (power_user.instruct.names_force_groups === undefined) {
power_user.instruct.names_force_groups = true;
}
controls.forEach(control => {
const $element = $(`#${control.id}`);
if (control.isCheckbox) {
$element.prop('checked', power_user.instruct[control.property]);
} else {
$element.val(power_user.instruct[control.property]);
}
$element.on('input', function () {
power_user.instruct[control.property] = control.isCheckbox ? !!$(this).prop('checked') : $(this).val();
saveSettingsDebounced();
});
});
instruct_presets.forEach((preset) => {
const name = preset.name;
const option = document.createElement('option');
option.value = name;
option.innerText = name;
option.selected = name === power_user.instruct.preset;
$('#instruct_presets').append(option);
});
$('#instruct_presets').on('change', function () {
const name = $(this).find(':selected').val();
const preset = instruct_presets.find(x => x.name === name);
if (!preset) {
return;
}
power_user.instruct.preset = name;
controls.forEach(control => {
if (preset[control.property] !== undefined) {
power_user.instruct[control.property] = preset[control.property];
const $element = $(`#${control.id}`);
if (control.isCheckbox) {
$element.prop('checked', power_user.instruct[control.property]).trigger('input');
} else {
$element.val(power_user.instruct[control.property]).trigger('input');
}
}
});
});
}
export function fuzzySearchCharacters(searchValue) {
const fuse = new Fuse(characters, {
keys: [
{ name: 'data.name', weight: 5 },
{ name: 'data.description', weight: 3 },
{ name: 'data.mes_example', weight: 3 },
{ name: 'data.scenario', weight: 2 },
{ name: 'data.personality', weight: 2 },
{ name: 'data.first_mes', weight: 2 },
{ name: 'data.creator_notes', weight: 2 },
{ name: 'data.creator', weight: 1 },
{ name: 'data.tags', weight: 1 },
{ name: 'data.alternate_greetings', weight: 1 }
],
includeScore: true,
ignoreLocation: true,
threshold: 0.2,
});
const results = fuse.search(searchValue);
console.debug('Fuzzy search results for ' + searchValue, results)
const indices = results.map(x => x.refIndex);
return indices;
}
export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2) {
let includeNames = isNarrator ? false : power_user.instruct.names;
if (!isNarrator && power_user.instruct.names_force_groups && (selected_group || forceAvatar)) {
includeNames = true;
}
let sequence = (isUser || isNarrator) ? power_user.instruct.input_sequence : power_user.instruct.output_sequence;
if (power_user.instruct.macro) {
sequence = substituteParams(sequence, name1, name2);
}
const separator = power_user.instruct.wrap ? '\n' : '';
const separatorSequence = power_user.instruct.separator_sequence && !isUser
? power_user.instruct.separator_sequence
: (power_user.instruct.wrap ? '\n' : '');
const textArray = includeNames ? [sequence, `${name}: ${mes}`, separatorSequence] : [sequence, mes, separatorSequence];
const text = textArray.filter(x => x).join(separator);
return text;
}
export function formatInstructStoryString(story, systemPrompt) {
// If the character has a custom system prompt AND user has it preferred, use that instead of the default
systemPrompt = power_user.prefer_character_prompt && systemPrompt ? systemPrompt : power_user.instruct.system_prompt;
const sequence = power_user.instruct.system_sequence || '';
const prompt = substituteParams(systemPrompt, name1, name2, power_user.instruct.system_prompt) || '';
const separator = power_user.instruct.wrap ? '\n' : '';
const textArray = [sequence, prompt + '\n' + story];
const text = textArray.filter(x => x).join(separator);
return text;
}
export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2) {
const includeNames = power_user.instruct.names || (!!selected_group && power_user.instruct.names_force_groups);
let sequence = isImpersonate ? power_user.instruct.input_sequence : power_user.instruct.output_sequence;
if (power_user.instruct.macro) {
sequence = substituteParams(sequence, name1, name2);
}
const separator = power_user.instruct.wrap ? '\n' : '';
let text = includeNames ? (separator + sequence + separator + `${name}:`) : (separator + sequence);
if (!isImpersonate && promptBias) {
text += (includeNames ? promptBias : (separator + promptBias));
}
return text.trimEnd();
}
const sortFunc = (a, b) => power_user.sort_order == 'asc' ? compareFunc(a, b) : compareFunc(b, a);
const compareFunc = (first, second) => {
if (power_user.sort_order == 'random') {
return Math.random() > 0.5 ? 1 : -1;
}
switch (power_user.sort_rule) {
case 'boolean':
const a = first[power_user.sort_field];
const b = second[power_user.sort_field];
if (a === true || a === 'true') return 1; // Prioritize 'true' or true
if (b === true || b === 'true') return -1; // Prioritize 'true' or true
if (a && !b) return -1; // Move truthy values to the end
if (!a && b) return 1; // Move falsy values to the beginning
if (a === b) return 0; // Sort equal values normally
return a < b ? -1 : 1; // Sort non-boolean values normally
default:
return typeof first[power_user.sort_field] == "string"
? first[power_user.sort_field].localeCompare(second[power_user.sort_field])
: first[power_user.sort_field] - second[power_user.sort_field];
}
};
function sortCharactersList() {
const arr1 = groups.map(x => ({
item: x,
id: x.id,
selector: '.group_select',
attribute: 'grid',
}))
const arr2 = characters.map((x, index) => ({
item: x,
id: index,
selector: '.character_select',
attribute: 'chid',
}));
const array = [...arr1, ...arr2];
if (power_user.sort_field == undefined || array.length === 0) {
return;
}
let orderedList = array.slice().sort((a, b) => sortFunc(a.item, b.item));
for (const item of array) {
$(`${item.selector}[${item.attribute}="${item.id}"]`).css({ 'order': orderedList.indexOf(item) });
}
updateVisibleDivs('#rm_print_characters_block', true);
}
function sortGroupMembers(selector) {
if (power_user.sort_field == undefined || characters.length === 0) {
return;
}
let orderedList = characters.slice().sort(sortFunc);
for (let i = 0; i < characters.length; i++) {
$(`${selector}[chid="${i}"]`).css({ 'order': orderedList.indexOf(characters[i]) });
}
}
async function saveTheme() {
const name = await callPopup('Enter a theme preset name:', 'input');
if (!name) {
return;
}
const theme = {
name,
blur_strength: power_user.blur_strength,
main_text_color: power_user.main_text_color,
italics_text_color: power_user.italics_text_color,
quote_text_color: power_user.quote_text_color,
//fastui_bg_color: power_user.fastui_bg_color,
blur_tint_color: power_user.blur_tint_color,
user_mes_blur_tint_color: power_user.user_mes_blur_tint_color,
bot_mes_blur_tint_color: power_user.bot_mes_blur_tint_color,
shadow_color: power_user.shadow_color,
shadow_width: power_user.shadow_width,
font_scale: power_user.font_scale,
fast_ui_mode: power_user.fast_ui_mode,
waifuMode: power_user.waifuMode,
avatar_style: power_user.avatar_style,
chat_display: power_user.chat_display,
noShadows: power_user.noShadows,
chat_width: power_user.chat_width,
timer_enabled: power_user.timer_enabled,
timestamps_enabled: power_user.timestamps_enabled,
mesIDDisplay_enabled: power_user.mesIDDisplay_enabled,
hotswap_enabled: power_user.hotswap_enabled,
};
const response = await fetch('/savetheme', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify(theme)
});
if (response.ok) {
const themeIndex = themes.findIndex(x => x.name == name);
if (themeIndex == -1) {
themes.push(theme);
const option = document.createElement('option');
option.selected = true;
option.value = name;
option.innerText = name;
$('#themes').append(option);
}
else {
themes[themeIndex] = theme;
$(`#themes option[value="${name}"]`).attr('selected', true);
}
power_user.theme = name;
saveSettingsDebounced();
}
}
async function saveMovingUI() {
const name = await callPopup('Enter a name for the MovingUI Preset:', 'input');
if (!name) {
return;
}
const movingUIPreset = {
name,
movingUIState: power_user.movingUIState
}
console.log(movingUIPreset)
const response = await fetch('/savemovingui', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify(movingUIPreset)
});
if (response.ok) {
const movingUIPresetIndex = movingUIPresets.findIndex(x => x.name == name);
if (movingUIPresetIndex == -1) {
movingUIPresets.push(movingUIPreset);
const option = document.createElement('option');
option.selected = true;
option.value = name;
option.innerText = name;
$('#movingUIPresets').append(option);
}
else {
movingUIPresets[movingUIPresetIndex] = movingUIPreset;
$(`#movingUIPresets option[value="${name}"]`).attr('selected', true);
}
power_user.movingUIPreset = name;
saveSettingsDebounced();
} else {
toastr.warning('failed to save MovingUI state.')
}
}
async function resetMovablePanels(type) {
const panelIds = [
'sheld',
'left-nav-panel',
'right-nav-panel',
'WorldInfo',
'floatingPrompt',
'expression-holder',
'groupMemberListPopout'
];
const panelStyles = ['top', 'left', 'right', 'bottom', 'height', 'width', 'margin',];
panelIds.forEach((id) => {
const panel = document.getElementById(id);
if (panel) {
$(panel).addClass('resizing');
panelStyles.forEach((style) => {
panel.style[style] = '';
});
}
});
const zoomedAvatars = document.querySelectorAll('.zoomed_avatar');
if (zoomedAvatars.length > 0) {
zoomedAvatars.forEach((avatar) => {
avatar.classList.add('resizing');
panelStyles.forEach((style) => {
avatar.style[style] = '';
});
});
}
$('[data-dragged="true"]').removeAttr('data-dragged');
await delay(50)
power_user.movingUIState = {};
//if user manually resets panels, deselect the current preset
if (type !== 'quiet' && type !== 'resize') {
power_user.movingUIPreset = 'Default'
$(`#movingUIPresets option[value="Default"]`).prop('selected', true);
}
saveSettingsDebounced();
eventSource.emit(event_types.MOVABLE_PANELS_RESET);
eventSource.once(event_types.SETTINGS_UPDATED, () => {
$(".resizing").removeClass('resizing');
//if happening as part of preset application, do it quietly.
if (type === 'quiet') {
return
//if happening due to resize, tell user.
} else if (type === 'resize') {
toastr.warning('Panel positions reset due to zoom/resize');
//if happening due to manual button press
} else {
toastr.success('Panel positions reset');
}
});
}
function doNewChat() {
setTimeout(() => {
$("#option_start_new_chat").trigger('click');
}, 1);
//$("#dialogue_popup").hide();
setTimeout(() => {
$("#dialogue_popup_ok").trigger('click');
}, 1);
}
function doRandomChat() {
resetSelectedGroup();
setCharacterId(Math.floor(Math.random() * characters.length).toString());
setTimeout(() => {
reloadCurrentChat();
}, 1);
}
async function doMesCut(_, text) {
console.debug(`was asked to cut message id #${text}`)
//reject invalid args or no args
if (text && isNaN(text) || !text) {
toastr.error(`Must enter a single number only, non-number characters disallowed.`)
return
}
let mesIDToCut = Number(text).toFixed(0)
let mesToCut = $("#chat").find(`.mes[mesid=${mesIDToCut}]`)
if (!mesToCut.length) {
toastr.error(`Could not find message with ID: ${mesIDToCut}`)
return
}
setEditedMessageId(mesIDToCut);
mesToCut.find('.mes_edit_delete').trigger('click', { fromSlashCommand: true });
}
async function doDelMode(_, text) {
//first enter delmode
$("#option_delete_mes").trigger('click')
//reject invalid args
if (text && isNaN(text)) {
toastr.warning('Must enter a number or nothing.')
await delay(300) //unsure why 300 is neccessary here, but any shorter and it wont see the delmode UI
$("#dialogue_del_mes_cancel").trigger('click');
return
}
//parse valid args
if (text) {
await delay(300) //same as above, need event signal for 'entered del mode'
console.debug('parsing msgs to del')
let numMesToDel = Number(text).toFixed(0)
let lastMesID = $('.last_mes').attr('mesid')
let oldestMesIDToDel = lastMesID - numMesToDel + 1;
//disallow targeting first message
if (oldestMesIDToDel <= 0) {
oldestMesIDToDel = 1
}
let oldestMesToDel = $('#chat').find(`.mes[mesid=${oldestMesIDToDel}]`)
let oldestDelMesCheckbox = $(oldestMesToDel).find('.del_checkbox');
let newLastMesID = oldestMesIDToDel - 1;
console.debug(`DelMesReport -- numMesToDel: ${numMesToDel}, lastMesID: ${lastMesID}, oldestMesIDToDel:${oldestMesIDToDel}, newLastMesID: ${newLastMesID}`)
oldestDelMesCheckbox.trigger('click');
let trueNumberOfDeletedMessage = lastMesID - oldestMesIDToDel + 1
//await delay(1)
$('#dialogue_del_mes_ok').trigger('click');
toastr.success(`Deleted ${trueNumberOfDeletedMessage} messages.`)
return
}
}
function doResetPanels() {
$("#movingUIreset").trigger('click');
}
function setAvgBG() {
const bgimg = new Image();
bgimg.src = $('#bg1')
.css('background-image')
.replace(/^url\(['"]?/, '')
.replace(/['"]?\)$/, '');
/* const charAvatar = new Image()
charAvatar.src = $("#avatar_load_preview")
.attr('src')
.replace(/^url\(['"]?/, '')
.replace(/['"]?\)$/, '');
const userAvatar = new Image()
userAvatar.src = $("#user_avatar_block .avatar.selected img")
.attr('src')
.replace(/^url\(['"]?/, '')
.replace(/['"]?\)$/, ''); */
bgimg.onload = function () {
var rgb = getAverageRGB(bgimg);
//console.log(`average color of the bg is:`)
//console.log(rgb);
$("#blur-tint-color-picker").attr('color', 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')');
const backgroundColorString = $("#blur-tint-color-picker").attr('color')
.replace('rgba', '')
.replace('rgb', '')
.replace('(', '[')
.replace(')', ']'); //[50, 120, 200, 1]; // Example background color
const backgroundColorArray = JSON.parse(backgroundColorString) //[200, 200, 200, 1]
console.log(backgroundColorArray)
$("#main-text-color-picker").attr('color', getReadableTextColor(backgroundColorArray));
console.log($("#main-text-color-picker").attr('color')); // Output: 'rgba(0, 47, 126, 1)'
}
/* charAvatar.onload = function () {
var rgb = getAverageRGB(charAvatar);
//console.log(`average color of the AI avatar is:`);
//console.log(rgb);
$("#bot-mes-blur-tint-color-picker").attr('color', 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')');
}
userAvatar.onload = function () {
var rgb = getAverageRGB(userAvatar);
//console.log(`average color of the user avatar is:`);
//console.log(rgb);
$("#user-mes-blur-tint-color-picker").attr('color', 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')');
} */
function getAverageRGB(imgEl) {
var blockSize = 5, // only visit every 5 pixels
defaultRGB = { r: 0, g: 0, b: 0 }, // for non-supporting envs
canvas = document.createElement('canvas'),
context = canvas.getContext && canvas.getContext('2d'),
data, width, height,
i = -4,
length,
rgb = { r: 0, g: 0, b: 0 },
count = 0;
if (!context) {
return defaultRGB;
}
height = canvas.height = imgEl.naturalHeight || imgEl.offsetHeight || imgEl.height;
width = canvas.width = imgEl.naturalWidth || imgEl.offsetWidth || imgEl.width;
context.drawImage(imgEl, 0, 0);
try {
data = context.getImageData(0, 0, width, height);
} catch (e) {
/* security error, img on diff domain */alert('x');
return defaultRGB;
}
length = data.data.length;
while ((i += blockSize * 4) < length) {
++count;
rgb.r += data.data[i];
rgb.g += data.data[i + 1];
rgb.b += data.data[i + 2];
}
// ~~ used to floor values
rgb.r = ~~(rgb.r / count);
rgb.g = ~~(rgb.g / count);
rgb.b = ~~(rgb.b / count);
return rgb;
}
function hslToRgb(h, s, l) {
const hueToRgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
if (s === 0) {
return [l, l, l];
}
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
const r = hueToRgb(p, q, h + 1 / 3);
const g = hueToRgb(p, q, h);
const b = hueToRgb(p, q, h - 1 / 3);
return [r * 255, g * 255, b * 255];
}
function rgbToLuminance(r, g, b) {
console.log(r, g, b)
const gammaCorrect = (color) => {
return color <= 0.03928
? color / 12.92
: Math.pow((color + 0.055) / 1.055, 2.4);
};
const rsRGB = r / 255;
const gsRGB = g / 255;
const bsRGB = b / 255;
const rLuminance = gammaCorrect(rsRGB).toFixed(2);
const gLuminance = gammaCorrect(gsRGB).toFixed(2);
const bLuminance = gammaCorrect(bsRGB).toFixed(2);
console.log(`rLum ${rLuminance}, gLum ${gLuminance}, bLum ${bLuminance}`)
return 0.2126 * rLuminance + 0.7152 * gLuminance + 0.0722 * bLuminance;
}
//this version keeps BG and main text in same hue
/* function getReadableTextColor(rgb) {
const [r, g, b] = rgb;
// Convert RGB to HSL
const rgbToHsl = (r, g, b) => {
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const d = max - min;
const l = (max + min) / 2;
if (d === 0) return [0, 0, l];
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
const h = (() => {
switch (max) {
case r:
return (g - b) / d + (g < b ? 6 : 0);
case g:
return (b - r) / d + 2;
case b:
return (r - g) / d + 4;
}
})() / 6;
return [h, s, l];
};
const [h, s, l] = rgbToHsl(r / 255, g / 255, b / 255);
// Calculate appropriate text color based on background color
const targetLuminance = l > 0.5 ? 0.2 : 0.8;
const targetSaturation = s > 0.5 ? s - 0.2 : s + 0.2;
const [rNew, gNew, bNew] = hslToRgb(h, targetSaturation, targetLuminance);
// Return the text color in RGBA format
return `rgba(${rNew.toFixed(0)}, ${gNew.toFixed(0)}, ${bNew.toFixed(0)}, 1)`;
}*/
//this version makes main text complimentary color to BG color
function getReadableTextColor(rgb) {
const [r, g, b] = rgb;
// Convert RGB to HSL
const rgbToHsl = (r, g, b) => {
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
const d = max - min;
const l = (max + min) / 2;
if (d === 0) return [0, 0, l];
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
const h = (() => {
switch (max) {
case r:
return (g - b) / d + (g < b ? 6 : 0);
case g:
return (b - r) / d + 2;
case b:
return (r - g) / d + 4;
}
})() / 6;
return [h, s, l];
};
const [h, s, l] = rgbToHsl(r / 255, g / 255, b / 255);
// Calculate complementary color based on background color
const complementaryHue = (h + 0.5) % 1;
const complementarySaturation = s > 0.5 ? s - 0.6 : s + 0.6;
const complementaryLuminance = l > 0.5 ? 0.2 : 0.8;
// Convert complementary color back to RGB
const [rNew, gNew, bNew] = hslToRgb(complementaryHue, complementarySaturation, complementaryLuminance);
// Return the text color in RGBA format
return `rgba(${rNew.toFixed(0)}, ${gNew.toFixed(0)}, ${bNew.toFixed(0)}, 1)`;
}
}
export function getCustomStoppingStrings() {
try {
// Parse the JSON string
const strings = JSON.parse(power_user.custom_stopping_strings);
// Make sure it's an array
if (!Array.isArray(strings)) {
return [];
}
// Make sure all the elements are strings
return strings.filter((s) => typeof s === 'string');
} catch (error) {
// If there's an error, return an empty array
console.warn('Error parsing custom stopping strings:', error);
return [];
}
}
$(document).ready(() => {
$(window).on('resize', async () => {
if (isMobile()) {
return
}
//console.log('Window resized!');
const zoomLevel = Number(window.devicePixelRatio).toFixed(2);
const winWidth = window.innerWidth;
const winHeight = window.innerHeight;
console.debug(`Zoom: ${zoomLevel}, X:${winWidth}, Y:${winHeight}`);
if (Object.keys(power_user.movingUIState).length > 0) {
resetMovablePanels('resize');
}
// Adjust layout and styling here
});
// Settings that go to settings.json
$("#collapse-newlines-checkbox").change(function () {
power_user.collapse_newlines = !!$(this).prop("checked");
saveSettingsDebounced();
});
$("#pygmalion_formatting").change(function (e) {
power_user.pygmalion_formatting = Number($(this).find(":selected").val());
getStatus();
saveSettingsDebounced();
});
$("#pin-examples-checkbox").change(function () {
power_user.pin_examples = !!$(this).prop("checked");
saveSettingsDebounced();
});
$("#disable-description-formatting-checkbox").change(function () {
power_user.disable_description_formatting = !!$(this).prop('checked');
saveSettingsDebounced();
})
$("#disable-scenario-formatting-checkbox").change(function () {
power_user.disable_scenario_formatting = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#disable-personality-formatting-checkbox").change(function () {
power_user.disable_personality_formatting = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#disable-examples-formatting-checkbox").change(function () {
power_user.disable_examples_formatting = !!$(this).prop('checked');
saveSettingsDebounced();
})
$("#disable-start-formatting-checkbox").change(function () {
power_user.disable_start_formatting = !!$(this).prop('checked');
saveSettingsDebounced();
});
// include newline is the child of trim sentences
// if include newline is checked, trim sentences must be checked
// if trim sentences is unchecked, include newline must be unchecked
$("#trim_sentences_checkbox").change(function () {
power_user.trim_sentences = !!$(this).prop("checked");
if (!$(this).prop("checked")) {
$("#include_newline_checkbox").prop("checked", false);
power_user.include_newline = false;
}
saveSettingsDebounced();
});
$("#include_newline_checkbox").change(function () {
power_user.include_newline = !!$(this).prop("checked");
if ($(this).prop("checked")) {
$("#trim_sentences_checkbox").prop("checked", true);
power_user.trim_sentences = true;
}
saveSettingsDebounced();
});
$("#always-force-name2-checkbox").change(function () {
power_user.always_force_name2 = !!$(this).prop("checked");
saveSettingsDebounced();
});
$("#custom_chat_separator").on('input', function () {
power_user.custom_chat_separator = $(this).val();
saveSettingsDebounced();
reloadMarkdownProcessor(power_user.render_formulas);
});
$("#markdown_escape_strings").on('input', function () {
power_user.markdown_escape_strings = $(this).val();
saveSettingsDebounced();
reloadMarkdownProcessor(power_user.render_formulas);
});
$("#start_reply_with").on('input', function () {
power_user.user_prompt_bias = $(this).val();
saveSettingsDebounced();
});
$("#chat-show-reply-prefix-checkbox").change(function () {
power_user.show_user_prompt_bias = !!$(this).prop("checked");
reloadCurrentChat();
saveSettingsDebounced();
})
$("#multigen").change(function () {
power_user.multigen = $(this).prop("checked");
saveSettingsDebounced();
});
// Settings that go to local storage
$("#fast_ui_mode").change(function () {
power_user.fast_ui_mode = $(this).prop("checked");
localStorage.setItem(storage_keys.fast_ui_mode, power_user.fast_ui_mode);
switchUiMode();
});
$("#waifuMode").on('change', () => {
power_user.waifuMode = $('#waifuMode').prop("checked");
saveSettingsDebounced();
switchWaifuMode();
});
$("#movingUImode").change(function () {
power_user.movingUI = $(this).prop("checked");
localStorage.setItem(storage_keys.movingUI, power_user.movingUI);
switchMovingUI();
});
$("#noShadowsmode").change(function () {
power_user.noShadows = $(this).prop("checked");
localStorage.setItem(storage_keys.noShadows, power_user.noShadows);
noShadows();
});
$("#movingUIreset").on('click', resetMovablePanels);
$(`input[name="avatar_style"]`).on('input', function (e) {
power_user.avatar_style = Number(e.target.value);
localStorage.setItem(storage_keys.avatar_style, power_user.avatar_style);
applyAvatarStyle();
});
$("#chat_display").on('change', function () {
console.debug('###CHAT DISPLAY SELECTOR CHANGE###')
const value = $(this).find(':selected').val();
power_user.chat_display = Number(value);
saveSettingsDebounced();
applyChatDisplay();
});
$('#chat_width_slider').on('input', function (e) {
power_user.chat_width = Number(e.target.value);
localStorage.setItem(storage_keys.chat_width, power_user.chat_width);
applyChatWidth();
});
$(`input[name="font_scale"]`).on('input', async function (e) {
power_user.font_scale = Number(e.target.value);
$("#font_scale_counter").text(power_user.font_scale);
localStorage.setItem(storage_keys.font_scale, power_user.font_scale);
await applyFontScale();
});
$(`input[name="blur_strength"]`).on('input', async function (e) {
power_user.blur_strength = Number(e.target.value);
$("#blur_strength_counter").text(power_user.blur_strength);
localStorage.setItem(storage_keys.blur_strength, power_user.blur_strength);
await applyBlurStrength();
});
$(`input[name="shadow_width"]`).on('input', async function (e) {
power_user.shadow_width = Number(e.target.value);
$("#shadow_width_counter").text(power_user.shadow_width);
localStorage.setItem(storage_keys.shadow_width, power_user.shadow_width);
await applyShadowWidth();
});
$("#main-text-color-picker").on('change', (evt) => {
power_user.main_text_color = evt.detail.rgba;
applyThemeColor('main');
saveSettingsDebounced();
});
$("#italics-color-picker").on('change', (evt) => {
power_user.italics_text_color = evt.detail.rgba;
applyThemeColor('italics');
saveSettingsDebounced();
});
$("#quote-color-picker").on('change', (evt) => {
power_user.quote_text_color = evt.detail.rgba;
applyThemeColor('quote');
saveSettingsDebounced();
});
$("#blur-tint-color-picker").on('change', (evt) => {
power_user.blur_tint_color = evt.detail.rgba;
applyThemeColor('blurTint');
saveSettingsDebounced();
});
$("#user-mes-blur-tint-color-picker").on('change', (evt) => {
power_user.user_mes_blur_tint_color = evt.detail.rgba;
applyThemeColor('userMesBlurTint');
saveSettingsDebounced();
});
$("#bot-mes-blur-tint-color-picker").on('change', (evt) => {
power_user.bot_mes_blur_tint_color = evt.detail.rgba;
applyThemeColor('botMesBlurTint');
saveSettingsDebounced();
});
$("#shadow-color-picker").on('change', (evt) => {
power_user.shadow_color = evt.detail.rgba;
applyThemeColor('shadow');
saveSettingsDebounced();
});
$("#themes").on('change', function () {
const themeSelected = $(this).find(':selected').val();
power_user.theme = themeSelected;
applyTheme(themeSelected);
saveSettingsDebounced();
});
$("#movingUIPresets").on('change', async function () {
console.log('saw MUI preset change')
const movingUIPresetSelected = $(this).find(':selected').val();
power_user.movingUIPreset = movingUIPresetSelected;
applyMovingUIPreset(movingUIPresetSelected);
saveSettingsDebounced();
});
$("#ui-preset-save-button").on('click', saveTheme);
$("#movingui-preset-save-button").on('click', saveMovingUI);
$("#never_resize_avatars").on('input', function () {
power_user.never_resize_avatars = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#show_card_avatar_urls").on('input', function () {
power_user.show_card_avatar_urls = !!$(this).prop('checked');
printCharacters();
saveSettingsDebounced();
});
$("#play_message_sound").on('input', function () {
power_user.play_message_sound = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#play_sound_unfocused").on('input', function () {
power_user.play_sound_unfocused = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#auto_save_msg_edits").on('input', function () {
power_user.auto_save_msg_edits = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#character_sort_order").on('change', function () {
power_user.sort_field = $(this).find(":selected").data('field');
power_user.sort_order = $(this).find(":selected").data('order');
power_user.sort_rule = $(this).find(":selected").data('rule');
sortCharactersList();
favsToHotswap();
saveSettingsDebounced();
});
$("#multigen_first_chunk").on('input', function () {
power_user.multigen_first_chunk = Number($(this).val());
saveSettingsDebounced();
});
$("#multigen_next_chunks").on('input', function () {
power_user.multigen_next_chunks = Number($(this).val());
saveSettingsDebounced();
});
$('#auto_swipe').on('input', function () {
power_user.auto_swipe = !!$(this).prop('checked');
saveSettingsDebounced();
});
$('#auto_swipe_blacklist').on('input', function () {
power_user.auto_swipe_blacklist = $(this).val()
.split(",")
.map(str => str.trim())
.filter(str => str);
console.log("power_user.auto_swipe_blacklist", power_user.auto_swipe_blacklist)
saveSettingsDebounced();
});
$('#auto_swipe_minimum_length').on('input', function () {
const number = parseInt($(this).val());
if (!isNaN(number)) {
power_user.auto_swipe_minimum_length = number;
saveSettingsDebounced();
}
});
$('#auto_swipe_blacklist_threshold').on('input', function () {
const number = parseInt($(this).val());
if (!isNaN(number)) {
power_user.auto_swipe_blacklist_threshold = number;
saveSettingsDebounced();
}
});
$('#auto_fix_generated_markdown').on('input', function () {
power_user.auto_fix_generated_markdown = !!$(this).prop('checked');
reloadCurrentChat();
saveSettingsDebounced();
});
$("#console_log_prompts").on('input', function () {
power_user.console_log_prompts = !!$(this).prop('checked');
saveSettingsDebounced();
});
$('#auto_scroll_chat_to_bottom').on("input", function () {
power_user.auto_scroll_chat_to_bottom = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#tokenizer").on('change', function () {
const value = $(this).find(':selected').val();
power_user.tokenizer = Number(value);
saveSettingsDebounced();
// Trigger character editor re-tokenize
$("#rm_ch_create_block").trigger('input');
$("#character_popup").trigger('input');
});
$("#send_on_enter").on('change', function () {
const value = $(this).find(':selected').val();
power_user.send_on_enter = Number(value);
saveSettingsDebounced();
});
$("#import_card_tags").on('input', function () {
power_user.import_card_tags = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#confirm_message_delete").on('input', function () {
power_user.confirm_message_delete = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#render_formulas").on("input", function () {
power_user.render_formulas = !!$(this).prop('checked');
reloadMarkdownProcessor(power_user.render_formulas);
reloadCurrentChat();
saveSettingsDebounced();
});
$("#reload_chat").on('click', function () {
const currentChatId = getCurrentChatId();
if (currentChatId !== undefined && currentChatId !== null) {
reloadCurrentChat();
}
});
$("#allow_name1_display").on("input", function () {
power_user.allow_name1_display = !!$(this).prop('checked');
reloadCurrentChat();
saveSettingsDebounced();
})
$("#allow_name2_display").on("input", function () {
power_user.allow_name2_display = !!$(this).prop('checked');
reloadCurrentChat();
saveSettingsDebounced();
});
/* $("#removeXML").on("input", function () {
power_user.removeXML = !!$(this).prop('checked');
reloadCurrentChat();
saveSettingsDebounced();
}); */
$("#token_padding").on("input", function () {
power_user.token_padding = Number($(this).val());
saveSettingsDebounced();
});
$("#messageTimerEnabled").on("input", function () {
const value = !!$(this).prop('checked');
power_user.timer_enabled = value;
localStorage.setItem(storage_keys.timer_enabled, power_user.timer_enabled);
switchTimer();
});
$("#messageTimestampsEnabled").on("input", function () {
const value = !!$(this).prop('checked');
power_user.timestamps_enabled = value;
localStorage.setItem(storage_keys.timestamps_enabled, power_user.timestamps_enabled);
switchTimestamps();
});
$("#mesIDDisplayEnabled").on("input", function () {
const value = !!$(this).prop('checked');
power_user.mesIDDisplay_enabled = value;
localStorage.setItem(storage_keys.mesIDDisplay_enabled, power_user.mesIDDisplay_enabled);
switchMesIDDisplay();
});
$("#hotswapEnabled").on("input", function () {
const value = !!$(this).prop('checked');
power_user.hotswap_enabled = value;
localStorage.setItem(storage_keys.hotswap_enabled, power_user.hotswap_enabled);
switchHotswap();
});
$("#prefer_character_prompt").on("input", function () {
const value = !!$(this).prop('checked');
power_user.prefer_character_prompt = value;
saveSettingsDebounced();
});
$("#prefer_character_jailbreak").on("input", function () {
const value = !!$(this).prop('checked');
power_user.prefer_character_jailbreak = value;
saveSettingsDebounced();
});
$("#continue_on_send").on("input", function () {
const value = !!$(this).prop('checked');
power_user.continue_on_send = value;
saveSettingsDebounced();
});
$("#trim_spaces").on("input", function () {
const value = !!$(this).prop('checked');
power_user.trim_spaces = value;
saveSettingsDebounced();
});
$("#relaxed_api_urls").on("input", function () {
const value = !!$(this).prop('checked');
power_user.relaxed_api_urls = value;
saveSettingsDebounced();
});
$('#spoiler_free_mode').on('input', function () {
power_user.spoiler_free_mode = !!$(this).prop('checked');
switchSpoilerMode();
saveSettingsDebounced();
});
$('#spoiler_free_desc_button').on('click', function () {
peekSpoilerMode();
$(this).toggleClass('fa-eye fa-eye-slash');
});
$('#custom_stopping_strings').on('input', function () {
power_user.custom_stopping_strings = $(this).val();
saveSettingsDebounced();
});
$("#custom_stopping_strings_macro").change(function () {
power_user.custom_stopping_strings_macro = !!$(this).prop("checked");
saveSettingsDebounced();
});
$('#fuzzy_search_checkbox').on('input', function () {
power_user.fuzzy_search = !!$(this).prop('checked');
saveSettingsDebounced();
});
$('#persona_show_notifications').on('input', function () {
power_user.persona_show_notifications = !!$(this).prop('checked');
saveSettingsDebounced();
});
$('#encode_tags').on('input', async function () {
power_user.encode_tags = !!$(this).prop('checked');
await reloadCurrentChat();
saveSettingsDebounced();
});
$('#lazy_load').on('input', function () {
power_user.lazy_load = Number($(this).val());
saveSettingsDebounced();
});
$(window).on('focus', function () {
browser_has_focus = true;
});
$(window).on('blur', function () {
browser_has_focus = false;
});
registerSlashCommand('vn', toggleWaifu, [], ' – swaps Visual Novel Mode On/Off', false, true);
registerSlashCommand('newchat', doNewChat, ['newchat'], ' – start a new chat with current character', true, true);
registerSlashCommand('random', doRandomChat, ['random'], ' – start a new chat with a random character', true, true);
registerSlashCommand('delmode', doDelMode, ['del'], '(optional number) – enter message deletion mode, and auto-deletes N messages if numeric argument is provided', true, true);
registerSlashCommand('cut', doMesCut, [], ' (requred number) – cuts the specified message from the chat', true, true);
registerSlashCommand('resetpanels', doResetPanels, ['resetui'], ' – resets UI panels to original state.', true, true);
registerSlashCommand('bgcol', setAvgBG, [], ' – WIP test of auto-bg avg coloring', true, true);
});