mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Added stop string cleanup, better stopping string param
This commit is contained in:
@ -2,7 +2,7 @@ import { getPresetManager } from './preset-manager.js';
|
|||||||
import { extractMessageFromData, getGenerateUrl, getRequestHeaders } from '../script.js';
|
import { extractMessageFromData, getGenerateUrl, getRequestHeaders } from '../script.js';
|
||||||
import { getTextGenServer } from './textgen-settings.js';
|
import { getTextGenServer } from './textgen-settings.js';
|
||||||
import { extractReasoningFromData } from './reasoning.js';
|
import { extractReasoningFromData } from './reasoning.js';
|
||||||
import { formatInstructModeChat, formatInstructModePrompt, names_behavior_types } from './instruct-mode.js';
|
import { formatInstructModeChat, formatInstructModePrompt, getInstructStoppingSequences, names_behavior_types } from './instruct-mode.js';
|
||||||
import { getStreamingReply, tryParseStreamingError } from './openai.js';
|
import { getStreamingReply, tryParseStreamingError } from './openai.js';
|
||||||
import EventSourceStream from './sse-stream.js';
|
import EventSourceStream from './sse-stream.js';
|
||||||
|
|
||||||
@ -222,10 +222,13 @@ export class TextCompletionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @type {InstructSettings | undefined} */
|
||||||
|
let instructPreset;
|
||||||
// Handle instruct formatting if requested
|
// Handle instruct formatting if requested
|
||||||
if (Array.isArray(prompt) && instructName) {
|
if (Array.isArray(prompt) && instructName) {
|
||||||
const instructPresetManager = getPresetManager('instruct');
|
const instructPresetManager = getPresetManager('instruct');
|
||||||
let instructPreset = instructPresetManager?.getCompletionPresetByName(instructName);
|
instructPreset = instructPresetManager?.getCompletionPresetByName(instructName);
|
||||||
if (instructPreset) {
|
if (instructPreset) {
|
||||||
// Clone the preset to avoid modifying the original
|
// Clone the preset to avoid modifying the original
|
||||||
instructPreset = structuredClone(instructPreset);
|
instructPreset = structuredClone(instructPreset);
|
||||||
@ -266,10 +269,9 @@ export class TextCompletionService {
|
|||||||
formattedMessages.push(messageContent);
|
formattedMessages.push(messageContent);
|
||||||
}
|
}
|
||||||
requestData.prompt = formattedMessages.join('');
|
requestData.prompt = formattedMessages.join('');
|
||||||
if (instructPreset.output_suffix) {
|
const stoppingStrings = getInstructStoppingSequences({ customInstruct: instructPreset, useStopString: false });
|
||||||
requestData.stop = [instructPreset.output_suffix];
|
requestData.stop = stoppingStrings
|
||||||
requestData.stopping_strings = [instructPreset.output_suffix];
|
requestData.stopping_strings = stoppingStrings;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
console.warn(`Instruct preset "${instructName}" not found, using basic formatting`);
|
console.warn(`Instruct preset "${instructName}" not found, using basic formatting`);
|
||||||
requestData.prompt = prompt.map(x => x.content).join('\n\n');
|
requestData.prompt = prompt.map(x => x.content).join('\n\n');
|
||||||
@ -283,7 +285,63 @@ export class TextCompletionService {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const data = this.createRequestData(requestData);
|
const data = this.createRequestData(requestData);
|
||||||
|
|
||||||
return await this.sendRequest(data, extractData, signal);
|
const response = await this.sendRequest(data, extractData, signal);
|
||||||
|
// Remove stopping strings from the end
|
||||||
|
if (!data.stream && extractData) {
|
||||||
|
/** @type {ExtractedData} */
|
||||||
|
// @ts-ignore
|
||||||
|
const extractedData = response;
|
||||||
|
|
||||||
|
let message = extractedData.content;
|
||||||
|
|
||||||
|
message = message.replace(/[^\S\r\n]+$/gm, '');
|
||||||
|
|
||||||
|
if (requestData.stopping_strings) {
|
||||||
|
for (const stoppingString of requestData.stopping_strings) {
|
||||||
|
if (stoppingString.length) {
|
||||||
|
for (let j = stoppingString.length; j > 0; j--) {
|
||||||
|
if (message.slice(-j) === stoppingString.slice(0, j)) {
|
||||||
|
message = message.slice(0, -j);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instructPreset) {
|
||||||
|
if (instructPreset.stop_sequence) {
|
||||||
|
const index = message.indexOf(instructPreset.stop_sequence);
|
||||||
|
if (index != -1) {
|
||||||
|
message = message.substring(0, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (instructPreset.input_sequence && instructPreset.input_sequence.trim()) {
|
||||||
|
const index = message.indexOf(instructPreset.input_sequence);
|
||||||
|
if (index != -1) {
|
||||||
|
message = message.substring(0, index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (instructPreset.output_sequence) {
|
||||||
|
instructPreset.output_sequence.split('\n')
|
||||||
|
.filter(line => line.trim() !== '')
|
||||||
|
.forEach(line => {
|
||||||
|
message = message.replaceAll(line, '');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (instructPreset.last_output_sequence) {
|
||||||
|
instructPreset.last_output_sequence.split('\n')
|
||||||
|
.filter(line => line.trim() !== '')
|
||||||
|
.forEach(line => {
|
||||||
|
message = message.replaceAll(line, '');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extractedData.content = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -243,9 +243,12 @@ export function autoSelectInstructPreset(modelId) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts instruct mode sequences to an array of stopping strings.
|
* Converts instruct mode sequences to an array of stopping strings.
|
||||||
|
* @param {{customInstruct?: InstructSettings, useStopString?: boolean}} options
|
||||||
* @returns {string[]} Array of instruct mode stopping strings.
|
* @returns {string[]} Array of instruct mode stopping strings.
|
||||||
*/
|
*/
|
||||||
export function getInstructStoppingSequences() {
|
export function getInstructStoppingSequences({ customInstruct = null, useStopString = false } = {}) {
|
||||||
|
const instruct = structuredClone(customInstruct ?? power_user.instruct);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds instruct mode sequence to the result array.
|
* Adds instruct mode sequence to the result array.
|
||||||
* @param {string} sequence Sequence string.
|
* @param {string} sequence Sequence string.
|
||||||
@ -254,7 +257,7 @@ export function getInstructStoppingSequences() {
|
|||||||
function addInstructSequence(sequence) {
|
function addInstructSequence(sequence) {
|
||||||
// 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) => instruct.wrap ? '\n' + s : s;
|
||||||
// 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) {
|
||||||
// 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
|
||||||
@ -262,7 +265,7 @@ export function getInstructStoppingSequences() {
|
|||||||
if (sequence.trim().length > 0) {
|
if (sequence.trim().length > 0) {
|
||||||
const wrappedSequence = wrap(sequence);
|
const wrappedSequence = wrap(sequence);
|
||||||
// Need to respect "insert macro" setting
|
// Need to respect "insert macro" setting
|
||||||
const stopString = power_user.instruct.macro ? substituteParams(wrappedSequence) : wrappedSequence;
|
const stopString = instruct.macro ? substituteParams(wrappedSequence) : wrappedSequence;
|
||||||
result.push(stopString);
|
result.push(stopString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -270,14 +273,15 @@ export function getInstructStoppingSequences() {
|
|||||||
|
|
||||||
const result = [];
|
const result = [];
|
||||||
|
|
||||||
if (power_user.instruct.enabled) {
|
// Since preset's don't have "enabled", we assume it's always enabled
|
||||||
const stop_sequence = power_user.instruct.stop_sequence || '';
|
if (customInstruct ?? instruct.enabled) {
|
||||||
const input_sequence = power_user.instruct.input_sequence?.replace(/{{name}}/gi, name1) || '';
|
const stop_sequence = instruct.stop_sequence || '';
|
||||||
const output_sequence = power_user.instruct.output_sequence?.replace(/{{name}}/gi, name2) || '';
|
const input_sequence = instruct.input_sequence?.replace(/{{name}}/gi, name1) || '';
|
||||||
const first_output_sequence = power_user.instruct.first_output_sequence?.replace(/{{name}}/gi, name2) || '';
|
const output_sequence = instruct.output_sequence?.replace(/{{name}}/gi, name2) || '';
|
||||||
const last_output_sequence = power_user.instruct.last_output_sequence?.replace(/{{name}}/gi, name2) || '';
|
const first_output_sequence = instruct.first_output_sequence?.replace(/{{name}}/gi, name2) || '';
|
||||||
const system_sequence = power_user.instruct.system_sequence?.replace(/{{name}}/gi, 'System') || '';
|
const last_output_sequence = instruct.last_output_sequence?.replace(/{{name}}/gi, name2) || '';
|
||||||
const last_system_sequence = power_user.instruct.last_system_sequence?.replace(/{{name}}/gi, 'System') || '';
|
const system_sequence = instruct.system_sequence?.replace(/{{name}}/gi, 'System') || '';
|
||||||
|
const last_system_sequence = instruct.last_system_sequence?.replace(/{{name}}/gi, 'System') || '';
|
||||||
|
|
||||||
const combined_sequence = [
|
const combined_sequence = [
|
||||||
stop_sequence,
|
stop_sequence,
|
||||||
@ -292,7 +296,7 @@ export function getInstructStoppingSequences() {
|
|||||||
combined_sequence.split('\n').filter((line, index, self) => self.indexOf(line) === index).forEach(addInstructSequence);
|
combined_sequence.split('\n').filter((line, index, self) => self.indexOf(line) === index).forEach(addInstructSequence);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (power_user.context.use_stop_strings) {
|
if (useStopString ?? power_user.context.use_stop_strings) {
|
||||||
if (power_user.context.chat_start) {
|
if (power_user.context.chat_start) {
|
||||||
result.push(`\n${substituteParams(power_user.context.chat_start)}`);
|
result.push(`\n${substituteParams(power_user.context.chat_start)}`);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user