Merge branch 'staging' into parser-v2
This commit is contained in:
commit
2ec8640870
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "Adventure"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "\n\n",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "Alpaca-Roleplay"
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "Alpaca-Single-Turn"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "\n\n",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "Alpaca"
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "<|im_end|>\n",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "ChatML"
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": true,
|
||||
"last_system_sequence": "",
|
||||
"name": "DreamGen Role-Play V1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": true,
|
||||
"last_system_sequence": "",
|
||||
"name": "Koala"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "Libra-32B"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": true,
|
||||
"last_system_sequence": "",
|
||||
"name": "Lightning 1.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.",
|
||||
"system_same_as_user": true,
|
||||
"last_system_sequence": "",
|
||||
"name": "Llama 2 Chat"
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": true,
|
||||
"last_system_sequence": "",
|
||||
"name": "Metharme"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.",
|
||||
"system_same_as_user": true,
|
||||
"last_system_sequence": "",
|
||||
"name": "Mistral"
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "OpenOrca-OpenChat"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": true,
|
||||
"last_system_sequence": "",
|
||||
"name": "Pygmalion"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "Story"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "\n",
|
||||
"user_alignment_message": "Let's get started. Please respond based on the information and instructions provided above.",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "Synthia"
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": true,
|
||||
"last_system_sequence": "",
|
||||
"name": "Vicuna 1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": true,
|
||||
"last_system_sequence": "",
|
||||
"name": "Vicuna 1.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": true,
|
||||
"last_system_sequence": "",
|
||||
"name": "WizardLM-13B"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "WizardLM"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,5 +19,6 @@
|
|||
"system_suffix": "",
|
||||
"user_alignment_message": "",
|
||||
"system_same_as_user": false,
|
||||
"last_system_sequence": "",
|
||||
"name": "simple-proxy-for-tavern"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -439,3 +439,11 @@ body.expandMessageActions .mes .mes_buttons .extraMesButtonsHint {
|
|||
#openai_image_inlining:checked~#image_inlining_hint {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#smooth_streaming:not(:checked)~#smooth_streaming_speed_control {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#smooth_streaming:checked~#smooth_streaming_speed_control {
|
||||
display: block;
|
||||
}
|
||||
|
|
|
@ -1953,10 +1953,6 @@
|
|||
<div data-for="api_key_novel" class="neutral_warning" data-i18n="For privacy reasons, your API key will be hidden after you reload the page.">
|
||||
For privacy reasons, your API key will be hidden after you reload the page.
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<div id="api_button_novel" class="api_button menu_button" type="submit" data-i18n="Connect">Connect</div>
|
||||
<div class="api_loading menu_button" data-i18n="Cancel">Cancel</div>
|
||||
</div>
|
||||
<h4><span data-i18n="Novel AI Model">Novel AI Model</span>
|
||||
<a href="https://docs.sillytavern.app/usage/api-connections/novelai/#models" class="notes-link" target="_blank">
|
||||
<span class="fa-solid fa-circle-question note-link-span"></span>
|
||||
|
@ -1966,6 +1962,10 @@
|
|||
<option value="clio-v1">Clio</option>
|
||||
<option value="kayra-v1">Kayra</option>
|
||||
</select>
|
||||
<div class="flex-container">
|
||||
<div id="api_button_novel" class="api_button menu_button" type="submit" data-i18n="Connect">Connect</div>
|
||||
<div class="api_loading menu_button" data-i18n="Cancel">Cancel</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="online_status">
|
||||
<div class="online_status_indicator"></div>
|
||||
|
@ -2489,6 +2489,20 @@
|
|||
</div>
|
||||
</form>
|
||||
<form id="openrouter_form" data-source="openrouter" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||
<h4 data-i18n="OpenRouter API Key">OpenRouter API Key</h4>
|
||||
<div>
|
||||
<small data-i18n="Click Authorize below or get the key from">
|
||||
Click "Authorize" below or get the key from </small> <a target="_blank" href="https://openrouter.ai/keys/">OpenRouter</a>.
|
||||
<br>
|
||||
<a href="https://openrouter.ai/account" target="_blank" data-i18n="View Remaining Credits">View Remaining Credits</a>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<input id="api_key_openrouter" name="api_key_openrouter" class="text_pole flex1 api_key_openrouter" maxlength="500" value="" type="text" autocomplete="off">
|
||||
<div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_openrouter"></div>
|
||||
</div>
|
||||
<div data-for="api_key_openrouter" class="neutral_warning">
|
||||
For privacy reasons, your API key will be hidden after you reload the page.
|
||||
</div>
|
||||
<div>
|
||||
<h4 data-i18n="OpenRouter Model">OpenRouter Model</h4>
|
||||
<select id="model_openrouter_select">
|
||||
|
@ -2552,20 +2566,6 @@
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<h4 data-i18n="OpenRouter API Key">OpenRouter API Key</h4>
|
||||
<div>
|
||||
<small data-i18n="Click Authorize below or get the key from">
|
||||
Click "Authorize" below or get the key from </small> <a target="_blank" href="https://openrouter.ai/keys/">OpenRouter</a>.
|
||||
<br>
|
||||
<a href="https://openrouter.ai/account" target="_blank" data-i18n="View Remaining Credits">View Remaining Credits</a>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<input id="api_key_openrouter" name="api_key_openrouter" class="text_pole flex1 api_key_openrouter" maxlength="500" value="" type="text" autocomplete="off">
|
||||
<div title="Clear your API key" data-i18n="[title]Clear your API key" class="menu_button fa-solid fa-circle-xmark clear-api-key" data-key="api_key_openrouter"></div>
|
||||
</div>
|
||||
<div data-for="api_key_openrouter" class="neutral_warning">
|
||||
For privacy reasons, your API key will be hidden after you reload the page.
|
||||
</div>
|
||||
</form>
|
||||
<form id="scale_form" data-source="scale" action="javascript:void(null);" method="post" enctype="multipart/form-data">
|
||||
<div id="normal_scale_form">
|
||||
|
@ -2691,6 +2691,7 @@
|
|||
<option value="command-light">command-light</option>
|
||||
<option value="command">command</option>
|
||||
<option value="command-r">command-r</option>
|
||||
<option value="command-r-plus">command-r-plus</option>
|
||||
</optgroup>
|
||||
<optgroup label="Nightly">
|
||||
<option value="command-light-nightly">command-light-nightly</option>
|
||||
|
@ -3033,12 +3034,12 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<div class="flex1" title="Will be inserted at the start of the chat history if it doesn't start with a User message.">
|
||||
<label for="instruct_user_alignment_message">
|
||||
<small data-i18n="User Filler Message">User Filler Message</small>
|
||||
<div class="flex1" title="Will be inserted as a last prompt line when using system/neutral generation.">
|
||||
<label for="instruct_last_system_sequence">
|
||||
<small data-i18n="System Instruction Prefix">System Instruction Prefix</small>
|
||||
</label>
|
||||
<div>
|
||||
<textarea id="instruct_user_alignment_message" class="text_pole textarea_compact autoSetHeight" maxlength="2000" placeholder="—" rows="1"></textarea>
|
||||
<textarea id="instruct_last_system_sequence" class="text_pole textarea_compact autoSetHeight" maxlength="2000" placeholder="—" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1" title="If a stop sequence is generated, everything past it will be removed from the output (inclusive).">
|
||||
|
@ -3050,6 +3051,16 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<div class="flex1" title="Will be inserted at the start of the chat history if it doesn't start with a User message.">
|
||||
<label for="instruct_user_alignment_message">
|
||||
<small data-i18n="User Filler Message">User Filler Message</small>
|
||||
</label>
|
||||
<div>
|
||||
<textarea id="instruct_user_alignment_message" class="text_pole textarea_compact autoSetHeight" maxlength="2000" placeholder="—" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3618,6 +3629,24 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label class="checkbox_label flexWrap" for="smooth_streaming">
|
||||
<input id="smooth_streaming" type="checkbox" />
|
||||
<div class="flex-container alignItemsBaseline">
|
||||
<span data-i18n="Smooth Streaming">
|
||||
Smooth Streaming
|
||||
</span>
|
||||
<i class="fa-solid fa-flask" title="Experimental feature. May not work for all backends."></i>
|
||||
</div>
|
||||
<div id="smooth_streaming_speed_control" class="flexBasis100p wide100p">
|
||||
<small class="flex justifyCenter" data-i18n="Speed">Speed</small>
|
||||
<input type="range" id="smooth_streaming_speed" name="smooth_streaming_speed" min="0" max="100" step="10" value="50">
|
||||
<div class="slider_hint">
|
||||
<span data-i18n="Slow">Slow</span>
|
||||
<span data-i18n=""></span>
|
||||
<span data-i18n="Slow">Fast</span>
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -4247,12 +4276,21 @@
|
|||
</div>
|
||||
<div id="descriptionWrapper" class="flex-container flexFlowColumn flex1">
|
||||
<hr>
|
||||
<div id="description_div" class="flex-container alignitemscenter">
|
||||
<span data-i18n="Character Description">Description</span>
|
||||
<i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="description_textarea" title="Expand the editor"></i>
|
||||
<a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#character-description" class="notes-link" target="_blank">
|
||||
<span class="fa-solid fa-circle-question note-link-span"></span>
|
||||
</a>
|
||||
<div id="description_div" class="title_restorable">
|
||||
<div class="flex-container alignitemscenter">
|
||||
<span data-i18n="Character Description">Description</span>
|
||||
<i class="editor_maximize fa-solid fa-maximize right_menu_button" data-for="description_textarea" title="Expand the editor"></i>
|
||||
<a href="https://docs.sillytavern.app/usage/core-concepts/characterdesign/#character-description" class="notes-link" target="_blank">
|
||||
<span class="fa-solid fa-circle-question note-link-span"></span>
|
||||
</a>
|
||||
</div>
|
||||
<div id="character_open_media_overrides" class="menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this character." data-i18n="[title]Click to allow/forbid the use of external media for this character.">
|
||||
<i id="character_media_allowed_icon" class="fa-solid fa-fw fa-link"></i>
|
||||
<i id="character_media_forbidden_icon" class="fa-solid fa-fw fa-link-slash"></i>
|
||||
<span data-i18n="Ext. Media">
|
||||
Ext. Media
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="description_textarea" data-i18n="[placeholder]Describe your character's physical and mental traits here." placeholder="Describe your character's physical and mental traits here." name="description" placeholder=""></textarea>
|
||||
<div class="extension_token_counter">
|
||||
|
@ -4352,6 +4390,10 @@
|
|||
<div id="rm_group_scenario" class="heightFitContent margin0 menu_button fa-solid fa-scroll" title="Set a group chat scenario" data-i18n="[title]Set a group chat scenario"></div>
|
||||
<div id="group_favorite_button" class="heightFitContent margin0 menu_button fa-solid fa-star" title="Add to Favorites" data-i18n="[title]Add to Favorites"></div>
|
||||
<input id="rm_group_fav" type="hidden" />
|
||||
<div id="group_open_media_overrides" class="heightFitContent margin0 menu_button menu_button_icon open_media_overrides" title="Click to allow/forbid the use of external media for this group." data-i18n="[title]Click to allow/forbid the use of external media for this group.">
|
||||
<i id="group_media_allowed_icon" class="fa-solid fa-fw fa-link"></i>
|
||||
<i id="group_media_forbidden_icon" class="fa-solid fa-fw fa-link-slash"></i>
|
||||
</div>
|
||||
<div id="rm_group_submit" class="heightFitContent margin0 menu_button fa-solid fa-check" title="Create" data-i18n="[title]Create"></div>
|
||||
<div id="rm_group_restore_avatar" class="heightFitContent margin0 menu_button fa-solid fa-images" title="Restore collage avatar" data-i18n="[title]Restore collage avatar"></div>
|
||||
<div id="rm_group_delete" class="heightFitContent margin0 menu_button fa-solid fa-trash-can" title="Delete" data-i18n="[title]Delete"></div>
|
||||
|
@ -4804,7 +4846,7 @@
|
|||
<div class="flex-container alignitemscenter wide100p">
|
||||
<div class="WIEntryTitleAndStatus flex-container flex1 alignitemscenter">
|
||||
<div class="flex-container flex1">
|
||||
<textarea class="text_pole autoSetHeight" name="comment" maxlength="5000" data-i18n="[placeholder]Entry Title/Memo" placeholder="Entry Title/Memo"></textarea>
|
||||
<textarea class="text_pole" rows="1" name="comment" maxlength="5000" data-i18n="[placeholder]Entry Title/Memo" placeholder="Entry Title/Memo"></textarea>
|
||||
</div>
|
||||
<!-- <span class="world_entry_form_position_value"></span> -->
|
||||
<select data-i18n="[title]WI Entry Status:🔵 Constant🟢 Normal❌ Disabled" title="WI Entry Status: 🔵 Constant 🟢 Normal ❌ Disabled" name="entryStateSelector" class="text_pole widthNatural margin0">
|
||||
|
@ -5359,6 +5401,32 @@
|
|||
<textarea name="alternate_greetings" data-i18n="[placeholder](This will be the first message from the character that starts every chat)" placeholder="(This will be the first message from the character that starts every chat)" class="text_pole textarea_compact alternate_greeting_text" maxlength="50000" value="" autocomplete="off" rows="16"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div id="forbid_media_override_template" class="template_element">
|
||||
<div class="forbid_media_override flex-container flexFlowColumn">
|
||||
<h4 data-i18n="Forbid Media Override explanation" class="margin0">
|
||||
Ability of the current character/group to use external media in chats.
|
||||
</h4>
|
||||
<small data-i18n="Forbid Media Override subtitle" class="marginBot5">
|
||||
Media: images, videos, audio. External: not hosted on the local server.
|
||||
</small>
|
||||
<label class="checkbox_label" for="forbid_media_override_global">
|
||||
<input type="radio" id="forbid_media_override_global" name="forbid_media_override" />
|
||||
<span>
|
||||
<span data-i18n="Use global setting">Use global setting</span>
|
||||
<b class="forbid_media_global_state_forbidden">(forbidden)</b>
|
||||
<b class="forbid_media_global_state_allowed">(allowed)</b>
|
||||
</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="forbid_media_override_forbidden">
|
||||
<input type="radio" id="forbid_media_override_forbidden" name="forbid_media_override" />
|
||||
<span data-i18n="Always forbidden">Always forbidden</span>
|
||||
</label>
|
||||
<label class="checkbox_label" for="forbid_media_override_allowed">
|
||||
<input type="radio" id="forbid_media_override_allowed" name="forbid_media_override" />
|
||||
<span data-i18n="Always allowed">Always allowed</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- chat and input bar -->
|
||||
<div id="typing_indicator_template" class="template_element">
|
||||
<div class="typing_indicator"><span class="typing_indicator_name">CHAR</span> is typing</div>
|
||||
|
|
|
@ -29,6 +29,12 @@ var EventEmitter = function () {
|
|||
};
|
||||
|
||||
EventEmitter.prototype.on = function (event, listener) {
|
||||
// Unknown event used by external libraries?
|
||||
if (event === undefined) {
|
||||
console.trace('EventEmitter: Cannot listen to undefined event');
|
||||
return;
|
||||
}
|
||||
|
||||
if (typeof this.events[event] !== 'object') {
|
||||
this.events[event] = [];
|
||||
}
|
||||
|
|
186
public/script.js
186
public/script.js
|
@ -208,7 +208,7 @@ import { getBackgrounds, initBackgrounds, loadBackgroundSettings, background_set
|
|||
import { hideLoader, showLoader } from './scripts/loader.js';
|
||||
import { BulkEditOverlay, CharacterContextMenu } from './scripts/BulkEditOverlay.js';
|
||||
import { loadMancerModels, loadOllamaModels, loadTogetherAIModels, loadInfermaticAIModels, loadOpenRouterModels, loadAphroditeModels, loadDreamGenModels } from './scripts/textgen-models.js';
|
||||
import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags } from './scripts/chats.js';
|
||||
import { appendFileContent, hasPendingFileAttachment, populateFileAttachment, decodeStyleTags, encodeStyleTags, isExternalMediaAllowed, getCurrentEntityId } from './scripts/chats.js';
|
||||
import { initPresetManager } from './scripts/preset-manager.js';
|
||||
import { evaluateMacros } from './scripts/macros.js';
|
||||
|
||||
|
@ -324,10 +324,13 @@ DOMPurify.addHook('uponSanitizeElement', (node, _, config) => {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!power_user.forbid_external_images) {
|
||||
const isMediaAllowed = isExternalMediaAllowed();
|
||||
if (isMediaAllowed) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mediaBlocked = false;
|
||||
|
||||
switch (node.tagName) {
|
||||
case 'AUDIO':
|
||||
case 'VIDEO':
|
||||
|
@ -350,6 +353,7 @@ DOMPurify.addHook('uponSanitizeElement', (node, _, config) => {
|
|||
if (isExternalUrl(url)) {
|
||||
console.warn('External media blocked', url);
|
||||
node.remove();
|
||||
mediaBlocked = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -357,16 +361,37 @@ DOMPurify.addHook('uponSanitizeElement', (node, _, config) => {
|
|||
|
||||
if (src && isExternalUrl(src)) {
|
||||
console.warn('External media blocked', src);
|
||||
mediaBlocked = true;
|
||||
node.remove();
|
||||
}
|
||||
|
||||
if (data && isExternalUrl(data)) {
|
||||
console.warn('External media blocked', data);
|
||||
mediaBlocked = true;
|
||||
node.remove();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (mediaBlocked) {
|
||||
const entityId = getCurrentEntityId();
|
||||
const warningShownKey = `mediaWarningShown:${entityId}`;
|
||||
|
||||
if (localStorage.getItem(warningShownKey) === null) {
|
||||
const warningToast = toastr.warning(
|
||||
'Use the "Ext. Media" button to allow it. Click on this message to dismiss.',
|
||||
'External media has been blocked',
|
||||
{
|
||||
timeOut: 0,
|
||||
preventDuplicates: true,
|
||||
onclick: () => toastr.clear(warningToast),
|
||||
},
|
||||
);
|
||||
|
||||
localStorage.setItem(warningShownKey, 'true');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// API OBJECT FOR EXTERNAL WIRING
|
||||
|
@ -416,6 +441,7 @@ export const event_types = {
|
|||
// TODO: Naming convention is inconsistent with other events
|
||||
CHARACTER_DELETED: 'characterDeleted',
|
||||
CHARACTER_DUPLICATED: 'character_duplicated',
|
||||
SMOOTH_STREAM_TOKEN_RECEIVED: 'smooth_stream_token_received',
|
||||
};
|
||||
|
||||
export const eventSource = new EventEmitter();
|
||||
|
@ -751,7 +777,6 @@ function reloadMarkdownProcessor(render_formulas = false) {
|
|||
}
|
||||
|
||||
function getCurrentChatId() {
|
||||
console.debug(`selectedGroup:${selected_group}, this_chid:${this_chid}`);
|
||||
if (selected_group) {
|
||||
return groups.find(x => x.id == selected_group)?.chat_id;
|
||||
}
|
||||
|
@ -1692,7 +1717,7 @@ export async function reloadCurrentChat() {
|
|||
chat.length = 0;
|
||||
|
||||
if (selected_group) {
|
||||
await getGroupChat(selected_group);
|
||||
await getGroupChat(selected_group, true);
|
||||
}
|
||||
else if (this_chid) {
|
||||
await getChat();
|
||||
|
@ -3032,8 +3057,8 @@ function saveResponseLength(api, responseLength) {
|
|||
oldValue = oai_settings.openai_max_tokens;
|
||||
oai_settings.openai_max_tokens = responseLength;
|
||||
} else {
|
||||
oldValue = max_context;
|
||||
max_context = responseLength;
|
||||
oldValue = amount_gen;
|
||||
amount_gen = responseLength;
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
|
@ -3048,7 +3073,7 @@ function restoreResponseLength(api, responseLength) {
|
|||
if (api === 'openai') {
|
||||
oai_settings.openai_max_tokens = responseLength;
|
||||
} else {
|
||||
max_context = responseLength;
|
||||
amount_gen = responseLength;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4058,6 +4083,10 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
|||
await streamingProcessor.onFinishStreaming(streamingProcessor.messageId, getMessage);
|
||||
streamingProcessor = null;
|
||||
triggerAutoContinue(messageChunk, isImpersonate);
|
||||
return Object.defineProperties(new String(getMessage), {
|
||||
'messageChunk': { value: messageChunk },
|
||||
'fromStream': { value: true },
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return await sendGenerationRequest(type, generate_data);
|
||||
|
@ -4068,6 +4097,11 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
|||
|
||||
async function onSuccess(data) {
|
||||
if (!data) return;
|
||||
|
||||
if (data?.fromStream) {
|
||||
return data;
|
||||
}
|
||||
|
||||
let messageChunk = '';
|
||||
|
||||
if (data.error) {
|
||||
|
@ -4177,6 +4211,9 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
|||
if (type !== 'quiet') {
|
||||
triggerAutoContinue(messageChunk, isImpersonate);
|
||||
}
|
||||
|
||||
// Don't break the API chain that expects a single string in return
|
||||
return Object.defineProperty(new String(getMessage), 'messageChunk', { value: messageChunk });
|
||||
}
|
||||
|
||||
function onError(exception) {
|
||||
|
@ -4271,57 +4308,81 @@ export function getNextMessageId(type) {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} messageChunk
|
||||
* @param {boolean} isImpersonate
|
||||
* @returns {void}
|
||||
* Determines if the message should be auto-continued.
|
||||
* @param {string} messageChunk Current message chunk
|
||||
* @param {boolean} isImpersonate Is the user impersonation
|
||||
* @returns {boolean} Whether the message should be auto-continued
|
||||
*/
|
||||
export function shouldAutoContinue(messageChunk, isImpersonate) {
|
||||
if (!power_user.auto_continue.enabled) {
|
||||
console.debug('Auto-continue is disabled by user.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeof messageChunk !== 'string') {
|
||||
console.debug('Not triggering auto-continue because message chunk is not a string');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isImpersonate) {
|
||||
console.log('Continue for impersonation is not implemented yet');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_send_press) {
|
||||
console.debug('Auto-continue is disabled because a message is currently being sent.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (power_user.auto_continue.target_length <= 0) {
|
||||
console.log('Auto-continue target length is 0, not triggering auto-continue');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (main_api === 'openai' && !power_user.auto_continue.allow_chat_completions) {
|
||||
console.log('Auto-continue for OpenAI is disabled by user.');
|
||||
return false;
|
||||
}
|
||||
|
||||
const textareaText = String($('#send_textarea').val());
|
||||
const USABLE_LENGTH = 5;
|
||||
|
||||
if (textareaText.length > 0) {
|
||||
console.log('Not triggering auto-continue because user input is not empty');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (messageChunk.trim().length > USABLE_LENGTH && chat.length) {
|
||||
const lastMessage = chat[chat.length - 1];
|
||||
const messageLength = getTokenCount(lastMessage.mes);
|
||||
const shouldAutoContinue = messageLength < power_user.auto_continue.target_length;
|
||||
|
||||
if (shouldAutoContinue) {
|
||||
console.log(`Triggering auto-continue. Message tokens: ${messageLength}. Target tokens: ${power_user.auto_continue.target_length}. Message chunk: ${messageChunk}`);
|
||||
return true;
|
||||
} else {
|
||||
console.log(`Not triggering auto-continue. Message tokens: ${messageLength}. Target tokens: ${power_user.auto_continue.target_length}`);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
console.log('Last generated chunk was empty, not triggering auto-continue');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers auto-continue if the message meets the criteria.
|
||||
* @param {string} messageChunk Current message chunk
|
||||
* @param {boolean} isImpersonate Is the user impersonation
|
||||
*/
|
||||
export function triggerAutoContinue(messageChunk, isImpersonate) {
|
||||
if (selected_group) {
|
||||
console.log('Auto-continue is disabled for group chat');
|
||||
console.debug('Auto-continue is disabled for group chat');
|
||||
return;
|
||||
}
|
||||
|
||||
if (power_user.auto_continue.enabled && !is_send_press) {
|
||||
if (power_user.auto_continue.target_length <= 0) {
|
||||
console.log('Auto-continue target length is 0, not triggering auto-continue');
|
||||
return;
|
||||
}
|
||||
|
||||
if (main_api === 'openai' && !power_user.auto_continue.allow_chat_completions) {
|
||||
console.log('Auto-continue for OpenAI is disabled by user.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (isImpersonate) {
|
||||
console.log('Continue for impersonation is not implemented yet');
|
||||
return;
|
||||
}
|
||||
|
||||
const textareaText = String($('#send_textarea').val());
|
||||
const USABLE_LENGTH = 5;
|
||||
|
||||
if (textareaText.length > 0) {
|
||||
console.log('Not triggering auto-continue because user input is not empty');
|
||||
return;
|
||||
}
|
||||
|
||||
if (messageChunk.trim().length > USABLE_LENGTH && chat.length) {
|
||||
const lastMessage = chat[chat.length - 1];
|
||||
const messageLength = getTokenCount(lastMessage.mes);
|
||||
const shouldAutoContinue = messageLength < power_user.auto_continue.target_length;
|
||||
|
||||
if (shouldAutoContinue) {
|
||||
console.log(`Triggering auto-continue. Message tokens: ${messageLength}. Target tokens: ${power_user.auto_continue.target_length}. Message chunk: ${messageChunk}`);
|
||||
$('#option_continue').trigger('click');
|
||||
} else {
|
||||
console.log(`Not triggering auto-continue. Message tokens: ${messageLength}. Target tokens: ${power_user.auto_continue.target_length}`);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
console.log('Last generated chunk was empty, not triggering auto-continue');
|
||||
return;
|
||||
}
|
||||
if (shouldAutoContinue(messageChunk, isImpersonate)) {
|
||||
$('#option_continue').trigger('click');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6863,6 +6924,12 @@ export function select_selected_character(chid) {
|
|||
|
||||
$('#form_create').attr('actiontype', 'editcharacter');
|
||||
$('.form_create_bottom_buttons_block .chat_lorebook_button').show();
|
||||
|
||||
const externalMediaState = isExternalMediaAllowed();
|
||||
$('#character_open_media_overrides').toggle(!selected_group);
|
||||
$('#character_media_allowed_icon').toggle(externalMediaState);
|
||||
$('#character_media_forbidden_icon').toggle(!externalMediaState);
|
||||
|
||||
saveSettingsDebounced();
|
||||
}
|
||||
|
||||
|
@ -6923,6 +6990,7 @@ function select_rm_create() {
|
|||
|
||||
$('#form_create').attr('actiontype', 'createcharacter');
|
||||
$('.form_create_bottom_buttons_block .chat_lorebook_button').hide();
|
||||
$('#character_open_media_overrides').hide();
|
||||
}
|
||||
|
||||
function select_rm_characters() {
|
||||
|
@ -8211,8 +8279,7 @@ const CONNECT_API_MAP = {
|
|||
|
||||
async function selectContextCallback(_, name) {
|
||||
if (!name) {
|
||||
toastr.warning('Context preset name is required');
|
||||
return '';
|
||||
return power_user.context.preset;
|
||||
}
|
||||
|
||||
const contextNames = context_presets.map(preset => preset.name);
|
||||
|
@ -8231,8 +8298,7 @@ async function selectContextCallback(_, name) {
|
|||
|
||||
async function selectInstructCallback(_, name) {
|
||||
if (!name) {
|
||||
toastr.warning('Instruct preset name is required');
|
||||
return '';
|
||||
return power_user.instruct.preset;
|
||||
}
|
||||
|
||||
const instructNames = instruct_presets.map(preset => preset.name);
|
||||
|
@ -8581,10 +8647,10 @@ jQuery(async function () {
|
|||
registerSlashCommand('closechat', doCloseChat, [], '– closes the current chat', true, true);
|
||||
registerSlashCommand('panels', doTogglePanels, ['togglepanels'], '– toggle UI panels on/off', true, true);
|
||||
registerSlashCommand('forcesave', doForceSave, [], '– forces a save of the current chat and settings', true, true);
|
||||
registerSlashCommand('instruct', selectInstructCallback, [], '<span class="monospace">(name)</span> – selects instruct mode preset by name', true, true);
|
||||
registerSlashCommand('instruct', selectInstructCallback, [], '<span class="monospace">(name)</span> – selects instruct mode preset by name. Gets the current instruct if no name is provided', true, true);
|
||||
registerSlashCommand('instruct-on', enableInstructCallback, [], '– enables instruct mode', true, true);
|
||||
registerSlashCommand('instruct-off', disableInstructCallback, [], '– disables instruct mode', true, true);
|
||||
registerSlashCommand('context', selectContextCallback, [], '<span class="monospace">(name)</span> – selects context template by name', true, true);
|
||||
registerSlashCommand('context', selectContextCallback, [], '<span class="monospace">(name)</span> – selects context template by name. Gets the current template if no name is provided', true, true);
|
||||
registerSlashCommand('chat-manager', () => $('#option_select_chat').trigger('click'), ['chat-history', 'manage-chats'], '– opens the chat manager for the current character/group', true, true);
|
||||
|
||||
setTimeout(function () {
|
||||
|
@ -9873,14 +9939,14 @@ jQuery(async function () {
|
|||
$('#character_import_file').click();
|
||||
});
|
||||
|
||||
$('#character_import_file').on('change', function (e) {
|
||||
$('#character_import_file').on('change', async function (e) {
|
||||
$('#rm_info_avatar').html('');
|
||||
if (!e.target.files.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const file of e.target.files) {
|
||||
importCharacter(file);
|
||||
await importCharacter(file);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
addCopyToCodeBlocks,
|
||||
appendMediaToMessage,
|
||||
callPopup,
|
||||
characters,
|
||||
chat,
|
||||
eventSource,
|
||||
event_types,
|
||||
|
@ -12,9 +13,14 @@ import {
|
|||
getRequestHeaders,
|
||||
hideSwipeButtons,
|
||||
name2,
|
||||
reloadCurrentChat,
|
||||
saveChatDebounced,
|
||||
saveSettingsDebounced,
|
||||
showSwipeButtons,
|
||||
this_chid,
|
||||
} from '../script.js';
|
||||
import { selected_group } from './group-chats.js';
|
||||
import { power_user } from './power-user.js';
|
||||
import {
|
||||
extractTextFromHTML,
|
||||
extractTextFromMarkdown,
|
||||
|
@ -416,6 +422,56 @@ export function decodeStyleTags(text) {
|
|||
});
|
||||
}
|
||||
|
||||
async function openExternalMediaOverridesDialog() {
|
||||
const entityId = getCurrentEntityId();
|
||||
|
||||
if (!entityId) {
|
||||
toastr.info('No character or group selected');
|
||||
return;
|
||||
}
|
||||
|
||||
const template = $('#forbid_media_override_template > .forbid_media_override').clone();
|
||||
template.find('.forbid_media_global_state_forbidden').toggle(power_user.forbid_external_images);
|
||||
template.find('.forbid_media_global_state_allowed').toggle(!power_user.forbid_external_images);
|
||||
|
||||
if (power_user.external_media_allowed_overrides.includes(entityId)) {
|
||||
template.find('#forbid_media_override_allowed').prop('checked', true);
|
||||
}
|
||||
else if (power_user.external_media_forbidden_overrides.includes(entityId)) {
|
||||
template.find('#forbid_media_override_forbidden').prop('checked', true);
|
||||
}
|
||||
else {
|
||||
template.find('#forbid_media_override_global').prop('checked', true);
|
||||
}
|
||||
|
||||
callPopup(template, 'text', '', { wide: false, large: false });
|
||||
}
|
||||
|
||||
export function getCurrentEntityId() {
|
||||
if (selected_group) {
|
||||
return String(selected_group);
|
||||
}
|
||||
|
||||
return characters[this_chid]?.avatar ?? null;
|
||||
}
|
||||
|
||||
export function isExternalMediaAllowed() {
|
||||
const entityId = getCurrentEntityId();
|
||||
if (!entityId) {
|
||||
return !power_user.forbid_external_images;
|
||||
}
|
||||
|
||||
if (power_user.external_media_allowed_overrides.includes(entityId)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (power_user.external_media_forbidden_overrides.includes(entityId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !power_user.forbid_external_images;
|
||||
}
|
||||
|
||||
jQuery(function () {
|
||||
$(document).on('click', '.mes_hide', async function () {
|
||||
const messageBlock = $(this).closest('.mes');
|
||||
|
@ -511,6 +567,32 @@ jQuery(function () {
|
|||
$(this).closest('.mes').find('.mes_edit').trigger('click');
|
||||
});
|
||||
|
||||
$(document).on('click', '.open_media_overrides', openExternalMediaOverridesDialog);
|
||||
$(document).on('input', '#forbid_media_override_allowed', function () {
|
||||
const entityId = getCurrentEntityId();
|
||||
if (!entityId) return;
|
||||
power_user.external_media_allowed_overrides.push(entityId);
|
||||
power_user.external_media_forbidden_overrides = power_user.external_media_forbidden_overrides.filter((v) => v !== entityId);
|
||||
saveSettingsDebounced();
|
||||
reloadCurrentChat();
|
||||
});
|
||||
$(document).on('input', '#forbid_media_override_forbidden', function () {
|
||||
const entityId = getCurrentEntityId();
|
||||
if (!entityId) return;
|
||||
power_user.external_media_forbidden_overrides.push(entityId);
|
||||
power_user.external_media_allowed_overrides = power_user.external_media_allowed_overrides.filter((v) => v !== entityId);
|
||||
saveSettingsDebounced();
|
||||
reloadCurrentChat();
|
||||
});
|
||||
$(document).on('input', '#forbid_media_override_global', function () {
|
||||
const entityId = getCurrentEntityId();
|
||||
if (!entityId) return;
|
||||
power_user.external_media_allowed_overrides = power_user.external_media_allowed_overrides.filter((v) => v !== entityId);
|
||||
power_user.external_media_forbidden_overrides = power_user.external_media_forbidden_overrides.filter((v) => v !== entityId);
|
||||
saveSettingsDebounced();
|
||||
reloadCurrentChat();
|
||||
});
|
||||
|
||||
$('#file_form_input').on('change', onFileAttach);
|
||||
$('#file_form').on('reset', function () {
|
||||
$('#file_form').addClass('displayNone');
|
||||
|
|
|
@ -354,15 +354,15 @@ jQuery(function () {
|
|||
<div class="flex1 flex-container flexFlowColumn flexNoGap">
|
||||
<label for="caption_multimodal_api">API</label>
|
||||
<select id="caption_multimodal_api" class="flex1 text_pole">
|
||||
<option value="llamacpp">llama.cpp</option>
|
||||
<option value="ooba">Text Generation WebUI (oobabooga)</option>
|
||||
<option value="anthropic">Anthropic</option>
|
||||
<option value="custom">Custom (OpenAI-compatible)</option>
|
||||
<option value="google">Google MakerSuite</option>
|
||||
<option value="koboldcpp">KoboldCpp</option>
|
||||
<option value="llamacpp">llama.cpp</option>
|
||||
<option value="ollama">Ollama</option>
|
||||
<option value="openai">OpenAI</option>
|
||||
<option value="anthropic">Anthropic</option>
|
||||
<option value="openrouter">OpenRouter</option>
|
||||
<option value="google">Google MakerSuite</option>
|
||||
<option value="custom">Custom (OpenAI-compatible)</option>
|
||||
<option value="ooba">Text Generation WebUI (oobabooga)</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex1 flex-container flexFlowColumn flexNoGap">
|
||||
|
@ -375,6 +375,14 @@ jQuery(function () {
|
|||
<option data-type="google" value="gemini-pro-vision">gemini-pro-vision</option>
|
||||
<option data-type="openrouter" value="openai/gpt-4-vision-preview">openai/gpt-4-vision-preview</option>
|
||||
<option data-type="openrouter" value="haotian-liu/llava-13b">haotian-liu/llava-13b</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-haiku">anthropic/claude-3-haiku</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-sonnet">anthropic/claude-3-sonnet</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-opus">anthropic/claude-3-opus</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-haiku:beta">anthropic/claude-3-haiku:beta</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-sonnet:beta">anthropic/claude-3-sonnet:beta</option>
|
||||
<option data-type="openrouter" value="anthropic/claude-3-opus:beta">anthropic/claude-3-opus:beta</option>
|
||||
<option data-type="openrouter" value="nousresearch/nous-hermes-2-vision-7b">nousresearch/nous-hermes-2-vision-7b</option>
|
||||
<option data-type="openrouter" value="google/gemini-pro-vision">google/gemini-pro-vision</option>
|
||||
<option data-type="ollama" value="ollama_current">[Currently selected]</option>
|
||||
<option data-type="ollama" value="bakllava:latest">bakllava:latest</option>
|
||||
<option data-type="ollama" value="llava:latest">llava:latest</option>
|
||||
|
|
|
@ -91,7 +91,7 @@ const defaultSettings = {
|
|||
maxMessagesPerRequestMin: 0,
|
||||
maxMessagesPerRequestMax: 250,
|
||||
maxMessagesPerRequestStep: 1,
|
||||
prompt_builder: prompt_builders.RAW_BLOCKING,
|
||||
prompt_builder: prompt_builders.DEFAULT,
|
||||
};
|
||||
|
||||
function loadSettings() {
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
<input type="checkbox" id="qr--executeOnGroupMemberDraft">
|
||||
<span><i class="fa-solid fa-fw fa-people-group"></i> Execute before group member message</span>
|
||||
</label>
|
||||
<div class="flex-container alignItemsBaseline" title="Activate this quick reply when a World Info entry with the same Automation ID is triggered.">
|
||||
<div class="flex-container alignItemsBaseline flexFlowColumn flexNoGap" title="Activate this quick reply when a World Info entry with the same Automation ID is triggered.">
|
||||
<small>Automation ID</small>
|
||||
<input type="text" id="qr--automationId" class="text_pole flex1" placeholder="( None )">
|
||||
</div>
|
||||
|
|
|
@ -104,7 +104,7 @@ const loadSets = async () => {
|
|||
qr.executeOnAi = slot.autoExecute_botMessage ?? false;
|
||||
qr.executeOnChatChange = slot.autoExecute_chatLoad ?? false;
|
||||
qr.executeOnGroupMemberDraft = slot.autoExecute_groupMemberDraft ?? false;
|
||||
qr.automationId = slot.automationId ?? false;
|
||||
qr.automationId = slot.automationId ?? '';
|
||||
qr.contextList = (slot.contextMenu ?? []).map(it=>({
|
||||
set: it.preset,
|
||||
isChained: it.chain,
|
||||
|
|
|
@ -1808,7 +1808,7 @@ function processReply(str) {
|
|||
str = str.replaceAll('“', '');
|
||||
str = str.replaceAll('.', ',');
|
||||
str = str.replaceAll('\n', ', ');
|
||||
str = str.replace(/[^a-zA-Z0-9,:()']+/g, ' '); // Replace everything except alphanumeric characters and commas with spaces
|
||||
str = str.replace(/[^a-zA-Z0-9,:()\-']+/g, ' '); // Replace everything except alphanumeric characters and commas with spaces
|
||||
str = str.replace(/\s+/g, ' '); // Collapse multiple whitespaces into one
|
||||
str = str.trim();
|
||||
|
||||
|
|
|
@ -69,9 +69,11 @@ import {
|
|||
loadItemizedPrompts,
|
||||
animation_duration,
|
||||
depth_prompt_role_default,
|
||||
shouldAutoContinue,
|
||||
} from '../script.js';
|
||||
import { printTagList, createTagMapFromList, applyTagsOnCharacterSelect, tag_map } from './tags.js';
|
||||
import { FILTER_TYPES, FilterHelper } from './filters.js';
|
||||
import { isExternalMediaAllowed } from './chats.js';
|
||||
|
||||
export {
|
||||
selected_group,
|
||||
|
@ -175,7 +177,7 @@ async function loadGroupChat(chatId) {
|
|||
return [];
|
||||
}
|
||||
|
||||
export async function getGroupChat(groupId) {
|
||||
export async function getGroupChat(groupId, reload = false) {
|
||||
const group = groups.find((x) => x.id === groupId);
|
||||
const chat_id = group.chat_id;
|
||||
const data = await loadGroupChat(chat_id);
|
||||
|
@ -215,6 +217,10 @@ export async function getGroupChat(groupId) {
|
|||
updateChatMetadata(metadata, true);
|
||||
}
|
||||
|
||||
if (reload) {
|
||||
select_group_chats(groupId, true);
|
||||
}
|
||||
|
||||
await eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId());
|
||||
}
|
||||
|
||||
|
@ -678,9 +684,10 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
|
|||
await delay(1);
|
||||
}
|
||||
|
||||
const group = groups.find((x) => x.id === selected_group);
|
||||
let typingIndicator = $('#chat .typing_indicator');
|
||||
/** @type {any} Caution: JS war crimes ahead */
|
||||
let textResult = '';
|
||||
let typingIndicator = $('#chat .typing_indicator');
|
||||
const group = groups.find((x) => x.id === selected_group);
|
||||
|
||||
if (!group || !Array.isArray(group.members) || !group.members.length) {
|
||||
sendSystemMessage(system_message_types.EMPTY, '', { isSmallSys: true });
|
||||
|
@ -778,8 +785,15 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
|
|||
}
|
||||
|
||||
// Wait for generation to finish
|
||||
const generateFinished = await Generate(generateType, { automatic_trigger: by_auto_mode, ...(params || {}) });
|
||||
textResult = await generateFinished;
|
||||
textResult = await Generate(generateType, { automatic_trigger: by_auto_mode, ...(params || {}) });
|
||||
let messageChunk = textResult?.messageChunk;
|
||||
|
||||
if (messageChunk) {
|
||||
while (shouldAutoContinue(messageChunk, type === 'impersonate')) {
|
||||
textResult = await Generate('continue', { automatic_trigger: by_auto_mode, ...(params || {}) });
|
||||
messageChunk = textResult?.messageChunk;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
typingIndicator.hide();
|
||||
|
@ -1297,6 +1311,10 @@ function select_group_chats(groupId, skipAnimation) {
|
|||
$('#rm_group_delete').show();
|
||||
$('#rm_group_scenario').show();
|
||||
$('#group-metadata-controls .chat_lorebook_button').removeClass('disabled').prop('disabled', false);
|
||||
$('#group_open_media_overrides').show();
|
||||
const isMediaAllowed = isExternalMediaAllowed();
|
||||
$('#group_media_allowed_icon').toggle(isMediaAllowed);
|
||||
$('#group_media_forbidden_icon').toggle(!isMediaAllowed);
|
||||
} else {
|
||||
$('#rm_group_submit').show();
|
||||
if ($('#groupAddMemberListToggle .inline-drawer-content').css('display') !== 'block') {
|
||||
|
@ -1305,6 +1323,7 @@ function select_group_chats(groupId, skipAnimation) {
|
|||
$('#rm_group_delete').hide();
|
||||
$('#rm_group_scenario').hide();
|
||||
$('#group-metadata-controls .chat_lorebook_button').addClass('disabled').prop('disabled', true);
|
||||
$('#group_open_media_overrides').hide();
|
||||
}
|
||||
|
||||
updateFavButtonState(group?.fav ?? false);
|
||||
|
|
|
@ -26,6 +26,7 @@ const controls = [
|
|||
{ id: 'instruct_output_suffix', property: 'output_suffix', isCheckbox: false },
|
||||
{ id: 'instruct_system_sequence', property: 'system_sequence', isCheckbox: false },
|
||||
{ id: 'instruct_system_suffix', property: 'system_suffix', isCheckbox: false },
|
||||
{ id: 'instruct_last_system_sequence', property: 'last_system_sequence', isCheckbox: false },
|
||||
{ id: 'instruct_user_alignment_message', property: 'user_alignment_message', isCheckbox: false },
|
||||
{ id: 'instruct_stop_sequence', property: 'stop_sequence', isCheckbox: false },
|
||||
{ id: 'instruct_names', property: 'names', isCheckbox: true },
|
||||
|
@ -56,6 +57,7 @@ function migrateInstructModeSettings(settings) {
|
|||
system_sequence: '',
|
||||
system_suffix: '',
|
||||
user_alignment_message: '',
|
||||
last_system_sequence: '',
|
||||
names_force_groups: true,
|
||||
skip_examples: false,
|
||||
system_same_as_user: false,
|
||||
|
@ -243,14 +245,15 @@ export function getInstructStoppingSequences() {
|
|||
const result = [];
|
||||
|
||||
if (power_user.instruct.enabled) {
|
||||
const stop_sequence = power_user.instruct.stop_sequence;
|
||||
const input_sequence = power_user.instruct.input_sequence.replace(/{{name}}/gi, name1);
|
||||
const output_sequence = power_user.instruct.output_sequence.replace(/{{name}}/gi, name2);
|
||||
const first_output_sequence = power_user.instruct.first_output_sequence.replace(/{{name}}/gi, name2);
|
||||
const last_output_sequence = power_user.instruct.last_output_sequence.replace(/{{name}}/gi, name2);
|
||||
const system_sequence = power_user.instruct.system_sequence.replace(/{{name}}/gi, 'System');
|
||||
const stop_sequence = power_user.instruct.stop_sequence || '';
|
||||
const input_sequence = power_user.instruct.input_sequence?.replace(/{{name}}/gi, name1) || '';
|
||||
const output_sequence = power_user.instruct.output_sequence?.replace(/{{name}}/gi, name2) || '';
|
||||
const first_output_sequence = power_user.instruct.first_output_sequence?.replace(/{{name}}/gi, name2) || '';
|
||||
const last_output_sequence = power_user.instruct.last_output_sequence?.replace(/{{name}}/gi, name2) || '';
|
||||
const system_sequence = power_user.instruct.system_sequence?.replace(/{{name}}/gi, 'System') || '';
|
||||
const last_system_sequence = power_user.instruct.last_system_sequence?.replace(/{{name}}/gi, 'System') || '';
|
||||
|
||||
const combined_sequence = `${stop_sequence}\n${input_sequence}\n${output_sequence}\n${first_output_sequence}\n${last_output_sequence}\n${system_sequence}`;
|
||||
const combined_sequence = `${stop_sequence}\n${input_sequence}\n${output_sequence}\n${first_output_sequence}\n${last_output_sequence}\n${system_sequence}\n${last_system_sequence}`;
|
||||
|
||||
combined_sequence.split('\n').filter((line, index, self) => self.indexOf(line) === index).forEach(addInstructSequence);
|
||||
}
|
||||
|
@ -452,9 +455,10 @@ export function formatInstructModePrompt(name, isImpersonate, promptBias, name1,
|
|||
return power_user.instruct.input_sequence;
|
||||
}
|
||||
|
||||
// Neutral / system prompt
|
||||
// Neutral / system / quiet prompt
|
||||
// Use a special quiet instruct sequence if defined, or assistant's output sequence otherwise
|
||||
if (isQuiet && !isQuietToLoud) {
|
||||
return power_user.instruct.output_sequence;
|
||||
return power_user.instruct.last_system_sequence || power_user.instruct.output_sequence;
|
||||
}
|
||||
|
||||
// Quiet in-character prompt
|
||||
|
@ -517,20 +521,28 @@ export function replaceInstructMacros(input) {
|
|||
if (!input) {
|
||||
return '';
|
||||
}
|
||||
const instructMacros = {
|
||||
'instructSystem|instructSystemPrompt': power_user.instruct.system_prompt,
|
||||
'instructSystemPromptPrefix': power_user.instruct.system_sequence_prefix,
|
||||
'instructSystemPromptSuffix': power_user.instruct.system_sequence_suffix,
|
||||
'instructInput|instructUserPrefix': power_user.instruct.input_sequence,
|
||||
'instructUserSuffix': power_user.instruct.input_suffix,
|
||||
'instructOutput|instructAssistantPrefix': power_user.instruct.output_sequence,
|
||||
'instructSeparator|instructAssistantSuffix': power_user.instruct.output_suffix,
|
||||
'instructSystemPrefix': power_user.instruct.system_sequence,
|
||||
'instructSystemSuffix': power_user.instruct.system_suffix,
|
||||
'instructFirstOutput|instructFirstAssistantPrefix': power_user.instruct.first_output_sequence || power_user.instruct.output_sequence,
|
||||
'instructLastOutput|instructLastAssistantPrefix': power_user.instruct.last_output_sequence || power_user.instruct.output_sequence,
|
||||
'instructStop': power_user.instruct.stop_sequence,
|
||||
'instructUserFiller': power_user.instruct.user_alignment_message,
|
||||
'instructSystemInstructionPrefix': power_user.instruct.last_system_sequence,
|
||||
};
|
||||
|
||||
for (const [placeholder, value] of Object.entries(instructMacros)) {
|
||||
const regex = new RegExp(`{{(${placeholder})}}`, 'gi');
|
||||
input = input.replace(regex, power_user.instruct.enabled ? value : '');
|
||||
}
|
||||
|
||||
input = input.replace(/{{(instructSystem|instructSystemPrompt)}}/gi, power_user.instruct.enabled ? power_user.instruct.system_prompt : '');
|
||||
input = input.replace(/{{instructSystemPromptPrefix}}/gi, power_user.instruct.enabled ? power_user.instruct.system_sequence_prefix : '');
|
||||
input = input.replace(/{{instructSystemPromptSuffix}}/gi, power_user.instruct.enabled ? power_user.instruct.system_sequence_suffix : '');
|
||||
input = input.replace(/{{(instructInput|instructUserPrefix)}}/gi, power_user.instruct.enabled ? power_user.instruct.input_sequence : '');
|
||||
input = input.replace(/{{instructUserSuffix}}/gi, power_user.instruct.enabled ? power_user.instruct.input_suffix : '');
|
||||
input = input.replace(/{{(instructOutput|instructAssistantPrefix)}}/gi, power_user.instruct.enabled ? power_user.instruct.output_sequence : '');
|
||||
input = input.replace(/{{(instructSeparator|instructAssistantSuffix)}}/gi, power_user.instruct.enabled ? power_user.instruct.output_suffix : '');
|
||||
input = input.replace(/{{instructSystemPrefix}}/gi, power_user.instruct.enabled ? power_user.instruct.system_sequence : '');
|
||||
input = input.replace(/{{instructSystemSuffix}}/gi, power_user.instruct.enabled ? power_user.instruct.system_suffix : '');
|
||||
input = input.replace(/{{(instructFirstOutput|instructFirstAssistantPrefix)}}/gi, power_user.instruct.enabled ? (power_user.instruct.first_output_sequence || power_user.instruct.output_sequence) : '');
|
||||
input = input.replace(/{{(instructLastOutput|instructLastAssistantPrefix)}}/gi, power_user.instruct.enabled ? (power_user.instruct.last_output_sequence || power_user.instruct.output_sequence) : '');
|
||||
input = input.replace(/{{instructStop}}/gi, power_user.instruct.enabled ? power_user.instruct.stop_sequence : '');
|
||||
input = input.replace(/{{instructUserFiller}}/gi, power_user.instruct.enabled ? power_user.instruct.user_alignment_message : '');
|
||||
input = input.replace(/{{exampleSeparator}}/gi, power_user.context.example_separator);
|
||||
input = input.replace(/{{chatStart}}/gi, power_user.context.chat_start);
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import {
|
|||
import {
|
||||
power_user,
|
||||
} from './power-user.js';
|
||||
import EventSourceStream from './sse-stream.js';
|
||||
import { getEventSourceStream } from './sse-stream.js';
|
||||
import { getSortableDelay } from './utils.js';
|
||||
|
||||
export const kai_settings = {
|
||||
|
@ -174,7 +174,7 @@ export async function generateKoboldWithStreaming(generate_data, signal) {
|
|||
tryParseStreamingError(response, await response.text());
|
||||
throw new Error(`Got response status ${response.status}`);
|
||||
}
|
||||
const eventStream = new EventSourceStream();
|
||||
const eventStream = getEventSourceStream();
|
||||
response.body.pipeThrough(eventStream);
|
||||
const reader = eventStream.readable.getReader();
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
Generate,
|
||||
getGeneratingApi,
|
||||
is_send_press,
|
||||
isStreamingEnabled,
|
||||
} from '../script.js';
|
||||
import { debounce, delay, getStringHash } from './utils.js';
|
||||
import { decodeTextTokens, getTokenizerBestMatch } from './tokenizers.js';
|
||||
|
@ -64,11 +65,15 @@ function renderAlternativeTokensView() {
|
|||
renderTopLogprobs();
|
||||
|
||||
const { messageLogprobs, continueFrom } = getActiveMessageLogprobData() || {};
|
||||
if (!messageLogprobs?.length) {
|
||||
const usingSmoothStreaming = isStreamingEnabled() && power_user.smooth_streaming;
|
||||
if (!messageLogprobs?.length || usingSmoothStreaming) {
|
||||
const emptyState = $('<div></div>');
|
||||
const noTokensMsg = usingSmoothStreaming
|
||||
? 'Token probabilities are not available when using Smooth Streaming.'
|
||||
: 'No token probabilities available for the current message.';
|
||||
const msg = power_user.request_token_probabilities
|
||||
? 'No token probabilities available for the current message.'
|
||||
: `<span>Enable <b>Request token probabilities</b> in the User Settings menu to use this feature.</span>`;
|
||||
? noTokensMsg
|
||||
: '<span>Enable <b>Request token probabilities</b> in the User Settings menu to use this feature.</span>';
|
||||
emptyState.html(msg);
|
||||
emptyState.addClass('logprobs_empty_state');
|
||||
view.append(emptyState);
|
||||
|
|
|
@ -10,7 +10,7 @@ import {
|
|||
import { getCfgPrompt } from './cfg-scale.js';
|
||||
import { MAX_CONTEXT_DEFAULT, MAX_RESPONSE_DEFAULT, power_user } from './power-user.js';
|
||||
import { getTextTokens, tokenizers } from './tokenizers.js';
|
||||
import EventSourceStream from './sse-stream.js';
|
||||
import { getEventSourceStream } from './sse-stream.js';
|
||||
import {
|
||||
getSortableDelay,
|
||||
getStringHash,
|
||||
|
@ -614,7 +614,7 @@ export async function generateNovelWithStreaming(generate_data, signal) {
|
|||
tryParseStreamingError(response, await response.text());
|
||||
throw new Error(`Got response status ${response.status}`);
|
||||
}
|
||||
const eventStream = new EventSourceStream();
|
||||
const eventStream = getEventSourceStream();
|
||||
response.body.pipeThrough(eventStream);
|
||||
const reader = eventStream.readable.getReader();
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ import {
|
|||
import { getCustomStoppingStrings, persona_description_positions, power_user } from './power-user.js';
|
||||
import { SECRET_KEYS, secret_state, writeSecret } from './secrets.js';
|
||||
|
||||
import EventSourceStream from './sse-stream.js';
|
||||
import { getEventSourceStream } from './sse-stream.js';
|
||||
import {
|
||||
delay,
|
||||
download,
|
||||
|
@ -1772,7 +1772,7 @@ async function sendOpenAIRequest(type, messages, signal) {
|
|||
throw new Error(`Got response status ${response.status}`);
|
||||
}
|
||||
if (stream) {
|
||||
const eventStream = new EventSourceStream();
|
||||
const eventStream = getEventSourceStream();
|
||||
response.body.pipeThrough(eventStream);
|
||||
const reader = eventStream.readable.getReader();
|
||||
return async function* streamData() {
|
||||
|
@ -3661,7 +3661,7 @@ async function onModelChange() {
|
|||
else if (['command-light-nightly', 'command-nightly'].includes(oai_settings.cohere_model)) {
|
||||
$('#openai_max_context').attr('max', max_8k);
|
||||
}
|
||||
else if (['command-r'].includes(oai_settings.cohere_model)) {
|
||||
else if (['command-r', 'command-r-plus'].includes(oai_settings.cohere_model)) {
|
||||
$('#openai_max_context').attr('max', max_128k);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -118,6 +118,8 @@ let power_user = {
|
|||
markdown_escape_strings: '',
|
||||
chat_truncation: 100,
|
||||
streaming_fps: 30,
|
||||
smooth_streaming: false,
|
||||
smooth_streaming_speed: 50,
|
||||
|
||||
ui_mode: ui_mode.POWER,
|
||||
fast_ui_mode: true,
|
||||
|
@ -202,6 +204,7 @@ let power_user = {
|
|||
output_suffix: '',
|
||||
system_sequence: '',
|
||||
system_suffix: '',
|
||||
last_system_sequence: '',
|
||||
first_output_sequence: '',
|
||||
last_output_sequence: '',
|
||||
system_sequence_prefix: '',
|
||||
|
@ -255,6 +258,8 @@ let power_user = {
|
|||
auto_connect: false,
|
||||
auto_load_chat: false,
|
||||
forbid_external_images: false,
|
||||
external_media_allowed_overrides: [],
|
||||
external_media_forbidden_overrides: [],
|
||||
};
|
||||
|
||||
let themes = [];
|
||||
|
@ -1548,6 +1553,9 @@ function loadPowerUserSettings(settings, data) {
|
|||
$('#streaming_fps').val(power_user.streaming_fps);
|
||||
$('#streaming_fps_counter').val(power_user.streaming_fps);
|
||||
|
||||
$('#smooth_streaming').prop('checked', power_user.smooth_streaming);
|
||||
$('#smooth_streaming_speed').val(power_user.smooth_streaming_speed);
|
||||
|
||||
$('#font_scale').val(power_user.font_scale);
|
||||
$('#font_scale_counter').val(power_user.font_scale);
|
||||
|
||||
|
@ -2759,22 +2767,35 @@ export function getCustomStoppingStrings(limit = undefined) {
|
|||
}
|
||||
|
||||
$(document).ready(() => {
|
||||
const adjustAutocompleteDebounced = debounce(() => {
|
||||
$('.ui-autocomplete-input').each(function () {
|
||||
const isOpen = $(this).autocomplete('widget')[0].style.display !== 'none';
|
||||
if (isOpen) {
|
||||
$(this).autocomplete('search');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(window).on('resize', async () => {
|
||||
if (isMobile()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//console.log('Window resized!');
|
||||
const reportZoomLevelDebounced = debounce(() => {
|
||||
const zoomLevel = Number(window.devicePixelRatio).toFixed(2);
|
||||
const winWidth = window.innerWidth;
|
||||
const winHeight = window.innerHeight;
|
||||
console.debug(`Zoom: ${zoomLevel}, X:${winWidth}, Y:${winHeight}`);
|
||||
});
|
||||
|
||||
$(window).on('resize', async () => {
|
||||
adjustAutocompleteDebounced();
|
||||
setHotswapsDebounced();
|
||||
|
||||
if (isMobile()) {
|
||||
return;
|
||||
}
|
||||
|
||||
reportZoomLevelDebounced();
|
||||
|
||||
if (Object.keys(power_user.movingUIState).length > 0) {
|
||||
resetMovablePanels('resize');
|
||||
}
|
||||
// Adjust layout and styling here
|
||||
setHotswapsDebounced();
|
||||
});
|
||||
|
||||
// Settings that go to settings.json
|
||||
|
@ -2945,6 +2966,16 @@ $(document).ready(() => {
|
|||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#smooth_streaming').on('input', function () {
|
||||
power_user.smooth_streaming = !!$(this).prop('checked');
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#smooth_streaming_speed').on('input', function () {
|
||||
power_user.smooth_streaming_speed = Number($('#smooth_streaming_speed').val());
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('input[name="font_scale"]').on('input', async function (e) {
|
||||
power_user.font_scale = Number(e.target.value);
|
||||
$('#font_scale_counter').val(power_user.font_scale);
|
||||
|
|
|
@ -470,7 +470,7 @@ async function waitForConnection() {
|
|||
export async function initPresetManager() {
|
||||
eventSource.on(event_types.CHAT_CHANGED, autoSelectPreset);
|
||||
registerPresetManagers();
|
||||
registerSlashCommand('preset', presetCommandCallback, [], '<span class="monospace">(name)</span> – sets a preset by name for the current API', true, true);
|
||||
registerSlashCommand('preset', presetCommandCallback, [], '<span class="monospace">(name)</span> – sets a preset by name for the current API. Gets the current preset if no name is provided', true, true);
|
||||
|
||||
$(document).on('click', '[data-preset-manager-update]', async function () {
|
||||
const apiId = $(this).data('preset-manager-update');
|
||||
|
|
|
@ -254,7 +254,7 @@ parser.addCommand('inject', injectCallback, [], '<span class="monospace">id=inje
|
|||
parser.addCommand('listinjects', listInjectsCallback, [], ' – lists all script injections for the current chat.', true, true);
|
||||
parser.addCommand('flushinjects', flushInjectsCallback, [], ' – removes all script injections for the current chat.', true, true);
|
||||
parser.addCommand('tokens', (_, text) => getTokenCount(text), [], '<span class="monospace">(text)</span> – counts the number of tokens in the text.', true, true);
|
||||
parser.addCommand('model', modelCallback, [], '<span class="monospace">(model name)</span> – sets the model for the current API.', true, true);
|
||||
parser.addCommand('model', modelCallback, [], '<span class="monospace">(model name)</span> – sets the model for the current API. Gets the current model name if no argument is provided.', true, true);
|
||||
registerVariableCommands();
|
||||
|
||||
const NARRATOR_NAME_KEY = 'narrator_name';
|
||||
|
@ -1653,16 +1653,10 @@ function setBackgroundCallback(_, bg) {
|
|||
/**
|
||||
* Sets a model for the current API.
|
||||
* @param {object} _ Unused
|
||||
* @param {string} model Model name
|
||||
* @returns {void}
|
||||
* @param {string} model New model name
|
||||
* @returns {string} New or existing model name
|
||||
*/
|
||||
function modelCallback(_, model) {
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Set model to ' + model);
|
||||
|
||||
const modelSelectMap = [
|
||||
{ id: 'model_togetherai_select', api: 'textgenerationwebui', type: textgen_types.TOGETHERAI },
|
||||
{ id: 'openrouter_model', api: 'textgenerationwebui', type: textgen_types.OPENROUTER },
|
||||
|
@ -1700,23 +1694,31 @@ function modelCallback(_, model) {
|
|||
|
||||
if (!modelSelectItem) {
|
||||
toastr.info('Setting a model for your API is not supported or not implemented yet.');
|
||||
return;
|
||||
return '';
|
||||
}
|
||||
|
||||
const modelSelectControl = document.getElementById(modelSelectItem);
|
||||
|
||||
if (!(modelSelectControl instanceof HTMLSelectElement)) {
|
||||
toastr.error(`Model select control not found: ${main_api}[${apiSubType}]`);
|
||||
return;
|
||||
return '';
|
||||
}
|
||||
|
||||
const options = Array.from(modelSelectControl.options);
|
||||
|
||||
if (!options.length) {
|
||||
toastr.warning('No model options found. Check your API settings.');
|
||||
return;
|
||||
return '';
|
||||
}
|
||||
|
||||
model = String(model || '').trim();
|
||||
|
||||
if (!model) {
|
||||
return modelSelectControl.value;
|
||||
}
|
||||
|
||||
console.log('Set model to ' + model);
|
||||
|
||||
let newSelectedOption = null;
|
||||
|
||||
const fuse = new Fuse(options, { keys: ['text', 'value'] });
|
||||
|
@ -1737,8 +1739,10 @@ function modelCallback(_, model) {
|
|||
modelSelectControl.value = newSelectedOption.value;
|
||||
$(modelSelectControl).trigger('change');
|
||||
toastr.success(`Model set to "${newSelectedOption.text}"`);
|
||||
return newSelectedOption.value;
|
||||
} else {
|
||||
toastr.warning(`No model found with name "${model}"`);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
import { eventSource, event_types } from '../script.js';
|
||||
import { power_user } from './power-user.js';
|
||||
import { delay } from './utils.js';
|
||||
|
||||
/**
|
||||
* A stream which handles Server-Sent Events from a binary ReadableStream like you get from the fetch API.
|
||||
*/
|
||||
|
@ -74,4 +78,215 @@ class EventSourceStream {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a delay based on the character.
|
||||
* @param {string} s The character.
|
||||
* @returns {number} The delay in milliseconds.
|
||||
*/
|
||||
function getDelay(s) {
|
||||
if (!s) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const speedFactor = Math.max(100 - power_user.smooth_streaming_speed, 1);
|
||||
const defaultDelayMs = speedFactor * 0.4;
|
||||
const punctuationDelayMs = defaultDelayMs * 25;
|
||||
|
||||
if ([',', '\n'].includes(s)) {
|
||||
return punctuationDelayMs / 2;
|
||||
}
|
||||
|
||||
if (['.', '!', '?'].includes(s)) {
|
||||
return punctuationDelayMs;
|
||||
}
|
||||
|
||||
return defaultDelayMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the stream data and returns the parsed data and the chunk to be sent.
|
||||
* @param {object} json The JSON data.
|
||||
* @returns {AsyncGenerator<{data: object, chunk: string}>} The parsed data and the chunk to be sent.
|
||||
*/
|
||||
async function* parseStreamData(json) {
|
||||
// Claude
|
||||
if (typeof json.delta === 'object') {
|
||||
if (typeof json.delta.text === 'string' && json.delta.text.length > 0) {
|
||||
for (let i = 0; i < json.delta.text.length; i++) {
|
||||
const str = json.delta.text[i];
|
||||
yield {
|
||||
data: { ...json, delta: { text: str } },
|
||||
chunk: str,
|
||||
};
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// MakerSuite
|
||||
else if (Array.isArray(json.candidates)) {
|
||||
for (let i = 0; i < json.candidates.length; i++) {
|
||||
const isNotPrimary = json.candidates?.[0]?.index > 0;
|
||||
if (isNotPrimary || json.candidates.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (typeof json.candidates[0].content === 'object' && Array.isArray(json.candidates[i].content.parts)) {
|
||||
for (let j = 0; j < json.candidates[i].content.parts.length; j++) {
|
||||
if (typeof json.candidates[i].content.parts[j].text === 'string') {
|
||||
for (let k = 0; k < json.candidates[i].content.parts[j].text.length; k++) {
|
||||
const str = json.candidates[i].content.parts[j].text[k];
|
||||
const candidateClone = structuredClone(json.candidates[0]);
|
||||
candidateClone.content.parts[j].text = str;
|
||||
const candidates = [candidateClone];
|
||||
yield {
|
||||
data: { ...json, candidates },
|
||||
chunk: str,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// NovelAI / KoboldCpp Classic
|
||||
else if (typeof json.token === 'string' && json.token.length > 0) {
|
||||
for (let i = 0; i < json.token.length; i++) {
|
||||
const str = json.token[i];
|
||||
yield {
|
||||
data: { ...json, token: str },
|
||||
chunk: str,
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
// llama.cpp?
|
||||
else if (typeof json.content === 'string' && json.content.length > 0) {
|
||||
for (let i = 0; i < json.content.length; i++) {
|
||||
const str = json.content[i];
|
||||
yield {
|
||||
data: { ...json, content: str },
|
||||
chunk: str,
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
// OpenAI-likes
|
||||
else if (Array.isArray(json.choices)) {
|
||||
const isNotPrimary = json?.choices?.[0]?.index > 0;
|
||||
if (isNotPrimary || json.choices.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (typeof json.choices[0].text === 'string' && json.choices[0].text.length > 0) {
|
||||
for (let j = 0; j < json.choices[0].text.length; j++) {
|
||||
const str = json.choices[0].text[j];
|
||||
const choiceClone = structuredClone(json.choices[0]);
|
||||
choiceClone.text = str;
|
||||
const choices = [choiceClone];
|
||||
yield {
|
||||
data: { ...json, choices },
|
||||
chunk: str,
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (typeof json.choices[0].delta === 'object') {
|
||||
if (typeof json.choices[0].delta.text === 'string' && json.choices[0].delta.text.length > 0) {
|
||||
for (let j = 0; j < json.choices[0].delta.text.length; j++) {
|
||||
const str = json.choices[0].delta.text[j];
|
||||
const choiceClone = structuredClone(json.choices[0]);
|
||||
choiceClone.delta.text = str;
|
||||
const choices = [choiceClone];
|
||||
yield {
|
||||
data: { ...json, choices },
|
||||
chunk: str,
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (typeof json.choices[0].delta.content === 'string' && json.choices[0].delta.content.length > 0) {
|
||||
for (let j = 0; j < json.choices[0].delta.content.length; j++) {
|
||||
const str = json.choices[0].delta.content[j];
|
||||
const choiceClone = structuredClone(json.choices[0]);
|
||||
choiceClone.delta.content = str;
|
||||
const choices = [choiceClone];
|
||||
yield {
|
||||
data: { ...json, choices },
|
||||
chunk: str,
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (typeof json.choices[0].message === 'object') {
|
||||
if (typeof json.choices[0].message.content === 'string' && json.choices[0].message.content.length > 0) {
|
||||
for (let j = 0; j < json.choices[0].message.content.length; j++) {
|
||||
const str = json.choices[0].message.content[j];
|
||||
const choiceClone = structuredClone(json.choices[0]);
|
||||
choiceClone.message.content = str;
|
||||
const choices = [choiceClone];
|
||||
yield {
|
||||
data: { ...json, choices },
|
||||
chunk: str,
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('Unknown event data format');
|
||||
}
|
||||
|
||||
/**
|
||||
* Like the default one, but multiplies the events by the number of letters in the event data.
|
||||
*/
|
||||
export class SmoothEventSourceStream extends EventSourceStream {
|
||||
constructor() {
|
||||
super();
|
||||
let lastStr = '';
|
||||
const transformStream = new TransformStream({
|
||||
async transform(chunk, controller) {
|
||||
const event = chunk;
|
||||
const data = event.data;
|
||||
try {
|
||||
const hasFocus = document.hasFocus();
|
||||
|
||||
if (data === '[DONE]') {
|
||||
lastStr = '';
|
||||
return controller.enqueue(event);
|
||||
}
|
||||
|
||||
const json = JSON.parse(data);
|
||||
|
||||
if (!json) {
|
||||
lastStr = '';
|
||||
return controller.enqueue(event);
|
||||
}
|
||||
|
||||
for await (const parsed of parseStreamData(json)) {
|
||||
hasFocus && await delay(getDelay(lastStr));
|
||||
controller.enqueue(new MessageEvent(event.type, { data: JSON.stringify(parsed.data) }));
|
||||
lastStr = parsed.chunk;
|
||||
hasFocus && await eventSource.emit(event_types.SMOOTH_STREAM_TOKEN_RECEIVED, parsed.chunk);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Smooth Streaming parsing error', error);
|
||||
controller.enqueue(event);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
this.readable = this.readable.pipeThrough(transformStream);
|
||||
}
|
||||
}
|
||||
|
||||
export function getEventSourceStream() {
|
||||
if (power_user.smooth_streaming) {
|
||||
return new SmoothEventSourceStream();
|
||||
}
|
||||
|
||||
return new EventSourceStream();
|
||||
}
|
||||
|
||||
export default EventSourceStream;
|
||||
|
|
|
@ -43,6 +43,9 @@ export {
|
|||
|
||||
const CHARACTER_FILTER_SELECTOR = '#rm_characters_block .rm_tag_filter';
|
||||
const GROUP_FILTER_SELECTOR = '#rm_group_chats_block .rm_tag_filter';
|
||||
const TAG_TEMPLATE = $('#tag_template .tag');
|
||||
const FOLDER_TEMPLATE = $('#bogus_folder_template .bogus_folder_select');
|
||||
const VIEW_TAG_TEMPLATE = $('#tag_view_template .tag_view_item');
|
||||
|
||||
function getFilterHelper(listSelector) {
|
||||
return $(listSelector).is(GROUP_FILTER_SELECTOR) ? groupCandidatesFilter : entitiesFilter;
|
||||
|
@ -271,7 +274,7 @@ function getTagBlock(tag, entities, hidden = 0) {
|
|||
|
||||
const tagFolder = TAG_FOLDER_TYPES[tag.folder_type];
|
||||
|
||||
const template = $('#bogus_folder_template .bogus_folder_select').clone();
|
||||
const template = FOLDER_TEMPLATE.clone();
|
||||
template.addClass(tagFolder.class);
|
||||
template.attr({ 'tagid': tag.id, 'id': `BogusFolder${tag.id}` });
|
||||
template.find('.avatar').css({ 'background-color': tag.color, 'color': tag.color2 }).attr('title', `[Folder] ${tag.name}`);
|
||||
|
@ -665,7 +668,7 @@ function appendTagToList(listElement, tag, { removable = false, selectable = fal
|
|||
return;
|
||||
}
|
||||
|
||||
let tagElement = $('#tag_template .tag').clone();
|
||||
let tagElement = TAG_TEMPLATE.clone();
|
||||
tagElement.attr('id', tag.id);
|
||||
|
||||
//tagElement.css('color', 'var(--SmartThemeBodyColor)');
|
||||
|
@ -765,7 +768,9 @@ function toggleTagThreeState(element, { stateOverride = undefined, simulateClick
|
|||
element.toggleClass(FILTER_STATES[state].class, state === states[targetStateIndex]);
|
||||
});
|
||||
|
||||
console.debug('toggle three-way filter from', states[currentStateIndex], 'to', states[targetStateIndex], 'on', element);
|
||||
if (states[currentStateIndex] !== states[targetStateIndex]) {
|
||||
console.debug('toggle three-way filter from', states[currentStateIndex], 'to', states[targetStateIndex], 'on', element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1129,7 +1134,7 @@ function onTagCreateClick() {
|
|||
|
||||
function appendViewTagToList(list, tag, everything) {
|
||||
const count = everything.filter(x => x == tag.id).length;
|
||||
const template = $('#tag_view_template .tag_view_item').clone();
|
||||
const template = VIEW_TAG_TEMPLATE.clone();
|
||||
template.attr('id', tag.id);
|
||||
template.find('.tag_view_counter_value').text(count);
|
||||
template.find('.tag_view_name').text(tag.name);
|
||||
|
@ -1146,16 +1151,18 @@ function appendViewTagToList(list, tag, everything) {
|
|||
template.find('.tag_as_folder').hide();
|
||||
}
|
||||
|
||||
template.find('.tagColorPickerHolder').html(
|
||||
`<toolcool-color-picker id="${colorPickerId}" color="${tag.color}" class="tag-color"></toolcool-color-picker>`,
|
||||
);
|
||||
template.find('.tagColorPicker2Holder').html(
|
||||
`<toolcool-color-picker id="${colorPicker2Id}" color="${tag.color2}" class="tag-color2"></toolcool-color-picker>`,
|
||||
);
|
||||
const primaryColorPicker = $('<toolcool-color-picker></toolcool-color-picker>')
|
||||
.addClass('tag-color')
|
||||
.attr({ id: colorPickerId, color: tag.color });
|
||||
|
||||
const secondaryColorPicker = $('<toolcool-color-picker></toolcool-color-picker>')
|
||||
.addClass('tag-color2')
|
||||
.attr({ id: colorPicker2Id, color: tag.color2 });
|
||||
|
||||
template.find('.tagColorPickerHolder').append(primaryColorPicker);
|
||||
template.find('.tagColorPicker2Holder').append(secondaryColorPicker);
|
||||
|
||||
template.find('.tag_as_folder').attr('id', tagAsFolderId);
|
||||
template.find('.tag-color').attr('id', colorPickerId);
|
||||
template.find('.tag-color2').attr('id', colorPicker2Id);
|
||||
|
||||
list.append(template);
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
<li><tt>{{instructLastAssistantPrefix}}</tt> – instruct assistant last output sequence</li>
|
||||
<li><tt>{{instructSystemPrefix}}</tt> – instruct system message prefix sequence</li>
|
||||
<li><tt>{{instructSystemSuffix}}</tt> – instruct system message suffix sequence</li>
|
||||
<li><tt>{{instructSystemInstructionPrefix}}</tt> – instruct system instruction prefix</li>
|
||||
<li><tt>{{instructUserFiller}}</tt> – instruct first user message filler</li>
|
||||
<li><tt>{{instructStop}}</tt> – instruct stop sequence</li>
|
||||
</ul>
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
import { BIAS_CACHE, createNewLogitBiasEntry, displayLogitBias, getLogitBiasListResult } from './logit-bias.js';
|
||||
|
||||
import { power_user, registerDebugFunction } from './power-user.js';
|
||||
import EventSourceStream from './sse-stream.js';
|
||||
import { getEventSourceStream } from './sse-stream.js';
|
||||
import { getCurrentDreamGenModelTokenizer, getCurrentOpenRouterModelTokenizer } from './textgen-models.js';
|
||||
import { SENTENCEPIECE_TOKENIZERS, TEXTGEN_TOKENIZERS, getTextTokens, tokenizers } from './tokenizers.js';
|
||||
import { getSortableDelay, onlyUnique } from './utils.js';
|
||||
|
@ -821,7 +821,7 @@ async function generateTextGenWithStreaming(generate_data, signal) {
|
|||
throw new Error(`Got response status ${response.status}`);
|
||||
}
|
||||
|
||||
const eventStream = new EventSourceStream();
|
||||
const eventStream = getEventSourceStream();
|
||||
response.body.pipeThrough(eventStream);
|
||||
const reader = eventStream.readable.getReader();
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ const world_info_logic = {
|
|||
AND_ALL: 3,
|
||||
};
|
||||
|
||||
const WI_ENTRY_EDIT_TEMPLATE = $('#entry_edit_template .world_entry');
|
||||
|
||||
let world_info = {};
|
||||
let selected_world_info = [];
|
||||
let world_names;
|
||||
|
@ -95,6 +97,11 @@ class WorldInfoBuffer {
|
|||
*/
|
||||
#skew = 0;
|
||||
|
||||
/**
|
||||
* @type {number} The starting depth of the global scan depth. Incremented by "min activations" feature to not repeat scans. When > 0 it means a complete scan was done up to #startDepth already, and `advanceScanPosition` was called.
|
||||
*/
|
||||
#startDepth = 0;
|
||||
|
||||
/**
|
||||
* Initialize the buffer with the given messages.
|
||||
* @param {string[]} messages Array of messages to add to the buffer
|
||||
|
@ -137,7 +144,10 @@ class WorldInfoBuffer {
|
|||
* @returns {string} A slice of buffer until the given depth (inclusive)
|
||||
*/
|
||||
get(entry) {
|
||||
let depth = entry.scanDepth ?? (world_info_depth + this.#skew);
|
||||
let depth = entry.scanDepth ?? this.getDepth();
|
||||
if (depth <= this.#startDepth) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (depth < 0) {
|
||||
console.error(`Invalid WI scan depth ${depth}. Must be >= 0`);
|
||||
|
@ -149,7 +159,7 @@ class WorldInfoBuffer {
|
|||
depth = MAX_SCAN_DEPTH;
|
||||
}
|
||||
|
||||
let result = this.#depthBuffer.slice(0, depth).join('\n');
|
||||
let result = this.#depthBuffer.slice(this.#startDepth, depth).join('\n');
|
||||
|
||||
if (this.#recurseBuffer.length > 0) {
|
||||
result += '\n' + this.#recurseBuffer.join('\n');
|
||||
|
@ -197,11 +207,19 @@ class WorldInfoBuffer {
|
|||
}
|
||||
|
||||
/**
|
||||
* Adds an increment to depth skew.
|
||||
* Increments skew and sets startDepth to previous depth.
|
||||
*/
|
||||
addSkew() {
|
||||
advanceScanPosition() {
|
||||
this.#startDepth = this.getDepth();
|
||||
this.#skew++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number} Settings' depth + current skew.
|
||||
*/
|
||||
getDepth() {
|
||||
return world_info_depth + this.#skew;
|
||||
}
|
||||
}
|
||||
|
||||
export function getWorldInfoSettings() {
|
||||
|
@ -783,6 +801,11 @@ function displayWorldEntries(name, data, navigation = navigation_option.none) {
|
|||
afterSizeSelectorChange: function (e) {
|
||||
localStorage.setItem(storageKey, e.target.value);
|
||||
},
|
||||
afterPaging: function () {
|
||||
$('#world_popup_entries_list textarea[name="comment"]').each(function () {
|
||||
initScrollHeight($(this));
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
if (typeof navigation === 'number' && Number(navigation) >= 0) {
|
||||
|
@ -970,7 +993,7 @@ function getWorldEntry(name, data, entry) {
|
|||
return;
|
||||
}
|
||||
|
||||
const template = $('#entry_edit_template .world_entry').clone();
|
||||
const template = WI_ENTRY_EDIT_TEMPLATE.clone();
|
||||
template.data('uid', entry.uid);
|
||||
template.attr('uid', entry.uid);
|
||||
|
||||
|
@ -982,10 +1005,10 @@ function getWorldEntry(name, data, entry) {
|
|||
event.stopPropagation();
|
||||
});
|
||||
|
||||
keyInput.on('input', function () {
|
||||
keyInput.on('input', function (_, { skipReset } = {}) {
|
||||
const uid = $(this).data('uid');
|
||||
const value = String($(this).val());
|
||||
resetScrollHeight(this);
|
||||
!skipReset && resetScrollHeight(this);
|
||||
data.entries[uid].key = value
|
||||
.split(',')
|
||||
.map((x) => x.trim())
|
||||
|
@ -994,7 +1017,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', { skipReset: true });
|
||||
//initScrollHeight(keyInput);
|
||||
|
||||
// logic AND/NOT
|
||||
|
@ -1008,7 +1031,6 @@ function getWorldEntry(name, data, entry) {
|
|||
selectiveLogicDropdown.on('input', function () {
|
||||
const uid = $(this).data('uid');
|
||||
const value = Number($(this).val());
|
||||
console.debug(`logic for ${entry.uid} set to ${value}`);
|
||||
data.entries[uid].selectiveLogic = !isNaN(value) ? value : world_info_logic.AND_ANY;
|
||||
setOriginalDataValue(data, uid, 'selectiveLogic', data.entries[uid].selectiveLogic);
|
||||
saveWorldInfo(name, data);
|
||||
|
@ -1118,10 +1140,10 @@ function getWorldEntry(name, data, entry) {
|
|||
// keysecondary
|
||||
const keySecondaryInput = template.find('textarea[name="keysecondary"]');
|
||||
keySecondaryInput.data('uid', entry.uid);
|
||||
keySecondaryInput.on('input', function () {
|
||||
keySecondaryInput.on('input', function (_, { skipReset } = {}) {
|
||||
const uid = $(this).data('uid');
|
||||
const value = String($(this).val());
|
||||
resetScrollHeight(this);
|
||||
!skipReset && resetScrollHeight(this);
|
||||
data.entries[uid].keysecondary = value
|
||||
.split(',')
|
||||
.map((x) => x.trim())
|
||||
|
@ -1131,17 +1153,17 @@ function getWorldEntry(name, data, entry) {
|
|||
saveWorldInfo(name, data);
|
||||
});
|
||||
|
||||
keySecondaryInput.val(entry.keysecondary.join(', ')).trigger('input');
|
||||
initScrollHeight(keySecondaryInput);
|
||||
keySecondaryInput.val(entry.keysecondary.join(', ')).trigger('input', { skipReset: true });
|
||||
//initScrollHeight(keySecondaryInput);
|
||||
|
||||
// comment
|
||||
const commentInput = template.find('textarea[name="comment"]');
|
||||
const commentToggle = template.find('input[name="addMemo"]');
|
||||
commentInput.data('uid', entry.uid);
|
||||
commentInput.on('input', function () {
|
||||
commentInput.on('input', function (_, { skipReset } = {}) {
|
||||
const uid = $(this).data('uid');
|
||||
const value = $(this).val();
|
||||
resetScrollHeight(this);
|
||||
!skipReset && resetScrollHeight(this);
|
||||
data.entries[uid].comment = value;
|
||||
|
||||
setOriginalDataValue(data, uid, 'comment', data.entries[uid].comment);
|
||||
|
@ -1160,8 +1182,8 @@ function getWorldEntry(name, data, entry) {
|
|||
value ? commentContainer.show() : commentContainer.hide();
|
||||
});
|
||||
|
||||
commentInput.val(entry.comment).trigger('input');
|
||||
initScrollHeight(commentInput);
|
||||
commentInput.val(entry.comment).trigger('input', { skipReset: true });
|
||||
//initScrollHeight(commentInput);
|
||||
commentToggle.prop('checked', true /* entry.addMemo */).trigger('input');
|
||||
commentToggle.parent().hide();
|
||||
|
||||
|
@ -1196,6 +1218,8 @@ function getWorldEntry(name, data, entry) {
|
|||
if (counter.data('first-run')) {
|
||||
counter.data('first-run', false);
|
||||
countTokensDebounced(counter, contentInput.val());
|
||||
initScrollHeight(keyInput);
|
||||
initScrollHeight(keySecondaryInput);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1362,7 +1386,7 @@ function getWorldEntry(name, data, entry) {
|
|||
}
|
||||
|
||||
const positionInput = template.find('select[name="position"]');
|
||||
initScrollHeight(positionInput);
|
||||
//initScrollHeight(positionInput);
|
||||
positionInput.data('uid', entry.uid);
|
||||
positionInput.on('click', function (event) {
|
||||
// Prevent closing the drawer on clicking the input
|
||||
|
@ -1419,7 +1443,6 @@ function getWorldEntry(name, data, entry) {
|
|||
//new tri-state selector for constant/normal/disabled
|
||||
const entryStateSelector = template.find('select[name="entryStateSelector"]');
|
||||
entryStateSelector.data('uid', entry.uid);
|
||||
console.log(entry.uid);
|
||||
entryStateSelector.on('click', function (event) {
|
||||
// Prevent closing the drawer on clicking the input
|
||||
event.stopPropagation();
|
||||
|
@ -1434,7 +1457,6 @@ function getWorldEntry(name, data, entry) {
|
|||
setOriginalDataValue(data, uid, 'enabled', true);
|
||||
setOriginalDataValue(data, uid, 'constant', true);
|
||||
template.removeClass('disabledWIEntry');
|
||||
console.debug('set to constant');
|
||||
break;
|
||||
case 'normal':
|
||||
data.entries[uid].constant = false;
|
||||
|
@ -1442,7 +1464,6 @@ function getWorldEntry(name, data, entry) {
|
|||
setOriginalDataValue(data, uid, 'enabled', true);
|
||||
setOriginalDataValue(data, uid, 'constant', false);
|
||||
template.removeClass('disabledWIEntry');
|
||||
console.debug('set to normal');
|
||||
break;
|
||||
case 'disabled':
|
||||
data.entries[uid].constant = false;
|
||||
|
@ -1450,7 +1471,6 @@ function getWorldEntry(name, data, entry) {
|
|||
setOriginalDataValue(data, uid, 'enabled', false);
|
||||
setOriginalDataValue(data, uid, 'constant', false);
|
||||
template.addClass('disabledWIEntry');
|
||||
console.debug('set to disabled');
|
||||
break;
|
||||
}
|
||||
saveWorldInfo(name, data);
|
||||
|
@ -1458,19 +1478,13 @@ function getWorldEntry(name, data, entry) {
|
|||
});
|
||||
|
||||
const entryState = function () {
|
||||
|
||||
console.log(`constant: ${entry.constant}, disabled: ${entry.disable}`);
|
||||
if (entry.constant === true) {
|
||||
console.debug('found constant');
|
||||
return 'constant';
|
||||
} else if (entry.disable === true) {
|
||||
console.debug('found disabled');
|
||||
return 'disabled';
|
||||
} else {
|
||||
console.debug('found normal');
|
||||
return 'normal';
|
||||
}
|
||||
|
||||
};
|
||||
template
|
||||
.find(`select[name="entryStateSelector"] option[value=${entryState()}]`)
|
||||
|
@ -1966,15 +1980,12 @@ async function getSortedEntries() {
|
|||
|
||||
switch (Number(world_info_character_strategy)) {
|
||||
case world_info_insertion_strategy.evenly:
|
||||
console.debug('WI using evenly');
|
||||
entries = [...globalLore, ...characterLore].sort(sortFn);
|
||||
break;
|
||||
case world_info_insertion_strategy.character_first:
|
||||
console.debug('WI using char first');
|
||||
entries = [...characterLore.sort(sortFn), ...globalLore.sort(sortFn)];
|
||||
break;
|
||||
case world_info_insertion_strategy.global_first:
|
||||
console.debug('WI using global first');
|
||||
entries = [...globalLore.sort(sortFn), ...characterLore.sort(sortFn)];
|
||||
break;
|
||||
default:
|
||||
|
@ -2009,7 +2020,6 @@ async function checkWorldInfo(chat, maxContext) {
|
|||
const buffer = new WorldInfoBuffer(chat);
|
||||
|
||||
// Combine the chat
|
||||
let minActivationMsgIndex = world_info_depth; // tracks chat index to satisfy `world_info_min_activations`
|
||||
|
||||
// Add the depth or AN if enabled
|
||||
// Put this code here since otherwise, the chat reference is modified
|
||||
|
@ -2102,8 +2112,6 @@ async function checkWorldInfo(chat, maxContext) {
|
|||
const substituted = substituteParams(key);
|
||||
const textToScan = buffer.get(entry);
|
||||
|
||||
console.debug(`${entry.uid}: ${substituted}`);
|
||||
|
||||
if (substituted && buffer.matchKeys(textToScan, substituted.trim(), entry)) {
|
||||
console.debug(`WI UID ${entry.uid} found by primary match: ${substituted}.`);
|
||||
|
||||
|
@ -2160,7 +2168,7 @@ async function checkWorldInfo(chat, maxContext) {
|
|||
activatedNow.add(entry);
|
||||
break primary;
|
||||
}
|
||||
} else { console.debug(`No active entries for logic checks for word: ${substituted}.`); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2225,15 +2233,14 @@ async function checkWorldInfo(chat, maxContext) {
|
|||
// world_info_min_activations
|
||||
if (!needsToScan && !token_budget_overflowed) {
|
||||
if (world_info_min_activations > 0 && (allActivatedEntries.size < world_info_min_activations)) {
|
||||
let over_max = false;
|
||||
over_max = (
|
||||
let over_max = (
|
||||
world_info_min_activations_depth_max > 0 &&
|
||||
minActivationMsgIndex > world_info_min_activations_depth_max
|
||||
) || (minActivationMsgIndex >= chat.length);
|
||||
buffer.getDepth() > world_info_min_activations_depth_max
|
||||
) || (buffer.getDepth() > chat.length);
|
||||
|
||||
if (!over_max) {
|
||||
needsToScan = true;
|
||||
minActivationMsgIndex += 1;
|
||||
buffer.addSkew();
|
||||
needsToScan = true; // loop
|
||||
buffer.advanceScanPosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -539,6 +539,7 @@ body.reduced-motion #bg_custom {
|
|||
margin-right: 5px;
|
||||
z-index: 2000;
|
||||
min-width: 55px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.panelControlBar .drag-grabber {
|
||||
|
|
10
server.js
10
server.js
|
@ -475,7 +475,15 @@ const autorunUrl = new URL(
|
|||
const setupTasks = async function () {
|
||||
const version = await getVersion();
|
||||
|
||||
console.log(`SillyTavern ${version.pkgVersion}` + (version.gitBranch ? ` '${version.gitBranch}' (${version.gitRevision})` : ''));
|
||||
// Print formatted header
|
||||
console.log();
|
||||
console.log(`SillyTavern ${version.pkgVersion}`);
|
||||
console.log(version.gitBranch ? `Running '${version.gitBranch}' (${version.gitRevision}) - ${version.commitDate}` : '');
|
||||
if (version.gitBranch && !version.isLatest && ['staging', 'release'].includes(version.gitBranch)) {
|
||||
console.log('INFO: Currently not on the latest commit.');
|
||||
console.log(' Run \'git pull\' to update. If you have any merge conflicts, run \'git reset --hard\' and \'git pull\' to reset your branch.');
|
||||
}
|
||||
console.log();
|
||||
|
||||
// TODO: do endpoint init functions depend on certain directories existing or not existing? They should be callable
|
||||
// in any order for encapsulation reasons, but right now it's unknown if that would break anything.
|
||||
|
|
|
@ -36,7 +36,13 @@ async function parseCohereStream(jsonStream, request, response) {
|
|||
} catch (e) {
|
||||
break;
|
||||
}
|
||||
if (json.event_type === 'text-generation') {
|
||||
if (json.message) {
|
||||
const message = json.message || 'Unknown error';
|
||||
const chunk = { error: { message: message } };
|
||||
response.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
||||
partialData = '';
|
||||
break;
|
||||
} else if (json.event_type === 'text-generation') {
|
||||
const text = json.text || '';
|
||||
const chunk = { choices: [{ text }] };
|
||||
response.write(`data: ${JSON.stringify(chunk)}\n\n`);
|
||||
|
|
20
src/util.js
20
src/util.js
|
@ -73,19 +73,31 @@ function getBasicAuthHeader(auth) {
|
|||
/**
|
||||
* Returns the version of the running instance. Get the version from the package.json file and the git revision.
|
||||
* Also returns the agent string for the Horde API.
|
||||
* @returns {Promise<{agent: string, pkgVersion: string, gitRevision: string | null, gitBranch: string | null}>} Version info object
|
||||
* @returns {Promise<{agent: string, pkgVersion: string, gitRevision: string | null, gitBranch: string | null, commitDate: string | null, isLatest: boolean}>} Version info object
|
||||
*/
|
||||
async function getVersion() {
|
||||
let pkgVersion = 'UNKNOWN';
|
||||
let gitRevision = null;
|
||||
let gitBranch = null;
|
||||
let commitDate = null;
|
||||
let isLatest = true;
|
||||
|
||||
try {
|
||||
const pkgJson = require(path.join(process.cwd(), './package.json'));
|
||||
pkgVersion = pkgJson.version;
|
||||
if (!process['pkg'] && commandExistsSync('git')) {
|
||||
const git = simpleGit();
|
||||
gitRevision = await git.cwd(process.cwd()).revparse(['--short', 'HEAD']);
|
||||
gitBranch = await git.cwd(process.cwd()).revparse(['--abbrev-ref', 'HEAD']);
|
||||
const cwd = process.cwd();
|
||||
gitRevision = await git.cwd(cwd).revparse(['--short', 'HEAD']);
|
||||
gitBranch = await git.cwd(cwd).revparse(['--abbrev-ref', 'HEAD']);
|
||||
commitDate = await git.cwd(cwd).show(['-s', '--format=%ci', gitRevision]);
|
||||
|
||||
const trackingBranch = await git.cwd(cwd).revparse(['--abbrev-ref', '@{u}']);
|
||||
|
||||
// Might fail, but exception is caught. Just don't run anything relevant after in this block...
|
||||
const localLatest = await git.cwd(cwd).revparse(['HEAD']);
|
||||
const remoteLatest = await git.cwd(cwd).revparse([trackingBranch]);
|
||||
isLatest = localLatest === remoteLatest;
|
||||
}
|
||||
}
|
||||
catch {
|
||||
|
@ -93,7 +105,7 @@ async function getVersion() {
|
|||
}
|
||||
|
||||
const agent = `SillyTavern:${pkgVersion}:Cohee#1207`;
|
||||
return { agent, pkgVersion, gitRevision, gitBranch };
|
||||
return { agent, pkgVersion, gitRevision, gitBranch, commitDate: commitDate?.trim() ?? null, isLatest };
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue