mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2024-12-14 02:16:14 +01:00
171 lines
6.3 KiB
JavaScript
171 lines
6.3 KiB
JavaScript
import { 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';
|
||
const UPDATE_INTERVAL = 1000;
|
||
|
||
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();
|
||
setInterval(moduleWorker, UPDATE_INTERVAL);
|
||
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);
|
||
});
|