mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Text Completion: Add context-specific {{timestamp}} macro
This commit is contained in:
@@ -3429,6 +3429,15 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
|
|||||||
const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0;
|
const responseLengthCustomized = typeof responseLength === 'number' && responseLength > 0;
|
||||||
const isInstruct = power_user.instruct.enabled && api !== 'openai' && api !== 'novel' && !instructOverride;
|
const isInstruct = power_user.instruct.enabled && api !== 'openai' && api !== 'novel' && !instructOverride;
|
||||||
const isQuiet = true;
|
const isQuiet = true;
|
||||||
|
const getInstructFormatParams = (/** @type {string} */ mes) => ({
|
||||||
|
name: name1,
|
||||||
|
mes: mes,
|
||||||
|
isUser: false,
|
||||||
|
isNarrator: true,
|
||||||
|
forceAvatar: '',
|
||||||
|
forceOutputSequence: false,
|
||||||
|
timestamp: moment(),
|
||||||
|
});
|
||||||
let eventHook = () => { };
|
let eventHook = () => { };
|
||||||
|
|
||||||
if (systemPrompt) {
|
if (systemPrompt) {
|
||||||
@@ -3439,8 +3448,8 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy
|
|||||||
|
|
||||||
prompt = substituteParams(prompt);
|
prompt = substituteParams(prompt);
|
||||||
prompt = api == 'novel' ? adjustNovelInstructionPrompt(prompt) : prompt;
|
prompt = api == 'novel' ? adjustNovelInstructionPrompt(prompt) : prompt;
|
||||||
prompt = isInstruct ? formatInstructModeChat(name1, prompt, false, true, '', name1, name2, false) : prompt;
|
prompt = isInstruct ? formatInstructModeChat(getInstructFormatParams(prompt)) : prompt;
|
||||||
prompt = isInstruct ? (prompt + formatInstructModePrompt(name2, false, '', name1, name2, isQuiet, quietToLoud)) : (prompt + '\n');
|
prompt = isInstruct ? (prompt + formatInstructModePrompt(name2, false, '', isQuiet, quietToLoud)) : (prompt + '\n');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (responseLengthCustomized) {
|
if (responseLengthCustomized) {
|
||||||
@@ -4016,7 +4025,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
|||||||
const mesExamplesRawArray = [...mesExamplesArray];
|
const mesExamplesRawArray = [...mesExamplesArray];
|
||||||
|
|
||||||
if (mesExamplesArray && isInstruct) {
|
if (mesExamplesArray && isInstruct) {
|
||||||
mesExamplesArray = formatInstructModeExamples(mesExamplesArray, name1, name2);
|
mesExamplesArray = formatInstructModeExamples(mesExamplesArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skipWIAN !== true) {
|
if (skipWIAN !== true) {
|
||||||
@@ -4336,7 +4345,16 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
|||||||
// here name1 is forced for all quiet prompts..why?
|
// here name1 is forced for all quiet prompts..why?
|
||||||
const name = name1;
|
const name = name1;
|
||||||
//checks if we are in instruct, if so, formats the chat as such, otherwise just adds the quiet prompt
|
//checks if we are in instruct, if so, formats the chat as such, otherwise just adds the quiet prompt
|
||||||
const quietAppend = isInstruct ? formatInstructModeChat(name, quiet_prompt, false, true, '', name1, name2, false) : `\n${quiet_prompt}`;
|
const quietInstructParams = {
|
||||||
|
name: name,
|
||||||
|
mes: quiet_prompt,
|
||||||
|
isUser: false,
|
||||||
|
isNarrator: true,
|
||||||
|
forceAvatar: '',
|
||||||
|
forceOutputSequence: false,
|
||||||
|
timestamp: moment(),
|
||||||
|
};
|
||||||
|
const quietAppend = isInstruct ? formatInstructModeChat(quietInstructParams) : `\n${quiet_prompt}`;
|
||||||
|
|
||||||
//This begins to fix quietPrompts (particularly /sysgen) for instruct
|
//This begins to fix quietPrompts (particularly /sysgen) for instruct
|
||||||
//previously instruct input sequence was being appended to the last chat message w/o '\n'
|
//previously instruct input sequence was being appended to the last chat message w/o '\n'
|
||||||
@@ -4366,7 +4384,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro
|
|||||||
if (isInstruct && !isContinue) {
|
if (isInstruct && !isContinue) {
|
||||||
const name = (quiet_prompt && !quietToLoud && !isImpersonate) ? (quietName ?? 'System') : (isImpersonate ? name1 : name2);
|
const name = (quiet_prompt && !quietToLoud && !isImpersonate) ? (quietName ?? 'System') : (isImpersonate ? name1 : name2);
|
||||||
const isQuiet = quiet_prompt && type == 'quiet';
|
const isQuiet = quiet_prompt && type == 'quiet';
|
||||||
lastMesString += formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2, isQuiet, quietToLoud);
|
lastMesString += formatInstructModePrompt(name, isImpersonate, promptBias, isQuiet, quietToLoud);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get non-instruct impersonation line
|
// Get non-instruct impersonation line
|
||||||
@@ -5147,7 +5165,16 @@ function formatMessageHistoryItem(chatItem, isInstruct, forceOutputSequence) {
|
|||||||
let textResult = chatItem?.name && shouldPrependName ? `${itemName}: ${chatItem.mes}\n` : `${chatItem.mes}\n`;
|
let textResult = chatItem?.name && shouldPrependName ? `${itemName}: ${chatItem.mes}\n` : `${chatItem.mes}\n`;
|
||||||
|
|
||||||
if (isInstruct) {
|
if (isInstruct) {
|
||||||
textResult = formatInstructModeChat(itemName, chatItem.mes, chatItem.is_user, isNarratorType, chatItem.force_avatar, name1, name2, forceOutputSequence);
|
const instructFormatParams = {
|
||||||
|
name: itemName,
|
||||||
|
mes: chatItem.mes,
|
||||||
|
isUser: chatItem.is_user,
|
||||||
|
isNarrator: isNarratorType,
|
||||||
|
forceAvatar: chatItem.force_avatar,
|
||||||
|
forceOutputSequence: forceOutputSequence,
|
||||||
|
timestamp: timestampToMoment(chatItem.send_date),
|
||||||
|
};
|
||||||
|
textResult = formatInstructModeChat(instructFormatParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
return textResult;
|
return textResult;
|
||||||
|
@@ -8,6 +8,7 @@ import {
|
|||||||
context_presets,
|
context_presets,
|
||||||
} from './power-user.js';
|
} from './power-user.js';
|
||||||
import { regexFromString, resetScrollHeight } from './utils.js';
|
import { regexFromString, resetScrollHeight } from './utils.js';
|
||||||
|
import { moment } from '../lib.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {any[]} Instruct mode presets.
|
* @type {any[]} Instruct mode presets.
|
||||||
@@ -254,8 +255,10 @@ export function getInstructStoppingSequences() {
|
|||||||
// Cohee: oobabooga's textgen always appends newline before the sequence as a stopping string
|
// Cohee: oobabooga's textgen always appends newline before the sequence as a stopping string
|
||||||
// But it's a problem for Metharme which doesn't use newlines to separate them.
|
// But it's a problem for Metharme which doesn't use newlines to separate them.
|
||||||
const wrap = (s) => power_user.instruct.wrap ? '\n' + s : s;
|
const wrap = (s) => power_user.instruct.wrap ? '\n' + s : s;
|
||||||
|
// Should not contain timestamp macros
|
||||||
|
const hasTimestamp = /{{timestamp}}/gi.test(sequence) || /{{timestamp::(.*?)}}/gi.test(sequence);
|
||||||
// Sequence must be a non-empty string
|
// Sequence must be a non-empty string
|
||||||
if (typeof sequence === 'string' && sequence.length > 0) {
|
if (typeof sequence === 'string' && sequence.length > 0 && !hasTimestamp) {
|
||||||
// If sequence is just a whitespace or newline - we don't want to make it a stopping string
|
// If sequence is just a whitespace or newline - we don't want to make it a stopping string
|
||||||
// User can always add it as a custom stop string if really needed
|
// User can always add it as a custom stop string if really needed
|
||||||
if (sequence.trim().length > 0) {
|
if (sequence.trim().length > 0) {
|
||||||
@@ -309,19 +312,35 @@ export const force_output_sequence = {
|
|||||||
LAST: 2,
|
LAST: 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces instruct mode macros in the given sequence string.
|
||||||
|
* @param {string} sequence Sequence string.
|
||||||
|
* @param {string} name Item name.
|
||||||
|
* @param {import('moment').Moment} timestamp Message timestamp.
|
||||||
|
* @returns {string} Sequence string with macros replaced.
|
||||||
|
*/
|
||||||
|
function replaceSequenceMacros(sequence, name, timestamp) {
|
||||||
|
sequence = substituteParams(sequence);
|
||||||
|
sequence = sequence.replace(/{{name}}/gi, name || 'System');
|
||||||
|
sequence = sequence.replace(/{{timestamp}}/gi, () => timestamp.format('YYYY-MM-DD HH:mm:ss'));
|
||||||
|
sequence = sequence.replace(/{{timestamp::(.*?)}}/gi, (_, format) => timestamp.format(format));
|
||||||
|
return sequence;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats instruct mode chat message.
|
* Formats instruct mode chat message.
|
||||||
* @param {string} name Character name.
|
* @param {InstructFormatParams} params Message parameters.
|
||||||
* @param {string} mes Message text.
|
* @typedef {object} InstructFormatParams Instruct mode chat message parameters.
|
||||||
* @param {boolean} isUser Is the message from the user.
|
* @property {string} name Character name.
|
||||||
* @param {boolean} isNarrator Is the message from the narrator.
|
* @property {string} mes Message text.
|
||||||
* @param {string} forceAvatar Force avatar string.
|
* @property {boolean} isUser Is the message from the user.
|
||||||
* @param {string} name1 User name.
|
* @property {boolean} isNarrator Is the message from the narrator.
|
||||||
* @param {string} name2 Character name.
|
* @property {string} forceAvatar Force avatar string.
|
||||||
* @param {boolean|number} forceOutputSequence Force to use first/last output sequence (if configured).
|
* @property {boolean|number} forceOutputSequence Force to use first/last output sequence (if configured).
|
||||||
|
* @property {import('moment').Moment} timestamp Message timestamp.
|
||||||
* @returns {string} Formatted instruct mode chat message.
|
* @returns {string} Formatted instruct mode chat message.
|
||||||
*/
|
*/
|
||||||
export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvatar, name1, name2, forceOutputSequence) {
|
export function formatInstructModeChat({ name, mes, isUser, isNarrator, forceAvatar, forceOutputSequence, timestamp }) {
|
||||||
let includeNames = isNarrator ? false : power_user.instruct.names_behavior === names_behavior_types.ALWAYS;
|
let includeNames = isNarrator ? false : power_user.instruct.names_behavior === names_behavior_types.ALWAYS;
|
||||||
|
|
||||||
if (!isNarrator && power_user.instruct.names_behavior === names_behavior_types.FORCE && ((selected_group && name !== name1) || (forceAvatar && name !== name1))) {
|
if (!isNarrator && power_user.instruct.names_behavior === names_behavior_types.FORCE && ((selected_group && name !== name1) || (forceAvatar && name !== name1))) {
|
||||||
@@ -372,11 +391,8 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata
|
|||||||
let suffix = getSuffix() || '';
|
let suffix = getSuffix() || '';
|
||||||
|
|
||||||
if (power_user.instruct.macro) {
|
if (power_user.instruct.macro) {
|
||||||
prefix = substituteParams(prefix, name1, name2);
|
prefix = replaceSequenceMacros(prefix, (name || 'System'), timestamp);
|
||||||
prefix = prefix.replace(/{{name}}/gi, name || 'System');
|
suffix = replaceSequenceMacros(suffix, (name || 'System'), timestamp);
|
||||||
|
|
||||||
suffix = substituteParams(suffix, name1, name2);
|
|
||||||
suffix = suffix.replace(/{{name}}/gi, name || 'System');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!suffix && power_user.instruct.wrap) {
|
if (!suffix && power_user.instruct.wrap) {
|
||||||
@@ -420,11 +436,9 @@ export function formatInstructModeSystemPrompt(systemPrompt) {
|
|||||||
/**
|
/**
|
||||||
* Formats example messages according to instruct mode settings.
|
* Formats example messages according to instruct mode settings.
|
||||||
* @param {string[]} mesExamplesArray Example messages array.
|
* @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(mesExamplesArray, name1, name2) {
|
export function formatInstructModeExamples(mesExamplesArray) {
|
||||||
const blockHeading = power_user.context.example_separator ? `${substituteParams(power_user.context.example_separator)}\n` : '';
|
const blockHeading = power_user.context.example_separator ? `${substituteParams(power_user.context.example_separator)}\n` : '';
|
||||||
|
|
||||||
if (power_user.instruct.skip_examples) {
|
if (power_user.instruct.skip_examples) {
|
||||||
@@ -440,15 +454,10 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) {
|
|||||||
let outputSuffix = power_user.instruct.output_suffix || '';
|
let outputSuffix = power_user.instruct.output_suffix || '';
|
||||||
|
|
||||||
if (power_user.instruct.macro) {
|
if (power_user.instruct.macro) {
|
||||||
inputPrefix = substituteParams(inputPrefix, name1, name2);
|
inputPrefix = replaceSequenceMacros(inputPrefix, name1, moment());
|
||||||
outputPrefix = substituteParams(outputPrefix, name1, name2);
|
outputPrefix = replaceSequenceMacros(outputPrefix, name2, moment());
|
||||||
inputSuffix = substituteParams(inputSuffix, name1, name2);
|
inputSuffix = replaceSequenceMacros(inputSuffix, name1, moment());
|
||||||
outputSuffix = substituteParams(outputSuffix, name1, name2);
|
outputSuffix = replaceSequenceMacros(outputSuffix, name2, moment());
|
||||||
|
|
||||||
inputPrefix = inputPrefix.replace(/{{name}}/gi, name1);
|
|
||||||
outputPrefix = outputPrefix.replace(/{{name}}/gi, name2);
|
|
||||||
inputSuffix = inputSuffix.replace(/{{name}}/gi, name1);
|
|
||||||
outputSuffix = outputSuffix.replace(/{{name}}/gi, name2);
|
|
||||||
|
|
||||||
if (!inputSuffix && power_user.instruct.wrap) {
|
if (!inputSuffix && power_user.instruct.wrap) {
|
||||||
inputSuffix = '\n';
|
inputSuffix = '\n';
|
||||||
@@ -499,13 +508,11 @@ export function formatInstructModeExamples(mesExamplesArray, name1, name2) {
|
|||||||
* @param {string} name Character name.
|
* @param {string} name Character name.
|
||||||
* @param {boolean} isImpersonate Is generation in impersonation mode.
|
* @param {boolean} isImpersonate Is generation in impersonation mode.
|
||||||
* @param {string} promptBias Prompt bias string.
|
* @param {string} promptBias Prompt bias string.
|
||||||
* @param {string} name1 User name.
|
|
||||||
* @param {string} name2 Character name.
|
|
||||||
* @param {boolean} isQuiet Is quiet mode generation.
|
* @param {boolean} isQuiet Is quiet mode generation.
|
||||||
* @param {boolean} isQuietToLoud Is quiet to loud generation.
|
* @param {boolean} isQuietToLoud Is quiet to loud generation.
|
||||||
* @returns {string} Formatted instruct mode last prompt line.
|
* @returns {string} Formatted instruct mode last prompt line.
|
||||||
*/
|
*/
|
||||||
export function formatInstructModePrompt(name, isImpersonate, promptBias, name1, name2, isQuiet, isQuietToLoud) {
|
export function formatInstructModePrompt(name, isImpersonate, promptBias, isQuiet, isQuietToLoud) {
|
||||||
const includeNames = name && (power_user.instruct.names_behavior === names_behavior_types.ALWAYS || (!!selected_group && power_user.instruct.names_behavior === names_behavior_types.FORCE)) && !(isQuiet && !isQuietToLoud);
|
const includeNames = name && (power_user.instruct.names_behavior === names_behavior_types.ALWAYS || (!!selected_group && power_user.instruct.names_behavior === names_behavior_types.FORCE)) && !(isQuiet && !isQuietToLoud);
|
||||||
|
|
||||||
function getSequence() {
|
function getSequence() {
|
||||||
@@ -545,8 +552,7 @@ export function formatInstructModePrompt(name, isImpersonate, promptBias, name1,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (power_user.instruct.macro) {
|
if (power_user.instruct.macro) {
|
||||||
sequence = substituteParams(sequence, name1, name2);
|
sequence = replaceSequenceMacros(sequence, (name || 'System'), moment());
|
||||||
sequence = sequence.replace(/{{name}}/gi, name || 'System');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const separator = power_user.instruct.wrap ? '\n' : '';
|
const separator = power_user.instruct.wrap ? '\n' : '';
|
||||||
|
Reference in New Issue
Block a user