Merge branch 'SillyTavern:dev' into dev

This commit is contained in:
BlipRanger
2023-06-24 20:43:42 -04:00
committed by GitHub
7 changed files with 224 additions and 15 deletions

View File

@ -2430,7 +2430,7 @@
</div>
<div id="avatar_div" class="avatar_div alignitemsflexstart justifySpaceBetween flexnowrap flexGap5">
<label id="avatar_div_div" for="add_avatar_button" class="avatar" title="Click to select a new avatar for this character">
<label id="avatar_div_div" class="add_avatar avatar" for="add_avatar_button" title="Click to select a new avatar for this character">
<img id="avatar_load_preview" src="img/ai4.png" alt="avatar">
<input hidden type="file" id="add_avatar_button" name="avatar" accept="image/png, image/jpeg, image/jpg, image/gif, image/bmp">
</label>
@ -2547,8 +2547,18 @@
</div>
<div id="groupTagList" class="tags paddingTopBot5"></div>
</div>
<div id="rm_group_top_bar" class="flex-container spaceBetween width100p">
<div name="GroupStragegyAndOrder" id="rm_group_buttons" class="fontsize80p flex-container paddingLeftRight5">
<div id="rm_group_top_bar" class="flex-container alignitemscenter spaceBetween width100p">
<div class="flex1 flex-container alignitemscenter justifyCenter">
<label class="add_avatar avatar" for="group_avatar_button" title="Click to select a new avatar for this group">
<div id="group_avatar_preview">
<div class="avatar">
<img src="img/ai4.png" alt="avatar">
</div>
</div>
<input hidden type="file" id="group_avatar_button" name="avatar" accept="image/png, image/jpeg, image/jpg, image/gif, image/bmp">
</label>
</div>
<div name="GroupStragegyAndOrder" id="rm_group_buttons" class="fontsize80p flex-container paddingLeftRight5 flex2">
<div class="">
<div class="flex-container flexnowrap width100p whitespacenowrap">
<span data-i18n="Group reply strategy">Group reply strategy</span>
@ -2576,12 +2586,13 @@
</label>
</div>
</div>
<div id="GroupFavDelOkBack" class="flex-container flexGap5 spaceEvenly">
<div id="GroupFavDelOkBack" class="flex-container flexGap5 spaceEvenly flex1">
<div id="rm_button_back_from_group" class="heightFitContent margin0 menu_button fa-solid fa-left-long"></div>
<div id="rm_group_scenario" class="heightFitContent margin0 menu_button fa-solid fa-scroll" title="Set a group chat scenario"></div>
<div id="group_favorite_button" class="heightFitContent margin0 menu_button fa-solid fa-star" title="Add to Favorites"></div>
<input id="rm_group_fav" type="hidden" />
<div id="rm_group_submit" class="heightFitContent margin0 menu_button fa-solid fa-check" title="Create"></div>
<div id="rm_group_restore_avatar" class="heightFitContent margin0 menu_button fa-solid fa-images" title="Restore collage avatar"></div>
<div id="rm_group_delete" class="heightFitContent margin0 menu_button fa-solid fa-trash-can" title="Delete"></div>
</div>
@ -3207,7 +3218,7 @@
<div title="Move up" data-action="up" class="right_menu_button fa-solid fa-chevron-up"></div>
<div title="Move down" data-action="down" class="right_menu_button fa-solid fa-chevron-down"></div>
</div>
<div title="View character card" data-action="view" class="right_menu_button fa-solid fa-xl fa-id-badge"></div>
<div title="View character card" data-action="view" class="right_menu_button fa-solid fa-xl fa-image-portrait"></div>
<div title="Remove from group" data-action="remove" class="right_menu_button fa-solid fa-2xl fa-xmark">
</div>
<div title="Add to group" data-action="add" class="right_menu_button fa-solid fa-2xl fa-plus"></div>

View File

