Update /ask with new char find functionality

d6e52dbb9727ff67ec7d52b664b17efcb363c208

Wolfsblvt <wolfsblvt@gmail.com>

1 files changed, +65 -41Showing whitespace changes
public/scripts/slash-commands.js+65 -41
@@ -247,7 +247,7 @@ export function initDefaultSlashCommands() {
247 namedArgumentList: [247 namedArgumentList: [
248 SlashCommandNamedArgument.fromProps({248 SlashCommandNamedArgument.fromProps({
249 name: 'name',249 name: 'name',
250 description: 'Character name',250 description: 'Character name - or unique character identifier (avatar key)',
251 typeList: [ARGUMENT_TYPE.STRING],251 typeList: [ARGUMENT_TYPE.STRING],
252 isRequired: true,252 isRequired: true,
253 enumProvider: commonEnumProviders.characters('character'),253 enumProvider: commonEnumProviders.characters('character'),
@@ -255,7 +255,7 @@ export function initDefaultSlashCommands() {
255 }),255 }),
256 SlashCommandNamedArgument.fromProps({256 SlashCommandNamedArgument.fromProps({
257 name: 'avatar',257 name: 'avatar',
258 description: 'Character avatar override (Can be either avatar filename or just the character name to pull the avatar from)',258 description: 'Character avatar override (Can be either avatar key or just the character name to pull the avatar from)',
259 typeList: [ARGUMENT_TYPE.STRING],259 typeList: [ARGUMENT_TYPE.STRING],
260 enumProvider: commonEnumProviders.characters('character'),260 enumProvider: commonEnumProviders.characters('character'),
261 }),261 }),
@@ -288,6 +288,9 @@ export function initDefaultSlashCommands() {
288 <pre><code>/sendas name="Chloe" Hello, guys!</code></pre>288 <pre><code>/sendas name="Chloe" Hello, guys!</code></pre>
289 will send "Hello, guys!" from "Chloe".289 will send "Hello, guys!" from "Chloe".
290 </li>290 </li>
291 <li>
292 <pre><code>/sendas name="Chloe" avatar="BigBadBoss" Hehehe, I am the big bad evil, fear me.</code></pre>
293 will send a message as the character "Chloe", but utilizing the avatar from a character named "BigBadBoss".
291 </ul>294 </ul>
292 </div>295 </div>
293 <div>296 <div>
@@ -509,7 +512,7 @@ export function initDefaultSlashCommands() {
509 namedArgumentList: [512 namedArgumentList: [
510 SlashCommandNamedArgument.fromProps({513 SlashCommandNamedArgument.fromProps({
511 name: 'name',514 name: 'name',
512 description: 'character name',515 description: 'Character name - or unique character identifier (avatar key)',
513 typeList: [ARGUMENT_TYPE.STRING],516 typeList: [ARGUMENT_TYPE.STRING],
514 isRequired: true,517 isRequired: true,
515 enumProvider: commonEnumProviders.characters('character'),518 enumProvider: commonEnumProviders.characters('character'),
@@ -2558,26 +2561,22 @@ async function askCharacter(args, text) {
2558 return '';2561 return '';
2559 }2562 }
25602563
2561 let name = '';2564 if (!args.name) {
2562
2563 if (args?.name) {
2564 name = args.name.trim();
2565
2566 if (!name) {
2567 toastr.warning('You must specify a name of the character to ask.');2565 toastr.warning('You must specify a name of the character to ask.');
2568 return '';2566 return '';
2569 }2567 }
2570 }
25712568
2572 const prevChId = this_chid;2569 const prevChId = this_chid;
25732570
2574 // Find the character2571 // Find the character
2575 const chId = characters.findIndex((e) => e.name === name || e.avatar === name);2572 const character = findChar({ name: args?.name });
2576 if (!characters[chId] || chId === -1) {2573 if (!character) {
2577 toastr.error('Character not found.');2574 toastr.error('Character not found.');
2578 return '';2575 return '';
2579 }2576 }
25802577
2578 const chId = getCharIndex(character);
2579
2581 if (text) {2580 if (text) {
2582 const mesText = getRegexedString(text.trim(), regex_placement.SLASH_COMMAND);2581 const mesText = getRegexedString(text.trim(), regex_placement.SLASH_COMMAND);
2583 // Sending a message implicitly saves the chat, so this needs to be done before changing the character2582 // Sending a message implicitly saves the chat, so this needs to be done before changing the character
@@ -2588,19 +2587,9 @@ async function askCharacter(args, text) {
2588 // Override character and send a user message2587 // Override character and send a user message
2589 setCharacterId(String(chId));2588 setCharacterId(String(chId));
25902589
2591 const character = characters[chId];2590 const { name, force_avatar, original_avatar } = getNameAndAvatarForMessage(character, args?.name);
2592 let force_avatar, original_avatar;
25932591
2594 if (character && character.avatar !== 'none') {2592 setCharacterName(name);
2595 force_avatar = getThumbnailUrl('avatar', character.avatar);
2596 original_avatar = character.avatar;
2597 }
2598 else {
2599 force_avatar = default_avatar;
2600 original_avatar = default_avatar;
2601 }
2602
2603 setCharacterName(character.name);
26042593
2605 const restoreCharacter = () => {2594 const restoreCharacter = () => {
2606 if (String(this_chid) !== String(chId)) {2595 if (String(this_chid) !== String(chId)) {
@@ -2613,7 +2602,7 @@ async function askCharacter(args, text) {
2613 // Only force the new avatar if the character name is the same2602 // Only force the new avatar if the character name is the same
2614 // This skips if an error was fired2603 // This skips if an error was fired
2615 const lastMessage = chat[chat.length - 1];2604 const lastMessage = chat[chat.length - 1];
2616 if (lastMessage && lastMessage?.name === character.name) {2605 if (lastMessage && lastMessage?.name === name) {
2617 lastMessage.force_avatar = force_avatar;2606 lastMessage.force_avatar = force_avatar;
2618 lastMessage.original_avatar = original_avatar;2607 lastMessage.original_avatar = original_avatar;
2619 }2608 }
@@ -2624,7 +2613,7 @@ async function askCharacter(args, text) {
2624 // Run generate and restore previous character2613 // Run generate and restore previous character
2625 try {2614 try {
2626 eventSource.once(event_types.MESSAGE_RECEIVED, restoreCharacter);2615 eventSource.once(event_types.MESSAGE_RECEIVED, restoreCharacter);
2627 toastr.info(`Asking ${character.name} something...`);2616 toastr.info(`Asking ${name} something...`);
2628 askResult = await Generate('ask_command');2617 askResult = await Generate('ask_command');
2629 } catch (error) {2618 } catch (error) {
2630 restoreCharacter();2619 restoreCharacter();
@@ -3215,6 +3204,41 @@ export function validateArrayArg(arg, name, { allowUndefined = true } = {}) {
3215 return arg;3204 return arg;
3216}3205}
32173206
3207
3208/**
3209 * Retrieves the name and avatar information for a message
3210 *
3211 * The name of the character will always have precendence over the one given as argument. If you want to specify a different name for the message,
3212 * explicitly implement this in the code using this.
3213 *
3214 * @param {object?} character - The character object to get the avatar data for
3215 * @param {string?} name - The name to get the avatar data for
3216 * @returns {{name: string, force_avatar: string, original_avatar: string}} An object containing the name for the message, forced avatar URL, and original avatar
3217 */
3218export function getNameAndAvatarForMessage(character, name = null) {
3219 const isNeutralCharacter = !character && name2 === neutralCharacterName && name === neutralCharacterName;
3220 const currentChar = characters[this_chid];
3221
3222 let force_avatar, original_avatar;
3223 if (character?.avatar === currentChar?.avatar || isNeutralCharacter) {
3224 // If the targeted character is the currently selected one in a solo chat, we don't need to force any avatars
3225 }
3226 else if (character && character.avatar !== 'none') {
3227 force_avatar = getThumbnailUrl('avatar', character.avatar);
3228 original_avatar = character.avatar;
3229 }
3230 else {
3231 force_avatar = default_avatar;
3232 original_avatar = default_avatar;
3233 }
3234
3235 return {
3236 name: character?.name || name,
3237 force_avatar: force_avatar,
3238 original_avatar: original_avatar,
3239 };
3240}
3241
3218/**3242/**
3219 * Finds a character by name, with optional filtering and precedence for avatars3243 * Finds a character by name, with optional filtering and precedence for avatars
3220 * @param {object} [options={}] - The options for the search3244 * @param {object} [options={}] - The options for the search
@@ -3273,6 +3297,19 @@ export function findChar({ name = null, allowAvatar = true, insensitive = true,
3273 return matchingCharacters[0] || null;3297 return matchingCharacters[0] || null;
3274}3298}
32753299
3300/**
3301 * Gets the index of a character based on the character object
3302 * @param {object} char - The character object to find the index for
3303 * @throws {Error} If the character is not found
3304 * @returns {number} The index of the character in the characters array
3305 */
3306export function getCharIndex(char) {
3307 if (!char) throw new Error('Character is undefined');
3308 const index = characters.findIndex(c => c.avatar === char.avatar);
3309 if (index === -1) throw new Error(`Character not found: ${char.avatar}`);
3310 return index;
3311}
3312
3276export async function sendMessageAs(args, text) {3313export async function sendMessageAs(args, text) {
3277 if (!text) {3314 if (!text) {
3278 return '';3315 return '';
@@ -3319,23 +3356,10 @@ export async function sendMessageAs(args, text) {
3319 return '';3356 return '';
3320 }3357 }
33213358
3322 const isNeutralCharacter = !character && name2 === neutralCharacterName && name === neutralCharacterName;3359 const { name: nameForMessage, force_avatar, original_avatar } = getNameAndAvatarForMessage(avatarCharacter, name);
3323
3324 let force_avatar, original_avatar;
3325 if (character === avatarCharacter || isNeutralCharacter) {
3326 // If the targeted character is the currently selected one in a solo chat, we don't need to force any avatars
3327 }
3328 else if (avatarCharacter && avatarCharacter.avatar !== 'none') {
3329 force_avatar = getThumbnailUrl('avatar', avatarCharacter.avatar);
3330 original_avatar = avatarCharacter.avatar;
3331 }
3332 else {
3333 force_avatar = default_avatar;
3334 original_avatar = default_avatar;
3335 }
33363360
3337 const message = {3361 const message = {
3338 name: character?.name || name,3362 name: nameForMessage,
3339 is_user: false,3363 is_user: false,
3340 is_system: isSystem,3364 is_system: isSystem,
3341 send_date: getMessageTimeStamp(),3365 send_date: getMessageTimeStamp(),