mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge remote-tracking branch 'upstream/staging' into quad-sample
This commit is contained in:
@ -148,7 +148,8 @@ body.big-avatars .avatar_collage {
|
|||||||
aspect-ratio: 2 / 3;
|
aspect-ratio: 2 / 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
body.big-avatars .ch_description {
|
body.big-avatars .ch_description,
|
||||||
|
.avatar-container .ch_description {
|
||||||
display: -webkit-box;
|
display: -webkit-box;
|
||||||
-webkit-line-clamp: 3;
|
-webkit-line-clamp: 3;
|
||||||
-webkit-box-orient: vertical;
|
-webkit-box-orient: vertical;
|
||||||
|
@ -2117,7 +2117,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-container width100p">
|
<div class="flex-container width100p">
|
||||||
<input id="openai_proxy_password" type="password" class="text_pole flex1" placeholder="" maxlength="500" form="openai_form" />
|
<input id="openai_proxy_password" type="password" class="text_pole flex1" placeholder="" maxlength="500" form="openai_form" autocomplete="off" />
|
||||||
<div id="openai_proxy_password_show" title="Peek a password" class="menu_button fa-solid fa-eye-slash fa-fw"></div>
|
<div id="openai_proxy_password_show" title="Peek a password" class="menu_button fa-solid fa-eye-slash fa-fw"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -3652,7 +3652,7 @@
|
|||||||
<div class="drawer-icon fa-solid fa-face-smile closedIcon" title="Persona Management" data-i18n="[title]Persona Management"></div>
|
<div class="drawer-icon fa-solid fa-face-smile closedIcon" title="Persona Management" data-i18n="[title]Persona Management"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="drawer-content closedDrawer">
|
<div class="drawer-content closedDrawer">
|
||||||
<div class="flex-container wide100p alignitemscenter spaceBetween">
|
<div class="flex-container wide100p alignitemscenter spaceBetween flexNoGap">
|
||||||
<div class="flex-container alignItemsBaseline wide100p">
|
<div class="flex-container alignItemsBaseline wide100p">
|
||||||
<div class="flex1 flex-container alignItemsBaseline">
|
<div class="flex1 flex-container alignItemsBaseline">
|
||||||
<h3 class="margin0" data-i18n="Persona Management">Persona Management</h3>
|
<h3 class="margin0" data-i18n="Persona Management">Persona Management</h3>
|
||||||
@ -3673,14 +3673,27 @@
|
|||||||
<i class="fa-solid fa-file-import"></i>
|
<i class="fa-solid fa-file-import"></i>
|
||||||
<span data-i18n="Restore">Restore</span>
|
<span data-i18n="Restore">Restore</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="create_dummy_persona" class="menu_button menu_button_icon" title="Create a dummy persona" data-i18n="[title]Create a dummy persona">
|
|
||||||
<i class="fa-solid fa-person-circle-question fa-fw"></i>
|
|
||||||
<span data-i18n="Create">Create</span>
|
|
||||||
</div>
|
|
||||||
<input id="personas_restore_input" type="file" accept=".json" hidden>
|
<input id="personas_restore_input" type="file" accept=".json" hidden>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="persona-management-block" class="flex-container wide100p">
|
<div id="persona-management-block" class="flex-container wide100p flexGap10">
|
||||||
|
<div class="flex1">
|
||||||
|
<div class="flex-container marginBot10 alignitemscenter">
|
||||||
|
<div id="create_dummy_persona" class="menu_button menu_button_icon" title="Create a dummy persona" data-i18n="[title]Create a dummy persona">
|
||||||
|
<i class="fa-solid fa-person-circle-question fa-fw"></i>
|
||||||
|
<span data-i18n="Create">Create</span>
|
||||||
|
</div>
|
||||||
|
<input id="persona_search_bar" class="text_pole width100p flex1 margin0" type="search" data-i18n="[placeholder]Search..." placeholder="Search..." maxlength="100">
|
||||||
|
<div id="persona_pagination_container" class="flex1"></div>
|
||||||
|
</div>
|
||||||
|
<div id="user_avatar_block">
|
||||||
|
<div class="avatar_upload">+</div>
|
||||||
|
</div>
|
||||||
|
<form id="form_upload_avatar" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||||
|
<input type="file" id="avatar_upload_file" accept="image/*" name="avatar">
|
||||||
|
<input type="hidden" id="avatar_upload_overwrite" name="overwrite_name" value="">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
<div class="flex1">
|
<div class="flex1">
|
||||||
<h4 data-i18n="Name">Name</h4>
|
<h4 data-i18n="Name">Name</h4>
|
||||||
<div class="change_name">
|
<div class="change_name">
|
||||||
@ -3716,18 +3729,6 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex1">
|
|
||||||
<h4 class="title_restorable">
|
|
||||||
<span data-i18n="Your Persona">Your Persona</span>
|
|
||||||
</h4>
|
|
||||||
<div id="user_avatar_block">
|
|
||||||
<div class="avatar_upload">+</div>
|
|
||||||
</div>
|
|
||||||
<form id="form_upload_avatar" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
|
||||||
<input type="file" id="avatar_upload_file" accept="image/*" name="avatar">
|
|
||||||
<input type="hidden" id="avatar_upload_overwrite" name="overwrite_name" value="">
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -3958,7 +3959,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<select id="rm_group_generation_mode">
|
<select id="rm_group_generation_mode">
|
||||||
<option value="0" data-i18n="Swap character cards">Swap character cards</option>
|
<option value="0" data-i18n="Swap character cards">Swap character cards</option>
|
||||||
<option value="1" data-i18n="Join character cards">Join character cards</option>
|
<option value="1" data-i18n="Join character cards (exclude muted)">Join character cards (exclude muted)</option>
|
||||||
|
<option value="2" data-i18n="Join character cards (include muted)">Join character cards (include muted)</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -4245,9 +4247,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div id="shadow_select_chat_popup">
|
<div id="shadow_select_chat_popup">
|
||||||
<div id="select_chat_popup">
|
<div id="select_chat_popup">
|
||||||
<div name="selectChatPopupHeader" class="flex-container alignitemscenter justifySpaceBetween">
|
<div name="selectChatPopupHeader" class="flex-container alignitemscenter justifySpaceBetween flexGap10">
|
||||||
<div id="select_chat_import"> <!-- import chat popup header -->
|
<div id="select_chat_import"> <!-- import chat popup header -->
|
||||||
<div id="chat_import_button" class="fa-solid fa-file-import opacity50p hoverglow fontsize120p"></div>
|
|
||||||
<form id="form_import_chat" action="javascript:void(null);" method="post" enctype="multipart/form-data" style="display: none;">
|
<form id="form_import_chat" action="javascript:void(null);" method="post" enctype="multipart/form-data" style="display: none;">
|
||||||
<input type="file" id="chat_import_file" accept=".json, .jsonl" name="avatar">
|
<input type="file" id="chat_import_file" accept=".json, .jsonl" name="avatar">
|
||||||
<input id="chat_import_file_type" name="file_type" class="text_pole" maxlength="999" size="2" value="" autocomplete="off" style="display: none;">
|
<input id="chat_import_file_type" name="file_type" class="text_pole" maxlength="999" size="2" value="" autocomplete="off" style="display: none;">
|
||||||
@ -4259,8 +4260,15 @@
|
|||||||
<span id="ChatHistoryCharName"></span><span data-i18n="Chat History">Chat History</span>
|
<span id="ChatHistoryCharName"></span><span data-i18n="Chat History">Chat History</span>
|
||||||
<a href="https://docs.sillytavern.app/usage/core-concepts/chatfilemanagement/#chat-import" class="notes-link" target="_blank"><span class="fa-solid fa-circle-question note-link-span"></span></a>
|
<a href="https://docs.sillytavern.app/usage/core-concepts/chatfilemanagement/#chat-import" class="notes-link" target="_blank"><span class="fa-solid fa-circle-question note-link-span"></span></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="fa-solid fa-plus menu_button" title="New Chat" id="newChatFromManageScreenButton"></div>
|
<div id="newChatFromManageScreenButton" class="menu_button menu_button_icon" >
|
||||||
<input type="text" id="select_chat_search" class="menu_button" placeholder="Search..." autocomplete="off">
|
<i class="fa-solid fa-plus"></i>
|
||||||
|
<span data-i18n="New Chat">New Chat</span>
|
||||||
|
</div>
|
||||||
|
<div id="chat_import_button" class="menu_button menu_button_icon">
|
||||||
|
<i class="fa-solid fa-file-import"></i>
|
||||||
|
<span data-i18n="Import Chat">Import Chat</span>
|
||||||
|
</div>
|
||||||
|
<input type="text" id="select_chat_search" class="text_pole flex1" placeholder="Search..." autocomplete="off">
|
||||||
<div id="select_chat_cross" class="opacity50p hoverglow fa-solid fa-circle-xmark fontsize120p" alt="Close Past Chat Popup"></div>
|
<div id="select_chat_cross" class="opacity50p hoverglow fa-solid fa-circle-xmark fontsize120p" alt="Close Past Chat Popup"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="select_chat_div"></div>
|
<div id="select_chat_div"></div>
|
||||||
@ -5339,25 +5347,29 @@
|
|||||||
<div id="rawPromptWrapper" class="tokenItemizingSubclass"></div>
|
<div id="rawPromptWrapper" class="tokenItemizingSubclass"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="user_avatar_template" class="template_element">
|
<div id="user_avatar_template" class="template_element">
|
||||||
<div class="avatar-container">
|
<div class="avatar-container wide100p">
|
||||||
<div imgfile="" class="avatar">
|
<div imgfile="" class="avatar">
|
||||||
<img src="" alt="User Avatar">
|
<img src="" alt="User Avatar">
|
||||||
</div>
|
</div>
|
||||||
<div class="avatar-buttons avatar-buttons-top">
|
<div class="flex-container wide100pLess70px character_select_container">
|
||||||
<button class="menu_button bind_user_name" title="Bind user name to that avatar" data-i18n="[title]Bind user name to that avatar">
|
<div class="wide100p character_name_block">
|
||||||
<i class="fa-solid fa-user-edit"></i>
|
<span class="ch_name flex1"></span>
|
||||||
</button>
|
<div class="avatar-buttons">
|
||||||
<button class="menu_button set_default_persona" title="Select this as default persona for the new chats." data-i18n="[title]Select this as default persona for the new chats.">
|
<button class="menu_button bind_user_name" title="Bind user name to that avatar" data-i18n="[title]Bind user name to that avatar">
|
||||||
<i class="fa-solid fa-crown"></i>
|
<i class="fa-fw fa-solid fa-user-edit"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
<button class="menu_button set_persona_image" title="Change persona image" data-i18n="[title]Change persona image">
|
||||||
<div class="avatar-buttons avatar-buttons-bottom">
|
<i class="fa-fw fa-solid fa-image"></i>
|
||||||
<button class="menu_button set_persona_image" title="Change persona image" data-i18n="[title]Change persona image">
|
</button>
|
||||||
<i class="fa-solid fa-image"></i>
|
<button class="menu_button set_default_persona" title="Select this as default persona for the new chats." data-i18n="[title]Select this as default persona for the new chats.">
|
||||||
</button>
|
<i class="fa-fw fa-solid fa-crown"></i>
|
||||||
<button class="menu_button delete_avatar" title="Delete persona" data-i18n="[title]Delete persona">
|
</button>
|
||||||
<i class="fa-solid fa-trash-alt"></i>
|
<button class="menu_button delete_avatar" title="Delete persona" data-i18n="[title]Delete persona">
|
||||||
</button>
|
<i class="fa-fw fa-solid fa-trash-alt"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="ch_description"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
102
public/script.js
102
public/script.js
@ -444,6 +444,7 @@ let generation_started = new Date();
|
|||||||
let characters = [];
|
let characters = [];
|
||||||
let this_chid;
|
let this_chid;
|
||||||
let saveCharactersPage = 0;
|
let saveCharactersPage = 0;
|
||||||
|
let savePersonasPage = 0;
|
||||||
const default_avatar = 'img/ai4.png';
|
const default_avatar = 'img/ai4.png';
|
||||||
export const system_avatar = 'img/five.png';
|
export const system_avatar = 'img/five.png';
|
||||||
export const comment_avatar = 'img/quill.png';
|
export const comment_avatar = 'img/quill.png';
|
||||||
@ -790,6 +791,7 @@ var PromptArrayItemForRawPromptDisplay;
|
|||||||
export let active_character = '';
|
export let active_character = '';
|
||||||
export let active_group = '';
|
export let active_group = '';
|
||||||
export const entitiesFilter = new FilterHelper(debounce(printCharacters, 100));
|
export const entitiesFilter = new FilterHelper(debounce(printCharacters, 100));
|
||||||
|
export const personasFilter = new FilterHelper(debounce(getUserAvatars, 100));
|
||||||
|
|
||||||
export function getRequestHeaders() {
|
export function getRequestHeaders() {
|
||||||
return {
|
return {
|
||||||
@ -5395,47 +5397,85 @@ function changeMainAPI() {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////
|
////////////////////////////////////////////////////
|
||||||
|
|
||||||
export async function getUserAvatars() {
|
/**
|
||||||
|
* Gets a list of user avatars.
|
||||||
|
* @param {boolean} doRender Whether to render the list
|
||||||
|
* @returns {Promise<string[]>} List of avatar file names
|
||||||
|
*/
|
||||||
|
export async function getUserAvatars(doRender = true) {
|
||||||
const response = await fetch('/getuseravatars', {
|
const response = await fetch('/getuseravatars', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: getRequestHeaders(),
|
headers: getRequestHeaders(),
|
||||||
body: JSON.stringify({
|
|
||||||
'': '',
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
if (response.ok === true) {
|
if (response.ok) {
|
||||||
const getData = await response.json();
|
const allEntities = await response.json();
|
||||||
$('#user_avatar_block').html(''); //RossAscends: necessary to avoid doubling avatars each refresh.
|
|
||||||
$('#user_avatar_block').append('<div class="avatar_upload">+</div>');
|
|
||||||
|
|
||||||
for (var i = 0; i < getData.length; i++) {
|
if (!doRender) {
|
||||||
appendUserAvatar(getData[i]);
|
return allEntities;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getData;
|
const entities = personasFilter.applyFilters(allEntities);
|
||||||
|
|
||||||
|
const storageKey = 'Personas_PerPage';
|
||||||
|
const listId = '#user_avatar_block';
|
||||||
|
|
||||||
|
$('#persona_pagination_container').pagination({
|
||||||
|
dataSource: entities,
|
||||||
|
pageSize: Number(localStorage.getItem(storageKey)) || 5,
|
||||||
|
sizeChangerOptions: [5, 10, 25, 50, 100, 250, 500, 1000],
|
||||||
|
pageRange: 1,
|
||||||
|
pageNumber: savePersonasPage || 1,
|
||||||
|
position: 'top',
|
||||||
|
showPageNumbers: false,
|
||||||
|
showSizeChanger: true,
|
||||||
|
prevText: '<',
|
||||||
|
nextText: '>',
|
||||||
|
formatNavigator: PAGINATION_TEMPLATE,
|
||||||
|
showNavigator: true,
|
||||||
|
callback: function (data) {
|
||||||
|
$(listId).empty();
|
||||||
|
for (const item of data) {
|
||||||
|
$(listId).append(getUserAvatarBlock(item));
|
||||||
|
}
|
||||||
|
highlightSelectedAvatar();
|
||||||
|
},
|
||||||
|
afterSizeSelectorChange: function (e) {
|
||||||
|
localStorage.setItem(storageKey, e.target.value);
|
||||||
|
},
|
||||||
|
afterPaging: function (e) {
|
||||||
|
savePersonasPage = e;
|
||||||
|
},
|
||||||
|
afterRender: function () {
|
||||||
|
$(listId).scrollTop(0);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return allEntities;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function highlightSelectedAvatar() {
|
function highlightSelectedAvatar() {
|
||||||
$('#user_avatar_block').find('.avatar').removeClass('selected');
|
$('#user_avatar_block .avatar-container').removeClass('selected');
|
||||||
$('#user_avatar_block')
|
$(`#user_avatar_block .avatar-container[imgfile='${user_avatar}']`).addClass('selected');
|
||||||
.find(`.avatar[imgfile='${user_avatar}']`)
|
|
||||||
.addClass('selected');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function appendUserAvatar(name) {
|
/**
|
||||||
|
* Gets a rendered avatar block.
|
||||||
|
* @param {string} name Avatar file name
|
||||||
|
* @returns {JQuery<HTMLElement>} Avatar block
|
||||||
|
*/
|
||||||
|
function getUserAvatarBlock(name) {
|
||||||
const template = $('#user_avatar_template .avatar-container').clone();
|
const template = $('#user_avatar_template .avatar-container').clone();
|
||||||
const personaName = power_user.personas[name];
|
const personaName = power_user.personas[name];
|
||||||
if (personaName) {
|
const personaDescription = power_user.persona_descriptions[name]?.description;
|
||||||
template.attr('title', personaName);
|
template.find('.ch_name').text(personaName || '[Unnamed Persona]');
|
||||||
} else {
|
template.find('.ch_description').text(personaDescription || '[No description]').toggleClass('text_muted', !personaDescription);
|
||||||
template.attr('title', '[Unnamed Persona]');
|
template.attr('imgfile', name);
|
||||||
}
|
|
||||||
template.find('.avatar').attr('imgfile', name);
|
template.find('.avatar').attr('imgfile', name);
|
||||||
template.toggleClass('default_persona', name === power_user.default_persona);
|
template.toggleClass('default_persona', name === power_user.default_persona);
|
||||||
template.find('img').attr('src', getUserAvatar(name));
|
template.find('img').attr('src', getUserAvatar(name));
|
||||||
$('#user_avatar_block').append(template);
|
$('#user_avatar_block').append(template);
|
||||||
highlightSelectedAvatar();
|
return template;
|
||||||
}
|
}
|
||||||
|
|
||||||
function reloadUserAvatar(force = false) {
|
function reloadUserAvatar(force = false) {
|
||||||
@ -5463,8 +5503,12 @@ export function setUserName(value) {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUserAvatar() {
|
/**
|
||||||
user_avatar = $(this).attr('imgfile');
|
* Sets a user avatar file
|
||||||
|
* @param {string} imgfile Link to an image file
|
||||||
|
*/
|
||||||
|
export function setUserAvatar(imgfile) {
|
||||||
|
user_avatar = imgfile && typeof imgfile === 'string' ? imgfile : $(this).attr('imgfile');
|
||||||
reloadUserAvatar();
|
reloadUserAvatar();
|
||||||
highlightSelectedAvatar();
|
highlightSelectedAvatar();
|
||||||
selectCurrentPersona();
|
selectCurrentPersona();
|
||||||
@ -7966,6 +8010,11 @@ jQuery(async function () {
|
|||||||
entitiesFilter.setFilterData(FILTER_TYPES.SEARCH, searchValue);
|
entitiesFilter.setFilterData(FILTER_TYPES.SEARCH, searchValue);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('#persona_search_bar').on('input', function () {
|
||||||
|
const searchValue = String($(this).val()).toLowerCase();
|
||||||
|
personasFilter.setFilterData(FILTER_TYPES.PERSONA_SEARCH, searchValue);
|
||||||
|
});
|
||||||
|
|
||||||
$('#mes_continue').on('click', function () {
|
$('#mes_continue').on('click', function () {
|
||||||
$('#option_continue').trigger('click');
|
$('#option_continue').trigger('click');
|
||||||
});
|
});
|
||||||
@ -8067,12 +8116,13 @@ jQuery(async function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).on('click', '#user_avatar_block .avatar', setUserAvatar);
|
$(document).on('click', '#user_avatar_block .avatar-container', setUserAvatar);
|
||||||
$(document).on('click', '#user_avatar_block .avatar_upload', function () {
|
$(document).on('click', '#user_avatar_block .avatar_upload', function () {
|
||||||
$('#avatar_upload_overwrite').val('');
|
$('#avatar_upload_overwrite').val('');
|
||||||
$('#avatar_upload_file').trigger('click');
|
$('#avatar_upload_file').trigger('click');
|
||||||
});
|
});
|
||||||
$(document).on('click', '#user_avatar_block .set_persona_image', function () {
|
$(document).on('click', '#user_avatar_block .set_persona_image', function (e) {
|
||||||
|
e.stopPropagation();
|
||||||
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
|
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
|
||||||
|
|
||||||
if (!avatarId) {
|
if (!avatarId) {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { fuzzySearchCharacters, fuzzySearchGroups, fuzzySearchTags, fuzzySearchWorldInfo, power_user } from './power-user.js';
|
import { fuzzySearchCharacters, fuzzySearchGroups, fuzzySearchPersonas, fuzzySearchTags, fuzzySearchWorldInfo, power_user } from './power-user.js';
|
||||||
import { tag_map } from './tags.js';
|
import { tag_map } from './tags.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,6 +11,7 @@ export const FILTER_TYPES = {
|
|||||||
FAV: 'fav',
|
FAV: 'fav',
|
||||||
GROUP: 'group',
|
GROUP: 'group',
|
||||||
WORLD_INFO_SEARCH: 'world_info_search',
|
WORLD_INFO_SEARCH: 'world_info_search',
|
||||||
|
PERSONA_SEARCH: 'persona_search',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -39,6 +40,7 @@ export class FilterHelper {
|
|||||||
[FILTER_TYPES.FAV]: this.favFilter.bind(this),
|
[FILTER_TYPES.FAV]: this.favFilter.bind(this),
|
||||||
[FILTER_TYPES.TAG]: this.tagFilter.bind(this),
|
[FILTER_TYPES.TAG]: this.tagFilter.bind(this),
|
||||||
[FILTER_TYPES.WORLD_INFO_SEARCH]: this.wiSearchFilter.bind(this),
|
[FILTER_TYPES.WORLD_INFO_SEARCH]: this.wiSearchFilter.bind(this),
|
||||||
|
[FILTER_TYPES.PERSONA_SEARCH]: this.personaSearchFilter.bind(this),
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,6 +53,7 @@ export class FilterHelper {
|
|||||||
[FILTER_TYPES.FAV]: false,
|
[FILTER_TYPES.FAV]: false,
|
||||||
[FILTER_TYPES.TAG]: { excluded: [], selected: [] },
|
[FILTER_TYPES.TAG]: { excluded: [], selected: [] },
|
||||||
[FILTER_TYPES.WORLD_INFO_SEARCH]: '',
|
[FILTER_TYPES.WORLD_INFO_SEARCH]: '',
|
||||||
|
[FILTER_TYPES.PERSONA_SEARCH]: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -69,6 +72,22 @@ export class FilterHelper {
|
|||||||
return data.filter(entity => fuzzySearchResults.includes(entity.uid));
|
return data.filter(entity => fuzzySearchResults.includes(entity.uid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies a search filter to Persona data.
|
||||||
|
* @param {string[]} data The data to filter.
|
||||||
|
* @returns {string[]} The filtered data.
|
||||||
|
*/
|
||||||
|
personaSearchFilter(data) {
|
||||||
|
const term = this.filterData[FILTER_TYPES.PERSONA_SEARCH];
|
||||||
|
|
||||||
|
if (!term) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fuzzySearchResults = fuzzySearchPersonas(data, term);
|
||||||
|
return data.filter(entity => fuzzySearchResults.includes(entity));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the given entity is tagged with the given tag ID.
|
* Checks if the given entity is tagged with the given tag ID.
|
||||||
* @param {object} entity Searchable entity
|
* @param {object} entity Searchable entity
|
||||||
|
@ -108,6 +108,7 @@ export const group_activation_strategy = {
|
|||||||
export const group_generation_mode = {
|
export const group_generation_mode = {
|
||||||
SWAP: 0,
|
SWAP: 0,
|
||||||
APPEND: 1,
|
APPEND: 1,
|
||||||
|
APPEND_DISABLED: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_AUTO_MODE_DELAY = 5;
|
const DEFAULT_AUTO_MODE_DELAY = 5;
|
||||||
@ -325,7 +326,7 @@ export function getGroupDepthPrompts(groupId, characterId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Combines group members info a single string. Only for groups with generation mode set to APPEND.
|
* Combines group members cards into a single string. Only for groups with generation mode set to APPEND or APPEND_DISABLED.
|
||||||
* @param {string} groupId Group ID
|
* @param {string} groupId Group ID
|
||||||
* @param {number} characterId Current Character ID
|
* @param {number} characterId Current Character ID
|
||||||
* @returns {{description: string, personality: string, scenario: string, mesExamples: string}} Group character cards combined
|
* @returns {{description: string, personality: string, scenario: string, mesExamples: string}} Group character cards combined
|
||||||
@ -334,7 +335,7 @@ export function getGroupCharacterCards(groupId, characterId) {
|
|||||||
console.debug('getGroupCharacterCards entered for group: ', groupId);
|
console.debug('getGroupCharacterCards entered for group: ', groupId);
|
||||||
const group = groups.find(x => x.id === groupId);
|
const group = groups.find(x => x.id === groupId);
|
||||||
|
|
||||||
if (!group || group?.generation_mode !== group_generation_mode.APPEND || !Array.isArray(group.members) || !group.members.length) {
|
if (!group || !group?.generation_mode || !Array.isArray(group.members) || !group.members.length) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +355,7 @@ export function getGroupCharacterCards(groupId, characterId) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group.disabled_members.includes(member) && characterId !== index) {
|
if (group.disabled_members.includes(member) && characterId !== index && group.generation_mode !== group_generation_mode.APPEND_DISABLED) {
|
||||||
console.debug(`Skipping disabled group member: ${member}`);
|
console.debug(`Skipping disabled group member: ${member}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
name1,
|
name1,
|
||||||
saveMetadata,
|
saveMetadata,
|
||||||
saveSettingsDebounced,
|
saveSettingsDebounced,
|
||||||
|
setUserAvatar,
|
||||||
setUserName,
|
setUserName,
|
||||||
this_chid,
|
this_chid,
|
||||||
user_avatar,
|
user_avatar,
|
||||||
@ -187,7 +188,7 @@ export function autoSelectPersona(name) {
|
|||||||
for (const [key, value] of Object.entries(power_user.personas)) {
|
for (const [key, value] of Object.entries(power_user.personas)) {
|
||||||
if (value === name) {
|
if (value === name) {
|
||||||
console.log(`Auto-selecting persona ${key} for name ${name}`);
|
console.log(`Auto-selecting persona ${key} for name ${name}`);
|
||||||
$(`.avatar[imgfile="${key}"]`).trigger('click');
|
setUserAvatar(key);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,7 +210,8 @@ export async function updatePersonaNameIfExists(avatarId, newName) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function bindUserNameToPersona() {
|
async function bindUserNameToPersona(e) {
|
||||||
|
e?.stopPropagation();
|
||||||
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
|
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
|
||||||
|
|
||||||
if (!avatarId) {
|
if (!avatarId) {
|
||||||
@ -331,7 +333,8 @@ async function lockUserNameToChat() {
|
|||||||
updateUserLockIcon();
|
updateUserLockIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteUserAvatar() {
|
async function deleteUserAvatar(e) {
|
||||||
|
e?.stopPropagation();
|
||||||
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
|
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
|
||||||
|
|
||||||
if (!avatarId) {
|
if (!avatarId) {
|
||||||
@ -400,6 +403,9 @@ function onPersonaDescriptionInput() {
|
|||||||
object.description = power_user.persona_description;
|
object.description = power_user.persona_description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$(`.avatar-container[imgfile="${user_avatar}"] .ch_description`)
|
||||||
|
.text(power_user.persona_description || '[No description]')
|
||||||
|
.toggleClass('text_muted', !power_user.persona_description);
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +431,8 @@ function onPersonaDescriptionPositionInput() {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setDefaultPersona() {
|
async function setDefaultPersona(e) {
|
||||||
|
e?.stopPropagation();
|
||||||
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
|
const avatarId = $(this).closest('.avatar-container').find('.avatar').attr('imgfile');
|
||||||
|
|
||||||
if (!avatarId) {
|
if (!avatarId) {
|
||||||
@ -481,7 +488,7 @@ function updateUserLockIcon() {
|
|||||||
$('#lock_user_name').toggleClass('fa-lock', hasLock);
|
$('#lock_user_name').toggleClass('fa-lock', hasLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setChatLockedPersona() {
|
async function setChatLockedPersona() {
|
||||||
// Define a persona for this chat
|
// Define a persona for this chat
|
||||||
let chatPersona = '';
|
let chatPersona = '';
|
||||||
|
|
||||||
@ -502,10 +509,10 @@ function setChatLockedPersona() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the avatar file
|
// Find the avatar file
|
||||||
const personaAvatar = $(`.avatar[imgfile="${chatPersona}"]`).trigger('click');
|
const userAvatars = await getUserAvatars(false);
|
||||||
|
|
||||||
// Avatar missing (persona deleted)
|
// Avatar missing (persona deleted)
|
||||||
if (chat_metadata['persona'] && personaAvatar.length == 0) {
|
if (chat_metadata['persona'] && !userAvatars.includes(chatPersona)) {
|
||||||
console.warn('Persona avatar not found, unlocking persona');
|
console.warn('Persona avatar not found, unlocking persona');
|
||||||
delete chat_metadata['persona'];
|
delete chat_metadata['persona'];
|
||||||
updateUserLockIcon();
|
updateUserLockIcon();
|
||||||
@ -513,7 +520,7 @@ function setChatLockedPersona() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Default persona missing
|
// Default persona missing
|
||||||
if (power_user.default_persona && personaAvatar.length == 0) {
|
if (power_user.default_persona && !userAvatars.includes(power_user.default_persona)) {
|
||||||
console.warn('Default persona avatar not found, clearing default persona');
|
console.warn('Default persona avatar not found, clearing default persona');
|
||||||
power_user.default_persona = null;
|
power_user.default_persona = null;
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
@ -521,7 +528,7 @@ function setChatLockedPersona() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Persona avatar found, select it
|
// Persona avatar found, select it
|
||||||
personaAvatar.trigger('click');
|
setUserAvatar(chatPersona);
|
||||||
updateUserLockIcon();
|
updateUserLockIcon();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -560,7 +567,7 @@ async function onPersonasRestoreInput(e) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const avatarsList = await getUserAvatars();
|
const avatarsList = await getUserAvatars(false);
|
||||||
const warnings = [];
|
const warnings = [];
|
||||||
|
|
||||||
// Merge personas with existing ones
|
// Merge personas with existing ones
|
||||||
|
@ -1831,6 +1831,23 @@ export function fuzzySearchWorldInfo(data, searchValue) {
|
|||||||
return results.map(x => x.item?.uid);
|
return results.map(x => x.item?.uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fuzzySearchPersonas(data, searchValue) {
|
||||||
|
data = data.map(x => ({ key: x, description: power_user.persona_descriptions[x]?.description ?? '', name: power_user.personas[x] ?? '' }));
|
||||||
|
const fuse = new Fuse(data, {
|
||||||
|
keys: [
|
||||||
|
{ name: 'name', weight: 4 },
|
||||||
|
{ name: 'description', weight: 1 },
|
||||||
|
],
|
||||||
|
includeScore: true,
|
||||||
|
ignoreLocation: true,
|
||||||
|
threshold: 0.2,
|
||||||
|
});
|
||||||
|
|
||||||
|
const results = fuse.search(searchValue);
|
||||||
|
console.debug('Personas fuzzy search results for ' + searchValue, results);
|
||||||
|
return results.map(x => x.item?.key);
|
||||||
|
}
|
||||||
|
|
||||||
export function fuzzySearchTags(searchValue) {
|
export function fuzzySearchTags(searchValue) {
|
||||||
const fuse = new Fuse(tags, {
|
const fuse = new Fuse(tags, {
|
||||||
keys: [
|
keys: [
|
||||||
|
@ -1596,7 +1596,8 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.bogus_folder_select:hover,
|
.bogus_folder_select:hover,
|
||||||
.character_select:hover {
|
.character_select:hover,
|
||||||
|
.avatar-container:hover {
|
||||||
background-color: var(--white30a);
|
background-color: var(--white30a);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1821,29 +1822,28 @@ input[type=search]:focus::-webkit-search-cancel-button {
|
|||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
|
gap: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-bottom: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
grammarly-extension {
|
grammarly-extension {
|
||||||
z-index: 35;
|
z-index: 35;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-container:hover .avatar-buttons {
|
.avatar-container .avatar-buttons {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 5px;
|
||||||
|
opacity: 0.3;
|
||||||
|
transition: opacity 0.25s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar-buttons .menu_button {
|
.avatar-container .avatar-buttons:hover {
|
||||||
pointer-events: all;
|
opacity: 1;
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-buttons-bottom {
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-buttons-top {
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ross should be able to handle this later */
|
/* Ross should be able to handle this later */
|
||||||
@ -1852,14 +1852,6 @@ grammarly-extension {
|
|||||||
width: fit-content;
|
width: fit-content;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
.avatar-buttons {
|
|
||||||
pointer-events: none;
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
width: 100%;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar_div .avatar {
|
.avatar_div .avatar {
|
||||||
/* margin-left: 4px;
|
/* margin-left: 4px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
@ -2279,29 +2271,33 @@ input[type="checkbox"]:not(#nav-toggle):not(#rm_button_panel_pin):not(#lm_button
|
|||||||
|
|
||||||
#user_avatar_block {
|
#user_avatar_block {
|
||||||
display: flex;
|
display: flex;
|
||||||
grid-gap: 10px;
|
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
}
|
}
|
||||||
|
|
||||||
#user_avatar_block .avatar {
|
.avatar-container .avatar {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 64px;
|
width: 64px;
|
||||||
height: 64px;
|
height: 64px;
|
||||||
outline: 2px solid rgba(255, 255, 255, 0.7);
|
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
align-self: center;
|
||||||
|
|
||||||
#user_avatar_block .avatar:not(.selected) {
|
|
||||||
outline: 2px solid transparent;
|
outline: 2px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
#user_avatar_block .default_persona .avatar {
|
.avatar-container {
|
||||||
border: 2px solid var(--golden);
|
outline: 2px solid transparent;
|
||||||
box-sizing: content-box;
|
border: 2px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
#user_avatar_block .default_persona .set_default_persona {
|
.avatar-container.selected {
|
||||||
|
border: 2px solid rgba(255, 255, 255, 0.7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-container.default_persona .avatar {
|
||||||
|
outline: 2px solid var(--golden);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-container.default_persona .set_default_persona {
|
||||||
color: var(--golden);
|
color: var(--golden);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user