Merge pull request #3737 from qvink/staging Adding option to disable removal of "{{user}}:" and "{{char}}:" in generateRaw()
Signed| @@ -3315,11 +3315,23 @@ class StreamingProcessor { | |||
| 3315 | 3315 | ||
| 3316 | if (!isImpersonate && !isContinue && Array.isArray(this.swipes) && this.swipes.length > 0) { | 3316 | if (!isImpersonate && !isContinue && Array.isArray(this.swipes) && this.swipes.length > 0) { |
| 3317 | for (let i = 0; i < this.swipes.length; i++) { | 3317 | for (let i = 0; i < this.swipes.length; i++) { |
| 3318 | this.swipes[i] = cleanUpMessage(this.swipes[i], false, false, true, this.stoppingStrings); | 3318 | this.swipes[i] = cleanUpMessage({ |
| 3319 | getMessage: this.swipes[i], | ||
| 3320 | isImpersonate: false, | ||
| 3321 | isContinue: false, | ||
| 3322 | displayIncompleteSentences: true, | ||
| 3323 | stoppingStrings: this.stoppingStrings, | ||
| 3324 | }); | ||
| 3319 | } | 3325 | } |
| 3320 | } | 3326 | } |
| 3321 | 3327 | ||
| 3322 | let processedText = cleanUpMessage(text, isImpersonate, isContinue, !isFinal, this.stoppingStrings); | 3328 | let processedText = cleanUpMessage({ |
| 3329 | getMessage: text, | ||
| 3330 | isImpersonate: isImpersonate, | ||
| 3331 | isContinue: isContinue, | ||
| 3332 | displayIncompleteSentences: !isFinal, | ||
| 3333 | stoppingStrings: this.stoppingStrings, | ||
| 3334 | }); | ||
| 3323 | 3335 | ||
| 3324 | const charsToBalance = ['*', '"', '```']; | 3336 | const charsToBalance = ['*', '"', '```']; |
| 3325 | for (const char of charsToBalance) { | 3337 | for (const char of charsToBalance) { |
| @@ -3551,9 +3563,10 @@ class StreamingProcessor { | |||
| 3551 | * @param {boolean} quietToLoud true to generate a message in system mode, false to generate a message in character mode | 3563 | * @param {boolean} quietToLoud true to generate a message in system mode, false to generate a message in character mode |
| 3552 | * @param {string} [systemPrompt] System prompt to use. Only Instruct mode or OpenAI. | 3564 | * @param {string} [systemPrompt] System prompt to use. Only Instruct mode or OpenAI. |
| 3553 | * @param {number} [responseLength] Maximum response length. If unset, the global default value is used. | 3565 | * @param {number} [responseLength] Maximum response length. If unset, the global default value is used. |
| 3566 | * @param {boolean} [trimNames] Whether to allow trimming "{{user}}:" and "{{char}}:" from the response. | ||
| 3554 | * @returns {Promise<string>} Generated message | 3567 | * @returns {Promise<string>} Generated message |
| 3555 | */ | 3568 | */ |
| 3556 | export async function generateRaw(prompt, api, instructOverride, quietToLoud, systemPrompt, responseLength) { | 3569 | export async function generateRaw(prompt, api, instructOverride, quietToLoud, systemPrompt, responseLength, trimNames = true) { |
| 3557 | if (!api) { | 3570 | if (!api) { |
| 3558 | api = main_api; | 3571 | api = main_api; |
| 3559 | } | 3572 | } |
| @@ -3643,7 +3656,15 @@ export async function generateRaw(prompt, api, instructOverride, quietToLoud, sy | |||
| 3643 | } | 3656 | } |
| 3644 | 3657 | ||
| 3645 | // format result, exclude user prompt bias | 3658 | // format result, exclude user prompt bias |
| 3646 | const message = cleanUpMessage(extractMessageFromData(data), false, false, true, null, false); | 3659 | const message = cleanUpMessage({ |
| 3660 | getMessage: extractMessageFromData(data), | ||
| 3661 | isImpersonate: false, | ||
| 3662 | isContinue: false, | ||
| 3663 | displayIncompleteSentences: true, | ||
| 3664 | includeUserPromptBias: false, | ||
| 3665 | trimNames: trimNames, | ||
| 3666 | trimWrongNames: trimNames, | ||
| 3667 | }); | ||
| 3647 | 3668 | ||
| 3648 | if (!message) { | 3669 | if (!message) { |
| 3649 | throw new Error('No message generated'); | 3670 | throw new Error('No message generated'); |
| @@ -4844,7 +4865,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4844 | 4865 | ||
| 4845 | hideSwipeButtons(); | 4866 | hideSwipeButtons(); |
| 4846 | let getMessage = await streamingProcessor.generate(); | 4867 | let getMessage = await streamingProcessor.generate(); |
| 4847 | let messageChunk = cleanUpMessage(getMessage, isImpersonate, isContinue, false); | 4868 | let messageChunk = cleanUpMessage({ |
| 4869 | getMessage: getMessage, | ||
| 4870 | isImpersonate: isImpersonate, | ||
| 4871 | isContinue: isContinue, | ||
| 4872 | displayIncompleteSentences: false, | ||
| 4873 | }); | ||
| 4848 | 4874 | ||
| 4849 | if (isContinue) { | 4875 | if (isContinue) { |
| 4850 | getMessage = continue_mag + getMessage; | 4876 | getMessage = continue_mag + getMessage; |
| @@ -4928,7 +4954,14 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4928 | 4954 | ||
| 4929 | const swipes = extractMultiSwipes(data, type); | 4955 | const swipes = extractMultiSwipes(data, type); |
| 4930 | 4956 | ||
| 4931 | messageChunk = cleanUpMessage(getMessage, isImpersonate, isContinue, false); | 4957 | messageChunk = cleanUpMessage({ |
| 4958 | getMessage: getMessage, | ||
| 4959 | isImpersonate: isImpersonate, | ||
| 4960 | isContinue: isContinue, | ||
| 4961 | displayIncompleteSentences: false, | ||
| 4962 | }); | ||
| 4963 | |||
| 4964 | |||
| 4932 | reasoning = getRegexedString(reasoning, regex_placement.REASONING); | 4965 | reasoning = getRegexedString(reasoning, regex_placement.REASONING); |
| 4933 | 4966 | ||
| 4934 | if (power_user.trim_spaces) { | 4967 | if (power_user.trim_spaces) { |
| @@ -4942,7 +4975,12 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | |||
| 4942 | 4975 | ||
| 4943 | //Formating | 4976 | //Formating |
| 4944 | const displayIncomplete = type === 'quiet' && !quietToLoud; | 4977 | const displayIncomplete = type === 'quiet' && !quietToLoud; |
| 4945 | getMessage = cleanUpMessage(getMessage, isImpersonate, isContinue, displayIncomplete); | 4978 | getMessage = cleanUpMessage({ |
| 4979 | getMessage: getMessage, | ||
| 4980 | isImpersonate: isImpersonate, | ||
| 4981 | isContinue: isContinue, | ||
| 4982 | displayIncompleteSentences: displayIncomplete, | ||
| 4983 | }); | ||
| 4946 | 4984 | ||
| 4947 | if (isImpersonate) { | 4985 | if (isImpersonate) { |
| 4948 | $('#send_textarea').val(getMessage)[0].dispatchEvent(new Event('input', { bubbles: true })); | 4986 | $('#send_textarea').val(getMessage)[0].dispatchEvent(new Event('input', { bubbles: true })); |
| @@ -5908,7 +5946,13 @@ function extractMultiSwipes(data, type) { | |||
| 5908 | 5946 | ||
| 5909 | for (let i = 1; i < data.choices.length; i++) { | 5947 | for (let i = 1; i < data.choices.length; i++) { |
| 5910 | const text = data?.choices[i]?.message?.content ?? data?.choices[i]?.text ?? ''; | 5948 | const text = data?.choices[i]?.message?.content ?? data?.choices[i]?.text ?? ''; |
| 5911 | const cleanedText = cleanUpMessage(text, false, false, false); | 5949 | const cleanedText = cleanUpMessage({ |
| 5950 | getMessage: text, | ||
| 5951 | isImpersonate: false, | ||
| 5952 | isContinue: false, | ||
| 5953 | displayIncompleteSentences: false, | ||
| 5954 | }); | ||
| 5955 | |||
| 5912 | swipes.push(cleanedText); | 5956 | swipes.push(cleanedText); |
| 5913 | } | 5957 | } |
| 5914 | } | 5958 | } |
| @@ -5916,7 +5960,26 @@ function extractMultiSwipes(data, type) { | |||
| 5916 | return swipes; | 5960 | return swipes; |
| 5917 | } | 5961 | } |
| 5918 | 5962 | ||
| 5919 | export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayIncompleteSentences = false, stoppingStrings = null, includeUserPromptBias = true) { | 5963 | /** |
| 5964 | * Formats a message according to user settings | ||
| 5965 | * @param {object} [options] - Additional options. | ||
| 5966 | * @param {string} [options.getMessage] The message to clean up | ||
| 5967 | * @param {boolean} [options.isImpersonate] Whether this is an impersonated message | ||
| 5968 | * @param {boolean} [options.isContinue] Whether this is a continued message | ||
| 5969 | * @param {boolean} [options.displayIncompleteSentences] Whether to keep incomplete sentences at the end. | ||
| 5970 | * @param {array} [options.stoppingStrings] Array of stopping strings. | ||
| 5971 | * @param {boolean} [options.includeUserPromptBias] Whether to permit prepending the user prompt bias at the beginning. | ||
| 5972 | * @param {boolean} [options.trimNames] Whether to allow trimming "{{char}}:" or "{{user}}:" from the beginning. | ||
| 5973 | * @param {boolean} [options.trimWrongNames] Whether to allow deleting responses prefixed by the incorrect name, depending on isImpersonate | ||
| 5974 | * | ||
| 5975 | * @returns {string} The formatted message | ||
| 5976 | */ | ||
| 5977 | export function cleanUpMessage({ getMessage, isImpersonate, isContinue, displayIncompleteSentences = false, stoppingStrings = null, includeUserPromptBias = true, trimNames = true, trimWrongNames = true } = {}) { | ||
| 5978 | if (arguments.length > 0 && typeof arguments[0] !== 'object') { | ||
| 5979 | console.trace('cleanUpMessage called with positional arguments. Please use an object instead.'); | ||
| 5980 | [getMessage, isImpersonate, isContinue, displayIncompleteSentences, stoppingStrings, includeUserPromptBias, trimNames, trimWrongNames] = arguments; | ||
| 5981 | } | ||
| 5982 | |||
| 5920 | if (!getMessage) { | 5983 | if (!getMessage) { |
| 5921 | return ''; | 5984 | return ''; |
| 5922 | } | 5985 | } |
| @@ -5961,21 +6024,32 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc | |||
| 5961 | // "trailing whitespace on newlines\nevery line of the string\nsample text" | 6024 | // "trailing whitespace on newlines\nevery line of the string\nsample text" |
| 5962 | getMessage = getMessage.replace(/[^\S\r\n]+$/gm, ''); | 6025 | getMessage = getMessage.replace(/[^\S\r\n]+$/gm, ''); |
| 5963 | 6026 | ||
| 5964 | let nameToTrim = isImpersonate ? name2 : name1; | 6027 | if (trimWrongNames) { |
| 6028 | // If this is an impersonation, delete the entire response if it starts with "{{char}}:" | ||
| 6029 | // If this isn't an impersonation, delete the entire response if it starts with "{{user}}:" | ||
| 6030 | // Also delete any trailing text that starts with the wrong name. | ||
| 6031 | // This only occurs if the corresponding "power_user.allow_nameX_display" is false. | ||
| 5965 | 6032 | ||
| 5966 | if (isImpersonate) { | 6033 | let wrongName = isImpersonate |
| 5967 | nameToTrim = power_user.allow_name2_display ? '' : name2; | 6034 | ? (!power_user.allow_name2_display ? name2 : '') // char |
| 5968 | } | 6035 | : (!power_user.allow_name1_display ? name1 : ''); // user |
| 5969 | else { | 6036 | |
| 5970 | nameToTrim = power_user.allow_name1_display ? '' : name1; | 6037 | if (wrongName) { |
| 6038 | // If the message starts with the wrong name, delete the entire response | ||
| 6039 | let startIndex = getMessage.indexOf(`${wrongName}:`); | ||
| 6040 | if (startIndex === 0) { | ||
| 6041 | getMessage = ''; | ||
| 6042 | console.debug(`Message started with the wrong name: "${wrongName}" - response was deleted.`); | ||
| 5971 | } | 6043 | } |
| 5972 | 6044 | ||
| 5973 | if (nameToTrim && getMessage.indexOf(`${nameToTrim}:`) == 0) { | 6045 | // If there is trailing text starting with the wrong name, trim it off. |
| 5974 | getMessage = getMessage.substring(0, getMessage.indexOf(`${nameToTrim}:`)); | 6046 | startIndex = getMessage.indexOf(`\n${wrongName}:`); |
| 6047 | if (startIndex >= 0) { | ||
| 6048 | getMessage = getMessage.substring(0, startIndex); | ||
| 5975 | } | 6049 | } |
| 5976 | if (nameToTrim && getMessage.indexOf(`\n${nameToTrim}:`) >= 0) { | ||
| 5977 | getMessage = getMessage.substring(0, getMessage.indexOf(`\n${nameToTrim}:`)); | ||
| 5978 | } | 6050 | } |
| 6051 | } | ||
| 6052 | |||
| 5979 | if (getMessage.indexOf('<|endoftext|>') != -1) { | 6053 | if (getMessage.indexOf('<|endoftext|>') != -1) { |
| 5980 | getMessage = getMessage.substring(0, getMessage.indexOf('<|endoftext|>')); | 6054 | getMessage = getMessage.substring(0, getMessage.indexOf('<|endoftext|>')); |
| 5981 | } | 6055 | } |
| @@ -6035,14 +6109,19 @@ export function cleanUpMessage(getMessage, isImpersonate, isContinue, displayInc | |||
| 6035 | getMessage = fixMarkdown(getMessage, false); | 6109 | getMessage = fixMarkdown(getMessage, false); |
| 6036 | } | 6110 | } |
| 6037 | 6111 | ||
| 6112 | if (trimNames) { | ||
| 6113 | // If this is an impersonation, trim "{{user}}:" from the beginning | ||
| 6114 | // If this isn't an impersonation, trim "{{char}}:" from the beginning. | ||
| 6115 | // Only applied when the corresponding "power_user.allow_nameX_display" is false. | ||
| 6038 | const nameToTrim2 = isImpersonate | 6116 | const nameToTrim2 = isImpersonate |
| 6039 | ? (!power_user.allow_name1_display ? name1 : '') | 6117 | ? (!power_user.allow_name1_display ? name1 : '') // user |
| 6040 | : (!power_user.allow_name2_display ? name2 : ''); | 6118 | : (!power_user.allow_name2_display ? name2 : ''); // char |
| 6041 | 6119 | ||
| 6042 | if (nameToTrim2 && getMessage.startsWith(nameToTrim2 + ':')) { | 6120 | if (nameToTrim2 && getMessage.startsWith(nameToTrim2 + ':')) { |
| 6043 | getMessage = getMessage.replace(nameToTrim2 + ':', ''); | 6121 | getMessage = getMessage.replace(nameToTrim2 + ':', ''); |
| 6044 | getMessage = getMessage.trimStart(); | 6122 | getMessage = getMessage.trimStart(); |
| 6045 | } | 6123 | } |
| 6124 | } | ||
| 6046 | 6125 | ||
| 6047 | if (isImpersonate) { | 6126 | if (isImpersonate) { |
| 6048 | getMessage = getMessage.trim(); | 6127 | getMessage = getMessage.trim(); |
| @@ -368,7 +368,12 @@ function onToggleLogprobsPanel() { | |||
| 368 | function createSwipe(messageId, prompt) { | 368 | function createSwipe(messageId, prompt) { |
| 369 | // need to call `cleanUpMessage` on our new prompt, because we were working | 369 | // need to call `cleanUpMessage` on our new prompt, because we were working |
| 370 | // with raw model output and our new prompt is missing trimming/macro replacements | 370 | // with raw model output and our new prompt is missing trimming/macro replacements |
| 371 | const cleanedPrompt = cleanUpMessage(prompt, false, false, true); | 371 | const cleanedPrompt = cleanUpMessage({ |
| 372 | getMessage: prompt, | ||
| 373 | isImpersonate: false, | ||
| 374 | isContinue: false, | ||
| 375 | displayIncompleteSentences: true, | ||
| 376 | }); | ||
| 372 | 377 | ||
| 373 | const msg = chat[messageId]; | 378 | const msg = chat[messageId]; |
| 374 | const newSwipeInfo = { | 379 | const newSwipeInfo = { |