mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
123
public/script.js
123
public/script.js
@ -391,8 +391,8 @@ DOMPurify.addHook('uponSanitizeElement', (node, _, config) => {
|
||||
|
||||
if (localStorage.getItem(warningShownKey) === null) {
|
||||
const warningToast = toastr.warning(
|
||||
'Use the "Ext. Media" button to allow it. Click on this message to dismiss.',
|
||||
'External media has been blocked',
|
||||
t`Use the 'Ext. Media' button to allow it. Click on this message to dismiss.`,
|
||||
t`External media has been blocked`,
|
||||
{
|
||||
timeOut: 0,
|
||||
preventDuplicates: true,
|
||||
@ -933,7 +933,7 @@ async function firstLoadInit() {
|
||||
token = tokenData.token;
|
||||
} catch {
|
||||
hideLoader();
|
||||
toastr.error('Couldn\'t get CSRF token. Please refresh the page.', 'Error', { timeOut: 0, extendedTimeOut: 0, preventDuplicates: true });
|
||||
toastr.error(t`Couldn't get CSRF token. Please refresh the page.`, t`Error`, { timeOut: 0, extendedTimeOut: 0, preventDuplicates: true });
|
||||
throw new Error('Initialization failed');
|
||||
}
|
||||
|
||||
@ -1149,7 +1149,7 @@ async function getStatusKobold() {
|
||||
|
||||
// We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress.
|
||||
if (online_status === 'no_connection' && data.response) {
|
||||
toastr.error(data.response, 'API Error', { timeOut: 5000, preventDuplicates: true });
|
||||
toastr.error(data.response, t`API Error`, { timeOut: 5000, preventDuplicates: true });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Error getting status', err);
|
||||
@ -1235,7 +1235,7 @@ async function getStatusTextgen() {
|
||||
|
||||
// We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress.
|
||||
if (online_status === 'no_connection' && data.response) {
|
||||
toastr.error(data.response, 'API Error', { timeOut: 5000, preventDuplicates: true });
|
||||
toastr.error(data.response, t`API Error`, { timeOut: 5000, preventDuplicates: true });
|
||||
}
|
||||
} catch (err) {
|
||||
if (err instanceof AbortReason) {
|
||||
@ -1287,7 +1287,7 @@ export async function selectCharacterById(id) {
|
||||
}
|
||||
|
||||
if (isChatSaving) {
|
||||
toastr.info('Please wait until the chat is saved before switching characters.', 'Your chat is still saving...');
|
||||
toastr.info(t`Please wait until the chat is saved before switching characters.`, t`Your chat is still saving...`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1641,7 +1641,7 @@ export async function getOneCharacter(avatarUrl) {
|
||||
if (indexOf !== -1) {
|
||||
characters[indexOf] = getData;
|
||||
} else {
|
||||
toastr.error(`Character ${avatarUrl} not found in the list`, 'Error', { timeOut: 5000, preventDuplicates: true });
|
||||
toastr.error(t`Character ${avatarUrl} not found in the list`, t`Error`, { timeOut: 5000, preventDuplicates: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3408,7 +3408,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
await eventSource.emit(event_types.GENERATION_AFTER_COMMANDS, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun);
|
||||
|
||||
if (main_api == 'kobold' && kai_settings.streaming_kobold && !kai_flags.can_use_streaming) {
|
||||
toastr.error('Streaming is enabled, but the version of Kobold used does not support token streaming.', undefined, { timeOut: 10000, preventDuplicates: true });
|
||||
toastr.error(t`Streaming is enabled, but the version of Kobold used does not support token streaming.`, undefined, { timeOut: 10000, preventDuplicates: true });
|
||||
unblockGeneration(type);
|
||||
return Promise.resolve();
|
||||
}
|
||||
@ -3417,7 +3417,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
textgen_settings.streaming &&
|
||||
textgen_settings.legacy_api &&
|
||||
textgen_settings.type === OOBA) {
|
||||
toastr.error('Streaming is not supported for the Legacy API. Update Ooba and use new API to enable streaming.', undefined, { timeOut: 10000, preventDuplicates: true });
|
||||
toastr.error(t`Streaming is not supported for the Legacy API. Update Ooba and use new API to enable streaming.`, undefined, { timeOut: 10000, preventDuplicates: true });
|
||||
unblockGeneration(type);
|
||||
return Promise.resolve();
|
||||
}
|
||||
@ -3433,7 +3433,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
|
||||
if (!pingResult) {
|
||||
unblockGeneration(type);
|
||||
toastr.error('Verify that the server is running and accessible.', 'ST Server cannot be reached');
|
||||
toastr.error(t`Verify that the server is running and accessible.`, t`ST Server cannot be reached`);
|
||||
throw new Error('Server unreachable');
|
||||
}
|
||||
|
||||
@ -4461,7 +4461,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
generatedPromptCache = '';
|
||||
|
||||
if (data?.response) {
|
||||
toastr.error(data.response, 'API Error', { preventDuplicates: true });
|
||||
toastr.error(data.response, t`API Error`, { preventDuplicates: true });
|
||||
}
|
||||
throw new Error(data?.response);
|
||||
}
|
||||
@ -4552,7 +4552,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
||||
|
||||
function onError(exception) {
|
||||
if (typeof exception?.error?.message === 'string') {
|
||||
toastr.error(exception.error.message, 'Error', { timeOut: 10000, extendedTimeOut: 20000 });
|
||||
toastr.error(exception.error.message, t`Error`, { timeOut: 10000, extendedTimeOut: 20000 });
|
||||
}
|
||||
|
||||
generatedPromptCache = '';
|
||||
@ -4956,7 +4956,7 @@ function addChatsSeparator(mesSendString) {
|
||||
|
||||
async function duplicateCharacter() {
|
||||
if (!this_chid) {
|
||||
toastr.warning('You must first select a character to duplicate!');
|
||||
toastr.warning(t`You must first select a character to duplicate!`);
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -4975,7 +4975,7 @@ async function duplicateCharacter() {
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
if (response.ok) {
|
||||
toastr.success('Character Duplicated');
|
||||
toastr.success(t`Character Duplicated`);
|
||||
const data = await response.json();
|
||||
await eventSource.emit(event_types.CHARACTER_DUPLICATED, { oldAvatar: body.avatar_url, newAvatar: data.path });
|
||||
await getCharacters();
|
||||
@ -5822,23 +5822,23 @@ export function setSendButtonState(value) {
|
||||
|
||||
export async function renameCharacter(name = null, { silent = false, renameChats = null } = {}) {
|
||||
if (!name && silent) {
|
||||
toastr.warning('No character name provided.', 'Rename Character');
|
||||
toastr.warning(t`No character name provided.`, t`Rename Character`);
|
||||
return false;
|
||||
}
|
||||
if (this_chid === undefined) {
|
||||
toastr.warning('No character selected.', 'Rename Character');
|
||||
toastr.warning(t`No character selected.`, t`Rename Character`);
|
||||
return false;
|
||||
}
|
||||
|
||||
const oldAvatar = characters[this_chid].avatar;
|
||||
const newValue = name || await callGenericPopup('<h3>New name:</h3>', POPUP_TYPE.INPUT, characters[this_chid].name);
|
||||
const newValue = name || await callGenericPopup('<h3>' + t`New name:` + '</h3>', POPUP_TYPE.INPUT, characters[this_chid].name);
|
||||
|
||||
if (!newValue) {
|
||||
toastr.warning('No character name provided.', 'Rename Character');
|
||||
toastr.warning(t`No character name provided.`, t`Rename Character`);
|
||||
return false;
|
||||
}
|
||||
if (newValue === characters[this_chid].name) {
|
||||
toastr.info('Same character name provided, so name did not change.', 'Rename Character');
|
||||
toastr.info(t`Same character name provided, so name did not change.`, t`Rename Character`);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5885,9 +5885,9 @@ export async function renameCharacter(name = null, { silent = false, renameChats
|
||||
if (renamePastChatsConfirm) {
|
||||
await renamePastChats(newAvatar, newValue);
|
||||
await reloadCurrentChat();
|
||||
toastr.success('Character renamed and past chats updated!', 'Rename Character');
|
||||
toastr.success(t`Character renamed and past chats updated!`, t`Rename Character`);
|
||||
} else {
|
||||
toastr.success('Character renamed!', 'Rename Character');
|
||||
toastr.success(t`Character renamed!`, t`Rename Character`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -5900,8 +5900,8 @@ export async function renameCharacter(name = null, { silent = false, renameChats
|
||||
}
|
||||
catch (error) {
|
||||
// Reloading to prevent data corruption
|
||||
if (!silent) await callPopup('Something went wrong. The page will be reloaded.', 'text');
|
||||
else toastr.error('Something went wrong. The page will be reloaded.', 'Rename Character');
|
||||
if (!silent) await callPopup(t`Something went wrong. The page will be reloaded.`, 'text');
|
||||
else toastr.error(t`Something went wrong. The page will be reloaded.`, t`Rename Character`);
|
||||
|
||||
console.log('Renaming character error:', error);
|
||||
location.reload();
|
||||
@ -5958,7 +5958,7 @@ async function renamePastChats(newAvatar, newValue) {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
toastr.error(`Past chat could not be updated: ${file_name}`);
|
||||
toastr.error(t`Past chat could not be updated: ${file_name}`);
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
@ -6007,7 +6007,7 @@ export async function saveChat(chatName, withMetadata, mesId) {
|
||||
characters[this_chid]['date_last_chat'] = Date.now();
|
||||
chat.forEach(function (item, i) {
|
||||
if (item['is_group']) {
|
||||
toastr.error('Trying to save group chat with regular saveChat function. Aborting to prevent corruption.');
|
||||
toastr.error(t`Trying to save group chat with regular saveChat function. Aborting to prevent corruption.`);
|
||||
throw new Error('Group chat saved from saveChat');
|
||||
}
|
||||
/*
|
||||
@ -6052,7 +6052,7 @@ export async function saveChat(chatName, withMetadata, mesId) {
|
||||
contentType: 'application/json',
|
||||
success: function (data) { },
|
||||
error: function (jqXHR, exception) {
|
||||
toastr.error('Check the server connection and reload the page to prevent data loss.', 'Chat could not be saved');
|
||||
toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Chat could not be saved`);
|
||||
console.log(exception);
|
||||
console.log(jqXHR);
|
||||
},
|
||||
@ -6449,7 +6449,7 @@ export async function getSettings() {
|
||||
|
||||
if (!response.ok) {
|
||||
reloadLoop();
|
||||
toastr.error('Settings could not be loaded after multiple attempts. Please try again later.');
|
||||
toastr.error(t`Settings could not be loaded after multiple attempts. Please try again later.`);
|
||||
throw new Error('Error getting settings');
|
||||
}
|
||||
|
||||
@ -6676,7 +6676,7 @@ export async function saveSettings(type) {
|
||||
eventSource.emit(event_types.SETTINGS_UPDATED);
|
||||
},
|
||||
error: function (jqXHR, exception) {
|
||||
toastr.error('Check the server connection and reload the page to prevent data loss.', 'Settings could not be saved');
|
||||
toastr.error(t`Check the server connection and reload the page to prevent data loss.t`, t`Settings could not be saved`);
|
||||
console.log(exception);
|
||||
console.log(jqXHR);
|
||||
},
|
||||
@ -6942,7 +6942,7 @@ export async function displayPastChats() {
|
||||
const data = await (selected_group ? getGroupPastChats(selected_group) : getPastCharacterChats());
|
||||
|
||||
if (!data) {
|
||||
toastr.error('Could not load chat data. Try reloading the page.');
|
||||
toastr.error(t`Could not load chat data. Try reloading the page.`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -7075,7 +7075,7 @@ export function selectRightMenuWithAnimation(selectedMenuId) {
|
||||
|
||||
export function select_rm_info(type, charId, previousCharId = null) {
|
||||
if (!type) {
|
||||
toastr.error('Invalid process (no \'type\')');
|
||||
toastr.error(t`Invalid process (no 'type')`);
|
||||
return;
|
||||
}
|
||||
if (type !== 'group_create') {
|
||||
@ -7083,20 +7083,20 @@ export function select_rm_info(type, charId, previousCharId = null) {
|
||||
}
|
||||
|
||||
if (type === 'char_delete') {
|
||||
toastr.warning(`Character Deleted: ${displayName}`);
|
||||
toastr.warning(t`Character Deleted: ${displayName}`);
|
||||
}
|
||||
if (type === 'char_create') {
|
||||
toastr.success(`Character Created: ${displayName}`);
|
||||
toastr.success(t`Character Created: ${displayName}`);
|
||||
}
|
||||
if (type === 'group_create') {
|
||||
toastr.success('Group Created');
|
||||
toastr.success(t`Group Created`);
|
||||
}
|
||||
if (type === 'group_delete') {
|
||||
toastr.warning('Group Deleted');
|
||||
toastr.warning(t`Group Deleted`);
|
||||
}
|
||||
|
||||
if (type === 'char_import') {
|
||||
toastr.success(`Character Imported: ${displayName}`);
|
||||
toastr.success(t`Character Imported: ${displayName}`);
|
||||
}
|
||||
|
||||
selectRightMenuWithAnimation('rm_characters_block');
|
||||
@ -7554,25 +7554,25 @@ export function hideSwipeButtons() {
|
||||
*/
|
||||
export async function deleteSwipe(swipeId = null) {
|
||||
if (swipeId && (isNaN(swipeId) || swipeId < 0)) {
|
||||
toastr.warning(`Invalid swipe ID: ${swipeId + 1}`);
|
||||
toastr.warning(t`Invalid swipe ID: ${swipeId + 1}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const lastMessage = chat[chat.length - 1];
|
||||
if (!lastMessage || !Array.isArray(lastMessage.swipes) || !lastMessage.swipes.length) {
|
||||
toastr.warning('No messages to delete swipes from.');
|
||||
toastr.warning(t`No messages to delete swipes from.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (lastMessage.swipes.length <= 1) {
|
||||
toastr.warning('Can\'t delete the last swipe.');
|
||||
toastr.warning(t`Can't delete the last swipe.`);
|
||||
return;
|
||||
}
|
||||
|
||||
swipeId = swipeId ?? lastMessage.swipe_id;
|
||||
|
||||
if (swipeId < 0 || swipeId >= lastMessage.swipes.length) {
|
||||
toastr.warning(`Invalid swipe ID: ${swipeId + 1}`);
|
||||
toastr.warning(t`Invalid swipe ID: ${swipeId + 1}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -7711,7 +7711,7 @@ export function setGenerationProgress(progress) {
|
||||
|
||||
function isHordeGenerationNotAllowed() {
|
||||
if (main_api == 'koboldhorde' && preset_settings == 'gui') {
|
||||
toastr.error('GUI Settings preset is not supported for Horde. Please select another preset.');
|
||||
toastr.error(t`GUI Settings preset is not supported for Horde. Please select another preset.`);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -7760,7 +7760,7 @@ function openCharacterWorldPopup() {
|
||||
}
|
||||
|
||||
$('#character_json_data').val(JSON.stringify(data));
|
||||
toastr.info('Embedded lorebook will be removed from this character.');
|
||||
toastr.info(t`Embedded lorebook will be removed from this character.`);
|
||||
} catch {
|
||||
console.error('Failed to parse character JSON data.');
|
||||
}
|
||||
@ -7951,11 +7951,11 @@ async function createOrEditCharacter(e) {
|
||||
|
||||
if ($('#form_create').attr('actiontype') == 'createcharacter') {
|
||||
if (String($('#character_name_pole').val()).length === 0) {
|
||||
toastr.error('Name is required');
|
||||
toastr.error(t`Name is required`);
|
||||
return;
|
||||
}
|
||||
if (is_group_generating || is_send_press) {
|
||||
toastr.error('Cannot create characters while generating. Stop the request and try again.', 'Creation aborted');
|
||||
toastr.error(t`Cannot create characters while generating. Stop the request and try again.`, t`Creation aborted`);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@ -8039,7 +8039,7 @@ async function createOrEditCharacter(e) {
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error creating character', error);
|
||||
toastr.error('Failed to create character');
|
||||
toastr.error(t`Failed to create character`);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
@ -8098,7 +8098,7 @@ async function createOrEditCharacter(e) {
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
toastr.error('Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.');
|
||||
toastr.error(t`Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8604,7 +8604,7 @@ async function selectContextCallback(args, name) {
|
||||
const result = fuse.search(name);
|
||||
|
||||
if (result.length === 0) {
|
||||
!quiet && toastr.warning(`Context template "${name}" not found`);
|
||||
!quiet && toastr.warning(t`Context template '${name}' not found`);
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -8624,7 +8624,7 @@ async function selectInstructCallback(args, name) {
|
||||
const result = fuse.search(name);
|
||||
|
||||
if (result.length === 0) {
|
||||
!quiet && toastr.warning(`Instruct template "${name}" not found`);
|
||||
!quiet && toastr.warning(t`Instruct template '${name}' not found`);
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -8676,7 +8676,7 @@ async function connectAPISlash(args, text) {
|
||||
|
||||
const apiConfig = CONNECT_API_MAP[text.toLowerCase()];
|
||||
if (!apiConfig) {
|
||||
toastr.error(`Error: ${text} is not a valid API`);
|
||||
toastr.error(t`Error: ${text} is not a valid API`);
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -8705,7 +8705,7 @@ async function connectAPISlash(args, text) {
|
||||
}
|
||||
|
||||
const quiet = isTrueBoolean(args?.quiet);
|
||||
const toast = quiet ? jQuery() : toastr.info(`API set to ${text}, trying to connect..`);
|
||||
const toast = quiet ? jQuery() : toastr.info(t`API set to ${text}, trying to connect..`);
|
||||
|
||||
try {
|
||||
await waitUntilCondition(() => online_status !== 'no_connection', 10000, 100);
|
||||
@ -8744,7 +8744,7 @@ export async function processDroppedFiles(files, data = new Map()) {
|
||||
const preservedName = data instanceof Map && data.get(file);
|
||||
await importCharacter(file, preservedName);
|
||||
} else {
|
||||
toastr.warning('Unsupported file type: ' + file.name);
|
||||
toastr.warning(t`Unsupported file type: ` + file.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8757,7 +8757,7 @@ export async function processDroppedFiles(files, data = new Map()) {
|
||||
*/
|
||||
async function importCharacter(file, preserveFileName = '') {
|
||||
if (is_group_generating || is_send_press) {
|
||||
toastr.error('Cannot import characters while generating. Stop the request and try again.', 'Import aborted');
|
||||
toastr.error(t`Cannot import characters while generating. Stop the request and try again.`, t`Import aborted`);
|
||||
throw new Error('Cannot import character while generating');
|
||||
}
|
||||
|
||||
@ -8784,7 +8784,7 @@ async function importCharacter(file, preserveFileName = '') {
|
||||
});
|
||||
|
||||
if (data.error) {
|
||||
toastr.error('The file is likely invalid or corrupted.', 'Could not import character');
|
||||
toastr.error(t`The file is likely invalid or corrupted.`, t`Could not import character`);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -8837,7 +8837,7 @@ async function doImpersonate(args, prompt) {
|
||||
await waitUntilCondition(() => !is_send_press && !is_group_generating, 10000, 100);
|
||||
} catch {
|
||||
console.warn('Timeout waiting for generation unlock');
|
||||
toastr.warning('Cannot run /impersonate command while the reply is being generated.');
|
||||
toastr.warning(t`Cannot run /impersonate command while the reply is being generated.`);
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -8899,19 +8899,19 @@ async function doDeleteChat() {
|
||||
|
||||
async function doRenameChat(_, chatName) {
|
||||
if (!chatName) {
|
||||
toastr.warning('Name must be provided as an argument to rename this chat.');
|
||||
toastr.warning(t`Name must be provided as an argument to rename this chat.`);
|
||||
return '';
|
||||
}
|
||||
|
||||
const currentChatName = getCurrentChatId();
|
||||
if (!currentChatName) {
|
||||
toastr.warning('No chat selected that can be renamed.');
|
||||
toastr.warning(t`No chat selected that can be renamed.`);
|
||||
return '';
|
||||
}
|
||||
|
||||
await renameChat(currentChatName, chatName);
|
||||
|
||||
toastr.success(`Successfully renamed chat to: ${chatName}`);
|
||||
toastr.success(t`Successfully renamed chat to: ${chatName}`);
|
||||
return '';
|
||||
}
|
||||
|
||||
@ -9026,7 +9026,7 @@ export async function deleteCharacter(characterKey, { deleteChats = true } = {})
|
||||
for (const key of characterKey) {
|
||||
const character = characters.find(x => x.avatar == key);
|
||||
if (!character) {
|
||||
toastr.warning(`Character ${key} not found. Skipping deletion.`);
|
||||
toastr.warning(t`Character ${key} not found. Skipping deletion.`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -9043,7 +9043,7 @@ export async function deleteCharacter(characterKey, { deleteChats = true } = {})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
toastr.error(`${response.status} ${response.statusText}`, 'Failed to delete character');
|
||||
toastr.error(`${response.status} ${response.statusText}`, t`Failed to delete character`);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -9802,12 +9802,7 @@ jQuery(async function () {
|
||||
|
||||
let deleteChats = false;
|
||||
|
||||
const confirm = await Popup.show.confirm('Delete the character?', `
|
||||
<b>THIS IS PERMANENT!<br><br>
|
||||
<label for="del_char_checkbox" class="checkbox_label justifyCenter">
|
||||
<input type="checkbox" id="del_char_checkbox" />
|
||||
<small>Also delete the chat files</small>
|
||||
</label></b>`, {
|
||||
const confirm = await Popup.show.confirm(t`Delete the character?`, await renderTemplateAsync('deleteConfirm'), {
|
||||
onClose: () => deleteChats = !!$('#del_char_checkbox').prop('checked'),
|
||||
});
|
||||
if (!confirm) {
|
||||
|
Reference in New Issue
Block a user