mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
#442 Auto-classify backgrounds based on chat context. Add string fuzzy matching library.
This commit is contained in:
@ -35,6 +35,7 @@
|
|||||||
<script src="scripts/cropper.min.js"></script>
|
<script src="scripts/cropper.min.js"></script>
|
||||||
<script src="scripts/jquery-cropper.min.js"></script>
|
<script src="scripts/jquery-cropper.min.js"></script>
|
||||||
<script src="scripts/toastr.min.js"></script>
|
<script src="scripts/toastr.min.js"></script>
|
||||||
|
<script src="scripts/fuse.js"></script>
|
||||||
<script type="module" src="scripts/eventemitter.js"></script>
|
<script type="module" src="scripts/eventemitter.js"></script>
|
||||||
<script type="module" src="scripts/power-user.js"></script>
|
<script type="module" src="scripts/power-user.js"></script>
|
||||||
<script type="module" src="scripts/swiped-events.js"></script>
|
<script type="module" src="scripts/swiped-events.js"></script>
|
||||||
|
@ -1399,6 +1399,20 @@ function getStoppingStrings(isImpersonate, addSpace) {
|
|||||||
return addSpace ? result.map(x => `${x} `) : result;
|
return addSpace ? result.map(x => `${x} `) : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Background prompt generation
|
||||||
|
export async function generateQuietPrompt(quiet_prompt) {
|
||||||
|
return await new Promise(
|
||||||
|
async function promptPromise(resolve, reject) {
|
||||||
|
try {
|
||||||
|
await Generate('quiet', { resolve, reject, quiet_prompt, force_name2: true, });
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function processCommands(message, type) {
|
function processCommands(message, type) {
|
||||||
if (type == "regenerate" || type == "swipe" || type == 'quiet') {
|
if (type == "regenerate" || type == "swipe" || type == 'quiet') {
|
||||||
return null;
|
return null;
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
import { generateQuietPrompt } from "../../../script.js";
|
||||||
import { getContext, saveMetadataDebounced } from "../../extensions.js";
|
import { getContext, saveMetadataDebounced } from "../../extensions.js";
|
||||||
|
import { registerSlashCommand } from "../../slash-commands.js";
|
||||||
|
import { stringFormat } from "../../utils.js";
|
||||||
export { MODULE_NAME };
|
export { MODULE_NAME };
|
||||||
|
|
||||||
const MODULE_NAME = 'backgrounds';
|
const MODULE_NAME = 'backgrounds';
|
||||||
@ -87,6 +90,30 @@ function onSelectBackgroundClick() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 () {
|
$(document).ready(function () {
|
||||||
function addSettings() {
|
function addSettings() {
|
||||||
const html = `
|
const html = `
|
||||||
@ -111,6 +138,16 @@ $(document).ready(function () {
|
|||||||
Any background image selected while lock is engaged will be saved automatically.
|
Any background image selected while lock is engaged will be saved automatically.
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</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>Preview</div>
|
||||||
<div id="custom_bg_preview">
|
<div id="custom_bg_preview">
|
||||||
</div>
|
</div>
|
||||||
@ -122,8 +159,12 @@ $(document).ready(function () {
|
|||||||
$('#lock_background').on('click', onLockBackgroundClick);
|
$('#lock_background').on('click', onLockBackgroundClick);
|
||||||
$('#unlock_background').on('click', onUnlockBackgroundClick);
|
$('#unlock_background').on('click', onUnlockBackgroundClick);
|
||||||
$(document).on("click", ".bg_example", onSelectBackgroundClick);
|
$(document).on("click", ".bg_example", onSelectBackgroundClick);
|
||||||
|
$('#auto_background').on("click", autoBackgroundCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
addSettings();
|
addSettings();
|
||||||
setInterval(moduleWorker, UPDATE_INTERVAL);
|
setInterval(moduleWorker, UPDATE_INTERVAL);
|
||||||
|
registerSlashCommand('lock', onLockBackgroundClick, [], " – locks a background for the currently selected chat", true, true);
|
||||||
|
registerSlashCommand('unlock', onUnlockBackgroundClick, [], ' – unlocks a background for the currently selected chat', true, true);
|
||||||
|
registerSlashCommand('autobg', autoBackgroundCommand, ['bgauto'], ' – automatically changes the background based on the chat context', true, true);
|
||||||
});
|
});
|
||||||
|
@ -904,7 +904,9 @@ function setExpressionOverrideHtml(forceClear = false) {
|
|||||||
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="inline-drawer-content">
|
<div class="inline-drawer-content">
|
||||||
<p class="offline_mode">You are in offline mode. Click on the image below to set the expression.</p>
|
<div class="offline_mode">
|
||||||
|
<small>You are in offline mode. Click on the image below to set the expression.</small>
|
||||||
|
</div>
|
||||||
<div class="flex-container flexnowrap">
|
<div class="flex-container flexnowrap">
|
||||||
<input id="expression_override" type="text" class="text_pole" placeholder="Override folder name" />
|
<input id="expression_override" type="text" class="text_pole" placeholder="Override folder name" />
|
||||||
<input id="expression_override_button" class="menu_button" type="submit" value="Submit" />
|
<input id="expression_override_button" class="menu_button" type="submit" value="Submit" />
|
||||||
|
@ -143,11 +143,6 @@ img.expression.default {
|
|||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
.expression_settings p {
|
|
||||||
margin-top: 0.5rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.expression_settings label {
|
.expression_settings label {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -171,4 +166,4 @@ img.expression.default {
|
|||||||
div.expression {
|
div.expression {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@ import {
|
|||||||
substituteParams,
|
substituteParams,
|
||||||
eventSource,
|
eventSource,
|
||||||
event_types,
|
event_types,
|
||||||
|
generateQuietPrompt,
|
||||||
} from "../../../script.js";
|
} from "../../../script.js";
|
||||||
|
import { registerSlashCommand } from "../../slash-commands.js";
|
||||||
|
|
||||||
const MODULE_NAME = "Objective"
|
const MODULE_NAME = "Objective"
|
||||||
|
|
||||||
@ -40,18 +42,6 @@ const objectivePrompts = {
|
|||||||
|
|
||||||
const extensionPrompt = "Your current task is [{{task}}]. Balance existing roleplay with completing this task."
|
const extensionPrompt = "Your current task is [{{task}}]. Balance existing roleplay with completing this task."
|
||||||
|
|
||||||
// Background prompt generation
|
|
||||||
async function generateQuietPrompt(quiet_prompt) {
|
|
||||||
return await new Promise(
|
|
||||||
async function promptPromise(resolve, reject) {
|
|
||||||
try {
|
|
||||||
await getContext().generate('quiet', { resolve, reject, quiet_prompt, force_name2: true, });
|
|
||||||
}
|
|
||||||
catch {
|
|
||||||
reject();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//###############################//
|
//###############################//
|
||||||
//# Task Management #//
|
//# Task Management #//
|
||||||
@ -112,7 +102,7 @@ async function generateTasks() {
|
|||||||
|
|
||||||
// Call Quiet Generate to check if a task is completed
|
// Call Quiet Generate to check if a task is completed
|
||||||
async function checkTaskCompleted() {
|
async function checkTaskCompleted() {
|
||||||
// Make sure there are tasks
|
// Make sure there are tasks
|
||||||
if (jQuery.isEmptyObject(currentTask)) {
|
if (jQuery.isEmptyObject(currentTask)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -146,7 +136,7 @@ function setCurrentTask(taskId = null) {
|
|||||||
currentTask = globalTasks[index];
|
currentTask = globalTasks[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the task description and add to extension prompt
|
// Get the task description and add to extension prompt
|
||||||
const description = currentTask.description || null;
|
const description = currentTask.description || null;
|
||||||
|
|
||||||
// Now update the extension prompt
|
// Now update the extension prompt
|
||||||
@ -201,7 +191,7 @@ class ObjectiveTask {
|
|||||||
this.id=id
|
this.id=id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Complete the current task, setting next task to next incomplete task
|
// Complete the current task, setting next task to next incomplete task
|
||||||
completeTask() {
|
completeTask() {
|
||||||
@ -221,10 +211,10 @@ class ObjectiveTask {
|
|||||||
<div id="objective-task-add-${this.id}" class="objective-task-button fa-solid fa-plus fa-2x" title="Add Task"></div>
|
<div id="objective-task-add-${this.id}" class="objective-task-button fa-solid fa-plus fa-2x" title="Add Task"></div>
|
||||||
</div><br>
|
</div><br>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
// Add the filled out template
|
// Add the filled out template
|
||||||
$('#objective-tasks').append(template);
|
$('#objective-tasks').append(template);
|
||||||
|
|
||||||
this.completedCheckbox = $(`#objective-task-complete-${this.id}`);
|
this.completedCheckbox = $(`#objective-task-complete-${this.id}`);
|
||||||
this.descriptionSpan = $(`#objective-task-description-${this.id}`);
|
this.descriptionSpan = $(`#objective-task-description-${this.id}`);
|
||||||
this.addButton = $(`#objective-task-add-${this.id}`);
|
this.addButton = $(`#objective-task-add-${this.id}`);
|
||||||
@ -250,7 +240,7 @@ class ObjectiveTask {
|
|||||||
onDescriptionFocusout(){
|
onDescriptionFocusout(){
|
||||||
setCurrentTask();
|
setCurrentTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeleteClick(){
|
onDeleteClick(){
|
||||||
deleteTask(this.id);
|
deleteTask(this.id);
|
||||||
}
|
}
|
||||||
@ -437,16 +427,16 @@ jQuery(() => {
|
|||||||
<label for="objective-text"><small>Enter an objective and generate tasks. The AI will attempt to complete tasks autonomously</small></label>
|
<label for="objective-text"><small>Enter an objective and generate tasks. The AI will attempt to complete tasks autonomously</small></label>
|
||||||
<textarea id="objective-text" type="text" class="text_pole textarea_compact" rows="4"></textarea>
|
<textarea id="objective-text" type="text" class="text_pole textarea_compact" rows="4"></textarea>
|
||||||
<div class="objective_block flex-container">
|
<div class="objective_block flex-container">
|
||||||
<input id="objective-generate" class="menu_button" type="submit" value="Auto-Generate Tasks" />
|
<input id="objective-generate" class="menu_button" type="submit" value="Auto-Generate Tasks" />
|
||||||
<label class="checkbox_label"><input id="objective-hide-tasks" type="checkbox"> Hide Tasks</label>
|
<label class="checkbox_label"><input id="objective-hide-tasks" type="checkbox"> Hide Tasks</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="objective-tasks"> </div>
|
<div id="objective-tasks"> </div>
|
||||||
<div class="objective_block margin-bot-10px">
|
<div class="objective_block margin-bot-10px">
|
||||||
<div class="objective_block objective_block_control flex1 flexFlowColumn">
|
<div class="objective_block objective_block_control flex1 flexFlowColumn">
|
||||||
<label for="objective-chat-depth">Position in Chat</label>
|
<label for="objective-chat-depth">Position in Chat</label>
|
||||||
<input id="objective-chat-depth" class="text_pole widthUnset" type="number" min="0" max="99" />
|
<input id="objective-chat-depth" class="text_pole widthUnset" type="number" min="0" max="99" />
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<div class="objective_block objective_block_control flex1">
|
<div class="objective_block objective_block_control flex1">
|
||||||
|
|
||||||
@ -486,4 +476,6 @@ jQuery(() => {
|
|||||||
setCurrentTask();
|
setCurrentTask();
|
||||||
$('#objective-counter').text(checkCounter)
|
$('#objective-counter').text(checkCounter)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerSlashCommand('taskcheck', checkTaskCompleted, [], ' – checks if the current task is completed', true, true);
|
||||||
});
|
});
|
||||||
|
2240
public/scripts/fuse.js
Normal file
2240
public/scripts/fuse.js
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user