From 310acfe810c8cc2e989e6a8b69ce0ade942a9b50 Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Thu, 28 Mar 2024 00:52:20 +0200
Subject: [PATCH] Use new instruct sequences in prompt formatting
---
public/index.html | 10 ++-
public/script.js | 10 +--
public/scripts/instruct-mode.js | 132 ++++++++++++++++++++++++--------
public/scripts/openai.js | 2 +-
public/scripts/power-user.js | 1 +
5 files changed, 114 insertions(+), 41 deletions(-)
diff --git a/public/index.html b/public/index.html
index 1140599f7..cb4d6dcf9 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2909,7 +2909,7 @@
-
+
@@ -2917,7 +2917,7 @@
-
+
@@ -2925,6 +2925,12 @@
+
+
+
System Prompt Wrapping
diff --git a/public/script.js b/public/script.js
index ba787581b..4b5ba72fb 100644
--- a/public/script.js
+++ b/public/script.js
@@ -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' ? '\n' : exampleSeparator;
+ const blockHeading = main_api === 'openai' ? '\n' : (exampleSeparator || (isInstruct ? '\n' : ''));
return examplesStr.split(//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);
diff --git a/public/scripts/instruct-mode.js b/public/scripts/instruct-mode.js
index 4159b3a66..e30d81a3f 100644
--- a/public/scripts/instruct-mode.js
+++ b/public/scripts/instruct-mode.js
@@ -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(/\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(//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);
}
});
diff --git a/public/scripts/openai.js b/public/scripts/openai.js
index 5a85da15e..bdfd3b827 100644
--- a/public/scripts/openai.js
+++ b/public/scripts/openai.js
@@ -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
diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js
index d91254c44..3602061dd 100644
--- a/public/scripts/power-user.js
+++ b/public/scripts/power-user.js
@@ -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: '',
},