#790 Simplify local prompt formatting. Use handlebars to render story string.

This commit is contained in:
Cohee 2023-08-17 22:47:34 +03:00
parent e502354cec
commit 80092b3170
11 changed files with 6141 additions and 414 deletions

View File

@ -64,11 +64,6 @@
"collapse_newlines": false,
"pygmalion_formatting": 0,
"pin_examples": false,
"disable_description_formatting": false,
"disable_scenario_formatting": false,
"disable_personality_formatting": false,
"disable_examples_formatting": false,
"disable_start_formatting": false,
"trim_sentences": false,
"include_newline": false,
"always_force_name2": true,
@ -77,7 +72,6 @@
"multigen": false,
"multigen_first_chunk": 50,
"multigen_next_chunks": 30,
"custom_chat_separator": "",
"markdown_escape_strings": "",
"fast_ui_mode": false,
"avatar_style": 0,
@ -312,9 +306,6 @@
"None": {}
}
},
"context_settings": {
"selected_template": ""
},
"tags": [
{
"id": "1345561466591",

View File

@ -1,5 +0,0 @@
{
"name": "Classic",
"storyString": "{{instructSystemPrompt}}\n{{wiBeforeCharacter}}\n{{description}}\n{{char}}'s personality: {{personality}}\nCircumstances and context of the dialogue: {{scenario}}\n{{wiAfterCharacter}}\nThis is how {{char}} should talk\n{{mesExamples}}\nThen the roleplay chat between {{user}} and {{char}} begins\n",
"injections": []
}

View File

@ -0,0 +1,6 @@
{
"name": "Default",
"story_string": "{{#if description}}{{{description}}}{{/if}}\n{{#if personality}}{{{personality}}}{{/if}}\n{{#if scenario}}Scenario: {{{scenario}}}{{/if}}",
"chat_start": "***",
"example_separator": "***"
}

View File

@ -1,5 +1,6 @@
{
"name": "Pygmalion",
"storyString": "{{instructSystemPrompt}}\n{{wiBeforeCharacter}}\n{{char}}'s Persona: {{description}}\nPersonality: {{personality}}\nScenario: {{scenario}}\n{{wiAfterCharacter}}\n<START>\n{{mesExamples}}\n<START>\n",
"injections": []
"story_string": "{{#if description}}{{{char}}}'s Persona: {{{description}}}{{/if}}\n{{#if personality}}Personality: {{{personality}}}{{/if}}\n{{#if scenario}}Scenario: {{{scenario}}}{{/if}}",
"chat_start": "<START>",
"example_separator": "<START>"
}

View File

@ -41,6 +41,7 @@
<script src="scripts/seedrandom.min.js"></script>
<script src="scripts/droll.js"></script>
<script src="scripts/localforage.min.js"></script>
<script src="scripts/handlebars.js"></script>
<script type="module" src="scripts/eventemitter.js"></script>
<script type="module" src="scripts/power-user.js"></script>
<script type="module" src="scripts/swiped-events.js"></script>
@ -94,7 +95,6 @@
<script type="module" src="scripts/slash-commands.js"></script>
<script type="module" src="scripts/tags.js"></script>
<script type="module" src="scripts/secrets.js"></script>
<script type="module" src="scripts/context-template.js"></script>
<script type="module" src="scripts/extensions.js"></script>
<script type="module" src="scripts/authors-note.js"></script>
<script type="module" src="scripts/preset-manager.js"></script>
@ -2006,58 +2006,40 @@
</h3>
<div class="flex-container">
<div name="PygOverrides" class="flex1">
<h4><span data-i18n="AutoFormat Overrides">AutoFormat Overrides</span></h4>
<label class="checkbox_label" for="disable-description-formatting-checkbox">
<input id="disable-description-formatting-checkbox" type="checkbox" />
<span data-i18n="Disable description formatting">Disable description formatting</span>
</label>
<label class="checkbox_label" for="disable-scenario-formatting-checkbox">
<input id="disable-scenario-formatting-checkbox" type="checkbox" />
<span data-i18n="Disable scenario formatting"> Disable scenario formatting</span>
</label>
<label class="checkbox_label" for="disable-personality-formatting-checkbox">
<input id="disable-personality-formatting-checkbox" type="checkbox" />
<span data-i18n="Disable personality formatting"> Disable personality formatting</span>
</label>
<label class="checkbox_label" for="disable-examples-formatting-checkbox">
<input id="disable-examples-formatting-checkbox" type="checkbox" />
<span data-i18n="Disable example chats formatting">Disable example chats formatting</span>
</label>
<label class="checkbox_label" for="disable-start-formatting-checkbox">
<input id="disable-start-formatting-checkbox" type="checkbox" />
<span data-i18n="Disable chat start formatting">Disable chat start formatting</span>
</label>
<label class="checkbox_label" for="trim_spaces">
<input id="trim_spaces" type="checkbox" />
<span data-i18n="Trim spaces">Trim spaces</span>
</label>
<label class="checkbox_label" for="trim_sentences_checkbox">
<input id="trim_sentences_checkbox" type="checkbox" />
<span data-i18n="Trim Incomplete Sentences">Trim Incomplete Sentences</span>
</label>
<!-- Add margin since this is a child of above -->
<label class="checkbox_label indent20p" for="include_newline_checkbox">
<input id="include_newline_checkbox" type="checkbox" />
<span data-i18n="Include Newline">Include Newline</span>
</label>
<div>
<h4 data-i18n="Custom Chat Separator">
Custom Chat Separator
<h4 data-i18n="Context Template">
Context Template
</h4>
<div class="flex-container flexGap5">
<select id="context_presets" class="flex1 margin0">
</select>
</div>
<div>
<textarea id="custom_chat_separator" class="text_pole textarea_compact" type="text" placeholder="&lt;START&gt;" maxlength="500" rows="1"></textarea>
<label for="context_story_string" data-i18n="Story String">
Story String
</label>
<textarea id="context_story_string" class="text_pole textarea_compact" rows="3"></textarea>
<div class="flex-container">
<div class="flex1">
<label for="context_example_separator">
<span data-i18n="Example Separator">Example Separator</span>
</label>
<div>
<textarea id="context_example_separator" class="text_pole textarea_compact" maxlength="500" rows="1"></textarea>
</div>
</div>
<div class="flex1">
<label for="context_chat_start">
<span data-i18n="Chat Start">Chat Start</span>
</label>
<div>
<textarea id="context_chat_start" class="text_pole textarea_compact" maxlength="500" rows="1"></textarea>
</div>
</div>
</div>
</div>
</div>
<div>
<h4 data-i18n="Non-markdown strings">
Non-markdown strings
</h4>
<div>
<input id="markdown_escape_strings" class="text_pole textarea_compact" type="text" data-i18n="[placeholder]separate with commas w/o space between" placeholder="separate with commas w/o space between" maxlength="100" />
</div>
</div>
<div>
<h4 data-i18n="Instruct mode">Instruct mode
<a href="https://docs.sillytavern.app/usage/core-concepts/instructmode/" class="notes-link" target="_blank">
<span class="note-link-span">?</span>
@ -2141,6 +2123,15 @@
</div>
</div>
</div>
<div>
<h4 data-i18n="Non-markdown strings">
Non-markdown strings
</h4>
<div>
<input id="markdown_escape_strings" class="text_pole textarea_compact" type="text" data-i18n="[placeholder]separate with commas w/o space between" placeholder="separate with commas w/o space between" maxlength="100" />
</div>
</div>
</div>
<div name="ContextFormatting" class="flex1">
<h4><span data-i18n="Context Formatting">Context Formatting</span></h4>
@ -2187,19 +2178,19 @@
Remove Empty New Lines from Output
</span>
</label>
<div id="context-templates-block" class="template_element">
<h4>
Context Templates
</h4>
<div class="flex-container flexGap5">
<select id="context_template" class="flex1 margin0">
</select>
<div id="context_template_new" class="menu_button fa-solid fa-plus margin0" title="Create new" data-i18n="[title]Create New"></div>
<div id="context_template_edit" class="menu_button fa-solid fa-file-pen margin0" title="Edit" data-i18n="[title]Edit"></div>
<div id="context_template_rename" class="menu_button fa-solid fa-i-cursor margin0" title="Rename" data-i18n="[title]Rename"></div>
<div id="context_template_delete" class="menu_button fa-solid fa-trash-can margin0" title="Delete" data-i18n="[title]Delete"></div>
</div>
</div>
<label class="checkbox_label" for="trim_spaces">
<input id="trim_spaces" type="checkbox" />
<span data-i18n="Trim spaces">Trim spaces</span>
</label>
<label class="checkbox_label" for="trim_sentences_checkbox">
<input id="trim_sentences_checkbox" type="checkbox" />
<span data-i18n="Trim Incomplete Sentences">Trim Incomplete Sentences</span>
</label>
<!-- Add margin since this is a child of above -->
<label class="checkbox_label indent20p" for="include_newline_checkbox">
<input id="include_newline_checkbox" type="checkbox" />
<span data-i18n="Include Newline">Include Newline</span>
</label>
<div>
<h4>
<span data-i18n="Start Reply With">

View File

@ -75,6 +75,7 @@ import {
fuzzySearchCharacters,
MAX_CONTEXT_DEFAULT,
fuzzySearchGroups,
renderStoryString,
} from "./scripts/power-user.js";
import {
@ -159,7 +160,6 @@ import {
writeSecret
} from "./scripts/secrets.js";
import { EventEmitter } from './scripts/eventemitter.js';
import { context_settings, loadContextTemplatesFromSettings } from "./scripts/context-template.js";
import { markdownExclusionExt } from "./scripts/showdown-exclusion.js";
import { NOTE_MODULE_NAME, metadata_keys, setFloatingPrompt, shouldWIAddPrompt } from "./scripts/authors-note.js";
import { deviceInfo } from "./scripts/RossAscends-mods.js";
@ -301,7 +301,6 @@ let firstRun = false;
const default_ch_mes = "Hello";
let count_view_mes = 0;
let mesStr = "";
let generatedPromtCache = "";
let generation_started = new Date();
let characters = [];
@ -311,8 +310,6 @@ const default_avatar = "img/ai4.png";
export const system_avatar = "img/five.png";
export const comment_avatar = "img/quill.png";
export let CLIENT_VERSION = 'SillyTavern:UNKNOWN:Cohee#1207'; // For Horde header
let is_colab = false;
let is_checked_colab = false;
let optionsPopper = Popper.createPopper(document.getElementById('options_button'), document.getElementById('options'), {
placement: 'top-start'
});
@ -331,10 +328,6 @@ let is_delete_mode = false;
let fav_ch_checked = false;
let scrollLock = false;
//initialize global var for future cropped blobs
let currentCroppedAvatar = '';
const durationSaveEdit = 1000;
const saveSettingsDebounced = debounce(() => saveSettings(), durationSaveEdit);
export const saveCharacterDebounced = debounce(() => $("#create_button").trigger('click'), durationSaveEdit);
@ -1095,30 +1088,6 @@ function getBackgroundFromTemplate(bg) {
return template;
}
async function isColab() {
is_checked_colab = true;
const response = await fetch("/iscolab", {
method: "POST",
headers: getRequestHeaders(),
body: JSON.stringify({
"": "",
}),
});
if (response.ok === true) {
const getData = await response.json();
if (getData.colaburl != false) {
$("#colab_shadow_popup").css("display", "none");
is_colab = true;
let url = String(getData.colaburl).split("flare.com")[0] + "flare.com";
url = String(url).split("loca.lt")[0] + "loca.lt";
$("#api_url_text").val(url);
setTimeout(function () {
$("#api_button").click();
}, 2000);
}
}
}
async function setBackground(bg) {
jQuery.ajax({
@ -2067,13 +2036,6 @@ function baseChatReplace(value, name1, name2) {
return value;
}
function appendToStoryString(value, prefix) {
if (value !== undefined && value.length > 0) {
return prefix + value + '\n';
}
return '';
}
function isStreamingEnabled() {
return ((main_api == 'openai' && oai_settings.stream_openai && oai_settings.chat_completion_source !== chat_completion_sources.SCALE)
|| (main_api == 'kobold' && kai_settings.streaming_kobold && kai_settings.can_use_streaming)
@ -2481,9 +2443,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
}
const blockHeading =
main_api === 'openai' ? '<START>' : // OpenAI handler always expects it
power_user.custom_chat_separator ? power_user.custom_chat_separator :
power_user.disable_examples_formatting ? '' :
is_pygmalion ? '<START>' : `This is how ${name2} should talk`;
power_user.context.example_separator;
let mesExamplesArray = mesExamples.split(/<START>/gi).slice(1).map(block => `${blockHeading}\n${block.trim()}\n`);
// First message in fresh 1-on-1 chat reacts to user/character settings changes
@ -2509,17 +2469,15 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
console.log(`Core/all messages: ${coreChat.length}/${chat.length}`);
let storyString = "";
const storyStringParams = {
description: charDescription,
personality: charPersonality,
scenario: Scenario,
char: name2,
user: name1,
};
if (is_pygmalion) {
storyString += appendToStoryString(charDescription, power_user.disable_description_formatting ? '' : name2 + "'s Persona: ");
storyString += appendToStoryString(charPersonality, power_user.disable_personality_formatting ? '' : 'Personality: ');
storyString += appendToStoryString(Scenario, power_user.disable_scenario_formatting ? '' : 'Scenario: ');
} else {
storyString += appendToStoryString(charDescription, '');
storyString += appendToStoryString(charPersonality, power_user.disable_personality_formatting ? '' : name2 + "'s personality: ");
storyString += appendToStoryString(Scenario, power_user.disable_scenario_formatting ? '' : 'Circumstances and context of the dialogue: ');
}
let storyString = renderStoryString(storyStringParams);
// kingbri MARK: - Make sure the prompt bias isn't the same as the user bias
if ((promptBias && !isUserPromptBias) || power_user.always_force_name2 || is_pygmalion) {
@ -3368,31 +3326,17 @@ function addChatsPreamble(mesSendString) {
}
function addChatsSeparator(mesSendString) {
if (power_user.custom_chat_separator && power_user.custom_chat_separator.length) {
mesSendString = power_user.custom_chat_separator + '\n' + mesSendString;
if (main_api === 'novel') {
return '***\n' + mesSendString;
}
// if chat start formatting is disabled
else if (power_user.disable_start_formatting) {
mesSendString = mesSendString;
else if (power_user.context.chat_start) {
return power_user.context.chat_start + '\n' + mesSendString;
}
else if (main_api === 'novel') {
mesSendString = '***\n' + mesSendString;
}
// add non-pygma dingus
else if (!is_pygmalion) {
mesSendString = '\nThen the roleplay chat between ' + name1 + ' and ' + name2 + ' begins.\n' + mesSendString;
}
// add pygma <START>
else {
mesSendString = '<START>\n' + mesSendString;
//mesSendString = mesSendString; //This edit simply removes the first "<START>" that is prepended to all context prompts
return mesSendString;
}
return mesSendString;
}
function appendZeroDepthAnchor(force_name2, zeroDepthAnchor, finalPromt) {
@ -5290,9 +5234,6 @@ async function getSettings(type) {
// Load character tags
loadTagsSettings(settings);
// Load context templates
loadContextTemplatesFromSettings(data, settings);
// Allow subscribers to mutate settings
eventSource.emit(event_types.SETTINGS_LOADED_AFTER, settings);
@ -5360,8 +5301,6 @@ async function getSettings(type) {
}
}
if (!is_checked_colab) isColab();
eventSource.emit(event_types.SETTINGS_LOADED);
}
@ -5396,7 +5335,6 @@ async function saveSettings(type) {
horde_settings: horde_settings,
power_user: power_user,
extension_settings: extension_settings,
context_settings: context_settings,
tags: tags,
tag_map: tag_map,
nai_settings: nai_settings,
@ -8285,7 +8223,6 @@ $(document).ready(function () {
const formattedValue = slider.format(value);
slider.setValue(value);
$(slider.counterId).text(formattedValue);
console.log('saving');
saveSettingsDebounced();
});
});

View File

@ -1,214 +0,0 @@
import {
callPopup,
getRequestHeaders,
saveSettingsDebounced,
} from '../script.js';
import { debounce } from './utils.js';
export let context_templates = [];
export let context_settings = {
selected_template: '',
};
const saveTemplateDebounced = debounce((name) => alert('implement me', name), 2000);
export function loadContextTemplatesFromSettings(data, settings) {
context_templates = data.context || [];
context_settings = Object.assign(context_settings, (settings.context_settings || {}));
const dropdown = $('#context_template');
dropdown.empty();
dropdown.append('<option value="">-- None --</option>')
for (const template of context_templates) {
const name = template.name;
const option = document.createElement('option');
option.innerText = name;
option.value = name;
option.selected = context_settings.selected_template == name;
dropdown.append(option);
}
}
function onContextTemplateChange() {
const value = $(this).find(':selected').val();
context_settings.selected_template = value;
saveSettingsDebounced();
}
function openContextTemplateEditor() {
const template = context_templates.find(x => x.name == context_settings.selected_template);
if (!template || !context_settings.selected_template) {
toastr.info('No context template selected');
return;
}
const editor = $('#context_editor_template .context_editor').clone();
const injectionsContainer = editor.find('.chat_injections_list');
editor.find('.template_name').text(template.name);
editor.find('.story_string_template').text(template.storyString).on('input', function () {
const value = $(this).val();
template.storyString = value;
saveTemplateDebounced(template.name);
});
editor.find('.chat_injection_add').on('click', function () {
const injection = { id: Date.now(), text: '', depth: 0 };
template.injections.push(injection);
addChatInjection(injectionsContainer, injection, template);
saveTemplateDebounced(template.name);
});
for (const injection of template.injections) {
addChatInjection(injectionsContainer, injection, template);
}
$('#dialogue_popup').addClass('large_dialogue_popup wide_dialogue_popup');
callPopup(editor, 'text');
}
async function onRenameContextTemplateClick() {
const oldName = context_settings.selected_template;
const newName = await inputTemplateName();
const template = context_templates.find(x => x.name === oldName);
if (!template || !newName || oldName === newName) {
return;
}
await saveContextTemplate(newName);
context_settings.selected_template = newName;
saveSettingsDebounced();
await deleteContextTemplate(oldName);
toastr.success('Context template renamed', newName);
}
async function deleteContextTemplate(name) {
const response = await fetch('/delete_context_template', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ name }),
});
if (!response.ok) {
throw new Error('Context template not deleted');
}
}
async function saveContextTemplate(name) {
const template = context_templates.find(x => x.name === name);
if (!template) {
throw new Error(`Context template not found: ${name}`);
}
const response = await fetch('/save_context_template', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ name, template }),
});
if (!response.ok) {
throw new Error('Context template not saved');
}
}
async function inputTemplateName() {
let name = await callPopup('Enter a template name:', 'input');
if (!name) {
return false;
}
name = DOMPurify.sanitize(name.trim());
if (context_templates.findIndex(x => x.name == name) > -1) {
toastr.warning('Template with that name already exists', 'Pick a unique name');
return false;
}
return name;
}
function addChatInjection(container, model, parent) {
const template = $('#chat_injection_template .chat_injection').clone();
template.attr('id', model.id);
template.find('.chat_injection_text').val(model.text).on('input', function () {
const value = $(this).val();
model.text = value;
saveTemplateDebounced(parent.name);
});
template.find('.chat_injection_depth').val(model.depth).on('input', function () {
const value = Math.abs(Number($(this).val()));
model.depth = value;
saveTemplateDebounced(parent.name);
});
template.find('.chat_injection_remove').on('click', function () {
if (!confirm('Are you sure?')) {
return;
}
const index = parent.injections.findIndex(x => x == model);
if (index === -1) {
console.error('Does not compute, injection index was lost');
return;
}
parent.injections.splice(index, 1);
template.remove();
saveTemplateDebounced(parent.name);
});
container.append(template);
}
function copyTemplateParameter(event) {
const text = $(event.target).text();
navigator.clipboard.writeText(text);
toastr.info('Copied!', '', { timeOut: 2000 });
}
async function onNewContextTemplateClick() {
const name = await inputTemplateName();
if (!name) {
return;
}
const template = { name: name, injections: [], storyString: '' };
context_templates.push(template);
const option = document.createElement('option');
option.innerText = name;
option.value = name;
option.selected = true;
$('#context_template').append(option).val(name).trigger('change');
saveTemplateDebounced(name);
}
async function onDeleteContextTemplateClick() {
const template = context_templates.find(x => x.name == context_settings.selected_template);
if (!template || !context_settings.selected_template) {
toastr.info('No context template selected');
return;
}
const confirm = await callPopup('Are you sure?', 'confirm');
if (!confirm) {
return;
}
await deleteContextTemplate(context_settings.selected_template);
$(`#context_template option[value="${context_settings.selected_template}"]`).remove();
$('#context_template').trigger('change');
}
jQuery(() => {
$('#context_template_edit').on('click', openContextTemplateEditor);
$('#context_template').on('change', onContextTemplateChange);
$('#context_template_new').on('click', onNewContextTemplateClick);
$('#context_template_rename').on('click', onRenameContextTemplateClick);
$('#context_template_delete').on('click', onDeleteContextTemplateClick);
$(document).on('pointerup', '.template_parameters_list code', copyTemplateParameter);
})

5972
public/scripts/handlebars.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -644,7 +644,6 @@ $(document).ready(function () {
const formattedValue = slider.format(value);
slider.setValue(value);
$(slider.counterId).text(formattedValue);
console.log('saving');
saveSettingsDebounced();
});
});

View File

@ -46,6 +46,12 @@ export {
export const MAX_CONTEXT_DEFAULT = 4096;
const MAX_CONTEXT_UNLOCKED = 65536;
const defaultStoryString = `{{#if description}}{{{description}}}{{/if}}
{{#if personality}}{{{personality}}}{{/if}}
{{#if scenario}}Scenario: {{{scenario}}}{{/if}}`;
const defaultExampleSeparator = '***';
const defaultChatStart = '***';
const avatar_styles = {
ROUND: 0,
RECTANGULAR: 1,
@ -93,11 +99,6 @@ let power_user = {
collapse_newlines: false,
pygmalion_formatting: pygmalion_options.AUTO,
pin_examples: false,
disable_description_formatting: false,
disable_scenario_formatting: false,
disable_personality_formatting: false,
disable_examples_formatting: false,
disable_start_formatting: false,
trim_sentences: false,
include_newline: false,
always_force_name2: false,
@ -106,7 +107,6 @@ let power_user = {
multigen: false,
multigen_first_chunk: 50,
multigen_next_chunks: 30,
custom_chat_separator: '',
markdown_escape_strings: '',
fast_ui_mode: true,
@ -182,6 +182,13 @@ let power_user = {
names_force_groups: true,
},
context: {
preset: 'Default',
story_string: defaultStoryString,
chat_start: defaultChatStart,
example_separator: defaultExampleSeparator,
},
personas: {},
default_persona: null,
persona_descriptions: {},
@ -200,6 +207,7 @@ let power_user = {
let themes = [];
let movingUIPresets = [];
let instruct_presets = [];
let context_presets = [];
const storage_keys = {
ui_language: "language",
@ -662,6 +670,10 @@ function loadPowerUserSettings(settings, data) {
instruct_presets = data.instruct;
}
if (data.context !== undefined) {
context_presets = data.context;
}
// These are still local storage
const fastUi = localStorage.getItem(storage_keys.fast_ui_mode);
const movingUI = localStorage.getItem(storage_keys.movingUI);
@ -720,16 +732,10 @@ function loadPowerUserSettings(settings, data) {
$("#spoiler_free_mode").prop("checked", power_user.spoiler_free_mode);
$("#collapse-newlines-checkbox").prop("checked", power_user.collapse_newlines);
$("#pin-examples-checkbox").prop("checked", power_user.pin_examples);
$("#disable-description-formatting-checkbox").prop("checked", power_user.disable_description_formatting);
$("#disable-scenario-formatting-checkbox").prop("checked", power_user.disable_scenario_formatting);
$("#disable-personality-formatting-checkbox").prop("checked", power_user.disable_personality_formatting);
$("#always-force-name2-checkbox").prop("checked", power_user.always_force_name2);
$("#disable-examples-formatting-checkbox").prop("checked", power_user.disable_examples_formatting);
$('#disable-start-formatting-checkbox').prop("checked", power_user.disable_start_formatting);
$("#trim_sentences_checkbox").prop("checked", power_user.trim_sentences);
$("#include_newline_checkbox").prop("checked", power_user.include_newline);
$('#render_formulas').prop("checked", power_user.render_formulas);
$("#custom_chat_separator").val(power_user.custom_chat_separator);
$("#markdown_escape_strings").val(power_user.markdown_escape_strings);
$("#fast_ui_mode").prop("checked", power_user.fast_ui_mode);
$("#waifuMode").prop("checked", power_user.waifuMode);
@ -799,6 +805,7 @@ function loadPowerUserSettings(settings, data) {
sortCharactersList();
reloadMarkdownProcessor(power_user.render_formulas);
loadInstructMode();
loadContextSettings();
loadMaxContextUnlocked();
switchWaifuMode();
switchSpoilerMode();
@ -867,6 +874,61 @@ function switchMaxContextSize() {
}
}
function loadContextSettings() {
const controls = [
{ id: "context_story_string", property: "story_string", isCheckbox: false },
{ id: "context_example_separator", property: "example_separator", isCheckbox: false },
{ id: "context_chat_start", property: "chat_start", isCheckbox: false },
];
controls.forEach(control => {
const $element = $(`#${control.id}`);
if (control.isCheckbox) {
$element.prop('checked', power_user.context[control.property]);
} else {
$element.val(power_user.context[control.property]);
}
$element.on('input', function () {
power_user.context[control.property] = control.isCheckbox ? !!$(this).prop('checked') : $(this).val();
saveSettingsDebounced();
});
});
context_presets.forEach((preset) => {
const name = preset.name;
const option = document.createElement('option');
option.value = name;
option.innerText = name;
option.selected = name === power_user.context.preset;
$('#context_presets').append(option);
});
$('#context_presets').on('change', function () {
const name = $(this).find(':selected').val();
const preset = context_presets.find(x => x.name === name);
if (!preset) {
return;
}
power_user.context.preset = name;
controls.forEach(control => {
if (preset[control.property] !== undefined) {
power_user.context[control.property] = preset[control.property];
const $element = $(`#${control.id}`);
if (control.isCheckbox) {
$element.prop('checked', power_user.context[control.property]).trigger('input');
} else {
$element.val(power_user.context[control.property]).trigger('input');
}
}
});
});
}
function loadInstructMode() {
const controls = [
{ id: "instruct_enabled", property: "enabled", isCheckbox: true },
@ -976,6 +1038,20 @@ export function fuzzySearchGroups(searchValue) {
return ids;
}
export function renderStoryString(params) {
try {
const compiledTemplate = Handlebars.compile(power_user.context.story_string);
let output = compiledTemplate(params);
output = substituteParams(output, params.user, params.char);
output = `${output.trim()}\n`; // add a newline to the end
return output;
} catch (e) {
toastr.error('Check the story string template for validity', 'Error rendering story string');
console.error('Error rendering story string', e);
throw e;
}
}
export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2) {
let includeNames = isNarrator ? false : power_user.instruct.names;
@ -1639,31 +1715,6 @@ $(document).ready(() => {
saveSettingsDebounced();
});
$("#disable-description-formatting-checkbox").change(function () {
power_user.disable_description_formatting = !!$(this).prop('checked');
saveSettingsDebounced();
})
$("#disable-scenario-formatting-checkbox").change(function () {
power_user.disable_scenario_formatting = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#disable-personality-formatting-checkbox").change(function () {
power_user.disable_personality_formatting = !!$(this).prop('checked');
saveSettingsDebounced();
});
$("#disable-examples-formatting-checkbox").change(function () {
power_user.disable_examples_formatting = !!$(this).prop('checked');
saveSettingsDebounced();
})
$("#disable-start-formatting-checkbox").change(function () {
power_user.disable_start_formatting = !!$(this).prop('checked');
saveSettingsDebounced();
});
// include newline is the child of trim sentences
// if include newline is checked, trim sentences must be checked
// if trim sentences is unchecked, include newline must be unchecked
@ -1690,12 +1741,6 @@ $(document).ready(() => {
saveSettingsDebounced();
});
$("#custom_chat_separator").on('input', function () {
power_user.custom_chat_separator = $(this).val();
saveSettingsDebounced();
reloadMarkdownProcessor(power_user.render_formulas);
});
$("#markdown_escape_strings").on('input', function () {
power_user.markdown_escape_strings = $(this).val();
saveSettingsDebounced();

View File

@ -8,8 +8,12 @@ export const markdownExclusionExt = () => {
}
let combinedExcludeString = '';
if (power_user.custom_chat_separator) {
combinedExcludeString += `${power_user.custom_chat_separator},`;
if (power_user.context.chat_start) {
combinedExcludeString += `${power_user.context.chat_start},`;
}
if (power_user.context.example_separator) {
combinedExcludeString += `${power_user.context.example_separator},`;
}
if (power_user.markdown_escape_strings) {