Merge chat backgrounds plugin with main backgrounds menu
This commit is contained in:
parent
7f8df9533b
commit
f285110773
|
@ -3234,9 +3234,18 @@
|
|||
<div id="site_logo" class="drawer-toggle drawer-header">
|
||||
<div class="drawer-icon fa-solid fa-panorama closedIcon"></div>
|
||||
</div>
|
||||
<div class="drawer-content closedDrawer">
|
||||
<div id="Backgrounds" class="drawer-content closedDrawer">
|
||||
<div class="flex-container">
|
||||
<input id="bg-filter" placeholder="Filter" class="text_pole" type="search" />
|
||||
<div class="flex-container wide100p">
|
||||
<input id="bg-filter" placeholder="Filter" class="text_pole flex1" type="search" />
|
||||
<div id="auto_background" class="menu_button menu_button_icon" title="Automatically select a background based on the chat context.">
|
||||
<i class="fa-solid fa-wand-magic"></i>
|
||||
Auto-select
|
||||
</div>
|
||||
</div>
|
||||
<h3 data-i18n="System Backgrounds" class="justifyCenter">
|
||||
System Backgrounds
|
||||
</h3>
|
||||
<div id="bg_menu_content">
|
||||
<form id="form_bg_download" class="bg_example no-border no-shadow" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||
<label class="input-file">
|
||||
|
@ -3883,8 +3892,10 @@
|
|||
|
||||
<div id="background_template" class="template_element">
|
||||
<div class="bg_example flex-container" bgfile="" class="bg_example_img" title="">
|
||||
<div title="Rename background" bgfile="" class="bg_button bg_example_edit fa-solid fa-pencil"></div>
|
||||
<div title="Delete background" bgfile="" class="bg_button bg_example_cross fa-solid fa-circle-xmark"></div>
|
||||
<div title="Rename background" class="bg_button bg_example_edit fa-solid fa-pencil"></div>
|
||||
<div title="Lock" class="bg_button bg_example_lock fa-solid fa-lock"></div>
|
||||
<div title="Unlock" class="bg_button bg_example_unlock fa-solid fa-lock-open"></div>
|
||||
<div title="Delete background" class="bg_button bg_example_cross fa-solid fa-circle-xmark"></div>
|
||||
<div class="BGSampleTitle">
|
||||
</div>
|
||||
</div>
|
||||
|
|
216
public/script.js
216
public/script.js
|
@ -182,6 +182,7 @@ import {
|
|||
import { applyLocale } from "./scripts/i18n.js";
|
||||
import { getTokenCount, getTokenizerModel, saveTokenCache } from "./scripts/tokenizers.js";
|
||||
import { initPersonas, selectCurrentPersona, setPersonaDescription } from "./scripts/personas.js";
|
||||
import { getBackgrounds, initBackgrounds } from "./scripts/backgrounds.js";
|
||||
|
||||
//exporting functions and vars for mods
|
||||
export {
|
||||
|
@ -319,7 +320,6 @@ reloadMarkdownProcessor();
|
|||
console.debug('initializing Prompt Itemization Array on Startup');
|
||||
let itemizedPrompts = [];
|
||||
|
||||
/* let bg_menu_toggle = false; */
|
||||
export const systemUserName = "SillyTavern System";
|
||||
let default_user_name = "User";
|
||||
let name1 = default_user_name;
|
||||
|
@ -348,7 +348,6 @@ let generation_started = new Date();
|
|||
let characters = [];
|
||||
let this_chid;
|
||||
let saveCharactersPage = 0;
|
||||
let backgrounds = [];
|
||||
const default_avatar = "img/ai4.png";
|
||||
export const system_avatar = "img/five.png";
|
||||
export const comment_avatar = "img/quill.png";
|
||||
|
@ -632,7 +631,6 @@ let create_save = {
|
|||
let animation_duration = 125;
|
||||
let animation_easing = "ease-in-out";
|
||||
let popup_type = "";
|
||||
let bg_file_for_del = "";
|
||||
let chat_file_for_del = "";
|
||||
let online_status = "no_connection";
|
||||
|
||||
|
@ -721,6 +719,7 @@ async function firstLoadInit() {
|
|||
await getUserAvatars();
|
||||
await getCharacters();
|
||||
await getBackgrounds();
|
||||
initBackgrounds();
|
||||
initAuthorsNote();
|
||||
initPersonas();
|
||||
initRossMods();
|
||||
|
@ -1033,73 +1032,6 @@ async function getCharacters() {
|
|||
}
|
||||
}
|
||||
|
||||
async function getBackgrounds() {
|
||||
const response = await fetch("/getbackgrounds", {
|
||||
method: "POST",
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
"": "",
|
||||
}),
|
||||
});
|
||||
if (response.ok === true) {
|
||||
const getData = await response.json();
|
||||
//background = getData;
|
||||
//console.log(getData.length);
|
||||
$("#bg_menu_content").children('div').remove();
|
||||
for (const bg of getData) {
|
||||
const template = getBackgroundFromTemplate(bg);
|
||||
$("#bg_menu_content").append(template);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getBackgroundFromTemplate(bg) {
|
||||
const thumbPath = getThumbnailUrl('bg', bg);
|
||||
const template = $('#background_template .bg_example').clone();
|
||||
template.attr('bgfile', bg);
|
||||
template.attr('title', bg);
|
||||
template.find('.bg_button').attr('bgfile', bg);
|
||||
template.css('background-image', `url('${thumbPath}')`);
|
||||
template.find('.BGSampleTitle').text(bg.slice(0, bg.lastIndexOf('.')));
|
||||
return template;
|
||||
}
|
||||
|
||||
async function setBackground(bg) {
|
||||
|
||||
jQuery.ajax({
|
||||
type: "POST", //
|
||||
url: "/setbackground", //
|
||||
data: JSON.stringify({
|
||||
bg: bg,
|
||||
}),
|
||||
beforeSend: function () {
|
||||
|
||||
},
|
||||
cache: false,
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
//processData: false,
|
||||
success: function (html) { },
|
||||
error: function (jqXHR, exception) {
|
||||
console.log(exception);
|
||||
console.log(jqXHR);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function delBackground(bg) {
|
||||
const response = await fetch("/delbackground", {
|
||||
method: "POST",
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
bg: bg,
|
||||
}),
|
||||
});
|
||||
if (response.ok === true) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
async function delChat(chatfile) {
|
||||
const response = await fetch("/delchat", {
|
||||
method: "POST",
|
||||
|
@ -4820,8 +4752,6 @@ export async function getUserAvatars() {
|
|||
});
|
||||
if (response.ok === true) {
|
||||
const getData = await response.json();
|
||||
//background = getData;
|
||||
//console.log(getData.length);
|
||||
$("#user_avatar_block").html(""); //RossAscends: necessary to avoid doubling avatars each refresh.
|
||||
$("#user_avatar_block").append('<div class="avatar_upload">+</div>');
|
||||
|
||||
|
@ -5933,48 +5863,6 @@ function callPopup(text, type, inputValue = '', { okButton, rows, wide, large }
|
|||
});
|
||||
}
|
||||
|
||||
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 () {
|
||||
|
||||
},
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
success: function (html) {
|
||||
setBackground(html);
|
||||
$("#bg1").css(
|
||||
"background-image",
|
||||
`url("${e.target.result}")`
|
||||
);
|
||||
$("#form_bg_download").after(getBackgroundFromTemplate(html));
|
||||
},
|
||||
error: function (jqXHR, exception) {
|
||||
console.log(exception);
|
||||
console.log(jqXHR);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
function showSwipeButtons() {
|
||||
if (chat.length === 0) {
|
||||
return;
|
||||
|
@ -7341,86 +7229,6 @@ jQuery(async function () {
|
|||
});
|
||||
$("#avatar_upload_file").on("change", uploadUserAvatar);
|
||||
|
||||
$(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_edit', async function (e) {
|
||||
e.stopPropagation();
|
||||
const old_bg = $(this).attr('bgfile');
|
||||
|
||||
if (!old_bg) {
|
||||
console.debug('no bgfile');
|
||||
return;
|
||||
}
|
||||
|
||||
const fileExtension = old_bg.split('.').pop();
|
||||
const old_bg_extensionless = old_bg.replace(`.${fileExtension}`, '');
|
||||
const new_bg_extensionless = await callPopup('<h3>Enter new background name:</h3>', 'input', old_bg_extensionless);
|
||||
|
||||
if (!new_bg_extensionless) {
|
||||
console.debug('no new_bg_extensionless');
|
||||
return;
|
||||
}
|
||||
|
||||
const new_bg = `${new_bg_extensionless}.${fileExtension}`;
|
||||
|
||||
if (old_bg_extensionless === new_bg_extensionless) {
|
||||
console.debug('new_bg === old_bg');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = { old_bg, new_bg };
|
||||
const response = await fetch('/renamebackground', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify(data),
|
||||
cache: 'no-cache',
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
await getBackgrounds();
|
||||
} else {
|
||||
toastr.warning('Failed to rename background');
|
||||
}
|
||||
});
|
||||
|
||||
$(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("<h3>Delete the background?</h3>");
|
||||
});
|
||||
|
||||
$(document).on("click", ".PastChat_cross", function () {
|
||||
chat_file_for_del = $(this).attr('file_name');
|
||||
console.debug('detected cross click for' + chat_file_for_del);
|
||||
|
@ -7477,10 +7285,6 @@ jQuery(async function () {
|
|||
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();
|
||||
|
@ -7575,10 +7379,6 @@ jQuery(async function () {
|
|||
|
||||
});
|
||||
|
||||
$("#add_bg_button").change(function () {
|
||||
read_bg_load(this);
|
||||
});
|
||||
|
||||
$("#add_avatar_button").change(function () {
|
||||
read_avatar_load(this);
|
||||
});
|
||||
|
@ -8819,18 +8619,6 @@ jQuery(async function () {
|
|||
}
|
||||
});
|
||||
|
||||
$("#bg-filter").on("input", function () {
|
||||
const filterValue = String($(this).val()).toLowerCase();
|
||||
$("#bg_menu_content > div").each(function () {
|
||||
const $bgContent = $(this);
|
||||
if ($bgContent.attr("title").toLowerCase().includes(filterValue)) {
|
||||
$bgContent.show();
|
||||
} else {
|
||||
$bgContent.hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#char-management-dropdown").on('change', async (e) => {
|
||||
let target = $(e.target.selectedOptions).attr('id');
|
||||
switch (target) {
|
||||
|
|
|
@ -0,0 +1,392 @@
|
|||
import { callPopup, chat_metadata, eventSource, event_types, generateQuietPrompt, getCurrentChatId, getRequestHeaders, getThumbnailUrl } from "../script.js";
|
||||
import { saveMetadataDebounced } from "./extensions.js";
|
||||
import { registerSlashCommand } from "./slash-commands.js";
|
||||
import { stringFormat } from "./utils.js";
|
||||
|
||||
const METADATA_KEY = 'custom_background';
|
||||
|
||||
/**
|
||||
* @param {string} background
|
||||
*/
|
||||
function forceSetBackground(background) {
|
||||
saveBackgroundMetadata(background);
|
||||
setCustomBackground();
|
||||
highlightLockedBackground();
|
||||
}
|
||||
|
||||
async function onChatChanged() {
|
||||
if (hasCustomBackground()) {
|
||||
setCustomBackground();
|
||||
}
|
||||
else {
|
||||
unsetCustomBackground();
|
||||
}
|
||||
|
||||
highlightLockedBackground();
|
||||
}
|
||||
|
||||
function getBackgroundPath(fileUrl) {
|
||||
return `backgrounds/${fileUrl}`;
|
||||
}
|
||||
|
||||
function highlightLockedBackground() {
|
||||
$('.bg_example').removeClass('locked');
|
||||
|
||||
const lockedBackground = chat_metadata[METADATA_KEY];
|
||||
|
||||
if (!lockedBackground) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(`.bg_example`).each(function () {
|
||||
const url = $(this).data('url');
|
||||
if (url === lockedBackground) {
|
||||
$(this).addClass('locked');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onLockBackgroundClick(e) {
|
||||
e.stopPropagation();
|
||||
|
||||
const chatName = getCurrentChatId();
|
||||
|
||||
if (!chatName) {
|
||||
toastr.warning('Select a chat to lock the background for it');
|
||||
return;
|
||||
}
|
||||
|
||||
const relativeBgImage = getUrlParameter(this);
|
||||
|
||||
saveBackgroundMetadata(relativeBgImage);
|
||||
setCustomBackground();
|
||||
highlightLockedBackground();
|
||||
}
|
||||
|
||||
function onUnlockBackgroundClick(e) {
|
||||
e.stopPropagation();
|
||||
removeBackgroundMetadata();
|
||||
unsetCustomBackground();
|
||||
highlightLockedBackground();
|
||||
}
|
||||
|
||||
function hasCustomBackground() {
|
||||
return chat_metadata[METADATA_KEY];
|
||||
}
|
||||
|
||||
function saveBackgroundMetadata(file) {
|
||||
chat_metadata[METADATA_KEY] = file;
|
||||
saveMetadataDebounced();
|
||||
}
|
||||
|
||||
function removeBackgroundMetadata() {
|
||||
delete chat_metadata[METADATA_KEY];
|
||||
saveMetadataDebounced();
|
||||
}
|
||||
|
||||
function setCustomBackground() {
|
||||
const file = chat_metadata[METADATA_KEY];
|
||||
|
||||
// bg already set
|
||||
if (document.getElementById("bg_custom").style.backgroundImage == file) {
|
||||
return;
|
||||
}
|
||||
|
||||
$("#bg_custom").css("background-image", file);
|
||||
}
|
||||
|
||||
function unsetCustomBackground() {
|
||||
$("#bg_custom").css("background-image", 'none');
|
||||
}
|
||||
|
||||
function onSelectBackgroundClick() {
|
||||
const relativeBgImage = getUrlParameter(this);
|
||||
|
||||
// if clicked on upload button
|
||||
if (!relativeBgImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hasCustomBackground()) {
|
||||
saveBackgroundMetadata(relativeBgImage);
|
||||
setCustomBackground();
|
||||
}
|
||||
|
||||
highlightLockedBackground();
|
||||
const customBg = window.getComputedStyle(document.getElementById('bg_custom')).backgroundImage;
|
||||
|
||||
// custom background is set. Do not override the layer below
|
||||
if (customBg !== 'none') {
|
||||
return;
|
||||
}
|
||||
|
||||
const bgFile = $(this).attr("bgfile");
|
||||
const backgroundUrl = getBackgroundPath(bgFile);
|
||||
|
||||
// fetching to browser memory to reduce flicker
|
||||
fetch(backgroundUrl).then(() => {
|
||||
$("#bg1").css("background-image", relativeBgImage);
|
||||
setBackground(bgFile);
|
||||
}).catch(() => {
|
||||
console.log('Background could not be set: ' + backgroundUrl);
|
||||
});
|
||||
}
|
||||
|
||||
async function onRenameBackgroundClick(e) {
|
||||
e.stopPropagation();
|
||||
const old_bg = $(this).closest('.bg_example').attr('bgfile');
|
||||
|
||||
if (!old_bg) {
|
||||
console.debug('no bgfile');
|
||||
return;
|
||||
}
|
||||
|
||||
const fileExtension = old_bg.split('.').pop();
|
||||
const old_bg_extensionless = old_bg.replace(`.${fileExtension}`, '');
|
||||
const new_bg_extensionless = await callPopup('<h3>Enter new background name:</h3>', 'input', old_bg_extensionless);
|
||||
|
||||
if (!new_bg_extensionless) {
|
||||
console.debug('no new_bg_extensionless');
|
||||
return;
|
||||
}
|
||||
|
||||
const new_bg = `${new_bg_extensionless}.${fileExtension}`;
|
||||
|
||||
if (old_bg_extensionless === new_bg_extensionless) {
|
||||
console.debug('new_bg === old_bg');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = { old_bg, new_bg };
|
||||
const response = await fetch('/renamebackground', {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify(data),
|
||||
cache: 'no-cache',
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
await getBackgrounds();
|
||||
highlightNewBackground(new_bg);
|
||||
} else {
|
||||
toastr.warning('Failed to rename background');
|
||||
}
|
||||
}
|
||||
|
||||
async function onDeleteBackgroundClick(e) {
|
||||
e.stopPropagation();
|
||||
const bgToDelete = $(this).closest('.bg_example');
|
||||
const url = bgToDelete.data('url');
|
||||
const confirm = await callPopup("<h3>Delete the background?</h3>", 'confirm');
|
||||
|
||||
if (confirm) {
|
||||
delBackground(bgToDelete.attr("bgfile"));
|
||||
|
||||
const siblingSelector = '.bg_example:not(#form_bg_download)';
|
||||
const nextBg = bgToDelete.next(siblingSelector);
|
||||
const prevBg = bgToDelete.prev(siblingSelector);
|
||||
|
||||
if (nextBg.length > 0) {
|
||||
nextBg.trigger('click');
|
||||
} else {
|
||||
prevBg.trigger('click');
|
||||
}
|
||||
|
||||
bgToDelete.remove();
|
||||
|
||||
if (url === chat_metadata[METADATA_KEY]) {
|
||||
removeBackgroundMetadata();
|
||||
unsetCustomBackground();
|
||||
highlightLockedBackground();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const autoBgPrompt = `Pause your roleplay and choose a location ONLY from the provided list that is the most suitable for the current scene. Do not output any other text:\n{0}`;
|
||||
|
||||
async function autoBackgroundCommand() {
|
||||
const options = Array.from(document.querySelectorAll('.BGSampleTitle')).map(x => ({ element: x, text: x.innerText.trim() })).filter(x => x.text.length > 0);
|
||||
if (options.length == 0) {
|
||||
toastr.warning('No backgrounds to choose from. Please upload some images to the "backgrounds" folder.');
|
||||
return;
|
||||
}
|
||||
|
||||
const list = options.map(option => `- ${option.text}`).join('\n');
|
||||
const prompt = stringFormat(autoBgPrompt, list);
|
||||
const reply = await generateQuietPrompt(prompt, false, false);
|
||||
const fuse = new Fuse(options, { keys: ['text'] });
|
||||
const bestMatch = fuse.search(reply, { limit: 1 });
|
||||
|
||||
if (bestMatch.length == 0) {
|
||||
toastr.warning('No match found. Please try again.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('Automatically choosing background:', bestMatch);
|
||||
bestMatch[0].item.element.click();
|
||||
}
|
||||
|
||||
export async function getBackgrounds() {
|
||||
const response = await fetch("/getbackgrounds", {
|
||||
method: "POST",
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
"": "",
|
||||
}),
|
||||
});
|
||||
if (response.ok === true) {
|
||||
const getData = await response.json();
|
||||
//background = getData;
|
||||
//console.log(getData.length);
|
||||
$("#bg_menu_content").children('div').remove();
|
||||
for (const bg of getData) {
|
||||
const template = getBackgroundFromTemplate(bg, false);
|
||||
$("#bg_menu_content").append(template);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the URL of the background
|
||||
* @param {Element} block
|
||||
* @returns {string} URL of the background
|
||||
*/
|
||||
function getUrlParameter(block) {
|
||||
return $(block).closest(".bg_example").data("url");
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a background template
|
||||
* @param {string} bg Path to background
|
||||
* @param {boolean} isCustom Whether the background is custom
|
||||
* @returns
|
||||
*/
|
||||
function getBackgroundFromTemplate(bg, isCustom) {
|
||||
const thumbPath = getThumbnailUrl('bg', bg);
|
||||
const template = $('#background_template .bg_example').clone();
|
||||
const url = isCustom ? `url("${bg}")` : `url("${getBackgroundPath(bg)}")`;
|
||||
template.attr('title', bg);
|
||||
template.attr('bgfile', bg);
|
||||
template.attr('custom', String(isCustom));
|
||||
template.data('url', url);
|
||||
template.css('background-image', `url('${thumbPath}')`);
|
||||
template.find('.BGSampleTitle').text(bg.slice(0, bg.lastIndexOf('.')));
|
||||
return template;
|
||||
}
|
||||
|
||||
async function setBackground(bg) {
|
||||
jQuery.ajax({
|
||||
type: "POST", //
|
||||
url: "/setbackground", //
|
||||
data: JSON.stringify({
|
||||
bg: bg,
|
||||
}),
|
||||
beforeSend: function () {
|
||||
|
||||
},
|
||||
cache: false,
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
//processData: false,
|
||||
success: function (html) { },
|
||||
error: function (jqXHR, exception) {
|
||||
console.log(exception);
|
||||
console.log(jqXHR);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function delBackground(bg) {
|
||||
const response = await fetch("/delbackground", {
|
||||
method: "POST",
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
bg: bg,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
function onBackgroundUploadSelected() {
|
||||
const input = this;
|
||||
|
||||
if (input.files && input.files[0]) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = function (e) {
|
||||
const form = $("#form_bg_download").get(0);
|
||||
|
||||
if (!(form instanceof HTMLFormElement)) {
|
||||
console.error('form_bg_download is not a form');
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData(form);
|
||||
|
||||
//console.log(formData);
|
||||
jQuery.ajax({
|
||||
type: "POST",
|
||||
url: "/downloadbackground",
|
||||
data: formData,
|
||||
beforeSend: function () {
|
||||
|
||||
},
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
success: async function (bg) {
|
||||
form.reset();
|
||||
setBackground(bg);
|
||||
$("#bg1").css("background-image", `url("${getBackgroundPath(bg)}"`);
|
||||
await getBackgrounds();
|
||||
highlightNewBackground(bg);
|
||||
},
|
||||
error: function (jqXHR, exception) {
|
||||
form.reset();
|
||||
console.log(exception);
|
||||
console.log(jqXHR);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} bg
|
||||
*/
|
||||
function highlightNewBackground(bg) {
|
||||
const newBg = $(`.bg_example[bgfile="${bg}"]`);
|
||||
const scrollOffset = newBg.offset().top - newBg.parent().offset().top;
|
||||
$('#Backgrounds').scrollTop(scrollOffset);
|
||||
newBg.addClass('flash animated');
|
||||
setTimeout(() => newBg.removeClass('flash animated'), 2000);
|
||||
}
|
||||
|
||||
function onBackgroundFilterInput() {
|
||||
const filterValue = String($(this).val()).toLowerCase();
|
||||
$("#bg_menu_content > div").each(function () {
|
||||
const $bgContent = $(this);
|
||||
if ($bgContent.attr("title").toLowerCase().includes(filterValue)) {
|
||||
$bgContent.show();
|
||||
} else {
|
||||
$bgContent.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function initBackgrounds() {
|
||||
eventSource.on(event_types.CHAT_CHANGED, onChatChanged);
|
||||
eventSource.on(event_types.FORCE_SET_BACKGROUND, forceSetBackground);
|
||||
$(document).on("click", ".bg_example", onSelectBackgroundClick);
|
||||
$(document).on('click', '.bg_example_lock', onLockBackgroundClick);
|
||||
$(document).on('click', '.bg_example_unlock', onUnlockBackgroundClick);
|
||||
$(document).on('click', '.bg_example_edit', onRenameBackgroundClick);
|
||||
$(document).on("click", ".bg_example_cross", onDeleteBackgroundClick);
|
||||
$('#auto_background').on("click", autoBackgroundCommand);
|
||||
$("#add_bg_button").on('change', onBackgroundUploadSelected);
|
||||
$("#bg-filter").on("input", onBackgroundFilterInput);
|
||||
registerSlashCommand('lockbg', onLockBackgroundClick, ['bglock'], "– locks a background for the currently selected chat", true, true);
|
||||
registerSlashCommand('unlockbg', onUnlockBackgroundClick, ['bgunlock'], '– unlocks a background for the currently selected chat', true, true);
|
||||
registerSlashCommand('autobg', autoBackgroundCommand, ['bgauto'], '– automatically changes the background based on the chat context using the AI request prompt', true, true);
|
||||
}
|
|
@ -1,178 +0,0 @@
|
|||
import { eventSource, event_types, generateQuietPrompt } from "../../../script.js";
|
||||
import { getContext, saveMetadataDebounced } from "../../extensions.js";
|
||||
import { registerSlashCommand } from "../../slash-commands.js";
|
||||
import { stringFormat } from "../../utils.js";
|
||||
export { MODULE_NAME };
|
||||
|
||||
const MODULE_NAME = 'backgrounds';
|
||||
const METADATA_KEY = 'custom_background';
|
||||
|
||||
/**
|
||||
* @param {string} background
|
||||
*/
|
||||
function forceSetBackground(background) {
|
||||
saveBackgroundMetadata(background);
|
||||
setCustomBackground();
|
||||
}
|
||||
|
||||
async function moduleWorker() {
|
||||
if (hasCustomBackground()) {
|
||||
$('#unlock_background').show();
|
||||
$('#lock_background').hide();
|
||||
setCustomBackground();
|
||||
}
|
||||
else {
|
||||
$('#unlock_background').hide();
|
||||
$('#lock_background').show();
|
||||
unsetCustomBackground();
|
||||
}
|
||||
}
|
||||
|
||||
function onLockBackgroundClick() {
|
||||
const bgImage = window.getComputedStyle(document.getElementById('bg1')).backgroundImage;
|
||||
|
||||
// Extract the URL from the CSS string
|
||||
const urlRegex = /url\((['"])?(.*?)\1\)/;
|
||||
const matches = bgImage.match(urlRegex);
|
||||
const url = matches[2];
|
||||
|
||||
// Remove the protocol and host, leaving the relative URL
|
||||
const relativeUrl = new URL(url).pathname;
|
||||
const relativeBgImage = `url("${relativeUrl}")`
|
||||
|
||||
saveBackgroundMetadata(relativeBgImage);
|
||||
setCustomBackground();
|
||||
$('#unlock_background').show();
|
||||
$('#lock_background').hide();
|
||||
}
|
||||
|
||||
function onUnlockBackgroundClick() {
|
||||
removeBackgroundMetadata();
|
||||
unsetCustomBackground();
|
||||
$('#unlock_background').hide();
|
||||
$('#lock_background').show();
|
||||
}
|
||||
|
||||
function hasCustomBackground() {
|
||||
const context = getContext();
|
||||
return !!context.chatMetadata[METADATA_KEY];
|
||||
}
|
||||
|
||||
function saveBackgroundMetadata(file) {
|
||||
const context = getContext();
|
||||
context.chatMetadata[METADATA_KEY] = file;
|
||||
saveMetadataDebounced();
|
||||
}
|
||||
|
||||
function removeBackgroundMetadata() {
|
||||
const context = getContext();
|
||||
delete context.chatMetadata[METADATA_KEY];
|
||||
saveMetadataDebounced();
|
||||
}
|
||||
|
||||
function setCustomBackground() {
|
||||
const context = getContext();
|
||||
const file = context.chatMetadata[METADATA_KEY];
|
||||
|
||||
// bg already set
|
||||
if (document.getElementById("bg_custom").style.backgroundImage == file) {
|
||||
return;
|
||||
}
|
||||
|
||||
$("#bg_custom").css("background-image", file);
|
||||
$("#custom_bg_preview").css("background-image", file);
|
||||
}
|
||||
|
||||
function unsetCustomBackground() {
|
||||
$("#bg_custom").css("background-image", 'none');
|
||||
$("#custom_bg_preview").css("background-image", 'none');
|
||||
}
|
||||
|
||||
function onSelectBackgroundClick() {
|
||||
const bgfile = $(this).attr("bgfile");
|
||||
|
||||
if (hasCustomBackground()) {
|
||||
saveBackgroundMetadata(`url("backgrounds/${bgfile}")`);
|
||||
setCustomBackground();
|
||||
}
|
||||
}
|
||||
|
||||
const autoBgPrompt = `Pause your roleplay and choose a location ONLY from the provided list that is the most suitable for the current scene. Do not output any other text:\n{0}`;
|
||||
|
||||
async function autoBackgroundCommand() {
|
||||
const options = Array.from(document.querySelectorAll('.BGSampleTitle')).map(x => ({ element: x, text: x.innerText.trim() })).filter(x => x.text.length > 0);
|
||||
if (options.length == 0) {
|
||||
toastr.warning('No backgrounds to choose from. Please upload some images to the "backgrounds" folder.');
|
||||
return;
|
||||
}
|
||||
|
||||
const list = options.map(option => `- ${option.text}`).join('\n');
|
||||
const prompt = stringFormat(autoBgPrompt, list);
|
||||
const reply = await generateQuietPrompt(prompt);
|
||||
const fuse = new Fuse(options, { keys: ['text'] });
|
||||
const bestMatch = fuse.search(reply, { limit: 1 });
|
||||
|
||||
if (bestMatch.length == 0) {
|
||||
toastr.warning('No match found. Please try again.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.debug('Automatically choosing background:', bestMatch);
|
||||
bestMatch[0].item.element.click();
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
function addSettings() {
|
||||
const html = `
|
||||
<div class="background_settings">
|
||||
<div class="inline-drawer">
|
||||
<div class="inline-drawer-toggle inline-drawer-header">
|
||||
<b>Chat Backgrounds</b>
|
||||
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||
</div>
|
||||
<div class="inline-drawer-content">
|
||||
<div class="background_controls">
|
||||
<div id="lock_background" class="menu_button">
|
||||
<i class="fa-solid fa-lock"></i>
|
||||
Lock
|
||||
</div>
|
||||
<div id="unlock_background" class="menu_button">
|
||||
<i class="fa-solid fa-unlock"></i>
|
||||
Unlock
|
||||
</div>
|
||||
<small>
|
||||
Press "Lock" to assign a currently selected background to a character or group chat.<br>
|
||||
Any background image selected while lock is engaged will be saved automatically.
|
||||
</small>
|
||||
</div>
|
||||
<div class="background_controls">
|
||||
<div id="auto_background" class="menu_button">
|
||||
<i class="fa-solid fa-wand-magic"></i>
|
||||
Auto
|
||||
</div>
|
||||
<small>
|
||||
Automatically select a background based on the chat context.<br>
|
||||
Respects the "Lock" setting state.
|
||||
</small>
|
||||
</div>
|
||||
<div>Preview</div>
|
||||
<div id="custom_bg_preview">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
$('#extensions_settings').append(html);
|
||||
$('#lock_background').on('click', onLockBackgroundClick);
|
||||
$('#unlock_background').on('click', onUnlockBackgroundClick);
|
||||
$(document).on("click", ".bg_example", onSelectBackgroundClick);
|
||||
$('#auto_background').on("click", autoBackgroundCommand);
|
||||
}
|
||||
|
||||
addSettings();
|
||||
registerSlashCommand('lockbg', onLockBackgroundClick, ['bglock'], "– locks a background for the currently selected chat", true, true);
|
||||
registerSlashCommand('unlockbg', onUnlockBackgroundClick, ['bgunlock'], '– unlocks a background for the currently selected chat', true, true);
|
||||
registerSlashCommand('autobg', autoBackgroundCommand, ['bgauto'], '– automatically changes the background based on the chat context using the AI request prompt', true, true);
|
||||
eventSource.on(event_types.FORCE_SET_BACKGROUND, forceSetBackground);
|
||||
eventSource.on(event_types.CHAT_CHANGED, moduleWorker);
|
||||
});
|
|
@ -1,11 +0,0 @@
|
|||
{
|
||||
"display_name": "Chat Backgrounds",
|
||||
"loading_order": 7,
|
||||
"requires": [],
|
||||
"optional": [],
|
||||
"js": "index.js",
|
||||
"css": "style.css",
|
||||
"author": "Cohee#1207",
|
||||
"version": "1.0.0",
|
||||
"homePage": "https://github.com/SillyTavern/SillyTavern"
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#custom_bg_preview {
|
||||
width: 160px;
|
||||
height: 90px;
|
||||
background-color: var(--grey30a);
|
||||
background-repeat: no-repeat;
|
||||
background-attachment: fixed;
|
||||
background-size: cover;
|
||||
border-radius: 20px;
|
||||
border: 1px solid var(--SmartThemeBorderColor);
|
||||
box-shadow: 0 0 7px var(--black50a);
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
#custom_bg_preview::before {
|
||||
content: 'No Background';
|
||||
color: white;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#custom_bg_preview:not([style*="background-image: none"])::before {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.background_controls .menu_button {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.background_controls {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.background_controls small {
|
||||
flex-grow: 1;
|
||||
}
|
|
@ -1512,7 +1512,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||
width: calc(var(--sheldWidth) - 10px);
|
||||
max-width: 100vw;
|
||||
max-width: 100svw;
|
||||
justify-content: center;
|
||||
justify-content: space-evenly;
|
||||
}
|
||||
|
||||
.bg_example {
|
||||
|
@ -1531,6 +1531,18 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.bg_example.locked {
|
||||
outline: 2px solid var(--golden);
|
||||
}
|
||||
|
||||
.bg_example:hover.locked .bg_example_lock {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bg_example:hover:not(.locked) .bg_example_unlock {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.BGSampleTitle {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
@ -1551,7 +1563,7 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||
position: absolute;
|
||||
top: 5px;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
opacity: 0.8;
|
||||
border-radius: 50%;
|
||||
font-size: 20px;
|
||||
color: var(--black70a);
|
||||
|
@ -1579,6 +1591,12 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||
left: 10px;
|
||||
}
|
||||
|
||||
.bg_example_lock,
|
||||
.bg_example_unlock {
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.add_bg_but {
|
||||
cursor: pointer;
|
||||
opacity: 0.1;
|
||||
|
|
Loading…
Reference in New Issue