Merge branch 'staging' into redesign-extension-manager
| @@ -54,6 +54,7 @@ module.exports = { | |||
| 54 | }, | 54 | }, |
| 55 | // These scripts are loaded in HTML; tell ESLint not to complain about them being undefined | 55 | // These scripts are loaded in HTML; tell ESLint not to complain about them being undefined |
| 56 | globals: { | 56 | globals: { |
| 57 | globalThis: 'readonly', | ||
| 57 | ePub: 'readonly', | 58 | ePub: 'readonly', |
| 58 | pdfjsLib: 'readonly', | 59 | pdfjsLib: 'readonly', |
| 59 | toastr: 'readonly', | 60 | toastr: 'readonly', |
| @@ -209,6 +209,44 @@ SillyTavern поддерживает расширения. | |||
| 209 | 5. Запустите лаунчер установки: `chmod +x install.sh && ./install.sh` and choose what you wanna install | 209 | 5. Запустите лаунчер установки: `chmod +x install.sh && ./install.sh` and choose what you wanna install |
| 210 | 6. После завершения установки, запустите лаунчер следующей командой: `chmod +x launcher.sh && ./launcher.sh` | 210 | 6. После завершения установки, запустите лаунчер следующей командой: `chmod +x launcher.sh && ./launcher.sh` |
| 211 | 211 | ||
| 212 | ## 🐋 Установка с помощью Docker | ||
| 213 | |||
| 214 | Предполагается, что вы уже установили Docker, имеете доступ к командной строке для установки контейнеров и знакомы с их базовым управлением. | ||
| 215 | |||
| 216 | ### Сборка образа самостоятельно | ||
| 217 | |||
| 218 | У нас есть подробное руководство по использованию SillyTavern в Docker [здесь](http://docs.sillytavern.app/installation/docker/), которое охватывает установку на Windows, macOS и Linux! Ознакомьтесь с ним, если хотите создать образ самостоятельно. | ||
| 219 | |||
| 220 | ### Использование реестра контейнеров GitHub (самый простой способ) | ||
| 221 | |||
| 222 | Для работы SillyTavern вам понадобятся две обязательные настройки каталогов и одна настройка порта. В команде замените указанные значения на свои: | ||
| 223 | |||
| 224 | #### Переменные контейнера | ||
| 225 | |||
| 226 | ##### Маппинг томов | ||
| 227 | |||
| 228 | * [config] - директория, где на вашем хосте будут храниться файлы конфигурации SillyTavern. | ||
| 229 | * [data] - директория, где на вашем хосте будут храниться пользовательские данные SillyTavern (включая персонажей). | ||
| 230 | * [plugins] - (необязательно) директория, где на вашем хосте будут храниться плагины сервера SillyTavern. | ||
| 231 | |||
| 232 | ##### Маппинг портов | ||
| 233 | |||
| 234 | * [PublicPort] - Порт, через который будет передаваться трафик. Это обязательно, так как вы будете обращаться к контейнеру извне его виртуальной машины. НЕ ОТКРЫВАЙТЕ этот порт в интернет без реализации дополнительного уровня безопасности. | ||
| 235 | |||
| 236 | ##### Дополнительные настройки | ||
| 237 | |||
| 238 | * [DockerNet] - Docker сеть, к которой контейнер должен быть подключен. Если вы не знаете, что это, обратитесь к [официальной документации Docker](https://docs.docker.com/reference/cli/docker/network/). | ||
| 239 | * [version] - на правой части этой страницы GitHub вы найдете раздел "Packages". Выберите пакет "sillytavern", чтобы увидеть версии образов. Тег "latest" позволит вам обновляться до текущего релиза. Также доступны теги "staging" и "release", которые соответствуют ночным сборкам соответствующих веток. Однако это может быть нецелесообразно, если вы используете расширения, которые могут ломаться и требуют времени для обновления. | ||
| 240 | |||
| 241 | #### Команда установки | ||
| 242 | |||
| 243 | 1. Откройте командную строку | ||
| 244 | 2. Выполните следующую команду | ||
| 245 | |||
| 246 | `docker create --name='sillytavern' --net='[DockerNet]' -p '8000:8000/tcp' -v '[plugins]':'/home/node/app/plugins':'rw' -v '[config]':'/home/node/app/config':'rw' -v '[data]':'/home/node/app/data':'rw' 'ghcr.io/sillytavern/sillytavern:[version]'` | ||
| 247 | |||
| 248 | > Заметьте, что 8000 является портом по умолчанию. Не забудьте использовать соответствующий порт, если вы измените его в конфиге. | ||
| 249 | |||
| 212 | ## 📱 Мобильные устройства - Установка при помощи termux | 250 | ## 📱 Мобильные устройства - Установка при помощи termux |
| 213 | 251 | ||
| 214 | > **ОБРАТИТЕ ВНИМАНИЕ!** | 252 | > **ОБРАТИТЕ ВНИМАНИЕ!** |
| @@ -1,6 +1,8 @@ | |||
| 1 | # -- DATA CONFIGURATION -- | 1 | # -- DATA CONFIGURATION -- |
| 2 | # Root directory for user data storage | 2 | # Root directory for user data storage |
| 3 | dataRoot: ./data | 3 | dataRoot: ./data |
| 4 | # The maximum amount of memory that parsed character cards can use in MB | ||
| 5 | cardsCacheCapacity: 100 | ||
| 4 | # -- SERVER CONFIGURATION -- | 6 | # -- SERVER CONFIGURATION -- |
| 5 | # Listen for incoming connections | 7 | # Listen for incoming connections |
| 6 | listen: false | 8 | listen: false |
| @@ -1,12 +1,12 @@ | |||
| 1 | { | 1 | { |
| 2 | "name": "sillytavern", | 2 | "name": "sillytavern", |
| 3 | "version": "1.12.8", | 3 | "version": "1.12.9", |
| 4 | "lockfileVersion": 3, | 4 | "lockfileVersion": 3, |
| 5 | "requires": true, | 5 | "requires": true, |
| 6 | "packages": { | 6 | "packages": { |
| 7 | "": { | 7 | "": { |
| 8 | "name": "sillytavern", | 8 | "name": "sillytavern", |
| 9 | "version": "1.12.8", | 9 | "version": "1.12.9", |
| 10 | "hasInstallScript": true, | 10 | "hasInstallScript": true, |
| 11 | "license": "AGPL-3.0", | 11 | "license": "AGPL-3.0", |
| 12 | "dependencies": { | 12 | "dependencies": { |
| @@ -3591,9 +3591,9 @@ | |||
| 3591 | "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" | 3591 | "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" |
| 3592 | }, | 3592 | }, |
| 3593 | "node_modules/express": { | 3593 | "node_modules/express": { |
| 3594 | "version": "4.21.1", | 3594 | "version": "4.21.2", |
| 3595 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", | 3595 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", |
| 3596 | "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", | 3596 | "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", |
| 3597 | "license": "MIT", | 3597 | "license": "MIT", |
| 3598 | "dependencies": { | 3598 | "dependencies": { |
| 3599 | "accepts": "~1.3.8", | 3599 | "accepts": "~1.3.8", |
| @@ -3615,7 +3615,7 @@ | |||
| 3615 | "methods": "~1.1.2", | 3615 | "methods": "~1.1.2", |
| 3616 | "on-finished": "2.4.1", | 3616 | "on-finished": "2.4.1", |
| 3617 | "parseurl": "~1.3.3", | 3617 | "parseurl": "~1.3.3", |
| 3618 | "path-to-regexp": "0.1.10", | 3618 | "path-to-regexp": "0.1.12", |
| 3619 | "proxy-addr": "~2.0.7", | 3619 | "proxy-addr": "~2.0.7", |
| 3620 | "qs": "6.13.0", | 3620 | "qs": "6.13.0", |
| 3621 | "range-parser": "~1.2.1", | 3621 | "range-parser": "~1.2.1", |
| @@ -3630,6 +3630,10 @@ | |||
| 3630 | }, | 3630 | }, |
| 3631 | "engines": { | 3631 | "engines": { |
| 3632 | "node": ">= 0.10.0" | 3632 | "node": ">= 0.10.0" |
| 3633 | }, | ||
| 3634 | "funding": { | ||
| 3635 | "type": "opencollective", | ||
| 3636 | "url": "https://opencollective.com/express" | ||
| 3633 | } | 3637 | } |
| 3634 | }, | 3638 | }, |
| 3635 | "node_modules/express/node_modules/cookie": { | 3639 | "node_modules/express/node_modules/cookie": { |
| @@ -5725,9 +5729,9 @@ | |||
| 5725 | } | 5729 | } |
| 5726 | }, | 5730 | }, |
| 5727 | "node_modules/path-to-regexp": { | 5731 | "node_modules/path-to-regexp": { |
| 5728 | "version": "0.1.10", | 5732 | "version": "0.1.12", |
| 5729 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", | 5733 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", |
| 5730 | "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", | 5734 | "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", |
| 5731 | "license": "MIT" | 5735 | "license": "MIT" |
| 5732 | }, | 5736 | }, |
| 5733 | "node_modules/peek-readable": { | 5737 | "node_modules/peek-readable": { |
| @@ -84,7 +84,7 @@ | |||
| 84 | "type": "git", | 84 | "type": "git", |
| 85 | "url": "https://github.com/SillyTavern/SillyTavern.git" | 85 | "url": "https://github.com/SillyTavern/SillyTavern.git" |
| 86 | }, | 86 | }, |
| 87 | "version": "1.12.8", | 87 | "version": "1.12.9", |
| 88 | "scripts": { | 88 | "scripts": { |
| 89 | "start": "node server.js", | 89 | "start": "node server.js", |
| 90 | "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js", | 90 | "start:deno": "deno run --allow-run --allow-net --allow-read --allow-write --allow-sys --allow-env server.js", |
| @@ -1,4 +1,5 @@ | |||
| 1 | import libs from './lib'; | 1 | import libs from './lib'; |
| 2 | import getContext from './scripts/st-context'; | ||
| 2 | 3 | ||
| 3 | // Global namespace modules | 4 | // Global namespace modules |
| 4 | declare var ai; | 5 | declare var ai; |
| @@ -6,7 +7,7 @@ declare var pdfjsLib; | |||
| 6 | declare var ePub; | 7 | declare var ePub; |
| 7 | 8 | ||
| 8 | declare var SillyTavern: { | 9 | declare var SillyTavern: { |
| 9 | getContext(): any; | 10 | getContext(): typeof getContext; |
| 10 | llm: any; | 11 | llm: any; |
| 11 | libs: typeof libs; | 12 | libs: typeof libs; |
| 12 | }; | 13 | }; |
| @@ -669,7 +669,7 @@ | |||
| 669 | </span> | 669 | </span> |
| 670 | </div> | 670 | </div> |
| 671 | </div> | 671 | </div> |
| 672 | <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai"> | 672 | <div class="range-block" data-source="openai,claude,windowai,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt"> |
| 673 | <div class="range-block-title" data-i18n="Temperature"> | 673 | <div class="range-block-title" data-i18n="Temperature"> |
| 674 | Temperature | 674 | Temperature |
| 675 | </div> | 675 | </div> |
| @@ -682,7 +682,7 @@ | |||
| 682 | </div> | 682 | </div> |
| 683 | </div> | 683 | </div> |
| 684 | </div> | 684 | </div> |
| 685 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai"> | 685 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt"> |
| 686 | <div class="range-block-title" data-i18n="Frequency Penalty"> | 686 | <div class="range-block-title" data-i18n="Frequency Penalty"> |
| 687 | Frequency Penalty | 687 | Frequency Penalty |
| 688 | </div> | 688 | </div> |
| @@ -695,7 +695,7 @@ | |||
| 695 | </div> | 695 | </div> |
| 696 | </div> | 696 | </div> |
| 697 | </div> | 697 | </div> |
| 698 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai"> | 698 | <div class="range-block" data-source="openai,openrouter,custom,cohere,perplexity,groq,mistralai,nanogpt"> |
| 699 | <div class="range-block-title" data-i18n="Presence Penalty"> | 699 | <div class="range-block-title" data-i18n="Presence Penalty"> |
| 700 | Presence Penalty | 700 | Presence Penalty |
| 701 | </div> | 701 | </div> |
| @@ -721,7 +721,7 @@ | |||
| 721 | </div> | 721 | </div> |
| 722 | </div> | 722 | </div> |
| 723 | </div> | 723 | </div> |
| 724 | <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai"> | 724 | <div class="range-block" data-source="openai,claude,openrouter,ai21,scale,makersuite,mistralai,custom,cohere,perplexity,groq,01ai,nanogpt"> |
| 725 | <div class="range-block-title" data-i18n="Top P"> | 725 | <div class="range-block-title" data-i18n="Top P"> |
| 726 | Top P | 726 | Top P |
| 727 | </div> | 727 | </div> |
| @@ -958,7 +958,7 @@ | |||
| 958 | </div> | 958 | </div> |
| 959 | </div> | 959 | </div> |
| 960 | </div> | 960 | </div> |
| 961 | <div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq"> | 961 | <div class="range-block" data-source="openai,openrouter,mistralai,custom,cohere,groq,nanogpt"> |
| 962 | <div class="range-block-title justifyLeft" data-i18n="Seed"> | 962 | <div class="range-block-title justifyLeft" data-i18n="Seed"> |
| 963 | Seed | 963 | Seed |
| 964 | </div> | 964 | </div> |
| @@ -2987,6 +2987,7 @@ | |||
| 2987 | <optgroup label="Subversions"> | 2987 | <optgroup label="Subversions"> |
| 2988 | <option value="gemini-exp-1121">Gemini Experimental 2024-11-21</option> | 2988 | <option value="gemini-exp-1121">Gemini Experimental 2024-11-21</option> |
| 2989 | <option value="gemini-exp-1114">Gemini Experimental 2024-11-14</option> | 2989 | <option value="gemini-exp-1114">Gemini Experimental 2024-11-14</option> |
| 2990 | <option value="gemini-exp-1206">Gemini Experimental 2024-12-06</option> | ||
| 2990 | <option value="gemini-1.5-pro-exp-0801">Gemini 1.5 Pro Experiment 2024-08-01</option> | 2991 | <option value="gemini-1.5-pro-exp-0801">Gemini 1.5 Pro Experiment 2024-08-01</option> |
| 2991 | <option value="gemini-1.5-pro-exp-0827">Gemini 1.5 Pro Experiment 2024-08-27</option> | 2992 | <option value="gemini-1.5-pro-exp-0827">Gemini 1.5 Pro Experiment 2024-08-27</option> |
| 2992 | <option value="gemini-1.5-pro-latest">Gemini 1.5 Pro [latest]</option> | 2993 | <option value="gemini-1.5-pro-latest">Gemini 1.5 Pro [latest]</option> |
| @@ -4183,7 +4184,7 @@ | |||
| 4183 | </label> | 4184 | </label> |
| 4184 | <label for="show_swipe_num_all_messages" class="checkbox_label" title="Display swipe numbers for all messages, not just the last." data-i18n="[title]Display swipe numbers for all messages, not just the last."> | 4185 | <label for="show_swipe_num_all_messages" class="checkbox_label" title="Display swipe numbers for all messages, not just the last." data-i18n="[title]Display swipe numbers for all messages, not just the last."> |
| 4185 | <input id="show_swipe_num_all_messages" type="checkbox" /> | 4186 | <input id="show_swipe_num_all_messages" type="checkbox" /> |
| 4186 | <small data-i18n="Swipe # for All Messages">Swipe # for All Messages</small><i class="fa-solid fa-mobile-screen-button"></i> | 4187 | <small data-i18n="Swipe # for All Messages">Swipe # for All Messages</small> |
| 4187 | </label> | 4188 | </label> |
| 4188 | <label for="hotswapEnabled" class="checkbox_label" title="In the Character Management panel, show quick selection buttons for favorited characters." data-i18n="[title]In the Character Management panel, show quick selection buttons for favorited characters"> | 4189 | <label for="hotswapEnabled" class="checkbox_label" title="In the Character Management panel, show quick selection buttons for favorited characters." data-i18n="[title]In the Character Management panel, show quick selection buttons for favorited characters"> |
| 4189 | <input id="hotswapEnabled" type="checkbox" /> | 4190 | <input id="hotswapEnabled" type="checkbox" /> |
| @@ -5,7 +5,8 @@ | |||
| 5 | "module": "ESNext", | 5 | "module": "ESNext", |
| 6 | "moduleResolution": "node", | 6 | "moduleResolution": "node", |
| 7 | "allowUmdGlobalAccess": true, | 7 | "allowUmdGlobalAccess": true, |
| 8 | "allowSyntheticDefaultImports": true | 8 | "allowSyntheticDefaultImports": true, |
| 9 | "strictBindCallApply": true | ||
| 9 | }, | 10 | }, |
| 10 | "exclude": [ | 11 | "exclude": [ |
| 11 | "**/node_modules/**", | 12 | "**/node_modules/**", |
| @@ -13,7 +13,7 @@ import { | |||
| 13 | default as libs, | 13 | default as libs, |
| 14 | } from './lib.js'; | 14 | } from './lib.js'; |
| 15 | 15 | ||
| 16 | import { humanizedDateTime, favsToHotswap, getMessageTimeStamp, dragElement, isMobile, initRossMods, shouldSendOnEnter } from './scripts/RossAscends-mods.js'; | 16 | import { humanizedDateTime, favsToHotswap, getMessageTimeStamp, dragElement, isMobile, initRossMods } from './scripts/RossAscends-mods.js'; |
| 17 | import { userStatsHandler, statMesProcess, initStats } from './scripts/stats.js'; | 17 | import { userStatsHandler, statMesProcess, initStats } from './scripts/stats.js'; |
| 18 | import { | 18 | import { |
| 19 | generateKoboldWithStreaming, | 19 | generateKoboldWithStreaming, |
| @@ -37,8 +37,6 @@ import { | |||
| 37 | parseTabbyLogprobs, | 37 | parseTabbyLogprobs, |
| 38 | } from './scripts/textgen-settings.js'; | 38 | } from './scripts/textgen-settings.js'; |
| 39 | 39 | ||
| 40 | const { MANCER, TOGETHERAI, OOBA, VLLM, APHRODITE, TABBY, OLLAMA, INFERMATICAI, DREAMGEN, OPENROUTER, FEATHERLESS } = textgen_types; | ||
| 41 | |||
| 42 | import { | 40 | import { |
| 43 | world_info, | 41 | world_info, |
| 44 | getWorldInfoPrompt, | 42 | getWorldInfoPrompt, |
| @@ -67,9 +65,7 @@ import { | |||
| 67 | getGroupChat, | 65 | getGroupChat, |
| 68 | renameGroupMember, | 66 | renameGroupMember, |
| 69 | createNewGroupChat, | 67 | createNewGroupChat, |
| 70 | getGroupPastChats, | ||
| 71 | getGroupAvatar, | 68 | getGroupAvatar, |
| 72 | openGroupChat, | ||
| 73 | editGroup, | 69 | editGroup, |
| 74 | deleteGroupChat, | 70 | deleteGroupChat, |
| 75 | renameGroupChat, | 71 | renameGroupChat, |
| @@ -98,7 +94,6 @@ import { | |||
| 98 | resetMovableStyles, | 94 | resetMovableStyles, |
| 99 | forceCharacterEditorTokenize, | 95 | forceCharacterEditorTokenize, |
| 100 | applyPowerUserSettings, | 96 | applyPowerUserSettings, |
| 101 | switchSwipeNumAllMessages, | ||
| 102 | } from './scripts/power-user.js'; | 97 | } from './scripts/power-user.js'; |
| 103 | 98 | ||
| 104 | import { | 99 | import { |
| @@ -174,8 +169,8 @@ import { | |||
| 174 | } from './scripts/utils.js'; | 169 | } from './scripts/utils.js'; |
| 175 | import { debounce_timeout } from './scripts/constants.js'; | 170 | import { debounce_timeout } from './scripts/constants.js'; |
| 176 | 171 | ||
| 177 | import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, initExtensions, loadExtensionSettings, renderExtensionTemplate, renderExtensionTemplateAsync, runGenerationInterceptors, saveMetadataDebounced, writeExtensionField } from './scripts/extensions.js'; | 172 | import { doDailyExtensionUpdatesCheck, extension_settings, initExtensions, loadExtensionSettings, runGenerationInterceptors, saveMetadataDebounced } from './scripts/extensions.js'; |
| 178 | import { COMMENT_NAME_DEFAULT, executeSlashCommands, executeSlashCommandsOnChatInput, executeSlashCommandsWithOptions, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, registerSlashCommand, stopScriptExecution } from './scripts/slash-commands.js'; | 173 | import { COMMENT_NAME_DEFAULT, executeSlashCommandsOnChatInput, getSlashCommandsHelp, initDefaultSlashCommands, isExecutingCommandsFromChatInput, pauseScriptExecution, processChatSlashCommands, stopScriptExecution } from './scripts/slash-commands.js'; |
| 179 | import { | 174 | import { |
| 180 | tag_map, | 175 | tag_map, |
| 181 | tags, | 176 | tags, |
| @@ -225,8 +220,8 @@ import { | |||
| 225 | instruct_presets, | 220 | instruct_presets, |
| 226 | selectContextPreset, | 221 | selectContextPreset, |
| 227 | } from './scripts/instruct-mode.js'; | 222 | } from './scripts/instruct-mode.js'; |
| 228 | import { initLocales, t, translate } from './scripts/i18n.js'; | 223 | import { initLocales, t } from './scripts/i18n.js'; |
| 229 | import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, getTokenizerModel, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js'; | 224 | import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js'; |
| 230 | import { | 225 | import { |
| 231 | user_avatar, | 226 | user_avatar, |
| 232 | getUserAvatars, | 227 | getUserAvatars, |
| @@ -241,12 +236,12 @@ import { hideLoader, showLoader } from './scripts/loader.js'; | |||
| 241 | import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js'; | 236 | import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js'; |
| 242 | import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels } from './scripts/textgen-models.js'; | 237 | import { loadFeatherlessModels, loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadVllmModels, loadAphroditeModels, loadDreamGenModels, initTextGenModels, loadTabbyModels } from './scripts/textgen-models.js'; |
| 243 | import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js'; | 238 | import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId, preserveNeutralChat, restoreNeutralChat } from './scripts/chats.js'; |
| 244 | import { initPresetManager } from './scripts/preset-manager.js'; | 239 | import { getPresetManager, initPresetManager } from './scripts/preset-manager.js'; |
| 245 | import { MacrosParser, evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js'; | 240 | import { evaluateMacros, getLastMessageId, initMacros } from './scripts/macros.js'; |
| 246 | import { currentUser, setUserControls } from './scripts/user.js'; | 241 | import { currentUser, setUserControls } from './scripts/user.js'; |
| 247 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js'; | 242 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup, fixToastrForDialogs } from './scripts/popup.js'; |
| 248 | import { renderTemplate, renderTemplateAsync } from './scripts/templates.js'; | 243 | import { renderTemplate, renderTemplateAsync } from './scripts/templates.js'; |
| 249 | import { initScrapers, ScraperManager } from './scripts/scrapers.js'; | 244 | import { initScrapers } from './scripts/scrapers.js'; |
| 250 | import { SlashCommandParser } from './scripts/slash-commands/SlashCommandParser.js'; | 245 | import { SlashCommandParser } from './scripts/slash-commands/SlashCommandParser.js'; |
| 251 | import { SlashCommand } from './scripts/slash-commands/SlashCommand.js'; | 246 | import { SlashCommand } from './scripts/slash-commands/SlashCommand.js'; |
| 252 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './scripts/slash-commands/SlashCommandArgument.js'; | 247 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './scripts/slash-commands/SlashCommandArgument.js'; |
| @@ -268,6 +263,13 @@ import { initServerHistory } from './scripts/server-history.js'; | |||
| 268 | import { initSettingsSearch } from './scripts/setting-search.js'; | 263 | import { initSettingsSearch } from './scripts/setting-search.js'; |
| 269 | import { initBulkEdit } from './scripts/bulk-edit.js'; | 264 | import { initBulkEdit } from './scripts/bulk-edit.js'; |
| 270 | import { deriveTemplatesFromChatTemplate } from './scripts/chat-templates.js'; | 265 | import { deriveTemplatesFromChatTemplate } from './scripts/chat-templates.js'; |
| 266 | import { getContext } from './scripts/st-context.js'; | ||
| 267 | |||
| 268 | // API OBJECT FOR EXTERNAL WIRING | ||
| 269 | globalThis.SillyTavern = { | ||
| 270 | libs, | ||
| 271 | getContext, | ||
| 272 | }; | ||
| 271 | 273 | ||
| 272 | //exporting functions and vars for mods | 274 | //exporting functions and vars for mods |
| 273 | export { | 275 | export { |
| @@ -427,10 +429,6 @@ DOMPurify.addHook('uponSanitizeElement', (node, _, config) => { | |||
| 427 | } | 429 | } |
| 428 | }); | 430 | }); |
| 429 | 431 | ||
| 430 | // API OBJECT FOR EXTERNAL WIRING | ||
| 431 | window['SillyTavern'] = {}; | ||
| 432 | window['SillyTavern'].libs = libs; | ||
| 433 | |||
| 434 | // Event source init | 432 | // Event source init |
| 435 | export const event_types = { | 433 | export const event_types = { |
| 436 | APP_READY: 'app_ready', | 434 | APP_READY: 'app_ready', |
| @@ -536,7 +534,7 @@ let displayVersion = 'SillyTavern'; | |||
| 536 | 534 | ||
| 537 | let generatedPromptCache = ''; | 535 | let generatedPromptCache = ''; |
| 538 | let generation_started = new Date(); | 536 | let generation_started = new Date(); |
| 539 | /** @type {import('scripts/char-data.js').v1CharData[]} */ | 537 | /** @type {import('./scripts/char-data.js').v1CharData[]} */ |
| 540 | export let characters = []; | 538 | export let characters = []; |
| 541 | export let this_chid; | 539 | export let this_chid; |
| 542 | let saveCharactersPage = 0; | 540 | let saveCharactersPage = 0; |
| @@ -812,7 +810,7 @@ export let menu_type = ''; | |||
| 812 | export let selected_button = ''; //which button pressed | 810 | export let selected_button = ''; //which button pressed |
| 813 | 811 | ||
| 814 | //create pole save | 812 | //create pole save |
| 815 | let create_save = { | 813 | export let create_save = { |
| 816 | name: '', | 814 | name: '', |
| 817 | description: '', | 815 | description: '', |
| 818 | creator_notes: '', | 816 | creator_notes: '', |
| @@ -864,7 +862,7 @@ export let amount_gen = 80; //default max length of AI generated responses | |||
| 864 | export let max_context = 2048; | 862 | export let max_context = 2048; |
| 865 | 863 | ||
| 866 | var swipes = true; | 864 | var swipes = true; |
| 867 | let extension_prompts = {}; | 865 | export let extension_prompts = {}; |
| 868 | 866 | ||
| 869 | export let main_api;// = "kobold"; | 867 | export let main_api;// = "kobold"; |
| 870 | //novel settings | 868 | //novel settings |
| @@ -1175,7 +1173,7 @@ async function getStatusTextgen() { | |||
| 1175 | return resultCheckStatus(); | 1173 | return resultCheckStatus(); |
| 1176 | } | 1174 | } |
| 1177 | 1175 | ||
| 1178 | if (textgen_settings.type == OOBA && textgen_settings.bypass_status_check) { | 1176 | if (textgen_settings.type == textgen_types.OOBA && textgen_settings.bypass_status_check) { |
| 1179 | setOnlineStatus('Status check bypassed'); | 1177 | setOnlineStatus('Status check bypassed'); |
| 1180 | return resultCheckStatus(); | 1178 | return resultCheckStatus(); |
| 1181 | } | 1179 | } |
| @@ -1193,34 +1191,34 @@ async function getStatusTextgen() { | |||
| 1193 | 1191 | ||
| 1194 | const data = await response.json(); | 1192 | const data = await response.json(); |
| 1195 | 1193 | ||
| 1196 | if (textgen_settings.type === MANCER) { | 1194 | if (textgen_settings.type === textgen_types.MANCER) { |
| 1197 | loadMancerModels(data?.data); | 1195 | loadMancerModels(data?.data); |
| 1198 | setOnlineStatus(textgen_settings.mancer_model); | 1196 | setOnlineStatus(textgen_settings.mancer_model); |
| 1199 | } else if (textgen_settings.type === TOGETHERAI) { | 1197 | } else if (textgen_settings.type === textgen_types.TOGETHERAI) { |
| 1200 | loadTogetherAIModels(data?.data); | 1198 | loadTogetherAIModels(data?.data); |
| 1201 | setOnlineStatus(textgen_settings.togetherai_model); | 1199 | setOnlineStatus(textgen_settings.togetherai_model); |
| 1202 | } else if (textgen_settings.type === OLLAMA) { | 1200 | } else if (textgen_settings.type === textgen_types.OLLAMA) { |
| 1203 | loadOllamaModels(data?.data); | 1201 | loadOllamaModels(data?.data); |
| 1204 | setOnlineStatus(textgen_settings.ollama_model || 'Connected'); | 1202 | setOnlineStatus(textgen_settings.ollama_model || 'Connected'); |
| 1205 | } else if (textgen_settings.type === INFERMATICAI) { | 1203 | } else if (textgen_settings.type === textgen_types.INFERMATICAI) { |
| 1206 | loadInfermaticAIModels(data?.data); | 1204 | loadInfermaticAIModels(data?.data); |
| 1207 | setOnlineStatus(textgen_settings.infermaticai_model); | 1205 | setOnlineStatus(textgen_settings.infermaticai_model); |
| 1208 | } else if (textgen_settings.type === DREAMGEN) { | 1206 | } else if (textgen_settings.type === textgen_types.DREAMGEN) { |
| 1209 | loadDreamGenModels(data?.data); | 1207 | loadDreamGenModels(data?.data); |
| 1210 | setOnlineStatus(textgen_settings.dreamgen_model); | 1208 | setOnlineStatus(textgen_settings.dreamgen_model); |
| 1211 | } else if (textgen_settings.type === OPENROUTER) { | 1209 | } else if (textgen_settings.type === textgen_types.OPENROUTER) { |
| 1212 | loadOpenRouterModels(data?.data); | 1210 | loadOpenRouterModels(data?.data); |
| 1213 | setOnlineStatus(textgen_settings.openrouter_model); | 1211 | setOnlineStatus(textgen_settings.openrouter_model); |
| 1214 | } else if (textgen_settings.type === VLLM) { | 1212 | } else if (textgen_settings.type === textgen_types.VLLM) { |
| 1215 | loadVllmModels(data?.data); | 1213 | loadVllmModels(data?.data); |
| 1216 | setOnlineStatus(textgen_settings.vllm_model); | 1214 | setOnlineStatus(textgen_settings.vllm_model); |
| 1217 | } else if (textgen_settings.type === APHRODITE) { | 1215 | } else if (textgen_settings.type === textgen_types.APHRODITE) { |
| 1218 | loadAphroditeModels(data?.data); | 1216 | loadAphroditeModels(data?.data); |
| 1219 | setOnlineStatus(textgen_settings.aphrodite_model); | 1217 | setOnlineStatus(textgen_settings.aphrodite_model); |
| 1220 | } else if (textgen_settings.type === FEATHERLESS) { | 1218 | } else if (textgen_settings.type === textgen_types.FEATHERLESS) { |
| 1221 | loadFeatherlessModels(data?.data); | 1219 | loadFeatherlessModels(data?.data); |
| 1222 | setOnlineStatus(textgen_settings.featherless_model); | 1220 | setOnlineStatus(textgen_settings.featherless_model); |
| 1223 | } else if (textgen_settings.type === TABBY) { | 1221 | } else if (textgen_settings.type === textgen_types.TABBY) { |
| 1224 | loadTabbyModels(data?.data); | 1222 | loadTabbyModels(data?.data); |
| 1225 | setOnlineStatus(textgen_settings.tabby_model || data?.result); | 1223 | setOnlineStatus(textgen_settings.tabby_model || data?.result); |
| 1226 | } else { | 1224 | } else { |
| @@ -1637,7 +1635,7 @@ export function getEntitiesList({ doFilter = false, doSort = true } = {}) { | |||
| 1637 | subEntities = entitiesFilter.applyFilters(subEntities, { clearScoreCache: false, tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED }, clearFuzzySearchCaches: false }); | 1635 | subEntities = entitiesFilter.applyFilters(subEntities, { clearScoreCache: false, tempOverrides: { [FILTER_TYPES.FOLDER]: FILTER_STATES.UNDEFINED }, clearFuzzySearchCaches: false }); |
| 1638 | } | 1636 | } |
| 1639 | if (doSort) { | 1637 | if (doSort) { |
| 1640 | sortEntitiesList(subEntities); | 1638 | sortEntitiesList(subEntities, false); |
| 1641 | } | 1639 | } |
| 1642 | entity.entities = subEntities; | 1640 | entity.entities = subEntities; |
| 1643 | entity.hidden = subCount - subEntities.length; | 1641 | entity.hidden = subCount - subEntities.length; |
| @@ -1665,7 +1663,7 @@ export function getEntitiesList({ doFilter = false, doSort = true } = {}) { | |||
| 1665 | 1663 | ||
| 1666 | // Sort before returning if requested | 1664 | // Sort before returning if requested |
| 1667 | if (doSort) { | 1665 | if (doSort) { |
| 1668 | sortEntitiesList(entities); | 1666 | sortEntitiesList(entities, false); |
| 1669 | } | 1667 | } |
| 1670 | entitiesFilter.clearFuzzySearchCaches(); | 1668 | entitiesFilter.clearFuzzySearchCaches(); |
| 1671 | return entities; | 1669 | return entities; |
| @@ -2607,15 +2605,18 @@ export function substituteParams(content, _name1, _name2, _original, _group, _re | |||
| 2607 | }; | 2605 | }; |
| 2608 | } | 2606 | } |
| 2609 | 2607 | ||
| 2610 | const getGroupValue = () => { | 2608 | const getGroupValue = (includeMuted) => { |
| 2611 | if (typeof _group === 'string') { | 2609 | if (typeof _group === 'string') { |
| 2612 | return _group; | 2610 | return _group; |
| 2613 | } | 2611 | } |
| 2614 | 2612 | ||
| 2615 | if (selected_group) { | 2613 | if (selected_group) { |
| 2616 | const members = groups.find(x => x.id === selected_group)?.members; | 2614 | const members = groups.find(x => x.id === selected_group)?.members; |
| 2615 | /** @type {string[]} */ | ||
| 2616 | const disabledMembers = groups.find(x => x.id === selected_group)?.disabled_members ?? []; | ||
| 2617 | const isMuted = x => includeMuted ? true : !disabledMembers.includes(x); | ||
| 2617 | const names = Array.isArray(members) | 2618 | const names = Array.isArray(members) |
| 2618 | ? members.map(m => characters.find(c => c.avatar === m)?.name).filter(Boolean).join(', ') | 2619 | ? members.filter(isMuted).map(m => characters.find(c => c.avatar === m)?.name).filter(Boolean).join(', ') |
| 2619 | : ''; | 2620 | : ''; |
| 2620 | return names; | 2621 | return names; |
| 2621 | } else { | 2622 | } else { |
| @@ -2639,7 +2640,8 @@ export function substituteParams(content, _name1, _name2, _original, _group, _re | |||
| 2639 | // Must be substituted last so that they're replaced inside {{description}} | 2640 | // Must be substituted last so that they're replaced inside {{description}} |
| 2640 | environment.user = _name1 ?? name1; | 2641 | environment.user = _name1 ?? name1; |
| 2641 | environment.char = _name2 ?? name2; | 2642 | environment.char = _name2 ?? name2; |
| 2642 | environment.group = environment.charIfNotGroup = getGroupValue(); | 2643 | environment.group = environment.charIfNotGroup = getGroupValue(true); |
| 2644 | environment.groupNotMuted = getGroupValue(false); | ||
| 2643 | environment.model = getGeneratingModel(); | 2645 | environment.model = getGeneratingModel(); |
| 2644 | 2646 | ||
| 2645 | if (additionalMacro && typeof additionalMacro === 'object') { | 2647 | if (additionalMacro && typeof additionalMacro === 'object') { |
| @@ -4494,6 +4496,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4494 | instruction: main_api !== 'openai' && power_user.sysprompt.enabled ? substituteParams(power_user.prefer_character_prompt && system ? system : power_user.sysprompt.content) : '', | 4496 | instruction: main_api !== 'openai' && power_user.sysprompt.enabled ? substituteParams(power_user.prefer_character_prompt && system ? system : power_user.sysprompt.content) : '', |
| 4495 | userPersona: (power_user.persona_description_position == persona_description_positions.IN_PROMPT ? (persona || '') : ''), | 4497 | userPersona: (power_user.persona_description_position == persona_description_positions.IN_PROMPT ? (persona || '') : ''), |
| 4496 | tokenizer: getFriendlyTokenizerName(main_api).tokenizerName || '', | 4498 | tokenizer: getFriendlyTokenizerName(main_api).tokenizerName || '', |
| 4499 | presetName: getPresetManager()?.getSelectedPresetName() || '', | ||
| 4497 | }; | 4500 | }; |
| 4498 | 4501 | ||
| 4499 | //console.log(additionalPromptStuff); | 4502 | //console.log(additionalPromptStuff); |
| @@ -5160,6 +5163,7 @@ export async function itemizedParams(itemizedPrompts, thisPromptSet, incomingMes | |||
| 5160 | dataBankVectorsStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].dataBankVectorsString), | 5163 | dataBankVectorsStringTokens: await getTokenCountAsync(itemizedPrompts[thisPromptSet].dataBankVectorsString), |
| 5161 | modelUsed: chat[incomingMesId]?.extra?.model, | 5164 | modelUsed: chat[incomingMesId]?.extra?.model, |
| 5162 | apiUsed: chat[incomingMesId]?.extra?.api, | 5165 | apiUsed: chat[incomingMesId]?.extra?.api, |
| 5166 | presetName: itemizedPrompts[thisPromptSet].presetName || t`(Unknown)`, | ||
| 5163 | }; | 5167 | }; |
| 5164 | 5168 | ||
| 5165 | const getFriendlyName = (value) => $(`#rm_api_block select option[value="${value}"]`).first().text() || value; | 5169 | const getFriendlyName = (value) => $(`#rm_api_block select option[value="${value}"]`).first().text() || value; |
| @@ -5536,7 +5540,7 @@ function extractMultiSwipes(data, type) { | |||
| 5536 | return swipes; | 5540 | return swipes; |
| 5537 | } | 5541 | } |
| 5538 | 5542 | ||
| 5539 | if (main_api === 'openai' || (main_api === 'textgenerationwebui' && [MANCER, VLLM, APHRODITE, TABBY, INFERMATICAI].includes(textgen_settings.type))) { | 5543 | if (main_api === 'openai' || (main_api === 'textgenerationwebui' && [textgen_types.MANCER, textgen_types.VLLM, textgen_types.APHRODITE, textgen_types.TABBY, textgen_types.INFERMATICAI].includes(textgen_settings.type))) { |
| 5540 | if (!Array.isArray(data.choices)) { | 5544 | if (!Array.isArray(data.choices)) { |
| 5541 | return swipes; | 5545 | return swipes; |
| 5542 | } | 5546 | } |
| @@ -5699,7 +5703,7 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc | |||
| 5699 | return getMessage; | 5703 | return getMessage; |
| 5700 | } | 5704 | } |
| 5701 | 5705 | ||
| 5702 | async function saveReply(type, getMessage, fromStreaming, title, swipes) { | 5706 | export async function saveReply(type, getMessage, fromStreaming, title, swipes) { |
| 5703 | if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined || | 5707 | if (type != 'append' && type != 'continue' && type != 'appendFinal' && chat.length && (chat[chat.length - 1]['swipe_id'] === undefined || |
| 5704 | chat[chat.length - 1]['is_user'])) { | 5708 | chat[chat.length - 1]['is_user'])) { |
| 5705 | type = 'normal'; | 5709 | type = 'normal'; |
| @@ -7658,14 +7662,12 @@ export function showSwipeButtons() { | |||
| 7658 | //allows for writing individual swipe counters for past messages | 7662 | //allows for writing individual swipe counters for past messages |
| 7659 | const lastSwipeCounter = $('.last_mes .swipes-counter'); | 7663 | const lastSwipeCounter = $('.last_mes .swipes-counter'); |
| 7660 | lastSwipeCounter.text(swipeCounterText).show(); | 7664 | lastSwipeCounter.text(swipeCounterText).show(); |
| 7661 | |||
| 7662 | switchSwipeNumAllMessages(); | ||
| 7663 | } | 7665 | } |
| 7664 | 7666 | ||
| 7665 | export function hideSwipeButtons() { | 7667 | export function hideSwipeButtons() { |
| 7666 | $('#chat').find('.swipe_right').hide(); | 7668 | chatElement.find('.swipe_right').hide(); |
| 7667 | $('#chat').find('.last_mes .swipes-counter').hide(); | 7669 | chatElement.find('.last_mes .swipes-counter').hide(); |
| 7668 | $('#chat').find('.swipe_left').hide(); | 7670 | chatElement.find('.swipe_left').hide(); |
| 7669 | } | 7671 | } |
| 7670 | 7672 | ||
| 7671 | /** | 7673 | /** |
| @@ -7752,25 +7754,31 @@ export async function saveChatConditional() { | |||
| 7752 | } | 7754 | } |
| 7753 | } | 7755 | } |
| 7754 | 7756 | ||
| 7755 | async function importCharacterChat(formData) { | 7757 | /** |
| 7756 | await jQuery.ajax({ | 7758 | * Saves the chat to the server. |
| 7757 | type: 'POST', | 7759 | * @param {FormData} formData Form data to send to the server. |
| 7758 | url: '/api/chats/import', | 7760 | * @param {EventTarget} eventTarget Event target to trigger the event on. |
| 7759 | data: formData, | 7761 | */ |
| 7760 | beforeSend: function () { | 7762 | async function importCharacterChat(formData, eventTarget) { |
| 7761 | }, | 7763 | const headers = getRequestHeaders(); |
| 7762 | cache: false, | 7764 | delete headers['Content-Type']; |
| 7763 | contentType: false, | 7765 | const fetchResult = await fetch('/api/chats/import', { |
| 7764 | processData: false, | 7766 | method: 'POST', |
| 7765 | success: async function (data) { | 7767 | body: formData, |
| 7766 | if (data.res) { | 7768 | headers: headers, |
| 7767 | await displayPastChats(); | 7769 | cache: 'no-cache', |
| 7768 | } | ||
| 7769 | }, | ||
| 7770 | error: function () { | ||
| 7771 | $('#create_button').removeAttr('disabled'); | ||
| 7772 | }, | ||
| 7773 | }); | 7770 | }); |
| 7771 | |||
| 7772 | if (fetchResult.ok) { | ||
| 7773 | const data = await fetchResult.json(); | ||
| 7774 | if (data.res) { | ||
| 7775 | await displayPastChats(); | ||
| 7776 | } | ||
| 7777 | } | ||
| 7778 | |||
| 7779 | if (eventTarget instanceof HTMLInputElement) { | ||
| 7780 | eventTarget.value = ''; | ||
| 7781 | } | ||
| 7774 | } | 7782 | } |
| 7775 | 7783 | ||
| 7776 | function updateViewMessageIds(startFromZero = false) { | 7784 | function updateViewMessageIds(startFromZero = false) { |
| @@ -8225,102 +8233,6 @@ async function createOrEditCharacter(e) { | |||
| 8225 | } | 8233 | } |
| 8226 | } | 8234 | } |
| 8227 | 8235 | ||
| 8228 | window['SillyTavern'].getContext = function () { | ||
| 8229 | return { | ||
| 8230 | chat: chat, | ||
| 8231 | characters: characters, | ||
| 8232 | groups: groups, | ||
| 8233 | name1: name1, | ||
| 8234 | name2: name2, | ||
| 8235 | characterId: this_chid, | ||
| 8236 | groupId: selected_group, | ||
| 8237 | chatId: selected_group | ||
| 8238 | ? groups.find(x => x.id == selected_group)?.chat_id | ||
| 8239 | : (this_chid && characters[this_chid] && characters[this_chid].chat), | ||
| 8240 | getCurrentChatId: getCurrentChatId, | ||
| 8241 | getRequestHeaders: getRequestHeaders, | ||
| 8242 | reloadCurrentChat: reloadCurrentChat, | ||
| 8243 | renameChat: renameChat, | ||
| 8244 | saveSettingsDebounced: saveSettingsDebounced, | ||
| 8245 | onlineStatus: online_status, | ||
| 8246 | maxContext: Number(max_context), | ||
| 8247 | chatMetadata: chat_metadata, | ||
| 8248 | streamingProcessor, | ||
| 8249 | eventSource: eventSource, | ||
| 8250 | eventTypes: event_types, | ||
| 8251 | addOneMessage: addOneMessage, | ||
| 8252 | generate: Generate, | ||
| 8253 | sendStreamingRequest: sendStreamingRequest, | ||
| 8254 | sendGenerationRequest: sendGenerationRequest, | ||
| 8255 | stopGeneration: stopGeneration, | ||
| 8256 | getTokenCount: getTokenCount, | ||
| 8257 | extensionPrompts: extension_prompts, | ||
| 8258 | setExtensionPrompt: setExtensionPrompt, | ||
| 8259 | updateChatMetadata: updateChatMetadata, | ||
| 8260 | saveChat: saveChatConditional, | ||
| 8261 | openCharacterChat: openCharacterChat, | ||
| 8262 | openGroupChat: openGroupChat, | ||
| 8263 | saveMetadata: saveMetadata, | ||
| 8264 | sendSystemMessage: sendSystemMessage, | ||
| 8265 | activateSendButtons, | ||
| 8266 | deactivateSendButtons, | ||
| 8267 | saveReply, | ||
| 8268 | substituteParams, | ||
| 8269 | substituteParamsExtended, | ||
| 8270 | SlashCommandParser, | ||
| 8271 | SlashCommand, | ||
| 8272 | SlashCommandArgument, | ||
| 8273 | SlashCommandNamedArgument, | ||
| 8274 | ARGUMENT_TYPE, | ||
| 8275 | executeSlashCommandsWithOptions, | ||
| 8276 | /** @deprecated Use SlashCommandParser.addCommandObject() instead */ | ||
| 8277 | registerSlashCommand: registerSlashCommand, | ||
| 8278 | /** @deprecated Use executeSlashCommandWithOptions instead */ | ||
| 8279 | executeSlashCommands: executeSlashCommands, | ||
| 8280 | timestampToMoment: timestampToMoment, | ||
| 8281 | /** @deprecated Handlebars for extensions are no longer supported. */ | ||
| 8282 | registerHelper: () => { }, | ||
| 8283 | registerMacro: MacrosParser.registerMacro.bind(MacrosParser), | ||
| 8284 | unregisterMacro: MacrosParser.unregisterMacro.bind(MacrosParser), | ||
| 8285 | registerFunctionTool: ToolManager.registerFunctionTool.bind(ToolManager), | ||
| 8286 | unregisterFunctionTool: ToolManager.unregisterFunctionTool.bind(ToolManager), | ||
| 8287 | isToolCallingSupported: ToolManager.isToolCallingSupported.bind(ToolManager), | ||
| 8288 | canPerformToolCalls: ToolManager.canPerformToolCalls.bind(ToolManager), | ||
| 8289 | registerDebugFunction: registerDebugFunction, | ||
| 8290 | /** @deprecated Use renderExtensionTemplateAsync instead. */ | ||
| 8291 | renderExtensionTemplate: renderExtensionTemplate, | ||
| 8292 | renderExtensionTemplateAsync: renderExtensionTemplateAsync, | ||
| 8293 | registerDataBankScraper: ScraperManager.registerDataBankScraper, | ||
| 8294 | /** @deprecated Use callGenericPopup or Popup instead. */ | ||
| 8295 | callPopup: callPopup, | ||
| 8296 | callGenericPopup: callGenericPopup, | ||
| 8297 | showLoader: showLoader, | ||
| 8298 | hideLoader: hideLoader, | ||
| 8299 | mainApi: main_api, | ||
| 8300 | extensionSettings: extension_settings, | ||
| 8301 | ModuleWorkerWrapper: ModuleWorkerWrapper, | ||
| 8302 | getTokenizerModel: getTokenizerModel, | ||
| 8303 | generateQuietPrompt: generateQuietPrompt, | ||
| 8304 | writeExtensionField: writeExtensionField, | ||
| 8305 | getThumbnailUrl: getThumbnailUrl, | ||
| 8306 | selectCharacterById: selectCharacterById, | ||
| 8307 | messageFormatting: messageFormatting, | ||
| 8308 | shouldSendOnEnter: shouldSendOnEnter, | ||
| 8309 | isMobile: isMobile, | ||
| 8310 | t: t, | ||
| 8311 | translate: translate, | ||
| 8312 | tags: tags, | ||
| 8313 | tagMap: tag_map, | ||
| 8314 | menuType: menu_type, | ||
| 8315 | createCharacterData: create_save, | ||
| 8316 | /** @deprecated Legacy snake-case naming, compatibility with old extensions */ | ||
| 8317 | event_types: event_types, | ||
| 8318 | Popup: Popup, | ||
| 8319 | POPUP_TYPE: POPUP_TYPE, | ||
| 8320 | POPUP_RESULT: POPUP_RESULT, | ||
| 8321 | }; | ||
| 8322 | }; | ||
| 8323 | |||
| 8324 | /** | 8236 | /** |
| 8325 | * Formats a counter for a swipe view. | 8237 | * Formats a counter for a swipe view. |
| 8326 | * @param {number} current The current number of items. | 8238 | * @param {number} current The current number of items. |
| @@ -10827,13 +10739,13 @@ jQuery(async function () { | |||
| 10827 | }); | 10739 | }); |
| 10828 | 10740 | ||
| 10829 | $('#chat_import_file').on('change', async function (e) { | 10741 | $('#chat_import_file').on('change', async function (e) { |
| 10830 | var file = e.target.files[0]; | 10742 | const file = e.target.files[0]; |
| 10831 | 10743 | ||
| 10832 | if (!file) { | 10744 | if (!file) { |
| 10833 | return; | 10745 | return; |
| 10834 | } | 10746 | } |
| 10835 | 10747 | ||
| 10836 | var ext = file.name.match(/\.(\w+)$/); | 10748 | const ext = file.name.match(/\.(\w+)$/); |
| 10837 | if ( | 10749 | if ( |
| 10838 | !ext || | 10750 | !ext || |
| 10839 | (ext[1].toLowerCase() != 'json' && ext[1].toLowerCase() != 'jsonl') | 10751 | (ext[1].toLowerCase() != 'json' && ext[1].toLowerCase() != 'jsonl') |
| @@ -10846,17 +10758,17 @@ jQuery(async function () { | |||
| 10846 | return; | 10758 | return; |
| 10847 | } | 10759 | } |
| 10848 | 10760 | ||
| 10849 | var format = ext[1].toLowerCase(); | 10761 | const format = ext[1].toLowerCase(); |
| 10850 | $('#chat_import_file_type').val(format); | 10762 | $('#chat_import_file_type').val(format); |
| 10851 | 10763 | ||
| 10852 | var formData = new FormData($('#form_import_chat').get(0)); | 10764 | const formData = new FormData($('#form_import_chat').get(0)); |
| 10853 | formData.append('user_name', name1); | 10765 | formData.append('user_name', name1); |
| 10854 | $('#select_chat_div').html(''); | 10766 | $('#select_chat_div').html(''); |
| 10855 | 10767 | ||
| 10856 | if (selected_group) { | 10768 | if (selected_group) { |
| 10857 | await importGroupChat(formData); | 10769 | await importGroupChat(formData, e.originalEvent.target); |
| 10858 | } else { | 10770 | } else { |
| 10859 | await importCharacterChat(formData); | 10771 | await importCharacterChat(formData, e.originalEvent.target); |
| 10860 | } | 10772 | } |
| 10861 | }); | 10773 | }); |
| 10862 | 10774 | ||
| @@ -75,6 +75,7 @@ | |||
| 75 | * @property {string} [source_url] - The source URL associated with the character. | 75 | * @property {string} [source_url] - The source URL associated with the character. |
| 76 | * @property {{full_path: string}} [chub] - The Chub-specific data associated with the character. | 76 | * @property {{full_path: string}} [chub] - The Chub-specific data associated with the character. |
| 77 | * @property {{source: string[]}} [risuai] - The RisuAI-specific data associated with the character. | 77 | * @property {{source: string[]}} [risuai] - The RisuAI-specific data associated with the character. |
| 78 | * @property {{positive: string, negative: string}} [sd_character_prompt] - SD-specific data associated with the character. | ||
| 78 | */ | 79 | */ |
| 79 | 80 | ||
| 80 | /** | 81 | /** |
| @@ -5,6 +5,7 @@ import { showLoader } from './loader.js'; | |||
| 5 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; | 5 | import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; |
| 6 | import { renderTemplate, renderTemplateAsync } from './templates.js'; | 6 | import { renderTemplate, renderTemplateAsync } from './templates.js'; |
| 7 | import { isSubsetOf, setValueByPath } from './utils.js'; | 7 | import { isSubsetOf, setValueByPath } from './utils.js'; |
| 8 | import { getContext } from './st-context.js'; | ||
| 8 | export { | 9 | export { |
| 9 | getContext, | 10 | getContext, |
| 10 | getApiUrl, | 11 | getApiUrl, |
| @@ -174,7 +175,6 @@ const extension_settings = { | |||
| 174 | let modules = []; | 175 | let modules = []; |
| 175 | let activeExtensions = new Set(); | 176 | let activeExtensions = new Set(); |
| 176 | 177 | ||
| 177 | const getContext = () => window['SillyTavern'].getContext(); | ||
| 178 | const getApiUrl = () => extension_settings.apiUrl; | 178 | const getApiUrl = () => extension_settings.apiUrl; |
| 179 | let connectedToApi = false; | 179 | let connectedToApi = false; |
| 180 | 180 | ||
| @@ -62,6 +62,7 @@ | |||
| 62 | <option data-type="google" value="gemini-1.5-flash-8b-exp-0924">gemini-1.5-flash-8b-exp-0924</option> | 62 | <option data-type="google" value="gemini-1.5-flash-8b-exp-0924">gemini-1.5-flash-8b-exp-0924</option> |
| 63 | <option data-type="google" value="gemini-exp-1114">gemini-exp-1114</option> | 63 | <option data-type="google" value="gemini-exp-1114">gemini-exp-1114</option> |
| 64 | <option data-type="google" value="gemini-exp-1121">gemini-exp-1121</option> | 64 | <option data-type="google" value="gemini-exp-1121">gemini-exp-1121</option> |
| 65 | <option data-type="google" value="gemini-exp-1206">gemini-exp-1206</option> | ||
| 65 | <option data-type="google" value="gemini-1.5-pro">gemini-1.5-pro</option> | 66 | <option data-type="google" value="gemini-1.5-pro">gemini-1.5-pro</option> |
| 66 | <option data-type="google" value="gemini-1.5-pro-latest">gemini-1.5-pro-latest</option> | 67 | <option data-type="google" value="gemini-1.5-pro-latest">gemini-1.5-pro-latest</option> |
| 67 | <option data-type="google" value="gemini-1.5-pro-001">gemini-1.5-pro-001</option> | 68 | <option data-type="google" value="gemini-1.5-pro-001">gemini-1.5-pro-001</option> |
| @@ -60,7 +60,6 @@ import { ToolManager } from '../../tool-calling.js'; | |||
| 60 | export { MODULE_NAME }; | 60 | export { MODULE_NAME }; |
| 61 | 61 | ||
| 62 | const MODULE_NAME = 'sd'; | 62 | const MODULE_NAME = 'sd'; |
| 63 | const UPDATE_INTERVAL = 1000; | ||
| 64 | // This is a 1x1 transparent PNG | 63 | // This is a 1x1 transparent PNG |
| 65 | const PNG_PIXEL = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; | 64 | const PNG_PIXEL = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; |
| 66 | const CUSTOM_STOP_EVENT = 'sd_stop_generation'; | 65 | const CUSTOM_STOP_EVENT = 'sd_stop_generation'; |
| @@ -3687,8 +3686,6 @@ async function addSDGenButtons() { | |||
| 3687 | const button = $('#sd_gen'); | 3686 | const button = $('#sd_gen'); |
| 3688 | const dropdown = $('#sd_dropdown'); | 3687 | const dropdown = $('#sd_dropdown'); |
| 3689 | dropdown.hide(); | 3688 | dropdown.hide(); |
| 3690 | button.hide(); | ||
| 3691 | messageButton.hide(); | ||
| 3692 | 3689 | ||
| 3693 | let popper = Popper.createPopper(button.get(0), dropdown.get(0), { | 3690 | let popper = Popper.createPopper(button.get(0), dropdown.get(0), { |
| 3694 | placement: 'top', | 3691 | placement: 'top', |
| @@ -3770,18 +3767,6 @@ function isValidState() { | |||
| 3770 | } | 3767 | } |
| 3771 | } | 3768 | } |
| 3772 | 3769 | ||
| 3773 | async function moduleWorker() { | ||
| 3774 | if (isValidState()) { | ||
| 3775 | $('#sd_gen').show(); | ||
| 3776 | $('.sd_message_gen').show(); | ||
| 3777 | } | ||
| 3778 | else { | ||
| 3779 | $('#sd_gen').hide(); | ||
| 3780 | $('.sd_message_gen').hide(); | ||
| 3781 | } | ||
| 3782 | } | ||
| 3783 | |||
| 3784 | setInterval(moduleWorker, UPDATE_INTERVAL); | ||
| 3785 | let buttonAbortController = null; | 3770 | let buttonAbortController = null; |
| 3786 | 3771 | ||
| 3787 | async function sdMessageButton(e) { | 3772 | async function sdMessageButton(e) { |
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #sd_dropdown { | 5 | #sd_dropdown { |
| 6 | z-index: 30000; | 6 | z-index: 30000; |
| 7 | backdrop-filter: blur(--SmartThemeBlurStrength); | 7 | backdrop-filter: blur(var(--SmartThemeBlurStrength)); |
| 8 | } | 8 | } |
| 9 | 9 | ||
| 10 | #sd_comfy_open_workflow_editor { | 10 | #sd_comfy_open_workflow_editor { |
| @@ -93,7 +93,7 @@ | |||
| 93 | .at-settings-separator { | 93 | .at-settings-separator { |
| 94 | margin-top: 10px; | 94 | margin-top: 10px; |
| 95 | margin-bottom: 10px; | 95 | margin-bottom: 10px; |
| 96 | padding: 18x; | 96 | padding: 18px; |
| 97 | font-weight: bold; | 97 | font-weight: bold; |
| 98 | border-top: 1px solid #e1e1e1; /* Grey line */ | 98 | border-top: 1px solid #e1e1e1; /* Grey line */ |
| 99 | border-bottom: 1px solid #e1e1e1; /* Grey line */ | 99 | border-bottom: 1px solid #e1e1e1; /* Grey line */ |
| @@ -1265,18 +1265,20 @@ function getGroupCharacters({ doFilter, onlyMembers } = {}) { | |||
| 1265 | const thisGroup = openGroupId && groups.find((x) => x.id == openGroupId); | 1265 | const thisGroup = openGroupId && groups.find((x) => x.id == openGroupId); |
| 1266 | let candidates = characters | 1266 | let candidates = characters |
| 1267 | .filter((x) => isGroupMember(thisGroup, x.avatar) == onlyMembers) | 1267 | .filter((x) => isGroupMember(thisGroup, x.avatar) == onlyMembers) |
| 1268 | .map((x, index) => ({ item: x, id: index, type: 'character' })); | 1268 | .map((x) => ({ item: x, id: characters.indexOf(x), type: 'character' })); |
| 1269 | |||
| 1270 | if (doFilter) { | ||
| 1271 | candidates = groupCandidatesFilter.applyFilters(candidates); | ||
| 1272 | } | ||
| 1269 | 1273 | ||
| 1270 | if (onlyMembers) { | 1274 | if (onlyMembers) { |
| 1271 | candidates.sort(sortMembersFn); | 1275 | candidates.sort(sortMembersFn); |
| 1272 | } else { | 1276 | } else { |
| 1273 | sortEntitiesList(candidates); | 1277 | const useFilterOrder = doFilter && !!$('#rm_group_filter').val(); |
| 1274 | } | 1278 | sortEntitiesList(candidates, useFilterOrder, groupCandidatesFilter); |
| 1275 | |||
| 1276 | if (doFilter) { | ||
| 1277 | candidates = groupCandidatesFilter.applyFilters(candidates); | ||
| 1278 | } | 1279 | } |
| 1279 | 1280 | ||
| 1281 | groupCandidatesFilter.clearFuzzySearchCaches(); | ||
| 1280 | return candidates; | 1282 | return candidates; |
| 1281 | } | 1283 | } |
| 1282 | 1284 | ||
| @@ -1863,32 +1865,38 @@ export async function deleteGroupChat(groupId, chatId) { | |||
| 1863 | } | 1865 | } |
| 1864 | } | 1866 | } |
| 1865 | 1867 | ||
| 1866 | export async function importGroupChat(formData) { | 1868 | /** |
| 1867 | await jQuery.ajax({ | 1869 | * Imports a group chat from a file and adds it to the group. |
| 1868 | type: 'POST', | 1870 | * @param {FormData} formData Form data to send to the server |
| 1869 | url: '/api/chats/group/import', | 1871 | * @param {EventTarget} eventTarget Element that triggered the import |
| 1870 | data: formData, | 1872 | */ |
| 1871 | beforeSend: function () { | 1873 | export async function importGroupChat(formData, eventTarget) { |
| 1872 | }, | 1874 | const headers = getRequestHeaders(); |
| 1873 | cache: false, | 1875 | delete headers['Content-Type']; |
| 1874 | contentType: false, | 1876 | const fetchResult = await fetch('/api/chats/group/import', { |
| 1875 | processData: false, | 1877 | method: 'POST', |
| 1876 | success: async function (data) { | 1878 | headers: headers, |
| 1877 | if (data.res) { | 1879 | body: formData, |
| 1878 | const chatId = data.res; | 1880 | cache: 'no-cache', |
| 1879 | const group = groups.find(x => x.id == selected_group); | ||
| 1880 | |||
| 1881 | if (group) { | ||
| 1882 | group.chats.push(chatId); | ||
| 1883 | await editGroup(selected_group, true, true); | ||
| 1884 | await displayPastChats(); | ||
| 1885 | } | ||
| 1886 | } | ||
| 1887 | }, | ||
| 1888 | error: function () { | ||
| 1889 | $('#create_button').removeAttr('disabled'); | ||
| 1890 | }, | ||
| 1891 | }); | 1881 | }); |
| 1882 | |||
| 1883 | if (fetchResult.ok) { | ||
| 1884 | const data = await fetchResult.json(); | ||
| 1885 | if (data.res) { | ||
| 1886 | const chatId = data.res; | ||
| 1887 | const group = groups.find(x => x.id == selected_group); | ||
| 1888 | |||
| 1889 | if (group) { | ||
| 1890 | group.chats.push(chatId); | ||
| 1891 | await editGroup(selected_group, true, true); | ||
| 1892 | await displayPastChats(); | ||
| 1893 | } | ||
| 1894 | } | ||
| 1895 | } | ||
| 1896 | |||
| 1897 | if (eventTarget instanceof HTMLInputElement) { | ||
| 1898 | eventTarget.value = ''; | ||
| 1899 | } | ||
| 1892 | } | 1900 | } |
| 1893 | 1901 | ||
| 1894 | export async function saveGroupBookmarkChat(groupId, name, metadata, mesId) { | 1902 | export async function saveGroupBookmarkChat(groupId, name, metadata, mesId) { |
| @@ -379,8 +379,8 @@ export let selected_proxy = proxies[0]; | |||
| 379 | let openai_setting_names; | 379 | let openai_setting_names; |
| 380 | let openai_settings; | 380 | let openai_settings; |
| 381 | 381 | ||
| 382 | 382 | /** @type {import('./PromptManager.js').PromptManager} */ | |
| 383 | let promptManager = null; | 383 | export let promptManager = null; |
| 384 | 384 | ||
| 385 | async function validateReverseProxy() { | 385 | async function validateReverseProxy() { |
| 386 | if (!oai_settings.reverse_proxy) { | 386 | if (!oai_settings.reverse_proxy) { |
| @@ -1812,6 +1812,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 1812 | const isPerplexity = oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY; | 1812 | const isPerplexity = oai_settings.chat_completion_source == chat_completion_sources.PERPLEXITY; |
| 1813 | const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ; | 1813 | const isGroq = oai_settings.chat_completion_source == chat_completion_sources.GROQ; |
| 1814 | const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI; | 1814 | const is01AI = oai_settings.chat_completion_source == chat_completion_sources.ZEROONEAI; |
| 1815 | const isNano = oai_settings.chat_completion_source == chat_completion_sources.NANOGPT; | ||
| 1815 | const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model); | 1816 | const isTextCompletion = isOAI && textCompletionModels.includes(oai_settings.openai_model); |
| 1816 | const isQuiet = type === 'quiet'; | 1817 | const isQuiet = type === 'quiet'; |
| 1817 | const isImpersonate = type === 'impersonate'; | 1818 | const isImpersonate = type === 'impersonate'; |
| @@ -1971,7 +1972,7 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 1971 | delete generate_data.stop; | 1972 | delete generate_data.stop; |
| 1972 | } | 1973 | } |
| 1973 | 1974 | ||
| 1974 | if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere) && oai_settings.seed >= 0) { | 1975 | if ((isOAI || isOpenRouter || isMistral || isCustom || isCohere || isNano) && oai_settings.seed >= 0) { |
| 1975 | generate_data['seed'] = oai_settings.seed; | 1976 | generate_data['seed'] = oai_settings.seed; |
| 1976 | } | 1977 | } |
| 1977 | 1978 | ||
| @@ -4076,7 +4077,7 @@ async function onModelChange() { | |||
| 4076 | $('#openai_max_context').attr('max', max_2mil); | 4077 | $('#openai_max_context').attr('max', max_2mil); |
| 4077 | } else if (value.includes('gemini-exp-1114') || value.includes('gemini-exp-1121')) { | 4078 | } else if (value.includes('gemini-exp-1114') || value.includes('gemini-exp-1121')) { |
| 4078 | $('#openai_max_context').attr('max', max_32k); | 4079 | $('#openai_max_context').attr('max', max_32k); |
| 4079 | } else if (value.includes('gemini-1.5-pro')) { | 4080 | } else if (value.includes('gemini-1.5-pro') || value.includes('gemini-exp-1206')) { |
| 4080 | $('#openai_max_context').attr('max', max_2mil); | 4081 | $('#openai_max_context').attr('max', max_2mil); |
| 4081 | } else if (value.includes('gemini-1.5-flash')) { | 4082 | } else if (value.includes('gemini-1.5-flash')) { |
| 4082 | $('#openai_max_context').attr('max', max_1mil); | 4083 | $('#openai_max_context').attr('max', max_1mil); |
| @@ -4760,6 +4761,7 @@ export function isImageInliningSupported() { | |||
| 4760 | 'gemini-1.5-flash-8b-exp-0924', | 4761 | 'gemini-1.5-flash-8b-exp-0924', |
| 4761 | 'gemini-exp-1114', | 4762 | 'gemini-exp-1114', |
| 4762 | 'gemini-exp-1121', | 4763 | 'gemini-exp-1121', |
| 4764 | 'gemini-exp-1206', | ||
| 4763 | 'gemini-1.0-pro-vision-latest', | 4765 | 'gemini-1.0-pro-vision-latest', |
| 4764 | 'gemini-1.5-pro', | 4766 | 'gemini-1.5-pro', |
| 4765 | 'gemini-1.5-pro-latest', | 4767 | 'gemini-1.5-pro-latest', |
| @@ -60,7 +60,6 @@ export { | |||
| 60 | loadMovingUIState, | 60 | loadMovingUIState, |
| 61 | collapseNewlines, | 61 | collapseNewlines, |
| 62 | playMessageSound, | 62 | playMessageSound, |
| 63 | sortEntitiesList, | ||
| 64 | fixMarkdown, | 63 | fixMarkdown, |
| 65 | power_user, | 64 | power_user, |
| 66 | send_on_enter_options, | 65 | send_on_enter_options, |
| @@ -473,9 +472,9 @@ function switchCompactInputArea() { | |||
| 473 | $('#compact_input_area').prop('checked', power_user.compact_input_area); | 472 | $('#compact_input_area').prop('checked', power_user.compact_input_area); |
| 474 | } | 473 | } |
| 475 | 474 | ||
| 476 | export function switchSwipeNumAllMessages() { | 475 | function switchSwipeNumAllMessages() { |
| 477 | $('#show_swipe_num_all_messages').prop('checked', power_user.show_swipe_num_all_messages); | 476 | $('#show_swipe_num_all_messages').prop('checked', power_user.show_swipe_num_all_messages); |
| 478 | $('.mes:not(.last_mes) .swipes-counter').css('opacity', '').toggle(power_user.show_swipe_num_all_messages); | 477 | $('body').toggleClass('swipeAllMessages', !!power_user.show_swipe_num_all_messages); |
| 479 | } | 478 | } |
| 480 | 479 | ||
| 481 | var originalSliderValues = []; | 480 | var originalSliderValues = []; |
| @@ -1837,7 +1836,7 @@ async function loadContextSettings() { | |||
| 1837 | * Common function to perform fuzzy search with optional caching | 1836 | * Common function to perform fuzzy search with optional caching |
| 1838 | * @param {string} type - Type of search from fuzzySearchCategories | 1837 | * @param {string} type - Type of search from fuzzySearchCategories |
| 1839 | * @param {any[]} data - Data array to search in | 1838 | * @param {any[]} data - Data array to search in |
| 1840 | * @param {Array<{name: string, weight: number, getFn?: Function}>} keys - Fuse.js keys configuration | 1839 | * @param {Array<{name: string, weight: number, getFn?: (obj: any) => string}>} keys - Fuse.js keys configuration |
| 1841 | * @param {string} searchValue - The search term | 1840 | * @param {string} searchValue - The search term |
| 1842 | * @param {Object.<string, { resultMap: Map<string, any> }>} [fuzzySearchCaches=null] - Optional fuzzy search caches | 1841 | * @param {Object.<string, { resultMap: Map<string, any> }>} [fuzzySearchCaches=null] - Optional fuzzy search caches |
| 1843 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score | 1842 | * @returns {import('fuse.js').FuseResult<any>[]} Results as items with their score |
| @@ -1851,7 +1850,6 @@ function performFuzzySearch(type, data, keys, searchValue, fuzzySearchCaches = n | |||
| 1851 | } | 1850 | } |
| 1852 | } | 1851 | } |
| 1853 | 1852 | ||
| 1854 | // @ts-ignore | ||
| 1855 | const fuse = new Fuse(data, { | 1853 | const fuse = new Fuse(data, { |
| 1856 | keys: keys, | 1854 | keys: keys, |
| 1857 | includeScore: true, | 1855 | includeScore: true, |
| @@ -1925,7 +1923,7 @@ export function fuzzySearchPersonas(data, searchValue, fuzzySearchCaches = null) | |||
| 1925 | const mappedData = data.map(x => ({ | 1923 | const mappedData = data.map(x => ({ |
| 1926 | key: x, | 1924 | key: x, |
| 1927 | name: power_user.personas[x] ?? '', | 1925 | name: power_user.personas[x] ?? '', |
| 1928 | description: power_user.persona_descriptions[x]?.description ?? '' | 1926 | description: power_user.persona_descriptions[x]?.description ?? '', |
| 1929 | })); | 1927 | })); |
| 1930 | 1928 | ||
| 1931 | const keys = [ | 1929 | const keys = [ |
| @@ -2080,19 +2078,22 @@ const compareFunc = (first, second) => { | |||
| 2080 | /** | 2078 | /** |
| 2081 | * Sorts an array of entities based on the current sort settings | 2079 | * Sorts an array of entities based on the current sort settings |
| 2082 | * @param {any[]} entities An array of objects with an `item` property | 2080 | * @param {any[]} entities An array of objects with an `item` property |
| 2081 | * @param {boolean} forceSearch Whether to force search sorting | ||
| 2082 | * @param {import('./filters.js').FilterHelper} [filterHelper=null] Filter helper to use | ||
| 2083 | */ | 2083 | */ |
| 2084 | function sortEntitiesList(entities) { | 2084 | export function sortEntitiesList(entities, forceSearch, filterHelper = null) { |
| 2085 | filterHelper = filterHelper ?? entitiesFilter; | ||
| 2085 | if (power_user.sort_field == undefined || entities.length === 0) { | 2086 | if (power_user.sort_field == undefined || entities.length === 0) { |
| 2086 | return; | 2087 | return; |
| 2087 | } | 2088 | } |
| 2088 | 2089 | ||
| 2089 | if (power_user.sort_order === 'random') { | 2090 | const isSearch = forceSearch || $('#character_sort_order option[data-field="search"]').is(':selected'); |
| 2091 | |||
| 2092 | if (!isSearch && power_user.sort_order === 'random') { | ||
| 2090 | shuffle(entities); | 2093 | shuffle(entities); |
| 2091 | return; | 2094 | return; |
| 2092 | } | 2095 | } |
| 2093 | 2096 | ||
| 2094 | const isSearch = $('#character_sort_order option[data-field="search"]').is(':selected'); | ||
| 2095 | |||
| 2096 | entities.sort((a, b) => { | 2097 | entities.sort((a, b) => { |
| 2097 | // Sort tags/folders will always be at the top | 2098 | // Sort tags/folders will always be at the top |
| 2098 | if (a.type === 'tag' && b.type !== 'tag') { | 2099 | if (a.type === 'tag' && b.type !== 'tag') { |
| @@ -2104,8 +2105,8 @@ function sortEntitiesList(entities) { | |||
| 2104 | 2105 | ||
| 2105 | // If we have search sorting, we take scores and use those | 2106 | // If we have search sorting, we take scores and use those |
| 2106 | if (isSearch) { | 2107 | if (isSearch) { |
| 2107 | const aScore = entitiesFilter.getScore(FILTER_TYPES.SEARCH, `${a.type}.${a.id}`); | 2108 | const aScore = filterHelper.getScore(FILTER_TYPES.SEARCH, `${a.type}.${a.id}`); |
| 2108 | const bScore = entitiesFilter.getScore(FILTER_TYPES.SEARCH, `${b.type}.${b.id}`); | 2109 | const bScore = filterHelper.getScore(FILTER_TYPES.SEARCH, `${b.type}.${b.id}`); |
| 2109 | return (aScore - bScore); | 2110 | return (aScore - bScore); |
| 2110 | } | 2111 | } |
| 2111 | 2112 | ||
| @@ -52,7 +52,7 @@ import { hideChatMessageRange } from './chats.js'; | |||
| 52 | import { getContext, saveMetadataDebounced } from './extensions.js'; | 52 | import { getContext, saveMetadataDebounced } from './extensions.js'; |
| 53 | import { getRegexedString, regex_placement } from './extensions/regex/engine.js'; | 53 | import { getRegexedString, regex_placement } from './extensions/regex/engine.js'; |
| 54 | import { findGroupMemberId, groups, is_group_generating, openGroupById, resetSelectedGroup, saveGroupChat, selected_group } from './group-chats.js'; | 54 | import { findGroupMemberId, groups, is_group_generating, openGroupById, resetSelectedGroup, saveGroupChat, selected_group } from './group-chats.js'; |
| 55 | import { chat_completion_sources, oai_settings, setupChatCompletionPromptManager } from './openai.js'; | 55 | import { chat_completion_sources, oai_settings, promptManager } from './openai.js'; |
| 56 | import { autoSelectPersona, retriggerFirstMessageOnEmptyChat, setPersonaLockState, togglePersonaLock, user_avatar } from './personas.js'; | 56 | import { autoSelectPersona, retriggerFirstMessageOnEmptyChat, setPersonaLockState, togglePersonaLock, user_avatar } from './personas.js'; |
| 57 | import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js'; | 57 | import { addEphemeralStoppingString, chat_styles, flushEphemeralStoppingStrings, power_user } from './power-user.js'; |
| 58 | import { SERVER_INPUTS, textgen_types, textgenerationwebui_settings } from './textgen-settings.js'; | 58 | import { SERVER_INPUTS, textgen_types, textgenerationwebui_settings } from './textgen-settings.js'; |
| @@ -269,7 +269,7 @@ export function initDefaultSlashCommands() { | |||
| 269 | }), | 269 | }), |
| 270 | SlashCommandNamedArgument.fromProps({ | 270 | SlashCommandNamedArgument.fromProps({ |
| 271 | name: 'at', | 271 | name: 'at', |
| 272 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', | 272 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', |
| 273 | typeList: [ARGUMENT_TYPE.NUMBER], | 273 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 274 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), | 274 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), |
| 275 | }), | 275 | }), |
| @@ -325,7 +325,7 @@ export function initDefaultSlashCommands() { | |||
| 325 | ), | 325 | ), |
| 326 | SlashCommandNamedArgument.fromProps({ | 326 | SlashCommandNamedArgument.fromProps({ |
| 327 | name: 'at', | 327 | name: 'at', |
| 328 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', | 328 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', |
| 329 | typeList: [ARGUMENT_TYPE.NUMBER], | 329 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 330 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), | 330 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), |
| 331 | }), | 331 | }), |
| @@ -388,7 +388,7 @@ export function initDefaultSlashCommands() { | |||
| 388 | ), | 388 | ), |
| 389 | SlashCommandNamedArgument.fromProps({ | 389 | SlashCommandNamedArgument.fromProps({ |
| 390 | name: 'at', | 390 | name: 'at', |
| 391 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', | 391 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', |
| 392 | typeList: [ARGUMENT_TYPE.NUMBER], | 392 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 393 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), | 393 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), |
| 394 | }), | 394 | }), |
| @@ -606,7 +606,7 @@ export function initDefaultSlashCommands() { | |||
| 606 | ), | 606 | ), |
| 607 | SlashCommandNamedArgument.fromProps({ | 607 | SlashCommandNamedArgument.fromProps({ |
| 608 | name: 'at', | 608 | name: 'at', |
| 609 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', | 609 | description: 'position to insert the message (index-based, corresponding to message id). If not set, the message will be inserted at the end of the chat.\nNegative values (including -0) are accepted and will work similarly to how \'depth\' usually works. For example, -1 will insert the message right before the last message in chat.', |
| 610 | typeList: [ARGUMENT_TYPE.NUMBER], | 610 | typeList: [ARGUMENT_TYPE.NUMBER], |
| 611 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), | 611 | enumProvider: commonEnumProviders.messages({ allowIdAfter: true }), |
| 612 | }), | 612 | }), |
| @@ -1699,6 +1699,49 @@ export function initDefaultSlashCommands() { | |||
| 1699 | helpString: 'Sets the model for the current API. Gets the current model name if no argument is provided.', | 1699 | helpString: 'Sets the model for the current API. Gets the current model name if no argument is provided.', |
| 1700 | })); | 1700 | })); |
| 1701 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | 1701 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ |
| 1702 | name: 'getpromptentry', | ||
| 1703 | aliases: ['getpromptentries'], | ||
| 1704 | callback: getPromptEntryCallback, | ||
| 1705 | returns: 'true/false state of prompt(s)', | ||
| 1706 | namedArgumentList: [ | ||
| 1707 | SlashCommandNamedArgument.fromProps({ | ||
| 1708 | name: 'identifier', | ||
| 1709 | description: 'Prompt entry identifier(s) to retrieve', | ||
| 1710 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], | ||
| 1711 | acceptsMultiple: true, | ||
| 1712 | enumProvider: () => | ||
| 1713 | promptManager.serviceSettings.prompts | ||
| 1714 | .map(prompt => prompt.identifier) | ||
| 1715 | .map(identifier => new SlashCommandEnumValue(identifier)), | ||
| 1716 | }), | ||
| 1717 | SlashCommandNamedArgument.fromProps({ | ||
| 1718 | name: 'name', | ||
| 1719 | description: 'Prompt entry name(s) to retrieve', | ||
| 1720 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], | ||
| 1721 | acceptsMultiple: true, | ||
| 1722 | enumProvider: () => | ||
| 1723 | promptManager.serviceSettings.prompts | ||
| 1724 | .map(prompt => prompt.name) | ||
| 1725 | .map(name => new SlashCommandEnumValue(name)), | ||
| 1726 | }), | ||
| 1727 | SlashCommandNamedArgument.fromProps({ | ||
| 1728 | name: 'return', | ||
| 1729 | description: 'Whether the return will be simple, a list, or a dict.', | ||
| 1730 | typeList: [ARGUMENT_TYPE.STRING], | ||
| 1731 | defaultValue: 'simple', | ||
| 1732 | enumList: ['simple', 'list', 'dict'], | ||
| 1733 | }), | ||
| 1734 | ], | ||
| 1735 | helpString: ` | ||
| 1736 | <div> | ||
| 1737 | Gets the state of the specified prompt entries. | ||
| 1738 | </div> | ||
| 1739 | <div> | ||
| 1740 | If <code>return</code> is <code>simple</code> (default) then the return will be a single value if only one value was retrieved; otherwise uses a dict (if the identifier parameter was used) or a list. | ||
| 1741 | </div> | ||
| 1742 | `, | ||
| 1743 | })); | ||
| 1744 | SlashCommandParser.addCommandObject(SlashCommand.fromProps({ | ||
| 1702 | name: 'setpromptentry', | 1745 | name: 'setpromptentry', |
| 1703 | aliases: ['setpromptentries'], | 1746 | aliases: ['setpromptentries'], |
| 1704 | callback: setPromptEntryCallback, | 1747 | callback: setPromptEntryCallback, |
| @@ -1709,7 +1752,6 @@ export function initDefaultSlashCommands() { | |||
| 1709 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], | 1752 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], |
| 1710 | acceptsMultiple: true, | 1753 | acceptsMultiple: true, |
| 1711 | enumProvider: () => { | 1754 | enumProvider: () => { |
| 1712 | const promptManager = setupChatCompletionPromptManager(oai_settings); | ||
| 1713 | const prompts = promptManager.serviceSettings.prompts; | 1755 | const prompts = promptManager.serviceSettings.prompts; |
| 1714 | return prompts.map(prompt => new SlashCommandEnumValue(prompt.identifier, prompt.name, enumTypes.enum)); | 1756 | return prompts.map(prompt => new SlashCommandEnumValue(prompt.identifier, prompt.name, enumTypes.enum)); |
| 1715 | }, | 1757 | }, |
| @@ -1720,7 +1762,6 @@ export function initDefaultSlashCommands() { | |||
| 1720 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], | 1762 | typeList: [ARGUMENT_TYPE.STRING, ARGUMENT_TYPE.LIST], |
| 1721 | acceptsMultiple: true, | 1763 | acceptsMultiple: true, |
| 1722 | enumProvider: () => { | 1764 | enumProvider: () => { |
| 1723 | const promptManager = setupChatCompletionPromptManager(oai_settings); | ||
| 1724 | const prompts = promptManager.serviceSettings.prompts; | 1765 | const prompts = promptManager.serviceSettings.prompts; |
| 1725 | return prompts.map(prompt => new SlashCommandEnumValue(prompt.name, prompt.identifier, enumTypes.enum)); | 1766 | return prompts.map(prompt => new SlashCommandEnumValue(prompt.name, prompt.identifier, enumTypes.enum)); |
| 1726 | }, | 1767 | }, |
| @@ -3025,7 +3066,7 @@ async function sendUserMessageCallback(args, text) { | |||
| 3025 | let insertAt = Number(args?.at); | 3066 | let insertAt = Number(args?.at); |
| 3026 | 3067 | ||
| 3027 | // Convert possible depth parameter to index | 3068 | // Convert possible depth parameter to index |
| 3028 | if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) { | 3069 | if (!isNaN(insertAt) && (insertAt < 0 || Object.is(insertAt, -0))) { |
| 3029 | // Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7) | 3070 | // Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7) |
| 3030 | insertAt = chat.length + insertAt; | 3071 | insertAt = chat.length + insertAt; |
| 3031 | } | 3072 | } |
| @@ -3399,7 +3440,7 @@ export async function sendMessageAs(args, text) { | |||
| 3399 | let insertAt = Number(args.at); | 3440 | let insertAt = Number(args.at); |
| 3400 | 3441 | ||
| 3401 | // Convert possible depth parameter to index | 3442 | // Convert possible depth parameter to index |
| 3402 | if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) { | 3443 | if (!isNaN(insertAt) && (insertAt < 0 || Object.is(insertAt, -0))) { |
| 3403 | // Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7) | 3444 | // Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7) |
| 3404 | insertAt = chat.length + insertAt; | 3445 | insertAt = chat.length + insertAt; |
| 3405 | } | 3446 | } |
| @@ -3453,7 +3494,7 @@ export async function sendNarratorMessage(args, text) { | |||
| 3453 | let insertAt = Number(args.at); | 3494 | let insertAt = Number(args.at); |
| 3454 | 3495 | ||
| 3455 | // Convert possible depth parameter to index | 3496 | // Convert possible depth parameter to index |
| 3456 | if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) { | 3497 | if (!isNaN(insertAt) && (insertAt < 0 || Object.is(insertAt, -0))) { |
| 3457 | // Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7) | 3498 | // Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7) |
| 3458 | insertAt = chat.length + insertAt; | 3499 | insertAt = chat.length + insertAt; |
| 3459 | } | 3500 | } |
| @@ -3542,7 +3583,7 @@ async function sendCommentMessage(args, text) { | |||
| 3542 | let insertAt = Number(args.at); | 3583 | let insertAt = Number(args.at); |
| 3543 | 3584 | ||
| 3544 | // Convert possible depth parameter to index | 3585 | // Convert possible depth parameter to index |
| 3545 | if (!isNaN(insertAt) && (insertAt < 0 || insertAt === Number(-0))) { | 3586 | if (!isNaN(insertAt) && (insertAt < 0 || Object.is(insertAt, -0))) { |
| 3546 | // Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7) | 3587 | // Negative value means going back from current chat length. (E.g.: 8 messages, Depth 1 means insert at index 7) |
| 3547 | insertAt = chat.length + insertAt; | 3588 | insertAt = chat.length + insertAt; |
| 3548 | } | 3589 | } |
| @@ -3787,6 +3828,75 @@ function modelCallback(args, model) { | |||
| 3787 | } | 3828 | } |
| 3788 | 3829 | ||
| 3789 | /** | 3830 | /** |
| 3831 | * Gets the state of prompt entries (toggles) either via identifier/uuid or name. | ||
| 3832 | * @param {object} args Object containing arguments | ||
| 3833 | * @param {string} args.identifier Select prompt entry using an identifier (uuid) | ||
| 3834 | * @param {string} args.name Select prompt entry using name | ||
| 3835 | * @param {string} args.return The type of return value to use (simple, list, dict) | ||
| 3836 | * @returns {Object} An object containing the states of the requested prompt entries | ||
| 3837 | */ | ||
| 3838 | function getPromptEntryCallback(args) { | ||
| 3839 | const prompts = promptManager.serviceSettings.prompts; | ||
| 3840 | let returnType = args.return ?? 'simple'; | ||
| 3841 | |||
| 3842 | function parseArgs(arg) { | ||
| 3843 | // Arg is already an array | ||
| 3844 | if (Array.isArray(arg)) { | ||
| 3845 | return arg; | ||
| 3846 | } | ||
| 3847 | const list = []; | ||
| 3848 | try { | ||
| 3849 | // Arg is a JSON-stringified array | ||
| 3850 | const parsedArg = JSON.parse(arg); | ||
| 3851 | list.push(...Array.isArray(parsedArg) ? parsedArg : [arg]); | ||
| 3852 | } catch { | ||
| 3853 | // Arg is a string | ||
| 3854 | list.push(arg); | ||
| 3855 | } | ||
| 3856 | return list; | ||
| 3857 | } | ||
| 3858 | |||
| 3859 | let identifiersList = parseArgs(args.identifier); | ||
| 3860 | let nameList = parseArgs(args.name); | ||
| 3861 | |||
| 3862 | // Check if identifiers exists in prompt, else remove from list | ||
| 3863 | if (identifiersList.length !== 0) { | ||
| 3864 | identifiersList = identifiersList.filter(identifier => prompts.some(prompt => prompt.identifier === identifier)); | ||
| 3865 | } | ||
| 3866 | |||
| 3867 | if (nameList.length !== 0) { | ||
| 3868 | nameList.forEach(name => { | ||
| 3869 | let identifiers = prompts | ||
| 3870 | .filter(entry => entry.name === name) | ||
| 3871 | .map(entry => entry.identifier); | ||
| 3872 | identifiersList = identifiersList.concat(identifiers); | ||
| 3873 | }); | ||
| 3874 | } | ||
| 3875 | |||
| 3876 | // Get the state for each prompt entry | ||
| 3877 | let promptStates = new Map(); | ||
| 3878 | identifiersList.forEach(identifier => { | ||
| 3879 | const promptOrderEntry = promptManager.getPromptOrderEntry(promptManager.activeCharacter, identifier); | ||
| 3880 | if (promptOrderEntry) { | ||
| 3881 | promptStates.set(identifier, promptOrderEntry.enabled); | ||
| 3882 | } | ||
| 3883 | }); | ||
| 3884 | |||
| 3885 | // If return is simple (default) but more than one prompt state was retrieved, then change return type | ||
| 3886 | if (returnType === 'simple' && promptStates.size > 1) { | ||
| 3887 | returnType = args.identifier ? 'dict' : 'list'; | ||
| 3888 | } | ||
| 3889 | |||
| 3890 | const result = (() => { | ||
| 3891 | if (returnType === 'list') return [...promptStates.values()]; | ||
| 3892 | if (returnType === 'dict') return Object.fromEntries(promptStates); | ||
| 3893 | return [...promptStates.values()][0]; | ||
| 3894 | })(); | ||
| 3895 | |||
| 3896 | return result; | ||
| 3897 | } | ||
| 3898 | |||
| 3899 | /** | ||
| 3790 | * Sets state of prompt entries (toggles) either via identifier/uuid or name. | 3900 | * Sets state of prompt entries (toggles) either via identifier/uuid or name. |
| 3791 | * @param {object} args Object containing arguments | 3901 | * @param {object} args Object containing arguments |
| 3792 | * @param {string} args.identifier Select prompt entry using an identifier (uuid) | 3902 | * @param {string} args.identifier Select prompt entry using an identifier (uuid) |
| @@ -3796,7 +3906,6 @@ function modelCallback(args, model) { | |||
| 3796 | */ | 3906 | */ |
| 3797 | function setPromptEntryCallback(args, targetState) { | 3907 | function setPromptEntryCallback(args, targetState) { |
| 3798 | // needs promptManager to manipulate prompt entries | 3908 | // needs promptManager to manipulate prompt entries |
| 3799 | const promptManager = setupChatCompletionPromptManager(oai_settings); | ||
| 3800 | const prompts = promptManager.serviceSettings.prompts; | 3909 | const prompts = promptManager.serviceSettings.prompts; |
| 3801 | 3910 | ||
| 3802 | function parseArgs(arg) { | 3911 | function parseArgs(arg) { |
| @@ -0,0 +1,171 @@ | |||
| 1 | import { | ||
| 2 | activateSendButtons, | ||
| 3 | addOneMessage, | ||
| 4 | callPopup, | ||
| 5 | characters, | ||
| 6 | chat, | ||
| 7 | chat_metadata, | ||
| 8 | create_save, | ||
| 9 | deactivateSendButtons, | ||
| 10 | event_types, | ||
| 11 | eventSource, | ||
| 12 | extension_prompts, | ||
| 13 | Generate, | ||
| 14 | generateQuietPrompt, | ||
| 15 | getCurrentChatId, | ||
| 16 | getRequestHeaders, | ||
| 17 | getThumbnailUrl, | ||
| 18 | main_api, | ||
| 19 | max_context, | ||
| 20 | menu_type, | ||
| 21 | messageFormatting, | ||
| 22 | name1, | ||
| 23 | name2, | ||
| 24 | online_status, | ||
| 25 | openCharacterChat, | ||
| 26 | reloadCurrentChat, | ||
| 27 | renameChat, | ||
| 28 | saveChatConditional, | ||
| 29 | saveMetadata, | ||
| 30 | saveReply, | ||
| 31 | saveSettingsDebounced, | ||
| 32 | selectCharacterById, | ||
| 33 | sendGenerationRequest, | ||
| 34 | sendStreamingRequest, | ||
| 35 | sendSystemMessage, | ||
| 36 | setExtensionPrompt, | ||
| 37 | stopGeneration, | ||
| 38 | streamingProcessor, | ||
| 39 | substituteParams, | ||
| 40 | substituteParamsExtended, | ||
| 41 | this_chid, | ||
| 42 | updateChatMetadata, | ||
| 43 | } from '../script.js'; | ||
| 44 | import { | ||
| 45 | extension_settings, | ||
| 46 | ModuleWorkerWrapper, | ||
| 47 | renderExtensionTemplate, | ||
| 48 | renderExtensionTemplateAsync, | ||
| 49 | writeExtensionField, | ||
| 50 | } from './extensions.js'; | ||
| 51 | import { groups, openGroupChat, selected_group } from './group-chats.js'; | ||
| 52 | import { t, translate } from './i18n.js'; | ||
| 53 | import { hideLoader, showLoader } from './loader.js'; | ||
| 54 | import { MacrosParser } from './macros.js'; | ||
| 55 | import { oai_settings } from './openai.js'; | ||
| 56 | import { callGenericPopup, Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js'; | ||
| 57 | import { power_user, registerDebugFunction } from './power-user.js'; | ||
| 58 | import { isMobile, shouldSendOnEnter } from './RossAscends-mods.js'; | ||
| 59 | import { ScraperManager } from './scrapers.js'; | ||
| 60 | import { executeSlashCommands, executeSlashCommandsWithOptions, registerSlashCommand } from './slash-commands.js'; | ||
| 61 | import { SlashCommand } from './slash-commands/SlashCommand.js'; | ||
| 62 | import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from './slash-commands/SlashCommandArgument.js'; | ||
| 63 | import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | ||
| 64 | import { tag_map, tags } from './tags.js'; | ||
| 65 | import { textgenerationwebui_settings } from './textgen-settings.js'; | ||
| 66 | import { getTokenCount, getTokenCountAsync, getTokenizerModel } from './tokenizers.js'; | ||
| 67 | import { ToolManager } from './tool-calling.js'; | ||
| 68 | import { timestampToMoment } from './utils.js'; | ||
| 69 | |||
| 70 | export function getContext() { | ||
| 71 | return { | ||
| 72 | chat, | ||
| 73 | characters, | ||
| 74 | groups, | ||
| 75 | name1, | ||
| 76 | name2, | ||
| 77 | characterId: this_chid, | ||
| 78 | groupId: selected_group, | ||
| 79 | chatId: selected_group | ||
| 80 | ? groups.find(x => x.id == selected_group)?.chat_id | ||
| 81 | : (characters[this_chid]?.chat), | ||
| 82 | getCurrentChatId, | ||
| 83 | getRequestHeaders, | ||
| 84 | reloadCurrentChat, | ||
| 85 | renameChat, | ||
| 86 | saveSettingsDebounced, | ||
| 87 | onlineStatus: online_status, | ||
| 88 | maxContext: Number(max_context), | ||
| 89 | chatMetadata: chat_metadata, | ||
| 90 | streamingProcessor, | ||
| 91 | eventSource, | ||
| 92 | eventTypes: event_types, | ||
| 93 | addOneMessage, | ||
| 94 | generate: Generate, | ||
| 95 | sendStreamingRequest, | ||
| 96 | sendGenerationRequest, | ||
| 97 | stopGeneration, | ||
| 98 | /** @deprecated Use getTokenCountAsync instead */ | ||
| 99 | getTokenCount, | ||
| 100 | getTokenCountAsync, | ||
| 101 | extensionPrompts: extension_prompts, | ||
| 102 | setExtensionPrompt, | ||
| 103 | updateChatMetadata, | ||
| 104 | saveChat: saveChatConditional, | ||
| 105 | openCharacterChat, | ||
| 106 | openGroupChat, | ||
| 107 | saveMetadata, | ||
| 108 | sendSystemMessage, | ||
| 109 | activateSendButtons, | ||
| 110 | deactivateSendButtons, | ||
| 111 | saveReply, | ||
| 112 | substituteParams, | ||
| 113 | substituteParamsExtended, | ||
| 114 | SlashCommandParser, | ||
| 115 | SlashCommand, | ||
| 116 | SlashCommandArgument, | ||
| 117 | SlashCommandNamedArgument, | ||
| 118 | ARGUMENT_TYPE, | ||
| 119 | executeSlashCommandsWithOptions, | ||
| 120 | /** @deprecated Use SlashCommandParser.addCommandObject() instead */ | ||
| 121 | registerSlashCommand, | ||
| 122 | /** @deprecated Use executeSlashCommandWithOptions instead */ | ||
| 123 | executeSlashCommands, | ||
| 124 | timestampToMoment, | ||
| 125 | /** @deprecated Handlebars for extensions are no longer supported. */ | ||
| 126 | registerHelper: () => { }, | ||
| 127 | registerMacro: MacrosParser.registerMacro.bind(MacrosParser), | ||
| 128 | unregisterMacro: MacrosParser.unregisterMacro.bind(MacrosParser), | ||
| 129 | registerFunctionTool: ToolManager.registerFunctionTool.bind(ToolManager), | ||
| 130 | unregisterFunctionTool: ToolManager.unregisterFunctionTool.bind(ToolManager), | ||
| 131 | isToolCallingSupported: ToolManager.isToolCallingSupported.bind(ToolManager), | ||
| 132 | canPerformToolCalls: ToolManager.canPerformToolCalls.bind(ToolManager), | ||
| 133 | registerDebugFunction, | ||
| 134 | /** @deprecated Use renderExtensionTemplateAsync instead. */ | ||
| 135 | renderExtensionTemplate, | ||
| 136 | renderExtensionTemplateAsync, | ||
| 137 | registerDataBankScraper: ScraperManager.registerDataBankScraper.bind(ScraperManager), | ||
| 138 | /** @deprecated Use callGenericPopup or Popup instead. */ | ||
| 139 | callPopup, | ||
| 140 | callGenericPopup, | ||
| 141 | showLoader, | ||
| 142 | hideLoader, | ||
| 143 | mainApi: main_api, | ||
| 144 | extensionSettings: extension_settings, | ||
| 145 | ModuleWorkerWrapper, | ||
| 146 | getTokenizerModel, | ||
| 147 | generateQuietPrompt, | ||
| 148 | writeExtensionField, | ||
| 149 | getThumbnailUrl, | ||
| 150 | selectCharacterById, | ||
| 151 | messageFormatting, | ||
| 152 | shouldSendOnEnter, | ||
| 153 | isMobile, | ||
| 154 | t, | ||
| 155 | translate, | ||
| 156 | tags, | ||
| 157 | tagMap: tag_map, | ||
| 158 | menuType: menu_type, | ||
| 159 | createCharacterData: create_save, | ||
| 160 | /** @deprecated Legacy snake-case naming, compatibility with old extensions */ | ||
| 161 | event_types: event_types, | ||
| 162 | Popup, | ||
| 163 | POPUP_TYPE, | ||
| 164 | POPUP_RESULT, | ||
| 165 | chatCompletionSettings: oai_settings, | ||
| 166 | textCompletionSettings: textgenerationwebui_settings, | ||
| 167 | powerUserSettings: power_user, | ||
| 168 | }; | ||
| 169 | } | ||
| 170 | |||
| 171 | export default getContext; | ||
| @@ -4,8 +4,17 @@ | |||
| 4 | <div id="copyPromptToClipboard" class="fa-solid fa-copy menu_button" title="Copy Prompt" data-i18n="[title]Copy Prompt"></div> | 4 | <div id="copyPromptToClipboard" class="fa-solid fa-copy menu_button" title="Copy Prompt" data-i18n="[title]Copy Prompt"></div> |
| 5 | <div id="diffPrevPrompt" class="fa-solid fa-code-compare menu_button" title="Show Prompt Differences" data-i18n="[title]Show Prompt Differences"></div> | 5 | <div id="diffPrevPrompt" class="fa-solid fa-code-compare menu_button" title="Show Prompt Differences" data-i18n="[title]Show Prompt Differences"></div> |
| 6 | </h3> | 6 | </h3> |
| 7 | API/Model Used: {{mainApiFriendlyName}} {{#if apiUsed}}({{apiUsed}}){{/if}} {{#if modelUsed}}– {{modelUsed}}{{/if}}<br> | 7 | <div> |
| 8 | Tokenizer: {{selectedTokenizer}}<br> | 8 | <div> |
| 9 | API/Model: {{mainApiFriendlyName}} {{#if apiUsed}}({{apiUsed}}){{/if}} {{#if modelUsed}}– {{modelUsed}}{{/if}} | ||
| 10 | </div> | ||
| 11 | <div> | ||
| 12 | <small>Preset: {{presetName}}</small> | ||
| 13 | <span>|</span> | ||
| 14 | <small>Tokenizer: {{selectedTokenizer}}</small> | ||
| 15 | </div> | ||
| 16 | </div> | ||
| 17 | |||
| 9 | <span class="tokenItemizingSubclass"> | 18 | <span class="tokenItemizingSubclass"> |
| 10 | Only the white numbers really matter. All numbers are estimates. | 19 | Only the white numbers really matter. All numbers are estimates. |
| 11 | Grey color items may not have been included in the context due to certain prompt format settings. | 20 | Grey color items may not have been included in the context due to certain prompt format settings. |
| @@ -4,8 +4,17 @@ | |||
| 4 | <div id="copyPromptToClipboard" class="fa-solid fa-copy menu_button" title="Copy Prompt" data-i18n="[title]Copy Prompt"></div> | 4 | <div id="copyPromptToClipboard" class="fa-solid fa-copy menu_button" title="Copy Prompt" data-i18n="[title]Copy Prompt"></div> |
| 5 | <div id="diffPrevPrompt" class="fa-solid fa-code-compare menu_button" title="Show Prompt Differences" data-i18n="[title]Show Prompt Differences"></div> | 5 | <div id="diffPrevPrompt" class="fa-solid fa-code-compare menu_button" title="Show Prompt Differences" data-i18n="[title]Show Prompt Differences"></div> |
| 6 | </h3> | 6 | </h3> |
| 7 | API/Model Used: {{mainApiFriendlyName}} {{#if apiUsed}}({{apiUsed}}){{/if}} {{#if modelUsed}}– {{modelUsed}}{{/if}}<br> | 7 | <div> |
| 8 | Tokenizer: {{selectedTokenizer}}<br> | 8 | <div> |
| 9 | API/Model: {{mainApiFriendlyName}} {{#if apiUsed}}({{apiUsed}}){{/if}} {{#if modelUsed}}– {{modelUsed}}{{/if}} | ||
| 10 | </div> | ||
| 11 | <div> | ||
| 12 | <small>Preset: {{presetName}}</small> | ||
| 13 | <span>|</span> | ||
| 14 | <small>Tokenizer: {{selectedTokenizer}}</small> | ||
| 15 | </div> | ||
| 16 | </div> | ||
| 17 | |||
| 9 | <span class="tokenItemizingSubclass"> | 18 | <span class="tokenItemizingSubclass"> |
| 10 | Only the white numbers really matter. All numbers are estimates. | 19 | Only the white numbers really matter. All numbers are estimates. |
| 11 | Grey color items may not have been included in the context due to certain prompt format settings. | 20 | Grey color items may not have been included in the context due to certain prompt format settings. |
| @@ -21,7 +21,8 @@ | |||
| 21 | <li><tt>{{user}}</tt> – <span data-i18n="help_macros_15">your current Persona username</span></li> | 21 | <li><tt>{{user}}</tt> – <span data-i18n="help_macros_15">your current Persona username</span></li> |
| 22 | <li><tt>{{char}}</tt> – <span data-i18n="help_macros_16">the Character's name</span></li> | 22 | <li><tt>{{char}}</tt> – <span data-i18n="help_macros_16">the Character's name</span></li> |
| 23 | <li><tt>{{char_version}}</tt> – <span data-i18n="help_macros_17">the Character's version number</span></li> | 23 | <li><tt>{{char_version}}</tt> – <span data-i18n="help_macros_17">the Character's version number</span></li> |
| 24 | <li><tt>{{group}}</tt> – <span data-i18n="help_macros_18">a comma-separated list of group member names or the character name in solo chats. Alias: {{charIfNotGroup}}</span></li> | 24 | <li><tt>{{group}}</tt> – <span data-i18n="help_macros_18">a comma-separated list of group member names (including muted) or the character name in solo chats. Alias: {{charIfNotGroup}}</span></li> |
| 25 | <li><tt>{{groupNotMuted}}</tt> – <span data-i18n="help_groupNotMuted">the same as {{group}}, but excludes muted members</span></li> | ||
| 25 | <li><tt>{{model}}</tt> – <span data-i18n="help_macros_19">a text generation model name for the currently selected API. </span><b data-i18n="Can be inaccurate!">Can be inaccurate!</b></li> | 26 | <li><tt>{{model}}</tt> – <span data-i18n="help_macros_19">a text generation model name for the currently selected API. </span><b data-i18n="Can be inaccurate!">Can be inaccurate!</b></li> |
| 26 | <li><tt>{{lastMessage}}</tt> – <span data-i18n="help_macros_20">the text of the latest chat message.</span></li> | 27 | <li><tt>{{lastMessage}}</tt> – <span data-i18n="help_macros_20">the text of the latest chat message.</span></li> |
| 27 | <li><tt>{{lastUserMessage}}</tt> – <span data-i18n="help_macros_lastUser">the text of the latest user chat message.</span></li> | 28 | <li><tt>{{lastUserMessage}}</tt> – <span data-i18n="help_macros_lastUser">the text of the latest user chat message.</span></li> |
| @@ -18,13 +18,6 @@ import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer } | |||
| 18 | import { ENCODE_TOKENIZERS, TEXTGEN_TOKENIZERS, getTextTokens, tokenizers } from './tokenizers.js'; | 18 | import { ENCODE_TOKENIZERS, TEXTGEN_TOKENIZERS, getTextTokens, tokenizers } from './tokenizers.js'; |
| 19 | import { getSortableDelay, onlyUnique } from './utils.js'; | 19 | import { getSortableDelay, onlyUnique } from './utils.js'; |
| 20 | 20 | ||
| 21 | export { | ||
| 22 | settings as textgenerationwebui_settings, | ||
| 23 | loadTextGenSettings, | ||
| 24 | generateTextGenWithStreaming, | ||
| 25 | formatTextGenURL, | ||
| 26 | }; | ||
| 27 | |||
| 28 | export const textgen_types = { | 21 | export const textgen_types = { |
| 29 | OOBA: 'ooba', | 22 | OOBA: 'ooba', |
| 30 | MANCER: 'mancer', | 23 | MANCER: 'mancer', |
| @@ -197,6 +190,10 @@ const settings = { | |||
| 197 | featherless_model: '', | 190 | featherless_model: '', |
| 198 | }; | 191 | }; |
| 199 | 192 | ||
| 193 | export { | ||
| 194 | settings as textgenerationwebui_settings, | ||
| 195 | }; | ||
| 196 | |||
| 200 | export let textgenerationwebui_banned_in_macros = []; | 197 | export let textgenerationwebui_banned_in_macros = []; |
| 201 | 198 | ||
| 202 | export let textgenerationwebui_presets = []; | 199 | export let textgenerationwebui_presets = []; |
| @@ -327,7 +324,7 @@ async function selectPreset(name) { | |||
| 327 | saveSettingsDebounced(); | 324 | saveSettingsDebounced(); |
| 328 | } | 325 | } |
| 329 | 326 | ||
| 330 | function formatTextGenURL(value) { | 327 | export function formatTextGenURL(value) { |
| 331 | try { | 328 | try { |
| 332 | const noFormatTypes = [MANCER, TOGETHERAI, INFERMATICAI, DREAMGEN, OPENROUTER]; | 329 | const noFormatTypes = [MANCER, TOGETHERAI, INFERMATICAI, DREAMGEN, OPENROUTER]; |
| 333 | if (noFormatTypes.includes(settings.type)) { | 330 | if (noFormatTypes.includes(settings.type)) { |
| @@ -465,7 +462,7 @@ function calculateLogitBias() { | |||
| 465 | return result; | 462 | return result; |
| 466 | } | 463 | } |
| 467 | 464 | ||
| 468 | function loadTextGenSettings(data, loadedSettings) { | 465 | export function loadTextGenSettings(data, loadedSettings) { |
| 469 | textgenerationwebui_presets = convertPresets(data.textgenerationwebui_presets); | 466 | textgenerationwebui_presets = convertPresets(data.textgenerationwebui_presets); |
| 470 | textgenerationwebui_preset_names = data.textgenerationwebui_preset_names ?? []; | 467 | textgenerationwebui_preset_names = data.textgenerationwebui_preset_names ?? []; |
| 471 | Object.assign(settings, loadedSettings.textgenerationwebui_settings ?? {}); | 468 | Object.assign(settings, loadedSettings.textgenerationwebui_settings ?? {}); |
| @@ -889,7 +886,7 @@ function setSettingByName(setting, value, trigger) { | |||
| 889 | * @returns {Promise<(function(): AsyncGenerator<{swipes: [], text: string, toolCalls: [], logprobs: {token: string, topLogprobs: Candidate[]}|null}, void, *>)|*>} | 886 | * @returns {Promise<(function(): AsyncGenerator<{swipes: [], text: string, toolCalls: [], logprobs: {token: string, topLogprobs: Candidate[]}|null}, void, *>)|*>} |
| 890 | * @throws {Error} - If the response status is not OK, or from within the generator | 887 | * @throws {Error} - If the response status is not OK, or from within the generator |
| 891 | */ | 888 | */ |
| 892 | async function generateTextGenWithStreaming(generate_data, signal) { | 889 | export async function generateTextGenWithStreaming(generate_data, signal) { |
| 893 | generate_data.stream = true; | 890 | generate_data.stream = true; |
| 894 | 891 | ||
| 895 | const response = await fetch('/api/backends/text-completions/generate', { | 892 | const response = await fetch('/api/backends/text-completions/generate', { |
| @@ -1340,6 +1337,9 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, | |||
| 1340 | 'dry_sequence_breakers': sequenceBreakers, | 1337 | 'dry_sequence_breakers': sequenceBreakers, |
| 1341 | }; | 1338 | }; |
| 1342 | params = Object.assign(params, llamaCppParams); | 1339 | params = Object.assign(params, llamaCppParams); |
| 1340 | if (!Array.isArray(sequenceBreakers) || sequenceBreakers.length === 0) { | ||
| 1341 | delete params.dry_sequence_breakers; | ||
| 1342 | } | ||
| 1343 | } | 1343 | } |
| 1344 | 1344 | ||
| 1345 | eventSource.emitAndWait(event_types.TEXT_COMPLETION_SETTINGS_READY, params); | 1345 | eventSource.emitAndWait(event_types.TEXT_COMPLETION_SETTINGS_READY, params); |
| @@ -8,8 +8,6 @@ import { kai_flags } from './kai-settings.js'; | |||
| 8 | import { textgen_types, textgenerationwebui_settings as textgen_settings, getTextGenServer, getTextGenModel } from './textgen-settings.js'; | 8 | import { textgen_types, textgenerationwebui_settings as textgen_settings, getTextGenServer, getTextGenModel } from './textgen-settings.js'; |
| 9 | import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, openRouterModels } from './textgen-models.js'; | 9 | import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer, openRouterModels } from './textgen-models.js'; |
| 10 | 10 | ||
| 11 | const { OOBA, TABBY, KOBOLDCPP, VLLM, APHRODITE, LLAMACPP, OPENROUTER, DREAMGEN } = textgen_types; | ||
| 12 | |||
| 13 | export const CHARACTERS_PER_TOKEN_RATIO = 3.35; | 11 | export const CHARACTERS_PER_TOKEN_RATIO = 3.35; |
| 14 | export const TOKENIZER_WARNING_KEY = 'tokenizationWarningShown'; | 12 | export const TOKENIZER_WARNING_KEY = 'tokenizationWarningShown'; |
| 15 | export const TOKENIZER_SUPPORTED_KEY = 'tokenizationSupported'; | 13 | export const TOKENIZER_SUPPORTED_KEY = 'tokenizationSupported'; |
| @@ -52,8 +50,12 @@ export const ENCODE_TOKENIZERS = [ | |||
| 52 | //tokenizers.NERD2, | 50 | //tokenizers.NERD2, |
| 53 | ]; | 51 | ]; |
| 54 | 52 | ||
| 55 | // A list of Text Completion sources that support remote tokenization. | 53 | /** |
| 56 | export const TEXTGEN_TOKENIZERS = [OOBA, TABBY, KOBOLDCPP, LLAMACPP, VLLM, APHRODITE]; | 54 | * A list of Text Completion sources that support remote tokenization. |
| 55 | * Populated in initTokenziers due to circular dependencies. | ||
| 56 | * @type {string[]} | ||
| 57 | */ | ||
| 58 | export const TEXTGEN_TOKENIZERS = []; | ||
| 57 | 59 | ||
| 58 | const TOKENIZER_URLS = { | 60 | const TOKENIZER_URLS = { |
| 59 | [tokenizers.GPT2]: { | 61 | [tokenizers.GPT2]: { |
| @@ -287,7 +289,7 @@ export function getTokenizerBestMatch(forApi) { | |||
| 287 | const hasTokenizerError = sessionStorage.getItem(TOKENIZER_WARNING_KEY); | 289 | const hasTokenizerError = sessionStorage.getItem(TOKENIZER_WARNING_KEY); |
| 288 | const hasValidEndpoint = sessionStorage.getItem(TOKENIZER_SUPPORTED_KEY); | 290 | const hasValidEndpoint = sessionStorage.getItem(TOKENIZER_SUPPORTED_KEY); |
| 289 | const isConnected = online_status !== 'no_connection'; | 291 | const isConnected = online_status !== 'no_connection'; |
| 290 | const isTokenizerSupported = TEXTGEN_TOKENIZERS.includes(textgen_settings.type) && (textgen_settings.type !== OOBA || hasValidEndpoint); | 292 | const isTokenizerSupported = TEXTGEN_TOKENIZERS.includes(textgen_settings.type) && (textgen_settings.type !== textgen_types.OOBA || hasValidEndpoint); |
| 291 | 293 | ||
| 292 | if (!hasTokenizerError && isConnected) { | 294 | if (!hasTokenizerError && isConnected) { |
| 293 | if (forApi === 'kobold' && kai_flags.can_use_tokenization) { | 295 | if (forApi === 'kobold' && kai_flags.can_use_tokenization) { |
| @@ -297,10 +299,10 @@ export function getTokenizerBestMatch(forApi) { | |||
| 297 | if (forApi === 'textgenerationwebui' && isTokenizerSupported) { | 299 | if (forApi === 'textgenerationwebui' && isTokenizerSupported) { |
| 298 | return tokenizers.API_TEXTGENERATIONWEBUI; | 300 | return tokenizers.API_TEXTGENERATIONWEBUI; |
| 299 | } | 301 | } |
| 300 | if (forApi === 'textgenerationwebui' && textgen_settings.type === OPENROUTER) { | 302 | if (forApi === 'textgenerationwebui' && textgen_settings.type === textgen_types.OPENROUTER) { |
| 301 | return getCurrentOpenRouterModelTokenizer(); | 303 | return getCurrentOpenRouterModelTokenizer(); |
| 302 | } | 304 | } |
| 303 | if (forApi === 'textgenerationwebui' && textgen_settings.type === DREAMGEN) { | 305 | if (forApi === 'textgenerationwebui' && textgen_settings.type === textgen_types.DREAMGEN) { |
| 304 | return getCurrentDreamGenModelTokenizer(); | 306 | return getCurrentDreamGenModelTokenizer(); |
| 305 | } | 307 | } |
| 306 | } | 308 | } |
| @@ -576,7 +578,7 @@ export function getTokenizerModel() { | |||
| 576 | 578 | ||
| 577 | // And for OpenRouter (if not a site model, then it's impossible to determine the tokenizer) | 579 | // And for OpenRouter (if not a site model, then it's impossible to determine the tokenizer) |
| 578 | if (main_api == 'openai' && oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER && oai_settings.openrouter_model || | 580 | if (main_api == 'openai' && oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER && oai_settings.openrouter_model || |
| 579 | main_api == 'textgenerationwebui' && textgen_settings.type === OPENROUTER && textgen_settings.openrouter_model) { | 581 | main_api == 'textgenerationwebui' && textgen_settings.type === textgen_types.OPENROUTER && textgen_settings.openrouter_model) { |
| 580 | const model = main_api == 'openai' | 582 | const model = main_api == 'openai' |
| 581 | ? model_list.find(x => x.id === oai_settings.openrouter_model) | 583 | ? model_list.find(x => x.id === oai_settings.openrouter_model) |
| 582 | : openRouterModels.find(x => x.id === textgen_settings.openrouter_model); | 584 | : openRouterModels.find(x => x.id === textgen_settings.openrouter_model); |
| @@ -652,7 +654,7 @@ export function getTokenizerModel() { | |||
| 652 | return oai_settings.custom_model; | 654 | return oai_settings.custom_model; |
| 653 | } | 655 | } |
| 654 | 656 | ||
| 655 | if (oai_settings.chat_completion_source === chat_completion_sources.PERPLEXITY) { | 657 | if (oai_settings.chat_completion_source === chat_completion_sources.PERPLEXITY) { |
| 656 | if (oai_settings.perplexity_model.includes('llama-3') || oai_settings.perplexity_model.includes('llama3')) { | 658 | if (oai_settings.perplexity_model.includes('llama-3') || oai_settings.perplexity_model.includes('llama3')) { |
| 657 | return llama3Tokenizer; | 659 | return llama3Tokenizer; |
| 658 | } | 660 | } |
| @@ -680,7 +682,7 @@ export function getTokenizerModel() { | |||
| 680 | return yiTokenizer; | 682 | return yiTokenizer; |
| 681 | } | 683 | } |
| 682 | 684 | ||
| 683 | if (oai_settings.chat_completion_source === chat_completion_sources.BLOCKENTROPY) { | 685 | if (oai_settings.chat_completion_source === chat_completion_sources.BLOCKENTROPY) { |
| 684 | if (oai_settings.blockentropy_model.includes('llama3')) { | 686 | if (oai_settings.blockentropy_model.includes('llama3')) { |
| 685 | return llama3Tokenizer; | 687 | return llama3Tokenizer; |
| 686 | } | 688 | } |
| @@ -1121,6 +1123,14 @@ export function decodeTextTokens(tokenizerType, ids) { | |||
| 1121 | } | 1123 | } |
| 1122 | 1124 | ||
| 1123 | export async function initTokenizers() { | 1125 | export async function initTokenizers() { |
| 1126 | TEXTGEN_TOKENIZERS.push( | ||
| 1127 | textgen_types.OOBA, | ||
| 1128 | textgen_types.TABBY, | ||
| 1129 | textgen_types.KOBOLDCPP, | ||
| 1130 | textgen_types.LLAMACPP, | ||
| 1131 | textgen_types.VLLM, | ||
| 1132 | textgen_types.APHRODITE, | ||
| 1133 | ); | ||
| 1124 | await loadTokenCache(); | 1134 | await loadTokenCache(); |
| 1125 | registerDebugFunction('resetTokenCache', 'Reset token cache', 'Purges the calculated token counts. Use this if you want to force a full re-tokenization of all chats or suspect the token counts are wrong.', resetTokenCache); | 1135 | registerDebugFunction('resetTokenCache', 'Reset token cache', 'Purges the calculated token counts. Use this if you want to force a full re-tokenization of all chats or suspect the token counts are wrong.', resetTokenCache); |
| 1126 | } | 1136 | } |
| @@ -947,7 +947,7 @@ export class ToolManager { | |||
| 947 | enumProvider: toolsEnumProvider, | 947 | enumProvider: toolsEnumProvider, |
| 948 | }), | 948 | }), |
| 949 | ], | 949 | ], |
| 950 | callback: async (name) => { | 950 | callback: async (_, name) => { |
| 951 | if (typeof name !== 'string' || !name) { | 951 | if (typeof name !== 'string' || !name) { |
| 952 | throw new Error('The unnamed argument must be a non-empty string.'); | 952 | throw new Error('The unnamed argument must be a non-empty string.'); |
| 953 | } | 953 | } |
| @@ -1040,8 +1040,14 @@ body .panelControlBar { | |||
| 1040 | height: var(--swipeCounterHeight); | 1040 | height: var(--swipeCounterHeight); |
| 1041 | } | 1041 | } |
| 1042 | 1042 | ||
| 1043 | .mes:not(.last_mes) .swipes-counter { | 1043 | body:not(.swipeAllMessages) .mes:not(.last_mes) .swipes-counter { |
| 1044 | opacity: 0.3; | 1044 | visibility: hidden; |
| 1045 | } | ||
| 1046 | |||
| 1047 | body.swipeAllMessages .mes:not(.last_mes) .swipes-counter { | ||
| 1048 | /* Avoid expensive DOM queries */ | ||
| 1049 | opacity: 0.3 !important; | ||
| 1050 | display: flex !important; | ||
| 1045 | } | 1051 | } |
| 1046 | 1052 | ||
| 1047 | .swipe_left { | 1053 | .swipe_left { |
| @@ -280,7 +280,7 @@ async function sendMakerSuiteRequest(request, response) { | |||
| 280 | delete generationConfig.stopSequences; | 280 | delete generationConfig.stopSequences; |
| 281 | } | 281 | } |
| 282 | 282 | ||
| 283 | const should_use_system_prompt = (model.includes('gemini-1.5-flash') || model.includes('gemini-1.5-pro') || model.includes('gemini-exp-1114') || model.includes('gemini-exp-1121')) && request.body.use_makersuite_sysprompt; | 283 | const should_use_system_prompt = (model.includes('gemini-1.5-flash') || model.includes('gemini-1.5-pro') || model.startsWith('gemini-exp')) && request.body.use_makersuite_sysprompt; |
| 284 | const prompt = convertGooglePrompt(request.body.messages, model, should_use_system_prompt, request.body.char_name, request.body.user_name); | 284 | const prompt = convertGooglePrompt(request.body.messages, model, should_use_system_prompt, request.body.char_name, request.body.user_name); |
| 285 | let body = { | 285 | let body = { |
| 286 | contents: prompt.contents, | 286 | contents: prompt.contents, |
| @@ -14,7 +14,7 @@ import jimp from 'jimp'; | |||
| 14 | 14 | ||
| 15 | import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js'; | 15 | import { AVATAR_WIDTH, AVATAR_HEIGHT } from '../constants.js'; |
| 16 | import { jsonParser, urlencodedParser } from '../express-common.js'; | 16 | import { jsonParser, urlencodedParser } from '../express-common.js'; |
| 17 | import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap } from '../util.js'; | 17 | import { deepMerge, humanizedISO8601DateTime, tryParse, extractFileFromZipBuffer, MemoryLimitedMap, getConfigValue } from '../util.js'; |
| 18 | import { TavernCardValidator } from '../validator/TavernCardValidator.js'; | 18 | import { TavernCardValidator } from '../validator/TavernCardValidator.js'; |
| 19 | import { parse, write } from '../character-card-parser.js'; | 19 | import { parse, write } from '../character-card-parser.js'; |
| 20 | import { readWorldInfoFile } from './worldinfo.js'; | 20 | import { readWorldInfoFile } from './worldinfo.js'; |
| @@ -23,8 +23,9 @@ import { importRisuSprites } from './sprites.js'; | |||
| 23 | const defaultAvatarPath = './public/img/ai4.png'; | 23 | const defaultAvatarPath = './public/img/ai4.png'; |
| 24 | 24 | ||
| 25 | // KV-store for parsed character data | 25 | // KV-store for parsed character data |
| 26 | // 100 MB limit. Would take roughly 3000 characters to reach this limit | 26 | const cacheCapacity = Number(getConfigValue('cardsCacheCapacity', 100)); // MB |
| 27 | const characterDataCache = new MemoryLimitedMap(1024 * 1024 * 100); | 27 | // With 100 MB limit it would take roughly 3000 characters to reach this limit |
| 28 | const characterDataCache = new MemoryLimitedMap(1024 * 1024 * cacheCapacity); | ||
| 28 | // Some Android devices require tighter memory management | 29 | // Some Android devices require tighter memory management |
| 29 | const isAndroid = process.platform === 'android'; | 30 | const isAndroid = process.platform === 'android'; |
| 30 | 31 | ||
| @@ -191,6 +191,44 @@ function importCAIChat(userName, characterName, jsonData) { | |||
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | /** | 193 | /** |
| 194 | * Imports a chat from Kobold Lite format. | ||
| 195 | * @param {string} _userName User name | ||
| 196 | * @param {string} _characterName Character name | ||
| 197 | * @param {object} data JSON data | ||
| 198 | * @returns {string} Chat data | ||
| 199 | */ | ||
| 200 | function importKoboldLiteChat(_userName, _characterName, data) { | ||
| 201 | const inputToken = '{{[INPUT]}}'; | ||
| 202 | const outputToken = '{{[OUTPUT]}}'; | ||
| 203 | |||
| 204 | /** @type {function(string): object} */ | ||
| 205 | function processKoboldMessage(msg) { | ||
| 206 | const isUser = msg.includes(inputToken); | ||
| 207 | return { | ||
| 208 | name: isUser ? header.user_name : header.character_name, | ||
| 209 | is_user: isUser, | ||
| 210 | mes: msg.replaceAll(inputToken, '').replaceAll(outputToken, '').trim(), | ||
| 211 | send_date: Date.now(), | ||
| 212 | }; | ||
| 213 | } | ||
| 214 | |||
| 215 | // Create the header | ||
| 216 | const header = { | ||
| 217 | user_name: String(data.savedsettings.chatname), | ||
| 218 | character_name: String(data.savedsettings.chatopponent).split('||$||')[0], | ||
| 219 | }; | ||
| 220 | // Format messages | ||
| 221 | const formattedMessages = data.actions.map(processKoboldMessage); | ||
| 222 | // Add prompt if available | ||
| 223 | if (data.prompt) { | ||
| 224 | formattedMessages.unshift(processKoboldMessage(data.prompt)); | ||
| 225 | } | ||
| 226 | // Combine header and messages | ||
| 227 | const chatData = [header, ...formattedMessages]; | ||
| 228 | return chatData.map(obj => JSON.stringify(obj)).join('\n'); | ||
| 229 | } | ||
| 230 | |||
| 231 | /** | ||
| 194 | * Flattens `msg` and `swipes` data from Chub Chat format. | 232 | * Flattens `msg` and `swipes` data from Chub Chat format. |
| 195 | * Only changes enough to make it compatible with the standard chat serialization format. | 233 | * Only changes enough to make it compatible with the standard chat serialization format. |
| 196 | * @param {string} userName User name | 234 | * @param {string} userName User name |
| @@ -413,7 +451,7 @@ router.post('/import', urlencodedParser, function (request, response) { | |||
| 413 | const format = request.body.file_type; | 451 | const format = request.body.file_type; |
| 414 | const avatarUrl = (request.body.avatar_url).replace('.png', ''); | 452 | const avatarUrl = (request.body.avatar_url).replace('.png', ''); |
| 415 | const characterName = request.body.character_name; | 453 | const characterName = request.body.character_name; |
| 416 | const userName = request.body.user_name || 'You'; | 454 | const userName = request.body.user_name || 'User'; |
| 417 | 455 | ||
| 418 | if (!request.file) { | 456 | if (!request.file) { |
| 419 | return response.sendStatus(400); | 457 | return response.sendStatus(400); |
| @@ -426,33 +464,38 @@ router.post('/import', urlencodedParser, function (request, response) { | |||
| 426 | if (format === 'json') { | 464 | if (format === 'json') { |
| 427 | fs.unlinkSync(pathToUpload); | 465 | fs.unlinkSync(pathToUpload); |
| 428 | const jsonData = JSON.parse(data); | 466 | const jsonData = JSON.parse(data); |
| 429 | if (jsonData.histories !== undefined) { | 467 | |
| 430 | // CAI Tools format | 468 | /** @type {function(string, string, object): string|string[]} */ |
| 431 | const chats = importCAIChat(userName, characterName, jsonData); | 469 | let importFunc; |
| 432 | for (const chat of chats) { | 470 | |
| 433 | const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`; | 471 | if (jsonData.savedsettings !== undefined) { // Kobold Lite format |
| 434 | const filePath = path.join(request.user.directories.chats, avatarUrl, fileName); | 472 | importFunc = importKoboldLiteChat; |
| 435 | writeFileAtomicSync(filePath, chat, 'utf8'); | 473 | } else if (jsonData.histories !== undefined) { // CAI Tools format |
| 436 | } | 474 | importFunc = importCAIChat; |
| 437 | return response.send({ res: true }); | 475 | } else if (Array.isArray(jsonData.data_visible)) { // oobabooga's format |
| 438 | } else if (Array.isArray(jsonData.data_visible)) { | 476 | importFunc = importOobaChat; |
| 439 | // oobabooga's format | 477 | } else if (Array.isArray(jsonData.messages)) { // Agnai's format |
| 440 | const chat = importOobaChat(userName, characterName, jsonData); | 478 | importFunc = importAgnaiChat; |
| 441 | const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`; | 479 | } else { // Unknown format |
| 442 | const filePath = path.join(request.user.directories.chats, avatarUrl, fileName); | 480 | console.log('Incorrect chat format .json'); |
| 443 | writeFileAtomicSync(filePath, chat, 'utf8'); | 481 | return response.send({ error: true }); |
| 444 | return response.send({ res: true }); | 482 | } |
| 445 | } else if (Array.isArray(jsonData.messages)) { | 483 | |
| 446 | // Agnai format | 484 | const handleChat = (chat) => { |
| 447 | const chat = importAgnaiChat(userName, characterName, jsonData); | ||
| 448 | const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`; | 485 | const fileName = `${characterName} - ${humanizedISO8601DateTime()} imported.jsonl`; |
| 449 | const filePath = path.join(request.user.directories.chats, avatarUrl, fileName); | 486 | const filePath = path.join(request.user.directories.chats, avatarUrl, fileName); |
| 450 | writeFileAtomicSync(filePath, chat, 'utf8'); | 487 | writeFileAtomicSync(filePath, chat, 'utf8'); |
| 451 | return response.send({ res: true }); | 488 | }; |
| 489 | |||
| 490 | const chat = importFunc(userName, characterName, jsonData); | ||
| 491 | |||
| 492 | if (Array.isArray(chat)) { | ||
| 493 | chat.forEach(handleChat); | ||
| 452 | } else { | 494 | } else { |
| 453 | console.log('Incorrect chat format .json'); | 495 | handleChat(chat); |
| 454 | return response.send({ error: true }); | ||
| 455 | } | 496 | } |
| 497 | |||
| 498 | return response.send({ res: true }); | ||
| 456 | } | 499 | } |
| 457 | 500 | ||
| 458 | if (format === 'jsonl') { | 501 | if (format === 'jsonl') { |
| @@ -561,10 +604,14 @@ router.post('/search', jsonParser, function (request, response) { | |||
| 561 | 604 | ||
| 562 | let targetGroup; | 605 | let targetGroup; |
| 563 | for (const groupFile of groupFiles) { | 606 | for (const groupFile of groupFiles) { |
| 564 | const groupData = JSON.parse(fs.readFileSync(path.join(groupDir, groupFile), 'utf8')); | 607 | try { |
| 565 | if (groupData.id === group_id) { | 608 | const groupData = JSON.parse(fs.readFileSync(path.join(groupDir, groupFile), 'utf8')); |
| 566 | targetGroup = groupData; | 609 | if (groupData.id === group_id) { |
| 567 | break; | 610 | targetGroup = groupData; |
| 611 | break; | ||
| 612 | } | ||
| 613 | } catch (error) { | ||
| 614 | console.error(groupFile, 'group file is corrupted:', error); | ||
| 568 | } | 615 | } |
| 569 | } | 616 | } |
| 570 | 617 | ||
| @@ -67,17 +67,17 @@ router.post('/login', jsonParser, async (request, response) => { | |||
| 67 | const user = await storage.getItem(toKey(request.body.handle)); | 67 | const user = await storage.getItem(toKey(request.body.handle)); |
| 68 | 68 | ||
| 69 | if (!user) { | 69 | if (!user) { |
| 70 | console.log('Login failed: User not found'); | 70 | console.log('Login failed: User', request.body.handle, 'not found'); |
| 71 | return response.status(403).json({ error: 'Incorrect credentials' }); | 71 | return response.status(403).json({ error: 'Incorrect credentials' }); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | if (!user.enabled) { | 74 | if (!user.enabled) { |
| 75 | console.log('Login failed: User is disabled'); | 75 | console.log('Login failed: User', user.handle, 'is disabled'); |
| 76 | return response.status(403).json({ error: 'User is disabled' }); | 76 | return response.status(403).json({ error: 'User is disabled' }); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | if (user.password && user.password !== getPasswordHash(request.body.password, user.salt)) { | 79 | if (user.password && user.password !== getPasswordHash(request.body.password, user.salt)) { |
| 80 | console.log('Login failed: Incorrect password'); | 80 | console.log('Login failed: Incorrect password for', user.handle); |
| 81 | return response.status(403).json({ error: 'Incorrect credentials' }); | 81 | return response.status(403).json({ error: 'Incorrect credentials' }); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| @@ -88,7 +88,7 @@ router.post('/login', jsonParser, async (request, response) => { | |||
| 88 | 88 | ||
| 89 | await loginLimiter.delete(ip); | 89 | await loginLimiter.delete(ip); |
| 90 | request.session.handle = user.handle; | 90 | request.session.handle = user.handle; |
| 91 | console.log('Login successful:', user.handle, request.session); | 91 | console.log('Login successful:', user.handle, 'from', ip, 'at', new Date().toLocaleString()); |
| 92 | return response.json({ handle: user.handle }); | 92 | return response.json({ handle: user.handle }); |
| 93 | } catch (error) { | 93 | } catch (error) { |
| 94 | if (error instanceof RateLimiterRes) { | 94 | if (error instanceof RateLimiterRes) { |
| @@ -115,12 +115,12 @@ router.post('/recover-step1', jsonParser, async (request, response) => { | |||
| 115 | const user = await storage.getItem(toKey(request.body.handle)); | 115 | const user = await storage.getItem(toKey(request.body.handle)); |
| 116 | 116 | ||
| 117 | if (!user) { | 117 | if (!user) { |
| 118 | console.log('Recover step 1 failed: User not found'); | 118 | console.log('Recover step 1 failed: User', request.body.handle, 'not found'); |
| 119 | return response.status(404).json({ error: 'User not found' }); | 119 | return response.status(404).json({ error: 'User not found' }); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | if (!user.enabled) { | 122 | if (!user.enabled) { |
| 123 | console.log('Recover step 1 failed: User is disabled'); | 123 | console.log('Recover step 1 failed: User', user.handle, 'is disabled'); |
| 124 | return response.status(403).json({ error: 'User is disabled' }); | 124 | return response.status(403).json({ error: 'User is disabled' }); |
| 125 | } | 125 | } |
| 126 | 126 | ||
| @@ -153,12 +153,12 @@ router.post('/recover-step2', jsonParser, async (request, response) => { | |||
| 153 | const ip = getIpFromRequest(request); | 153 | const ip = getIpFromRequest(request); |
| 154 | 154 | ||
| 155 | if (!user) { | 155 | if (!user) { |
| 156 | console.log('Recover step 2 failed: User not found'); | 156 | console.log('Recover step 2 failed: User', request.body.handle, 'not found'); |
| 157 | return response.status(404).json({ error: 'User not found' }); | 157 | return response.status(404).json({ error: 'User not found' }); |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | if (!user.enabled) { | 160 | if (!user.enabled) { |
| 161 | console.log('Recover step 2 failed: User is disabled'); | 161 | console.log('Recover step 2 failed: User', user.handle, 'is disabled'); |
| 162 | return response.status(403).json({ error: 'User is disabled' }); | 162 | return response.status(403).json({ error: 'User is disabled' }); |
| 163 | } | 163 | } |
| 164 | 164 | ||
| @@ -347,6 +347,7 @@ export function convertGooglePrompt(messages, model, useSysPrompt = false, charN | |||
| 347 | 'gemini-1.5-flash-8b-exp-0924', | 347 | 'gemini-1.5-flash-8b-exp-0924', |
| 348 | 'gemini-exp-1114', | 348 | 'gemini-exp-1114', |
| 349 | 'gemini-exp-1121', | 349 | 'gemini-exp-1121', |
| 350 | 'gemini-exp-1206', | ||
| 350 | 'gemini-1.5-pro', | 351 | 'gemini-1.5-pro', |
| 351 | 'gemini-1.5-pro-latest', | 352 | 'gemini-1.5-pro-latest', |
| 352 | 'gemini-1.5-pro-001', | 353 | 'gemini-1.5-pro-001', |
| @@ -680,8 +680,9 @@ export class MemoryLimitedMap { | |||
| 680 | * @param {number} maxMemoryInBytes - The maximum allowed memory in bytes for string values. | 680 | * @param {number} maxMemoryInBytes - The maximum allowed memory in bytes for string values. |
| 681 | */ | 681 | */ |
| 682 | constructor(maxMemoryInBytes) { | 682 | constructor(maxMemoryInBytes) { |
| 683 | if (typeof maxMemoryInBytes !== 'number' || maxMemoryInBytes <= 0) { | 683 | if (typeof maxMemoryInBytes !== 'number' || maxMemoryInBytes <= 0 || isNaN(maxMemoryInBytes)) { |
| 684 | throw new Error('maxMemoryInBytes must be a positive number'); | 684 | console.warn('Invalid maxMemoryInBytes, using a fallback value of 1 GB.'); |
| 685 | maxMemoryInBytes = 1024 * 1024 * 1024; // 1 GB | ||
| 685 | } | 686 | } |
| 686 | this.maxMemory = maxMemoryInBytes; | 687 | this.maxMemory = maxMemoryInBytes; |
| 687 | this.currentMemory = 0; | 688 | this.currentMemory = 0; |