mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Add extension setting for fallback expression
This commit is contained in:
@ -11,7 +11,7 @@ const MODULE_NAME = 'expressions';
|
|||||||
const UPDATE_INTERVAL = 2000;
|
const UPDATE_INTERVAL = 2000;
|
||||||
const STREAMING_UPDATE_INTERVAL = 6000;
|
const STREAMING_UPDATE_INTERVAL = 6000;
|
||||||
const TALKINGCHECK_UPDATE_INTERVAL = 500;
|
const TALKINGCHECK_UPDATE_INTERVAL = 500;
|
||||||
const FALLBACK_EXPRESSION = 'joy';
|
const DEFAULT_FALLBACK_EXPRESSION = 'joy';
|
||||||
const DEFAULT_EXPRESSIONS = [
|
const DEFAULT_EXPRESSIONS = [
|
||||||
'talkinghead',
|
'talkinghead',
|
||||||
'admiration',
|
'admiration',
|
||||||
@ -58,6 +58,14 @@ function isTalkingHeadEnabled() {
|
|||||||
return extension_settings.expressions.talkinghead && !extension_settings.expressions.local;
|
return extension_settings.expressions.talkinghead && !extension_settings.expressions.local;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the fallback expression if explicitly chosen, otherwise the default one
|
||||||
|
* @returns {string} expression name
|
||||||
|
*/
|
||||||
|
function getFallbackExpression() {
|
||||||
|
return extension_settings.expressions.fallback_expression ?? DEFAULT_FALLBACK_EXPRESSION;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles Talkinghead mode on/off.
|
* Toggles Talkinghead mode on/off.
|
||||||
*
|
*
|
||||||
@ -157,7 +165,8 @@ async function visualNovelSetCharacterSprites(container, name, expression) {
|
|||||||
|
|
||||||
const sprites = spriteCache[spriteFolderName];
|
const sprites = spriteCache[spriteFolderName];
|
||||||
const expressionImage = container.find(`.expression-holder[data-avatar="${avatar}"]`);
|
const expressionImage = container.find(`.expression-holder[data-avatar="${avatar}"]`);
|
||||||
const defaultSpritePath = sprites.find(x => x.label === FALLBACK_EXPRESSION)?.path;
|
const defaultExpression = getFallbackExpression();
|
||||||
|
const defaultSpritePath = sprites.find(x => x.label === defaultExpression)?.path;
|
||||||
const noSprites = sprites.length === 0;
|
const noSprites = sprites.length === 0;
|
||||||
|
|
||||||
if (expressionImage.length > 0) {
|
if (expressionImage.length > 0) {
|
||||||
@ -568,7 +577,7 @@ function handleImageChange() {
|
|||||||
// This preserves the same expression Talkinghead had at the moment it was switched off.
|
// This preserves the same expression Talkinghead had at the moment it was switched off.
|
||||||
const charName = getContext().name2;
|
const charName = getContext().name2;
|
||||||
const last = lastExpression[charName];
|
const last = lastExpression[charName];
|
||||||
const targetExpression = last ? last : FALLBACK_EXPRESSION;
|
const targetExpression = last ? last : getFallbackExpression();
|
||||||
setExpression(charName, targetExpression, true);
|
setExpression(charName, targetExpression, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -691,8 +700,8 @@ async function moduleWorker() {
|
|||||||
const force = !!context.groupId;
|
const force = !!context.groupId;
|
||||||
|
|
||||||
// Character won't be angry on you for swiping
|
// Character won't be angry on you for swiping
|
||||||
if (currentLastMessage.mes == '...' && expressionsList.includes(FALLBACK_EXPRESSION)) {
|
if (currentLastMessage.mes == '...' && expressionsList.includes(getFallbackExpression())) {
|
||||||
expression = FALLBACK_EXPRESSION;
|
expression = getFallbackExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
await sendExpressionCall(spriteFolderName, expression, force, vnMode);
|
await sendExpressionCall(spriteFolderName, expression, force, vnMode);
|
||||||
@ -965,7 +974,7 @@ function sampleClassifyText(text) {
|
|||||||
async function getExpressionLabel(text) {
|
async function getExpressionLabel(text) {
|
||||||
// Return if text is undefined, saving a costly fetch request
|
// Return if text is undefined, saving a costly fetch request
|
||||||
if ((!modules.includes('classify') && !extension_settings.expressions.local) || !text) {
|
if ((!modules.includes('classify') && !extension_settings.expressions.local) || !text) {
|
||||||
return FALLBACK_EXPRESSION;
|
return getFallbackExpression();
|
||||||
}
|
}
|
||||||
|
|
||||||
text = sampleClassifyText(text);
|
text = sampleClassifyText(text);
|
||||||
@ -1004,7 +1013,7 @@ async function getExpressionLabel(text) {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
return FALLBACK_EXPRESSION;
|
return getFallbackExpression();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1108,6 +1117,11 @@ async function getSpritesList(name) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function renderAdditionalExpressionSettings() {
|
||||||
|
renderCustomExpressions();
|
||||||
|
await renderFallbackExpressionPicker();
|
||||||
|
}
|
||||||
|
|
||||||
function renderCustomExpressions() {
|
function renderCustomExpressions() {
|
||||||
if (!Array.isArray(extension_settings.expressions.custom)) {
|
if (!Array.isArray(extension_settings.expressions.custom)) {
|
||||||
extension_settings.expressions.custom = [];
|
extension_settings.expressions.custom = [];
|
||||||
@ -1128,6 +1142,23 @@ function renderCustomExpressions() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function renderFallbackExpressionPicker() {
|
||||||
|
const expressions = await getExpressionsList();
|
||||||
|
|
||||||
|
const defaultPicker = $('#expression_fallback');
|
||||||
|
defaultPicker.empty();
|
||||||
|
|
||||||
|
const fallbackExpression = getFallbackExpression();
|
||||||
|
|
||||||
|
for (const expression of expressions) {
|
||||||
|
const option = document.createElement('option');
|
||||||
|
option.value = expression;
|
||||||
|
option.text = expression;
|
||||||
|
option.selected = expression == fallbackExpression;
|
||||||
|
defaultPicker.append(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function getExpressionsList() {
|
async function getExpressionsList() {
|
||||||
// Return cached list if available
|
// Return cached list if available
|
||||||
if (Array.isArray(expressionsList)) {
|
if (Array.isArray(expressionsList)) {
|
||||||
@ -1365,7 +1396,7 @@ async function onClickExpressionAddCustom() {
|
|||||||
|
|
||||||
// Add custom expression into settings
|
// Add custom expression into settings
|
||||||
extension_settings.expressions.custom.push(expressionName);
|
extension_settings.expressions.custom.push(expressionName);
|
||||||
renderCustomExpressions();
|
await renderAdditionalExpressionSettings();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
|
||||||
// Force refresh sprites list
|
// Force refresh sprites list
|
||||||
@ -1392,7 +1423,7 @@ async function onClickExpressionRemoveCustom() {
|
|||||||
// Remove custom expression from settings
|
// Remove custom expression from settings
|
||||||
const index = extension_settings.expressions.custom.indexOf(selectedExpression);
|
const index = extension_settings.expressions.custom.indexOf(selectedExpression);
|
||||||
extension_settings.expressions.custom.splice(index, 1);
|
extension_settings.expressions.custom.splice(index, 1);
|
||||||
renderCustomExpressions();
|
await renderAdditionalExpressionSettings();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
|
|
||||||
// Force refresh sprites list
|
// Force refresh sprites list
|
||||||
@ -1401,6 +1432,14 @@ async function onClickExpressionRemoveCustom() {
|
|||||||
moduleWorker();
|
moduleWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onExpressionFallbackChanged() {
|
||||||
|
const expression = this.value;
|
||||||
|
if (expression) {
|
||||||
|
extension_settings.expressions.fallback_expression = expression;
|
||||||
|
saveSettingsDebounced();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function handleFileUpload(url, formData) {
|
async function handleFileUpload(url, formData) {
|
||||||
try {
|
try {
|
||||||
const data = await jQuery.ajax({
|
const data = await jQuery.ajax({
|
||||||
@ -1648,7 +1687,7 @@ async function fetchImagesNoCache() {
|
|||||||
return await Promise.allSettled(promises);
|
return await Promise.allSettled(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
(function () {
|
(async function () {
|
||||||
function addExpressionImage() {
|
function addExpressionImage() {
|
||||||
const html = `
|
const html = `
|
||||||
<div id="expression-wrapper">
|
<div id="expression-wrapper">
|
||||||
@ -1668,7 +1707,7 @@ async function fetchImagesNoCache() {
|
|||||||
element.hide();
|
element.hide();
|
||||||
$('body').append(element);
|
$('body').append(element);
|
||||||
}
|
}
|
||||||
function addSettings() {
|
async function addSettings() {
|
||||||
$('#extensions_settings').append(renderExtensionTemplate(MODULE_NAME, 'settings'));
|
$('#extensions_settings').append(renderExtensionTemplate(MODULE_NAME, 'settings'));
|
||||||
$('#expression_override_button').on('click', onClickExpressionOverrideButton);
|
$('#expression_override_button').on('click', onClickExpressionOverrideButton);
|
||||||
$('#expressions_show_default').on('input', onExpressionsShowDefaultInput);
|
$('#expressions_show_default').on('input', onExpressionsShowDefaultInput);
|
||||||
@ -1696,10 +1735,11 @@ async function fetchImagesNoCache() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
renderCustomExpressions();
|
await renderAdditionalExpressionSettings();
|
||||||
|
|
||||||
$('#expression_custom_add').on('click', onClickExpressionAddCustom);
|
$('#expression_custom_add').on('click', onClickExpressionAddCustom);
|
||||||
$('#expression_custom_remove').on('click', onClickExpressionRemoveCustom);
|
$('#expression_custom_remove').on('click', onClickExpressionRemoveCustom);
|
||||||
|
$('#expression_fallback').on('change', onExpressionFallbackChanged)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause Talkinghead to save resources when the ST tab is not visible or the window is minimized.
|
// Pause Talkinghead to save resources when the ST tab is not visible or the window is minimized.
|
||||||
@ -1732,7 +1772,7 @@ async function fetchImagesNoCache() {
|
|||||||
|
|
||||||
addExpressionImage();
|
addExpressionImage();
|
||||||
addVisualNovelMode();
|
addVisualNovelMode();
|
||||||
addSettings();
|
await addSettings();
|
||||||
const wrapper = new ModuleWorkerWrapper(moduleWorker);
|
const wrapper = new ModuleWorkerWrapper(moduleWorker);
|
||||||
const updateFunction = wrapper.update.bind(wrapper);
|
const updateFunction = wrapper.update.bind(wrapper);
|
||||||
setInterval(updateFunction, UPDATE_INTERVAL);
|
setInterval(updateFunction, UPDATE_INTERVAL);
|
||||||
|
@ -18,6 +18,11 @@
|
|||||||
<input id="image_type_toggle" type="checkbox">
|
<input id="image_type_toggle" type="checkbox">
|
||||||
<span>Image Type - talkinghead (extras)</span>
|
<span>Image Type - talkinghead (extras)</span>
|
||||||
</label>
|
</label>
|
||||||
|
<div class="expression_fallback_block m-b-1 m-t-1">
|
||||||
|
<label for="expression_fallback">Default / Fallback Expression</label>
|
||||||
|
<small>Set the default and fallback expression being used when no matching expression is found.</small>
|
||||||
|
<select id="expression_fallback" class="flex1 margin0" data-i18n="Fallback Expression" placeholder="Fallback Expression"></select>
|
||||||
|
</div>
|
||||||
<div class="expression_custom_block m-b-1 m-t-1">
|
<div class="expression_custom_block m-b-1 m-t-1">
|
||||||
<label for="expression_custom">Custom Expressions</label>
|
<label for="expression_custom">Custom Expressions</label>
|
||||||
<small>Can be set manually or with an <tt>/emote</tt> slash command.</small>
|
<small>Can be set manually or with an <tt>/emote</tt> slash command.</small>
|
||||||
|
Reference in New Issue
Block a user