Merge branch 'staging' of https://github.com/joenunezb/SillyTavern into optimize/improve-search
| @@ -229,6 +229,46 @@ SillyTavern сохраняет ключи от ваших API в файле `sec | |||
| 229 | 1. Зайдите в файл `config.yaml` и установите `allowKeysExposure` в положение `true`. | 229 | 1. Зайдите в файл `config.yaml` и установите `allowKeysExposure` в положение `true`. |
| 230 | 2. Перезапустите сервер SillyTavern. | 230 | 2. Перезапустите сервер SillyTavern. |
| 231 | 231 | ||
| 232 | ## Аргументы командной строки | ||
| 233 | |||
| 234 | Вы можете передавать аргументы командной строки при запуске сервера SillyTavern, чтобы переопределять настройки из `config.yaml`. | ||
| 235 | |||
| 236 | ### Примеры | ||
| 237 | |||
| 238 | ```shell | ||
| 239 | node server.js --port 8000 --listen false | ||
| 240 | # или | ||
| 241 | npm run start -- --port 8000 --listen false | ||
| 242 | # или (только на Windows) | ||
| 243 | Start.bat --port 8000 --listen false | ||
| 244 | ``` | ||
| 245 | |||
| 246 | ### Поддерживаемые аргументы | ||
| 247 | |||
| 248 | | Аргумент | Описание | Тип | | ||
| 249 | |-------------------------|----------------------------------------------------------------------------------------------------------------|----------| | ||
| 250 | | `--version` | Показывает номер версии. | boolean | | ||
| 251 | | `--enableIPv6` | Включает IPv6. | boolean | | ||
| 252 | | `--enableIPv4` | Включает IPv4. | boolean | | ||
| 253 | | `--port` | Устанавливает порт, котрый будет использовать SillyTavern. Если не указан, то используется yaml-конфиг 'port'. | number | | ||
| 254 | | `--dnsPreferIPv6` | Отдает предпочтение IPv6 для dns. Если не указан, то используется yaml-конфиг 'preferIPv6'. | boolean | | ||
| 255 | | `--autorun` | Автоматический запуск SillyTavern в браузере. Если не указан, то используется yaml-конфиг 'autorun'. | boolean | | ||
| 256 | | `--autorunHostname` | Имя хоста автозапуска, лучше оставить на 'auto'. | string | | ||
| 257 | | `--autorunPortOverride` | Переопределяет порт для автозапуска. | string | | ||
| 258 | | `--listen` | SillyTavern будет прослушивать все сетевые интерфейсы. Если не указан, то используется yaml-конфиг 'listen'. | boolean | | ||
| 259 | | `--corsProxy` | Включает CORS-прокси. Если не указан, то используется yaml-конфиг 'enableCorsProxy'. | boolean | | ||
| 260 | | `--disableCsrf` | Отключает защиту от CSRF. | boolean | | ||
| 261 | | `--ssl` | Включает SSL. | boolean | | ||
| 262 | | `--certPath` | Путь к файлу c сертификатом. | string | | ||
| 263 | | `--keyPath` | Путь к файлу с закрытым ключом. | string | | ||
| 264 | | `--whitelist` | Включает режим белого списка. | boolean | | ||
| 265 | | `--dataRoot` | Корневой каталог для хранения данных. | string | | ||
| 266 | | `--avoidLocalhost` | Избегает использования 'localhost' для автозапуска в режиме 'auto'. | boolean | | ||
| 267 | | `--basicAuthMode` | Включает простую аутентификацию. | boolean | | ||
| 268 | | `--requestProxyEnabled` | Разрешает использование прокси для исходящих запросов. | boolean | | ||
| 269 | | `--requestProxyUrl` | URL-адрес прокси (протоколы HTTP или SOCKS). | string | | ||
| 270 | | `--requestProxyBypass` | Bypass список прокси (список хостов, разделенных пробелами). | array | | ||
| 271 | |||
| 232 | ## Удалённое подключение | 272 | ## Удалённое подключение |
| 233 | 273 | ||
| 234 | В основном этим пользуются тогда, когда хотят использовать SillyTavern с телефона, запустив сервер SillyTavern на стационарном ПК в той же Wi-Fi-сети. | 274 | В основном этим пользуются тогда, когда хотят использовать SillyTavern с телефона, запустив сервер SillyTavern на стационарном ПК в той же Wi-Fi-сети. |
| @@ -230,7 +230,6 @@ | |||
| 230 | "show_external_models": false, | 230 | "show_external_models": false, |
| 231 | "assistant_prefill": "", | 231 | "assistant_prefill": "", |
| 232 | "assistant_impersonation": "", | 232 | "assistant_impersonation": "", |
| 233 | "human_sysprompt_message": "Let's get started. Please generate your response based on the information and instructions provided above.", | ||
| 234 | "claude_use_sysprompt": false, | 233 | "claude_use_sysprompt": false, |
| 235 | "use_alt_scale": false, | 234 | "use_alt_scale": false, |
| 236 | "squash_system_messages": false, | 235 | "squash_system_messages": false, |
| @@ -1291,6 +1291,14 @@ | |||
| 1291 | <input class="neo-range-slider" type="range" id="epsilon_cutoff_textgenerationwebui" name="volume" min="0" max="9" step="0.01"> | 1291 | <input class="neo-range-slider" type="range" id="epsilon_cutoff_textgenerationwebui" name="volume" min="0" max="9" step="0.01"> |
| 1292 | <input class="neo-range-input" type="number" min="0" max="9" step="0.01" data-for="epsilon_cutoff_textgenerationwebui" id="epsilon_cutoff_counter_textgenerationwebui"> | 1292 | <input class="neo-range-input" type="number" min="0" max="9" step="0.01" data-for="epsilon_cutoff_textgenerationwebui" id="epsilon_cutoff_counter_textgenerationwebui"> |
| 1293 | </div> | 1293 | </div> |
| 1294 | <div data-tg-type="aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> | ||
| 1295 | <small> | ||
| 1296 | <span data-i18n="Top nsigma">Top nsigma</span> | ||
| 1297 | <div class="fa-solid fa-circle-info opacity50p" title="A sampling method that filters logits based on their statistical properties. It keeps tokens within n standard deviations of the maximum logit value, providing a simpler alternative to top-p/top-k sampling while maintaining sampling stability across different temperatures."></div> | ||
| 1298 | </small> | ||
| 1299 | <input class="neo-range-slider" type="range" id="nsigma_textgenerationwebui" name="volume" min="0" max="5" step="0.01"> | ||
| 1300 | <input class="neo-range-input" type="number" min="0" max="5" step="0.01" data-for="nsigma_textgenerationwebui" id="nsigma_counter_textgenerationwebui"> | ||
| 1301 | </div> | ||
| 1294 | <div data-tg-type="ooba,mancer,aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> | 1302 | <div data-tg-type="ooba,mancer,aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> |
| 1295 | <small> | 1303 | <small> |
| 1296 | <span data-i18n="Eta Cutoff">Eta Cutoff</span> | 1304 | <span data-i18n="Eta Cutoff">Eta Cutoff</span> |
| @@ -1334,12 +1342,12 @@ | |||
| 1334 | <input class="neo-range-slider" type="range" id="presence_pen_textgenerationwebui" name="volume" min="-2" max="2" step="0.01" /> | 1342 | <input class="neo-range-slider" type="range" id="presence_pen_textgenerationwebui" name="volume" min="-2" max="2" step="0.01" /> |
| 1335 | <input class="neo-range-input" type="number" min="-2" max="2" step="0.01" data-for="presence_pen_textgenerationwebui" id="presence_pen_counter_textgenerationwebui"> | 1343 | <input class="neo-range-input" type="number" min="-2" max="2" step="0.01" data-for="presence_pen_textgenerationwebui" id="presence_pen_counter_textgenerationwebui"> |
| 1336 | </div> | 1344 | </div> |
| 1337 | <div data-tg-type="ooba" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> | 1345 | <div data-tg-type="aphrodite, ooba" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> |
| 1338 | <small data-i18n="No Repeat Ngram Size">No Repeat Ngram Size</small> | 1346 | <small data-i18n="No Repeat Ngram Size">No Repeat Ngram Size</small> |
| 1339 | <input class="neo-range-slider" type="range" id="no_repeat_ngram_size_textgenerationwebui" name="volume" min="0" max="20" step="1"> | 1347 | <input class="neo-range-slider" type="range" id="no_repeat_ngram_size_textgenerationwebui" name="volume" min="0" max="20" step="1"> |
| 1340 | <input class="neo-range-input" type="number" min="0" max="20" step="1" data-for="no_repeat_ngram_size_textgenerationwebui" id="no_repeat_ngram_size_counter_textgenerationwebui"> | 1348 | <input class="neo-range-input" type="number" min="0" max="20" step="1" data-for="no_repeat_ngram_size_textgenerationwebui" id="no_repeat_ngram_size_counter_textgenerationwebui"> |
| 1341 | </div> | 1349 | </div> |
| 1342 | <div data-tg-type="tabby" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> | 1350 | <div data-tg-type="tabby, aphrodite" class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> |
| 1343 | <small data-i18n="Skew">Skew</small> | 1351 | <small data-i18n="Skew">Skew</small> |
| 1344 | <input class="neo-range-slider" type="range" id="skew_textgenerationwebui" name="volume" min="-5" max="5" step="0.01" /> | 1352 | <input class="neo-range-slider" type="range" id="skew_textgenerationwebui" name="volume" min="-5" max="5" step="0.01" /> |
| 1345 | <input class="neo-range-input" type="number" min="-5" max="5" step="0.01" data-for="skew_textgenerationwebui" id="skew_counter_textgenerationwebui"> | 1353 | <input class="neo-range-input" type="number" min="-5" max="5" step="0.01" data-for="skew_textgenerationwebui" id="skew_counter_textgenerationwebui"> |
| @@ -1394,7 +1402,7 @@ | |||
| 1394 | </div> | 1402 | </div> |
| 1395 | </div> | 1403 | </div> |
| 1396 | 1404 | ||
| 1397 | <div data-tg-type="ooba, koboldcpp, tabby, llamacpp" id="dryBlock" class="wide100p"> | 1405 | <div data-tg-type="aphrodite, ooba, koboldcpp, tabby, llamacpp" id="dryBlock" class="wide100p"> |
| 1398 | <h4 class="wide100p textAlignCenter" title="DRY penalizes tokens that would extend the end of the input into a sequence that has previously occurred in the input. Set multiplier to 0 to disable." data-i18n="[title]DRY_Repetition_Penalty_desc"> | 1406 | <h4 class="wide100p textAlignCenter" title="DRY penalizes tokens that would extend the end of the input into a sequence that has previously occurred in the input. Set multiplier to 0 to disable." data-i18n="[title]DRY_Repetition_Penalty_desc"> |
| 1399 | <label data-i18n="DRY Repetition Penalty">DRY Repetition Penalty</label> | 1407 | <label data-i18n="DRY Repetition Penalty">DRY Repetition Penalty</label> |
| 1400 | <a href="https://github.com/oobabooga/text-generation-webui/pull/5677" target="_blank"> | 1408 | <a href="https://github.com/oobabooga/text-generation-webui/pull/5677" target="_blank"> |
| @@ -1951,15 +1959,6 @@ | |||
| 1951 | Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt. | 1959 | Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt. |
| 1952 | </span> | 1960 | </span> |
| 1953 | </div> | 1961 | </div> |
| 1954 | <div id="claude_human_sysprompt_message_block" class="wide100p"> | ||
| 1955 | <div class="range-block-title openai_restorable"> | ||
| 1956 | <span data-i18n="User first message">User first message</span> | ||
| 1957 | <div id="claude_human_sysprompt_message_restore" title="Restore User first message" data-i18n="[title]Restore User first message" class="right_menu_button"> | ||
| 1958 | <div class="fa-solid fa-clock-rotate-left"></div> | ||
| 1959 | </div> | ||
| 1960 | </div> | ||
| 1961 | <textarea id="claude_human_sysprompt_textarea" class="text_pole textarea_compact autoSetHeight" rows="2" data-i18n="[placeholder]Human message" placeholder="Human message, instruction, etc. Adds nothing when empty, i.e. requires a new prompt with the role 'user'."></textarea> | ||
| 1962 | </div> | ||
| 1963 | </div> | 1962 | </div> |
| 1964 | </div> | 1963 | </div> |
| 1965 | <div class="range-block m-t-1" data-source="openai,openrouter,scale,custom"> | 1964 | <div class="range-block m-t-1" data-source="openai,openrouter,scale,custom"> |
| @@ -2805,9 +2804,6 @@ | |||
| 2805 | <option value="claude-3-haiku-20240307">claude-3-haiku-20240307</option> | 2804 | <option value="claude-3-haiku-20240307">claude-3-haiku-20240307</option> |
| 2806 | <option value="claude-2.1">claude-2.1</option> | 2805 | <option value="claude-2.1">claude-2.1</option> |
| 2807 | <option value="claude-2.0">claude-2.0</option> | 2806 | <option value="claude-2.0">claude-2.0</option> |
| 2808 | <option value="claude-1.3">claude-1.3</option> | ||
| 2809 | <option value="claude-instant-1.2">claude-instant-1.2</option> | ||
| 2810 | <option value="claude-instant-1.1">claude-instant-1.1</option> | ||
| 2811 | </optgroup> | 2807 | </optgroup> |
| 2812 | </select> | 2808 | </select> |
| 2813 | </div> | 2809 | </div> |
| @@ -2707,8 +2707,7 @@ export async function generateQuietPrompt(quiet_prompt, quietToLoud, skipWIAN, q | |||
| 2707 | quietName: quietName, | 2707 | quietName: quietName, |
| 2708 | }; | 2708 | }; |
| 2709 | originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1; | 2709 | originalResponseLength = responseLengthCustomized ? saveResponseLength(main_api, responseLength) : -1; |
| 2710 | const generateFinished = await Generate('quiet', options); | 2710 | return await Generate('quiet', options); |
| 2711 | return generateFinished; | ||
| 2712 | } finally { | 2711 | } finally { |
| 2713 | if (responseLengthCustomized) { | 2712 | if (responseLengthCustomized) { |
| 2714 | restoreResponseLength(main_api, originalResponseLength); | 2713 | restoreResponseLength(main_api, originalResponseLength); |
| @@ -3363,9 +3362,9 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | |||
| 3363 | 3362 | ||
| 3364 | let data = {}; | 3363 | let data = {}; |
| 3365 | 3364 | ||
| 3366 | if (api == 'koboldhorde') { | 3365 | if (api === 'koboldhorde') { |
| 3367 | data = await generateHorde(prompt, generateData, abortController.signal, false); | 3366 | data = await generateHorde(prompt, generateData, abortController.signal, false); |
| 3368 | } else if (api == 'openai') { | 3367 | } else if (api === 'openai') { |
| 3369 | data = await sendOpenAIRequest('quiet', generateData, abortController.signal); | 3368 | data = await sendOpenAIRequest('quiet', generateData, abortController.signal); |
| 3370 | } else { | 3369 | } else { |
| 3371 | const generateUrl = getGenerateUrl(api); | 3370 | const generateUrl = getGenerateUrl(api); |
| @@ -3378,13 +3377,15 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | |||
| 3378 | }); | 3377 | }); |
| 3379 | 3378 | ||
| 3380 | if (!response.ok) { | 3379 | if (!response.ok) { |
| 3381 | const error = await response.json(); | 3380 | throw await response.json(); |
| 3382 | throw error; | ||
| 3383 | } | 3381 | } |
| 3384 | 3382 | ||
| 3385 | data = await response.json(); | 3383 | data = await response.json(); |
| 3386 | } | 3384 | } |
| 3387 | 3385 | ||
| 3386 | // should only happen for text completions | ||
| 3387 | // other frontend paths do not return data if calling the backend fails, | ||
| 3388 | // they throw things instead | ||
| 3388 | if (data.error) { | 3389 | if (data.error) { |
| 3389 | throw new Error(data.response); | 3390 | throw new Error(data.response); |
| 3390 | } | 3391 | } |
| @@ -4436,6 +4437,11 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4436 | return Promise.resolve(); | 4437 | return Promise.resolve(); |
| 4437 | } | 4438 | } |
| 4438 | 4439 | ||
| 4440 | /** | ||
| 4441 | * Saves itemized prompt bits and calls streaming or non-streaming generation API. | ||
| 4442 | * @returns {Promise<void|*|Awaited<*>|String|{fromStream}|string|undefined|Object>} | ||
| 4443 | * @throws {Error|object} Error with message text, or Error with response JSON (OAI/Horde), or the actual response JSON (novel|textgenerationwebui|kobold) | ||
| 4444 | */ | ||
| 4439 | async function finishGenerating() { | 4445 | async function finishGenerating() { |
| 4440 | if (power_user.console_log_prompts) { | 4446 | if (power_user.console_log_prompts) { |
| 4441 | console.log(generate_data.prompt); | 4447 | console.log(generate_data.prompt); |
| @@ -4547,6 +4553,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4547 | 4553 | ||
| 4548 | return finishGenerating().then(onSuccess, onError); | 4554 | return finishGenerating().then(onSuccess, onError); |
| 4549 | 4555 | ||
| 4556 | /** | ||
| 4557 | * Handles the successful response from the generation API. | ||
| 4558 | * @param data | ||
| 4559 | * @returns {Promise<String|{fromStream}|*|string|string|void|Awaited<*>|undefined>} | ||
| 4560 | * @throws {Error} Throws an error if the response data contains an error message | ||
| 4561 | */ | ||
| 4550 | async function onSuccess(data) { | 4562 | async function onSuccess(data) { |
| 4551 | if (!data) return; | 4563 | if (!data) return; |
| 4552 | 4564 | ||
| @@ -4556,6 +4568,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4556 | 4568 | ||
| 4557 | let messageChunk = ''; | 4569 | let messageChunk = ''; |
| 4558 | 4570 | ||
| 4571 | // if an error was returned in data (textgenwebui), show it and throw it | ||
| 4559 | if (data.error) { | 4572 | if (data.error) { |
| 4560 | unblockGeneration(type); | 4573 | unblockGeneration(type); |
| 4561 | generatedPromptCache = ''; | 4574 | generatedPromptCache = ''; |
| @@ -4670,9 +4683,15 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4670 | return Object.defineProperty(new String(getMessage), 'messageChunk', { value: messageChunk }); | 4683 | return Object.defineProperty(new String(getMessage), 'messageChunk', { value: messageChunk }); |
| 4671 | } | 4684 | } |
| 4672 | 4685 | ||
| 4686 | /** | ||
| 4687 | * Exception handler for finishGenerating | ||
| 4688 | * @param {Error|object} exception Error or response JSON | ||
| 4689 | * @throws {Error|object} Re-throws the exception | ||
| 4690 | */ | ||
| 4673 | function onError(exception) { | 4691 | function onError(exception) { |
| 4692 | // if the response JSON was thrown (novel|textgenerationwebui|kobold), show the error message | ||
| 4674 | if (typeof exception?.error?.message === 'string') { | 4693 | if (typeof exception?.error?.message === 'string') { |
| 4675 | toastr.error(exception.error.message, t`Error`, { timeOut: 10000, extendedTimeOut: 20000 }); | 4694 | toastr.error(exception.error.message, t`Text generation error`, { timeOut: 10000, extendedTimeOut: 20000 }); |
| 4676 | } | 4695 | } |
| 4677 | 4696 | ||
| 4678 | generatedPromptCache = ''; | 4697 | generatedPromptCache = ''; |
| @@ -5340,6 +5359,7 @@ function setInContextMessages(lastmsg, type) { | |||
| 5340 | * @param {string} type Generation type | 5359 | * @param {string} type Generation type |
| 5341 | * @param {object} data Generation data | 5360 | * @param {object} data Generation data |
| 5342 | * @returns {Promise<object>} Response data from the API | 5361 | * @returns {Promise<object>} Response data from the API |
| 5362 | * @throws {Error|object} | ||
| 5343 | */ | 5363 | */ |
| 5344 | export async function sendGenerationRequest(type, data) { | 5364 | export async function sendGenerationRequest(type, data) { |
| 5345 | if (main_api === 'openai') { | 5365 | if (main_api === 'openai') { |
| @@ -5359,12 +5379,10 @@ export async function sendGenerationRequest(type, data) { | |||
| 5359 | }); | 5379 | }); |
| 5360 | 5380 | ||
| 5361 | if (!response.ok) { | 5381 | if (!response.ok) { |
| 5362 | const error = await response.json(); | 5382 | throw await response.json(); |
| 5363 | throw error; | ||
| 5364 | } | 5383 | } |
| 5365 | 5384 | ||
| 5366 | const responseData = await response.json(); | 5385 | return await response.json(); |
| 5367 | return responseData; | ||
| 5368 | } | 5386 | } |
| 5369 | 5387 | ||
| 5370 | /** | 5388 | /** |
| @@ -5396,6 +5414,7 @@ export async function sendStreamingRequest(type, data) { | |||
| 5396 | * Gets the generation endpoint URL for the specified API. | 5414 | * Gets the generation endpoint URL for the specified API. |
| 5397 | * @param {string} api API name | 5415 | * @param {string} api API name |
| 5398 | * @returns {string} Generation URL | 5416 | * @returns {string} Generation URL |
| 5417 | * @throws {Error} If the API is unknown | ||
| 5399 | */ | 5418 | */ |
| 5400 | function getGenerateUrl(api) { | 5419 | function getGenerateUrl(api) { |
| 5401 | switch (api) { | 5420 | switch (api) { |
| @@ -65,6 +65,11 @@ const parse_derivation = derivation => (typeof derivation === 'string') ? { | |||
| 65 | } : derivation; | 65 | } : derivation; |
| 66 | 66 | ||
| 67 | export async function deriveTemplatesFromChatTemplate(chat_template, hash) { | 67 | export async function deriveTemplatesFromChatTemplate(chat_template, hash) { |
| 68 | if (chat_template.trim() === '') { | ||
| 69 | console.log('Missing chat template.'); | ||
| 70 | return null; | ||
| 71 | } | ||
| 72 | |||
| 68 | if (hash in hash_derivations) { | 73 | if (hash in hash_derivations) { |
| 69 | return parse_derivation(hash_derivations[hash]); | 74 | return parse_derivation(hash_derivations[hash]); |
| 70 | } | 75 | } |
| @@ -2373,6 +2373,7 @@ function ensureSelectionExists(setting, selector) { | |||
| 2373 | * @param {string} [message] Chat message | 2373 | * @param {string} [message] Chat message |
| 2374 | * @param {function} [callback] Callback function | 2374 | * @param {function} [callback] Callback function |
| 2375 | * @returns {Promise<string|undefined>} Image path | 2375 | * @returns {Promise<string|undefined>} Image path |
| 2376 | * @throws {Error} If the prompt or image generation fails | ||
| 2376 | */ | 2377 | */ |
| 2377 | async function generatePicture(initiator, args, trigger, message, callback) { | 2378 | async function generatePicture(initiator, args, trigger, message, callback) { |
| 2378 | if (!trigger || trigger.trim().length === 0) { | 2379 | if (!trigger || trigger.trim().length === 0) { |
| @@ -2391,7 +2392,7 @@ async function generatePicture(initiator, args, trigger, message, callback) { | |||
| 2391 | trigger = trigger.trim(); | 2392 | trigger = trigger.trim(); |
| 2392 | const generationType = getGenerationType(trigger); | 2393 | const generationType = getGenerationType(trigger); |
| 2393 | const generationTypeKey = Object.keys(generationMode).find(key => generationMode[key] === generationType); | 2394 | const generationTypeKey = Object.keys(generationMode).find(key => generationMode[key] === generationType); |
| 2394 | console.log(`Generation mode ${generationTypeKey} triggered with "${trigger}"`); | 2395 | console.log(`Image generation mode ${generationTypeKey} triggered with "${trigger}"`); |
| 2395 | 2396 | ||
| 2396 | const quietPrompt = getQuietPrompt(generationType, trigger); | 2397 | const quietPrompt = getQuietPrompt(generationType, trigger); |
| 2397 | const context = getContext(); | 2398 | const context = getContext(); |
| @@ -2428,6 +2429,8 @@ async function generatePicture(initiator, args, trigger, message, callback) { | |||
| 2428 | 2429 | ||
| 2429 | try { | 2430 | try { |
| 2430 | const combineNegatives = (prefix) => { negativePromptPrefix = combinePrefixes(negativePromptPrefix, prefix); }; | 2431 | const combineNegatives = (prefix) => { negativePromptPrefix = combinePrefixes(negativePromptPrefix, prefix); }; |
| 2432 | |||
| 2433 | // generate the text prompt for the image | ||
| 2431 | const prompt = await getPrompt(generationType, message, trigger, quietPrompt, combineNegatives); | 2434 | const prompt = await getPrompt(generationType, message, trigger, quietPrompt, combineNegatives); |
| 2432 | console.log('Processed image prompt:', prompt); | 2435 | console.log('Processed image prompt:', prompt); |
| 2433 | 2436 | ||
| @@ -2438,11 +2441,16 @@ async function generatePicture(initiator, args, trigger, message, callback) { | |||
| 2438 | args._abortController.addEventListener('abort', stopListener); | 2441 | args._abortController.addEventListener('abort', stopListener); |
| 2439 | } | 2442 | } |
| 2440 | 2443 | ||
| 2444 | // generate the image | ||
| 2441 | imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback, initiator, abortController.signal); | 2445 | imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback, initiator, abortController.signal); |
| 2442 | } catch (err) { | 2446 | } catch (err) { |
| 2443 | console.trace(err); | 2447 | console.trace(err); |
| 2444 | toastr.error('SD prompt text generation failed. Reason: ' + err, 'Image Generation'); | 2448 | // errors here are most likely due to text generation failure |
| 2445 | throw new Error('SD prompt text generation failed. Reason: ' + err); | 2449 | // sendGenerationRequest mostly deals with its own errors |
| 2450 | const reason = err.error?.message || err.message || 'Unknown error'; | ||
| 2451 | const errorText = 'SD prompt text generation failed. ' + reason; | ||
| 2452 | toastr.error(errorText, 'Image Generation'); | ||
| 2453 | throw new Error(errorText); | ||
| 2446 | } | 2454 | } |
| 2447 | finally { | 2455 | finally { |
| 2448 | $(stopButton).hide(); | 2456 | $(stopButton).hide(); |
| @@ -2513,7 +2521,7 @@ function restoreOriginalDimensions(savedParams) { | |||
| 2513 | */ | 2521 | */ |
| 2514 | async function getPrompt(generationType, message, trigger, quietPrompt, combineNegatives) { | 2522 | async function getPrompt(generationType, message, trigger, quietPrompt, combineNegatives) { |
| 2515 | let prompt; | 2523 | let prompt; |
| 2516 | 2524 | console.log('getPrompt: Generation mode', generationType, 'triggered with', trigger); | |
| 2517 | switch (generationType) { | 2525 | switch (generationType) { |
| 2518 | case generationMode.RAW_LAST: | 2526 | case generationMode.RAW_LAST: |
| 2519 | prompt = message || getRawLastMessage(); | 2527 | prompt = message || getRawLastMessage(); |
| @@ -2729,7 +2737,7 @@ async function sendGenerationRequest(generationType, prompt, additionalNegativeP | |||
| 2729 | throw new Error('Endpoint did not return image data.'); | 2737 | throw new Error('Endpoint did not return image data.'); |
| 2730 | } | 2738 | } |
| 2731 | } catch (err) { | 2739 | } catch (err) { |
| 2732 | console.error(err); | 2740 | console.error('Image generation request error: ', err); |
| 2733 | toastr.error('Image generation failed. Please try again.' + '\n\n' + String(err), 'Image Generation'); | 2741 | toastr.error('Image generation failed. Please try again.' + '\n\n' + String(err), 'Image Generation'); |
| 2734 | return; | 2742 | return; |
| 2735 | } | 2743 | } |
| @@ -181,6 +181,14 @@ function setContextSizePreview() { | |||
| 181 | } | 181 | } |
| 182 | } | 182 | } |
| 183 | 183 | ||
| 184 | /** Generates text using the Horde API. | ||
| 185 | * @param {string} prompt | ||
| 186 | * @param params | ||
| 187 | * @param signal | ||
| 188 | * @param reportProgress | ||
| 189 | * @returns {Promise<{text: *, workerName: string}>} | ||
| 190 | * @throws {Error} | ||
| 191 | */ | ||
| 184 | async function generateHorde(prompt, params, signal, reportProgress) { | 192 | async function generateHorde(prompt, params, signal, reportProgress) { |
| 185 | validateHordeModel(); | 193 | validateHordeModel(); |
| 186 | delete params.prompt; | 194 | delete params.prompt; |
| @@ -99,7 +99,6 @@ const default_wi_format = '{0}'; | |||
| 99 | const default_new_chat_prompt = '[Start a new Chat]'; | 99 | const default_new_chat_prompt = '[Start a new Chat]'; |
| 100 | const default_new_group_chat_prompt = '[Start a new group chat. Group members: {{group}}]'; | 100 | const default_new_group_chat_prompt = '[Start a new group chat. Group members: {{group}}]'; |
| 101 | const default_new_example_chat_prompt = '[Example Chat]'; | 101 | const default_new_example_chat_prompt = '[Example Chat]'; |
| 102 | const default_claude_human_sysprompt_message = 'Let\'s get started. Please generate your response based on the information and instructions provided above.'; | ||
| 103 | const default_continue_nudge_prompt = '[Continue the following message. Do not include ANY parts of the original message. Use capitalization and punctuation as if your reply is a part of the original message: {{lastChatMessage}}]'; | 102 | const default_continue_nudge_prompt = '[Continue the following message. Do not include ANY parts of the original message. Use capitalization and punctuation as if your reply is a part of the original message: {{lastChatMessage}}]'; |
| 104 | const default_bias = 'Default (none)'; | 103 | const default_bias = 'Default (none)'; |
| 105 | const default_personality_format = '[{{char}}\'s personality: {{personality}}]'; | 104 | const default_personality_format = '[{{char}}\'s personality: {{personality}}]'; |
| @@ -276,7 +275,6 @@ const default_settings = { | |||
| 276 | proxy_password: '', | 275 | proxy_password: '', |
| 277 | assistant_prefill: '', | 276 | assistant_prefill: '', |
| 278 | assistant_impersonation: '', | 277 | assistant_impersonation: '', |
| 279 | human_sysprompt_message: default_claude_human_sysprompt_message, | ||
| 280 | claude_use_sysprompt: false, | 278 | claude_use_sysprompt: false, |
| 281 | use_makersuite_sysprompt: true, | 279 | use_makersuite_sysprompt: true, |
| 282 | use_alt_scale: false, | 280 | use_alt_scale: false, |
| @@ -353,7 +351,6 @@ const oai_settings = { | |||
| 353 | proxy_password: '', | 351 | proxy_password: '', |
| 354 | assistant_prefill: '', | 352 | assistant_prefill: '', |
| 355 | assistant_impersonation: '', | 353 | assistant_impersonation: '', |
| 356 | human_sysprompt_message: default_claude_human_sysprompt_message, | ||
| 357 | claude_use_sysprompt: false, | 354 | claude_use_sysprompt: false, |
| 358 | use_makersuite_sysprompt: true, | 355 | use_makersuite_sysprompt: true, |
| 359 | use_alt_scale: false, | 356 | use_alt_scale: false, |
| @@ -1313,6 +1310,11 @@ export async function prepareOpenAIMessages({ | |||
| 1313 | return [chat, promptManager.tokenHandler.counts]; | 1310 | return [chat, promptManager.tokenHandler.counts]; |
| 1314 | } | 1311 | } |
| 1315 | 1312 | ||
| 1313 | /** | ||
| 1314 | * Handles errors during streaming requests. | ||
| 1315 | * @param {Response} response | ||
| 1316 | * @param {string} decoded - response text or decoded stream data | ||
| 1317 | */ | ||
| 1316 | function tryParseStreamingError(response, decoded) { | 1318 | function tryParseStreamingError(response, decoded) { |
| 1317 | try { | 1319 | try { |
| 1318 | const data = JSON.parse(decoded); | 1320 | const data = JSON.parse(decoded); |
| @@ -1324,6 +1326,9 @@ function tryParseStreamingError(response, decoded) { | |||
| 1324 | checkQuotaError(data); | 1326 | checkQuotaError(data); |
| 1325 | checkModerationError(data); | 1327 | checkModerationError(data); |
| 1326 | 1328 | ||
| 1329 | // these do not throw correctly (equiv to Error("[object Object]")) | ||
| 1330 | // if trying to fix "[object Object]" displayed to users, start here | ||
| 1331 | |||
| 1327 | if (data.error) { | 1332 | if (data.error) { |
| 1328 | toastr.error(data.error.message || response.statusText, 'Chat Completion API'); | 1333 | toastr.error(data.error.message || response.statusText, 'Chat Completion API'); |
| 1329 | throw new Error(data); | 1334 | throw new Error(data); |
| @@ -1339,15 +1344,22 @@ function tryParseStreamingError(response, decoded) { | |||
| 1339 | } | 1344 | } |
| 1340 | } | 1345 | } |
| 1341 | 1346 | ||
| 1342 | async function checkQuotaError(data) { | 1347 | /** |
| 1343 | const errorText = await renderTemplateAsync('quotaError'); | 1348 | * Checks if the response contains a quota error and displays a popup if it does. |
| 1344 | 1349 | * @param data | |
| 1350 | * @returns {void} | ||
| 1351 | * @throws {object} - response JSON | ||
| 1352 | */ | ||
| 1353 | function checkQuotaError(data) { | ||
| 1345 | if (!data) { | 1354 | if (!data) { |
| 1346 | return; | 1355 | return; |
| 1347 | } | 1356 | } |
| 1348 | 1357 | ||
| 1349 | if (data.quota_error) { | 1358 | if (data.quota_error) { |
| 1350 | callPopup(errorText, 'text'); | 1359 | renderTemplateAsync('quotaError').then((html) => Popup.show.text('Quota Error', html)); |
| 1360 | |||
| 1361 | // this does not throw correctly (equiv to Error("[object Object]")) | ||
| 1362 | // if trying to fix "[object Object]" displayed to users, start here | ||
| 1351 | throw new Error(data); | 1363 | throw new Error(data); |
| 1352 | } | 1364 | } |
| 1353 | } | 1365 | } |
| @@ -1766,6 +1778,15 @@ async function sendAltScaleRequest(messages, logit_bias, signal, type) { | |||
| 1766 | return data.output; | 1778 | return data.output; |
| 1767 | } | 1779 | } |
| 1768 | 1780 | ||
| 1781 | /** | ||
| 1782 | * Send a chat completion request to backend | ||
| 1783 | * @param {string} type (impersonate, quiet, continue, etc) | ||
| 1784 | * @param {Array} messages | ||
| 1785 | * @param {AbortSignal?} signal | ||
| 1786 | * @returns {Promise<unknown>} | ||
| 1787 | * @throws {Error} | ||
| 1788 | */ | ||
| 1789 | |||
| 1769 | async function sendOpenAIRequest(type, messages, signal) { | 1790 | async function sendOpenAIRequest(type, messages, signal) { |
| 1770 | // Provide default abort signal | 1791 | // Provide default abort signal |
| 1771 | if (!signal) { | 1792 | if (!signal) { |
| @@ -1868,7 +1889,6 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 1868 | generate_data['top_k'] = Number(oai_settings.top_k_openai); | 1889 | generate_data['top_k'] = Number(oai_settings.top_k_openai); |
| 1869 | generate_data['claude_use_sysprompt'] = oai_settings.claude_use_sysprompt; | 1890 | generate_data['claude_use_sysprompt'] = oai_settings.claude_use_sysprompt; |
| 1870 | generate_data['stop'] = getCustomStoppingStrings(); // Claude shouldn't have limits on stop strings. | 1891 | generate_data['stop'] = getCustomStoppingStrings(); // Claude shouldn't have limits on stop strings. |
| 1871 | generate_data['human_sysprompt_message'] = substituteParams(oai_settings.human_sysprompt_message); | ||
| 1872 | // Don't add a prefill on quiet gens (summarization) and when using continue prefill. | 1892 | // Don't add a prefill on quiet gens (summarization) and when using continue prefill. |
| 1873 | if (!isQuiet && !(isContinue && oai_settings.continue_prefill)) { | 1893 | if (!isQuiet && !(isContinue && oai_settings.continue_prefill)) { |
| 1874 | generate_data['assistant_prefill'] = isImpersonate ? substituteParams(oai_settings.assistant_impersonation) : substituteParams(oai_settings.assistant_prefill); | 1894 | generate_data['assistant_prefill'] = isImpersonate ? substituteParams(oai_settings.assistant_impersonation) : substituteParams(oai_settings.assistant_prefill); |
| @@ -2028,12 +2048,13 @@ async function sendOpenAIRequest(type, messages, signal) { | |||
| 2028 | else { | 2048 | else { |
| 2029 | const data = await response.json(); | 2049 | const data = await response.json(); |
| 2030 | 2050 | ||
| 2031 | await checkQuotaError(data); | 2051 | checkQuotaError(data); |
| 2032 | checkModerationError(data); | 2052 | checkModerationError(data); |
| 2033 | 2053 | ||
| 2034 | if (data.error) { | 2054 | if (data.error) { |
| 2035 | toastr.error(data.error.message || response.statusText, t`API returned an error`); | 2055 | const message = data.error.message || response.statusText || t`Unknown error`; |
| 2036 | throw new Error(data); | 2056 | toastr.error(message, t`API returned an error`); |
| 2057 | throw new Error(message); | ||
| 2037 | } | 2058 | } |
| 2038 | 2059 | ||
| 2039 | if (type !== 'quiet') { | 2060 | if (type !== 'quiet') { |
| @@ -3005,7 +3026,6 @@ function loadOpenAISettings(data, settings) { | |||
| 3005 | oai_settings.proxy_password = settings.proxy_password ?? default_settings.proxy_password; | 3026 | oai_settings.proxy_password = settings.proxy_password ?? default_settings.proxy_password; |
| 3006 | oai_settings.assistant_prefill = settings.assistant_prefill ?? default_settings.assistant_prefill; | 3027 | oai_settings.assistant_prefill = settings.assistant_prefill ?? default_settings.assistant_prefill; |
| 3007 | oai_settings.assistant_impersonation = settings.assistant_impersonation ?? default_settings.assistant_impersonation; | 3028 | oai_settings.assistant_impersonation = settings.assistant_impersonation ?? default_settings.assistant_impersonation; |
| 3008 | oai_settings.human_sysprompt_message = settings.human_sysprompt_message ?? default_settings.human_sysprompt_message; | ||
| 3009 | oai_settings.image_inlining = settings.image_inlining ?? default_settings.image_inlining; | 3029 | oai_settings.image_inlining = settings.image_inlining ?? default_settings.image_inlining; |
| 3010 | oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality; | 3030 | oai_settings.inline_image_quality = settings.inline_image_quality ?? default_settings.inline_image_quality; |
| 3011 | oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check; | 3031 | oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check; |
| @@ -3045,7 +3065,6 @@ function loadOpenAISettings(data, settings) { | |||
| 3045 | $('#openai_proxy_password').val(oai_settings.proxy_password); | 3065 | $('#openai_proxy_password').val(oai_settings.proxy_password); |
| 3046 | $('#claude_assistant_prefill').val(oai_settings.assistant_prefill); | 3066 | $('#claude_assistant_prefill').val(oai_settings.assistant_prefill); |
| 3047 | $('#claude_assistant_impersonation').val(oai_settings.assistant_impersonation); | 3067 | $('#claude_assistant_impersonation').val(oai_settings.assistant_impersonation); |
| 3048 | $('#claude_human_sysprompt_textarea').val(oai_settings.human_sysprompt_message); | ||
| 3049 | $('#openai_image_inlining').prop('checked', oai_settings.image_inlining); | 3068 | $('#openai_image_inlining').prop('checked', oai_settings.image_inlining); |
| 3050 | $('#openai_bypass_status_check').prop('checked', oai_settings.bypass_status_check); | 3069 | $('#openai_bypass_status_check').prop('checked', oai_settings.bypass_status_check); |
| 3051 | 3070 | ||
| @@ -3375,7 +3394,6 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { | |||
| 3375 | show_external_models: settings.show_external_models, | 3394 | show_external_models: settings.show_external_models, |
| 3376 | assistant_prefill: settings.assistant_prefill, | 3395 | assistant_prefill: settings.assistant_prefill, |
| 3377 | assistant_impersonation: settings.assistant_impersonation, | 3396 | assistant_impersonation: settings.assistant_impersonation, |
| 3378 | human_sysprompt_message: settings.human_sysprompt_message, | ||
| 3379 | claude_use_sysprompt: settings.claude_use_sysprompt, | 3397 | claude_use_sysprompt: settings.claude_use_sysprompt, |
| 3380 | use_makersuite_sysprompt: settings.use_makersuite_sysprompt, | 3398 | use_makersuite_sysprompt: settings.use_makersuite_sysprompt, |
| 3381 | use_alt_scale: settings.use_alt_scale, | 3399 | use_alt_scale: settings.use_alt_scale, |
| @@ -3800,7 +3818,6 @@ function onSettingsPresetChange() { | |||
| 3800 | proxy_password: ['#openai_proxy_password', 'proxy_password', false], | 3818 | proxy_password: ['#openai_proxy_password', 'proxy_password', false], |
| 3801 | assistant_prefill: ['#claude_assistant_prefill', 'assistant_prefill', false], | 3819 | assistant_prefill: ['#claude_assistant_prefill', 'assistant_prefill', false], |
| 3802 | assistant_impersonation: ['#claude_assistant_impersonation', 'assistant_impersonation', false], | 3820 | assistant_impersonation: ['#claude_assistant_impersonation', 'assistant_impersonation', false], |
| 3803 | human_sysprompt_message: ['#claude_human_sysprompt_textarea', 'human_sysprompt_message', false], | ||
| 3804 | claude_use_sysprompt: ['#claude_use_sysprompt', 'claude_use_sysprompt', true], | 3821 | claude_use_sysprompt: ['#claude_use_sysprompt', 'claude_use_sysprompt', true], |
| 3805 | use_makersuite_sysprompt: ['#use_makersuite_sysprompt', 'use_makersuite_sysprompt', true], | 3822 | use_makersuite_sysprompt: ['#use_makersuite_sysprompt', 'use_makersuite_sysprompt', true], |
| 3806 | use_alt_scale: ['#use_alt_scale', 'use_alt_scale', true], | 3823 | use_alt_scale: ['#use_alt_scale', 'use_alt_scale', true], |
| @@ -4652,10 +4669,6 @@ function toggleChatCompletionForms() { | |||
| 4652 | const validSources = $(this).data('source').split(','); | 4669 | const validSources = $(this).data('source').split(','); |
| 4653 | $(this).toggle(validSources.includes(oai_settings.chat_completion_source)); | 4670 | $(this).toggle(validSources.includes(oai_settings.chat_completion_source)); |
| 4654 | }); | 4671 | }); |
| 4655 | |||
| 4656 | if (chat_completion_sources.CLAUDE == oai_settings.chat_completion_source) { | ||
| 4657 | $('#claude_human_sysprompt_message_block').toggle(oai_settings.claude_use_sysprompt); | ||
| 4658 | } | ||
| 4659 | } | 4672 | } |
| 4660 | 4673 | ||
| 4661 | async function testApiConnection() { | 4674 | async function testApiConnection() { |
| @@ -5011,7 +5024,6 @@ export function initOpenAI() { | |||
| 5011 | 5024 | ||
| 5012 | $('#claude_use_sysprompt').on('change', function () { | 5025 | $('#claude_use_sysprompt').on('change', function () { |
| 5013 | oai_settings.claude_use_sysprompt = !!$('#claude_use_sysprompt').prop('checked'); | 5026 | oai_settings.claude_use_sysprompt = !!$('#claude_use_sysprompt').prop('checked'); |
| 5014 | $('#claude_human_sysprompt_message_block').toggle(oai_settings.claude_use_sysprompt); | ||
| 5015 | saveSettingsDebounced(); | 5027 | saveSettingsDebounced(); |
| 5016 | }); | 5028 | }); |
| 5017 | 5029 | ||
| @@ -5088,12 +5100,6 @@ export function initOpenAI() { | |||
| 5088 | saveSettingsDebounced(); | 5100 | saveSettingsDebounced(); |
| 5089 | }); | 5101 | }); |
| 5090 | 5102 | ||
| 5091 | $('#claude_human_sysprompt_message_restore').on('click', function () { | ||
| 5092 | oai_settings.human_sysprompt_message = default_claude_human_sysprompt_message; | ||
| 5093 | $('#claude_human_sysprompt_textarea').val(oai_settings.human_sysprompt_message); | ||
| 5094 | saveSettingsDebounced(); | ||
| 5095 | }); | ||
| 5096 | |||
| 5097 | $('#newgroupchat_prompt_restore').on('click', function () { | 5103 | $('#newgroupchat_prompt_restore').on('click', function () { |
| 5098 | oai_settings.new_group_chat_prompt = default_new_group_chat_prompt; | 5104 | oai_settings.new_group_chat_prompt = default_new_group_chat_prompt; |
| 5099 | $('#newgroupchat_prompt_textarea').val(oai_settings.new_group_chat_prompt); | 5105 | $('#newgroupchat_prompt_textarea').val(oai_settings.new_group_chat_prompt); |
| @@ -5185,11 +5191,6 @@ export function initOpenAI() { | |||
| 5185 | saveSettingsDebounced(); | 5191 | saveSettingsDebounced(); |
| 5186 | }); | 5192 | }); |
| 5187 | 5193 | ||
| 5188 | $('#claude_human_sysprompt_textarea').on('input', function () { | ||
| 5189 | oai_settings.human_sysprompt_message = String($('#claude_human_sysprompt_textarea').val()); | ||
| 5190 | saveSettingsDebounced(); | ||
| 5191 | }); | ||
| 5192 | |||
| 5193 | $('#openrouter_use_fallback').on('input', function () { | 5194 | $('#openrouter_use_fallback').on('input', function () { |
| 5194 | oai_settings.openrouter_use_fallback = !!$(this).prop('checked'); | 5195 | oai_settings.openrouter_use_fallback = !!$(this).prop('checked'); |
| 5195 | saveSettingsDebounced(); | 5196 | saveSettingsDebounced(); |
| @@ -658,6 +658,10 @@ async function CreateZenSliders(elmnt) { | |||
| 658 | numSteps = 50; | 658 | numSteps = 50; |
| 659 | decimals = 1; | 659 | decimals = 1; |
| 660 | } | 660 | } |
| 661 | if (sliderID == 'nsigma') { | ||
| 662 | numSteps = 50; | ||
| 663 | decimals = 1; | ||
| 664 | } | ||
| 661 | //customize steps | 665 | //customize steps |
| 662 | if (sliderID == 'mirostat_mode_textgenerationwebui' || | 666 | if (sliderID == 'mirostat_mode_textgenerationwebui' || |
| 663 | sliderID == 'mirostat_mode_kobold') { | 667 | sliderID == 'mirostat_mode_kobold') { |
| @@ -702,6 +706,7 @@ async function CreateZenSliders(elmnt) { | |||
| 702 | sliderID == 'penalty_alpha_textgenerationwebui' || | 706 | sliderID == 'penalty_alpha_textgenerationwebui' || |
| 703 | sliderID == 'length_penalty_textgenerationwebui' || | 707 | sliderID == 'length_penalty_textgenerationwebui' || |
| 704 | sliderID == 'epsilon_cutoff_textgenerationwebui' || | 708 | sliderID == 'epsilon_cutoff_textgenerationwebui' || |
| 709 | sliderID == 'nsigma' || | ||
| 705 | sliderID == 'rep_pen_range' || | 710 | sliderID == 'rep_pen_range' || |
| 706 | sliderID == 'eta_cutoff_textgenerationwebui' || | 711 | sliderID == 'eta_cutoff_textgenerationwebui' || |
| 707 | sliderID == 'top_a_textgenerationwebui' || | 712 | sliderID == 'top_a_textgenerationwebui' || |
| @@ -1,5 +1,4 @@ | |||
| 1 | import { escapeRegex } from '../utils.js'; | 1 | import { escapeRegex } from '../utils.js'; |
| 2 | import { SlashCommand } from './SlashCommand.js'; | ||
| 3 | import { SlashCommandParser } from './SlashCommandParser.js'; | 2 | import { SlashCommandParser } from './SlashCommandParser.js'; |
| 4 | 3 | ||
| 5 | export class SlashCommandBrowser { | 4 | export class SlashCommandBrowser { |
| @@ -30,7 +29,7 @@ export class SlashCommandBrowser { | |||
| 30 | this.details?.remove(); | 29 | this.details?.remove(); |
| 31 | this.details = null; | 30 | this.details = null; |
| 32 | let query = inp.value.trim(); | 31 | let query = inp.value.trim(); |
| 33 | if (query.slice(-1) == '"' && !/(?:^|\s+)"/.test(query)) { | 32 | if (query.slice(-1) === '"' && !/(?:^|\s+)"/.test(query)) { |
| 34 | query = `"${query}`; | 33 | query = `"${query}`; |
| 35 | } | 34 | } |
| 36 | let fuzzyList = []; | 35 | let fuzzyList = []; |
| @@ -59,7 +58,7 @@ export class SlashCommandBrowser { | |||
| 59 | cmd.helpString, | 58 | cmd.helpString, |
| 60 | ]; | 59 | ]; |
| 61 | const find = ()=>targets.find(t=>(fuzzyList.find(f=>f.test(t)) ?? quotedList.find(q=>t.includes(q))) !== undefined) !== undefined; | 60 | const find = ()=>targets.find(t=>(fuzzyList.find(f=>f.test(t)) ?? quotedList.find(q=>t.includes(q))) !== undefined) !== undefined; |
| 62 | if (fuzzyList.length + quotedList.length == 0 || find()) { | 61 | if (fuzzyList.length + quotedList.length === 0 || find()) { |
| 63 | this.itemMap[cmd.name].classList.remove('isFiltered'); | 62 | this.itemMap[cmd.name].classList.remove('isFiltered'); |
| 64 | } else { | 63 | } else { |
| 65 | this.itemMap[cmd.name].classList.add('isFiltered'); | 64 | this.itemMap[cmd.name].classList.add('isFiltered'); |
| @@ -78,7 +77,7 @@ export class SlashCommandBrowser { | |||
| 78 | list.classList.add('autoComplete'); | 77 | list.classList.add('autoComplete'); |
| 79 | this.cmdList = Object | 78 | this.cmdList = Object |
| 80 | .keys(SlashCommandParser.commands) | 79 | .keys(SlashCommandParser.commands) |
| 81 | .filter(key => SlashCommandParser.commands[key].name == key) // exclude aliases | 80 | .filter(key => SlashCommandParser.commands[key].name === key) // exclude aliases |
| 82 | .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())) | 81 | .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase())) |
| 83 | .map(key => SlashCommandParser.commands[key]) | 82 | .map(key => SlashCommandParser.commands[key]) |
| 84 | ; | 83 | ; |
| @@ -97,7 +96,7 @@ export class SlashCommandBrowser { | |||
| 97 | } | 96 | } |
| 98 | } | 97 | } |
| 99 | } | 98 | } |
| 100 | if (this.details != details) { | 99 | if (this.details !== details) { |
| 101 | Array.from(list.querySelectorAll('.selected')).forEach(it=>it.classList.remove('selected')); | 100 | Array.from(list.querySelectorAll('.selected')).forEach(it=>it.classList.remove('selected')); |
| 102 | item.classList.add('selected'); | 101 | item.classList.add('selected'); |
| 103 | this.details?.remove(); | 102 | this.details?.remove(); |
| @@ -124,7 +123,7 @@ export class SlashCommandBrowser { | |||
| 124 | parent.append(this.dom); | 123 | parent.append(this.dom); |
| 125 | 124 | ||
| 126 | this.mo = new MutationObserver(muts=>{ | 125 | this.mo = new MutationObserver(muts=>{ |
| 127 | if (muts.find(mut=>Array.from(mut.removedNodes).find(it=>it == this.dom || it.contains(this.dom)))) { | 126 | if (muts.find(mut=>Array.from(mut.removedNodes).find(it=>it === this.dom || it.contains(this.dom)))) { |
| 128 | this.mo.disconnect(); | 127 | this.mo.disconnect(); |
| 129 | window.removeEventListener('keydown', boundHandler); | 128 | window.removeEventListener('keydown', boundHandler); |
| 130 | } | 129 | } |
| @@ -136,7 +135,7 @@ export class SlashCommandBrowser { | |||
| 136 | } | 135 | } |
| 137 | 136 | ||
| 138 | handleKeyDown(evt) { | 137 | handleKeyDown(evt) { |
| 139 | if (!evt.shiftKey && !evt.altKey && evt.ctrlKey && evt.key.toLowerCase() == 'f') { | 138 | if (!evt.shiftKey && !evt.altKey && evt.ctrlKey && evt.key.toLowerCase() === 'f') { |
| 140 | if (!this.dom.closest('body')) return; | 139 | if (!this.dom.closest('body')) return; |
| 141 | if (this.dom.closest('.mes') && !this.dom.closest('.last_mes')) return; | 140 | if (this.dom.closest('.mes') && !this.dom.closest('.last_mes')) return; |
| 142 | evt.preventDefault(); | 141 | evt.preventDefault(); |
| @@ -193,6 +193,7 @@ const settings = { | |||
| 193 | openrouter_allow_fallbacks: true, | 193 | openrouter_allow_fallbacks: true, |
| 194 | xtc_threshold: 0.1, | 194 | xtc_threshold: 0.1, |
| 195 | xtc_probability: 0, | 195 | xtc_probability: 0, |
| 196 | nsigma: 0.0, | ||
| 196 | featherless_model: '', | 197 | featherless_model: '', |
| 197 | }; | 198 | }; |
| 198 | 199 | ||
| @@ -265,6 +266,7 @@ export const setting_names = [ | |||
| 265 | 'openrouter_allow_fallbacks', | 266 | 'openrouter_allow_fallbacks', |
| 266 | 'xtc_threshold', | 267 | 'xtc_threshold', |
| 267 | 'xtc_probability', | 268 | 'xtc_probability', |
| 269 | 'nsigma', | ||
| 268 | ]; | 270 | ]; |
| 269 | 271 | ||
| 270 | const DYNATEMP_BLOCK = document.getElementById('dynatemp_block_ooba'); | 272 | const DYNATEMP_BLOCK = document.getElementById('dynatemp_block_ooba'); |
| @@ -880,6 +882,13 @@ function setSettingByName(setting, value, trigger) { | |||
| 880 | } | 882 | } |
| 881 | } | 883 | } |
| 882 | 884 | ||
| 885 | /** | ||
| 886 | * Sends a streaming request for textgenerationwebui. | ||
| 887 | * @param generate_data | ||
| 888 | * @param signal | ||
| 889 | * @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 | ||
| 891 | */ | ||
| 883 | async function generateTextGenWithStreaming(generate_data, signal) { | 892 | async function generateTextGenWithStreaming(generate_data, signal) { |
| 884 | generate_data.stream = true; | 893 | generate_data.stream = true; |
| 885 | 894 | ||
| @@ -995,6 +1004,7 @@ export function parseTabbyLogprobs(data) { | |||
| 995 | * @param {Response} response - Response from the server. | 1004 | * @param {Response} response - Response from the server. |
| 996 | * @param {string} decoded - Decoded response body. | 1005 | * @param {string} decoded - Decoded response body. |
| 997 | * @returns {void} Nothing. | 1006 | * @returns {void} Nothing. |
| 1007 | * @throws {Error} If the response contains an error message, throws Error with the message. | ||
| 998 | */ | 1008 | */ |
| 999 | function tryParseStreamingError(response, decoded) { | 1009 | function tryParseStreamingError(response, decoded) { |
| 1000 | let data = {}; | 1010 | let data = {}; |
| @@ -1178,6 +1188,7 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, | |||
| 1178 | 'sampler_order': settings.type === textgen_types.KOBOLDCPP ? settings.sampler_order : undefined, | 1188 | 'sampler_order': settings.type === textgen_types.KOBOLDCPP ? settings.sampler_order : undefined, |
| 1179 | 'xtc_threshold': settings.xtc_threshold, | 1189 | 'xtc_threshold': settings.xtc_threshold, |
| 1180 | 'xtc_probability': settings.xtc_probability, | 1190 | 'xtc_probability': settings.xtc_probability, |
| 1191 | 'nsigma': settings.nsigma, | ||
| 1181 | }; | 1192 | }; |
| 1182 | const nonAphroditeParams = { | 1193 | const nonAphroditeParams = { |
| 1183 | 'rep_pen': settings.rep_pen, | 1194 | 'rep_pen': settings.rep_pen, |
| @@ -1245,7 +1256,9 @@ export function getTextGenGenerationData(finalPrompt, maxTokens, isImpersonate, | |||
| 1245 | 'dynatemp_exponent': dynatemp ? settings.dynatemp_exponent : undefined, | 1256 | 'dynatemp_exponent': dynatemp ? settings.dynatemp_exponent : undefined, |
| 1246 | 'xtc_threshold': settings.xtc_threshold, | 1257 | 'xtc_threshold': settings.xtc_threshold, |
| 1247 | 'xtc_probability': settings.xtc_probability, | 1258 | 'xtc_probability': settings.xtc_probability, |
| 1259 | 'nsigma': settings.nsigma, | ||
| 1248 | 'custom_token_bans': toIntArray(banned_tokens), | 1260 | 'custom_token_bans': toIntArray(banned_tokens), |
| 1261 | 'no_repeat_ngram_size': settings.no_repeat_ngram_size, | ||
| 1249 | }; | 1262 | }; |
| 1250 | 1263 | ||
| 1251 | if (settings.type === OPENROUTER) { | 1264 | if (settings.type === OPENROUTER) { |
| @@ -102,7 +102,7 @@ async function sendClaudeRequest(request, response) { | |||
| 102 | const additionalHeaders = {}; | 102 | const additionalHeaders = {}; |
| 103 | const useTools = request.body.model.startsWith('claude-3') && Array.isArray(request.body.tools) && request.body.tools.length > 0; | 103 | const useTools = request.body.model.startsWith('claude-3') && Array.isArray(request.body.tools) && request.body.tools.length > 0; |
| 104 | const useSystemPrompt = (request.body.model.startsWith('claude-2') || request.body.model.startsWith('claude-3')) && request.body.claude_use_sysprompt; | 104 | const useSystemPrompt = (request.body.model.startsWith('claude-2') || request.body.model.startsWith('claude-3')) && request.body.claude_use_sysprompt; |
| 105 | const convertedPrompt = convertClaudeMessages(request.body.messages, request.body.assistant_prefill, useSystemPrompt, useTools, request.body.human_sysprompt_message, request.body.char_name, request.body.user_name); | 105 | const convertedPrompt = convertClaudeMessages(request.body.messages, request.body.assistant_prefill, useSystemPrompt, useTools, request.body.char_name, request.body.user_name); |
| 106 | // Add custom stop sequences | 106 | // Add custom stop sequences |
| 107 | const stopSequences = []; | 107 | const stopSequences = []; |
| 108 | if (Array.isArray(request.body.stop)) { | 108 | if (Array.isArray(request.body.stop)) { |
| @@ -1051,8 +1051,12 @@ router.post('/generate', jsonParser, function (request, response) { | |||
| 1051 | } | 1051 | } |
| 1052 | } catch (error) { | 1052 | } catch (error) { |
| 1053 | console.log('Generation failed', error); | 1053 | console.log('Generation failed', error); |
| 1054 | const message = error.code === 'ECONNREFUSED' | ||
| 1055 | ? `Connection refused: ${error.message}` | ||
| 1056 | : error.message || 'Unknown error occurred'; | ||
| 1057 | |||
| 1054 | if (!response.headersSent) { | 1058 | if (!response.headersSent) { |
| 1055 | response.send({ error: true }); | 1059 | response.status(502).send({ error: { message, ...error } }); |
| 1056 | } else { | 1060 | } else { |
| 1057 | response.end(); | 1061 | response.end(); |
| 1058 | } | 1062 | } |
| @@ -1068,7 +1072,7 @@ router.post('/generate', jsonParser, function (request, response) { | |||
| 1068 | 1072 | ||
| 1069 | const message = errorResponse.statusText || 'Unknown error occurred'; | 1073 | const message = errorResponse.statusText || 'Unknown error occurred'; |
| 1070 | const quota_error = errorResponse.status === 429 && errorData?.error?.type === 'insufficient_quota'; | 1074 | const quota_error = errorResponse.status === 429 && errorData?.error?.type === 'insufficient_quota'; |
| 1071 | console.log(message, responseText); | 1075 | console.log('Chat completion request error: ', message, responseText); |
| 1072 | 1076 | ||
| 1073 | if (!response.headersSent) { | 1077 | if (!response.headersSent) { |
| 1074 | response.send({ error: { message }, quota_error: quota_error }); | 1078 | response.send({ error: { message }, quota_error: quota_error }); |
| @@ -24,6 +24,8 @@ const defaultAvatarPath = './public/img/ai4.png'; | |||
| 24 | 24 | ||
| 25 | // KV-store for parsed character data | 25 | // KV-store for parsed character data |
| 26 | const characterDataCache = new Map(); | 26 | const characterDataCache = new Map(); |
| 27 | // Some Android devices require tighter memory management | ||
| 28 | const isAndroid = process.platform === 'android'; | ||
| 27 | 29 | ||
| 28 | /** | 30 | /** |
| 29 | * Reads the character card from the specified image file. | 31 | * Reads the character card from the specified image file. |
| @@ -39,7 +41,7 @@ async function readCharacterData(inputFile, inputFormat = 'png') { | |||
| 39 | } | 41 | } |
| 40 | 42 | ||
| 41 | const result = parse(inputFile, inputFormat); | 43 | const result = parse(inputFile, inputFormat); |
| 42 | characterDataCache.set(cacheKey, result); | 44 | !isAndroid && characterDataCache.set(cacheKey, result); |
| 43 | return result; | 45 | return result; |
| 44 | } | 46 | } |
| 45 | 47 | ||
| @@ -6,7 +6,7 @@ import { publicLibConfig } from '../../webpack.config.js'; | |||
| 6 | export default function getWebpackServeMiddleware() { | 6 | export default function getWebpackServeMiddleware() { |
| 7 | const compiler = webpack(publicLibConfig); | 7 | const compiler = webpack(publicLibConfig); |
| 8 | 8 | ||
| 9 | if (process.env.NODE_ENV === 'production') { | 9 | if (process.env.NODE_ENV === 'production' || process.platform === 'android') { |
| 10 | compiler.hooks.done.tap('serve', () => { | 10 | compiler.hooks.done.tap('serve', () => { |
| 11 | if (compiler.watching) { | 11 | if (compiler.watching) { |
| 12 | compiler.watching.close(() => { }); | 12 | compiler.watching.close(() => { }); |
| @@ -91,11 +91,10 @@ export function convertClaudePrompt(messages, addAssistantPostfix, addAssistantP | |||
| 91 | * @param {string} prefillString User determined prefill string | 91 | * @param {string} prefillString User determined prefill string |
| 92 | * @param {boolean} useSysPrompt See if we want to use a system prompt | 92 | * @param {boolean} useSysPrompt See if we want to use a system prompt |
| 93 | * @param {boolean} useTools See if we want to use tools | 93 | * @param {boolean} useTools See if we want to use tools |
| 94 | * @param {string} humanMsgFix Add Human message between system prompt and assistant. | ||
| 95 | * @param {string} charName Character name | 94 | * @param {string} charName Character name |
| 96 | * @param {string} userName User name | 95 | * @param {string} userName User name |
| 97 | */ | 96 | */ |
| 98 | export function convertClaudeMessages(messages, prefillString, useSysPrompt, useTools, humanMsgFix, charName = '', userName = '') { | 97 | export function convertClaudeMessages(messages, prefillString, useSysPrompt, useTools, charName, userName) { |
| 99 | let systemPrompt = []; | 98 | let systemPrompt = []; |
| 100 | if (useSysPrompt) { | 99 | if (useSysPrompt) { |
| 101 | // Collect all the system messages up until the first instance of a non-system message, and then remove them from the messages array. | 100 | // Collect all the system messages up until the first instance of a non-system message, and then remove them from the messages array. |
| @@ -122,10 +121,10 @@ export function convertClaudeMessages(messages, prefillString, useSysPrompt, use | |||
| 122 | 121 | ||
| 123 | // Check if the first message in the array is of type user, if not, interject with humanMsgFix or a blank message. | 122 | // Check if the first message in the array is of type user, if not, interject with humanMsgFix or a blank message. |
| 124 | // Also prevents erroring out if the messages array is empty. | 123 | // Also prevents erroring out if the messages array is empty. |
| 125 | if (messages.length === 0 || (messages.length > 0 && messages[0].role !== 'user')) { | 124 | if (messages.length === 0) { |
| 126 | messages.unshift({ | 125 | messages.unshift({ |
| 127 | role: 'user', | 126 | role: 'user', |
| 128 | content: humanMsgFix || PROMPT_PLACEHOLDER, | 127 | content: PROMPT_PLACEHOLDER, |
| 129 | }); | 128 | }); |
| 130 | } | 129 | } |
| 131 | } | 130 | } |