mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "sillytavern",
|
||||
"version": "1.10.8",
|
||||
"version": "1.10.9",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "sillytavern",
|
||||
"version": "1.10.8",
|
||||
"version": "1.10.9",
|
||||
"hasInstallScript": true,
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
|
@@ -50,7 +50,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/SillyTavern/SillyTavern.git"
|
||||
},
|
||||
"version": "1.10.8",
|
||||
"version": "1.10.9",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"start-multi": "node server.js --disableCsrf",
|
||||
|
@@ -229,6 +229,10 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.flexBasis100p {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
.flexBasis50p {
|
||||
flex-basis: 50%
|
||||
}
|
||||
@@ -263,6 +267,10 @@
|
||||
flex-shrink: 1
|
||||
}
|
||||
|
||||
.flexWrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.flexnowrap {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
@@ -358,3 +358,11 @@ body.expandMessageActions .mes .mes_buttons .extraMesButtons {
|
||||
body.expandMessageActions .mes .mes_buttons .extraMesButtonsHint {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#openai_image_inlining:not(:checked) ~ #image_inlining_hint {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#openai_image_inlining:checked ~ #image_inlining_hint {
|
||||
display: block;
|
||||
}
|
||||
|
@@ -121,7 +121,7 @@
|
||||
<div id="clickSlidersTips" data-i18n="clickslidertips" class="toggle-description wide100p editable-slider-notification">
|
||||
Click slider numbers to input manually.
|
||||
</div>
|
||||
<div id="labModeWarning" class="redWarningBG textAlignCenter">MAD LAB MODE ON</div>
|
||||
<div id="labModeWarning" class="redWarningBG textAlignCenter displayNone">MAD LAB MODE ON</div>
|
||||
<a href="https://docs.sillytavern.app/usage/common-settings/" target="_blank" title="Documentation on sampling parameters.">
|
||||
<span name="samplerHelpButton" class="note-link-span topRightInset fa-solid fa-circle-question"></span>
|
||||
</a>
|
||||
@@ -213,8 +213,8 @@
|
||||
</div>
|
||||
<div id="common-gen-settings-block" class="width100p">
|
||||
<div id="pro-settings-block" class="flex-container gap10h5v justifyCenter">
|
||||
<div id="amount_gen_block" class="alignitemscenter flex-container marginBot5 flexFlowColumn flexBasis48p flexGrow flexShrink gap0" data-i18n="response legth(tokens)">
|
||||
<small>Response (tokens)</small>
|
||||
<div id="amount_gen_block" class="alignitemscenter flex-container marginBot5 flexFlowColumn flexBasis48p flexGrow flexShrink gap0">
|
||||
<small data-i18n="response legth(tokens)">Response (tokens)</small>
|
||||
<input class="neo-range-slider" type="range" id="amount_gen" name="volume" min="16" max="1024" step="1">
|
||||
<div data-randomization-disabled="true" class="wide100p">
|
||||
<input class="neo-range-input" type="number" min="16" max="1024" step="1" data-for="amount_gen" id="amount_gen_counter">
|
||||
@@ -236,8 +236,8 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div id="max_context_block" class="alignitemscenter flex-container marginBot5 flexFlowColumn flexBasis48p flexGrow flexShrink gap0" data-i18n="context size(tokens)">
|
||||
<small>Context (tokens)</small>
|
||||
<div id="max_context_block" class="alignitemscenter flex-container marginBot5 flexFlowColumn flexBasis48p flexGrow flexShrink gap0">
|
||||
<small data-i18n="context size(tokens)">Context (tokens)</small>
|
||||
<input class="neo-range-slider" type="range" id="max_context" name="volume" min="512" max="8192" step="64">
|
||||
<div data-randomization-disabled="true" class="wide100p">
|
||||
<input class="neo-range-input" type="number" min="512" max="8192" step="64" data-for="max_context" id="max_context_counter">
|
||||
@@ -245,7 +245,7 @@
|
||||
<div class="flex-container alignitemscenter justifyCenter marginTop5" id="max_context_unlocked_block">
|
||||
<label class="checkbox_label">
|
||||
<input id="max_context_unlocked" type="checkbox" />
|
||||
<small data-i18n="unlocked">Unlocked
|
||||
<small><span data-i18n="unlocked">Unlocked</span>
|
||||
<div id="max_context_unlocked_warning" class="fa-solid fa-circle-info opacity50p " title="Only select models support context sizes greater than 4096 tokens. Increase only if you know what you're doing."></div>
|
||||
</small>
|
||||
</label>
|
||||
@@ -735,12 +735,12 @@
|
||||
<input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_p" id="top_p_counter">
|
||||
</div>
|
||||
<div data-newbie-hidden class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0">
|
||||
<small data-i18n="Typical Sampling">
|
||||
Typical Sampling
|
||||
<div class="fa-solid fa-circle-info opacity50p" title="Typical Sampling prioritizes tokens based on their deviation from the average entropy of the set. It maintains tokens whose cumulative probability is close to a predefined threshold (e.g., 0.5), emphasizing those with average information content. Set to 1.0 to disable."></div>
|
||||
<small data-i18n="Typical P">
|
||||
Typical P
|
||||
<div class="fa-solid fa-circle-info opacity50p" title="Typical P Sampling prioritizes tokens based on their deviation from the average entropy of the set. It maintains tokens whose cumulative probability is close to a predefined threshold (e.g., 0.5), emphasizing those with average information content. Set to 1.0 to disable."></div>
|
||||
</small>
|
||||
<input class="neo-range-slider" type="range" id="typical" name="volume" min="0" max="1" step="0.001">
|
||||
<input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="typical" id="typical_counter">
|
||||
<input class="neo-range-slider" type="range" id="typical_p" name="volume" min="0" max="1" step="0.001">
|
||||
<input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="typical_p" id="typical_p_counter">
|
||||
</div>
|
||||
<div data-newbie-hidden class="alignitemscenter flex-container flexFlowColumn flexBasis48p flexGrow flexShrink gap0">
|
||||
<small data-i18n="Min P">
|
||||
@@ -867,7 +867,7 @@
|
||||
<small>3</small>
|
||||
</div>
|
||||
<div data-id="4">
|
||||
<span data-i18n="Typical Sampling">Typical P Sampling</span>
|
||||
<span data-i18n="Typical P">Typical P</span>
|
||||
<small>4</small>
|
||||
</div>
|
||||
<div data-id="5">
|
||||
@@ -1077,7 +1077,7 @@
|
||||
<div class="toggle_button right_menu_button"></div>
|
||||
</div>
|
||||
<div data-id="5">
|
||||
<span data-i18n="Typical Sampling">Typical Sampling</span>
|
||||
<span data-i18n="Typical P">Typical P</span>
|
||||
<small>5</small>
|
||||
<div class="toggle_button right_menu_button"></div>
|
||||
</div>
|
||||
@@ -1723,6 +1723,7 @@
|
||||
</optgroup>
|
||||
<optgroup label="GPT-4">
|
||||
<option value="gpt-4">gpt-4</option>
|
||||
<option value="gpt-4-vision-preview">gpt-4-vision-preview</option>
|
||||
<option value="gpt-4-1106-preview">gpt-4-1106-preview</option>
|
||||
<option value="gpt-4-0613">gpt-4-0613</option>
|
||||
<option value="gpt-4-0314">gpt-4-0314</option>
|
||||
@@ -1741,10 +1742,25 @@
|
||||
<optgroup id="openai_external_category" label="External">
|
||||
</optgroup>
|
||||
</select>
|
||||
<label for="openai_bypass_status_check" class="checkbox_label">
|
||||
<input id="openai_bypass_status_check" type="checkbox" />
|
||||
<span data-i18n="Bypass API status check">Bypass API status check</span>
|
||||
</label>
|
||||
<label for="openai_show_external_models" class="checkbox_label">
|
||||
<input id="openai_show_external_models" type="checkbox" />
|
||||
<span data-i18n="Show External models (provided by API)">Show "External" models (provided by API)</span>
|
||||
</label>
|
||||
<label for="openai_image_inlining" class="checkbox_label flexWrap">
|
||||
<input id="openai_image_inlining" type="checkbox" />
|
||||
<span data-i18n="Send inline images">Send inline images (only GPT-4V model)</span>
|
||||
<div id="image_inlining_hint" class="flexBasis100p">
|
||||
<small>
|
||||
Natively replaces captioning if the model supports it.<br>
|
||||
Use the <code><i class="fa-solid fa-image"></i></code> action on any message or the
|
||||
<code><i class="fa-solid fa-wand-magic-sparkles"></i></code> menu to attach an image to the chat.
|
||||
</small>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
<form id="claude_form" data-source="claude" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||
@@ -1815,6 +1831,36 @@
|
||||
<option data-i18n="Connect to the API">-- Connect to the API --</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="marginTopBot5">
|
||||
<div class="inline-drawer wide100p">
|
||||
<div class="inline-drawer-toggle inline-drawer-header">
|
||||
<b data-i18n="Model Order">OpenRouter Model Sorting</b>
|
||||
<div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
||||
</div>
|
||||
<div class="inline-drawer-content m-b-1">
|
||||
<div class="marginTopBot5">
|
||||
<label for="openrouter_sort_models" class="checkbox_label">
|
||||
<select id="openrouter_sort_models">
|
||||
<option data-i18n="Alphabetically" value="alphabetically">Alphabetically</option>
|
||||
<option data-i18n="Price" value="pricing.prompt">Price (cheapest)</option>
|
||||
<option data-i18n="Context Size" value="context_length">Context Size</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="marginTopBot5">
|
||||
<label for="openrouter_group_models" class="checkbox_label">
|
||||
<input id="openrouter_group_models" type="checkbox"/>
|
||||
<span data-i18n="Group by vendors">Group by vendors</span>
|
||||
</label>
|
||||
<div class="toggle-description justifyLeft wide100p">
|
||||
<span data-i18n="Group by vendors Description">
|
||||
Put OpenAI models in one group, Anthropic models in other group, etc. Can be combined with sorting.
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="marginTopBot5">
|
||||
<label for="openrouter_use_fallback" class="checkbox_label">
|
||||
<input id="openrouter_use_fallback" type="checkbox" />
|
||||
@@ -1916,7 +1962,7 @@
|
||||
<select id="model_palm_select" class="displayNone"></select>
|
||||
</form>
|
||||
<div class="flex-container flex">
|
||||
<div id="api_button_openai" class="menu_button menu_button_icon" type="submit" data-i18n="Connect">Connect</div>
|
||||
<div id="api_button_openai" class="api_button menu_button menu_button_icon" type="submit" data-i18n="Connect">Connect</div>
|
||||
<div class="api_loading menu_button" data-i18n="Cancel">Cancel</div>
|
||||
<div data-source="openrouter" id="openrouter_authorize" class="menu_button menu_button_icon" title="Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai" data-i18n="[title]Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai">Authorize</div>
|
||||
<div id="test_api_button" class="menu_button menu_button_icon" title="Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!" data-i18n="[title]Verifies your API connection by sending a short test message. Be aware that you'll be credited for it!">Test Message</div>
|
||||
@@ -2079,9 +2125,6 @@
|
||||
<label>
|
||||
<small data-i18n="System Prompt">System Prompt</small>
|
||||
</label>
|
||||
<div class="prompt_overridden">
|
||||
Overridden by the Character Definitions.
|
||||
</div>
|
||||
<textarea id="instruct_system_prompt" class="text_pole textarea_compact autoSetHeight" rows="1"></textarea>
|
||||
</div>
|
||||
<div data-newbie-hidden class="inline-drawer wide100p flexFlowColumn">
|
||||
@@ -2502,6 +2545,7 @@
|
||||
<input type="search" class="text_pole textarea_compact" data-i18n="[placeholder]Search..." id="world_info_search" placeholder="Search...">
|
||||
<select id="world_info_sort_order" class="margin0">
|
||||
<option data-rule="priority" value="0">Priority</option>
|
||||
<option data-rule="custom" value="13">Custom</option>
|
||||
<option data-order="asc" data-field="comment" value="1">Title A-Z</option>
|
||||
<option data-order="desc" data-field="comment" value="2">Title Z-A</option>
|
||||
<option data-order="asc" data-field="content" data-rule="length" value="3">Tokens ↗</option>
|
||||
@@ -2680,7 +2724,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div name="UserSettingsSecondColumn" id="UI-Customization" class="flex-container flexFlowColumn wide100p">
|
||||
<div name="UserSettingsSecondColumn" id="UI-Customization" class="flex-container flexFlowColumn wide100p flexNoGap">
|
||||
<div name="themeToggles">
|
||||
<h4 data-i18n="Theme Toggles">Theme Toggles</h4>
|
||||
<label data-newbie-hidden for="fast_ui_mode" class="checkbox_label" title="removes blur from window backgrounds" data-i18n="[title]removes blur from window backgrounds">
|
||||
@@ -2737,6 +2781,13 @@
|
||||
</label>
|
||||
</div>
|
||||
<h4><span data-i18n="Miscellaneous">Miscellaneous</span></h4>
|
||||
<div title="If set in the advanced character definitions, this field will be displayed in the characters list.">
|
||||
<label for="aux_field" data-i18n="Aux List Field">Aux List Field</label>
|
||||
<select id="aux_field">
|
||||
<option data-i18n="Character Version" value="character_version">Character Version</option>
|
||||
<option data-i18n="Created by" value="creator">Created by</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="play_message_sound" class="checkbox_label">
|
||||
<input id="play_message_sound" type="checkbox" />
|
||||
@@ -3752,7 +3803,7 @@
|
||||
<form class="world_entry_form wi-card-entry">
|
||||
<div class="inline-drawer wide100p">
|
||||
<div class="inline-drawer-toggle inline-drawer-header gap5px padding0">
|
||||
<!-- <span class="drag-handle">☰</span> -->
|
||||
<span class="drag-handle">☰</span>
|
||||
<div class="gap5px world_entry_thin_controls wide100p alignitemscenter">
|
||||
<div class="fa-fw fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
|
||||
<span class="flex-container alignitemscenter wide100p">
|
||||
@@ -3854,7 +3905,7 @@
|
||||
</span>
|
||||
</small>
|
||||
</label>
|
||||
<textarea class="text_pole" name="content" rows="4" data-i18n="[placeholder]What this keyword should mean to the AI, sent verbatim" placeholder="What this keyword should mean to the AI, sent verbatim"></textarea>
|
||||
<textarea class="text_pole" name="content" rows="8" data-i18n="[placeholder]What this keyword should mean to the AI, sent verbatim" placeholder="What this keyword should mean to the AI, sent verbatim"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="world_entry_thin_controls commentContainer">
|
||||
@@ -4049,6 +4100,7 @@
|
||||
<div title="Prompt" class="mes_prompt fa-solid fa-square-poll-horizontal " data-i18n="[title]Prompt"></div>
|
||||
<div title="Exclude message from prompts" class="mes_hide fa-solid fa-eye" data-i18n="[title]Exclude message from prompts"></div>
|
||||
<div title="Include message in prompts" class="mes_unhide fa-solid fa-eye-slash" data-i18n="[title]Include message in prompts"></div>
|
||||
<div title="Embed image" class="mes_embed fa-solid fa-image" data-i18n="[title]Embed image"></div>
|
||||
<div title="Create bookmark" class="mes_create_bookmark fa-regular fa-solid fa-book-bookmark" data-i18n="[title]Create Bookmark"></div>
|
||||
<div title="Create branch" class="mes_create_branch fa-regular fa-code-branch" data-i18n="[title]Create Branch"></div>
|
||||
<div title="Copy" class="mes_copy fa-solid fa-copy " data-i18n="[title]Copy"></div>
|
||||
|
104
public/script.js
104
public/script.js
@@ -143,6 +143,7 @@ import {
|
||||
escapeRegex,
|
||||
resetScrollHeight,
|
||||
onlyUnique,
|
||||
getBase64Async,
|
||||
} from "./scripts/utils.js";
|
||||
|
||||
import { ModuleWorkerWrapper, doDailyExtensionUpdatesCheck, extension_settings, getContext, loadExtensionSettings, processExtensionHelpers, registerExtensionHelper, renderExtensionTemplate, runGenerationInterceptors, saveMetadataDebounced } from "./scripts/extensions.js";
|
||||
@@ -184,7 +185,7 @@ import {
|
||||
} from "./scripts/instruct-mode.js";
|
||||
import { applyLocale } from "./scripts/i18n.js";
|
||||
import { getFriendlyTokenizerName, getTokenCount, getTokenizerModel, initTokenizers, saveTokenCache } from "./scripts/tokenizers.js";
|
||||
import { initPersonas, selectCurrentPersona, setPersonaDescription } from "./scripts/personas.js";
|
||||
import { createPersona, initPersonas, selectCurrentPersona, setPersonaDescription } from "./scripts/personas.js";
|
||||
import { getBackgrounds, initBackgrounds } from "./scripts/backgrounds.js";
|
||||
import { hideLoader, showLoader } from "./scripts/loader.js";
|
||||
import { CharacterContextMenu, BulkEditOverlay } from "./scripts/BulkEditOverlay.js";
|
||||
@@ -313,11 +314,6 @@ export const event_types = {
|
||||
|
||||
export const eventSource = new EventEmitter();
|
||||
|
||||
// Check for override warnings every 5 seconds...
|
||||
setInterval(displayOverrideWarnings, 5000);
|
||||
// ...or when the chat changes
|
||||
eventSource.on(event_types.SETTINGS_LOADED, () => { settingsReady = true; });
|
||||
eventSource.on(event_types.CHAT_CHANGED, displayOverrideWarnings);
|
||||
eventSource.on(event_types.MESSAGE_RECEIVED, processExtensionHelpers);
|
||||
eventSource.on(event_types.MESSAGE_SENT, processExtensionHelpers);
|
||||
|
||||
@@ -729,7 +725,7 @@ async function firstLoadInit() {
|
||||
sendSystemMessage(system_message_types.WELCOME);
|
||||
await readSecretState();
|
||||
await getClientVersion();
|
||||
await getSettings("def");
|
||||
await getSettings();
|
||||
await getUserAvatars();
|
||||
await getCharacters();
|
||||
await getBackgrounds();
|
||||
@@ -926,12 +922,12 @@ async function getStatus() {
|
||||
|
||||
export function startStatusLoading() {
|
||||
$(".api_loading").show();
|
||||
$(".api_button").attr("disabled", "disabled").addClass("disabled");
|
||||
$(".api_button").addClass("disabled");
|
||||
}
|
||||
|
||||
export function stopStatusLoading() {
|
||||
$(".api_loading").hide();
|
||||
$(".api_button").removeAttr("disabled").removeClass("disabled");
|
||||
$(".api_button").removeClass("disabled");
|
||||
}
|
||||
|
||||
export function resultCheckStatus() {
|
||||
@@ -1014,7 +1010,7 @@ function getBackBlock() {
|
||||
function getEmptyBlock() {
|
||||
const icons = ['fa-dragon', 'fa-otter', 'fa-kiwi-bird', 'fa-crow', 'fa-frog'];
|
||||
const texts = ['Here be dragons', 'Otterly empty', 'Kiwibunga', 'Pump-a-Rum', 'Croak it'];
|
||||
const roll = Math.floor(Math.random() * icons.length);
|
||||
const roll = new Date().getMinutes() % icons.length;
|
||||
const emptyBlock = `
|
||||
<div class="empty_block">
|
||||
<i class="fa-solid ${icons[roll]} fa-4x"></i>
|
||||
@@ -1050,9 +1046,10 @@ function getCharacterBlock(item, id) {
|
||||
template.find('.ch_description').hide();
|
||||
}
|
||||
|
||||
const version = item.data?.character_version || '';
|
||||
if (version) {
|
||||
template.find('.character_version').text(version);
|
||||
const auxFieldName = power_user.aux_field || 'character_version';
|
||||
const auxFieldValue = (item.data && item.data[auxFieldName]) || '';
|
||||
if (auxFieldValue) {
|
||||
template.find('.character_version').text(auxFieldValue);
|
||||
}
|
||||
else {
|
||||
template.find('.character_version').hide();
|
||||
@@ -1079,7 +1076,6 @@ async function printCharacters(fullRefresh = false) {
|
||||
}
|
||||
|
||||
await delay(1);
|
||||
displayOverrideWarnings();
|
||||
}
|
||||
|
||||
const storageKey = 'Characters_PerPage';
|
||||
@@ -3408,7 +3404,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
|
||||
generate_data = getNovelGenerationData(finalPrompt, presetSettings, maxLength, isImpersonate, cfgValues);
|
||||
}
|
||||
else if (main_api == 'openai') {
|
||||
let [prompt, counts] = prepareOpenAIMessages({
|
||||
let [prompt, counts] = await prepareOpenAIMessages({
|
||||
name2: name2,
|
||||
charDescription: description,
|
||||
charPersonality: personality,
|
||||
@@ -4784,22 +4780,21 @@ async function read_avatar_load(input) {
|
||||
create_save.avatar = input.files;
|
||||
}
|
||||
|
||||
const e = await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = resolve;
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(input.files[0]);
|
||||
})
|
||||
const file = input.files[0];
|
||||
const fileData = await getBase64Async(file);
|
||||
|
||||
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
|
||||
if (!power_user.never_resize_avatars) {
|
||||
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
|
||||
const croppedImage = await callPopup(getCropPopup(fileData), 'avatarToCrop');
|
||||
if (!croppedImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const croppedImage = await callPopup(getCropPopup(e.target.result), 'avatarToCrop');
|
||||
if (!croppedImage) {
|
||||
return;
|
||||
$("#avatar_load_preview").attr("src", croppedImage);
|
||||
} else {
|
||||
$("#avatar_load_preview").attr("src", fileData);
|
||||
}
|
||||
|
||||
$("#avatar_load_preview").attr("src", croppedImage || e.target.result);
|
||||
|
||||
if (menu_type == "create") {
|
||||
return;
|
||||
}
|
||||
@@ -5161,24 +5156,19 @@ async function uploadUserAvatar(e) {
|
||||
}
|
||||
|
||||
const formData = new FormData($("#form_upload_avatar").get(0));
|
||||
|
||||
const dataUrl = await new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = resolve;
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
|
||||
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
|
||||
const confirmation = await callPopup(getCropPopup(dataUrl.target.result), 'avatarToCrop');
|
||||
if (!confirmation) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dataUrl = await getBase64Async(file);
|
||||
let url = "/uploaduseravatar";
|
||||
|
||||
if (crop_data !== undefined) {
|
||||
url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`;
|
||||
if (!power_user.never_resize_avatars) {
|
||||
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
|
||||
const confirmation = await callPopup(getCropPopup(dataUrl), 'avatarToCrop');
|
||||
if (!confirmation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (crop_data !== undefined) {
|
||||
url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`;
|
||||
}
|
||||
}
|
||||
|
||||
jQuery.ajax({
|
||||
@@ -5189,7 +5179,7 @@ async function uploadUserAvatar(e) {
|
||||
cache: false,
|
||||
contentType: false,
|
||||
processData: false,
|
||||
success: async function () {
|
||||
success: async function (data) {
|
||||
// If the user uploaded a new avatar, we want to make sure it's not cached
|
||||
const name = formData.get("overwrite_name");
|
||||
if (name) {
|
||||
@@ -5197,6 +5187,12 @@ async function uploadUserAvatar(e) {
|
||||
reloadUserAvatar(true);
|
||||
}
|
||||
|
||||
if (data.path) {
|
||||
await getUserAvatars();
|
||||
await delay(500);
|
||||
await createPersona(data.path);
|
||||
}
|
||||
|
||||
crop_data = undefined;
|
||||
await getUserAvatars();
|
||||
},
|
||||
@@ -5234,7 +5230,7 @@ async function doOnboarding(avatarId) {
|
||||
|
||||
//***************SETTINGS****************//
|
||||
///////////////////////////////////////////
|
||||
async function getSettings(type) {
|
||||
async function getSettings() {
|
||||
const response = await fetch("/getsettings", {
|
||||
method: "POST",
|
||||
headers: getRequestHeaders(),
|
||||
@@ -5407,6 +5403,7 @@ async function getSettings(type) {
|
||||
}
|
||||
}
|
||||
|
||||
settingsReady = true;
|
||||
eventSource.emit(event_types.SETTINGS_LOADED);
|
||||
}
|
||||
|
||||
@@ -7131,19 +7128,6 @@ const swipe_right = () => {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function displayOverrideWarnings() {
|
||||
if (!this_chid || !selected_group) {
|
||||
$('.prompt_overridden').hide();
|
||||
$('.jailbreak_overridden').hide();
|
||||
return;
|
||||
}
|
||||
|
||||
$('.prompt_overridden').toggle(!!(characters[this_chid]?.data?.system_prompt));
|
||||
$('.jailbreak_overridden').toggle(!!(characters[this_chid]?.data?.post_history_instructions));
|
||||
}
|
||||
|
||||
function connectAPISlash(_, text) {
|
||||
if (!text) return;
|
||||
|
||||
@@ -8694,7 +8678,7 @@ jQuery(async function () {
|
||||
|
||||
startStatusLoading();
|
||||
// Check near immediately rather than waiting for up to 90s
|
||||
setTimeout(getStatusNovel, 10);
|
||||
await getStatusNovel();
|
||||
});
|
||||
|
||||
//**************************CHARACTER IMPORT EXPORT*************************//
|
||||
@@ -9130,7 +9114,7 @@ jQuery(async function () {
|
||||
|
||||
//yolo anything for Lab Mode
|
||||
if (power_user.enableLabMode) {
|
||||
console.log($(masterElement).attr('id'), myValue)
|
||||
//console.log($(masterElement).attr('id'), myValue)
|
||||
$(masterElement).val(myValue).trigger('input')
|
||||
return
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ import {
|
||||
} from "../script.js";
|
||||
|
||||
import { favsToHotswap } from "./RossAscends-mods.js";
|
||||
import { hideLoader, showLoader } from "./loader.js";
|
||||
import { convertCharacterToPersona } from "./personas.js";
|
||||
import { createTagInput, getTagKeyForCharacter, tag_map } from "./tags.js";
|
||||
|
||||
@@ -614,9 +615,12 @@ class BulkEditOverlay {
|
||||
|
||||
const deleteChats = document.getElementById('del_char_checkbox').checked ?? false;
|
||||
|
||||
showLoader();
|
||||
toastr.info("We're deleting your characters, please wait...", 'Working on it');
|
||||
Promise.all(this.selectedCharacters.map(async characterId => CharacterContextMenu.delete(characterId, deleteChats)))
|
||||
.then(() => getCharacters())
|
||||
.then(() => this.browseState())
|
||||
.finally(() => hideLoader());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@@ -1,8 +1,9 @@
|
||||
import { getBase64Async, saveBase64AsFile } from "../../utils.js";
|
||||
import { getContext, getApiUrl, doExtrasFetch, extension_settings, modules } from "../../extensions.js";
|
||||
import { callPopup, getRequestHeaders, saveSettingsDebounced, substituteParams } from "../../../script.js";
|
||||
import { appendImageToMessage, callPopup, getRequestHeaders, saveSettingsDebounced, substituteParams } from "../../../script.js";
|
||||
import { getMessageTimeStamp } from "../../RossAscends-mods.js";
|
||||
import { SECRET_KEYS, secret_state } from "../../secrets.js";
|
||||
import { isImageInliningSupported } from "../../openai.js";
|
||||
export { MODULE_NAME };
|
||||
|
||||
const MODULE_NAME = 'caption';
|
||||
@@ -223,6 +224,83 @@ function onRefineModeInput() {
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
async function sendEmbeddedImage(e) {
|
||||
const file = e.target.files[0];
|
||||
|
||||
if (!file || !(file instanceof File)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const context = getContext();
|
||||
const fileData = await getBase64Async(file);
|
||||
const base64Format = fileData.split(',')[0].split(';')[0].split('/')[1];
|
||||
const base64Data = fileData.split(',')[1];
|
||||
const caption = await callPopup('<h3>Enter a comment or question (optional)</h3>', 'input', 'What is this?', { okButton: 'Send', rows: 2 });
|
||||
const imagePath = await saveBase64AsFile(base64Data, context.name2, '', base64Format);
|
||||
const message = {
|
||||
name: context.name1,
|
||||
is_user: true,
|
||||
send_date: getMessageTimeStamp(),
|
||||
mes: caption || `[${context.name1} sends ${context.name2} a picture]`,
|
||||
extra: {
|
||||
image: imagePath,
|
||||
inline_image: !!caption,
|
||||
title: caption || '',
|
||||
},
|
||||
};
|
||||
context.chat.push(message);
|
||||
context.addOneMessage(message);
|
||||
await context.generate('caption');
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
finally {
|
||||
e.target.form.reset();
|
||||
setImageIcon();
|
||||
}
|
||||
}
|
||||
|
||||
function onImageEmbedClicked() {
|
||||
const context = getContext();
|
||||
const messageElement = $(this).closest('.mes');
|
||||
const messageId = messageElement.attr('mesid');
|
||||
const message = context.chat[messageId];
|
||||
|
||||
if (!message) {
|
||||
console.warn('Failed to find message with id', messageId);
|
||||
return;
|
||||
}
|
||||
|
||||
$('#embed_img_file')
|
||||
.off('change')
|
||||
.on('change', parseAndUploadEmbed)
|
||||
.trigger('click');
|
||||
|
||||
async function parseAndUploadEmbed(e) {
|
||||
const file = e.target.files[0];
|
||||
|
||||
if (!file || !(file instanceof File)) {
|
||||
return;
|
||||
}
|
||||
const fileData = await getBase64Async(file);
|
||||
const base64Data = fileData.split(',')[1];
|
||||
const base64Format = fileData.split(',')[0].split(';')[0].split('/')[1];
|
||||
const imagePath = await saveBase64AsFile(base64Data, context.name2, '', base64Format);
|
||||
|
||||
if (!message.extra) {
|
||||
message.extra = {};
|
||||
}
|
||||
|
||||
message.extra.image = imagePath;
|
||||
message.extra.inline_image = true;
|
||||
message.extra.title = '';
|
||||
appendImageToMessage(message, messageElement);
|
||||
await context.saveChat();
|
||||
}
|
||||
}
|
||||
|
||||
jQuery(function () {
|
||||
function addSendPictureButton() {
|
||||
const sendButton = $(`
|
||||
@@ -234,6 +312,12 @@ jQuery(function () {
|
||||
$('#extensionsMenu').prepend(sendButton);
|
||||
$(sendButton).hide();
|
||||
$(sendButton).on('click', () => {
|
||||
if (isImageInliningSupported()) {
|
||||
console.log('Native image inlining is supported. Skipping captioning.');
|
||||
$('#embed_img_file').off('change').on('change', sendEmbeddedImage).trigger('click');
|
||||
return;
|
||||
}
|
||||
|
||||
const hasCaptionModule =
|
||||
(modules.includes('caption') && extension_settings.caption.source === 'extras') ||
|
||||
(extension_settings.caption.source === 'openai' && secret_state[SECRET_KEYS.OPENAI]) ||
|
||||
@@ -249,10 +333,12 @@ jQuery(function () {
|
||||
});
|
||||
}
|
||||
function addPictureSendForm() {
|
||||
const inputHtml = `<input id="img_file" type="file" accept="image/*">`;
|
||||
const inputHtml = `<input id="img_file" type="file" hidden accept="image/*">`;
|
||||
const embedInputHtml = `<input id="embed_img_file" type="file" hidden accept="image/*">`;
|
||||
const imgForm = document.createElement('form');
|
||||
imgForm.id = 'img_form';
|
||||
$(imgForm).append(inputHtml);
|
||||
$(imgForm).append(embedInputHtml);
|
||||
$(imgForm).hide();
|
||||
$('#form_sheld').append(imgForm);
|
||||
$('#img_file').on('change', onSelectImage);
|
||||
@@ -312,5 +398,6 @@ jQuery(function () {
|
||||
extension_settings.caption.template = String($('#caption_template').val());
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
$(document).on('click', '.mes_embed', onImageEmbedClicked);
|
||||
setInterval(moduleWorker, UPDATE_INTERVAL);
|
||||
});
|
||||
|
@@ -21,7 +21,7 @@ const defaultSettings = {
|
||||
|
||||
//method from worldinfo
|
||||
async function updateQuickReplyPresetList() {
|
||||
var result = await fetch("/getsettings", {
|
||||
const result = await fetch("/getsettings", {
|
||||
method: "POST",
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({}),
|
||||
|
@@ -71,7 +71,7 @@ const triggerWords = {
|
||||
}
|
||||
|
||||
const messageTrigger = {
|
||||
activationRegex: /\b(send|mail|imagine|generate|make|create|draw|paint|render)\b.*\b(pic|picture|image|drawing|painting|photo|photograph)\b(?:\s+of)?(?:\s+(?:a|an|the)?)?(.+)/i,
|
||||
activationRegex: /\b(send|mail|imagine|generate|make|create|draw|paint|render)\b.*\b(pic|picture|image|drawing|painting|photo|photograph)\b(?:\s+of)?(?:\s+(?:a|an|the|this|that|those)?)?(.+)/i,
|
||||
specialCases: {
|
||||
[generationMode.CHARACTER]: ['you', 'yourself'],
|
||||
[generationMode.USER]: ['me', 'myself'],
|
||||
@@ -251,12 +251,12 @@ function processTriggers(chat, _, abort) {
|
||||
|
||||
console.log(`SD: Triggered by "${message}", detected subject: ${subject}"`);
|
||||
|
||||
for (const [specialMode, triggers] of Object.entries(messageTrigger.specialCases)) {
|
||||
outer: for (const [specialMode, triggers] of Object.entries(messageTrigger.specialCases)) {
|
||||
for (const trigger of triggers) {
|
||||
if (subject === trigger) {
|
||||
subject = triggerWords[specialMode][0];
|
||||
console.log(`SD: Detected special case "${trigger}", switching to mode ${specialMode}`);
|
||||
break;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -45,6 +45,8 @@ class ElevenLabsTtsProvider {
|
||||
this.settings.stability = $('#elevenlabs_tts_stability').val()
|
||||
this.settings.similarity_boost = $('#elevenlabs_tts_similarity_boost').val()
|
||||
this.settings.model = $('#elevenlabs_tts_model').find(':selected').val()
|
||||
$('#elevenlabs_tts_stability_output').text(this.settings.stability);
|
||||
$('#elevenlabs_tts_similarity_boost_output').text(this.settings.similarity_boost);
|
||||
saveTtsProviderSettings()
|
||||
}
|
||||
|
||||
@@ -79,6 +81,8 @@ class ElevenLabsTtsProvider {
|
||||
$('#elevenlabs_tts_similarity_boost').on('input', this.onSettingsChange.bind(this))
|
||||
$('#elevenlabs_tts_stability').on('input', this.onSettingsChange.bind(this))
|
||||
$('#elevenlabs_tts_model').on('change', this.onSettingsChange.bind(this))
|
||||
$('#elevenlabs_tts_stability_output').text(this.settings.stability);
|
||||
$('#elevenlabs_tts_similarity_boost_output').text(this.settings.similarity_boost);
|
||||
|
||||
try {
|
||||
await this.checkReady()
|
||||
|
@@ -9,6 +9,7 @@ import { SystemTtsProvider } from './system.js'
|
||||
import { NovelTtsProvider } from './novel.js'
|
||||
import { power_user } from '../../power-user.js'
|
||||
import { registerSlashCommand } from '../../slash-commands.js'
|
||||
import { OpenAITtsProvider } from './openai.js'
|
||||
export { talkingAnimation };
|
||||
|
||||
const UPDATE_INTERVAL = 1000
|
||||
@@ -73,6 +74,7 @@ let ttsProviders = {
|
||||
Coqui: CoquiTtsProvider,
|
||||
Edge: EdgeTtsProvider,
|
||||
Novel: NovelTtsProvider,
|
||||
OpenAI: OpenAITtsProvider,
|
||||
}
|
||||
let ttsProvider
|
||||
let ttsProviderName
|
||||
|
148
public/scripts/extensions/tts/openai.js
Normal file
148
public/scripts/extensions/tts/openai.js
Normal file
@@ -0,0 +1,148 @@
|
||||
import { getRequestHeaders } from "../../../script.js"
|
||||
import { saveTtsProviderSettings } from "./index.js";
|
||||
|
||||
export { OpenAITtsProvider }
|
||||
|
||||
class OpenAITtsProvider {
|
||||
static voices = [
|
||||
{ name: 'Alloy', voice_id: 'alloy', lang: 'en-US', preview_url: 'https://cdn.openai.com/API/docs/audio/alloy.wav' },
|
||||
{ name: 'Echo', voice_id: 'echo', lang: 'en-US', preview_url: 'https://cdn.openai.com/API/docs/audio/echo.wav' },
|
||||
{ name: 'Fable', voice_id: 'fable', lang: 'en-US', preview_url: 'https://cdn.openai.com/API/docs/audio/fable.wav' },
|
||||
{ name: 'Onyx', voice_id: 'onyx', lang: 'en-US', preview_url: 'https://cdn.openai.com/API/docs/audio/onyx.wav' },
|
||||
{ name: 'Nova', voice_id: 'nova', lang: 'en-US', preview_url: 'https://cdn.openai.com/API/docs/audio/nova.wav' },
|
||||
{ name: 'Shimmer', voice_id: 'shimmer', lang: 'en-US', preview_url: 'https://cdn.openai.com/API/docs/audio/shimmer.wav' },
|
||||
];
|
||||
|
||||
settings
|
||||
voices = []
|
||||
separator = ' . '
|
||||
audioElement = document.createElement('audio')
|
||||
|
||||
defaultSettings = {
|
||||
voiceMap: {},
|
||||
customVoices: [],
|
||||
model: 'tts-1',
|
||||
speed: 1,
|
||||
}
|
||||
|
||||
get settingsHtml() {
|
||||
let html = `
|
||||
<div>Use OpenAI's TTS engine.</div>
|
||||
<small>Hint: Save an API key in the OpenAI API settings to use it here.</small>
|
||||
<div>
|
||||
<label for="openai-tts-model">Model:</label>
|
||||
<select id="openai-tts-model">
|
||||
<optgroup label="Latest">
|
||||
<option value="tts-1">tts-1</option>
|
||||
<option value="tts-1-hd">tts-1-hd</option>
|
||||
</optgroup>
|
||||
<optgroup label="Snapshots">
|
||||
<option value="tts-1-1106">tts-1-1106</option>
|
||||
<option value="tts-1-hd-1106">tts-1-hd-1106</option>
|
||||
</optgroup>
|
||||
<select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="openai-tts-speed">Speed: <span id="openai-tts-speed-output"></span></label>
|
||||
<input type="range" id="openai-tts-speed" value="1" min="0.25" max="4" step="0.25">
|
||||
</div>`;
|
||||
return html;
|
||||
}
|
||||
|
||||
async loadSettings(settings) {
|
||||
// Populate Provider UI given input settings
|
||||
if (Object.keys(settings).length == 0) {
|
||||
console.info("Using default TTS Provider settings")
|
||||
}
|
||||
|
||||
// Only accept keys defined in defaultSettings
|
||||
this.settings = this.defaultSettings;
|
||||
|
||||
for (const key in settings) {
|
||||
if (key in this.settings) {
|
||||
this.settings[key] = settings[key];
|
||||
} else {
|
||||
throw `Invalid setting passed to TTS Provider: ${key}`;
|
||||
}
|
||||
}
|
||||
|
||||
$('#openai-tts-model').val(this.settings.model);
|
||||
$('#openai-tts-model').on('change', () => {
|
||||
this.onSettingsChange();
|
||||
});
|
||||
|
||||
$('#openai-tts-speed').val(this.settings.speed);
|
||||
$('#openai-tts-speed').on('input', () => {
|
||||
this.onSettingsChange();
|
||||
});
|
||||
|
||||
$('#openai-tts-speed-output').text(this.settings.speed);
|
||||
|
||||
await this.checkReady();
|
||||
console.debug("OpenAI TTS: Settings loaded");
|
||||
}
|
||||
|
||||
onSettingsChange() {
|
||||
// Update dynamically
|
||||
this.settings.model = String($('#openai-tts-model').find(':selected').val());
|
||||
this.settings.speed = Number($('#openai-tts-speed').val());
|
||||
$('#openai-tts-speed-output').text(this.settings.speed);
|
||||
saveTtsProviderSettings();
|
||||
}
|
||||
|
||||
async checkReady() {
|
||||
await this.fetchTtsVoiceObjects();
|
||||
}
|
||||
|
||||
async onRefreshClick() {
|
||||
return;
|
||||
}
|
||||
|
||||
async getVoice(voiceName) {
|
||||
if (!voiceName) {
|
||||
throw `TTS Voice name not provided`
|
||||
}
|
||||
|
||||
const voice = OpenAITtsProvider.voices.find(voice => voice.voice_id === voiceName || voice.name === voiceName);
|
||||
|
||||
if (!voice) {
|
||||
throw `TTS Voice not found: ${voiceName}`
|
||||
}
|
||||
|
||||
return voice;
|
||||
}
|
||||
|
||||
async generateTts(text, voiceId) {
|
||||
const response = await this.fetchTtsGeneration(text, voiceId)
|
||||
return response
|
||||
}
|
||||
|
||||
async fetchTtsVoiceObjects() {
|
||||
return OpenAITtsProvider.voices;
|
||||
}
|
||||
|
||||
async previewTtsVoice(_) {
|
||||
return;
|
||||
}
|
||||
|
||||
async fetchTtsGeneration(inputText, voiceId) {
|
||||
console.info(`Generating new TTS for voice_id ${voiceId}`)
|
||||
const response = await fetch(`/api/openai/generate-voice`, {
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
"text": inputText,
|
||||
"voice": voiceId,
|
||||
"model": this.settings.model,
|
||||
"speed": this.settings.speed,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
toastr.error(response.statusText, 'TTS Generation Failed');
|
||||
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
@@ -31,6 +31,11 @@ export const kai_settings = {
|
||||
seed: -1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Stable version of KoboldAI has a nasty payload validation.
|
||||
* It will reject any payload that has a key that is not in the whitelist.
|
||||
* @typedef {Object.<string, boolean>} kai_flags
|
||||
*/
|
||||
export const kai_flags = {
|
||||
can_use_tokenization: false,
|
||||
can_use_stop_sequence: false,
|
||||
@@ -38,6 +43,7 @@ export const kai_flags = {
|
||||
can_use_default_badwordsids: false,
|
||||
can_use_mirostat: false,
|
||||
can_use_grammar: false,
|
||||
can_use_min_p: false,
|
||||
};
|
||||
|
||||
const defaultValues = Object.freeze(structuredClone(kai_settings));
|
||||
@@ -48,6 +54,7 @@ const MIN_STREAMING_KCPPVERSION = '1.30';
|
||||
const MIN_TOKENIZATION_KCPPVERSION = '1.41';
|
||||
const MIN_MIROSTAT_KCPPVERSION = '1.35';
|
||||
const MIN_GRAMMAR_KCPPVERSION = '1.44';
|
||||
const MIN_MIN_P_KCPPVERSION = '1.48';
|
||||
const KOBOLDCPP_ORDER = [6, 0, 1, 3, 4, 2, 5];
|
||||
|
||||
export function formatKoboldUrl(value) {
|
||||
@@ -114,7 +121,7 @@ export function getKoboldGenerationData(finalPrompt, settings, maxLength, maxCon
|
||||
top_a: kai_settings.top_a,
|
||||
top_k: kai_settings.top_k,
|
||||
top_p: kai_settings.top_p,
|
||||
min_p: kai_settings.min_p,
|
||||
min_p: (kai_flags.can_use_min_p || isHorde) ? kai_settings.min_p : undefined,
|
||||
typical: kai_settings.typical,
|
||||
s1: sampler_order[0],
|
||||
s2: sampler_order[1],
|
||||
@@ -128,11 +135,11 @@ export function getKoboldGenerationData(finalPrompt, settings, maxLength, maxCon
|
||||
stop_sequence: (kai_flags.can_use_stop_sequence || isHorde) ? getStoppingStrings(isImpersonate) : undefined,
|
||||
streaming: kai_settings.streaming_kobold && kai_flags.can_use_streaming && type !== 'quiet',
|
||||
can_abort: kai_flags.can_use_streaming,
|
||||
mirostat: kai_flags.can_use_mirostat ? kai_settings.mirostat : undefined,
|
||||
mirostat_tau: kai_flags.can_use_mirostat ? kai_settings.mirostat_tau : undefined,
|
||||
mirostat_eta: kai_flags.can_use_mirostat ? kai_settings.mirostat_eta : undefined,
|
||||
use_default_badwordsids: kai_flags.can_use_default_badwordsids ? kai_settings.use_default_badwordsids : undefined,
|
||||
grammar: kai_flags.can_use_grammar ? substituteParams(kai_settings.grammar) : undefined,
|
||||
mirostat: (kai_flags.can_use_mirostat || isHorde) ? kai_settings.mirostat : undefined,
|
||||
mirostat_tau: (kai_flags.can_use_mirostat || isHorde) ? kai_settings.mirostat_tau : undefined,
|
||||
mirostat_eta: (kai_flags.can_use_mirostat || isHorde) ? kai_settings.mirostat_eta : undefined,
|
||||
use_default_badwordsids: (kai_flags.can_use_default_badwordsids || isHorde) ? kai_settings.use_default_badwordsids : undefined,
|
||||
grammar: (kai_flags.can_use_grammar || isHorde) ? substituteParams(kai_settings.grammar) : undefined,
|
||||
sampler_seed: kai_settings.seed >= 0 ? kai_settings.seed : undefined,
|
||||
};
|
||||
return generate_data;
|
||||
@@ -302,6 +309,7 @@ export function setKoboldFlags(version, koboldVersion) {
|
||||
kai_flags.can_use_default_badwordsids = canUseDefaultBadwordIds(version);
|
||||
kai_flags.can_use_mirostat = canUseMirostat(koboldVersion);
|
||||
kai_flags.can_use_grammar = canUseGrammar(koboldVersion);
|
||||
kai_flags.can_use_min_p = canUseMinP(koboldVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,6 +374,17 @@ function canUseGrammar(koboldVersion) {
|
||||
} else return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the Kobold min_p can be used with the given version.
|
||||
* @param {{result:string, version:string;}} koboldVersion KoboldAI version object.
|
||||
* @returns {boolean} True if the Kobold min_p can be used, false otherwise.
|
||||
*/
|
||||
function canUseMinP(koboldVersion) {
|
||||
if (koboldVersion && koboldVersion.result == 'KoboldCpp') {
|
||||
return (koboldVersion.version || '0.0').localeCompare(MIN_MIN_P_KCPPVERSION, undefined, { numeric: true, sensitivity: 'base' }) > -1;
|
||||
} else return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the sampler items by the given order.
|
||||
* @param {any[]} orderArray Sampler order array.
|
||||
|
@@ -5,62 +5,63 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
saveSettingsDebounced,
|
||||
setOnlineStatus,
|
||||
abortStatusCheck,
|
||||
callPopup,
|
||||
characters,
|
||||
event_types,
|
||||
eventSource,
|
||||
extension_prompt_types,
|
||||
Generate,
|
||||
getExtensionPrompt,
|
||||
getNextMessageId,
|
||||
getRequestHeaders,
|
||||
getStoppingStrings,
|
||||
is_send_press,
|
||||
main_api,
|
||||
MAX_INJECTION_DEPTH,
|
||||
name1,
|
||||
name2,
|
||||
extension_prompt_types,
|
||||
characters,
|
||||
this_chid,
|
||||
callPopup,
|
||||
getRequestHeaders,
|
||||
system_message_types,
|
||||
replaceBiasMarkup,
|
||||
is_send_press,
|
||||
Generate,
|
||||
main_api,
|
||||
eventSource,
|
||||
event_types,
|
||||
substituteParams,
|
||||
MAX_INJECTION_DEPTH,
|
||||
getStoppingStrings,
|
||||
getNextMessageId,
|
||||
replaceItemizedPromptText,
|
||||
startStatusLoading,
|
||||
resultCheckStatus,
|
||||
abortStatusCheck,
|
||||
saveSettingsDebounced,
|
||||
setOnlineStatus,
|
||||
startStatusLoading,
|
||||
substituteParams,
|
||||
system_message_types,
|
||||
this_chid,
|
||||
} from "../script.js";
|
||||
import { groups, selected_group } from "./group-chats.js";
|
||||
|
||||
import {
|
||||
promptManagerDefaultPromptOrders,
|
||||
chatCompletionDefaultPrompts, Prompt,
|
||||
PromptManagerModule as PromptManager,
|
||||
chatCompletionDefaultPrompts,
|
||||
INJECTION_POSITION,
|
||||
Prompt,
|
||||
promptManagerDefaultPromptOrders,
|
||||
PromptManagerModule as PromptManager,
|
||||
} from "./PromptManager.js";
|
||||
|
||||
import {
|
||||
getCustomStoppingStrings,
|
||||
persona_description_positions,
|
||||
power_user,
|
||||
} from "./power-user.js";
|
||||
import {
|
||||
SECRET_KEYS,
|
||||
secret_state,
|
||||
writeSecret,
|
||||
} from "./secrets.js";
|
||||
import { getCustomStoppingStrings, persona_description_positions, power_user, } from "./power-user.js";
|
||||
import { SECRET_KEYS, secret_state, writeSecret, } from "./secrets.js";
|
||||
|
||||
import {
|
||||
delay,
|
||||
download,
|
||||
getFileText, getSortableDelay,
|
||||
getBase64Async,
|
||||
getFileText,
|
||||
getSortableDelay,
|
||||
isDataURL,
|
||||
parseJsonFile,
|
||||
resetScrollHeight,
|
||||
stringFormat,
|
||||
} from "./utils.js";
|
||||
import { countTokensOpenAI, getTokenizerModel } from "./tokenizers.js";
|
||||
import { formatInstructModeChat, formatInstructModeExamples, formatInstructModePrompt, formatInstructModeSystemPrompt } from "./instruct-mode.js";
|
||||
import {
|
||||
formatInstructModeChat,
|
||||
formatInstructModeExamples,
|
||||
formatInstructModePrompt,
|
||||
formatInstructModeSystemPrompt
|
||||
} from "./instruct-mode.js";
|
||||
|
||||
export {
|
||||
openai_msgs,
|
||||
@@ -70,7 +71,6 @@ export {
|
||||
setOpenAIMessages,
|
||||
setOpenAIMessageExamples,
|
||||
setupChatCompletionPromptManager,
|
||||
prepareOpenAIMessages,
|
||||
sendOpenAIRequest,
|
||||
getChatCompletionModel,
|
||||
TokenHandler,
|
||||
@@ -208,6 +208,8 @@ const default_settings = {
|
||||
openrouter_model: openrouter_website_model,
|
||||
openrouter_use_fallback: false,
|
||||
openrouter_force_instruct: false,
|
||||
openrouter_group_models: false,
|
||||
openrouter_sort_models: 'alphabetically',
|
||||
jailbreak_system: false,
|
||||
reverse_proxy: '',
|
||||
legacy_streaming: false,
|
||||
@@ -221,6 +223,8 @@ const default_settings = {
|
||||
exclude_assistant: false,
|
||||
use_alt_scale: false,
|
||||
squash_system_messages: false,
|
||||
image_inlining: false,
|
||||
bypass_status_check: false,
|
||||
};
|
||||
|
||||
const oai_settings = {
|
||||
@@ -254,6 +258,8 @@ const oai_settings = {
|
||||
openrouter_model: openrouter_website_model,
|
||||
openrouter_use_fallback: false,
|
||||
openrouter_force_instruct: false,
|
||||
openrouter_group_models: false,
|
||||
openrouter_sort_models: 'alphabetically',
|
||||
jailbreak_system: false,
|
||||
reverse_proxy: '',
|
||||
legacy_streaming: false,
|
||||
@@ -267,6 +273,8 @@ const oai_settings = {
|
||||
exclude_assistant: false,
|
||||
use_alt_scale: false,
|
||||
squash_system_messages: false,
|
||||
image_inlining: false,
|
||||
bypass_status_check: false,
|
||||
};
|
||||
|
||||
let openai_setting_names;
|
||||
@@ -409,7 +417,8 @@ function setOpenAIMessages(chat) {
|
||||
// Apply the "wrap in quotes" option
|
||||
if (role == 'user' && oai_settings.wrap_in_quotes) content = `"${content}"`;
|
||||
const name = chat[j]['name'];
|
||||
openai_msgs[i] = { "role": role, "content": content, name: name };
|
||||
const image = chat[j]?.extra?.image;
|
||||
openai_msgs[i] = { "role": role, "content": content, name: name, "image": image };
|
||||
j++;
|
||||
}
|
||||
}
|
||||
@@ -592,7 +601,7 @@ export function isOpenRouterWithInstruct() {
|
||||
* @param type
|
||||
* @param cyclePrompt
|
||||
*/
|
||||
function populateChatHistory(prompts, chatCompletion, type = null, cyclePrompt = null) {
|
||||
async function populateChatHistory(prompts, chatCompletion, type = null, cyclePrompt = null) {
|
||||
chatCompletion.add(new MessageCollection('chatHistory'), prompts.index('chatHistory'));
|
||||
|
||||
let names = (selected_group && groups.find(x => x.id === selected_group)?.members.map(member => characters.find(c => c.avatar === member)?.name).filter(Boolean).join(', ')) || '';
|
||||
@@ -629,8 +638,13 @@ function populateChatHistory(prompts, chatCompletion, type = null, cyclePrompt =
|
||||
chatCompletion.insert(message, 'chatHistory');
|
||||
}
|
||||
|
||||
const imageInlining = isImageInliningSupported();
|
||||
|
||||
// Insert chat messages as long as there is budget available
|
||||
[...openai_msgs].reverse().every((chatPrompt, index) => {
|
||||
const chatPool = [...openai_msgs].reverse();
|
||||
for (let index = 0; index < chatPool.length; index++) {
|
||||
const chatPrompt = chatPool[index];
|
||||
|
||||
// We do not want to mutate the prompt
|
||||
const prompt = new Prompt(chatPrompt);
|
||||
prompt.identifier = `chatHistory-${openai_msgs.length - index}`;
|
||||
@@ -641,10 +655,16 @@ function populateChatHistory(prompts, chatCompletion, type = null, cyclePrompt =
|
||||
chatMessage.setName(messageName);
|
||||
}
|
||||
|
||||
if (chatCompletion.canAfford(chatMessage)) chatCompletion.insertAtStart(chatMessage, 'chatHistory');
|
||||
else return false;
|
||||
return true;
|
||||
});
|
||||
if (imageInlining && chatPrompt.image) {
|
||||
await chatMessage.addImage(chatPrompt.image);
|
||||
}
|
||||
|
||||
if (chatCompletion.canAfford(chatMessage)) {
|
||||
chatCompletion.insertAtStart(chatMessage, 'chatHistory');
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Insert and free new chat
|
||||
chatCompletion.freeBudget(newChatMessage);
|
||||
@@ -724,7 +744,7 @@ function getPromptPosition(position) {
|
||||
* @param {string} options.quietPrompt - Instruction prompt for extras
|
||||
* @param {string} options.type - The type of the chat, can be 'impersonate'.
|
||||
*/
|
||||
function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, type, cyclePrompt } = {}) {
|
||||
async function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, type, cyclePrompt } = {}) {
|
||||
// Helper function for preparing a prompt, that already exists within the prompt collection, for completion
|
||||
const addToChatCompletion = (source, target = null) => {
|
||||
// We need the prompts array to determine a position for the source.
|
||||
@@ -825,9 +845,9 @@ function populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, ty
|
||||
// Decide whether dialogue examples should always be added
|
||||
if (power_user.pin_examples) {
|
||||
populateDialogueExamples(prompts, chatCompletion);
|
||||
populateChatHistory(prompts, chatCompletion, type, cyclePrompt);
|
||||
await populateChatHistory(prompts, chatCompletion, type, cyclePrompt);
|
||||
} else {
|
||||
populateChatHistory(prompts, chatCompletion, type, cyclePrompt);
|
||||
await populateChatHistory(prompts, chatCompletion, type, cyclePrompt);
|
||||
populateDialogueExamples(prompts, chatCompletion);
|
||||
}
|
||||
|
||||
@@ -969,7 +989,7 @@ function preparePromptsForChatCompletion({ Scenario, charPersonality, name2, wor
|
||||
* @param dryRun - Whether this is a live call or not.
|
||||
* @returns {(*[]|boolean)[]} An array where the first element is the prepared chat and the second element is a boolean flag.
|
||||
*/
|
||||
function prepareOpenAIMessages({
|
||||
export async function prepareOpenAIMessages({
|
||||
name2,
|
||||
charDescription,
|
||||
charPersonality,
|
||||
@@ -1012,7 +1032,7 @@ function prepareOpenAIMessages({
|
||||
});
|
||||
|
||||
// Fill the chat completion with as much context as the budget allows
|
||||
populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, type, cyclePrompt });
|
||||
await populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, type, cyclePrompt });
|
||||
} catch (error) {
|
||||
if (error instanceof TokenBudgetExceededError) {
|
||||
toastr.error('An error occurred while counting tokens: Token budget exceeded.')
|
||||
@@ -1224,18 +1244,16 @@ function saveModelList(data) {
|
||||
model_list.sort((a, b) => a?.id && b?.id && a.id.localeCompare(b.id));
|
||||
|
||||
if (oai_settings.chat_completion_source == chat_completion_sources.OPENROUTER) {
|
||||
model_list = openRouterSortBy(model_list, oai_settings.openrouter_sort_models);
|
||||
|
||||
$('#model_openrouter_select').empty();
|
||||
$('#model_openrouter_select').append($('<option>', { value: openrouter_website_model, text: 'Use OpenRouter website setting' }));
|
||||
model_list.forEach((model) => {
|
||||
let tokens_dollar = Number(1 / (1000 * model.pricing?.prompt));
|
||||
let tokens_rounded = (Math.round(tokens_dollar * 1000) / 1000).toFixed(0);
|
||||
let model_description = `${model.id} | ${tokens_rounded}k t/$ | ${model.context_length} ctx`;
|
||||
$('#model_openrouter_select').append(
|
||||
$('<option>', {
|
||||
value: model.id,
|
||||
text: model_description,
|
||||
}));
|
||||
});
|
||||
|
||||
if (true === oai_settings.openrouter_group_models) {
|
||||
appendOpenRouterOptions(openRouterGroupByVendor(model_list), oai_settings.openrouter_group_models);
|
||||
} else {
|
||||
appendOpenRouterOptions(model_list);
|
||||
}
|
||||
|
||||
$('#model_openrouter_select').val(oai_settings.openrouter_model).trigger('change');
|
||||
}
|
||||
|
||||
@@ -1256,6 +1274,67 @@ function saveModelList(data) {
|
||||
}
|
||||
}
|
||||
|
||||
function appendOpenRouterOptions(model_list, groupModels = false, sort = false) {
|
||||
$('#model_openrouter_select').append($('<option>', { value: openrouter_website_model, text: 'Use OpenRouter website setting' }));
|
||||
|
||||
const appendOption = (model, parent = null) => {
|
||||
let tokens_dollar = Number(1 / (1000 * model.pricing?.prompt));
|
||||
let tokens_rounded = (Math.round(tokens_dollar * 1000) / 1000).toFixed(0);
|
||||
|
||||
const price = 0 === Number(model.pricing?.prompt) ? 'Free' : `${tokens_rounded}k t/$ `;
|
||||
|
||||
let model_description = `${model.id} | ${price} | ${model.context_length} ctx`;
|
||||
(parent || $('#model_openrouter_select')).append(
|
||||
$('<option>', {
|
||||
value: model.id,
|
||||
text: model_description,
|
||||
}));
|
||||
};
|
||||
|
||||
if (groupModels) {
|
||||
model_list.forEach((models, vendor) => {
|
||||
const optgroup = $(`<optgroup label="${vendor}">`);
|
||||
|
||||
models.forEach((model) => {
|
||||
appendOption(model, optgroup);
|
||||
});
|
||||
|
||||
$('#model_openrouter_select').append(optgroup);
|
||||
});
|
||||
} else {
|
||||
model_list.forEach((model) => {
|
||||
appendOption(model);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const openRouterSortBy = (data, property = 'alphabetically') => {
|
||||
return data.sort((a, b) => {
|
||||
if (property === 'context_length') {
|
||||
return b.context_length - a.context_length;
|
||||
} else if (property === 'pricing.prompt') {
|
||||
return parseFloat(a.pricing.prompt) - parseFloat(b.pricing.prompt);
|
||||
} else {
|
||||
// Alphabetically
|
||||
return a?.id && b?.id && a.id.localeCompare(b.id);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function openRouterGroupByVendor(array) {
|
||||
return array.reduce((acc, curr) => {
|
||||
const vendor = curr.id.split('/')[0];
|
||||
|
||||
if (!acc.has(vendor)) {
|
||||
acc.set(vendor, []);
|
||||
}
|
||||
|
||||
acc.get(vendor).push(curr);
|
||||
|
||||
return acc;
|
||||
}, new Map());
|
||||
}
|
||||
|
||||
async function sendAltScaleRequest(openai_msgs_tosend, logit_bias, signal, type) {
|
||||
const generate_url = '/generate_altscale';
|
||||
|
||||
@@ -1372,6 +1451,16 @@ async function sendOpenAIRequest(type, openai_msgs_tosend, signal) {
|
||||
"stop": getCustomStoppingStrings(openai_max_stop_strings),
|
||||
};
|
||||
|
||||
// Empty array will produce a validation error
|
||||
if (!Array.isArray(generate_data.stop) || !generate_data.stop.length) {
|
||||
delete generate_data.stop;
|
||||
}
|
||||
|
||||
// Vision models don't support logit bias
|
||||
if (isImageInliningSupported()) {
|
||||
delete generate_data.logit_bias;
|
||||
}
|
||||
|
||||
// Proxy is only supported for Claude and OpenAI
|
||||
if (oai_settings.reverse_proxy && [chat_completion_sources.CLAUDE, chat_completion_sources.OPENAI].includes(oai_settings.chat_completion_source)) {
|
||||
validateReverseProxy();
|
||||
@@ -1640,7 +1729,18 @@ class InvalidCharacterNameError extends Error {
|
||||
* Used for creating, managing, and interacting with a specific message object.
|
||||
*/
|
||||
class Message {
|
||||
tokens; identifier; role; content; name;
|
||||
static tokensPerImage = 85;
|
||||
|
||||
/** @type {number} */
|
||||
tokens;
|
||||
/** @type {string} */
|
||||
identifier;
|
||||
/** @type {string} */
|
||||
role;
|
||||
/** @type {string|any[]} */
|
||||
content;
|
||||
/** @type {string} */
|
||||
name;
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
@@ -1665,6 +1765,30 @@ class Message {
|
||||
this.tokens = tokenHandler.count({ role: this.role, content: this.content, name: this.name });
|
||||
}
|
||||
|
||||
async addImage(image) {
|
||||
const textContent = this.content;
|
||||
const isDataUrl = isDataURL(image);
|
||||
|
||||
if (!isDataUrl) {
|
||||
try {
|
||||
const response = await fetch(image, { method: 'GET', cache: 'force-cache' });
|
||||
if (!response.ok) throw new Error('Failed to fetch image');
|
||||
const blob = await response.blob();
|
||||
image = await getBase64Async(blob);
|
||||
} catch (error) {
|
||||
console.error('Image adding skipped', error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.content = [
|
||||
{ type: "text", text: textContent },
|
||||
{ type: "image_url", image_url: { "url": image, "detail": "low" } },
|
||||
];
|
||||
|
||||
this.tokens += Message.tokensPerImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Message instance from a prompt.
|
||||
* @static
|
||||
@@ -2140,6 +2264,8 @@ function loadOpenAISettings(data, settings) {
|
||||
oai_settings.claude_model = settings.claude_model ?? default_settings.claude_model;
|
||||
oai_settings.windowai_model = settings.windowai_model ?? default_settings.windowai_model;
|
||||
oai_settings.openrouter_model = settings.openrouter_model ?? default_settings.openrouter_model;
|
||||
oai_settings.openrouter_group_models = settings.openrouter_group_models ?? default_settings.openrouter_group_models;
|
||||
oai_settings.openrouter_sort_models = settings.openrouter_sort_models ?? default_settings.openrouter_sort_models;
|
||||
oai_settings.openrouter_use_fallback = settings.openrouter_use_fallback ?? default_settings.openrouter_use_fallback;
|
||||
oai_settings.openrouter_force_instruct = settings.openrouter_force_instruct ?? default_settings.openrouter_force_instruct;
|
||||
oai_settings.ai21_model = settings.ai21_model ?? default_settings.ai21_model;
|
||||
@@ -2148,6 +2274,8 @@ function loadOpenAISettings(data, settings) {
|
||||
oai_settings.show_external_models = settings.show_external_models ?? default_settings.show_external_models;
|
||||
oai_settings.proxy_password = settings.proxy_password ?? default_settings.proxy_password;
|
||||
oai_settings.assistant_prefill = settings.assistant_prefill ?? default_settings.assistant_prefill;
|
||||
oai_settings.image_inlining = settings.image_inlining ?? default_settings.image_inlining;
|
||||
oai_settings.bypass_status_check = settings.bypass_status_check ?? default_settings.bypass_status_check;
|
||||
|
||||
oai_settings.prompts = settings.prompts ?? default_settings.prompts;
|
||||
oai_settings.prompt_order = settings.prompt_order ?? default_settings.prompt_order;
|
||||
@@ -2168,6 +2296,8 @@ function loadOpenAISettings(data, settings) {
|
||||
$('#api_url_scale').val(oai_settings.api_url_scale);
|
||||
$('#openai_proxy_password').val(oai_settings.proxy_password);
|
||||
$('#claude_assistant_prefill').val(oai_settings.assistant_prefill);
|
||||
$('#openai_image_inlining').prop('checked', oai_settings.image_inlining);
|
||||
$('#openai_bypass_status_check').prop('checked', oai_settings.bypass_status_check);
|
||||
|
||||
$('#model_openai_select').val(oai_settings.openai_model);
|
||||
$(`#model_openai_select option[value="${oai_settings.openai_model}"`).attr('selected', true);
|
||||
@@ -2180,6 +2310,7 @@ function loadOpenAISettings(data, settings) {
|
||||
$('#openai_max_context').val(oai_settings.openai_max_context);
|
||||
$('#openai_max_context_counter').val(`${oai_settings.openai_max_context}`);
|
||||
$('#model_openrouter_select').val(oai_settings.openrouter_model);
|
||||
$('#openrouter_sort_models').val(oai_settings.openrouter_sort_models);
|
||||
|
||||
$('#openai_max_tokens').val(oai_settings.openai_max_tokens);
|
||||
|
||||
@@ -2194,6 +2325,7 @@ function loadOpenAISettings(data, settings) {
|
||||
$('#scale-alt').prop('checked', oai_settings.use_alt_scale);
|
||||
$('#openrouter_use_fallback').prop('checked', oai_settings.openrouter_use_fallback);
|
||||
$('#openrouter_force_instruct').prop('checked', oai_settings.openrouter_force_instruct);
|
||||
$('#openrouter_group_models').prop('checked', oai_settings.openrouter_group_models);
|
||||
$('#squash_system_messages').prop('checked', oai_settings.squash_system_messages);
|
||||
if (settings.impersonation_prompt !== undefined) oai_settings.impersonation_prompt = settings.impersonation_prompt;
|
||||
|
||||
@@ -2277,6 +2409,11 @@ async function getStatusOpen() {
|
||||
validateReverseProxy();
|
||||
}
|
||||
|
||||
const canBypass = oai_settings.chat_completion_source === chat_completion_sources.OPENAI && oai_settings.bypass_status_check;
|
||||
if (canBypass) {
|
||||
setOnlineStatus('Status check bypassed');
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/getstatus_openai', {
|
||||
method: 'POST',
|
||||
@@ -2292,14 +2429,18 @@ async function getStatusOpen() {
|
||||
|
||||
const responseData = await response.json();
|
||||
|
||||
if (!('error' in responseData))
|
||||
if (!('error' in responseData)) {
|
||||
setOnlineStatus('Valid');
|
||||
}
|
||||
if ('data' in responseData && Array.isArray(responseData.data)) {
|
||||
saveModelList(responseData.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
setOnlineStatus('no_connection');
|
||||
|
||||
if (!canBypass) {
|
||||
setOnlineStatus('no_connection');
|
||||
}
|
||||
}
|
||||
|
||||
return resultCheckStatus();
|
||||
@@ -2353,6 +2494,8 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
|
||||
openrouter_model: settings.openrouter_model,
|
||||
openrouter_use_fallback: settings.openrouter_use_fallback,
|
||||
openrouter_force_instruct: settings.openrouter_force_instruct,
|
||||
openrouter_group_models: settings.openrouter_group_models,
|
||||
openrouter_sort_models: settings.openrouter_sort_models,
|
||||
ai21_model: settings.ai21_model,
|
||||
temperature: settings.temp_openai,
|
||||
frequency_penalty: settings.freq_pen_openai,
|
||||
@@ -2388,6 +2531,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
|
||||
exclude_assistant: settings.exclude_assistant,
|
||||
use_alt_scale: settings.use_alt_scale,
|
||||
squash_system_messages: settings.squash_system_messages,
|
||||
image_inlining: settings.image_inlining,
|
||||
};
|
||||
|
||||
const savePresetSettings = await fetch(`/api/presets/save-openai?name=${name}`, {
|
||||
@@ -2715,6 +2859,8 @@ function onSettingsPresetChange() {
|
||||
openrouter_model: ['#model_openrouter_select', 'openrouter_model', false],
|
||||
openrouter_use_fallback: ['#openrouter_use_fallback', 'openrouter_use_fallback', true],
|
||||
openrouter_force_instruct: ['#openrouter_force_instruct', 'openrouter_force_instruct', true],
|
||||
openrouter_group_models: ['#openrouter_group_models', 'openrouter_group_models', false],
|
||||
openrouter_sort_models: ['#openrouter_sort_models', 'openrouter_sort_models', false],
|
||||
ai21_model: ['#model_ai21_select', 'ai21_model', false],
|
||||
openai_max_context: ['#openai_max_context', 'openai_max_context', false],
|
||||
openai_max_tokens: ['#openai_max_tokens', 'openai_max_tokens', false],
|
||||
@@ -2741,6 +2887,7 @@ function onSettingsPresetChange() {
|
||||
exclude_assistant: ['#exclude_assistant', 'exclude_assistant', true],
|
||||
use_alt_scale: ['#use_alt_scale', 'use_alt_scale', true],
|
||||
squash_system_messages: ['#squash_system_messages', 'squash_system_messages', true],
|
||||
image_inlining: ['#openai_image_inlining', 'image_inlining', true],
|
||||
};
|
||||
|
||||
const presetName = $('#settings_preset_openai').find(":selected").text();
|
||||
@@ -2785,6 +2932,9 @@ function getMaxContextOpenAI(value) {
|
||||
else if (value.includes('gpt-4-1106')) {
|
||||
return max_128k;
|
||||
}
|
||||
else if (value.includes('gpt-4-vision')) {
|
||||
return max_128k;
|
||||
}
|
||||
else if (value.includes('gpt-3.5-turbo-1106')) {
|
||||
return max_16k;
|
||||
}
|
||||
@@ -2831,6 +2981,9 @@ function getMaxContextWindowAI(value) {
|
||||
else if (value.includes('gpt-4-1106')) {
|
||||
return max_128k;
|
||||
}
|
||||
else if (value.includes('gpt-4-vision')) {
|
||||
return max_128k;
|
||||
}
|
||||
else if (value.includes('gpt-4-32k')) {
|
||||
return max_32k;
|
||||
}
|
||||
@@ -3016,6 +3169,10 @@ async function onModelChange() {
|
||||
eventSource.emit(event_types.CHATCOMPLETION_MODEL_CHANGED, value);
|
||||
}
|
||||
|
||||
async function onOpenrouterModelSortChange() {
|
||||
await getStatusOpen();
|
||||
}
|
||||
|
||||
async function onNewPresetClick() {
|
||||
const popupText = `
|
||||
<h3>Preset name:</h3>
|
||||
@@ -3217,6 +3374,31 @@ function updateScaleForm() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the model supports image inlining
|
||||
* @returns {boolean} True if the model supports image inlining
|
||||
*/
|
||||
export function isImageInliningSupported() {
|
||||
if (main_api !== 'openai') {
|
||||
return false;
|
||||
}
|
||||
|
||||
const modelId = 'gpt-4-vision';
|
||||
|
||||
if (!oai_settings.image_inlining) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (oai_settings.chat_completion_source) {
|
||||
case chat_completion_sources.OPENAI:
|
||||
return oai_settings.openai_model.includes(modelId);
|
||||
case chat_completion_sources.OPENROUTER:
|
||||
return oai_settings.openrouter_model.includes(modelId);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$(document).ready(async function () {
|
||||
$('#test_api_button').on('click', testApiConnection);
|
||||
|
||||
@@ -3409,6 +3591,12 @@ $(document).ready(async function () {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#openai_bypass_status_check').on('input', function () {
|
||||
oai_settings.bypass_status_check = !!$(this).prop('checked');
|
||||
getStatusOpen();
|
||||
saveSettingsDebounced();
|
||||
})
|
||||
|
||||
$('#chat_completion_source').on('change', function () {
|
||||
oai_settings.chat_completion_source = String($(this).find(":selected").val());
|
||||
toggleChatCompletionForms();
|
||||
@@ -3458,11 +3646,26 @@ $(document).ready(async function () {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#openrouter_group_models').on('input', function () {
|
||||
oai_settings.openrouter_group_models = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#openrouter_sort_models').on('input', function () {
|
||||
oai_settings.openrouter_sort_models = String($(this).val());
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#squash_system_messages').on('input', function () {
|
||||
oai_settings.squash_system_messages = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#openai_image_inlining').on('input', function () {
|
||||
oai_settings.image_inlining = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$(document).on('input', '#openai_settings .autoSetHeight', function () {
|
||||
resetScrollHeight($(this));
|
||||
});
|
||||
@@ -3475,6 +3678,8 @@ $(document).ready(async function () {
|
||||
$("#model_scale_select").on("change", onModelChange);
|
||||
$("#model_palm_select").on("change", onModelChange);
|
||||
$("#model_openrouter_select").on("change", onModelChange);
|
||||
$("#openrouter_group_models").on("change", onOpenrouterModelSortChange);
|
||||
$("#openrouter_sort_models").on("change", onOpenrouterModelSortChange);
|
||||
$("#model_ai21_select").on("change", onModelChange);
|
||||
$("#settings_preset_openai").on("change", onSettingsPresetChange);
|
||||
$("#new_oai_preset").on("click", onNewPresetClick);
|
||||
|
@@ -1,7 +1,3 @@
|
||||
/**
|
||||
* This is a placeholder file for all the Persona Management code. Will be refactored into a separate file soon.
|
||||
*/
|
||||
|
||||
import { callPopup, characters, chat_metadata, default_avatar, eventSource, event_types, getRequestHeaders, getThumbnailUrl, getUserAvatars, name1, saveMetadata, saveSettingsDebounced, setUserName, this_chid, user_avatar } from "../script.js";
|
||||
import { persona_description_positions, power_user } from "./power-user.js";
|
||||
import { getTokenCount } from "./tokenizers.js";
|
||||
@@ -38,6 +34,28 @@ async function uploadUserAvatar(url, name) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user to create a persona for the uploaded avatar.
|
||||
* @param {string} avatarId User avatar id
|
||||
* @returns {Promise} Promise that resolves when the persona is set
|
||||
*/
|
||||
export async function createPersona(avatarId) {
|
||||
const personaName = await callPopup('<h3>Enter a name for this persona:</h3>Cancel if you\'re just uploading an avatar.', 'input', '');
|
||||
|
||||
if (!personaName) {
|
||||
console.debug('User cancelled creating a persona');
|
||||
return;
|
||||
}
|
||||
|
||||
await delay(500);
|
||||
const personaDescription = await callPopup('<h3>Enter a description for this persona:</h3>You can always add or change it later.', 'input', '', { rows: 4 });
|
||||
|
||||
initPersona(avatarId, personaName, personaDescription);
|
||||
if (power_user.persona_show_notifications) {
|
||||
toastr.success(`You can now pick ${personaName} as a persona in the Persona Management menu.`, 'Persona Created');
|
||||
}
|
||||
}
|
||||
|
||||
async function createDummyPersona() {
|
||||
const personaName = await callPopup('<h3>Enter a name for this persona:</h3>', 'input', '');
|
||||
|
||||
@@ -48,18 +66,28 @@ async function createDummyPersona() {
|
||||
|
||||
// Date + name (only ASCII) to make it unique
|
||||
const avatarId = `${Date.now()}-${personaName.replace(/[^a-zA-Z0-9]/g, '')}.png`;
|
||||
initPersona(avatarId, personaName, '');
|
||||
await uploadUserAvatar(default_avatar, avatarId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a persona for the given avatar id.
|
||||
* @param {string} avatarId User avatar id
|
||||
* @param {string} personaName Name for the persona
|
||||
* @param {string} personaDescription Optional description for the persona
|
||||
* @returns {void}
|
||||
*/
|
||||
export function initPersona(avatarId, personaName, personaDescription) {
|
||||
power_user.personas[avatarId] = personaName;
|
||||
power_user.persona_descriptions[avatarId] = {
|
||||
description: '',
|
||||
description: personaDescription || '',
|
||||
position: persona_description_positions.IN_PROMPT,
|
||||
};
|
||||
|
||||
await uploadUserAvatar(default_avatar, avatarId);
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
export async function convertCharacterToPersona(characterId = null) {
|
||||
|
||||
if (null === characterId) characterId = this_chid;
|
||||
|
||||
const avatarUrl = characters[characterId]?.avatar;
|
||||
|
@@ -220,6 +220,7 @@ let power_user = {
|
||||
encode_tags: false,
|
||||
servers: [],
|
||||
bogus_folders: false,
|
||||
aux_field: 'character_version',
|
||||
};
|
||||
|
||||
let themes = [];
|
||||
@@ -432,10 +433,12 @@ var originalSliderValues = []
|
||||
|
||||
async function switchLabMode() {
|
||||
|
||||
if (power_user.enableZenSliders) {
|
||||
//force disable ZenSliders for Lab Mode
|
||||
$("#enableZenSliders").trigger('click')
|
||||
}
|
||||
/* if (power_user.enableZenSliders && power_user.enableLabMode) {
|
||||
toastr.warning("Can't start Lab Mode while Zen Sliders are active")
|
||||
return
|
||||
//$("#enableZenSliders").trigger('click')
|
||||
}
|
||||
*/
|
||||
await delay(100)
|
||||
const value = localStorage.getItem(storage_keys.enableLabMode);
|
||||
power_user.enableLabMode = value === null ? false : value == "true";
|
||||
@@ -457,7 +460,7 @@ async function switchLabMode() {
|
||||
.attr('min', '-99999')
|
||||
.attr('max', '99999')
|
||||
.attr('step', '0.001')
|
||||
$("#labModeWarning").show()
|
||||
$("#labModeWarning").removeClass('displayNone')
|
||||
//$("#advanced-ai-config-block input[type='range']").hide()
|
||||
|
||||
} else {
|
||||
@@ -470,20 +473,17 @@ async function switchLabMode() {
|
||||
.trigger('input')
|
||||
});
|
||||
$("#advanced-ai-config-block input[type='range']").show()
|
||||
$("#labModeWarning").hide()
|
||||
$("#labModeWarning").addClass('displayNone')
|
||||
}
|
||||
}
|
||||
|
||||
async function switchZenSliders() {
|
||||
|
||||
await delay(100)
|
||||
const value = localStorage.getItem(storage_keys.enableZenSliders);
|
||||
power_user.enableZenSliders = value === null ? false : value == "true";
|
||||
$("body").toggleClass("enableZenSliders", power_user.enableZenSliders);
|
||||
$("#enableZenSliders").prop("checked", power_user.enableZenSliders);
|
||||
|
||||
|
||||
|
||||
if (power_user.enableZenSliders) {
|
||||
$("#clickSlidersTips").hide()
|
||||
$("#pro-settings-block input[type='number']").hide();
|
||||
@@ -526,6 +526,7 @@ async function switchZenSliders() {
|
||||
var sliderRange = sliderMax - sliderMin
|
||||
var numSteps = 10
|
||||
var decimals = 2
|
||||
var offVal
|
||||
|
||||
if (sliderID == 'amount_gen') {
|
||||
decimals = 0
|
||||
@@ -537,58 +538,107 @@ async function switchZenSliders() {
|
||||
sliderValue = steps.indexOf(Number(sliderValue))
|
||||
if (sliderValue === -1) { sliderValue = 4 } // default to '200' if origSlider has value we can't use
|
||||
}
|
||||
if (sliderID == 'max_context') {
|
||||
numSteps = 15
|
||||
//customize decimals
|
||||
if (sliderID == 'max_context' ||
|
||||
sliderID == 'mirostat_mode_textgenerationwebui' ||
|
||||
sliderID == 'mirostat_tau_textgenerationwebui' ||
|
||||
sliderID == 'top_k_textgenerationwebui' ||
|
||||
sliderID == 'num_beams_textgenerationwebui' ||
|
||||
sliderID == 'no_repeat_ngram_size_textgenerationwebui' ||
|
||||
sliderID == 'min_length_textgenerationwebui' ||
|
||||
sliderID == 'top_k' ||
|
||||
sliderID == 'mirostat_mode_kobold' ||
|
||||
sliderID == 'rep_pen_range') {
|
||||
decimals = 0
|
||||
}
|
||||
if (sliderID == 'eta_cutoff_textgenerationwebui' ||
|
||||
sliderID == 'epsilon_cutoff_textgenerationwebui') {
|
||||
numSteps = 50
|
||||
decimals = 1
|
||||
}
|
||||
|
||||
if (sliderID == 'rep_pen_range_textgenerationwebui') {
|
||||
numSteps = 16
|
||||
decimals = 0
|
||||
//customize steps
|
||||
if (sliderID == 'mirostat_mode_textgenerationwebui' ||
|
||||
sliderID == 'mirostat_mode_kobold') {
|
||||
numSteps = 2
|
||||
}
|
||||
if (sliderID == 'encoder_rep_pen_textgenerationwebui') {
|
||||
numSteps = 14
|
||||
}
|
||||
if (sliderID == 'mirostat_mode_textgenerationwebui') {
|
||||
numSteps = 2
|
||||
decimals = 0
|
||||
if (sliderID == 'max_context') {
|
||||
numSteps = 15
|
||||
}
|
||||
if (sliderID == 'rep_pen_range_textgenerationwebui') {
|
||||
numSteps = 16
|
||||
}
|
||||
if (sliderID == 'mirostat_tau_textgenerationwebui' ||
|
||||
sliderID == 'top_k_textgenerationwebui' ||
|
||||
sliderID == 'num_beams_textgenerationwebui' ||
|
||||
sliderID == 'no_repeat_ngram_size_textgenerationwebui') {
|
||||
sliderID == 'no_repeat_ngram_size_textgenerationwebui' ||
|
||||
sliderID == 'epsilon_cutoff_textgenerationwebui' ||
|
||||
sliderID == 'tfs_textgenerationwebui' ||
|
||||
sliderID == 'min_p_textgenerationwebui' ||
|
||||
sliderID == 'temp_textgenerationwebui' ||
|
||||
sliderID == 'temp') {
|
||||
numSteps = 20
|
||||
decimals = 0
|
||||
}
|
||||
if (sliderID == 'epsilon_cutoff_textgenerationwebui') {
|
||||
numSteps = 20
|
||||
decimals = 1
|
||||
}
|
||||
if (sliderID == 'tfs_textgenerationwebui' ||
|
||||
sliderID == 'min_p_textgenerationwebui') {
|
||||
numSteps = 20
|
||||
decimals = 2
|
||||
}
|
||||
|
||||
if (sliderID == 'mirostat_eta_textgenerationwebui' ||
|
||||
sliderID == 'penalty_alpha_textgenerationwebui' ||
|
||||
sliderID == 'length_penalty_textgenerationwebui') {
|
||||
numSteps = 50
|
||||
}
|
||||
if (sliderID == 'eta_cutoff_textgenerationwebui') {
|
||||
numSteps = 50
|
||||
decimals = 1
|
||||
|
||||
//customize off values
|
||||
if (sliderID == 'presence_pen_textgenerationwebui' ||
|
||||
sliderID == 'freq_pen_textgenerationwebui' ||
|
||||
sliderID == 'mirostat_mode_textgenerationwebui' ||
|
||||
sliderID == 'mirostat_mode_kobold' ||
|
||||
sliderID == 'mirostat_tau_textgenerationwebui' ||
|
||||
sliderID == 'mirostat_tau_kobold' ||
|
||||
sliderID == 'mirostat_eta_textgenerationwebui' ||
|
||||
sliderID == 'mirostat_eta_kobold' ||
|
||||
sliderID == 'min_p_textgenerationwebui' ||
|
||||
sliderID == 'min_p' ||
|
||||
sliderID == 'no_repeat_ngram_size_textgenerationwebui' ||
|
||||
sliderID == 'penalty_alpha_textgenerationwebui' ||
|
||||
sliderID == 'length_penalty_textgenerationwebui' ||
|
||||
sliderID == 'epsilon_cutoff_textgenerationwebui' ||
|
||||
sliderID == 'rep_pen_range_textgenerationwebui' ||
|
||||
sliderID == 'rep_pen_range' ||
|
||||
sliderID == 'eta_cutoff_textgenerationwebui' ||
|
||||
sliderID == 'top_a_textgenerationwebui' ||
|
||||
sliderID == 'top_a' ||
|
||||
sliderID == 'top_k_textgenerationwebui' ||
|
||||
sliderID == 'top_k' ||
|
||||
sliderID == 'rep_pen_slope' ||
|
||||
sliderID == 'min_length_textgenerationwebui') {
|
||||
offVal = 0
|
||||
}
|
||||
|
||||
if (sliderID == 'rep_pen_textgenerationwebui' ||
|
||||
sliderID == 'rep_pen' ||
|
||||
sliderID == 'tfs_textgenerationwebui' ||
|
||||
sliderID == 'tfs' ||
|
||||
sliderID == 'top_p_textgenerationwebui' ||
|
||||
sliderID == 'top_p' ||
|
||||
sliderID == 'num_beams_textgenerationwebui' ||
|
||||
sliderID == 'typical_p_textgenerationwebui' ||
|
||||
sliderID == 'typical_p' ||
|
||||
sliderID == 'encoder_rep_pen_textgenerationwebui' ||
|
||||
sliderID == 'temp_textgenerationwebui' ||
|
||||
sliderID == 'temp' ||
|
||||
sliderID == 'guidance_scale_textgenerationwebui' ||
|
||||
sliderID == 'guidance_scale') {
|
||||
offVal = 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (sliderID == 'guidance_scale_textgenerationwebui') {
|
||||
numSteps = 78
|
||||
}
|
||||
if (sliderID == 'min_length_textgenerationwebui') {
|
||||
decimals = 0
|
||||
}
|
||||
if (sliderID == 'temp_textgenerationwebui') {
|
||||
numSteps = 20
|
||||
}
|
||||
|
||||
//customize amt gen steps
|
||||
if (sliderID !== 'amount_gen') {
|
||||
var stepScale = sliderRange / numSteps
|
||||
}
|
||||
@@ -605,60 +655,124 @@ async function switchZenSliders() {
|
||||
max: sliderMax,
|
||||
create: function () {
|
||||
var handle = $(this).find(".ui-slider-handle");
|
||||
//handling creaetion of amt_gen
|
||||
if (newSlider.attr('id') == 'amount_gen_zenslider') {
|
||||
//console.log(sliderValue, steps.indexOf(Number(sliderValue)))
|
||||
var handleText = steps[sliderValue]
|
||||
handle.text(handleText);
|
||||
//console.log(handleText)
|
||||
var stepNumber = sliderValue
|
||||
var leftMargin = ((stepNumber) / numSteps) * 50 * -1
|
||||
//console.log(`initial value:${handleText}, stepNum:${stepNumber}, numSteps:${numSteps}, left-margin:${leftMargin}`)
|
||||
handle.css('margin-left', `${leftMargin}px`)
|
||||
handle.text(handleText)
|
||||
.css('margin-left', `${leftMargin}px`)
|
||||
console.log(`initial value:${handleText}, stepNum:${stepNumber}, numSteps:${numSteps}, left-margin:${leftMargin}`)
|
||||
} else {
|
||||
|
||||
var handleText = Number(sliderValue).toFixed(decimals)
|
||||
handle.text(handleText);
|
||||
//handling creation for all other sliders
|
||||
var numVal = Number(sliderValue).toFixed(decimals)
|
||||
offVal = Number(offVal).toFixed(decimals)
|
||||
console.log(`${sliderID} ON LOAD OFFVAL ${offVal}`)
|
||||
if (numVal === offVal) {
|
||||
handle.text('Off').css('color', 'rgba(128,128,128,0.5');
|
||||
} else {
|
||||
handle.text(numVal).css('color', '');
|
||||
}
|
||||
var stepNumber = ((sliderValue - sliderMin) / stepScale)
|
||||
var leftMargin = (stepNumber / numSteps) * 50 * -1
|
||||
var isManualInput = false
|
||||
var valueBeforeManualInput
|
||||
handle.css('margin-left', `${leftMargin}px`)
|
||||
.attr('contenteditable', 'true')
|
||||
.on('click', function () {
|
||||
//this just selects all the text in the handle so user can overwrite easily
|
||||
//needed because JQUery UI uses left/right arrow keys as well as home/end to move the slider..
|
||||
valueBeforeManualInput = newSlider.val()
|
||||
console.log(valueBeforeManualInput)
|
||||
let handleElement = handle.get(0);
|
||||
let range = document.createRange();
|
||||
range.selectNodeContents(handleElement);
|
||||
let selection = window.getSelection();
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
})
|
||||
.on('keyup', function () {
|
||||
valueBeforeManualInput = newSlider.val()
|
||||
console.log(valueBeforeManualInput)
|
||||
isManualInput = true
|
||||
})
|
||||
//trigger slider changes when user clicks away
|
||||
.on('mouseup blur', function () {
|
||||
let manualInput = parseFloat(handle.text()).toFixed(decimals)
|
||||
if (isManualInput) {
|
||||
//disallow manual inputs outside acceptable range
|
||||
if (manualInput >= sliderMin && manualInput <= sliderMax) {
|
||||
//if value is ok, assign to slider and update handle text and position
|
||||
newSlider.val(manualInput)
|
||||
handleSlideEvent.call(newSlider, null, { value: parseFloat(manualInput) }, 'manual');
|
||||
valueBeforeManualInput = manualInput
|
||||
} else {
|
||||
//if value not ok, warn and reset to last known valid value
|
||||
toastr.warning(`Invalid value. Must be between ${sliderMin} and ${sliderMax}`)
|
||||
console.log(valueBeforeManualInput)
|
||||
newSlider.val(valueBeforeManualInput)
|
||||
handle.text(valueBeforeManualInput)
|
||||
}
|
||||
}
|
||||
isManualInput = false
|
||||
})
|
||||
console.debug(sliderID, sliderValue, handleText, stepNumber, stepScale)
|
||||
}
|
||||
},
|
||||
slide: function (event, ui) {
|
||||
var handle = $(this).find(".ui-slider-handle");
|
||||
if (newSlider.attr('id') == 'amount_gen_zenslider') {
|
||||
//console.log(`stepScale${stepScale}, UIvalue:${ui.value}, mappedValue:${steps[ui.value]}`)
|
||||
$(this).val(steps[ui.value])
|
||||
let handleText = steps[ui.value].toFixed(decimals)
|
||||
handle.text(handleText);
|
||||
var stepNumber = steps.indexOf(Number(handleText))
|
||||
var leftMargin = (stepNumber / numSteps) * 50 * -1
|
||||
//console.log(`handleText:${handleText},stepNum:${stepNumber}, numSteps:${numSteps},LeftMargin:${leftMargin}`)
|
||||
handle.css('margin-left', `${leftMargin}px`)
|
||||
originalSlider.val(handleText);
|
||||
originalSlider.trigger('input')
|
||||
originalSlider.trigger('change')
|
||||
} else {
|
||||
handle.text(ui.value.toFixed(decimals));
|
||||
var stepNumber = ((ui.value - sliderMin) / stepScale)
|
||||
var leftMargin = (stepNumber / numSteps) * 50 * -1
|
||||
handle.css('margin-left', `${leftMargin}px`)
|
||||
let handleText = (ui.value)
|
||||
originalSlider.val(handleText);
|
||||
originalSlider.trigger('input')
|
||||
originalSlider.trigger('change')
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
slide: handleSlideEvent
|
||||
});
|
||||
|
||||
function handleSlideEvent(event, ui, type) {
|
||||
var handle = $(this).find(".ui-slider-handle");
|
||||
var numVal = Number(ui.value).toFixed(decimals);
|
||||
offVal = Number(offVal).toFixed(decimals);
|
||||
var stepNumber = ((ui.value - sliderMin) / stepScale);
|
||||
var handleText = (ui.value);
|
||||
var leftMargin = (stepNumber / numSteps) * 50 * -1;
|
||||
var percentOfMax = Number((ui.value / sliderMax)) //what % our value is of the max
|
||||
var perStepPercent = 1 / numSteps //how far in % each step should be on the slider
|
||||
var leftPos = newSlider.width() * (stepNumber * perStepPercent) //how big of a left margin to give the slider for manual inputs
|
||||
|
||||
console.log(`
|
||||
numVal: ${numVal},
|
||||
offVal: ${offVal},
|
||||
initial value: ${handleText},
|
||||
stepNum: ${stepNumber},
|
||||
numSteps: ${numSteps},
|
||||
left-margin: ${leftMargin},
|
||||
width: ${newSlider.width()}
|
||||
percent of max: ${percentOfMax}
|
||||
left: ${leftPos}`)
|
||||
|
||||
//special handling for response length slider, pulls text aliases for step values from an array
|
||||
if (newSlider.attr('id') == 'amount_gen_zenslider') {
|
||||
handleText = steps[stepNumber]
|
||||
handle.text(handleText);
|
||||
newSlider.val(stepNumber)
|
||||
}
|
||||
//everything else uses the flat slider value
|
||||
else {
|
||||
//show 'off' if disabled value is set
|
||||
if (numVal === offVal) { handle.text('Off').css('color', 'rgba(128,128,128,0.5'); }
|
||||
else { handle.text(ui.value.toFixed(decimals)).css('color', ''); }
|
||||
newSlider.val(handleText)
|
||||
}
|
||||
//for manually typed-in values we must adjust left position because JQUI doesn't do it for us
|
||||
if (type === 'manual') { handle.css('left', leftPos) }
|
||||
//adjust a negative left margin to avoid overflowing right side of slider body
|
||||
handle.css('margin-left', `${leftMargin}px`);
|
||||
|
||||
originalSlider.val(handleText);
|
||||
originalSlider.trigger('input');
|
||||
originalSlider.trigger('change');
|
||||
}
|
||||
originalSlider.data("newSlider", newSlider);
|
||||
await delay(1)
|
||||
originalSlider.hide();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
function switchUiMode() {
|
||||
const fastUi = localStorage.getItem(storage_keys.fast_ui_mode);
|
||||
power_user.fast_ui_mode = fastUi === null ? true : fastUi == "true";
|
||||
@@ -1255,6 +1369,7 @@ function loadPowerUserSettings(settings, data) {
|
||||
$(`#chat_display option[value=${power_user.chat_display}]`).attr("selected", true).trigger('change');
|
||||
$('#chat_width_slider').val(power_user.chat_width);
|
||||
$("#token_padding").val(power_user.token_padding);
|
||||
$("#aux_field").val(power_user.aux_field);
|
||||
|
||||
$("#font_scale").val(power_user.font_scale);
|
||||
$("#font_scale_counter").val(power_user.font_scale);
|
||||
@@ -1355,16 +1470,17 @@ function loadMaxContextUnlocked() {
|
||||
}
|
||||
|
||||
function switchMaxContextSize() {
|
||||
const elements = [$('#max_context'), $('#rep_pen_range'), $('#rep_pen_range_textgenerationwebui')];
|
||||
const elements = [$('#max_context'), $('#max_context_counter'), $('#rep_pen_range'), $('#rep_pen_range_textgenerationwebui')];
|
||||
const maxValue = power_user.max_context_unlocked ? MAX_CONTEXT_UNLOCKED : MAX_CONTEXT_DEFAULT;
|
||||
const minValue = power_user.max_context_unlocked ? maxContextMin : maxContextMin;
|
||||
const steps = power_user.max_context_unlocked ? unlockedMaxContextStep : maxContextStep;
|
||||
|
||||
for (const element of elements) {
|
||||
const id = element.attr('id');
|
||||
element.attr('max', maxValue);
|
||||
element.attr('step', steps);
|
||||
|
||||
if (element.attr('id') == 'max_context') {
|
||||
if (typeof id === 'string' && id?.indexOf('max_context') !== -1) {
|
||||
element.attr('min', minValue);
|
||||
}
|
||||
const value = Number(element.val());
|
||||
@@ -1550,7 +1666,7 @@ export function fuzzySearchWorldInfo(data, searchValue) {
|
||||
export function fuzzySearchTags(searchValue) {
|
||||
const fuse = new Fuse(tags, {
|
||||
keys: [
|
||||
{ name: 'name', weight: 1},
|
||||
{ name: 'name', weight: 1 },
|
||||
],
|
||||
includeScore: true,
|
||||
ignoreLocation: true,
|
||||
@@ -2690,28 +2806,31 @@ $(document).ready(() => {
|
||||
});
|
||||
|
||||
$("#enableZenSliders").on("input", function () {
|
||||
if (power_user.enableLabMode) {
|
||||
const value = !!$(this).prop('checked');
|
||||
if (power_user.enableLabMode === true && value === true) {
|
||||
//disallow zenSliders while Lab Mode is active
|
||||
toastr.warning('ZenSliders not allowed in Mad Lab Mode')
|
||||
$(this).prop('checked', false);
|
||||
toastr.warning('Disable Mad Lab Mode before enabling Zen Sliders')
|
||||
$(this).prop('checked', false).trigger('input');
|
||||
return
|
||||
}
|
||||
const value = !!$(this).prop('checked');
|
||||
power_user.enableZenSliders = value;
|
||||
localStorage.setItem(storage_keys.enableZenSliders, Boolean(power_user.enableZenSliders));
|
||||
saveSettingsDebounced();
|
||||
switchZenSliders();
|
||||
});
|
||||
|
||||
$("#enableLabMode").on("input", function () {
|
||||
if (power_user.enableZenSliders) {
|
||||
const value = !!$(this).prop('checked');
|
||||
if (power_user.enableZenSliders === true && value === true) {
|
||||
//disallow Lab Mode if ZenSliders are active
|
||||
toastr.warning('Mad Lab Mode not allowed while ZenSliders are active')
|
||||
$(this).prop('checked', false);
|
||||
toastr.warning('Disable Zen Sliders before enabling Mad Lab Mode')
|
||||
$(this).prop('checked', false).trigger('input');;
|
||||
return
|
||||
}
|
||||
const value = !!$(this).prop('checked');
|
||||
|
||||
power_user.enableLabMode = value;
|
||||
localStorage.setItem(storage_keys.enableLabMode, Boolean(power_user.enableLabMode));
|
||||
saveSettingsDebounced();
|
||||
switchLabMode();
|
||||
});
|
||||
|
||||
@@ -2825,13 +2944,20 @@ $(document).ready(() => {
|
||||
switchSimpleMode();
|
||||
});
|
||||
|
||||
$('#bogus_folders').on('input', function() {
|
||||
$('#bogus_folders').on('input', function () {
|
||||
const value = !!$(this).prop('checked');
|
||||
power_user.bogus_folders = value;
|
||||
saveSettingsDebounced();
|
||||
printCharacters(true);
|
||||
});
|
||||
|
||||
$('#aux_field').on('change', function () {
|
||||
const value = $(this).find(':selected').val();
|
||||
power_user.aux_field = String(value);
|
||||
saveSettingsDebounced();
|
||||
printCharacters(false);
|
||||
});
|
||||
|
||||
$(document).on('click', '#debug_table [data-debug-function]', function () {
|
||||
const functionId = $(this).data('debug-function');
|
||||
const functionRecord = debug_functions.find(f => f.functionId === functionId);
|
||||
|
@@ -227,7 +227,7 @@ async function loadWorldInfoData(name) {
|
||||
}
|
||||
|
||||
async function updateWorldInfoList() {
|
||||
var result = await fetch("/getsettings", {
|
||||
const result = await fetch("/getsettings", {
|
||||
method: "POST",
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({}),
|
||||
@@ -269,7 +269,15 @@ function sortEntries(data) {
|
||||
const sortRule = option.data('rule');
|
||||
const orderSign = sortOrder === 'asc' ? 1 : -1;
|
||||
|
||||
if (sortRule === 'priority') {
|
||||
if (sortRule === 'custom') {
|
||||
// First by display index, then by order, then by uid
|
||||
data.sort((a, b) => {
|
||||
const aValue = a.displayIndex;
|
||||
const bValue = b.displayIndex;
|
||||
|
||||
return (aValue - bValue || b.order - a.order || a.uid - b.uid);
|
||||
});
|
||||
} else if (sortRule === 'priority') {
|
||||
// First constant, then normal, then disabled. Then sort by order
|
||||
data.sort((a, b) => {
|
||||
const aValue = a.constant ? 0 : a.disable ? 2 : 1;
|
||||
@@ -375,7 +383,7 @@ function displayWorldEntries(name, data, navigation = navigation_option.none) {
|
||||
nextText: '>',
|
||||
formatNavigator: PAGINATION_TEMPLATE,
|
||||
showNavigator: true,
|
||||
callback: function (page) {
|
||||
callback: function (/** @type {object[]} */ page) {
|
||||
$("#world_popup_entries_list").empty();
|
||||
const keywordHeaders = `
|
||||
<div id="WIEntryHeaderTitlesPC" class="flex-container wide100p spaceBetween justifyCenter textAlignCenter" style="padding:0 2.5em;">
|
||||
@@ -399,6 +407,12 @@ function displayWorldEntries(name, data, navigation = navigation_option.none) {
|
||||
</small>
|
||||
</div>`
|
||||
const blocks = page.map(entry => getWorldEntry(name, data, entry)).filter(x => x);
|
||||
const isCustomOrder = $('#world_info_sort_order').find(':selected').data('rule') === 'custom';
|
||||
if (!isCustomOrder) {
|
||||
blocks.forEach(block => {
|
||||
block.find('.drag-handle').remove();
|
||||
});
|
||||
}
|
||||
$("#world_popup_entries_list").append(keywordHeaders);
|
||||
$("#world_popup_entries_list").append(blocks);
|
||||
},
|
||||
@@ -500,6 +514,8 @@ function displayWorldEntries(name, data, navigation = navigation_option.none) {
|
||||
delay: getSortableDelay(),
|
||||
handle: ".drag-handle",
|
||||
stop: async function (event, ui) {
|
||||
const firstEntryUid = $('#world_popup_entries_list .world_entry').first().data('uid');
|
||||
const minDisplayIndex = data?.entries[firstEntryUid]?.displayIndex ?? 0;
|
||||
$('#world_popup_entries_list .world_entry').each(function (index) {
|
||||
const uid = $(this).data('uid');
|
||||
|
||||
@@ -511,8 +527,8 @@ function displayWorldEntries(name, data, navigation = navigation_option.none) {
|
||||
return;
|
||||
}
|
||||
|
||||
item.displayIndex = index;
|
||||
setOriginalDataValue(data, uid, 'extensions.display_index', index);
|
||||
item.displayIndex = minDisplayIndex + index;
|
||||
setOriginalDataValue(data, uid, 'extensions.display_index', item.displayIndex);
|
||||
});
|
||||
|
||||
console.table(Object.keys(data.entries).map(uid => data.entries[uid]).map(x => ({ uid: x.uid, key: x.key.join(','), displayIndex: x.displayIndex })));
|
||||
@@ -587,7 +603,7 @@ function getWorldEntry(name, data, entry) {
|
||||
setOriginalDataValue(data, uid, "keys", data.entries[uid].key);
|
||||
saveWorldInfo(name, data);
|
||||
});
|
||||
keyInput.val(entry.key.join(",")).trigger("input");
|
||||
keyInput.val(entry.key.join(", ")).trigger("input");
|
||||
//initScrollHeight(keyInput);
|
||||
|
||||
// logic AND/NOT
|
||||
@@ -708,7 +724,7 @@ function getWorldEntry(name, data, entry) {
|
||||
saveWorldInfo(name, data);
|
||||
});
|
||||
|
||||
keySecondaryInput.val(entry.keysecondary.join(",")).trigger("input");
|
||||
keySecondaryInput.val(entry.keysecondary.join(", ")).trigger("input");
|
||||
initScrollHeight(keySecondaryInput);
|
||||
|
||||
// comment
|
||||
@@ -1582,9 +1598,7 @@ async function checkWorldInfo(chat, maxContext) {
|
||||
over_max = (
|
||||
world_info_min_activations_depth_max > 0 &&
|
||||
minActivationMsgIndex > world_info_min_activations_depth_max
|
||||
) || (
|
||||
minActivationMsgIndex >= chat.length
|
||||
)
|
||||
) || (minActivationMsgIndex >= chat.length)
|
||||
if (!over_max) {
|
||||
needsToScan = true
|
||||
textToScan = transformString(chat.slice(minActivationMsgIndex, minActivationMsgIndex + 1).join(""));
|
||||
@@ -2167,11 +2181,9 @@ jQuery(() => {
|
||||
updateEditor(navigation_option.previous);
|
||||
});
|
||||
|
||||
$('#world_info_sort_order').on('change', function (e) {
|
||||
if (e.target instanceof HTMLOptionElement) {
|
||||
localStorage.setItem(SORT_ORDER_KEY, e.target.value);
|
||||
}
|
||||
|
||||
$('#world_info_sort_order').on('change', function () {
|
||||
const value = String($(this).find(":selected").val());
|
||||
localStorage.setItem(SORT_ORDER_KEY, value);
|
||||
updateEditor(navigation_option.none);
|
||||
})
|
||||
|
||||
|
@@ -1383,7 +1383,8 @@ select option:not(:checked) {
|
||||
|
||||
.menu_button.disabled {
|
||||
filter: brightness(75%) grayscale(1);
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.fav_on {
|
||||
@@ -3491,14 +3492,6 @@ a {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.prompt_overridden,
|
||||
.jailbreak_overridden {
|
||||
color: var(--SmartThemeQuoteColor);
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.openai_restorable .right_menu_button img {
|
||||
height: 20px;
|
||||
}
|
||||
|
@@ -2764,8 +2764,8 @@ app.post("/getstatus_openai", jsonParser, async function (request, response_gets
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.log('Access Token is incorrect.');
|
||||
response_getstatus_openai.send({ error: true });
|
||||
console.log('OpenAI status check failed. Either Access Token is incorrect or API endpoint is down.');
|
||||
response_getstatus_openai.send({ error: true, can_bypass: true, data: { data: [] } });
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
@@ -37,6 +37,25 @@ function checkAssetFileName(inputFilename) {
|
||||
return path.normalize(inputFilename).replace(/^(\.\.(\/|\\|$))+/, '');;
|
||||
}
|
||||
|
||||
// Recursive function to get files
|
||||
function getFiles(dir, files = []) {
|
||||
// Get an array of all files and directories in the passed directory using fs.readdirSync
|
||||
const fileList = fs.readdirSync(dir);
|
||||
// Create the full path of the file/directory by concatenating the passed directory and file/directory name
|
||||
for (const file of fileList) {
|
||||
const name = `${dir}/${file}`;
|
||||
// Check if the current file/directory is a directory using fs.statSync
|
||||
if (fs.statSync(name).isDirectory()) {
|
||||
// If it is a directory, recursively call the getFiles function with the directory path and the files array
|
||||
getFiles(name, files);
|
||||
} else {
|
||||
// If it is a file, push the full path to the files array
|
||||
files.push(name);
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the endpoints for the asset management.
|
||||
* @param {import('express').Express} app Express app
|
||||
@@ -70,16 +89,14 @@ function registerEndpoints(app, jsonParser) {
|
||||
// Live2d assets
|
||||
if (folder == "live2d") {
|
||||
output[folder] = [];
|
||||
const live2d_folders = fs.readdirSync(path.join(folderPath, folder));
|
||||
for (let model_folder of live2d_folders) {
|
||||
const live2d_model_path = path.join(folderPath, folder, model_folder);
|
||||
if (fs.statSync(live2d_model_path).isDirectory()) {
|
||||
for (let file of fs.readdirSync(live2d_model_path)) {
|
||||
if (file.includes("model")) {
|
||||
//console.debug("Asset live2d model found:",file)
|
||||
output[folder].push([`${model_folder}`, path.join("assets", folder, model_folder, file)]);
|
||||
}
|
||||
}
|
||||
const live2d_folder = path.normalize(path.join(folderPath, folder));
|
||||
const files = getFiles(live2d_folder);
|
||||
//console.debug("FILE FOUND:",files)
|
||||
for (let file of files) {
|
||||
file = path.normalize(file.replace('public' + path.sep, ''));
|
||||
if (file.endsWith("model3.json")) {
|
||||
//console.debug("Asset live2d model found:",file)
|
||||
output[folder].push(path.normalize(path.join(file)));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
@@ -257,7 +274,7 @@ function registerEndpoints(app, jsonParser) {
|
||||
for (let file of fs.readdirSync(live2dModelPath)) {
|
||||
//console.debug("Character live2d model found:", file)
|
||||
if (file.includes("model"))
|
||||
output.push([`${modelFolder}`, path.join("characters", name, category, modelFolder, file)]);
|
||||
output.push(path.join("characters", name, category, modelFolder, file));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -63,6 +63,45 @@ function registerEndpoints(app, jsonParser) {
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/openai/generate-voice', jsonParser, async (request, response) => {
|
||||
try {
|
||||
const key = readSecret(SECRET_KEYS.OPENAI);
|
||||
|
||||
if (!key) {
|
||||
console.log('No OpenAI key found');
|
||||
return response.sendStatus(401);
|
||||
}
|
||||
|
||||
const result = await fetch('https://api.openai.com/v1/audio/speech', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${key}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
input: request.body.text,
|
||||
response_format: 'mp3',
|
||||
voice: request.body.voice ?? 'alloy',
|
||||
speed: request.body.speed ?? 1,
|
||||
model: request.body.model ?? 'tts-1',
|
||||
}),
|
||||
});
|
||||
|
||||
if (!result.ok) {
|
||||
const text = await result.text();
|
||||
console.log('OpenAI request failed', result.statusText, text);
|
||||
return response.status(500).send(text);
|
||||
}
|
||||
|
||||
const buffer = await result.arrayBuffer();
|
||||
response.setHeader('Content-Type', 'audio/mpeg');
|
||||
return response.send(Buffer.from(buffer));
|
||||
} catch (error) {
|
||||
console.error('OpenAI TTS generation failed', error);
|
||||
response.status(500).send('Internal server error');
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/api/openai/generate-image', jsonParser, async (request, response) => {
|
||||
try {
|
||||
const key = readSecret(SECRET_KEYS.OPENAI);
|
||||
|
Reference in New Issue
Block a user