Added stop string cleanup, better stopping string param

c5f251c6e376701a273876affaa7a87910420453

bmen25124 <bmen25124@gmail.com>

2 files changed, +81 -19Ignore whitespace
public/scripts/custom-request.js+65 -7
@@ -2,7 +2,7 @@ import { getPresetManager } from './preset-manager.js';
22import { extractMessageFromData, getGenerateUrl, getRequestHeaders } from '../script.js';
33import { getTextGenServer } from './textgen-settings.js';
44import { extractReasoningFromData } from './reasoning.js';
55import { formatInstructModeChat, formatInstructModePrompt, getInstructStoppingSequences, names_behavior_types } from './instruct-mode.js';
66import { getStreamingReply, tryParseStreamingError } from './openai.js';
77import EventSourceStream from './sse-stream.js';
88
@@ -222,10 +222,13 @@ export class TextCompletionService {
222222 }
223223 }
224224
225+
226+ /** @type {InstructSettings | undefined} */
227+ let instructPreset;
225228 // Handle instruct formatting if requested
226229 if (Array.isArray(prompt) && instructName) {
227230 const instructPresetManager = getPresetManager('instruct');
228231 let instructPreset = instructPresetManager?.getCompletionPresetByName(instructName);
229232 if (instructPreset) {
230233 // Clone the preset to avoid modifying the original
231234 instructPreset = structuredClone(instructPreset);
@@ -266,10 +269,9 @@ export class TextCompletionService {
266269 formattedMessages.push(messageContent);
267270 }
268271 requestData.prompt = formattedMessages.join('');
269- if (instructPreset.output_suffix) {
272+ const stoppingStrings = getInstructStoppingSequences({ customInstruct: instructPreset, useStopString: false });
270273 requestData.stop = [instructPreset.output_suffix];stoppingStrings
271274 requestData.stopping_strings = [instructPreset.output_suffix]stoppingStrings;
272- }
273275 } else {
274276 console.warn(`Instruct preset "${instructName}" not found, using basic formatting`);
275277 requestData.prompt = prompt.map(x => x.content).join('\n\n');
@@ -283,7 +285,63 @@ export class TextCompletionService {
283285 // @ts-ignore
284286 const data = this.createRequestData(requestData);
285287
286288 returnconst response = await this.sendRequest(data, extractData, signal);
289+ // Remove stopping strings from the end
290+ if (!data.stream && extractData) {
291+ /** @type {ExtractedData} */
292+ // @ts-ignore
293+ const extractedData = response;
294+
295+ let message = extractedData.content;
296+
297+ message = message.replace(/[^\S\r\n]+$/gm, '');
298+
299+ if (requestData.stopping_strings) {
300+ for (const stoppingString of requestData.stopping_strings) {
301+ if (stoppingString.length) {
302+ for (let j = stoppingString.length; j > 0; j--) {
303+ if (message.slice(-j) === stoppingString.slice(0, j)) {
304+ message = message.slice(0, -j);
305+ break;
306+ }
307+ }
308+ }
309+ }
310+ }
311+
312+ if (instructPreset) {
313+ if (instructPreset.stop_sequence) {
314+ const index = message.indexOf(instructPreset.stop_sequence);
315+ if (index != -1) {
316+ message = message.substring(0, index);
317+ }
318+ }
319+ if (instructPreset.input_sequence && instructPreset.input_sequence.trim()) {
320+ const index = message.indexOf(instructPreset.input_sequence);
321+ if (index != -1) {
322+ message = message.substring(0, index);
323+ }
324+ }
325+ if (instructPreset.output_sequence) {
326+ instructPreset.output_sequence.split('\n')
327+ .filter(line => line.trim() !== '')
328+ .forEach(line => {
329+ message = message.replaceAll(line, '');
330+ });
331+ }
332+ if (instructPreset.last_output_sequence) {
333+ instructPreset.last_output_sequence.split('\n')
334+ .filter(line => line.trim() !== '')
335+ .forEach(line => {
336+ message = message.replaceAll(line, '');
337+ });
338+ }
339+ }
340+
341+ extractedData.content = message;
342+ }
343+
344+ return response;
287345 }
288346
289347 /**
public/scripts/instruct-mode.js+16 -12
@@ -243,9 +243,12 @@ export function autoSelectInstructPreset(modelId) {
243243
244244/**
245245 * Converts instruct mode sequences to an array of stopping strings.
246+ * @param {{customInstruct?: InstructSettings, useStopString?: boolean}} options
246247 * @returns {string[]} Array of instruct mode stopping strings.
247248 */
248-export function getInstructStoppingSequences() {
249+export function getInstructStoppingSequences({ customInstruct = null, useStopString = false } = {}) {
250+ const instruct = structuredClone(customInstruct ?? power_user.instruct);
251+
249252 /**
250253 * Adds instruct mode sequence to the result array.
251254 * @param {string} sequence Sequence string.
@@ -254,7 +257,7 @@ export function getInstructStoppingSequences() {
254257 function addInstructSequence(sequence) {
255258 // Cohee: oobabooga's textgen always appends newline before the sequence as a stopping string
256259 // But it's a problem for Metharme which doesn't use newlines to separate them.
257260 const wrap = (s) => power_user.instruct.wrap ? '\n' + s : s;
258261 // Sequence must be a non-empty string
259262 if (typeof sequence === 'string' && sequence.length > 0) {
260263 // 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() {
262265 if (sequence.trim().length > 0) {
263266 const wrappedSequence = wrap(sequence);
264267 // Need to respect "insert macro" setting
265268 const stopString = power_user.instruct.macro ? substituteParams(wrappedSequence) : wrappedSequence;
266269 result.push(stopString);
267270 }
268271 }
@@ -270,14 +273,15 @@ export function getInstructStoppingSequences() {
270273
271274 const result = [];
272275
273- if (power_user.instruct.enabled) {
276+ // Since preset's don't have "enabled", we assume it's always enabled
274- const stop_sequence = power_user.instruct.stop_sequence || '';
277+ if (customInstruct ?? instruct.enabled) {
275278 const input_sequencestop_sequence = power_user.instruct.input_sequence?.replace(/{{name}}/gi, name1)stop_sequence || '';
276279 const output_sequenceinput_sequence = power_user.instruct.output_sequenceinput_sequence?.replace(/{{name}}/gi, name2name1) || '';
277280 const first_output_sequenceoutput_sequence = power_user.instruct.first_output_sequenceoutput_sequence?.replace(/{{name}}/gi, name2) || '';
278281 const last_output_sequencefirst_output_sequence = power_user.instruct.last_output_sequencefirst_output_sequence?.replace(/{{name}}/gi, name2) || '';
279282 const system_sequencelast_output_sequence = power_user.instruct.system_sequencelast_output_sequence?.replace(/{{name}}/gi, 'System'name2) || '';
280283 const last_system_sequencesystem_sequence = power_user.instruct.last_system_sequencesystem_sequence?.replace(/{{name}}/gi, 'System') || '';
284+ const last_system_sequence = instruct.last_system_sequence?.replace(/{{name}}/gi, 'System') || '';
281285
282286 const combined_sequence = [
283287 stop_sequence,
@@ -292,7 +296,7 @@ export function getInstructStoppingSequences() {
292296 combined_sequence.split('\n').filter((line, index, self) => self.indexOf(line) === index).forEach(addInstructSequence);
293297 }
294298
295299 if (useStopString ?? power_user.context.use_stop_strings) {
296300 if (power_user.context.chat_start) {
297301 result.push(`\n${substituteParams(power_user.context.chat_start)}`);
298302 }