Work on tl

890d10d811789d12c9f0c4902b7b0995641c2307

Yokayo <nonameutubecomm@gmail.com>

10 files changed, +124 -60Ignore whitespace
public/index.html+4 -4
@@ -2015,7 +2015,7 @@
2015 </div>2015 </div>
2016 </div>2016 </div>
2017 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom">2017 <div class="flex-container flexFlowColumn wide100p textAlignCenter marginTop10" data-source="openai,custom">
2018 <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models.&#10;Currently supported values are low, medium, and high.&#10;Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response.">2018 <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models.&#10;Currently supported values are low, medium, and high.&#10;Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models.">
2019 <label for="openai_reasoning_effort" data-i18n="Reasoning Effort">2019 <label for="openai_reasoning_effort" data-i18n="Reasoning Effort">
2020 Reasoning Effort2020 Reasoning Effort
2021 </label>2021 </label>
@@ -4001,7 +4001,7 @@
4001 <div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" title="Cap the number of entry activation recursions" data-i18n="[title]Cap the number of entry activation recursions">4001 <div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" title="Cap the number of entry activation recursions" data-i18n="[title]Cap the number of entry activation recursions">
4002 <small>4002 <small>
4003 <span data-i18n="Max Recursion Steps">Max Recursion Steps</span>4003 <span data-i18n="Max Recursion Steps">Max Recursion Steps</span>
4004 <div class="fa-solid fa-triangle-exclamation opacity50p" data-i18n="[title]0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc\n(disabled when min activations are used)" title="0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc&#10;(disabled when min activations are used)"></div>4004 <div class="fa-solid fa-triangle-exclamation opacity50p" data-i18n="[title]0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc" title="0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc&#10;(disabled when min activations are used)"></div>
4005 </small>4005 </small>
4006 <input class="neo-range-slider" type="range" id="world_info_max_recursion_steps" name="world_info_max_recursion_steps" min="0" max="10" step="1">4006 <input class="neo-range-slider" type="range" id="world_info_max_recursion_steps" name="world_info_max_recursion_steps" min="0" max="10" step="1">
4007 <input class="neo-range-input" type="number" min="0" max="10" step="1" data-for="world_info_max_recursion_steps" id="world_info_max_recursion_steps_counter">4007 <input class="neo-range-input" type="number" min="0" max="10" step="1" data-for="world_info_max_recursion_steps" id="world_info_max_recursion_steps_counter">
@@ -6890,8 +6890,8 @@
6890 </div>6890 </div>
6891 <div id="form_sheld">6891 <div id="form_sheld">
6892 <div id="dialogue_del_mes">6892 <div id="dialogue_del_mes">
6893 <div id="dialogue_del_mes_ok" class="menu_button">Delete</div>6893 <div id="dialogue_del_mes_ok" data-i18n="Delete" class="menu_button">Delete</div>
6894 <div id="dialogue_del_mes_cancel" class="menu_button">Cancel</div>6894 <div id="dialogue_del_mes_cancel" data-i18n="Cancel" class="menu_button">Cancel</div>
6895 </div>6895 </div>
6896 <div id="send_form" class="no-connection">6896 <div id="send_form" class="no-connection">
6897 <form id="file_form" class="wide100p displayNone">6897 <form id="file_form" class="wide100p displayNone">
public/locales/ru-ru.json+73 -13
@@ -195,7 +195,7 @@
195 "Yes": "Да",195 "Yes": "Да",
196 "No": "Нет",196 "No": "Нет",
197 "Context %": "Процент контекста",197 "Context %": "Процент контекста",
198 "Budget Cap": "Бюджетный лимит",198 "Budget Cap": "Лимит бюджета",
199 "(0 = disabled)": "(0 = отключено)",199 "(0 = disabled)": "(0 = отключено)",
200 "None": "Отсутствует",200 "None": "Отсутствует",
201 "User Settings": "Настройки пользователя",201 "User Settings": "Настройки пользователя",
@@ -575,10 +575,10 @@
575 "Characters sorting order": "Порядок сортировки персонажей",575 "Characters sorting order": "Порядок сортировки персонажей",
576 "Remove": "Убрать",576 "Remove": "Убрать",
577 "Select a World Info file for": "Выбрать файл с миром для",577 "Select a World Info file for": "Выбрать файл с миром для",
578 "Primary Lorebook": "Основного лорбука",578 "Primary Lorebook": "Основной лорбук",
579 "A selected World Info will be bound to this character as its own Lorebook.": "Информация о мире будет привязана к персонажу как его собственный лорбук",579 "A selected World Info will be bound to this character as its own Lorebook.": "Информация о мире будет привязана к персонажу как его собственный лорбук.",
580 "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Когда ИИ генерирует ответ, он будет совмещён с записями из глобально выбранного мира",580 "When generating an AI reply, it will be combined with the entries from a global World Info selector.": "Когда ИИ генерирует ответ, он будет совмещён с записями из глобально выбранного мира.",
581 "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "При экспорте персонажа вместе с ним также выгрузится выбранный лорбук в виде JSON",581 "Exporting a character would also export the selected Lorebook file embedded in the JSON data.": "При экспорте персонажа вместе с ним также выгрузится выбранный лорбук в виде JSON.",
582 "Additional Lorebooks": "Вспомогательные лорбуки",582 "Additional Lorebooks": "Вспомогательные лорбуки",
583 "Associate one or more auxillary Lorebooks with this character.": "Привязать к этому персонажу один или больше вспомогательных лорбуков",583 "Associate one or more auxillary Lorebooks with this character.": "Привязать к этому персонажу один или больше вспомогательных лорбуков",
584 "NOTE: These choices are optional and won't be preserved on character export!": "ВНИМАНИЕ: эти выборы необязательные и не будут сохранены при экспорте персонажа!",584 "NOTE: These choices are optional and won't be preserved on character export!": "ВНИМАНИЕ: эти выборы необязательные и не будут сохранены при экспорте персонажа!",
@@ -593,7 +593,7 @@
593 "Prompt": "Промпт",593 "Prompt": "Промпт",
594 "Copy": "Скопировать",594 "Copy": "Скопировать",
595 "Confirm": "Подтвердить",595 "Confirm": "Подтвердить",
596 "Copy this message": "Скопировать сообщение",596 "Copy this message": "Продублировать сообщение",
597 "Delete this message": "Удалить сообщение",597 "Delete this message": "Удалить сообщение",
598 "Move message up": "Переместить сообщение вверх",598 "Move message up": "Переместить сообщение вверх",
599 "Move message down": "Переместить сообщение вниз",599 "Move message down": "Переместить сообщение вниз",
@@ -612,7 +612,7 @@
612 "Ask AI to write your message for you": "Попросить ИИ написать сообщение за вас",612 "Ask AI to write your message for you": "Попросить ИИ написать сообщение за вас",
613 "Continue the last message": "Продолжить текущее сообщение",613 "Continue the last message": "Продолжить текущее сообщение",
614 "Bind user name to that avatar": "Закрепить имя за этим аватаром",614 "Bind user name to that avatar": "Закрепить имя за этим аватаром",
615 "Select this as default persona for the new chats.": "Выберать эту Персону в качестве персоны по умолчанию для новых чатов.",615 "Select this as default persona for the new chats.": "Выбирать эту персону по умолчанию для всех новых чатов.",
616 "Change persona image": "Сменить аватар персоны",616 "Change persona image": "Сменить аватар персоны",
617 "Delete persona": "Удалить персону",617 "Delete persona": "Удалить персону",
618 "Reduced Motion": "Сокращение анимаций",618 "Reduced Motion": "Сокращение анимаций",
@@ -640,7 +640,7 @@
640 "Token Probabilities": "Вероятности токенов",640 "Token Probabilities": "Вероятности токенов",
641 "Close chat": "Закрыть чат",641 "Close chat": "Закрыть чат",
642 "Manage chat files": "Все чаты",642 "Manage chat files": "Все чаты",
643 "Import Extension From Git Repo": "Импортировать расширение из Git Repository",643 "Import Extension From Git Repo": "Импортировать расширение из Git-репозитория.",
644 "Install extension": "Установить расширение",644 "Install extension": "Установить расширение",
645 "Manage extensions": "Управление расширениями",645 "Manage extensions": "Управление расширениями",
646 "Tokens persona description": "Токенов",646 "Tokens persona description": "Токенов",
@@ -1122,7 +1122,7 @@
1122 "help_hotkeys_0": "Горячие клавиши",1122 "help_hotkeys_0": "Горячие клавиши",
1123 "You can browse a list of bundled characters in the": "Комплектных персонажей можно найти в меню",1123 "You can browse a list of bundled characters in the": "Комплектных персонажей можно найти в меню",
1124 "Download Extensions & Assets": "Загрузить расширения и ресурсы",1124 "Download Extensions & Assets": "Загрузить расширения и ресурсы",
1125 "menu within": "внутри этих кубиков",1125 "menu within": "в меню",
1126 "Assets URL": "URL с описанием ресурсов",1126 "Assets URL": "URL с описанием ресурсов",
1127 "Custom (OpenAI-compatible)": "Кастомный (совместимый с OpenAI)",1127 "Custom (OpenAI-compatible)": "Кастомный (совместимый с OpenAI)",
1128 "Custom Endpoint (Base URL)": "Кастомный эндпоинт (базовый URL)",1128 "Custom Endpoint (Base URL)": "Кастомный эндпоинт (базовый URL)",
@@ -1943,7 +1943,7 @@
1943 "and connect to an": "и подключитесь к",1943 "and connect to an": "и подключитесь к",
1944 "You can add more": "Можете добавить больше",1944 "You can add more": "Можете добавить больше",
1945 "from other websites": "с других сайтов.",1945 "from other websites": "с других сайтов.",
1946 "Go to the": "Загляните в",1946 "Go to the": "Заходите в",
1947 "to install additional features.": ", чтобы установить разные дополнительные ресурсы.",1947 "to install additional features.": ", чтобы установить разные дополнительные ресурсы.",
1948 "or_welcome": "; также доступен",1948 "or_welcome": "; также доступен",
1949 "Claude API Key": "Ключ от API Claude",1949 "Claude API Key": "Ключ от API Claude",
@@ -1958,7 +1958,7 @@
1958 "Save": "Сохранить",1958 "Save": "Сохранить",
1959 "Chat Lorebook": "Лорбук для чата",1959 "Chat Lorebook": "Лорбук для чата",
1960 "chat_world_template_txt": "Выбранный мир будет привязан к этому чату. Будет добавляться в промпт наряду с глобальным лорбуком и лором персонажа.",1960 "chat_world_template_txt": "Выбранный мир будет привязан к этому чату. Будет добавляться в промпт наряду с глобальным лорбуком и лором персонажа.",
1961 "world_button_title": "Лор персонажа\n\nНажмите, чтобы загрузить\nShift + клик, чтобы открыть диалог привязки мира",1961 "world_button_title": "Лор персонажа\n\nНажмите, чтобы загрузить\nShift + ЛКМ, чтобы открыть диалог привязки мира",
1962 "No auxillary Lorebooks set. Click here to select.": "Вспомогательный лорбук не выбран. Нажмите, чтобы выбрать.",1962 "No auxillary Lorebooks set. Click here to select.": "Вспомогательный лорбук не выбран. Нажмите, чтобы выбрать.",
1963 "ext_regex_user_input_desc": "Отправленные вами сообщения.",1963 "ext_regex_user_input_desc": "Отправленные вами сообщения.",
1964 "ext_regex_ai_input_desc": "Полученные от API ответы.",1964 "ext_regex_ai_input_desc": "Полученные от API ответы.",
@@ -2144,5 +2144,65 @@
2144 "Not connected to the API!": "Нет соединения с API!",2144 "Not connected to the API!": "Нет соединения с API!",
2145 "ext_type_system": "Это комплектное расширение. Его нельзя удалить, а обновляется оно вместе со всей системой.",2145 "ext_type_system": "Это комплектное расширение. Его нельзя удалить, а обновляется оно вместе со всей системой.",
2146 "Update all": "Обновить все",2146 "Update all": "Обновить все",
2147 "Close": "Закрыть"2147 "Close": "Закрыть",
2148}2148 "Optional modules:": "Необязательные модули:",
2149 "Sort: Display Name": "Сортировать: по названию",
2150 "Sort: Loading Order": "Сортировать: в порядке загрузки",
2151 "Click to toggle": "Нажмите, чтобы включить или выключить",
2152 "Loading Asset List": "Загрузить список ресурсов",
2153 "Don't ask again for this URL": "Запомнить выбор для этого адреса",
2154 "Are you sure you want to connect to the following url?": "Вы точно хотите подключиться к этому адресу?",
2155 "All": "Всё",
2156 "Characters": "Персонажи",
2157 "Ambient sounds": "Звуковой эмбиент",
2158 "Blip sounds": "Звуки уведомлений",
2159 "Background music": "Фоновая музыка",
2160 "Search": "Поиск",
2161 "extension_install_1": "Чтобы загружать расширения из этого списка, у вас должен быть установлен ",
2162 "extension_install_2": ".",
2163 "extension_install_3": "Нажмите на иконку ",
2164 "extension_install_4": ", чтобы перейти в репозиторий расширения и получить более подробную информацию о нём.",
2165 "Extension repo/guide:": "Репозиторий расширения:",
2166 "Preview in browser": "Предпросмотр",
2167 "Adds a function tool": "Частично или полностью работает через вызов функций",
2168 "Tool": "Функции",
2169 "Move extension": "Переместить расширение",
2170 "ext_type_local": "Это локальное расширение, доступно только вам",
2171 "ext_type_global": "Это глобальное расширение, доступно всем пользователям",
2172 "Move": "Переместить",
2173 "Enter the Git URL of the extension to install": "Введите Git-адрес расширения",
2174 "Please be aware that using external extensions can have unintended side effects and may pose security risks. Always make sure you trust the source before importing an extension. We are not responsible for any damage caused by third-party extensions.": "помните, что используя расширения от сторонних авторов, вы можете подвергать систему опасности. Устанавливайте расширения только от проверенных разработчиков. Мы не несём ответственности за любой ущерб, причинённый сторонними расширениями.",
2175 "Disclaimer:": "Внимание:",
2176 "Example:": "Пример:",
2177 "context_derived": "Считывать из метаданных модели (по возможности)",
2178 "instruct_derived": "Считывать из метаданных модели (по возможности)",
2179 "Confirm token parsing with": "Чтобы убедиться в правильности выделения токенов, используйте",
2180 "Reasoning Effort": "Рассуждения",
2181 "Constrains effort on reasoning for reasoning models.": "Регулирует объём внутренних рассуждений модели (reasoning), для моделей которые поддерживают эту возможность.\nНа данный момент поддерживаются три значения: Подробные, Обычные, Поверхностные.\nПри менее подробном рассуждении ответ получается быстрее, а также экономятся токены, уходящие на расуждения.",
2182 "openai_reasoning_effort_low": "Поверхностные",
2183 "openai_reasoning_effort_medium": "Обычные",
2184 "openai_reasoning_effort_high": "Подробные",
2185 "Persona Lore Alt+Click to open the lorebook": "Лорбук данной персоны\nAlt + ЛКМ чтобы открыть лорбук",
2186 "Persona Lorebook for": "Лорбук для персоны",
2187 "persona_world_template_txt": "Выбранная Информация о мире будет привязана к этой персоне. Информация будет добавляться в каждом промпте вместе с глобальным лорбуком и лорбуками персонажа и чата.",
2188 "Global list": "Глобальный список",
2189 "Preset-specific list": "Список для данного пресета",
2190 "Banned tokens/strings are being sent in the request.": "Запрещённые токены и строки отсылаются в запросе.",
2191 "Banned tokens/strings are NOT being sent in the request.": "Запрещённые токены и строки НЕ отсылаются в запросе.",
2192 "Add a reasoning block": "Добавить блок рассуждений",
2193 "Create a copy of this message?": "Продублировать это сообщение?",
2194 "Max Recursion Steps": "Макс. глубина рекурсии",
2195 "0 = unlimited, 1 = scans once and doesn't recurse, 2 = scans once and recurses once, etc": "0 = неограничено, 1 = сканировать единожды, 2 = сканировать единожды и сделать один повторный проход, и т.д.\n(неактивно при указанном мин. числе активаций)",
2196 "(disabled when max recursion steps are used)": "(неактивно при указанной макс. глубине рекурсии)",
2197 "Enter a valid API URL": "Введите корректный адрес API",
2198 "No Ollama model selected.": "Не выбрана модель Ollama",
2199 "Background Fitting": "Способ подгонки фона под разрешение",
2200 "Chat Lore Alt+Click to open the lorebook": "Лорбук данного чата\nAlt + ЛКМ чтобы открыть лорбук",
2201 "Token Counter": "Подсчитать токены",
2202 "Type / paste in the box below to see the number of tokens in the text.": "Введите или вставьте текст в окошко ниже, чтобы подсчитать количество токенов в нём.",
2203 "Selected tokenizer:": "Выбранный токенайзер:",
2204 "Input:": "Входные данные:",
2205 "Tokenized text:": "Токенизированный текст:",
2206 "Token IDs:": "Идентификаторы токенов:",
2207 "Tokens:": "Токенов:"
2208}
\ No newline at end of file2208 \ No newline at end of file
public/script.js+1 -1
@@ -10943,7 +10943,7 @@ jQuery(async function () {
10943 });10943 });
1094410944
10945 $(document).on('click', '.mes_edit_copy', async function () {10945 $(document).on('click', '.mes_edit_copy', async function () {
10946 const confirmation = await callGenericPopup('Create a copy of this message?', POPUP_TYPE.CONFIRM);10946 const confirmation = await callGenericPopup(t`Create a copy of this message?`, POPUP_TYPE.CONFIRM);
10947 if (!confirmation) {10947 if (!confirmation) {
10948 return;10948 return;
10949 }10949 }
public/scripts/extensions.js+4 -4
@@ -603,12 +603,12 @@ function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal,
603 }603 }
604604
605 let toggleElement = isActive || isDisabled ?605 let toggleElement = isActive || isDisabled ?
606 `<input type="checkbox" title="Click to toggle" data-name="${name}" class="${isActive ? 'toggle_disable' : 'toggle_enable'} ${checkboxClass}" ${isActive ? 'checked' : ''}>` :606 '<input type="checkbox" title="' + t`Click to toggle` + `" data-name="${name}" class="${isActive ? 'toggle_disable' : 'toggle_enable'} ${checkboxClass}" ${isActive ? 'checked' : ''}>` :
607 `<input type="checkbox" title="Cannot enable extension" data-name="${name}" class="extension_missing ${checkboxClass}" disabled>`;607 `<input type="checkbox" title="Cannot enable extension" data-name="${name}" class="extension_missing ${checkboxClass}" disabled>`;
608608
609 let deleteButton = isExternal ? `<button class="btn_delete menu_button" data-name="${externalId}" title="Delete"><i class="fa-fw fa-solid fa-trash-can"></i></button>` : '';609 let deleteButton = isExternal ? `<button class="btn_delete menu_button" data-name="${externalId}" data-i18n="[title]Delete" title="Delete"><i class="fa-fw fa-solid fa-trash-can"></i></button>` : '';
610 let updateButton = isExternal ? `<button class="btn_update menu_button displayNone" data-name="${externalId}" title="Update available"><i class="fa-solid fa-download fa-fw"></i></button>` : '';610 let updateButton = isExternal ? `<button class="btn_update menu_button displayNone" data-name="${externalId}" title="Update available"><i class="fa-solid fa-download fa-fw"></i></button>` : '';
611 let moveButton = isExternal && isUserAdmin ? `<button class="btn_move menu_button" data-name="${externalId}" title="Move"><i class="fa-solid fa-folder-tree fa-fw"></i></button>` : '';611 let moveButton = isExternal && isUserAdmin ? `<button class="btn_move menu_button" data-name="${externalId}" data-i18n="[title]Move" title="Move"><i class="fa-solid fa-folder-tree fa-fw"></i></button>` : '';
612 let modulesInfo = '';612 let modulesInfo = '';
613613
614 if (isActive && Array.isArray(manifest.optional)) {614 if (isActive && Array.isArray(manifest.optional)) {
@@ -616,7 +616,7 @@ function generateExtensionHtml(name, manifest, isActive, isDisabled, isExternal,
616 modules.forEach(x => optional.delete(x));616 modules.forEach(x => optional.delete(x));
617 if (optional.size > 0) {617 if (optional.size > 0) {
618 const optionalString = DOMPurify.sanitize([...optional].join(', '));618 const optionalString = DOMPurify.sanitize([...optional].join(', '));
619 modulesInfo = `<div class="extension_modules">Optional modules: <span class="optional">${optionalString}</span></div>`;619 modulesInfo = '<div class="extension_modules">' + t`Optional modules:` + ` <span class="optional">${optionalString}</span></div>`;
620 }620 }
621 } else if (!isDisabled) { // Neither active nor disabled621 } else if (!isDisabled) { // Neither active nor disabled
622 const requirements = new Set(manifest.requires);622 const requirements = new Set(manifest.requires);
public/scripts/extensions/assets/index.js+13 -15
@@ -10,6 +10,7 @@ import { POPUP_TYPE, Popup, callGenericPopup } from '../../popup.js';
10import { executeSlashCommands } from '../../slash-commands.js';10import { executeSlashCommands } from '../../slash-commands.js';
11import { accountStorage } from '../../util/AccountStorage.js';11import { accountStorage } from '../../util/AccountStorage.js';
12import { flashHighlight, getStringHash, isValidUrl } from '../../utils.js';12import { flashHighlight, getStringHash, isValidUrl } from '../../utils.js';
13import { t } from '../../i18n.js';
13export { MODULE_NAME };14export { MODULE_NAME };
1415
15const MODULE_NAME = 'assets';16const MODULE_NAME = 'assets';
@@ -59,11 +60,11 @@ const KNOWN_TYPES = {
59 'blip': 'Blip sounds',60 'blip': 'Blip sounds',
60};61};
6162
62function downloadAssetsList(url) {63async function downloadAssetsList(url) {
63 updateCurrentAssets().then(function () {64 updateCurrentAssets().then(async function () {
64 fetch(url, { cache: 'no-cache' })65 fetch(url, { cache: 'no-cache' })
65 .then(response => response.json())66 .then(response => response.json())
66 .then(json => {67 .then(async function(json) {
6768
68 availableAssets = {};69 availableAssets = {};
69 $('#assets_menu').empty();70 $('#assets_menu').empty();
@@ -84,10 +85,10 @@ function downloadAssetsList(url) {
8485
85 $('#assets_type_select').empty();86 $('#assets_type_select').empty();
86 $('#assets_search').val('');87 $('#assets_search').val('');
87 $('#assets_type_select').append($('<option />', { value: '', text: 'All' }));88 $('#assets_type_select').append($('<option />', { value: '', text: t`All` }));
8889
89 for (const type of assetTypes) {90 for (const type of assetTypes) {
90 const option = $('<option />', { value: type, text: KNOWN_TYPES[type] || type });91 const option = $('<option />', { value: type, text: t([KNOWN_TYPES[type] || type]) });
91 $('#assets_type_select').append(option);92 $('#assets_type_select').append(option);
92 }93 }
9394
@@ -104,11 +105,7 @@ function downloadAssetsList(url) {
104 assetTypeMenu.append(`<h3>${KNOWN_TYPES[assetType] || assetType}</h3>`).hide();105 assetTypeMenu.append(`<h3>${KNOWN_TYPES[assetType] || assetType}</h3>`).hide();
105106
106 if (assetType == 'extension') {107 if (assetType == 'extension') {
107 assetTypeMenu.append(`108 assetTypeMenu.append(await renderExtensionTemplateAsync('assets', 'installation'));
108 <div class="assets-list-git">
109 To download extensions from this page, you need to have <a href="https://git-scm.com/downloads" target="_blank">Git</a> installed.<br>
110 Click the <i class="fa-solid fa-sm fa-arrow-up-right-from-square"></i> icon to visit the Extension's repo for tips on how to use it.
111 </div>`);
112 }109 }
113110
114 for (const i in availableAssets[assetType].sort((a, b) => a?.name && b?.name && a['name'].localeCompare(b['name']))) {111 for (const i in availableAssets[assetType].sort((a, b) => a?.name && b?.name && a['name'].localeCompare(b['name']))) {
@@ -184,7 +181,7 @@ function downloadAssetsList(url) {
184 const displayName = DOMPurify.sanitize(asset['name'] || asset['id']);181 const displayName = DOMPurify.sanitize(asset['name'] || asset['id']);
185 const description = DOMPurify.sanitize(asset['description'] || '');182 const description = DOMPurify.sanitize(asset['description'] || '');
186 const url = isValidUrl(asset['url']) ? asset['url'] : '';183 const url = isValidUrl(asset['url']) ? asset['url'] : '';
187 const title = assetType === 'extension' ? `Extension repo/guide: ${url}` : 'Preview in browser';184 const title = assetType === 'extension' ? t`Extension repo/guide:` + ` ${url}` : t`Preview in browser`;
188 const previewIcon = (assetType === 'extension' || assetType === 'character') ? 'fa-arrow-up-right-from-square' : 'fa-headphones-simple';185 const previewIcon = (assetType === 'extension' || assetType === 'character') ? 'fa-arrow-up-right-from-square' : 'fa-headphones-simple';
189 const toolTag = assetType === 'extension' && asset['tool'];186 const toolTag = assetType === 'extension' && asset['tool'];
190187
@@ -195,9 +192,10 @@ function downloadAssetsList(url) {
195 <b>${displayName}</b>192 <b>${displayName}</b>
196 <a class="asset_preview" href="${url}" target="_blank" title="${title}">193 <a class="asset_preview" href="${url}" target="_blank" title="${title}">
197 <i class="fa-solid fa-sm ${previewIcon}"></i>194 <i class="fa-solid fa-sm ${previewIcon}"></i>
198 </a>195 </a>` +
199 ${toolTag ? '<span class="tag" title="Adds a function tool"><i class="fa-solid fa-sm fa-wrench"></i> Tool</span>' : ''}196 (toolTag ? '<span class="tag" title="' + t`Adds a function tool` + '"><i class="fa-solid fa-sm fa-wrench"></i> ' +
200 </span>197 t`Tool` + '</span>' : '') +
198 `</span>
201 <small class="asset-description">199 <small class="asset-description">
202 ${description}200 ${description}
203 </small>201 </small>
@@ -435,7 +433,7 @@ jQuery(async () => {
435 const rememberKey = `Assets_SkipConfirm_${getStringHash(url)}`;433 const rememberKey = `Assets_SkipConfirm_${getStringHash(url)}`;
436 const skipConfirm = accountStorage.getItem(rememberKey) === 'true';434 const skipConfirm = accountStorage.getItem(rememberKey) === 'true';
437435
438 const confirmation = skipConfirm || await Popup.show.confirm('Loading Asset List', `<span>Are you sure you want to connect to the following url?</span><var>${url}</var>`, {436 const confirmation = skipConfirm || await Popup.show.confirm(t`Loading Asset List`, '<span>' + t`Are you sure you want to connect to the following url?` + `</span><var>${url}</var>`, {
439 customInputs: [{ id: 'assets-remember', label: 'Don\'t ask again for this URL' }],437 customInputs: [{ id: 'assets-remember', label: 'Don\'t ask again for this URL' }],
440 onClose: popup => {438 onClose: popup => {
441 if (popup.result) {439 if (popup.result) {
public/scripts/extensions/assets/installation.html+4 -0
@@ -0,0 +1,4 @@
1<div class="assets-list-git">
2 <span data-i18n="extension_install_1">To download extensions from this page, you need to have </span><a href="https://git-scm.com/downloads" target="_blank">Git</a><span data-i18n="extension_install_2"> installed.</span><br>
3 <span data-i18n="extension_install_3">Click the </span><i class="fa-solid fa-sm fa-arrow-up-right-from-square"></i><span data-i18n="extension_install_4"> icon to visit the Extension's repo for tips on how to use it.</span>
4</div>
\ No newline at end of file4 \ No newline at end of file
public/scripts/extensions/assets/window.html+1 -1
@@ -33,7 +33,7 @@ To install a single 3rd party extension, use the &quot;Install Extensions&quot;
33 <div id="assets_filters" class="flex-container">33 <div id="assets_filters" class="flex-container">
34 <select id="assets_type_select" class="text_pole flex1">34 <select id="assets_type_select" class="text_pole flex1">
35 </select>35 </select>
36 <input id="assets_search" class="text_pole flex1" placeholder="Search" type="search">36 <input id="assets_search" class="text_pole flex1" data-i18n="[placeholder]Search" placeholder="Search" type="search">
37 <div id="assets-characters-button" class="menu_button menu_button_icon">37 <div id="assets-characters-button" class="menu_button menu_button_icon">
38 <i class="fa-solid fa-image-portrait"></i>38 <i class="fa-solid fa-image-portrait"></i>
39 <span data-i18n="Characters">Characters</span>39 <span data-i18n="Characters">Characters</span>
public/scripts/extensions/token-counter/index.js+6 -20
@@ -6,6 +6,8 @@ import { getFriendlyTokenizerName, getTextTokens, getTokenCountAsync, tokenizers
6import { resetScrollHeight, debounce } from '../../utils.js';6import { resetScrollHeight, debounce } from '../../utils.js';
7import { debounce_timeout } from '../../constants.js';7import { debounce_timeout } from '../../constants.js';
8import { POPUP_TYPE, callGenericPopup } from '../../popup.js';8import { POPUP_TYPE, callGenericPopup } from '../../popup.js';
9import { renderExtensionTemplateAsync } from '../../extensions.js';
10import { t } from '../../i18n.js';
911
10function rgb2hex(rgb) {12function rgb2hex(rgb) {
11 rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);13 rgb = rgb.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i);
@@ -22,23 +24,7 @@ $('button').click(function () {
2224
23async function doTokenCounter() {25async function doTokenCounter() {
24 const { tokenizerName, tokenizerId } = getFriendlyTokenizerName(main_api);26 const { tokenizerName, tokenizerId } = getFriendlyTokenizerName(main_api);
25 const html = `27 const html = await renderExtensionTemplateAsync('token-counter', 'window', {tokenizerName});
26 <div class="wide100p">
27 <h3>Token Counter</h3>
28 <div class="justifyLeft flex-container flexFlowColumn">
29 <h4>Type / paste in the box below to see the number of tokens in the text.</h4>
30 <p>Selected tokenizer: ${tokenizerName}</p>
31 <div>Input:</div>
32 <textarea id="token_counter_textarea" class="wide100p textarea_compact" rows="1"></textarea>
33 <div>Tokens: <span id="token_counter_result">0</span></div>
34 <hr>
35 <div>Tokenized text:</div>
36 <div id="tokenized_chunks_display" class="wide100p">—</div>
37 <hr>
38 <div>Token IDs:</div>
39 <textarea id="token_counter_ids" class="wide100p textarea_compact" readonly rows="1">—</textarea>
40 </div>
41 </div>`;
4228
43 const dialog = $(html);29 const dialog = $(html);
44 const countDebounced = debounce(async () => {30 const countDebounced = debounce(async () => {
@@ -131,9 +117,9 @@ async function doCount() {
131jQuery(() => {117jQuery(() => {
132 const buttonHtml = `118 const buttonHtml = `
133 <div id="token_counter" class="list-group-item flex-container flexGap5">119 <div id="token_counter" class="list-group-item flex-container flexGap5">
134 <div class="fa-solid fa-1 extensionsMenuExtensionButton" /></div>120 <div class="fa-solid fa-1 extensionsMenuExtensionButton" /></div>` +
135 Token Counter121 t`Token Counter` +
136 </div>`;122 '</div>';
137 $('#token_counter_wand_container').append(buttonHtml);123 $('#token_counter_wand_container').append(buttonHtml);
138 $('#token_counter').on('click', doTokenCounter);124 $('#token_counter').on('click', doTokenCounter);
139 SlashCommandParser.addCommandObject(SlashCommand.fromProps({125 SlashCommandParser.addCommandObject(SlashCommand.fromProps({
public/scripts/extensions/token-counter/window.html+16 -0
@@ -0,0 +1,16 @@
1<div class="wide100p">
2 <h3 data-i18n="Token Counter">Token Counter</h3>
3 <div class="justifyLeft flex-container flexFlowColumn">
4 <h4 data-i18n="Type / paste in the box below to see the number of tokens in the text.">Type / paste in the box below to see the number of tokens in the text.</h4>
5 <p><span data-i18n="Selected tokenizer:">Selected tokenizer:</span> {{tokenizerName}}</p>
6 <div data-i18n="Input:">Input:</div>
7 <textarea id="token_counter_textarea" class="wide100p textarea_compact" rows="1"></textarea>
8 <div><span data-i18n="Tokens:">Tokens:</span> <span id="token_counter_result">0</span></div>
9 <hr>
10 <div data-i18n="Tokenized text:">Tokenized text:</div>
11 <div id="tokenized_chunks_display" class="wide100p">—</div>
12 <hr>
13 <div data-i18n="Token IDs:">Token IDs:</div>
14 <textarea id="token_counter_ids" class="wide100p textarea_compact" readonly rows="1">—</textarea>
15 </div>
16</div>
\ No newline at end of file16 \ No newline at end of file
public/scripts/textgen-settings.js+2 -2
@@ -311,7 +311,7 @@ export function validateTextGenUrl() {
311 const formattedUrl = formatTextGenURL(url);311 const formattedUrl = formatTextGenURL(url);
312312
313 if (!formattedUrl) {313 if (!formattedUrl) {
314 toastr.error('Enter a valid API URL', 'Text Completion API');314 toastr.error(t`Enter a valid API URL`, 'Text Completion API');
315 return;315 return;
316 }316 }
317317
@@ -1187,7 +1187,7 @@ export function getTextGenModel() {
1187 return settings.aphrodite_model;1187 return settings.aphrodite_model;
1188 case OLLAMA:1188 case OLLAMA:
1189 if (!settings.ollama_model) {1189 if (!settings.ollama_model) {
1190 toastr.error('No Ollama model selected.', 'Text Completion API');1190 toastr.error(t`No Ollama model selected.`, 'Text Completion API');
1191 throw new Error('No Ollama model selected');1191 throw new Error('No Ollama model selected');
1192 }1192 }
1193 return settings.ollama_model;1193 return settings.ollama_model;