mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-02-03 04:37:40 +01:00
Use new instruct sequences in prompt formatting
This commit is contained in:
parent
39768b78ce
commit
310acfe810
@ -2909,7 +2909,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-container">
|
||||
<div class="flex1" title="Inserted before a System (added by slash commands or extensions) message and as a last prompt line when generating a neutral/system reply. Defaults to User Prefix if not defined.">
|
||||
<div class="flex1" title="Inserted before a System (added by slash commands or extensions) message and as a last prompt line when generating a neutral/system reply.">
|
||||
<label for="instruct_system_sequence">
|
||||
<small data-i18n="System Message Prefix">System Message Prefix</small>
|
||||
</label>
|
||||
@ -2917,7 +2917,7 @@
|
||||
<textarea id="instruct_system_sequence" class="text_pole textarea_compact autoSetHeight" maxlength="2000" placeholder="—" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex1" title="Inserted after a System message. Defaults to User Suffix if not defined.">
|
||||
<div class="flex1" title="Inserted after a System message.">
|
||||
<label for="instruct_system_suffix">
|
||||
<small data-i18n="System Message Suffix">System Message Suffix</small>
|
||||
</label>
|
||||
@ -2925,6 +2925,12 @@
|
||||
<textarea id="instruct_system_suffix" class="text_pole wide100p textarea_compact autoSetHeight" maxlength="2000" placeholder="—" rows="1"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flexBasis100p" title="If enabled, System Sequences will be the same as User Sequences.">
|
||||
<label class="checkbox_label" for="instruct_system_same_as_user">
|
||||
<input id="instruct_system_same_as_user" type="checkbox" />
|
||||
<small data-i18n="System same as User">System same as User</small>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="textAlignCenter" data-i18n="System Prompt Wrapping">
|
||||
System Prompt Wrapping
|
||||
|
@ -3127,10 +3127,6 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
||||
mesExamples = '';
|
||||
}
|
||||
const mesExamplesRaw = mesExamples;
|
||||
if (mesExamples && isInstruct) {
|
||||
mesExamples = formatInstructModeExamples(mesExamples, name1, name2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a block heading to the examples string.
|
||||
* @param {string} examplesStr
|
||||
@ -3138,13 +3134,17 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu
|
||||
*/
|
||||
function addBlockHeading(examplesStr) {
|
||||
const exampleSeparator = power_user.context.example_separator ? `${substituteParams(power_user.context.example_separator)}\n` : '';
|
||||
const blockHeading = main_api === 'openai' ? '<START>\n' : exampleSeparator;
|
||||
const blockHeading = main_api === 'openai' ? '<START>\n' : (exampleSeparator || (isInstruct ? '<START>\n' : ''));
|
||||
return examplesStr.split(/<START>/gi).slice(1).map(block => `${blockHeading}${block.trim()}\n`);
|
||||
}
|
||||
|
||||
let mesExamplesArray = addBlockHeading(mesExamples);
|
||||
let mesExamplesRawArray = addBlockHeading(mesExamplesRaw);
|
||||
|
||||
if (mesExamplesArray && isInstruct) {
|
||||
mesExamplesArray = formatInstructModeExamples(mesExamplesArray, name1, name2);
|
||||
}
|
||||
|
||||
// First message in fresh 1-on-1 chat reacts to user/character settings changes
|
||||
if (chat.length) {
|
||||
chat[0].mes = substituteParams(chat[0].mes);
|
||||
|
@ -1,7 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
import { saveSettingsDebounced, substituteParams } from '../script.js';
|
||||
import { name1, name2, saveSettingsDebounced, substituteParams } from '../script.js';
|
||||
import { selected_group } from './group-chats.js';
|
||||
import { parseExampleIntoIndividual } from './openai.js';
|
||||
import {
|
||||
power_user,
|
||||
context_presets,
|
||||
@ -35,6 +36,7 @@ const controls = [
|
||||
{ id: 'instruct_activation_regex', property: 'activation_regex', isCheckbox: false },
|
||||
{ id: 'instruct_bind_to_context', property: 'bind_to_context', isCheckbox: true },
|
||||
{ id: 'instruct_skip_examples', property: 'skip_examples', isCheckbox: true },
|
||||
{ id: 'instruct_system_same_as_user', property: 'system_same_as_user', isCheckbox: true, trigger: true },
|
||||
];
|
||||
|
||||
/**
|
||||
@ -75,6 +77,10 @@ function migrateInstructModeSettings(settings) {
|
||||
if (settings.skip_examples === undefined) {
|
||||
settings.skip_examples = false;
|
||||
}
|
||||
|
||||
if (settings.system_same_as_user === undefined) {
|
||||
settings.system_same_as_user = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -104,6 +110,10 @@ export function loadInstructMode(data) {
|
||||
resetScrollHeight($element);
|
||||
}
|
||||
});
|
||||
|
||||
if (control.trigger) {
|
||||
$element.trigger('input');
|
||||
}
|
||||
});
|
||||
|
||||
instruct_presets.forEach((preset) => {
|
||||
@ -248,12 +258,14 @@ export function getInstructStoppingSequences() {
|
||||
const result = [];
|
||||
|
||||
if (power_user.instruct.enabled) {
|
||||
const input_sequence = power_user.instruct.input_sequence;
|
||||
const output_sequence = power_user.instruct.output_sequence;
|
||||
const first_output_sequence = power_user.instruct.first_output_sequence;
|
||||
const last_output_sequence = power_user.instruct.last_output_sequence;
|
||||
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 combined_sequence = `${input_sequence}\n${output_sequence}\n${first_output_sequence}\n${last_output_sequence}`;
|
||||
const combined_sequence = `${stop_sequence}\n${input_sequence}\n${output_sequence}\n${first_output_sequence}\n${last_output_sequence}\n${system_sequence}`;
|
||||
|
||||
combined_sequence.split('\n').filter((line, index, self) => self.indexOf(line) === index).forEach(addInstructSequence);
|
||||
}
|
||||
@ -295,26 +307,48 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata
|
||||
includeNames = true;
|
||||
}
|
||||
|
||||
let sequence = (isUser || isNarrator) ? power_user.instruct.input_sequence : power_user.instruct.output_sequence;
|
||||
|
||||
if (forceOutputSequence && sequence === power_user.instruct.output_sequence) {
|
||||
if (forceOutputSequence === force_output_sequence.FIRST && power_user.instruct.first_output_sequence) {
|
||||
sequence = power_user.instruct.first_output_sequence;
|
||||
} else if (forceOutputSequence === force_output_sequence.LAST && power_user.instruct.last_output_sequence) {
|
||||
sequence = power_user.instruct.last_output_sequence;
|
||||
function getPrefix() {
|
||||
if (isNarrator) {
|
||||
return power_user.instruct.system_same_as_user ? power_user.instruct.input_sequence : power_user.instruct.system_sequence;
|
||||
}
|
||||
|
||||
if (isUser) {
|
||||
return power_user.instruct.input_sequence;
|
||||
}
|
||||
|
||||
if (forceOutputSequence === force_output_sequence.FIRST) {
|
||||
return power_user.instruct.first_output_sequence || power_user.instruct.output_sequence;
|
||||
}
|
||||
|
||||
if (forceOutputSequence === force_output_sequence.LAST) {
|
||||
return power_user.instruct.last_output_sequence || power_user.instruct.output_sequence;
|
||||
}
|
||||
|
||||
return power_user.instruct.output_sequence;
|
||||
}
|
||||
|
||||
function getSuffix() {
|
||||
if (isNarrator) {
|
||||
return power_user.instruct.system_same_as_user ? power_user.instruct.input_suffix : power_user.instruct.system_suffix;
|
||||
}
|
||||
|
||||
if (isUser) {
|
||||
return power_user.instruct.input_suffix;
|
||||
}
|
||||
|
||||
return power_user.instruct.output_suffix;
|
||||
}
|
||||
|
||||
let prefix = getPrefix() || '';
|
||||
let suffix = getSuffix() || '';
|
||||
|
||||
if (power_user.instruct.macro) {
|
||||
sequence = substituteParams(sequence, name1, name2);
|
||||
sequence = sequence.replace(/{{name}}/gi, name || 'System');
|
||||
prefix = substituteParams(prefix, name1, name2);
|
||||
prefix = prefix.replace(/{{name}}/gi, name || 'System');
|
||||
}
|
||||
|
||||
const separator = power_user.instruct.wrap ? '\n' : '';
|
||||
const separatorSequence = power_user.instruct.separator_sequence && !isUser
|
||||
? power_user.instruct.separator_sequence
|
||||
: separator;
|
||||
const textArray = includeNames ? [sequence, `${name}: ${mes}` + separatorSequence] : [sequence, mes + separatorSequence];
|
||||
const textArray = includeNames ? [prefix, `${name}: ${mes}` + suffix] : [prefix, mes + suffix];
|
||||
const text = textArray.filter(x => x).join(separator);
|
||||
return text;
|
||||
}
|
||||
@ -324,7 +358,7 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata
|
||||
* @param {string} systemPrompt System prompt string.
|
||||
* @returns {string} Formatted instruct mode system prompt.
|
||||
*/
|
||||
export function formatInstructModeSystemPrompt(systemPrompt){
|
||||
export function formatInstructModeSystemPrompt(systemPrompt) {
|
||||
const separator = power_user.instruct.wrap ? '\n' : '';
|
||||
|
||||
if (power_user.instruct.system_sequence_prefix) {
|
||||
@ -340,33 +374,59 @@ export function formatInstructModeSystemPrompt(systemPrompt){
|
||||
|
||||
/**
|
||||
* Formats example messages according to instruct mode settings.
|
||||
* @param {string} mesExamples Example messages string.
|
||||
* @param {string[]} mesExamplesArray Example messages array.
|
||||
* @param {string} name1 User name.
|
||||
* @param {string} name2 Character name.
|
||||
* @returns {string} Formatted example messages string.
|
||||
* @returns {string[]} Formatted example messages string.
|
||||
*/
|
||||
export function formatInstructModeExamples(mesExamples, name1, name2) {
|
||||
export function formatInstructModeExamples(mesExamplesArray, name1, name2) {
|
||||
if (power_user.instruct.skip_examples) {
|
||||
return mesExamples;
|
||||
return mesExamplesArray.map(x => x.replace(/<START>\n/i, ''));
|
||||
}
|
||||
|
||||
const includeNames = power_user.instruct.names || (!!selected_group && power_user.instruct.names_force_groups);
|
||||
|
||||
let inputSequence = power_user.instruct.input_sequence;
|
||||
let outputSequence = power_user.instruct.output_sequence;
|
||||
let inputPrefix = power_user.instruct.input_sequence || '';
|
||||
let outputPrefix = power_user.instruct.output_sequence || '';
|
||||
let inputSuffix = power_user.instruct.output_suffix || '';
|
||||
let outputSuffix = power_user.instruct.output_suffix || '';
|
||||
|
||||
if (power_user.instruct.macro) {
|
||||
inputSequence = substituteParams(inputSequence, name1, name2);
|
||||
outputSequence = substituteParams(outputSequence, name1, name2);
|
||||
inputPrefix = substituteParams(inputPrefix, name1, name2);
|
||||
outputPrefix = substituteParams(outputPrefix, name1, name2);
|
||||
inputSuffix = substituteParams(inputSuffix, name1, name2);
|
||||
outputSuffix = substituteParams(outputSuffix, name1, name2);
|
||||
|
||||
inputPrefix = inputPrefix.replace(/{{name}}/gi, name1);
|
||||
outputPrefix = outputPrefix.replace(/{{name}}/gi, name2);
|
||||
}
|
||||
|
||||
const separator = power_user.instruct.wrap ? '\n' : '';
|
||||
const separatorSequence = power_user.instruct.separator_sequence ? power_user.instruct.separator_sequence : separator;
|
||||
const parsedExamples = [];
|
||||
|
||||
mesExamples = mesExamples.replace(new RegExp(`\n${name1}: `, 'gm'), separatorSequence + inputSequence + separator + (includeNames ? `${name1}: ` : ''));
|
||||
mesExamples = mesExamples.replace(new RegExp(`\n${name2}: `, 'gm'), separator + outputSequence + separator + (includeNames ? `${name2}: ` : ''));
|
||||
for (const item of mesExamplesArray) {
|
||||
const cleanedItem = item.replace(/<START>/i, '{Example Dialogue:}').replace(/\r/gm, '');
|
||||
const blockExamples = parseExampleIntoIndividual(cleanedItem);
|
||||
parsedExamples.push(...blockExamples);
|
||||
}
|
||||
|
||||
return mesExamples;
|
||||
// Not something we can parse, return as is
|
||||
if (!Array.isArray(parsedExamples) || parsedExamples.length === 0) {
|
||||
return mesExamplesArray;
|
||||
}
|
||||
|
||||
const formattedExamples = [];
|
||||
|
||||
for (const example of parsedExamples) {
|
||||
const prefix = example.name == 'example_user' ? inputPrefix : outputPrefix;
|
||||
const suffix = example.name == 'example_user' ? inputSuffix : outputSuffix;
|
||||
const name = example.name == 'example_user' ? name1 : name2;
|
||||
const messageContent = includeNames ? `${name}: ${example.content}` : example.content;
|
||||
const formattedMessage = [prefix, messageContent + suffix].filter(x => x).join(separator);
|
||||
formattedExamples.push(formattedMessage);
|
||||
}
|
||||
|
||||
return formattedExamples;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -458,6 +518,12 @@ jQuery(() => {
|
||||
saveSettingsDebounced();
|
||||
});
|
||||
|
||||
$('#instruct_system_same_as_user').on('input', function () {
|
||||
const state = !!$(this).prop('checked');
|
||||
$('#instruct_system_sequence').prop('disabled', state);
|
||||
$('#instruct_system_suffix').prop('disabled', state);
|
||||
});
|
||||
|
||||
$('#instruct_enabled').on('change', function () {
|
||||
if (!power_user.instruct.bind_to_context) {
|
||||
return;
|
||||
@ -466,8 +532,8 @@ jQuery(() => {
|
||||
// When instruct mode gets enabled, select context template matching selected instruct preset
|
||||
if (power_user.instruct.enabled) {
|
||||
selectMatchingContextTemplate(power_user.instruct.preset);
|
||||
// When instruct mode gets disabled, select default context preset
|
||||
} else {
|
||||
// When instruct mode gets disabled, select default context preset
|
||||
selectContextPreset(power_user.default_context);
|
||||
}
|
||||
});
|
||||
|
@ -588,7 +588,7 @@ function setupChatCompletionPromptManager(openAiSettings) {
|
||||
* Parses the example messages into individual messages.
|
||||
* @param {string} messageExampleString - The string containing the example messages
|
||||
* @param {boolean} appendNamesForGroup - Whether to append the character name for group chats
|
||||
* @returns {object[]} Array of message objects
|
||||
* @returns {Message[]} Array of message objects
|
||||
*/
|
||||
export function parseExampleIntoIndividual(messageExampleString, appendNamesForGroup = true) {
|
||||
let result = []; // array of msgs
|
||||
|
@ -214,6 +214,7 @@ let power_user = {
|
||||
activation_regex: '',
|
||||
bind_to_context: false,
|
||||
user_alignment_message: '',
|
||||
system_same_as_user: false,
|
||||
/** @deprecated Use output_suffix instead */
|
||||
separator_sequence: '',
|
||||
},
|
||||
|
Loading…
x
Reference in New Issue
Block a user