Validate story string about missing fields (#2462) * Validate story string about missing fields * Update validation to only warn once * Improve story string validation log once --------- Co-authored-by: Cohee <18619528+Cohee1207@users.noreply.github.com>

8159b7f5f44a33f9dde5666327561ba0062f3c88

Wolfsblvt <wolfsblvt@gmail.com>

Signed
1 files changed, +55 -1Ignore whitespace
public/scripts/power-user.js+55 -1
@@ -40,7 +40,7 @@ import { tokenizers } from './tokenizers.js';
40import { BIAS_CACHE } from './logit-bias.js';40import { BIAS_CACHE } from './logit-bias.js';
41import { renderTemplateAsync } from './templates.js';41import { renderTemplateAsync } from './templates.js';
4242
43import { countOccurrences, debounce, delay, download, getFileText, isOdd, isTrueBoolean, onlyUnique, resetScrollHeight, shuffle, sortMoments, stringToRange, timestampToMoment } from './utils.js';43import { countOccurrences, debounce, delay, download, getFileText, getStringHash, isOdd, isTrueBoolean, onlyUnique, resetScrollHeight, shuffle, sortMoments, stringToRange, timestampToMoment } from './utils.js';
44import { FILTER_TYPES } from './filters.js';44import { FILTER_TYPES } from './filters.js';
45import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js';45import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js';
46import { SlashCommand } from './slash-commands/SlashCommand.js';46import { SlashCommand } from './slash-commands/SlashCommand.js';
@@ -335,6 +335,8 @@ const storage_keys = {
335 compact_input_area: 'compact_input_area',335 compact_input_area: 'compact_input_area',
336 auto_connect_legacy: 'AutoConnectEnabled',336 auto_connect_legacy: 'AutoConnectEnabled',
337 auto_load_chat_legacy: 'AutoLoadChatEnabled',337 auto_load_chat_legacy: 'AutoLoadChatEnabled',
338
339 storyStringValidationCache: 'StoryStringValidationCache',
338};340};
339341
340const contextControls = [342const contextControls = [
@@ -2105,6 +2107,9 @@ export function fuzzySearchGroups(searchValue) {
2105 */2107 */
2106export function renderStoryString(params) {2108export function renderStoryString(params) {
2107 try {2109 try {
2110 // Validate and log possible warnings/errors
2111 validateStoryString(power_user.context.story_string, params);
2112
2108 // compile the story string template into a function, with no HTML escaping2113 // compile the story string template into a function, with no HTML escaping
2109 const compiledTemplate = Handlebars.compile(power_user.context.story_string, { noEscape: true });2114 const compiledTemplate = Handlebars.compile(power_user.context.story_string, { noEscape: true });
21102115
@@ -2132,6 +2137,55 @@ export function renderStoryString(params) {
2132 }2137 }
2133}2138}
21342139
2140/**
2141 * Validate the story string for possible warnings or issues
2142 *
2143 * @param {string} storyString - The story string
2144 * @param {Object} params - The story string parameters
2145 */
2146function validateStoryString(storyString, params) {
2147 /** @type {{hashCache: {[hash: string]: {fieldsWarned: {[key: string]: boolean}}}}} */
2148 const cache = JSON.parse(localStorage.getItem(storage_keys.storyStringValidationCache)) ?? { hashCache: {} };
2149
2150 const hash = getStringHash(storyString);
2151
2152 // Initialize the cache for the current hash if it doesn't exist
2153 if (!cache.hashCache[hash]) {
2154 cache.hashCache[hash] = { fieldsWarned: {} };
2155 }
2156
2157 const currentCache = cache.hashCache[hash];
2158 const fieldsToWarn = [];
2159
2160 function validateMissingField(field, fallbackLegacyField = null) {
2161 const contains = storyString.includes(`{{${field}}}`) || (!!fallbackLegacyField && storyString.includes(`{{${fallbackLegacyField}}}`));
2162 if (!contains && params[field]) {
2163 const wasLogged = currentCache.fieldsWarned[field];
2164 if (!wasLogged) {
2165 fieldsToWarn.push(field);
2166 currentCache.fieldsWarned[field] = true;
2167 }
2168 console.warn(`The story string does not contain {{${field}}}, but it would contain content:\n`, params[field]);
2169 }
2170 }
2171
2172 validateMissingField('description');
2173 validateMissingField('personality');
2174 validateMissingField('persona');
2175 validateMissingField('scenario');
2176 validateMissingField('system');
2177 validateMissingField('wiBefore', 'loreBefore');
2178 validateMissingField('wiAfter', 'loreAfter');
2179
2180 if (fieldsToWarn.length > 0) {
2181 const fieldsList = fieldsToWarn.map(field => `{{${field}}}`).join(', ');
2182 toastr.warning(`The story string does not contain the following fields, but they would contain content: ${fieldsList}`, 'Story String Validation');
2183 }
2184
2185 localStorage.setItem(storage_keys.storyStringValidationCache, JSON.stringify(cache));
2186}
2187
2188
2135const sortFunc = (a, b) => power_user.sort_order == 'asc' ? compareFunc(a, b) : compareFunc(b, a);2189const sortFunc = (a, b) => power_user.sort_order == 'asc' ? compareFunc(a, b) : compareFunc(b, a);
2136const compareFunc = (first, second) => {2190const compareFunc = (first, second) => {
2137 const a = first[power_user.sort_field];2191 const a = first[power_user.sort_field];