@ -3742,7 +3742,7 @@ async function read_avatar_load(input) {
}
}
function getCropPopup(src) {
export function getCropPopup(src) {
return `<h3>Set the crop position of the avatar image and click Ok to confirm.</h3>
<div id='avatarCropWrap'>
<img id='avatarToCrop' src='${src}'>
@ -7351,6 +7351,8 @@ $(document).ready(function () {
return;
}
// Save before exporting
await createOrEditCharacter();
const body = { format, avatar_url: characters[this_chid].avatar };
const response = await fetch('/exportcharacter', {

View File

@ -27,6 +27,12 @@ export const metadata_keys = {
position: 'note_position',
}
const chara_note_position = {
replace: 0,
before: 1,
after: 2,
}
function setNoteTextCommand(_, text) {
$('#extension_floating_prompt').val(text).trigger('input');
toastr.success("Author's Note text updated");
@ -87,11 +93,13 @@ async function onExtensionFloatingPromptInput() {
chat_metadata[metadata_keys.prompt] = $(this).val();
setMainPromptTokenCounterDebounced(chat_metadata[metadata_keys.prompt]);
updateSettings();
saveMetadataDebounced();
}
async function onExtensionFloatingIntervalInput() {
chat_metadata[metadata_keys.interval] = Number($(this).val());
updateSettings();
saveMetadataDebounced();
}
async function onExtensionFloatingDepthInput() {
@ -104,11 +112,23 @@ async function onExtensionFloatingDepthInput() {
chat_metadata[metadata_keys.depth] = value;
updateSettings();
saveMetadataDebounced();
}
async function onExtensionFloatingPositionInput(e) {
chat_metadata[metadata_keys.position] = e.target.value;
updateSettings();
saveMetadataDebounced();
}
async function onExtensionFloatingCharPositionInput(e) {
const value = e.target.value;
const charaNote = extension_settings.note.chara.find((e) => e.name === getCharaFilename());
if (charaNote) {
charaNote.position = Number(value);
updateSettings();
}
}
function onExtensionFloatingCharaPromptInput() {
@ -143,7 +163,7 @@ function onExtensionFloatingCharaPromptInput() {
if (!extension_settings.note.chara) {
extension_settings.note.chara = []
}
Object.assign(tempCharaNote, { useChara: false })
Object.assign(tempCharaNote, { useChara: false, position: chara_note_position.replace })
extension_settings.note.chara.push(tempCharaNote);
} else {
@ -189,9 +209,11 @@ function loadSettings() {
$('#extension_floating_chara').val(charaNote ? charaNote.prompt : '');
$('#extension_use_floating_chara').prop('checked', charaNote ? charaNote.useChara : false);
$(`input[name="extension_floating_char_position"][value="${charaNote?.position ?? chara_note_position.replace}"]`).prop('checked', true);
} else {
$('#extension_floating_chara').val('');
$('#extension_use_floating_chara').prop('checked', false);
$(`input[name="extension_floating_char_position"][value="${chara_note_position.replace}"]`).prop('checked', true);
}
$('#extension_floating_default').val(extension_settings.note.default);
@ -236,7 +258,17 @@ export function setFloatingPrompt() {
// Only replace with the chara note if the user checked the box
if (charaNote && charaNote.useChara) {
switch (charaNote.position) {
case chara_note_position.before:
prompt = charaNote.prompt + '\n' + prompt;
break;
case chara_note_position.after:
prompt = prompt + '\n' + charaNote.prompt;
break;
default:
prompt = charaNote.prompt;
break;
}
}
}
context.setExtensionPrompt(MODULE_NAME, prompt, chat_metadata[metadata_keys.position], chat_metadata[metadata_keys.depth]);
@ -369,6 +401,20 @@ setTimeout(function () {
<input id="extension_use_floating_chara" type="checkbox" />
<span data-i18n="Use character author's note">Use character author's note</span>
</label>
<div class="floating_prompt_radio_group">
<label>
<input type="radio" name="extension_floating_char_position" value="0" />
Replace Author's Note
</label>
<label>
<input type="radio" name="extension_floating_char_position" value="1" />
Top of Author's Note
</label>
<label>
<input type="radio" name="extension_floating_char_position" value="2" />
Bottom of Author's Note
</label>
</div>
</div>
</div>
<hr class="sysHR">
@ -404,6 +450,7 @@ setTimeout(function () {
$('#extension_use_floating_chara').on('input', onExtensionFloatingCharaCheckboxChanged);
$('#extension_floating_default').on('input', onExtensionFloatingDefaultInput);
$('input[name="extension_floating_position"]').on('change', onExtensionFloatingPositionInput);
$('input[name="extension_floating_char_position"]').on('change', onExtensionFloatingCharPositionInput);
$('#ANClose').on('click', function () {
$("#floatingPrompt").transition({
opacity: 0,

View File

@ -3,6 +3,8 @@ import {
onlyUnique,
debounce,
delay,
isDataURL,
createThumbnail,
} from './utils.js';
import { RA_CountCharTokens, humanizedDateTime } from "./RossAscends-mods.js";
import { sortCharactersList, sortGroupMembers } from './power-user.js';
@ -57,6 +59,7 @@ import {
event_types,
getCurrentChatId,
setScenarioOverride,
getCropPopup,
} from "../script.js";
import { appendTagToList, createTagMapFromList, getTagsList, applyTagsOnCharacterSelect, tag_map } from './tags.js';
@ -357,6 +360,14 @@ function updateGroupAvatar(group) {
}
function getGroupAvatar(group) {
if (!group) {
return $(`<div class="avatar"><img src="${default_avatar}"></div>`);
}
if (isDataURL(group.avatar_url)) {
return $(`<div class="avatar"><img src="${group.avatar_url}"></div>`);
}
const memberAvatars = [];
if (group && Array.isArray(group.members) && group.members.length) {
for (const member of group.members) {
@ -925,6 +936,8 @@ function select_group_chats(groupId, skipAnimation) {
const group = groupId && groups.find((x) => x.id == groupId);
const groupName = group?.name ?? "";
setMenuType(!!group ? 'group_edit' : 'group_create');
$("#group_avatar_preview").empty().append(getGroupAvatar(group));
$("#rm_group_restore_avatar").toggle(!!group && isDataURL(group.avatar_url));
$("#rm_group_chat_name").val(groupName);
$("#rm_group_chat_name").off();
$("#rm_group_chat_name").on("input", async function () {
@ -1049,6 +1062,67 @@ function select_group_chats(groupId, skipAnimation) {
$("#rm_group_automode_label").hide();
}
$("#group_avatar_button").off('input').on("input", uploadGroupAvatar);
$("#rm_group_restore_avatar").off('click').on("click", restoreGroupAvatar);
async function uploadGroupAvatar(event) {
const file = event.target.files[0];
if (!file) {
return;
}
const e = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = resolve;
reader.onerror = reject;
reader.readAsDataURL(file);
});
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
const croppedImage = await callPopup(getCropPopup(e.target.result), 'avatarToCrop');
if (!croppedImage) {
return;
}
const thumbnail = await createThumbnail(croppedImage, 96, 144);
if (!groupId) {
$('#group_avatar_preview img').attr('src', thumbnail);
$('#rm_group_restore_avatar').show();
return;
}
let _thisGroup = groups.find((x) => x.id == groupId);
_thisGroup.avatar_url = thumbnail;
$("#group_avatar_preview").empty().append(getGroupAvatar(_thisGroup));
$("#rm_group_restore_avatar").show();
await editGroup(groupId, true, true);
}
async function restoreGroupAvatar() {
const confirm = await callPopup('<h3>Are you sure you want to restore the group avatar?</h3> Your custom image will be deleted, and a collage will be used instead.', 'confirm');
if (!confirm) {
return;
}
if (!groupId) {
$("#group_avatar_preview img").attr("src", default_avatar);
$("#rm_group_restore_avatar").hide();
return;
}
let _thisGroup = groups.find((x) => x.id == groupId);
_thisGroup.avatar_url = '';
$("#group_avatar_preview").empty().append(getGroupAvatar(_thisGroup));
$("#rm_group_restore_avatar").hide();
await editGroup(groupId, true, true);
}
$(document).off("click", ".group_member .right_menu_button");
$(document).on("click", ".group_member .right_menu_button", async function (event) {
event.stopPropagation();
@ -1174,8 +1248,7 @@ async function createGroup() {
name = `Group: ${memberNames}`;
}
// placeholder
const avatar_url = 'img/five.png';
const avatar_url = $('#group_avatar_preview img').attr('src');
const chatName = humanizedDateTime();
const chats = [chatName];
@ -1186,7 +1259,7 @@ async function createGroup() {
body: JSON.stringify({
name: name,
members: members,
avatar_url: avatar_url,
avatar_url: isDataURL(avatar_url) ? avatar_url : default_avatar,
allow_self_responses: allow_self_responses,
activation_strategy: activation_strategy,
disabled_members: [],

View File

@ -616,3 +616,38 @@ export function extractDataFromPng(data, identifier = 'chara') {
}
}
}
export function createThumbnail(dataUrl, maxWidth, maxHeight) {
return new Promise((resolve, reject) => {
const img = new Image();
img.src = dataUrl;
img.onload = () => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Calculate the thumbnail dimensions while maintaining the aspect ratio
const aspectRatio = img.width / img.height;
let thumbnailWidth = maxWidth;
let thumbnailHeight = maxHeight;
if (img.width > img.height) {
thumbnailHeight = maxWidth / aspectRatio;
} else {
thumbnailWidth = maxHeight * aspectRatio;
}
// Set the canvas dimensions and draw the resized image
canvas.width = thumbnailWidth;
canvas.height = thumbnailHeight;
ctx.drawImage(img, 0, 0, thumbnailWidth, thumbnailHeight);
// Convert the canvas to a data URL and resolve the promise
const thumbnailDataUrl = canvas.toDataURL('image/jpeg');
resolve(thumbnailDataUrl);
};
img.onerror = () => {
reject(new Error('Failed to load the image.'));
};
});
}

View File

@ -45,6 +45,8 @@ const world_info_position = {
};
const worldInfoCache = {};
async function getWorldInfoPrompt(chat2, maxContext) {
let worldInfoString = "", worldInfoBefore = "", worldInfoAfter = "";
@ -124,6 +126,10 @@ async function loadWorldInfoData(name) {
return;
}
if (worldInfoCache[name]) {
return worldInfoCache[name];
}
const response = await fetch("/getworldinfo", {
method: "POST",
headers: getRequestHeaders(),
@ -133,6 +139,7 @@ async function loadWorldInfoData(name) {
if (response.ok) {
const data = await response.json();
worldInfoCache[name] = data;
return data;
}
@ -557,6 +564,8 @@ async function saveWorldInfo(name, data, immediately) {
return;
}
delete worldInfoCache[name];
if (immediately) {
return await _save(name, data);
}
@ -902,6 +911,30 @@ function convertAgnaiMemoryBook(inputObj) {
return outputObj;
}
function convertRisuLorebook(inputObj) {
const outputObj = { entries: {} };
inputObj.data.forEach((entry, index) => {
outputObj.entries[index] = {
uid: index,
key: entry.key.split(',').map(x => x.trim()),
keysecondary: entry.secondkey ? entry.secondkey.split(',').map(x => x.trim()) : [],
comment: entry.comment,
content: entry.content,
constant: entry.alwaysActive,
selective: entry.selective,
order: entry.insertorder,
position: world_info_position.before,
disable: false,
addMemo: true,
excludeRecursion: false,
displayIndex: index,
};
});
return outputObj;
}
function convertNovelLorebook(inputObj) {
const outputObj = {
entries: {}
@ -1055,13 +1088,21 @@ jQuery(() => {
// Convert Novel Lorebook
if (jsonData.lorebookVersion !== undefined) {
console.log('Converting Novel Lorebook');
formData.append('convertedData', JSON.stringify(convertNovelLorebook(jsonData)));
}
// Convert Agnai Memory Book
if (jsonData.kind === 'memory') {
console.log('Converting Agnai Memory Book');
formData.append('convertedData', JSON.stringify(convertAgnaiMemoryBook(jsonData)));
}
// Convert Risu Lorebook
if (jsonData.type === 'risu') {
console.log('Converting Risu Lorebook');
formData.append('convertedData', JSON.stringify(convertRisuLorebook(jsonData)));
}
} catch (error) {
toastr.error(`Error parsing file: ${error}`);
return;

View File

@ -687,14 +687,14 @@ hr {
gap: 5px;
}
#avatar_div_div {
.add_avatar {
border: 2px solid var(--SmartThemeBodyColor);
margin: 2px;
cursor: pointer;
transition: filter 0.2s ease-in-out;
}
#avatar_div_div:hover {
.add_avatar:hover {
filter: drop-shadow(0px 0px 5px var(--SmartThemeQuoteColor));
}