mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Add slash command parser
This commit is contained in:
@ -48,6 +48,7 @@
|
||||
<script type="module" src="scripts/horde.js"></script>
|
||||
<script type="module" src="scripts/poe.js"></script>
|
||||
<script type="module" src="scripts/RossAscends-mods.js"></script>
|
||||
<script type="module" src="scripts/slash-commands.js"></script>
|
||||
<script type="text/javascript" src="scripts/toolcool-color-picker.js"></script>
|
||||
|
||||
<title>SillyTavern</title>
|
||||
|
@ -91,6 +91,7 @@ import {
|
||||
|
||||
import { debounce, delay } from "./scripts/utils.js";
|
||||
import { extension_settings, loadExtensionSettings } from "./scripts/extensions.js";
|
||||
import { executeSlashCommands } from "./scripts/slash-commands.js";
|
||||
|
||||
//exporting functions and vars for mods
|
||||
export {
|
||||
@ -1031,23 +1032,20 @@ function getStoppingStrings(isImpersonate, addSpace) {
|
||||
return [addSpace ? `${result} ` : result];
|
||||
}
|
||||
|
||||
function getSlashCommand(message, type) {
|
||||
function processCommands(message, type) {
|
||||
if (type == "regenerate" || type == "swipe") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const commandMap = {
|
||||
"/?": system_message_types.HELP,
|
||||
"/help": system_message_types.HELP
|
||||
};
|
||||
const result = executeSlashCommands(message);
|
||||
$("#send_textarea").val(result.newText).trigger('input');
|
||||
|
||||
const activationText = message.trim().toLowerCase();
|
||||
|
||||
if (Object.keys(commandMap).includes(activationText)) {
|
||||
return commandMap[activationText];
|
||||
// interrupt generation if the input was nothing but a command
|
||||
if (message.length > 0 && result.newText.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return null;
|
||||
return result.interrupt;
|
||||
}
|
||||
|
||||
function sendSystemMessage(type, text) {
|
||||
@ -1311,11 +1309,11 @@ async function Generate(type, automatic_trigger, force_name2) {
|
||||
const isImpersonate = type == "impersonate";
|
||||
message_already_generated = isImpersonate ? `${name1}: ` : `${name2}: `;
|
||||
|
||||
const slashCommand = getSlashCommand($("#send_textarea").val(), type);
|
||||
const interruptedByCommand = processCommands($("#send_textarea").val(), type);
|
||||
|
||||
if (slashCommand == system_message_types.HELP) {
|
||||
sendSystemMessage(system_message_types.HELP);
|
||||
if (interruptedByCommand) {
|
||||
$("#send_textarea").val('').trigger('input');
|
||||
is_send_press = false;
|
||||
return;
|
||||
}
|
||||
|
||||
|
117
public/scripts/slash-commands.js
Normal file
117
public/scripts/slash-commands.js
Normal file
@ -0,0 +1,117 @@
|
||||
import {
|
||||
sendSystemMessage,
|
||||
system_message_types
|
||||
} from "../script.js";
|
||||
export {
|
||||
executeSlashCommands,
|
||||
registerSlashCommand,
|
||||
}
|
||||
|
||||
class SlashCommandParser {
|
||||
constructor() {
|
||||
this.commands = {};
|
||||
}
|
||||
|
||||
addCommand(command, callback, aliases, helpString = '', interruptsGeneration = false, purgeFromMessage = true) {
|
||||
const fnObj = { callback, helpString, interruptsGeneration, purgeFromMessage };
|
||||
this.commands[command] = fnObj;
|
||||
|
||||
if (Array.isArray(aliases)) {
|
||||
aliases.forEach((alias) => {
|
||||
this.commands[alias] = fnObj;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
parse(text) {
|
||||
const firstSpace = text.indexOf(' ');
|
||||
const command = firstSpace !== -1 ? text.substring(1, firstSpace) : text.substring(1);
|
||||
const args = firstSpace !== -1 ? text.substring(firstSpace + 1) : '';
|
||||
const argObj = {};
|
||||
let unnamedArg;
|
||||
|
||||
if (args.length > 0) {
|
||||
const argsArray = args.split(' ');
|
||||
for (let arg of argsArray) {
|
||||
const equalsIndex = arg.indexOf('=');
|
||||
if (equalsIndex !== -1) {
|
||||
const key = arg.substring(0, equalsIndex);
|
||||
const value = arg.substring(equalsIndex + 1);
|
||||
argObj[key] = value;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
unnamedArg = argsArray.slice(Object.keys(argObj).length).join(' ');
|
||||
}
|
||||
|
||||
if (this.commands[command]) {
|
||||
return { command: this.commands[command], args: argObj, value: unnamedArg };
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const parser = new SlashCommandParser();
|
||||
const registerSlashCommand = parser.addCommand.bind(parser);
|
||||
|
||||
parser.addCommand('help', helpCommandCallback, ['?'], 'Displays a help information', true, true);
|
||||
parser.addCommand('bg', setBackgroundCallback, ['background'], 'Sets a background', false, true);
|
||||
|
||||
function helpCommandCallback() {
|
||||
sendSystemMessage(system_message_types.HELP);
|
||||
}
|
||||
|
||||
function setBackgroundCallback(_, bg) {
|
||||
if (!bg) {
|
||||
return;
|
||||
}
|
||||
console.log('Set background to ' + bg);
|
||||
const bgElement = $(`.bg_example[bgfile^="${bg.trim()}"`);
|
||||
|
||||
if (bgElement.length) {
|
||||
bgElement.get(0).click();
|
||||
}
|
||||
}
|
||||
|
||||
function executeSlashCommands(text) {
|
||||
if (!text) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const lines = text.split('\n');
|
||||
const linesToRemove = [];
|
||||
|
||||
let interrupt = false;
|
||||
|
||||
for (let index = 0; index < lines.length; index++) {
|
||||
const trimmedLine = lines[index].trim();
|
||||
|
||||
if (!trimmedLine.startsWith('/')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const result = parser.parse(trimmedLine);
|
||||
|
||||
if (!result) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result.command.callback(result.args, result.value);
|
||||
|
||||
if (result.command.interruptsGeneration) {
|
||||
interrupt = true;
|
||||
}
|
||||
|
||||
if (result.command.purgeFromMessage) {
|
||||
linesToRemove.push(lines[index]);
|
||||
}
|
||||
}
|
||||
|
||||
const newText = lines.filter(x => linesToRemove.indexOf(x) === -1).join('\n');
|
||||
|
||||
return { interrupt, newText };
|
||||
}
|
Reference in New Issue
Block a user