mirror of
				https://github.com/SillyTavern/SillyTavern.git
				synced 2025-06-05 21:59:27 +02:00 
			
		
		
		
	@@ -8,6 +8,7 @@ import { debounce, waitUntilCondition, escapeHtml } from './utils.js';
 | 
			
		||||
import { debounce_timeout } from './constants.js';
 | 
			
		||||
import { renderTemplateAsync } from './templates.js';
 | 
			
		||||
import { Popup } from './popup.js';
 | 
			
		||||
import { t } from './i18n.js';
 | 
			
		||||
 | 
			
		||||
function debouncePromise(func, delay) {
 | 
			
		||||
    let timeoutId;
 | 
			
		||||
@@ -455,7 +456,7 @@ class PromptManager {
 | 
			
		||||
 | 
			
		||||
        // Delete selected prompt from list form and close edit form
 | 
			
		||||
        this.handleDeletePrompt = async (event) => {
 | 
			
		||||
            Popup.show.confirm('Are you sure you want to delete this prompt?', null).then((userChoice) => {
 | 
			
		||||
            Popup.show.confirm(t`Are you sure you want to delete this prompt?`, null).then((userChoice) => {
 | 
			
		||||
                if (!userChoice) return;
 | 
			
		||||
                const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value;
 | 
			
		||||
                const prompt = this.getPromptById(promptID);
 | 
			
		||||
@@ -531,7 +532,7 @@ class PromptManager {
 | 
			
		||||
 | 
			
		||||
        // Import prompts for the selected character
 | 
			
		||||
        this.handleImport = () => {
 | 
			
		||||
            Popup.show.confirm('Existing prompts with the same ID will be overridden. Do you want to proceed?', null)
 | 
			
		||||
            Popup.show.confirm(t`Existing prompts with the same ID will be overridden. Do you want to proceed?`, null)
 | 
			
		||||
                .then(userChoice => {
 | 
			
		||||
                    if (!userChoice) return;
 | 
			
		||||
 | 
			
		||||
@@ -552,7 +553,7 @@ class PromptManager {
 | 
			
		||||
                                const data = JSON.parse(fileContent);
 | 
			
		||||
                                this.import(data);
 | 
			
		||||
                            } catch (err) {
 | 
			
		||||
                                toastr.error('An error occurred while importing prompts. More info available in console.');
 | 
			
		||||
                                toastr.error(t`An error occurred while importing prompts. More info available in console.`);
 | 
			
		||||
                                console.log('An error occurred while importing prompts');
 | 
			
		||||
                                console.log(err.toString());
 | 
			
		||||
                            }
 | 
			
		||||
@@ -567,7 +568,7 @@ class PromptManager {
 | 
			
		||||
 | 
			
		||||
        // Restore default state of a characters prompt order
 | 
			
		||||
        this.handleCharacterReset = () => {
 | 
			
		||||
            Popup.show.confirm('This will reset the prompt order for this character. You will not lose any prompts.', null)
 | 
			
		||||
            Popup.show.confirm(t`This will reset the prompt order for this character. You will not lose any prompts.`, null)
 | 
			
		||||
                .then(userChoice => {
 | 
			
		||||
                    if (!userChoice) return;
 | 
			
		||||
 | 
			
		||||
@@ -1649,7 +1650,7 @@ class PromptManager {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (false === this.validateObject(controlObj, importData)) {
 | 
			
		||||
            toastr.warning('Could not import prompts. Export failed validation.');
 | 
			
		||||
            toastr.warning(t`Could not import prompts. Export failed validation.`);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1672,7 +1673,7 @@ class PromptManager {
 | 
			
		||||
            throw new Error('Prompt order strategy not supported.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        toastr.success('Prompt import complete.');
 | 
			
		||||
        toastr.success(t`Prompt import complete.`);
 | 
			
		||||
        this.saveServiceSettings().then(() => this.render());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
 | 
			
		||||
import { SlashCommand } from './slash-commands/SlashCommand.js';
 | 
			
		||||
import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
 | 
			
		||||
export { MODULE_NAME as NOTE_MODULE_NAME };
 | 
			
		||||
import { t } from './i18n.js';
 | 
			
		||||
 | 
			
		||||
const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory
 | 
			
		||||
 | 
			
		||||
@@ -37,7 +38,7 @@ const chara_note_position = {
 | 
			
		||||
 | 
			
		||||
function setNoteTextCommand(_, text) {
 | 
			
		||||
    $('#extension_floating_prompt').val(text).trigger('input');
 | 
			
		||||
    toastr.success('Author\'s Note text updated');
 | 
			
		||||
    toastr.success(t`Author's Note text updated`);
 | 
			
		||||
    return '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -45,12 +46,12 @@ function setNoteDepthCommand(_, text) {
 | 
			
		||||
    const value = Number(text);
 | 
			
		||||
 | 
			
		||||
    if (Number.isNaN(value)) {
 | 
			
		||||
        toastr.error('Not a valid number');
 | 
			
		||||
        toastr.error(t`Not a valid number`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $('#extension_floating_depth').val(Math.abs(value)).trigger('input');
 | 
			
		||||
    toastr.success('Author\'s Note depth updated');
 | 
			
		||||
    toastr.success(t`Author's Note depth updated`);
 | 
			
		||||
    return '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -58,12 +59,12 @@ function setNoteIntervalCommand(_, text) {
 | 
			
		||||
    const value = Number(text);
 | 
			
		||||
 | 
			
		||||
    if (Number.isNaN(value)) {
 | 
			
		||||
        toastr.error('Not a valid number');
 | 
			
		||||
        toastr.error(t`Not a valid number`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $('#extension_floating_interval').val(Math.abs(value)).trigger('input');
 | 
			
		||||
    toastr.success('Author\'s Note frequency updated');
 | 
			
		||||
    toastr.success(t`Author's Note frequency updated`);
 | 
			
		||||
    return '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -76,12 +77,12 @@ function setNotePositionCommand(_, text) {
 | 
			
		||||
    const position = validPositions[text?.trim()];
 | 
			
		||||
 | 
			
		||||
    if (Number.isNaN(position)) {
 | 
			
		||||
        toastr.error('Not a valid position');
 | 
			
		||||
        toastr.error(t`Not a valid position`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $(`input[name="extension_floating_position"][value="${position}"]`).prop('checked', true).trigger('input');
 | 
			
		||||
    toastr.info('Author\'s Note position updated');
 | 
			
		||||
    toastr.info(t`Author's Note position updated`);
 | 
			
		||||
    return '';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -206,7 +207,7 @@ function onExtensionFloatingCharaPromptInput() {
 | 
			
		||||
        extension_settings.note.chara.push(tempCharaNote);
 | 
			
		||||
    } else {
 | 
			
		||||
        console.log('Character author\'s note error: No avatar name key could be found.');
 | 
			
		||||
        toastr.error('Something went wrong. Could not save character\'s author\'s note.');
 | 
			
		||||
        toastr.error(t`Something went wrong. Could not save character's author's note.`);
 | 
			
		||||
 | 
			
		||||
        // Don't save settings if something went wrong
 | 
			
		||||
        return;
 | 
			
		||||
@@ -397,7 +398,7 @@ function onANMenuItemClick() {
 | 
			
		||||
        //because this listener takes priority
 | 
			
		||||
        $('#options').stop().fadeOut(animation_duration);
 | 
			
		||||
    } else {
 | 
			
		||||
        toastr.warning('Select a character before trying to use Author\'s Note', '', { timeOut: 2000 });
 | 
			
		||||
        toastr.warning(t`Select a character before trying to use Author's Note`, '', { timeOut: 2000 });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,7 @@ import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
 | 
			
		||||
import { ScraperManager } from './scrapers.js';
 | 
			
		||||
import { DragAndDropHandler } from './dragdrop.js';
 | 
			
		||||
import { renderTemplateAsync } from './templates.js';
 | 
			
		||||
import { t } from './i18n.js';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {Object} FileAttachment
 | 
			
		||||
@@ -206,7 +207,7 @@ export async function populateFileAttachment(message, inputId = 'file_form_input
 | 
			
		||||
                    const fileText = await converter(file);
 | 
			
		||||
                    base64Data = window.btoa(unescape(encodeURIComponent(fileText)));
 | 
			
		||||
                } catch (error) {
 | 
			
		||||
                    toastr.error(String(error), 'Could not convert file');
 | 
			
		||||
                    toastr.error(String(error), t`Could not convert file`);
 | 
			
		||||
                    console.error('Could not convert file', error);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -257,7 +258,7 @@ export async function uploadFileAttachment(fileName, base64Data) {
 | 
			
		||||
        const responseData = await result.json();
 | 
			
		||||
        return responseData.path;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        toastr.error(String(error), 'Could not upload file');
 | 
			
		||||
        toastr.error(String(error), t`Could not upload file`);
 | 
			
		||||
        console.error('Could not upload file', error);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -283,7 +284,7 @@ export async function getFileAttachment(url) {
 | 
			
		||||
        const text = await result.text();
 | 
			
		||||
        return text;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        toastr.error(error, 'Could not download file');
 | 
			
		||||
        toastr.error(error, t`Could not download file`);
 | 
			
		||||
        console.error('Could not download file', error);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -299,13 +300,13 @@ async function validateFile(file) {
 | 
			
		||||
    const isBinary = /^[\x00-\x08\x0E-\x1F\x7F-\xFF]*$/.test(fileText);
 | 
			
		||||
 | 
			
		||||
    if (!isImage && file.size > fileSizeLimit) {
 | 
			
		||||
        toastr.error(`File is too big. Maximum size is ${humanFileSize(fileSizeLimit)}.`);
 | 
			
		||||
        toastr.error(t`File is too big. Maximum size is ${humanFileSize(fileSizeLimit)}.`);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // If file is binary
 | 
			
		||||
    if (isBinary && !isImage && !isConvertible(file.type)) {
 | 
			
		||||
        toastr.error('Binary files are not supported. Select a text file or image.');
 | 
			
		||||
        toastr.error(t`Binary files are not supported. Select a text file or image.`);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -521,7 +522,7 @@ async function openExternalMediaOverridesDialog() {
 | 
			
		||||
    const entityId = getCurrentEntityId();
 | 
			
		||||
 | 
			
		||||
    if (!entityId) {
 | 
			
		||||
        toastr.info('No character or group selected');
 | 
			
		||||
        toastr.info(t`No character or group selected`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -646,7 +647,7 @@ async function deleteFileFromServer(url, silent = false) {
 | 
			
		||||
        await eventSource.emit(event_types.FILE_ATTACHMENT_DELETED, url);
 | 
			
		||||
        return true;
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        toastr.error(String(error), 'Could not delete file');
 | 
			
		||||
        toastr.error(String(error), t`Could not delete file`);
 | 
			
		||||
        console.error('Could not delete file', error);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1054,7 +1055,7 @@ async function openAttachmentManager() {
 | 
			
		||||
            const selectedAttachments = document.querySelectorAll('.attachmentListItemCheckboxContainer .attachmentListItemCheckbox:checked');
 | 
			
		||||
 | 
			
		||||
            if (selectedAttachments.length === 0) {
 | 
			
		||||
                toastr.info('No attachments selected.', 'Data Bank');
 | 
			
		||||
                toastr.info(t`No attachments selected.`, t`Data Bank`);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -1168,7 +1169,7 @@ async function runScraper(scraperId, target, callback) {
 | 
			
		||||
 | 
			
		||||
        if (files.length === 0) {
 | 
			
		||||
            console.warn('Scraping returned no files');
 | 
			
		||||
            toastr.info('No files were scraped.', 'Data Bank');
 | 
			
		||||
            toastr.info(t`No files were scraped.`, t`Data Bank`);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -1176,12 +1177,12 @@ async function runScraper(scraperId, target, callback) {
 | 
			
		||||
            await uploadFileAttachmentToServer(file, target);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        toastr.success(`Scraped ${files.length} files from ${scraperId} to ${target}.`, 'Data Bank');
 | 
			
		||||
        toastr.success(t`Scraped ${files.length} files from ${scraperId} to ${target}.`, t`Data Bank`);
 | 
			
		||||
        callback();
 | 
			
		||||
    }
 | 
			
		||||
    catch (error) {
 | 
			
		||||
        console.error('Scraping failed', error);
 | 
			
		||||
        toastr.error('Check browser console for details.', 'Scraping failed');
 | 
			
		||||
        toastr.error(t`Check browser console for details.`, t`Scraping failed`);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -1208,7 +1209,7 @@ export async function uploadFileAttachmentToServer(file, target) {
 | 
			
		||||
            const fileText = await converter(file);
 | 
			
		||||
            base64Data = window.btoa(unescape(encodeURIComponent(fileText)));
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            toastr.error(String(error), 'Could not convert file');
 | 
			
		||||
            toastr.error(String(error), t`Could not convert file`);
 | 
			
		||||
            console.error('Could not convert file', error);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
 
 | 
			
		||||
@@ -132,7 +132,7 @@
 | 
			
		||||
                    <small data-i18n="ext_regex_other_options" data-i18n="Ephemerality">Ephemerality</small>
 | 
			
		||||
                    <span class="fa-solid fa-circle-question note-link-span" title="By default, regex scripts alter the chat file directly and irreversibly.
Enabling either (or both) of the options below will prevent chat file alteration, while still altering the specified item(s)."></span>
 | 
			
		||||
                </span>
 | 
			
		||||
                <label class="checkbox flex-container" title="Chat history file contents won't change, but regex will be applied to the messages displayed in the Chat UI.">
 | 
			
		||||
                <label class="checkbox flex-container" data-i18n="[title]ext_regex_only_format_visual_desc" title="Chat history file contents won't change, but regex will be applied to the messages displayed in the Chat UI.">
 | 
			
		||||
                    <input type="checkbox" name="only_format_display" />
 | 
			
		||||
                    <span data-i18n="Only Format Display">Alter Chat Display</span>
 | 
			
		||||
                </label>
 | 
			
		||||
 
 | 
			
		||||
@@ -189,8 +189,8 @@ async function validateGroup(group) {
 | 
			
		||||
    group.members = group.members.filter(member => {
 | 
			
		||||
        const character = characters.find(x => x.avatar === member || x.name === member);
 | 
			
		||||
        if (!character) {
 | 
			
		||||
            const msg = `Warning: Listed member ${member} does not exist as a character. It will be removed from the group.`;
 | 
			
		||||
            toastr.warning(msg, 'Group Validation');
 | 
			
		||||
            const msg = t`Warning: Listed member ${member} does not exist as a character. It will be removed from the group.`;
 | 
			
		||||
            toastr.warning(msg, t`Group Validation`);
 | 
			
		||||
            console.warn(msg);
 | 
			
		||||
            dirty = true;
 | 
			
		||||
        }
 | 
			
		||||
@@ -522,7 +522,7 @@ async function saveGroupChat(groupId, shouldSaveGroup) {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!response.ok) {
 | 
			
		||||
        toastr.error('Check the server connection and reload the page to prevent data loss.', 'Group Chat could not be saved');
 | 
			
		||||
        toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Group Chat could not be saved`);
 | 
			
		||||
        console.error('Group chat could not be saved', response);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
@@ -837,7 +837,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
 | 
			
		||||
            activatedMembers = activateSwipe(group.members);
 | 
			
		||||
 | 
			
		||||
            if (activatedMembers.length === 0) {
 | 
			
		||||
                toastr.warning('Deleted group member swiped. To get a reply, add them back to the group.');
 | 
			
		||||
                toastr.warning(t`Deleted group member swiped. To get a reply, add them back to the group.`);
 | 
			
		||||
                throw new Error('Deleted group member swiped');
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -1368,15 +1368,15 @@ function isGroupMemberDisabled(avatarId) {
 | 
			
		||||
 | 
			
		||||
async function onDeleteGroupClick() {
 | 
			
		||||
    if (!openGroupId) {
 | 
			
		||||
        toastr.warning('Currently no group selected.');
 | 
			
		||||
        toastr.warning(t`Currently no group selected.`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (is_group_generating) {
 | 
			
		||||
        toastr.warning('Not so fast! Wait for the characters to stop typing before deleting the group.');
 | 
			
		||||
        toastr.warning(t`Not so fast! Wait for the characters to stop typing before deleting the group.`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const confirm = await Popup.show.confirm('Delete the group?', '<p>This will also delete all your chats with that group. If you want to delete a single conversation, select a "View past chats" option in the lower left menu.</p>');
 | 
			
		||||
    const confirm = await Popup.show.confirm(t`Delete the group?`, '<p>' + t`This will also delete all your chats with that group. If you want to delete a single conversation, select a "View past chats" option in the lower left menu.` + '</p>');
 | 
			
		||||
    if (confirm) {
 | 
			
		||||
        deleteGroup(openGroupId);
 | 
			
		||||
    }
 | 
			
		||||
@@ -1630,7 +1630,7 @@ function updateFavButtonState(state) {
 | 
			
		||||
 | 
			
		||||
export async function openGroupById(groupId) {
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -1659,7 +1659,7 @@ export async function openGroupById(groupId) {
 | 
			
		||||
 | 
			
		||||
function openCharacterDefinition(characterSelect) {
 | 
			
		||||
    if (is_group_generating) {
 | 
			
		||||
        toastr.warning('Can\'t peek a character while group reply is being generated');
 | 
			
		||||
        toastr.warning(t`Can't peek a character while group reply is being generated`);
 | 
			
		||||
        console.warn('Can\'t peek a character def while group reply is being generated');
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
@@ -1908,7 +1908,7 @@ export async function saveGroupBookmarkChat(groupId, name, metadata, mesId) {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!response.ok) {
 | 
			
		||||
        toastr.error('Check the server connection and reload the page to prevent data loss.', 'Group chat could not be saved');
 | 
			
		||||
        toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Group chat could not be saved`);
 | 
			
		||||
        console.error('Group chat could not be saved', response);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -388,7 +388,7 @@ async function validateReverseProxy() {
 | 
			
		||||
        new URL(oai_settings.reverse_proxy);
 | 
			
		||||
    }
 | 
			
		||||
    catch (err) {
 | 
			
		||||
        toastr.error('Entered reverse proxy address is not a valid URL');
 | 
			
		||||
        toastr.error(t`Entered reverse proxy address is not a valid URL`);
 | 
			
		||||
        setOnlineStatus('no_connection');
 | 
			
		||||
        resultCheckStatus();
 | 
			
		||||
        throw err;
 | 
			
		||||
@@ -399,7 +399,7 @@ async function validateReverseProxy() {
 | 
			
		||||
    const confirmation = skipConfirm || await Popup.show.confirm(t`Connecting To Proxy`, await renderTemplateAsync('proxyConnectionWarning', { proxyURL: DOMPurify.sanitize(oai_settings.reverse_proxy) }));
 | 
			
		||||
 | 
			
		||||
    if (!confirmation) {
 | 
			
		||||
        toastr.error('Update or remove your reverse proxy settings.');
 | 
			
		||||
        toastr.error(t`Update or remove your reverse proxy settings.`);
 | 
			
		||||
        setOnlineStatus('no_connection');
 | 
			
		||||
        resultCheckStatus();
 | 
			
		||||
        throw new Error('Proxy connection denied.');
 | 
			
		||||
@@ -1231,15 +1231,15 @@ export async function prepareOpenAIMessages({
 | 
			
		||||
        await populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, quietImage, type, cyclePrompt, messages, messageExamples });
 | 
			
		||||
    } catch (error) {
 | 
			
		||||
        if (error instanceof TokenBudgetExceededError) {
 | 
			
		||||
            toastr.error('An error occurred while counting tokens: Token budget exceeded.');
 | 
			
		||||
            toastr.error(t`An error occurred while counting tokens: Token budget exceeded.`);
 | 
			
		||||
            chatCompletion.log('Token budget exceeded.');
 | 
			
		||||
            promptManager.error = 'Not enough free tokens for mandatory prompts. Raise your token Limit or disable custom prompts.';
 | 
			
		||||
            promptManager.error = t`Not enough free tokens for mandatory prompts. Raise your token Limit or disable custom prompts.`;
 | 
			
		||||
        } else if (error instanceof InvalidCharacterNameError) {
 | 
			
		||||
            toastr.warning('An error occurred while counting tokens: Invalid character name');
 | 
			
		||||
            toastr.warning(t`An error occurred while counting tokens: Invalid character name`);
 | 
			
		||||
            chatCompletion.log('Invalid character name');
 | 
			
		||||
            promptManager.error = 'The name of at least one character contained whitespaces or special characters. Please check your user and character name.';
 | 
			
		||||
            promptManager.error = t`The name of at least one character contained whitespaces or special characters. Please check your user and character name.`;
 | 
			
		||||
        } else {
 | 
			
		||||
            toastr.error('An unknown error occurred while counting tokens. Further information may be available in console.');
 | 
			
		||||
            toastr.error(t`An unknown error occurred while counting tokens. Further information may be available in console.`);
 | 
			
		||||
            chatCompletion.log('----- Unexpected error while preparing prompts -----');
 | 
			
		||||
            chatCompletion.log(error);
 | 
			
		||||
            chatCompletion.log(error.stack);
 | 
			
		||||
@@ -1293,11 +1293,8 @@ function tryParseStreamingError(response, decoded) {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function checkQuotaError(data) {
 | 
			
		||||
    const errorText = `<h3>Encountered an error while processing your request.<br>
 | 
			
		||||
    Check you have credits available on your
 | 
			
		||||
    <a href="https://platform.openai.com/account/usage" target="_blank">OpenAI account</a>.<br>
 | 
			
		||||
    If you have sufficient credits, please try again later.</h3>`;
 | 
			
		||||
async function checkQuotaError(data) {
 | 
			
		||||
    const errorText = await renderTemplateAsync('quotaError');
 | 
			
		||||
 | 
			
		||||
    if (!data) {
 | 
			
		||||
        return;
 | 
			
		||||
@@ -1933,11 +1930,11 @@ async function sendOpenAIRequest(type, messages, signal) {
 | 
			
		||||
    else {
 | 
			
		||||
        const data = await response.json();
 | 
			
		||||
 | 
			
		||||
        checkQuotaError(data);
 | 
			
		||||
        await checkQuotaError(data);
 | 
			
		||||
        checkModerationError(data);
 | 
			
		||||
 | 
			
		||||
        if (data.error) {
 | 
			
		||||
            toastr.error(data.error.message || response.statusText, 'API returned an error');
 | 
			
		||||
            toastr.error(data.error.message || response.statusText, t`API returned an error`);
 | 
			
		||||
            throw new Error(data);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -2184,7 +2181,7 @@ function parseOpenAITextLogprobs(logprobs) {
 | 
			
		||||
 | 
			
		||||
function handleWindowError(err) {
 | 
			
		||||
    const text = parseWindowError(err);
 | 
			
		||||
    toastr.error(text, 'Window.ai returned an error');
 | 
			
		||||
    toastr.error(text, t`Window.ai returned an error`);
 | 
			
		||||
    throw err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -3257,7 +3254,7 @@ async function getStatusOpen() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function showWindowExtensionError() {
 | 
			
		||||
    toastr.error('Get it here: <a href="https://windowai.io/" target="_blank">windowai.io</a>', 'Extension is not installed', {
 | 
			
		||||
    toastr.error(t`Get it here:` + ' <a href="https://windowai.io/" target="_blank">windowai.io</a>', t`Extension is not installed`, {
 | 
			
		||||
        escapeHtml: false,
 | 
			
		||||
        timeOut: 0,
 | 
			
		||||
        extendedTimeOut: 0,
 | 
			
		||||
@@ -3376,7 +3373,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
 | 
			
		||||
            if (triggerUi) $('#settings_preset_openai').append(option).trigger('change');
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        toastr.error('Failed to save preset');
 | 
			
		||||
        toastr.error(t`Failed to save preset`);
 | 
			
		||||
        throw new Error('Failed to save preset');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -3455,7 +3452,7 @@ async function createNewLogitBiasPreset() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (name in oai_settings.bias_presets) {
 | 
			
		||||
        toastr.error('Preset name should be unique.');
 | 
			
		||||
        toastr.error(t`Preset name should be unique.`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -3499,7 +3496,7 @@ async function onPresetImportFileChange(e) {
 | 
			
		||||
    try {
 | 
			
		||||
        presetBody = JSON.parse(importedFile);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        toastr.error('Invalid file');
 | 
			
		||||
        toastr.error(t`Invalid file`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -3540,7 +3537,7 @@ async function onPresetImportFileChange(e) {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!savePresetSettings.ok) {
 | 
			
		||||
        toastr.error('Failed to save preset');
 | 
			
		||||
        toastr.error(t`Failed to save preset`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -3565,7 +3562,7 @@ async function onPresetImportFileChange(e) {
 | 
			
		||||
 | 
			
		||||
async function onExportPresetClick() {
 | 
			
		||||
    if (!oai_settings.preset_settings_openai) {
 | 
			
		||||
        toastr.error('No preset selected');
 | 
			
		||||
        toastr.error(t`No preset selected`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -3606,12 +3603,12 @@ async function onLogitBiasPresetImportFileChange(e) {
 | 
			
		||||
    e.target.value = '';
 | 
			
		||||
 | 
			
		||||
    if (name in oai_settings.bias_presets) {
 | 
			
		||||
        toastr.error('Preset name should be unique.');
 | 
			
		||||
        toastr.error(t`Preset name should be unique.`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!Array.isArray(importedFile)) {
 | 
			
		||||
        toastr.error('Invalid logit bias preset file.');
 | 
			
		||||
        toastr.error(t`Invalid logit bias preset file.`);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -3670,16 +3667,16 @@ async function onDeletePresetClick() {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (!response.ok) {
 | 
			
		||||
        toastr.warning('Preset was not deleted from server');
 | 
			
		||||
        toastr.warning(t`Preset was not deleted from server`);
 | 
			
		||||
    } else {
 | 
			
		||||
        toastr.success('Preset deleted');
 | 
			
		||||
        toastr.success(t`Preset deleted`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    saveSettingsDebounced();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function onLogitBiasPresetDeleteClick() {
 | 
			
		||||
    const value = await callPopup('Delete the preset?', 'confirm');
 | 
			
		||||
    const value = await callPopup(t`Delete the preset?`, 'confirm');
 | 
			
		||||
 | 
			
		||||
    if (!value) {
 | 
			
		||||
        return;
 | 
			
		||||
@@ -4816,7 +4813,7 @@ function runProxyCallback(_, value) {
 | 
			
		||||
    const result = fuse.search(value);
 | 
			
		||||
 | 
			
		||||
    if (result.length === 0) {
 | 
			
		||||
        toastr.warning(`Proxy preset "${value}" not found`);
 | 
			
		||||
        toastr.warning(t`Proxy preset '${value}' not found`);
 | 
			
		||||
        return '';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -4990,7 +4987,7 @@ export function initOpenAI() {
 | 
			
		||||
    $('#update_oai_preset').on('click', async function () {
 | 
			
		||||
        const name = oai_settings.preset_settings_openai;
 | 
			
		||||
        await saveOpenAIPreset(name, oai_settings);
 | 
			
		||||
        toastr.success('Preset updated');
 | 
			
		||||
        toastr.success(t`Preset updated`);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $('#impersonation_prompt_restore').on('click', function () {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,3 @@
 | 
			
		||||
<div>
 | 
			
		||||
    <b>Note:</b> this chat is temporary and will be deleted as soon as you leave it.
 | 
			
		||||
    <b data-i18n="Note:">Note:</b> <span data-i18n="this chat is temporary and will be deleted as soon as you leave it.">this chat is temporary and will be deleted as soon as you leave it.</span>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								public/scripts/templates/deleteConfirm.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								public/scripts/templates/deleteConfirm.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
<b><span data-i18n="THIS IS PERMANENT!">THIS IS PERMANENT!</span><br><br>
 | 
			
		||||
<label for="del_char_checkbox" class="checkbox_label justifyCenter">
 | 
			
		||||
    <input type="checkbox" id="del_char_checkbox" />
 | 
			
		||||
    <small data-i18n="Also delete the chat files">Also delete the chat files</small>
 | 
			
		||||
</label></b>
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<div>
 | 
			
		||||
    <h3>Are you sure you want to duplicate this character?</h3>
 | 
			
		||||
    <span>If you just want to start a new chat with the same character, use "Start new chat" option in the bottom-left options menu.</span>
 | 
			
		||||
    <h3 data-i18n="Are you sure you want to duplicate this character?">Are you sure you want to duplicate this character?</h3>
 | 
			
		||||
    <span data-i18n="If you just want to start a new chat with the same character...">If you just want to start a new chat with the same character, use "Start new chat" option in the bottom-left options menu.</span>
 | 
			
		||||
    <br>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -14,18 +14,18 @@
 | 
			
		||||
    <li><kbd data-i18n="help_hotkeys_19">Ctrl+Shift+Down</kbd> = <span data-i18n="help_hotkeys_20">Scroll chat to bottom</span></li>
 | 
			
		||||
</ul>
 | 
			
		||||
<div>
 | 
			
		||||
    <strong>Markdown Hotkeys</strong>
 | 
			
		||||
    <strong data-i18n="help_hotkeys_20">Markdown Hotkeys</strong>
 | 
			
		||||
</div>
 | 
			
		||||
<div>
 | 
			
		||||
    <small>
 | 
			
		||||
        <span>Works in the chatbar and textareas marked with this icon:</span>
 | 
			
		||||
        <span data-i18n="help_hotkeys_21">Works in the chatbar and textareas marked with this icon:</span>
 | 
			
		||||
        <code><i class="fa-brands fa-markdown"></i></code>
 | 
			
		||||
    </small>
 | 
			
		||||
</div>
 | 
			
		||||
<ul>
 | 
			
		||||
    <li><kbd>Ctrl+B</kbd> = <span>**bold**</span></li>
 | 
			
		||||
    <li><kbd>Ctrl+I</kbd> = <span>*italic*</span></li>
 | 
			
		||||
    <li><kbd>Ctrl+U</kbd> = <span>__underline__</span></li>
 | 
			
		||||
    <li><kbd>Ctrl+K</kbd> = <span>`inline code`</span></li>
 | 
			
		||||
    <li><kbd>Ctrl+Shift+~</kbd> = <span>~~strikethrough~~</span></li>
 | 
			
		||||
    <li><kbd>Ctrl+B</kbd> = <span data-i18n="help_hotkeys_22">**bold**</span></li>
 | 
			
		||||
    <li><kbd>Ctrl+I</kbd> = <span data-i18n="help_hotkeys_23">*italic*</span></li>
 | 
			
		||||
    <li><kbd>Ctrl+U</kbd> = <span data-i18n="help_hotkeys_24">__underline__</span></li>
 | 
			
		||||
    <li><kbd>Ctrl+K</kbd> = <span data-i18n="help_hotkeys_25">`inline code`</span></li>
 | 
			
		||||
    <li><kbd>Ctrl+Shift+~</kbd> = <span data-i18n="help_hotkeys_26">~~strikethrough~~</span></li>
 | 
			
		||||
</ul>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								public/scripts/templates/quotaError.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								public/scripts/templates/quotaError.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
			
		||||
<h3><span data-i18n="Encountered an error while processing your request.">Encountered an error while processing your request.</span><br>
 | 
			
		||||
    <span data-i18n="Check you have credits available on your">Check you have credits available on your</span>
 | 
			
		||||
    <a href="https://platform.openai.com/account/usage" target="_blank" data-i18n="OpenAI account quora_error">OpenAI account</a><span data-i18n="dot quota_error">.</span><br>
 | 
			
		||||
    <span data-i18n="If you have sufficient credits, please try again later.">If you have sufficient credits, please try again later.</span></h3>
 | 
			
		||||
		Reference in New Issue
	
	Block a user