Added stop string cleanup, better stopping string param
| @@ -2,7 +2,7 @@ import { getPresetManager } from './preset-manager.js'; | ||
| 2 | 2 | import { extractMessageFromData, getGenerateUrl, getRequestHeaders } from '../script.js'; |
| 3 | 3 | import { getTextGenServer } from './textgen-settings.js'; |
| 4 | 4 | import { extractReasoningFromData } from './reasoning.js'; |
| 5 | 5 | import { formatInstructModeChat, formatInstructModePrompt, getInstructStoppingSequences, names_behavior_types } from './instruct-mode.js'; |
| 6 | 6 | import { getStreamingReply, tryParseStreamingError } from './openai.js'; |
| 7 | 7 | import EventSourceStream from './sse-stream.js'; |
| 8 | 8 | |
| @@ -222,10 +222,13 @@ export class TextCompletionService { | ||
| 222 | 222 | } |
| 223 | 223 | } |
| 224 | 224 | |
| 225 | + | |
| 226 | + /** @type {InstructSettings | undefined} */ | |
| 227 | + let instructPreset; | |
| 225 | 228 | // Handle instruct formatting if requested |
| 226 | 229 | if (Array.isArray(prompt) && instructName) { |
| 227 | 230 | const instructPresetManager = getPresetManager('instruct'); |
| 228 | 231 | let instructPreset = instructPresetManager?.getCompletionPresetByName(instructName); |
| 229 | 232 | if (instructPreset) { |
| 230 | 233 | // Clone the preset to avoid modifying the original |
| 231 | 234 | instructPreset = structuredClone(instructPreset); |
| @@ -266,10 +269,9 @@ export class TextCompletionService { | ||
| 266 | 269 | formattedMessages.push(messageContent); |
| 267 | 270 | } |
| 268 | 271 | requestData.prompt = formattedMessages.join(''); |
| 269 | - if (instructPreset.output_suffix) { | |
| 272 | + const stoppingStrings = getInstructStoppingSequences({ customInstruct: instructPreset, useStopString: false }); | |
| 270 | 273 | requestData.stop = [instructPreset.output_suffix];stoppingStrings |
| 271 | 274 | requestData.stopping_strings = [instructPreset.output_suffix]stoppingStrings; |
| 272 | - } | |
| 273 | 275 | } else { |
| 274 | 276 | console.warn(`Instruct preset "${instructName}" not found, using basic formatting`); |
| 275 | 277 | requestData.prompt = prompt.map(x => x.content).join('\n\n'); |
| @@ -283,7 +285,63 @@ export class TextCompletionService { | ||
| 283 | 285 | // @ts-ignore |
| 284 | 286 | const data = this.createRequestData(requestData); |
| 285 | 287 | |
| 286 | 288 | 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; | |
| 287 | 345 | } |
| 288 | 346 | |
| 289 | 347 | /** |
| @@ -243,9 +243,12 @@ export function autoSelectInstructPreset(modelId) { | ||
| 243 | 243 | |
| 244 | 244 | /** |
| 245 | 245 | * Converts instruct mode sequences to an array of stopping strings. |
| 246 | + * @param {{customInstruct?: InstructSettings, useStopString?: boolean}} options | |
| 246 | 247 | * @returns {string[]} Array of instruct mode stopping strings. |
| 247 | 248 | */ |
| 248 | -export function getInstructStoppingSequences() { | |
| 249 | +export function getInstructStoppingSequences({ customInstruct = null, useStopString = false } = {}) { | |
| 250 | + const instruct = structuredClone(customInstruct ?? power_user.instruct); | |
| 251 | + | |
| 249 | 252 | /** |
| 250 | 253 | * Adds instruct mode sequence to the result array. |
| 251 | 254 | * @param {string} sequence Sequence string. |
| @@ -254,7 +257,7 @@ export function getInstructStoppingSequences() { | ||
| 254 | 257 | function addInstructSequence(sequence) { |
| 255 | 258 | // Cohee: oobabooga's textgen always appends newline before the sequence as a stopping string |
| 256 | 259 | // But it's a problem for Metharme which doesn't use newlines to separate them. |
| 257 | 260 | const wrap = (s) => power_user.instruct.wrap ? '\n' + s : s; |
| 258 | 261 | // Sequence must be a non-empty string |
| 259 | 262 | if (typeof sequence === 'string' && sequence.length > 0) { |
| 260 | 263 | // 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() { | ||
| 262 | 265 | if (sequence.trim().length > 0) { |
| 263 | 266 | const wrappedSequence = wrap(sequence); |
| 264 | 267 | // Need to respect "insert macro" setting |
| 265 | 268 | const stopString = power_user.instruct.macro ? substituteParams(wrappedSequence) : wrappedSequence; |
| 266 | 269 | result.push(stopString); |
| 267 | 270 | } |
| 268 | 271 | } |
| @@ -270,14 +273,15 @@ export function getInstructStoppingSequences() { | ||
| 270 | 273 | |
| 271 | 274 | const result = []; |
| 272 | 275 | |
| 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) { | |
| 275 | 278 | const input_sequencestop_sequence = power_user.instruct.input_sequence?.replace(/{{name}}/gi, name1)stop_sequence || ''; |
| 276 | 279 | const output_sequenceinput_sequence = power_user.instruct.output_sequenceinput_sequence?.replace(/{{name}}/gi, name2name1) || ''; |
| 277 | 280 | const first_output_sequenceoutput_sequence = power_user.instruct.first_output_sequenceoutput_sequence?.replace(/{{name}}/gi, name2) || ''; |
| 278 | 281 | const last_output_sequencefirst_output_sequence = power_user.instruct.last_output_sequencefirst_output_sequence?.replace(/{{name}}/gi, name2) || ''; |
| 279 | 282 | const system_sequencelast_output_sequence = power_user.instruct.system_sequencelast_output_sequence?.replace(/{{name}}/gi, 'System'name2) || ''; |
| 280 | 283 | 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') || ''; | |
| 281 | 285 | |
| 282 | 286 | const combined_sequence = [ |
| 283 | 287 | stop_sequence, |
| @@ -292,7 +296,7 @@ export function getInstructStoppingSequences() { | ||
| 292 | 296 | combined_sequence.split('\n').filter((line, index, self) => self.indexOf(line) === index).forEach(addInstructSequence); |
| 293 | 297 | } |
| 294 | 298 | |
| 295 | 299 | if (useStopString ?? power_user.context.use_stop_strings) { |
| 296 | 300 | if (power_user.context.chat_start) { |
| 297 | 301 | result.push(`\n${substituteParams(power_user.context.chat_start)}`); |
| 298 | 302 | } |