mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Allow setting floating prompt for each chat. Add extensions management
This commit is contained in:
@ -874,6 +874,7 @@
|
|||||||
<h4>Active extensions</h4>
|
<h4>Active extensions</h4>
|
||||||
<ul id="extensions_list">
|
<ul id="extensions_list">
|
||||||
</ul>
|
</ul>
|
||||||
|
<p>Missing something? Press <a id="extensions_details" href="javascript:void">here</a> for more details!</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="extensions_settings">
|
<div id="extensions_settings">
|
||||||
<h3>Extension settings</h3>
|
<h3>Extension settings</h3>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { callPopup } from "../script.js";
|
||||||
import { isSubsetOf } from "./utils.js";
|
import { isSubsetOf } from "./utils.js";
|
||||||
export {
|
export {
|
||||||
getContext,
|
getContext,
|
||||||
@ -9,7 +10,10 @@ const extensionNames = ['caption', 'dice', 'expressions', 'floating-prompt', 'me
|
|||||||
const manifests = await getManifests(extensionNames);
|
const manifests = await getManifests(extensionNames);
|
||||||
const extensions_urlKey = 'extensions_url';
|
const extensions_urlKey = 'extensions_url';
|
||||||
const extensions_autoConnectKey = 'extensions_autoconnect';
|
const extensions_autoConnectKey = 'extensions_autoconnect';
|
||||||
|
const extensions_disabledKey = 'extensions_disabled';
|
||||||
|
|
||||||
let modules = [];
|
let modules = [];
|
||||||
|
let disabledExtensions = getDisabledExtensions();
|
||||||
let activeExtensions = new Set();
|
let activeExtensions = new Set();
|
||||||
|
|
||||||
const getContext = () => window['TavernAI'].getContext();
|
const getContext = () => window['TavernAI'].getContext();
|
||||||
@ -18,6 +22,33 @@ const defaultUrl = "http://localhost:5100";
|
|||||||
const defaultRequestArgs = { method: 'GET', headers: { 'Bypass-Tunnel-Reminder': 'bypass' } };
|
const defaultRequestArgs = { method: 'GET', headers: { 'Bypass-Tunnel-Reminder': 'bypass' } };
|
||||||
let connectedToApi = false;
|
let connectedToApi = false;
|
||||||
|
|
||||||
|
function getDisabledExtensions() {
|
||||||
|
const value = localStorage.getItem(extensions_disabledKey);
|
||||||
|
return value ? JSON.parse(value) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
function onDisableExtensionClick() {
|
||||||
|
const name = $(this).data('name');
|
||||||
|
disableExtension(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onEnableExtensionClick() {
|
||||||
|
const name = $(this).data('name');
|
||||||
|
enableExtension(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function enableExtension(name) {
|
||||||
|
disabledExtensions = disabledExtensions.filter(x => x !== name);
|
||||||
|
localStorage.setItem(extensions_disabledKey, JSON.stringify(disabledExtensions));
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function disableExtension(name) {
|
||||||
|
disabledExtensions.push(name);
|
||||||
|
localStorage.setItem(extensions_disabledKey, JSON.stringify(disabledExtensions));
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
async function getManifests(names) {
|
async function getManifests(names) {
|
||||||
const obj = {};
|
const obj = {};
|
||||||
for (const name of names) {
|
for (const name of names) {
|
||||||
@ -45,10 +76,22 @@ async function activateExtensions() {
|
|||||||
// all required modules are active (offline extensions require none)
|
// all required modules are active (offline extensions require none)
|
||||||
if (isSubsetOf(modules, manifest.requires)) {
|
if (isSubsetOf(modules, manifest.requires)) {
|
||||||
try {
|
try {
|
||||||
|
const isDisabled = disabledExtensions.includes(name);
|
||||||
|
const li = document.createElement('li');
|
||||||
|
|
||||||
|
if (!isDisabled) {
|
||||||
await addExtensionScript(name, manifest);
|
await addExtensionScript(name, manifest);
|
||||||
await addExtensionStyle(name, manifest);
|
await addExtensionStyle(name, manifest);
|
||||||
activeExtensions.add(name);
|
activeExtensions.add(name);
|
||||||
$('#extensions_list').append(`<li id="${name}">${manifest.display_name}</li>`);
|
}
|
||||||
|
else {
|
||||||
|
li.classList.add('disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
li.id = name;
|
||||||
|
li.innerText = manifest.display_name;
|
||||||
|
|
||||||
|
$('#extensions_list').append(li);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
console.error(`Could not activate extension: ${name}`);
|
console.error(`Could not activate extension: ${name}`);
|
||||||
@ -156,6 +199,32 @@ function addExtensionScript(name, manifest) {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showExtensionsDetails() {
|
||||||
|
let html = '<h3>Modules provided by your Extensions API:</h3>';
|
||||||
|
html += modules.length ? modules.join(', ') : '<p class="failure">Not connected to the API!</p>';
|
||||||
|
html += '<h3>Available extensions:</h3>';
|
||||||
|
|
||||||
|
Object.entries(manifests).sort((a, b) => a[1].loading_order - b[1].loading_order).forEach(extension => {
|
||||||
|
const name = extension[0];
|
||||||
|
const manifest = extension[1];
|
||||||
|
html += `<h4>${manifest.display_name}</h4>`;
|
||||||
|
if (activeExtensions.has(name)) {
|
||||||
|
html += `<p class="success">Extension is active. <a href="javascript:void" data-name="${name}" class="disable_extension">Disable</a></p>`;
|
||||||
|
}
|
||||||
|
else if (disabledExtensions.includes(name)) {
|
||||||
|
html += `<p class="disabled">Extension is disabled. <a href="javascript:void" data-name=${name} class="enable_extension">Enable</a></p>`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const requirements = new Set(manifest.requires);
|
||||||
|
modules.forEach(x => requirements.delete(x));
|
||||||
|
const requirementsString = [...requirements].join(', ');
|
||||||
|
html += `<p>Missing modules: <span class="failure">${requirementsString}</span></p>`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
callPopup(`<div class="extensions_info">${html}</div>`, 'text');
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(async function () {
|
$(document).ready(async function () {
|
||||||
const url = localStorage.getItem(extensions_urlKey) ?? defaultUrl;
|
const url = localStorage.getItem(extensions_urlKey) ?? defaultUrl;
|
||||||
const autoConnect = localStorage.getItem(extensions_autoConnectKey) == 'true';
|
const autoConnect = localStorage.getItem(extensions_autoConnectKey) == 'true';
|
||||||
@ -163,6 +232,9 @@ $(document).ready(async function () {
|
|||||||
$("#extensions_connect").on('click', connectClickHandler);
|
$("#extensions_connect").on('click', connectClickHandler);
|
||||||
$("#extensions_autoconnect").on('input', autoConnectInputHandler);
|
$("#extensions_autoconnect").on('input', autoConnectInputHandler);
|
||||||
$("#extensions_autoconnect").prop('checked', autoConnect).trigger('input');
|
$("#extensions_autoconnect").prop('checked', autoConnect).trigger('input');
|
||||||
|
$("#extensions_details").on('click', showExtensionsDetails);
|
||||||
|
$(document).on('click', '.disable_extension', onDisableExtensionClick);
|
||||||
|
$(document).on('click', '.enable_extension', onEnableExtensionClick);
|
||||||
|
|
||||||
// Activate offline extensions
|
// Activate offline extensions
|
||||||
activateExtensions();
|
activateExtensions();
|
||||||
|
@ -2,8 +2,6 @@ import { getContext } from "../../extensions.js";
|
|||||||
export { MODULE_NAME };
|
export { MODULE_NAME };
|
||||||
|
|
||||||
const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory
|
const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory
|
||||||
const PROMPT_KEY = 'extensions_floating_prompt';
|
|
||||||
const INTERVAL_KEY = 'extensions_floating_interval';
|
|
||||||
const UPDATE_INTERVAL = 1000;
|
const UPDATE_INTERVAL = 1000;
|
||||||
|
|
||||||
let lastMessageNumber = null;
|
let lastMessageNumber = null;
|
||||||
@ -18,20 +16,29 @@ function onExtensionFloatingIntervalInput() {
|
|||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getLocalStorageKeys() {
|
||||||
|
const context = getContext();
|
||||||
|
const keySuffix = context.groupId ? context.groupId : `${context.characters[context.characterId].name}_${context.chatId}`;
|
||||||
|
return { prompt: `extensions_floating_prompt_${keySuffix}`, interval: `extensions_floating_interval_${keySuffix}` };
|
||||||
|
}
|
||||||
|
|
||||||
function loadSettings() {
|
function loadSettings() {
|
||||||
const prompt = localStorage.getItem(PROMPT_KEY);
|
const keys = getLocalStorageKeys();
|
||||||
const interval = localStorage.getItem(INTERVAL_KEY);
|
const prompt = localStorage.getItem(keys.prompt) ?? '';
|
||||||
|
const interval = localStorage.getItem(keys.interval) ?? 0;
|
||||||
$('#extension_floating_prompt').val(prompt).trigger('input');
|
$('#extension_floating_prompt').val(prompt).trigger('input');
|
||||||
$('#extension_floating_interval').val(interval).trigger('input');
|
$('#extension_floating_interval').val(interval).trigger('input');
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
localStorage.setItem(PROMPT_KEY, $('#extension_floating_prompt').val());
|
const keys = getLocalStorageKeys();
|
||||||
localStorage.setItem(INTERVAL_KEY, $('#extension_floating_interval').val());
|
localStorage.setItem(keys.prompt, $('#extension_floating_prompt').val());
|
||||||
|
localStorage.setItem(keys.interval, $('#extension_floating_interval').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
async function moduleWorker() {
|
async function moduleWorker() {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
|
loadSettings();
|
||||||
|
|
||||||
// take the count of messages
|
// take the count of messages
|
||||||
lastMessageNumber = Array.isArray(context.chat) && context.chat.length ? context.chat.filter(m => m.is_user).length : 0;
|
lastMessageNumber = Array.isArray(context.chat) && context.chat.length ? context.chat.filter(m => m.is_user).length : 0;
|
||||||
@ -41,7 +48,9 @@ async function moduleWorker() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const messagesTillInsertion = (lastMessageNumber % promptInsertionInterval);
|
const messagesTillInsertion = lastMessageNumber >= promptInsertionInterval
|
||||||
|
? (lastMessageNumber % promptInsertionInterval)
|
||||||
|
: (promptInsertionInterval - lastMessageNumber);
|
||||||
const shouldAddPrompt = messagesTillInsertion == 0;
|
const shouldAddPrompt = messagesTillInsertion == 0;
|
||||||
const prompt = shouldAddPrompt ? $('#extension_floating_prompt').val() : '';
|
const prompt = shouldAddPrompt ? $('#extension_floating_prompt').val() : '';
|
||||||
context.setExtensionPrompt(MODULE_NAME, prompt);
|
context.setExtensionPrompt(MODULE_NAME, prompt);
|
||||||
@ -67,6 +76,5 @@ async function moduleWorker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addExtensionsSettings();
|
addExtensionsSettings();
|
||||||
loadSettings();
|
|
||||||
setInterval(moduleWorker, UPDATE_INTERVAL);
|
setInterval(moduleWorker, UPDATE_INTERVAL);
|
||||||
})();
|
})();
|
@ -1171,8 +1171,9 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 36vh;
|
|
||||||
box-shadow: 0 0 5px 5px var(--fullred);
|
box-shadow: 0 0 5px 5px var(--fullred);
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
background-color: var(--black70a);
|
background-color: var(--black70a);
|
||||||
@ -2819,3 +2820,29 @@ label[for="extensions_autoconnect"] {
|
|||||||
.drawer-content {
|
.drawer-content {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.extensions_info {
|
||||||
|
text-align: left;
|
||||||
|
margin: 0 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extensions_info h3 {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extensions_info h4 {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extensions_info p {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.extensions_info .disabled {
|
||||||
|
color: lightgray;
|
||||||
|
}
|
||||||
|
|
||||||
|
#extensions_list .disabled {
|
||||||
|
text-decoration: line-through;
|
||||||
|
color: lightgray;
|
||||||
|
}
|
Reference in New Issue
Block a user