mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge branch 'staging' of https://github.com/Cohee1207/SillyTavern into staging
This commit is contained in:
193
public/script.js
193
public/script.js
@ -129,6 +129,7 @@ import {
|
|||||||
getCharaFilename,
|
getCharaFilename,
|
||||||
isDigitsOnly,
|
isDigitsOnly,
|
||||||
PAGINATION_TEMPLATE,
|
PAGINATION_TEMPLATE,
|
||||||
|
waitUntilCondition,
|
||||||
} from "./scripts/utils.js";
|
} from "./scripts/utils.js";
|
||||||
|
|
||||||
import { extension_settings, getContext, loadExtensionSettings, processExtensionHelpers, registerExtensionHelper, runGenerationInterceptors, saveMetadataDebounced } from "./scripts/extensions.js";
|
import { extension_settings, getContext, loadExtensionSettings, processExtensionHelpers, registerExtensionHelper, runGenerationInterceptors, saveMetadataDebounced } from "./scripts/extensions.js";
|
||||||
@ -314,6 +315,8 @@ let safetychat = [
|
|||||||
mes: "You deleted a character/chat and arrived back here for safety reasons! Pick another character!",
|
mes: "You deleted a character/chat and arrived back here for safety reasons! Pick another character!",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
let chatSaveTimeout;
|
||||||
|
export let isChatSaving = false;
|
||||||
let chat_create_date = 0;
|
let chat_create_date = 0;
|
||||||
let firstRun = false;
|
let firstRun = false;
|
||||||
|
|
||||||
@ -350,7 +353,6 @@ let scrollLock = false;
|
|||||||
const durationSaveEdit = 1000;
|
const durationSaveEdit = 1000;
|
||||||
const saveSettingsDebounced = debounce(() => saveSettings(), durationSaveEdit);
|
const saveSettingsDebounced = debounce(() => saveSettings(), durationSaveEdit);
|
||||||
export const saveCharacterDebounced = debounce(() => $("#create_button").trigger('click'), durationSaveEdit);
|
export const saveCharacterDebounced = debounce(() => $("#create_button").trigger('click'), durationSaveEdit);
|
||||||
const saveChatDebounced = debounce(() => saveChatConditional(), durationSaveEdit);
|
|
||||||
|
|
||||||
const system_message_types = {
|
const system_message_types = {
|
||||||
HELP: "help",
|
HELP: "help",
|
||||||
@ -623,7 +625,6 @@ let is_api_button_press_novel = false;
|
|||||||
let api_use_mancer_webui = false;
|
let api_use_mancer_webui = false;
|
||||||
|
|
||||||
let is_send_press = false; //Send generation
|
let is_send_press = false; //Send generation
|
||||||
let add_mes_without_animation = false;
|
|
||||||
|
|
||||||
let this_del_mes = 0;
|
let this_del_mes = 0;
|
||||||
|
|
||||||
@ -821,6 +822,11 @@ export function selectCharacterById(id) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isChatSaving) {
|
||||||
|
toastr.info("Please wait until the chat is saved before switching characters.", "Your chat is still saving...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (selected_group && is_group_generating) {
|
if (selected_group && is_group_generating) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -2287,6 +2293,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
|||||||
setCharacterName('');
|
setCharacterName('');
|
||||||
} else {
|
} else {
|
||||||
console.log('No enabled members found');
|
console.log('No enabled members found');
|
||||||
|
is_send_press = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4139,6 +4146,32 @@ async function renamePastChats(newAvatar, newValue) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function saveChatDebounced() {
|
||||||
|
const chid = this_chid;
|
||||||
|
const selectedGroup = selected_group;
|
||||||
|
|
||||||
|
if (chatSaveTimeout) {
|
||||||
|
console.debug('Clearing chat save timeout');
|
||||||
|
clearTimeout(chatSaveTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
chatSaveTimeout = setTimeout(async () => {
|
||||||
|
if (selectedGroup !== selected_group) {
|
||||||
|
console.warn('Chat save timeout triggered, but group changed. Aborting.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chid !== this_chid) {
|
||||||
|
console.warn('Chat save timeout triggered, but chid changed. Aborting.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.debug('Chat save timeout triggered');
|
||||||
|
await saveChatConditional();
|
||||||
|
console.debug('Chat saved');
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
async function saveChat(chat_name, withMetadata, mesId) {
|
async function saveChat(chat_name, withMetadata, mesId) {
|
||||||
const metadata = { ...chat_metadata, ...(withMetadata || {}) };
|
const metadata = { ...chat_metadata, ...(withMetadata || {}) };
|
||||||
let file_name = chat_name ?? characters[this_chid].chat;
|
let file_name = chat_name ?? characters[this_chid].chat;
|
||||||
@ -4290,7 +4323,6 @@ async function getChat() {
|
|||||||
chat_create_date = humanizedDateTime();
|
chat_create_date = humanizedDateTime();
|
||||||
}
|
}
|
||||||
await getChatResult();
|
await getChatResult();
|
||||||
saveChatDebounced();
|
|
||||||
eventSource.emit('chatLoaded', { detail: { id: this_chid, character: characters[this_chid] } });
|
eventSource.emit('chatLoaded', { detail: { id: this_chid, character: characters[this_chid] } });
|
||||||
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
@ -4306,26 +4338,9 @@ async function getChat() {
|
|||||||
async function getChatResult() {
|
async function getChatResult() {
|
||||||
name2 = characters[this_chid].name;
|
name2 = characters[this_chid].name;
|
||||||
if (chat.length === 0) {
|
if (chat.length === 0) {
|
||||||
const firstMes = characters[this_chid].first_mes || default_ch_mes;
|
const message = getFirstMessage();
|
||||||
const alternateGreetings = characters[this_chid]?.data?.alternate_greetings;
|
chat.push(message);
|
||||||
|
await saveChatConditional();
|
||||||
chat[0] = {
|
|
||||||
name: name2,
|
|
||||||
is_user: false,
|
|
||||||
is_name: true,
|
|
||||||
send_date: getMessageTimeStamp(),
|
|
||||||
mes: getRegexedString(firstMes, regex_placement.AI_OUTPUT),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Array.isArray(alternateGreetings) && alternateGreetings.length > 0) {
|
|
||||||
chat[0]['swipe_id'] = 0;
|
|
||||||
chat[0]['swipes'] = [chat[0]['mes']].concat(
|
|
||||||
alternateGreetings.map(
|
|
||||||
(greeting) => substituteParams(getRegexedString(greeting, regex_placement.AI_OUTPUT))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
chat[0]['swipe_info'] = [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
printMessages();
|
printMessages();
|
||||||
select_selected_character(this_chid);
|
select_selected_character(this_chid);
|
||||||
@ -4338,6 +4353,30 @@ async function getChatResult() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFirstMessage() {
|
||||||
|
const firstMes = characters[this_chid].first_mes || default_ch_mes;
|
||||||
|
const alternateGreetings = characters[this_chid]?.data?.alternate_greetings;
|
||||||
|
|
||||||
|
const message = {
|
||||||
|
name: name2,
|
||||||
|
is_user: false,
|
||||||
|
is_name: true,
|
||||||
|
send_date: getMessageTimeStamp(),
|
||||||
|
mes: getRegexedString(firstMes, regex_placement.AI_OUTPUT),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Array.isArray(alternateGreetings) && alternateGreetings.length > 0) {
|
||||||
|
message['swipe_id'] = 0;
|
||||||
|
message['swipes'] = message['mes'].concat(
|
||||||
|
alternateGreetings.map(
|
||||||
|
(greeting) => substituteParams(getRegexedString(greeting, regex_placement.AI_OUTPUT))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
message['swipe_info'] = [];
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
async function openCharacterChat(file_name) {
|
async function openCharacterChat(file_name) {
|
||||||
characters[this_chid]["chat"] = file_name;
|
characters[this_chid]["chat"] = file_name;
|
||||||
clearChat();
|
clearChat();
|
||||||
@ -4872,7 +4911,7 @@ async function deleteUserAvatar() {
|
|||||||
if (avatarId === chat_metadata['persona']) {
|
if (avatarId === chat_metadata['persona']) {
|
||||||
toastr.warning('The locked persona was deleted. You will need to set a new persona for this chat.', 'Persona deleted');
|
toastr.warning('The locked persona was deleted. You will need to set a new persona for this chat.', 'Persona deleted');
|
||||||
delete chat_metadata['persona'];
|
delete chat_metadata['persona'];
|
||||||
saveMetadata();
|
await saveMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
@ -4881,11 +4920,11 @@ async function deleteUserAvatar() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function lockUserNameToChat() {
|
async function lockUserNameToChat() {
|
||||||
if (chat_metadata['persona']) {
|
if (chat_metadata['persona']) {
|
||||||
console.log(`Unlocking persona for this chat ${chat_metadata['persona']}`);
|
console.log(`Unlocking persona for this chat ${chat_metadata['persona']}`);
|
||||||
delete chat_metadata['persona'];
|
delete chat_metadata['persona'];
|
||||||
saveMetadata();
|
await saveMetadata();
|
||||||
if (power_user.persona_show_notifications) {
|
if (power_user.persona_show_notifications) {
|
||||||
toastr.info('User persona is now unlocked for this chat. Click the "Lock" again to revert.', 'Persona unlocked');
|
toastr.info('User persona is now unlocked for this chat. Click the "Lock" again to revert.', 'Persona unlocked');
|
||||||
}
|
}
|
||||||
@ -4907,7 +4946,7 @@ function lockUserNameToChat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
chat_metadata['persona'] = user_avatar;
|
chat_metadata['persona'] = user_avatar;
|
||||||
saveMetadata();
|
await saveMetadata();
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
console.log(`Locking persona for this chat ${user_avatar}`);
|
console.log(`Locking persona for this chat ${user_avatar}`);
|
||||||
if (power_user.persona_show_notifications) {
|
if (power_user.persona_show_notifications) {
|
||||||
@ -6006,23 +6045,38 @@ function hideSwipeButtons() {
|
|||||||
|
|
||||||
async function saveMetadata() {
|
async function saveMetadata() {
|
||||||
if (selected_group) {
|
if (selected_group) {
|
||||||
await editGroup(selected_group, false, false);
|
await editGroup(selected_group, true, false);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
saveChatDebounced();
|
await saveChatConditional();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function saveChatConditional() {
|
export async function saveChatConditional() {
|
||||||
if (selected_group) {
|
try {
|
||||||
await saveGroupChat(selected_group, true);
|
await waitUntilCondition(() => !isChatSaving, durationSaveEdit, 100);
|
||||||
}
|
} catch {
|
||||||
else {
|
console.warn('Timeout waiting for chat to save');
|
||||||
await saveChat();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save token cache to IndexedDB storage
|
try {
|
||||||
await saveTokenCache();
|
isChatSaving = true;
|
||||||
|
|
||||||
|
if (selected_group) {
|
||||||
|
await saveGroupChat(selected_group, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await saveChat();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save token cache to IndexedDB storage
|
||||||
|
saveTokenCache();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error saving chat', error);
|
||||||
|
} finally {
|
||||||
|
isChatSaving = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function importCharacterChat(formData) {
|
async function importCharacterChat(formData) {
|
||||||
@ -6454,58 +6508,6 @@ async function createOrEditCharacter(e) {
|
|||||||
contentType: false,
|
contentType: false,
|
||||||
processData: false,
|
processData: false,
|
||||||
success: async function (html) {
|
success: async function (html) {
|
||||||
if (chat.length === 1 && !selected_group) {
|
|
||||||
var this_ch_mes = default_ch_mes;
|
|
||||||
|
|
||||||
if ($("#firstmessage_textarea").val() != "") {
|
|
||||||
this_ch_mes = $("#firstmessage_textarea").val();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
this_ch_mes !=
|
|
||||||
$.trim(
|
|
||||||
$("#chat")
|
|
||||||
.children(".mes")
|
|
||||||
.children(".mes_block")
|
|
||||||
.children(".mes_text")
|
|
||||||
.text()
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
// MARK - kingbri: Regex on character greeting message
|
|
||||||
// May need to be placed somewhere else
|
|
||||||
this_ch_mes = getRegexedString(this_ch_mes, regex_placement.AI_OUTPUT);
|
|
||||||
|
|
||||||
clearChat();
|
|
||||||
chat.length = 0;
|
|
||||||
chat[0] = {};
|
|
||||||
chat[0]["name"] = name2;
|
|
||||||
chat[0]["is_user"] = false;
|
|
||||||
chat[0]["is_name"] = true;
|
|
||||||
chat[0]["mes"] = this_ch_mes;
|
|
||||||
chat[0]["extra"] = {};
|
|
||||||
chat[0]["send_date"] = getMessageTimeStamp();
|
|
||||||
|
|
||||||
const alternateGreetings = characters[this_chid]?.data?.alternate_greetings;
|
|
||||||
|
|
||||||
if (Array.isArray(alternateGreetings) && alternateGreetings.length > 0) {
|
|
||||||
chat[0]['swipe_id'] = 0;
|
|
||||||
chat[0]['swipes'] = [];
|
|
||||||
chat[0]['swipe_info'] = [];
|
|
||||||
chat[0]['swipes'][0] = chat[0]['mes'];
|
|
||||||
|
|
||||||
for (let i = 0; i < alternateGreetings.length; i++) {
|
|
||||||
const alternateGreeting = getRegexedString(alternateGreetings[i], regex_placement.AI_OUTPUT);
|
|
||||||
chat[0]['swipes'].push(substituteParams(alternateGreeting));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
add_mes_without_animation = true;
|
|
||||||
//console.log('form create submission calling addOneMessage');
|
|
||||||
await eventSource.emit(event_types.MESSAGE_RECEIVED, (chat.length - 1));
|
|
||||||
addOneMessage(chat[0]);
|
|
||||||
await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, (chat.length - 1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$("#create_button").removeAttr("disabled");
|
$("#create_button").removeAttr("disabled");
|
||||||
|
|
||||||
await getOneCharacter(formData.get('avatar_url'));
|
await getOneCharacter(formData.get('avatar_url'));
|
||||||
@ -6516,6 +6518,17 @@ async function createOrEditCharacter(e) {
|
|||||||
$("#create_button").attr("value", "Save");
|
$("#create_button").attr("value", "Save");
|
||||||
crop_data = undefined;
|
crop_data = undefined;
|
||||||
eventSource.emit(event_types.CHARACTER_EDITED, { detail: { id: this_chid, character: characters[this_chid] } });
|
eventSource.emit(event_types.CHARACTER_EDITED, { detail: { id: this_chid, character: characters[this_chid] } });
|
||||||
|
|
||||||
|
if (chat.length === 1 && !selected_group) {
|
||||||
|
const firstMessage = getFirstMessage();
|
||||||
|
chat[0] = firstMessage;
|
||||||
|
|
||||||
|
await eventSource.emit(event_types.MESSAGE_RECEIVED, (chat.length - 1));
|
||||||
|
clearChat();
|
||||||
|
printMessages();
|
||||||
|
await eventSource.emit(event_types.CHARACTER_MESSAGE_RENDERED, (chat.length - 1));
|
||||||
|
await saveChatConditional();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error: function (jqXHR, exception) {
|
error: function (jqXHR, exception) {
|
||||||
$("#create_button").removeAttr("disabled");
|
$("#create_button").removeAttr("disabled");
|
||||||
@ -7630,11 +7643,11 @@ $(document).ready(function () {
|
|||||||
else {
|
else {
|
||||||
if (characters[this_chid].chat == old_filename) {
|
if (characters[this_chid].chat == old_filename) {
|
||||||
characters[this_chid].chat = newName;
|
characters[this_chid].chat = newName;
|
||||||
saveCharacterDebounced();
|
await createOrEditCharacter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
reloadCurrentChat();
|
await reloadCurrentChat();
|
||||||
|
|
||||||
await delay(250);
|
await delay(250);
|
||||||
$("#option_select_chat").trigger('click');
|
$("#option_select_chat").trigger('click');
|
||||||
|
@ -14,7 +14,37 @@ export {
|
|||||||
let extensionNames = [];
|
let extensionNames = [];
|
||||||
let manifests = {};
|
let manifests = {};
|
||||||
const defaultUrl = "http://localhost:5100";
|
const defaultUrl = "http://localhost:5100";
|
||||||
export const saveMetadataDebounced = debounce(async () => await getContext().saveMetadata(), 1000);
|
|
||||||
|
let saveMetadataTimeout = null;
|
||||||
|
|
||||||
|
export function saveMetadataDebounced() {
|
||||||
|
const context = getContext();
|
||||||
|
const groupId = context.groupId;
|
||||||
|
const characterId = context.characterId;
|
||||||
|
|
||||||
|
if (saveMetadataTimeout) {
|
||||||
|
console.debug('Clearing save metadata timeout');
|
||||||
|
clearTimeout(saveMetadataTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
saveMetadataTimeout = setTimeout(async () => {
|
||||||
|
const newContext = getContext();
|
||||||
|
|
||||||
|
if (groupId !== newContext.groupId) {
|
||||||
|
console.warn('Group changed, not saving metadata');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (characterId !== newContext.characterId) {
|
||||||
|
console.warn('Character changed, not saving metadata');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.debug('Saving metadata...');
|
||||||
|
newContext.saveMetadata();
|
||||||
|
console.debug('Saved metadata...');
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
export const extensionsHandlebars = Handlebars.create();
|
export const extensionsHandlebars = Handlebars.create();
|
||||||
|
|
||||||
|
@ -164,7 +164,7 @@ function getNextIncompleteTaskRecurse(task){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set a task in extensionPrompt context. Defaults to first incomplete
|
// Set a task in extensionPrompt context. Defaults to first incomplete
|
||||||
function setCurrentTask(taskId = null) {
|
function setCurrentTask(taskId = null, skipSave = false) {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
|
|
||||||
// TODO: Should probably null this rather than set empty object
|
// TODO: Should probably null this rather than set empty object
|
||||||
@ -202,7 +202,10 @@ function setCurrentTask(taskId = null) {
|
|||||||
console.info(`No current task`);
|
console.info(`No current task`);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveState();
|
// Save state if not skipping
|
||||||
|
if (!skipSave) {
|
||||||
|
saveState();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHighestTaskIdRecurse(task) {
|
function getHighestTaskIdRecurse(task) {
|
||||||
@ -731,7 +734,7 @@ function loadSettings() {
|
|||||||
$('#objective-check-frequency').val(chat_metadata['objective'].checkFrequency)
|
$('#objective-check-frequency').val(chat_metadata['objective'].checkFrequency)
|
||||||
$('#objective-hide-tasks').prop('checked', chat_metadata['objective'].hideTasks)
|
$('#objective-hide-tasks').prop('checked', chat_metadata['objective'].hideTasks)
|
||||||
$('#objective-tasks').prop('hidden', $('#objective-hide-tasks').prop('checked'))
|
$('#objective-tasks').prop('hidden', $('#objective-hide-tasks').prop('checked'))
|
||||||
setCurrentTask()
|
setCurrentTask(null, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
function addManualTaskCheckUi() {
|
function addManualTaskCheckUi() {
|
||||||
|
@ -63,6 +63,7 @@ import {
|
|||||||
setScenarioOverride,
|
setScenarioOverride,
|
||||||
getCropPopup,
|
getCropPopup,
|
||||||
system_avatar,
|
system_avatar,
|
||||||
|
isChatSaving,
|
||||||
} from "../script.js";
|
} from "../script.js";
|
||||||
import { appendTagToList, createTagMapFromList, getTagsList, applyTagsOnCharacterSelect, tag_map, printTagFilters } from './tags.js';
|
import { appendTagToList, createTagMapFromList, getTagsList, applyTagsOnCharacterSelect, tag_map, printTagFilters } from './tags.js';
|
||||||
import { FILTER_TYPES, FilterHelper } from './filters.js';
|
import { FILTER_TYPES, FilterHelper } from './filters.js';
|
||||||
@ -1272,6 +1273,11 @@ function updateFavButtonState(state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function openGroupById(groupId) {
|
export async function openGroupById(groupId) {
|
||||||
|
if (isChatSaving) {
|
||||||
|
toastr.info("Please wait until the chat is saved before switching characters.", "Your chat is still saving...");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!groups.find(x => x.id === groupId)) {
|
if (!groups.find(x => x.id === groupId)) {
|
||||||
console.log('Group not found', groupId);
|
console.log('Group not found', groupId);
|
||||||
return;
|
return;
|
||||||
|
Reference in New Issue
Block a user