From a37b805a5db526158478dd84a20aee96c35f2efc Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Thu, 5 Sep 2024 00:06:14 +0200 Subject: [PATCH 1/6] /classify can specify classier API as argument --- .../scripts/extensions/expressions/index.js | 43 +++++++++++++++---- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index ab02d1a51..ef5000fac 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -8,7 +8,7 @@ import { isJsonSchemaSupported } from '../../textgen-settings.js'; import { debounce_timeout } from '../../constants.js'; import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js'; import { SlashCommand } from '../../slash-commands/SlashCommand.js'; -import { ARGUMENT_TYPE, SlashCommandArgument } from '../../slash-commands/SlashCommandArgument.js'; +import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js'; import { isFunctionCallingSupported } from '../../openai.js'; import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js'; import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; @@ -52,6 +52,7 @@ const DEFAULT_EXPRESSIONS = [ 'surprise', 'neutral', ]; +/** @enum {number} */ const EXPRESSION_API = { local: 0, extras: 1, @@ -920,18 +921,24 @@ async function setSpriteSetCommand(_, folder) { return ''; } -async function classifyCommand(_, text) { +async function classifyCallback(/** @type {{api: string?}} */ { api = null }, text) { if (!text) { - console.log('No text provided'); + toastr.warning('No text provided'); + return ''; + } + if (api && !Object.keys(EXPRESSION_API).includes(api)) { + toastr.warning('Invalid API provided'); return ''; } - if (!modules.includes('classify') && extension_settings.expressions.api == EXPRESSION_API.extras) { + const expressionApi = EXPRESSION_API[api] || extension_settings.expressions.api; + + if (!modules.includes('classify') && expressionApi == EXPRESSION_API.extras) { toastr.warning('Text classification is disabled or not available'); return ''; } - const label = getExpressionLabel(text); + const label = getExpressionLabel(text, expressionApi); console.debug(`Classification result for "${text}": ${label}`); return label; } @@ -1108,9 +1115,16 @@ function onTextGenSettingsReady(args) { } } -async function getExpressionLabel(text) { +/** + * Retrieves the label of an expression via classification based on the provided text. + * Optionally allows to override the expressions API being used. + * @param {string} text - The text to classify and retrieve the expression label for. + * @param {EXPRESSION_API} [expressionsApi=extension_settings.expressions.api] - The expressions API to use for classification. + * @returns {Promise} - The label of the expression. + */ +export async function getExpressionLabel(text, expressionsApi = extension_settings.expressions.api) { // Return if text is undefined, saving a costly fetch request - if ((!modules.includes('classify') && extension_settings.expressions.api == EXPRESSION_API.extras) || !text) { + if ((!modules.includes('classify') && expressionsApi == EXPRESSION_API.extras) || !text) { return getFallbackExpression(); } @@ -1121,7 +1135,7 @@ async function getExpressionLabel(text) { text = sampleClassifyText(text); try { - switch (extension_settings.expressions.api) { + switch (expressionsApi) { // Local BERT pipeline case EXPRESSION_API.local: { const localResult = await fetch('/api/extra/classify', { @@ -2105,7 +2119,15 @@ function migrateSettings() { })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'classify', - callback: classifyCommand, + callback: classifyCallback, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'api', + description: 'The Classifier API to classify with. If not specified, the configured one will be used.', + typeList: [ARGUMENT_TYPE.STRING], + enumList: Object.keys(EXPRESSION_API).map(api => new SlashCommandEnumValue(api, null, enumTypes.enum)), + }), + ], unnamedArgumentList: [ new SlashCommandArgument( 'text', [ARGUMENT_TYPE.STRING], true, @@ -2116,6 +2138,9 @@ function migrateSettings() {
Performs an emotion classification of the given text and returns a label.
+
+ Allows to specify which Classifier API to perform the classification with. +
Example:
    From 2472b2605766eb032253d96a4f3fb27ed20522ff Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Thu, 5 Sep 2024 00:13:54 +0200 Subject: [PATCH 2/6] /classify allows custom prompt for LLM api --- public/scripts/extensions/expressions/index.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index ef5000fac..e642cedac 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -921,7 +921,7 @@ async function setSpriteSetCommand(_, folder) { return ''; } -async function classifyCallback(/** @type {{api: string?}} */ { api = null }, text) { +async function classifyCallback(/** @type {{api: string?, prompt: string?}} */ { api = null, prompt = null }, text) { if (!text) { toastr.warning('No text provided'); return ''; @@ -938,7 +938,7 @@ async function classifyCallback(/** @type {{api: string?}} */ { api = null }, te return ''; } - const label = getExpressionLabel(text, expressionApi); + const label = getExpressionLabel(text, expressionApi, { customPrompt: prompt }); console.debug(`Classification result for "${text}": ${label}`); return label; } @@ -1120,9 +1120,11 @@ function onTextGenSettingsReady(args) { * Optionally allows to override the expressions API being used. * @param {string} text - The text to classify and retrieve the expression label for. * @param {EXPRESSION_API} [expressionsApi=extension_settings.expressions.api] - The expressions API to use for classification. + * @param {object} [options={}] - Optional arguments. + * @param {string?} [options.customPrompt=null] - The custom prompt to use for classification. * @returns {Promise} - The label of the expression. */ -export async function getExpressionLabel(text, expressionsApi = extension_settings.expressions.api) { +export async function getExpressionLabel(text, expressionsApi = extension_settings.expressions.api, { customPrompt = null } = {}) { // Return if text is undefined, saving a costly fetch request if ((!modules.includes('classify') && expressionsApi == EXPRESSION_API.extras) || !text) { return getFallbackExpression(); @@ -1159,7 +1161,7 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin } const expressionsList = await getExpressionsList(); - const prompt = await getLlmPrompt(expressionsList); + const prompt = customPrompt || await getLlmPrompt(expressionsList); let functionResult = null; eventSource.once(event_types.TEXT_COMPLETION_SETTINGS_READY, onTextGenSettingsReady); eventSource.once(event_types.LLM_FUNCTION_TOOL_REGISTER, onFunctionToolRegister); @@ -2127,6 +2129,11 @@ function migrateSettings() { typeList: [ARGUMENT_TYPE.STRING], enumList: Object.keys(EXPRESSION_API).map(api => new SlashCommandEnumValue(api, null, enumTypes.enum)), }), + SlashCommandNamedArgument.fromProps({ + name: 'prompt', + description: 'Custom prompt for classification. Only relevant if Classifier API is set to LLM.', + typeList: [ARGUMENT_TYPE.STRING], + }), ], unnamedArgumentList: [ new SlashCommandArgument( From 3b10ae00c7c6c2b801363a8f65251f936a062a88 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Thu, 5 Sep 2024 00:24:10 +0200 Subject: [PATCH 3/6] Add /classify-expressions to retrieve emote list --- public/scripts/extensions/expressions/index.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index e642cedac..87298f85d 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -1354,7 +1354,7 @@ function getCachedExpressions() { return [...expressionsList, ...extension_settings.expressions.custom].filter(onlyUnique); } -async function getExpressionsList() { +export async function getExpressionsList() { // Return cached list if available if (Array.isArray(expressionsList)) { return getCachedExpressions(); @@ -2085,7 +2085,7 @@ function migrateSettings() { }), ], helpString: 'Force sets the sprite for the current character.', - returns: 'label', + returns: 'the currently set sprite label after setting it.', })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'spriteoverride', @@ -2101,7 +2101,7 @@ function migrateSettings() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'lastsprite', callback: (_, value) => lastExpression[String(value).trim()] ?? '', - returns: 'sprite', + returns: 'the last set sprite / expression for the named character.', unnamedArgumentList: [ SlashCommandArgument.fromProps({ description: 'character name', @@ -2117,7 +2117,14 @@ function migrateSettings() { callback: toggleTalkingHeadCommand, aliases: ['talkinghead'], helpString: 'Character Expressions: toggles Image Type - talkinghead (extras) on/off.', - returns: ARGUMENT_TYPE.BOOLEAN, + returns: 'the current state of the Image Type - talkinghead (extras) on/off.', + })); + SlashCommandParser.addCommandObject(SlashCommand.fromProps({ + name: 'classify-expressions', + aliases: ['expressions'], + callback: async () => (await getExpressionsList()).join(', '), + returns: 'The comma-separated list of available expressions, including custom expressions.', + helpString: 'Returns a list of available expressions, including custom expressions.', })); SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'classify', From d62f18b523cef28a6ab73cbe8d0485d16e342cb8 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Thu, 5 Sep 2024 00:34:52 +0200 Subject: [PATCH 4/6] Add missing await --- public/scripts/extensions/expressions/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index 87298f85d..a55a95994 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -938,7 +938,7 @@ async function classifyCallback(/** @type {{api: string?, prompt: string?}} */ { return ''; } - const label = getExpressionLabel(text, expressionApi, { customPrompt: prompt }); + const label = await getExpressionLabel(text, expressionApi, { customPrompt: prompt }); console.debug(`Classification result for "${text}": ${label}`); return label; } From b4ecba2a453235d784556774aeab971d8e19a71e Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:23:51 +0300 Subject: [PATCH 5/6] Fix macro not replacing in custom prompt --- public/scripts/extensions/expressions/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index a55a95994..e1dfe873f 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -1161,7 +1161,7 @@ export async function getExpressionLabel(text, expressionsApi = extension_settin } const expressionsList = await getExpressionsList(); - const prompt = customPrompt || await getLlmPrompt(expressionsList); + const prompt = substituteParamsExtended(String(customPrompt), { labels: expressionsList }) || await getLlmPrompt(expressionsList); let functionResult = null; eventSource.once(event_types.TEXT_COMPLETION_SETTINGS_READY, onTextGenSettingsReady); eventSource.once(event_types.LLM_FUNCTION_TOOL_REGISTER, onFunctionToolRegister); From 85773ace79b3c9484e8351157894baa0d5ad74f3 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 5 Sep 2024 10:48:46 +0300 Subject: [PATCH 6/6] Add format arg for classify-expressions --- .../scripts/extensions/expressions/index.js | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/public/scripts/extensions/expressions/index.js b/public/scripts/extensions/expressions/index.js index e1dfe873f..b79acc2bb 100644 --- a/public/scripts/extensions/expressions/index.js +++ b/public/scripts/extensions/expressions/index.js @@ -2122,7 +2122,26 @@ function migrateSettings() { SlashCommandParser.addCommandObject(SlashCommand.fromProps({ name: 'classify-expressions', aliases: ['expressions'], - callback: async () => (await getExpressionsList()).join(', '), + callback: async (args) => { + const list = await getExpressionsList(); + switch (String(args.format).toLowerCase()) { + case 'json': + return JSON.stringify(list); + default: + return list.join(', '); + } + }, + namedArgumentList: [ + SlashCommandNamedArgument.fromProps({ + name: 'format', + description: 'The format to return the list in: comma-separated plain text or JSON array. Default is plain text.', + typeList: [ARGUMENT_TYPE.STRING], + enumList: [ + new SlashCommandEnumValue('plain', null, enumTypes.enum, ', '), + new SlashCommandEnumValue('json', null, enumTypes.enum, '[]'), + ], + }), + ], returns: 'The comma-separated list of available expressions, including custom expressions.', helpString: 'Returns a list of available expressions, including custom expressions.', }));