Rename expression sync to thought-based expression portraits and clean up compatibility solutions
This commit is contained in:
@@ -139,15 +139,15 @@ import {
|
||||
renderAlternatePresentCharacters
|
||||
} from './src/systems/ui/alternatePresentCharacters.js';
|
||||
import {
|
||||
initExpressionSync,
|
||||
queueExpressionSyncFromThoughts,
|
||||
onExpressionSyncSettingChanged,
|
||||
initThoughtBasedExpressions,
|
||||
queueThoughtBasedExpressionsUpdate,
|
||||
onThoughtBasedExpressionsSettingChanged,
|
||||
onAlternatePresentCharactersVisibilityChanged,
|
||||
onHideDefaultExpressionDisplaySettingChanged,
|
||||
clearExpressionSyncCache,
|
||||
onExpressionSyncChatChanged,
|
||||
setExpressionSyncRefreshHandler
|
||||
} from './src/systems/integration/expressionSync.js';
|
||||
clearThoughtBasedExpressionsCache,
|
||||
onThoughtBasedExpressionsChatChanged,
|
||||
setThoughtBasedExpressionsRefreshHandler
|
||||
} from './src/systems/integration/thoughtBasedExpressions.js';
|
||||
|
||||
// Feature modules
|
||||
import { setupPlotButtons, sendPlotProgression } from './src/systems/features/plotProgression.js';
|
||||
@@ -177,7 +177,7 @@ import {
|
||||
// Old state variable declarations removed - now imported from core modules
|
||||
// (extensionSettings, lastGeneratedData, committedTrackerData, etc. are now in src/core/state.js)
|
||||
|
||||
setExpressionSyncRefreshHandler(() => {
|
||||
setThoughtBasedExpressionsRefreshHandler(() => {
|
||||
renderAlternatePresentCharacters({ useCommittedFallback: true });
|
||||
});
|
||||
|
||||
@@ -237,7 +237,7 @@ async function addExtensionSettings() {
|
||||
clearExtensionPrompts();
|
||||
updateChatThoughts(); // Remove thought bubbles
|
||||
cleanupCheckpointUI(); // Remove checkpoint buttons and indicators
|
||||
clearExpressionSyncCache();
|
||||
clearThoughtBasedExpressionsCache();
|
||||
|
||||
// Disable dynamic weather effects
|
||||
toggleDynamicWeather(false);
|
||||
@@ -253,7 +253,7 @@ async function addExtensionSettings() {
|
||||
await initUI();
|
||||
loadChatData(); // Load chat data for current chat
|
||||
scheduleChatStateRehydration();
|
||||
initExpressionSync();
|
||||
initThoughtBasedExpressions();
|
||||
updateChatThoughts(); // Create thought bubbles if data exists
|
||||
injectCheckpointButton(); // Re-add checkpoint buttons
|
||||
updateAllCheckpointIndicators(); // Update button states
|
||||
@@ -370,10 +370,10 @@ async function initUI() {
|
||||
onAlternatePresentCharactersVisibilityChanged();
|
||||
});
|
||||
|
||||
$('#rpg-toggle-sync-expressions').on('change', function() {
|
||||
extensionSettings.syncExpressionsToPresentCharacters = $(this).prop('checked');
|
||||
$('#rpg-toggle-thought-based-expressions').on('change', function() {
|
||||
extensionSettings.enableThoughtBasedExpressions = $(this).prop('checked');
|
||||
saveSettings();
|
||||
onExpressionSyncSettingChanged(extensionSettings.syncExpressionsToPresentCharacters);
|
||||
onThoughtBasedExpressionsSettingChanged(extensionSettings.enableThoughtBasedExpressions);
|
||||
});
|
||||
|
||||
$('#rpg-toggle-hide-default-expressions').on('change', function() {
|
||||
@@ -1095,7 +1095,7 @@ async function initUI() {
|
||||
$('#rpg-toggle-info-box').prop('checked', extensionSettings.showInfoBox);
|
||||
$('#rpg-toggle-thoughts').prop('checked', extensionSettings.showCharacterThoughts);
|
||||
$('#rpg-toggle-alt-present-characters').prop('checked', extensionSettings.showAlternatePresentCharactersPanel ?? false);
|
||||
$('#rpg-toggle-sync-expressions').prop('checked', extensionSettings.syncExpressionsToPresentCharacters === true);
|
||||
$('#rpg-toggle-thought-based-expressions').prop('checked', extensionSettings.enableThoughtBasedExpressions === true);
|
||||
$('#rpg-toggle-hide-default-expressions').prop('checked', extensionSettings.hideDefaultExpressionDisplay === true);
|
||||
$('#rpg-toggle-inventory').prop('checked', extensionSettings.showInventory);
|
||||
$('#rpg-toggle-quests').prop('checked', extensionSettings.showQuests);
|
||||
@@ -1339,7 +1339,7 @@ jQuery(async () => {
|
||||
try {
|
||||
loadChatData();
|
||||
scheduleChatStateRehydration();
|
||||
initExpressionSync();
|
||||
initThoughtBasedExpressions();
|
||||
// Initialize FAB widgets and strip widgets with any loaded data
|
||||
updateFabWidgets();
|
||||
updateStripWidgets();
|
||||
@@ -1425,7 +1425,7 @@ jQuery(async () => {
|
||||
|
||||
const renderedMessage = chat[messageId];
|
||||
if (renderedMessage && !renderedMessage.is_user && !renderedMessage.is_system) {
|
||||
queueExpressionSyncFromThoughts();
|
||||
queueThoughtBasedExpressionsUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1436,7 +1436,7 @@ jQuery(async () => {
|
||||
|
||||
const updatedMessage = chat[messageId];
|
||||
if (updatedMessage && !updatedMessage.is_user && !updatedMessage.is_system) {
|
||||
queueExpressionSyncFromThoughts();
|
||||
queueThoughtBasedExpressionsUpdate();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1447,13 +1447,13 @@ jQuery(async () => {
|
||||
|
||||
const swipedMessage = chat[messageIndex];
|
||||
if (swipedMessage && !swipedMessage.is_user && !swipedMessage.is_system) {
|
||||
queueExpressionSyncFromThoughts({ immediate: true });
|
||||
queueThoughtBasedExpressionsUpdate({ immediate: true });
|
||||
}
|
||||
});
|
||||
|
||||
eventSource.on(event_types.CHAT_CHANGED, () => {
|
||||
clearExpressionSyncCache();
|
||||
setTimeout(() => onExpressionSyncChatChanged(), 0);
|
||||
clearThoughtBasedExpressionsCache();
|
||||
setTimeout(() => onThoughtBasedExpressionsChatChanged(), 0);
|
||||
});
|
||||
|
||||
eventSource.on(event_types.MESSAGE_DELETED, () => {
|
||||
@@ -1461,8 +1461,8 @@ jQuery(async () => {
|
||||
return;
|
||||
}
|
||||
|
||||
clearExpressionSyncCache();
|
||||
setTimeout(() => onExpressionSyncChatChanged(), 0);
|
||||
clearThoughtBasedExpressionsCache();
|
||||
setTimeout(() => onThoughtBasedExpressionsChatChanged(), 0);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('[RPG Companion] Event registration failed:', error);
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ export const defaultSettings = {
|
||||
showInfoBox: true,
|
||||
showCharacterThoughts: true,
|
||||
showAlternatePresentCharactersPanel: false,
|
||||
syncExpressionsToPresentCharacters: false,
|
||||
enableThoughtBasedExpressions: false,
|
||||
hideDefaultExpressionDisplay: false,
|
||||
showInventory: true, // Show inventory section (v2 system)
|
||||
showQuests: true, // Show quests section
|
||||
|
||||
+8
-13
@@ -9,13 +9,13 @@ import {
|
||||
extensionSettings,
|
||||
lastGeneratedData,
|
||||
committedTrackerData,
|
||||
syncedExpressionPortraits,
|
||||
thoughtBasedExpressionPortraits,
|
||||
setExtensionSettings,
|
||||
updateExtensionSettings,
|
||||
setLastGeneratedData,
|
||||
setCommittedTrackerData,
|
||||
setSyncedExpressionPortraits,
|
||||
clearSyncedExpressionPortraits,
|
||||
setThoughtBasedExpressionPortraits,
|
||||
clearThoughtBasedExpressionPortraits,
|
||||
FEATURE_FLAGS
|
||||
} from './state.js';
|
||||
import { migrateInventory } from '../utils/migration.js';
|
||||
@@ -384,11 +384,6 @@ export function loadSettings() {
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (extensionSettings.syncExpressionsToPresentCharacters === undefined) {
|
||||
extensionSettings.syncExpressionsToPresentCharacters = false;
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (extensionSettings.hideDefaultExpressionDisplay === undefined) {
|
||||
extensionSettings.hideDefaultExpressionDisplay = false;
|
||||
settingsChanged = true;
|
||||
@@ -478,7 +473,7 @@ export function saveChatData() {
|
||||
quests: extensionSettings.quests,
|
||||
lastGeneratedData: lastGeneratedData,
|
||||
committedTrackerData: committedTrackerData,
|
||||
syncedExpressionPortraits: syncedExpressionPortraits,
|
||||
thoughtBasedExpressionPortraits: thoughtBasedExpressionPortraits,
|
||||
timestamp: Date.now()
|
||||
};
|
||||
|
||||
@@ -562,7 +557,7 @@ export function loadChatData() {
|
||||
infoBox: null,
|
||||
characterThoughts: null
|
||||
});
|
||||
clearSyncedExpressionPortraits();
|
||||
clearThoughtBasedExpressionPortraits();
|
||||
}
|
||||
|
||||
// Restore stats
|
||||
@@ -611,10 +606,10 @@ export function loadChatData() {
|
||||
// console.log('[RPG Companion] ⚠️ No lastGeneratedData found in save');
|
||||
}
|
||||
|
||||
if (savedData?.syncedExpressionPortraits && typeof savedData.syncedExpressionPortraits === 'object') {
|
||||
setSyncedExpressionPortraits(savedData.syncedExpressionPortraits);
|
||||
if (savedData?.thoughtBasedExpressionPortraits && typeof savedData.thoughtBasedExpressionPortraits === 'object') {
|
||||
setThoughtBasedExpressionPortraits(savedData.thoughtBasedExpressionPortraits);
|
||||
} else {
|
||||
clearSyncedExpressionPortraits();
|
||||
clearThoughtBasedExpressionPortraits();
|
||||
}
|
||||
|
||||
// Migrate inventory in chat data if feature flag enabled
|
||||
|
||||
+9
-25
@@ -19,7 +19,7 @@ export let extensionSettings = {
|
||||
showInfoBox: true,
|
||||
showCharacterThoughts: true,
|
||||
showAlternatePresentCharactersPanel: false,
|
||||
syncExpressionsToPresentCharacters: false,
|
||||
enableThoughtBasedExpressions: false,
|
||||
hideDefaultExpressionDisplay: false,
|
||||
showInventory: true, // Show inventory section (v2 system)
|
||||
showQuests: true, // Show quests section
|
||||
@@ -364,37 +364,21 @@ export function clearSessionAvatarPrompts() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-chat storage for thoughts-synced Character Expressions portraits.
|
||||
* Per-chat storage for thought-based Character Expressions portraits.
|
||||
* Maps normalized character names to the current below-chat portrait URL.
|
||||
*/
|
||||
export let syncedExpressionPortraits = {};
|
||||
export let thoughtBasedExpressionPortraits = {};
|
||||
|
||||
export function setSyncedExpressionPortrait(characterName, src) {
|
||||
if (!characterName || !src) {
|
||||
return;
|
||||
}
|
||||
|
||||
syncedExpressionPortraits[characterName] = src;
|
||||
export function setThoughtBasedExpressionPortraits(portraits) {
|
||||
thoughtBasedExpressionPortraits = portraits && typeof portraits === 'object' ? { ...portraits } : {};
|
||||
}
|
||||
|
||||
export function removeSyncedExpressionPortrait(characterName) {
|
||||
if (!characterName) {
|
||||
return;
|
||||
}
|
||||
|
||||
delete syncedExpressionPortraits[characterName];
|
||||
export function getThoughtBasedExpressionPortrait(characterName) {
|
||||
return thoughtBasedExpressionPortraits[characterName] || null;
|
||||
}
|
||||
|
||||
export function setSyncedExpressionPortraits(portraits) {
|
||||
syncedExpressionPortraits = portraits && typeof portraits === 'object' ? { ...portraits } : {};
|
||||
}
|
||||
|
||||
export function getSyncedExpressionPortrait(characterName) {
|
||||
return syncedExpressionPortraits[characterName] || null;
|
||||
}
|
||||
|
||||
export function clearSyncedExpressionPortraits() {
|
||||
syncedExpressionPortraits = {};
|
||||
export function clearThoughtBasedExpressionPortraits() {
|
||||
thoughtBasedExpressionPortraits = {};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@
|
||||
"template.settingsModal.display.showPresentCharactersNote": "Display character portraits with their current thoughts and status.",
|
||||
"template.settingsModal.display.showBelowChatPresentCharacters": "Show Below-Chat Present Characters",
|
||||
"template.settingsModal.display.showBelowChatPresentCharactersNote": "Display a compact Present Characters panel below the chat.",
|
||||
"template.settingsModal.display.syncBelowChatPresentCharactersExpressions": "Sync Expressions in Below-Chat Panel",
|
||||
"template.settingsModal.display.syncBelowChatPresentCharactersExpressionsNote": "Use SillyTavern Character Expressions to classify each present character's thoughts for the below-chat panel. If Character Expressions uses Main API with Full Context, this may increase token usage.",
|
||||
"template.settingsModal.display.thoughtBasedExpressions": "Thought-Based Expressions",
|
||||
"template.settingsModal.display.thoughtBasedExpressionsNote": "Use SillyTavern Character Expressions to classify each present character's thoughts for the below-chat panel. May increase token usage depending on the selected Classifier API.",
|
||||
"template.settingsModal.display.hideDefaultExpressionDisplay": "Hide Default Expression Display",
|
||||
"template.settingsModal.display.hideDefaultExpressionDisplayNote": "Hide SillyTavern's built-in Character Expressions display.",
|
||||
"template.settingsModal.display.narratorMode": "Narrator Mode",
|
||||
|
||||
+2
-2
@@ -37,8 +37,8 @@
|
||||
"template.settingsModal.display.showPresentCharactersNote": "Afficher les portraits des personnages avec leurs pensées actuelles et leur statut.",
|
||||
"template.settingsModal.display.showBelowChatPresentCharacters": "Afficher les personnages sous le chat",
|
||||
"template.settingsModal.display.showBelowChatPresentCharactersNote": "Afficher un panneau compact des personnages présents sous le chat.",
|
||||
"template.settingsModal.display.syncBelowChatPresentCharactersExpressions": "Synchroniser les expressions dans le panneau sous le chat",
|
||||
"template.settingsModal.display.syncBelowChatPresentCharactersExpressionsNote": "Utiliser Character Expressions de SillyTavern pour classifier les pensées de chaque personnage présent dans le panneau sous le chat. Si Character Expressions utilise Main API avec Full Context, cela peut augmenter l'utilisation de tokens.",
|
||||
"template.settingsModal.display.thoughtBasedExpressions": "Expressions basées sur les pensées",
|
||||
"template.settingsModal.display.thoughtBasedExpressionsNote": "Utiliser Character Expressions de SillyTavern pour classifier les pensées de chaque personnage présent dans le panneau sous le chat. L'utilisation de tokens peut augmenter selon l'API de classification sélectionnée.",
|
||||
"template.settingsModal.display.hideDefaultExpressionDisplay": "Masquer l'affichage d'expressions par défaut",
|
||||
"template.settingsModal.display.hideDefaultExpressionDisplayNote": "Masquer l'affichage intégré des expressions de personnage de SillyTavern.",
|
||||
"template.settingsModal.display.narratorMode": "Mode Narrateur",
|
||||
|
||||
+2
-2
@@ -36,8 +36,8 @@
|
||||
"template.settingsModal.display.showPresentCharactersNote": "Показывать портреты персонажей с их текущимы мыслями и статусом.",
|
||||
"template.settingsModal.display.showBelowChatPresentCharacters": "Показывать персонажей под чатом",
|
||||
"template.settingsModal.display.showBelowChatPresentCharactersNote": "Показывать компактную панель персонажей под чатом.",
|
||||
"template.settingsModal.display.syncBelowChatPresentCharactersExpressions": "Синхронизировать выражения в панели под чатом",
|
||||
"template.settingsModal.display.syncBelowChatPresentCharactersExpressionsNote": "Использовать Character Expressions в SillyTavern для классификации мыслей каждого присутствующего персонажа в панели под чатом. Если Character Expressions использует Main API с Full Context, расход token-ов может вырасти.",
|
||||
"template.settingsModal.display.thoughtBasedExpressions": "Выражения на основе мыслей",
|
||||
"template.settingsModal.display.thoughtBasedExpressionsNote": "Использовать Character Expressions в SillyTavern для классификации мыслей каждого присутствующего персонажа в панели под чатом. Расход токенов может увеличиться в зависимости от выбранного API классификации.",
|
||||
"template.settingsModal.display.hideDefaultExpressionDisplay": "Скрыть отображение выражений по умолчанию",
|
||||
"template.settingsModal.display.hideDefaultExpressionDisplayNote": "Скрыть встроенное отображение выражений персонажей SillyTavern.",
|
||||
"template.settingsModal.display.narratorMode": "Режим расказчика",
|
||||
|
||||
+2
-2
@@ -32,8 +32,8 @@
|
||||
"template.settingsModal.display.showPresentCharacters": "顯示在場角色",
|
||||
"template.settingsModal.display.showBelowChatPresentCharacters": "顯示聊天下方的在場角色",
|
||||
"template.settingsModal.display.showBelowChatPresentCharactersNote": "在聊天下方顯示精簡的在場角色面板。",
|
||||
"template.settingsModal.display.syncBelowChatPresentCharactersExpressions": "在聊天下方面板同步表情",
|
||||
"template.settingsModal.display.syncBelowChatPresentCharactersExpressionsNote": "使用 SillyTavern Character Expressions 對聊天下方面板中每個在場角色的想法進行分類。如果 Character Expressions 使用 Main API + Full Context,可能會增加 token 使用量。",
|
||||
"template.settingsModal.display.thoughtBasedExpressions": "基於想法的表情",
|
||||
"template.settingsModal.display.thoughtBasedExpressionsNote": "使用 SillyTavern Character Expressions 對聊天下方面板中每個在場角色的想法進行分類。Token 用量可能會依所選的分類 API 而增加。",
|
||||
"template.settingsModal.display.hideDefaultExpressionDisplay": "隱藏預設表情顯示",
|
||||
"template.settingsModal.display.hideDefaultExpressionDisplayNote": "隱藏 SillyTavern 內建的角色表情顯示。",
|
||||
"template.settingsModal.display.showInventory": "顯示物品欄",
|
||||
|
||||
+133
-129
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Character Expressions -> below-chat Present Characters portrait sync.
|
||||
* Thought-based Character Expressions for the below-chat Present Characters panel.
|
||||
*
|
||||
* Derives expression portraits from the current Present Characters thoughts
|
||||
* Derives portrait expressions from the current Present Characters thoughts
|
||||
* payload, while keeping SillyTavern's native Character Expressions widget
|
||||
* independent from the below-chat panel.
|
||||
*/
|
||||
@@ -9,15 +9,15 @@
|
||||
import { getContext } from '../../../../../../extensions.js';
|
||||
import {
|
||||
extensionSettings,
|
||||
syncedExpressionPortraits,
|
||||
setSyncedExpressionPortraits
|
||||
thoughtBasedExpressionPortraits,
|
||||
setThoughtBasedExpressionPortraits
|
||||
} from '../../core/state.js';
|
||||
import {
|
||||
getCurrentMessageSwipeTrackerData,
|
||||
saveChatData,
|
||||
setMessageSwipeTrackerField
|
||||
} from '../../core/persistence.js';
|
||||
import { isUsableExpressionSrc } from '../../utils/expressionPortraits.js';
|
||||
import { isUsableThoughtBasedExpressionSrc } from '../../utils/thoughtBasedExpressionPortraits.js';
|
||||
import {
|
||||
getPresentCharactersTrackerData,
|
||||
parsePresentCharacters
|
||||
@@ -35,16 +35,16 @@ import {
|
||||
|
||||
const OFF_SCENE_THOUGHT_PATTERN = /\b(not\s+(currently\s+)?(in|at|present|in\s+the)\s+(the\s+)?(scene|area|room|location|vicinity))\b|\b(off[\s-]?scene)\b|\b(not\s+present)\b|\b(absent)\b|\b(away\s+from\s+(the\s+)?scene)\b/i;
|
||||
const CHAT_CHANGE_RETRY_DELAYS = [0, 80, 220, 500];
|
||||
const SYNC_DEBOUNCE_DELAY = 80;
|
||||
const EXPRESSION_SYNC_CACHE_VERSION = 1;
|
||||
const EXPRESSION_SYNC_CACHE_FIELD = 'expressionSync';
|
||||
const REFRESH_DEBOUNCE_DELAY = 80;
|
||||
const THOUGHT_BASED_EXPRESSIONS_CACHE_VERSION = 1;
|
||||
const THOUGHT_BASED_EXPRESSIONS_CACHE_FIELD = 'thoughtBasedExpressions';
|
||||
|
||||
let hiddenExpressionStyleElement = null;
|
||||
let refreshExpressionConsumersHandler = null;
|
||||
let scheduledSyncTimer = null;
|
||||
let activeSyncRunId = 0;
|
||||
let lastCompletedSyncSignature = null;
|
||||
let lastExpressionsSettingsSignature = null;
|
||||
let thoughtBasedExpressionsRefreshHandler = null;
|
||||
let scheduledRefreshTimer = null;
|
||||
let activeRefreshRunId = 0;
|
||||
let lastCompletedRefreshSignature = null;
|
||||
let lastExpressionSettingsSignature = null;
|
||||
|
||||
function normalizeName(name) {
|
||||
return String(name || '').trim().toLowerCase();
|
||||
@@ -54,14 +54,14 @@ function shouldHideNativeExpressionDisplay() {
|
||||
return extensionSettings.enabled === true && extensionSettings.hideDefaultExpressionDisplay === true;
|
||||
}
|
||||
|
||||
function shouldSyncExpressionPortraits() {
|
||||
function shouldUseThoughtBasedExpressions() {
|
||||
return extensionSettings.enabled === true
|
||||
&& extensionSettings.syncExpressionsToPresentCharacters === true
|
||||
&& extensionSettings.enableThoughtBasedExpressions === true
|
||||
&& extensionSettings.showAlternatePresentCharactersPanel === true;
|
||||
}
|
||||
|
||||
function refreshExpressionConsumers() {
|
||||
refreshExpressionConsumersHandler?.();
|
||||
function notifyThoughtBasedExpressionsConsumers() {
|
||||
thoughtBasedExpressionsRefreshHandler?.();
|
||||
}
|
||||
|
||||
function getHideStyleCss() {
|
||||
@@ -109,7 +109,7 @@ function showNativeExpressionDisplay() {
|
||||
hiddenExpressionStyleElement = null;
|
||||
}
|
||||
|
||||
function syncNativeExpressionDisplayVisibility() {
|
||||
function updateNativeExpressionDisplayVisibility() {
|
||||
if (shouldHideNativeExpressionDisplay()) {
|
||||
hideNativeExpressionDisplay();
|
||||
} else {
|
||||
@@ -117,10 +117,10 @@ function syncNativeExpressionDisplayVisibility() {
|
||||
}
|
||||
}
|
||||
|
||||
function clearScheduledSync() {
|
||||
if (scheduledSyncTimer !== null) {
|
||||
clearTimeout(scheduledSyncTimer);
|
||||
scheduledSyncTimer = null;
|
||||
function clearScheduledRefresh() {
|
||||
if (scheduledRefreshTimer !== null) {
|
||||
clearTimeout(scheduledRefreshTimer);
|
||||
scheduledRefreshTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,25 +176,25 @@ function arePortraitMapsEqual(left, right) {
|
||||
return leftKeys.every(key => left[key] === right[key]);
|
||||
}
|
||||
|
||||
function applySyncedExpressionPortraits(nextPortraits) {
|
||||
if (arePortraitMapsEqual(syncedExpressionPortraits, nextPortraits)) {
|
||||
function applyThoughtBasedExpressionPortraits(nextPortraits) {
|
||||
if (arePortraitMapsEqual(thoughtBasedExpressionPortraits, nextPortraits)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
setSyncedExpressionPortraits(nextPortraits);
|
||||
setThoughtBasedExpressionPortraits(nextPortraits);
|
||||
return true;
|
||||
}
|
||||
|
||||
function purgeInvalidSyncedExpressionPortraits() {
|
||||
function purgeInvalidThoughtBasedExpressionPortraits() {
|
||||
const nextPortraits = {};
|
||||
|
||||
for (const [characterName, src] of Object.entries(syncedExpressionPortraits)) {
|
||||
if (isUsableExpressionSrc(src)) {
|
||||
for (const [characterName, src] of Object.entries(thoughtBasedExpressionPortraits)) {
|
||||
if (isUsableThoughtBasedExpressionSrc(src)) {
|
||||
nextPortraits[characterName] = src;
|
||||
}
|
||||
}
|
||||
|
||||
return applySyncedExpressionPortraits(nextPortraits);
|
||||
return applyThoughtBasedExpressionPortraits(nextPortraits);
|
||||
}
|
||||
|
||||
function getMessageThoughtPayload(message) {
|
||||
@@ -242,24 +242,28 @@ function findThoughtSourceMessageInfo(characterThoughtsData) {
|
||||
return currentThoughts ? null : fallback;
|
||||
}
|
||||
|
||||
function getSwipeExpressionSyncCache(sourceInfo) {
|
||||
const cache = sourceInfo?.swipeData?.[EXPRESSION_SYNC_CACHE_FIELD];
|
||||
if (!cache || typeof cache !== 'object' || Array.isArray(cache)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cache.version !== EXPRESSION_SYNC_CACHE_VERSION) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return cache;
|
||||
function isThoughtBasedExpressionsCache(candidate) {
|
||||
return !!(
|
||||
candidate
|
||||
&& typeof candidate === 'object'
|
||||
&& !Array.isArray(candidate)
|
||||
&& candidate.version === THOUGHT_BASED_EXPRESSIONS_CACHE_VERSION
|
||||
&& candidate.entries
|
||||
&& typeof candidate.entries === 'object'
|
||||
&& !Array.isArray(candidate.entries)
|
||||
);
|
||||
}
|
||||
|
||||
function areExpressionSyncCachesEqual(left, right) {
|
||||
function getSwipeThoughtBasedExpressionsCache(sourceInfo) {
|
||||
const directCache = sourceInfo?.swipeData?.[THOUGHT_BASED_EXPRESSIONS_CACHE_FIELD];
|
||||
return isThoughtBasedExpressionsCache(directCache) ? directCache : null;
|
||||
}
|
||||
|
||||
function areThoughtBasedExpressionsCachesEqual(left, right) {
|
||||
return stableStringify(left) === stableStringify(right);
|
||||
}
|
||||
|
||||
function getThoughtSyncEntries(characterThoughtsData) {
|
||||
function getThoughtBasedExpressionEntries(characterThoughtsData) {
|
||||
const thoughtsConfig = extensionSettings.trackerConfig?.presentCharacters?.thoughts;
|
||||
if (thoughtsConfig?.enabled === false) {
|
||||
return [];
|
||||
@@ -278,7 +282,7 @@ function getThoughtSyncEntries(characterThoughtsData) {
|
||||
.filter(character => character.name && character.thought && !OFF_SCENE_THOUGHT_PATTERN.test(character.thought));
|
||||
}
|
||||
|
||||
function buildSyncSignature(thoughtEntries, expressionsSettingsSignature) {
|
||||
function buildRefreshSignature(thoughtEntries, expressionsSettingsSignature) {
|
||||
return JSON.stringify({
|
||||
expressionsSettingsSignature,
|
||||
thoughtEntries: thoughtEntries.map(entry => ({
|
||||
@@ -289,53 +293,53 @@ function buildSyncSignature(thoughtEntries, expressionsSettingsSignature) {
|
||||
});
|
||||
}
|
||||
|
||||
async function syncExpressionsFromThoughts({ force = false } = {}) {
|
||||
syncNativeExpressionDisplayVisibility();
|
||||
async function refreshThoughtBasedExpressions({ force = false } = {}) {
|
||||
updateNativeExpressionDisplayVisibility();
|
||||
|
||||
if (!extensionSettings.enabled) {
|
||||
showNativeExpressionDisplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shouldSyncExpressionPortraits()) {
|
||||
if (!shouldUseThoughtBasedExpressions()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isExpressionsExtensionEnabled()) {
|
||||
lastCompletedSyncSignature = null;
|
||||
lastExpressionsSettingsSignature = null;
|
||||
lastCompletedRefreshSignature = null;
|
||||
lastExpressionSettingsSignature = null;
|
||||
clearExpressionsCompatibilityCache();
|
||||
const portraitsChanged = applySyncedExpressionPortraits({});
|
||||
const portraitsChanged = applyThoughtBasedExpressionPortraits({});
|
||||
if (portraitsChanged) {
|
||||
saveChatData();
|
||||
}
|
||||
refreshExpressionConsumers();
|
||||
notifyThoughtBasedExpressionsConsumers();
|
||||
return;
|
||||
}
|
||||
|
||||
const expressionsSettingsSignature = getExpressionsSettingsSignature();
|
||||
if (expressionsSettingsSignature !== lastExpressionsSettingsSignature) {
|
||||
if (expressionsSettingsSignature !== lastExpressionSettingsSignature) {
|
||||
clearExpressionsCompatibilityCache();
|
||||
lastExpressionsSettingsSignature = expressionsSettingsSignature;
|
||||
lastCompletedSyncSignature = null;
|
||||
lastExpressionSettingsSignature = expressionsSettingsSignature;
|
||||
lastCompletedRefreshSignature = null;
|
||||
}
|
||||
|
||||
const characterThoughtsData = getPresentCharactersTrackerData({ useCommittedFallback: true });
|
||||
const thoughtEntries = getThoughtSyncEntries(characterThoughtsData);
|
||||
const syncSignature = buildSyncSignature(thoughtEntries, expressionsSettingsSignature);
|
||||
if (!force && syncSignature === lastCompletedSyncSignature) {
|
||||
const thoughtEntries = getThoughtBasedExpressionEntries(characterThoughtsData);
|
||||
const refreshSignature = buildRefreshSignature(thoughtEntries, expressionsSettingsSignature);
|
||||
if (!force && refreshSignature === lastCompletedRefreshSignature) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sourceInfo = findThoughtSourceMessageInfo(characterThoughtsData);
|
||||
const cachedSyncData = getSwipeExpressionSyncCache(sourceInfo);
|
||||
const cachedEntries = cachedSyncData?.entries && typeof cachedSyncData.entries === 'object' && !Array.isArray(cachedSyncData.entries)
|
||||
? cachedSyncData.entries
|
||||
const cachedThoughtBasedExpressions = getSwipeThoughtBasedExpressionsCache(sourceInfo);
|
||||
const cachedEntries = cachedThoughtBasedExpressions?.entries && typeof cachedThoughtBasedExpressions.entries === 'object' && !Array.isArray(cachedThoughtBasedExpressions.entries)
|
||||
? cachedThoughtBasedExpressions.entries
|
||||
: {};
|
||||
const currentThoughtsSignature = normalizeThoughtPayload(characterThoughtsData);
|
||||
const classificationSettingsSignature = getExpressionClassificationSettingsSignature();
|
||||
const portraitSettingsSignature = getExpressionPortraitSettingsSignature();
|
||||
const runId = ++activeSyncRunId;
|
||||
const runId = ++activeRefreshRunId;
|
||||
const nextPortraits = {};
|
||||
const nextCacheEntries = {};
|
||||
|
||||
@@ -349,7 +353,7 @@ async function syncExpressionsFromThoughts({ force = false } = {}) {
|
||||
const cachedEntry = cachedEntries[portraitKey] && typeof cachedEntries[portraitKey] === 'object'
|
||||
? cachedEntries[portraitKey]
|
||||
: null;
|
||||
const previousSrc = nextPortraits[portraitKey] || syncedExpressionPortraits[portraitKey] || null;
|
||||
const previousSrc = nextPortraits[portraitKey] || thoughtBasedExpressionPortraits[portraitKey] || null;
|
||||
const canReuseExpression = cachedEntry
|
||||
&& cachedEntry.thought === entry.thought
|
||||
&& cachedEntry.classificationSettingsSignature === classificationSettingsSignature
|
||||
@@ -359,7 +363,7 @@ async function syncExpressionsFromThoughts({ force = false } = {}) {
|
||||
const expression = canReuseExpression
|
||||
? normalizeExpressionLabel(cachedEntry.expression)
|
||||
: normalizeExpressionLabel(await classifyExpressionText(entry.thought, { characterName: entry.name }));
|
||||
if (runId !== activeSyncRunId) {
|
||||
if (runId !== activeRefreshRunId) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -371,13 +375,13 @@ async function syncExpressionsFromThoughts({ force = false } = {}) {
|
||||
&& cachedEntry.portraitResolved === true;
|
||||
|
||||
const portraitSrc = canReusePortrait
|
||||
? (isUsableExpressionSrc(cachedEntry.portraitSrc) ? cachedEntry.portraitSrc : null)
|
||||
? (isUsableThoughtBasedExpressionSrc(cachedEntry.portraitSrc) ? cachedEntry.portraitSrc : null)
|
||||
: await resolveExpressionPortraitForCharacter(entry.name, expression, { previousSrc });
|
||||
if (runId !== activeSyncRunId) {
|
||||
if (runId !== activeRefreshRunId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUsableExpressionSrc(portraitSrc)) {
|
||||
if (isUsableThoughtBasedExpressionSrc(portraitSrc)) {
|
||||
nextPortraits[portraitKey] = portraitSrc;
|
||||
}
|
||||
|
||||
@@ -388,159 +392,159 @@ async function syncExpressionsFromThoughts({ force = false } = {}) {
|
||||
classificationSettingsSignature,
|
||||
portraitSettingsSignature,
|
||||
expression,
|
||||
portraitSrc: isUsableExpressionSrc(portraitSrc) ? portraitSrc : null,
|
||||
portraitSrc: isUsableThoughtBasedExpressionSrc(portraitSrc) ? portraitSrc : null,
|
||||
portraitResolved: true
|
||||
};
|
||||
}
|
||||
|
||||
if (runId !== activeSyncRunId) {
|
||||
if (runId !== activeRefreshRunId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cacheChanged = false;
|
||||
if (sourceInfo) {
|
||||
const nextCache = {
|
||||
version: EXPRESSION_SYNC_CACHE_VERSION,
|
||||
version: THOUGHT_BASED_EXPRESSIONS_CACHE_VERSION,
|
||||
thoughtsSignature: currentThoughtsSignature,
|
||||
entries: nextCacheEntries
|
||||
};
|
||||
|
||||
if (!areExpressionSyncCachesEqual(cachedSyncData, nextCache)) {
|
||||
setMessageSwipeTrackerField(sourceInfo.message, sourceInfo.swipeId, EXPRESSION_SYNC_CACHE_FIELD, nextCache);
|
||||
if (!areThoughtBasedExpressionsCachesEqual(cachedThoughtBasedExpressions, nextCache)) {
|
||||
setMessageSwipeTrackerField(sourceInfo.message, sourceInfo.swipeId, THOUGHT_BASED_EXPRESSIONS_CACHE_FIELD, nextCache);
|
||||
cacheChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
lastCompletedSyncSignature = syncSignature;
|
||||
const portraitsChanged = applySyncedExpressionPortraits(nextPortraits);
|
||||
lastCompletedRefreshSignature = refreshSignature;
|
||||
const portraitsChanged = applyThoughtBasedExpressionPortraits(nextPortraits);
|
||||
if (portraitsChanged || cacheChanged) {
|
||||
saveChatData();
|
||||
}
|
||||
if (portraitsChanged) {
|
||||
refreshExpressionConsumers();
|
||||
notifyThoughtBasedExpressionsConsumers();
|
||||
}
|
||||
}
|
||||
|
||||
export function setExpressionSyncRefreshHandler(handler) {
|
||||
refreshExpressionConsumersHandler = typeof handler === 'function' ? handler : null;
|
||||
export function setThoughtBasedExpressionsRefreshHandler(handler) {
|
||||
thoughtBasedExpressionsRefreshHandler = typeof handler === 'function' ? handler : null;
|
||||
}
|
||||
|
||||
export function queueExpressionSyncFromThoughts({ immediate = false, force = false } = {}) {
|
||||
clearScheduledSync();
|
||||
export function queueThoughtBasedExpressionsUpdate({ immediate = false, force = false } = {}) {
|
||||
clearScheduledRefresh();
|
||||
|
||||
const runSync = () => {
|
||||
syncExpressionsFromThoughts({ force }).catch(error => {
|
||||
console.warn('[RPG Companion] Thoughts-driven expression sync failed:', error);
|
||||
const runRefresh = () => {
|
||||
refreshThoughtBasedExpressions({ force }).catch(error => {
|
||||
console.warn('[RPG Companion] Thought-based expressions update failed:', error);
|
||||
});
|
||||
};
|
||||
|
||||
if (immediate) {
|
||||
runSync();
|
||||
runRefresh();
|
||||
return;
|
||||
}
|
||||
|
||||
scheduledSyncTimer = setTimeout(() => {
|
||||
scheduledSyncTimer = null;
|
||||
runSync();
|
||||
}, SYNC_DEBOUNCE_DELAY);
|
||||
scheduledRefreshTimer = setTimeout(() => {
|
||||
scheduledRefreshTimer = null;
|
||||
runRefresh();
|
||||
}, REFRESH_DEBOUNCE_DELAY);
|
||||
}
|
||||
|
||||
export function initExpressionSync() {
|
||||
const purged = purgeInvalidSyncedExpressionPortraits();
|
||||
syncNativeExpressionDisplayVisibility();
|
||||
export function initThoughtBasedExpressions() {
|
||||
const purged = purgeInvalidThoughtBasedExpressionPortraits();
|
||||
updateNativeExpressionDisplayVisibility();
|
||||
|
||||
if (purged) {
|
||||
saveChatData();
|
||||
refreshExpressionConsumers();
|
||||
notifyThoughtBasedExpressionsConsumers();
|
||||
}
|
||||
|
||||
if (shouldSyncExpressionPortraits()) {
|
||||
queueExpressionSyncFromThoughts({ immediate: true, force: true });
|
||||
if (shouldUseThoughtBasedExpressions()) {
|
||||
queueThoughtBasedExpressionsUpdate({ immediate: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
export function onExpressionSyncChatChanged() {
|
||||
export function onThoughtBasedExpressionsChatChanged() {
|
||||
if (!extensionSettings.enabled) {
|
||||
showNativeExpressionDisplay();
|
||||
return;
|
||||
}
|
||||
|
||||
clearScheduledSync();
|
||||
activeSyncRunId += 1;
|
||||
lastCompletedSyncSignature = null;
|
||||
lastExpressionsSettingsSignature = null;
|
||||
clearScheduledRefresh();
|
||||
activeRefreshRunId += 1;
|
||||
lastCompletedRefreshSignature = null;
|
||||
lastExpressionSettingsSignature = null;
|
||||
clearExpressionsCompatibilityCache();
|
||||
|
||||
const purged = purgeInvalidSyncedExpressionPortraits();
|
||||
const purged = purgeInvalidThoughtBasedExpressionPortraits();
|
||||
if (purged) {
|
||||
saveChatData();
|
||||
refreshExpressionConsumers();
|
||||
notifyThoughtBasedExpressionsConsumers();
|
||||
}
|
||||
|
||||
for (const delay of CHAT_CHANGE_RETRY_DELAYS) {
|
||||
setTimeout(() => {
|
||||
syncNativeExpressionDisplayVisibility();
|
||||
if (shouldSyncExpressionPortraits()) {
|
||||
queueExpressionSyncFromThoughts({ immediate: true, force: true });
|
||||
updateNativeExpressionDisplayVisibility();
|
||||
if (shouldUseThoughtBasedExpressions()) {
|
||||
queueThoughtBasedExpressionsUpdate({ immediate: true, force: true });
|
||||
} else {
|
||||
refreshExpressionConsumers();
|
||||
notifyThoughtBasedExpressionsConsumers();
|
||||
}
|
||||
}, delay);
|
||||
}
|
||||
}
|
||||
|
||||
export function onExpressionSyncSettingChanged(enabled) {
|
||||
syncNativeExpressionDisplayVisibility();
|
||||
export function onThoughtBasedExpressionsSettingChanged(enabled) {
|
||||
updateNativeExpressionDisplayVisibility();
|
||||
|
||||
if (enabled) {
|
||||
const purged = purgeInvalidSyncedExpressionPortraits();
|
||||
const purged = purgeInvalidThoughtBasedExpressionPortraits();
|
||||
if (purged) {
|
||||
saveChatData();
|
||||
refreshExpressionConsumers();
|
||||
notifyThoughtBasedExpressionsConsumers();
|
||||
}
|
||||
|
||||
if (shouldSyncExpressionPortraits()) {
|
||||
queueExpressionSyncFromThoughts({ immediate: true, force: true });
|
||||
if (shouldUseThoughtBasedExpressions()) {
|
||||
queueThoughtBasedExpressionsUpdate({ immediate: true, force: true });
|
||||
} else {
|
||||
refreshExpressionConsumers();
|
||||
notifyThoughtBasedExpressionsConsumers();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
clearScheduledSync();
|
||||
activeSyncRunId += 1;
|
||||
lastCompletedSyncSignature = null;
|
||||
lastExpressionsSettingsSignature = null;
|
||||
clearScheduledRefresh();
|
||||
activeRefreshRunId += 1;
|
||||
lastCompletedRefreshSignature = null;
|
||||
lastExpressionSettingsSignature = null;
|
||||
clearExpressionsCompatibilityCache();
|
||||
refreshExpressionConsumers();
|
||||
notifyThoughtBasedExpressionsConsumers();
|
||||
}
|
||||
|
||||
export function onAlternatePresentCharactersVisibilityChanged() {
|
||||
syncNativeExpressionDisplayVisibility();
|
||||
updateNativeExpressionDisplayVisibility();
|
||||
|
||||
if (shouldSyncExpressionPortraits()) {
|
||||
queueExpressionSyncFromThoughts({ immediate: true, force: true });
|
||||
if (shouldUseThoughtBasedExpressions()) {
|
||||
queueThoughtBasedExpressionsUpdate({ immediate: true, force: true });
|
||||
return;
|
||||
}
|
||||
|
||||
clearScheduledSync();
|
||||
activeSyncRunId += 1;
|
||||
lastCompletedSyncSignature = null;
|
||||
lastExpressionsSettingsSignature = null;
|
||||
clearScheduledRefresh();
|
||||
activeRefreshRunId += 1;
|
||||
lastCompletedRefreshSignature = null;
|
||||
lastExpressionSettingsSignature = null;
|
||||
}
|
||||
|
||||
export function onHideDefaultExpressionDisplaySettingChanged(enabled) {
|
||||
extensionSettings.hideDefaultExpressionDisplay = enabled === true;
|
||||
syncNativeExpressionDisplayVisibility();
|
||||
setTimeout(() => syncNativeExpressionDisplayVisibility(), 0);
|
||||
setTimeout(() => syncNativeExpressionDisplayVisibility(), 120);
|
||||
updateNativeExpressionDisplayVisibility();
|
||||
setTimeout(() => updateNativeExpressionDisplayVisibility(), 0);
|
||||
setTimeout(() => updateNativeExpressionDisplayVisibility(), 120);
|
||||
}
|
||||
|
||||
export function clearExpressionSyncCache() {
|
||||
clearScheduledSync();
|
||||
activeSyncRunId += 1;
|
||||
lastCompletedSyncSignature = null;
|
||||
lastExpressionsSettingsSignature = null;
|
||||
export function clearThoughtBasedExpressionsCache() {
|
||||
clearScheduledRefresh();
|
||||
activeRefreshRunId += 1;
|
||||
lastCompletedRefreshSignature = null;
|
||||
lastExpressionSettingsSignature = null;
|
||||
clearExpressionsCompatibilityCache();
|
||||
showNativeExpressionDisplay();
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
} from '../../utils/presentCharacters.js';
|
||||
import { isItemLocked, setItemLock } from '../generation/lockManager.js';
|
||||
import { renderAlternatePresentCharacters } from '../ui/alternatePresentCharacters.js';
|
||||
import { queueExpressionSyncFromThoughts } from '../integration/expressionSync.js';
|
||||
import { queueThoughtBasedExpressionsUpdate } from '../integration/thoughtBasedExpressions.js';
|
||||
|
||||
/**
|
||||
* Helper to generate lock icon HTML if setting is enabled
|
||||
@@ -93,7 +93,7 @@ function getStatColor(percentage, lowColor, highColor, lowOpacity = 100, highOpa
|
||||
*/
|
||||
export function renderThoughts({ preserveScroll = false, useCommittedFallback = true } = {}) {
|
||||
renderAlternatePresentCharacters({ useCommittedFallback });
|
||||
queueExpressionSyncFromThoughts();
|
||||
queueThoughtBasedExpressionsUpdate();
|
||||
|
||||
if (!extensionSettings.showCharacterThoughts || !$thoughtsContainer) {
|
||||
return;
|
||||
@@ -1284,7 +1284,7 @@ export function updateCharacterField(characterName, field, value) {
|
||||
// console.log('[RPG Companion] After update - lastGeneratedData.characterThoughts:', lastGeneratedData.characterThoughts);
|
||||
|
||||
if (field === 'name' || isEditingThoughts) {
|
||||
queueExpressionSyncFromThoughts({ immediate: true, force: true });
|
||||
queueThoughtBasedExpressionsUpdate({ immediate: true, force: true });
|
||||
}
|
||||
|
||||
if (isEditingThoughts && extensionSettings.showThoughtsInChat) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { extensionSettings } from '../../core/state.js';
|
||||
import { i18n } from '../../core/i18n.js';
|
||||
import { getExpressionPortraitForCharacter } from '../../utils/expressionPortraits.js';
|
||||
import { getThoughtBasedExpressionPortraitForCharacter } from '../../utils/thoughtBasedExpressionPortraits.js';
|
||||
import { getSafeImageSrc } from '../../utils/imageUrls.js';
|
||||
import {
|
||||
getPresentCharactersTrackerData,
|
||||
@@ -49,8 +49,8 @@ function handlePortraitLoadError() {
|
||||
}
|
||||
|
||||
function createAlternatePresentCharacterCard(character) {
|
||||
const rawPortrait = (extensionSettings.syncExpressionsToPresentCharacters
|
||||
? getExpressionPortraitForCharacter(character.name)
|
||||
const rawPortrait = (extensionSettings.enableThoughtBasedExpressions
|
||||
? getThoughtBasedExpressionPortraitForCharacter(character.name)
|
||||
: null) || resolvePresentCharacterPortrait(character.name);
|
||||
const portrait = getSafeImageSrc(rawPortrait);
|
||||
const name = String(character.name || '');
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
$infoBoxContainer,
|
||||
$thoughtsContainer,
|
||||
$userStatsContainer,
|
||||
clearSyncedExpressionPortraits,
|
||||
clearThoughtBasedExpressionPortraits,
|
||||
setPendingDiceRoll,
|
||||
getPendingDiceRoll,
|
||||
clearSessionAvatarPrompts
|
||||
@@ -371,7 +371,7 @@ export function setupSettingsPopup() {
|
||||
|
||||
// Clear session avatar prompts
|
||||
clearSessionAvatarPrompts();
|
||||
clearSyncedExpressionPortraits();
|
||||
clearThoughtBasedExpressionPortraits();
|
||||
|
||||
// Clear chat metadata immediately (don't wait for debounced save)
|
||||
const context = getContext();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {
|
||||
syncedExpressionPortraits,
|
||||
getSyncedExpressionPortrait
|
||||
thoughtBasedExpressionPortraits,
|
||||
getThoughtBasedExpressionPortrait
|
||||
} from '../core/state.js';
|
||||
import {
|
||||
isSafeImageSrc,
|
||||
@@ -35,7 +35,7 @@ function isDocumentLikeUrl(src) {
|
||||
&& candidate.search === current.search;
|
||||
}
|
||||
|
||||
export function isUsableExpressionSrc(src) {
|
||||
export function isUsableThoughtBasedExpressionSrc(src) {
|
||||
const normalized = normalizeImageSrc(src);
|
||||
if (!normalized) {
|
||||
return false;
|
||||
@@ -48,7 +48,7 @@ export function isUsableExpressionSrc(src) {
|
||||
return isSafeImageSrc(normalized);
|
||||
}
|
||||
|
||||
export function getExpressionPortraitForCharacter(characterName) {
|
||||
export function getThoughtBasedExpressionPortraitForCharacter(characterName) {
|
||||
if (!isExpressionsExtensionEnabled()) {
|
||||
return null;
|
||||
}
|
||||
@@ -58,13 +58,13 @@ export function getExpressionPortraitForCharacter(characterName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const exact = getSyncedExpressionPortrait(target);
|
||||
if (isUsableExpressionSrc(exact)) {
|
||||
const exact = getThoughtBasedExpressionPortrait(target);
|
||||
if (isUsableThoughtBasedExpressionSrc(exact)) {
|
||||
return exact;
|
||||
}
|
||||
|
||||
for (const [storedName, src] of Object.entries(syncedExpressionPortraits)) {
|
||||
if (namesMatch(storedName, target) && isUsableExpressionSrc(src)) {
|
||||
for (const [storedName, src] of Object.entries(thoughtBasedExpressionPortraits)) {
|
||||
if (namesMatch(storedName, target) && isUsableThoughtBasedExpressionSrc(src)) {
|
||||
return src;
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -368,12 +368,12 @@
|
||||
</small>
|
||||
|
||||
<label class="checkbox_label">
|
||||
<input type="checkbox" id="rpg-toggle-sync-expressions" />
|
||||
<span data-i18n-key="template.settingsModal.display.syncBelowChatPresentCharactersExpressions">Sync Expressions in Below-Chat Panel</span>
|
||||
<input type="checkbox" id="rpg-toggle-thought-based-expressions" />
|
||||
<span data-i18n-key="template.settingsModal.display.thoughtBasedExpressions">Thought-Based Expressions</span>
|
||||
</label>
|
||||
<small style="display: block; margin-left: 24px; margin-top: -8px; color: #888; font-size: 11px;"
|
||||
data-i18n-key="template.settingsModal.display.syncBelowChatPresentCharactersExpressionsNote">
|
||||
Use each character's current SillyTavern expression portrait in the below-chat Present Characters panel.
|
||||
data-i18n-key="template.settingsModal.display.thoughtBasedExpressionsNote">
|
||||
Use SillyTavern Character Expressions to classify each present character's thoughts for the below-chat panel. May increase token usage depending on the selected Classifier API.
|
||||
</small>
|
||||
|
||||
<label class="checkbox_label">
|
||||
|
||||
Reference in New Issue
Block a user