diff --git a/public/index.html b/public/index.html index 895ba3c8a..dfbdcf032 100644 --- a/public/index.html +++ b/public/index.html @@ -1551,13 +1551,23 @@
+ +
+ + Exclude Human/Assistant prefixes from being added to the prompt, except very first/last message, system prompt Human message and Assistant suffix. + Requires 'Add character names' checked. + +
-
+
- Exclude the assistant suffix from being added to the end of prompt (Requires jailbreak with 'Assistant:' in it). + Exclude the assistant suffix from being added to the end of prompt. Requires jailbreak with 'Assistant:' in it.
@@ -1570,7 +1580,7 @@ Use system prompt (Claude 2.1+ only) -
+
Exclude the 'Human: ' prefix from being added to the beginning of the prompt. Instead, place it between the system prompt and the first message with the role 'assistant' (right before 'Chat History' by default). diff --git a/public/script.js b/public/script.js index d80bb98d8..a437e6423 100644 --- a/public/script.js +++ b/public/script.js @@ -2891,7 +2891,7 @@ export async function generateRaw(prompt, api, instructOverride) { case 'kobold': case 'koboldhorde': if (preset_settings === 'gui') { - generateData = { prompt: prompt, gui_settings: true, max_length: amount_gen, max_context_length: max_context }; + generateData = { prompt: prompt, gui_settings: true, max_length: amount_gen, max_context_length: max_context, api_server }; } else { const isHorde = api === 'koboldhorde'; const koboldSettings = koboldai_settings[koboldai_setting_names[preset_settings]]; @@ -3724,6 +3724,7 @@ async function Generate(type, { automatic_trigger, force_name2, quiet_prompt, qu gui_settings: true, max_length: maxLength, max_context_length: max_context, + api_server, }; if (preset_settings != 'gui') { diff --git a/public/scripts/extensions/regex/editor.html b/public/scripts/extensions/regex/editor.html index 72c95d3d9..1789dbe98 100644 --- a/public/scripts/extensions/regex/editor.html +++ b/public/scripts/extensions/regex/editor.html @@ -1,9 +1,14 @@
-

Regex Editor +

+ Regex Editor ? +

@@ -11,6 +16,22 @@
+
+
+ + +
+
+ + +
+
+
+

- - `; - - html += ` - - Use XTTSv2 TTS Server. + + + + + + + + + + + + + + + + + + + + + + + `; return html; } + onSettingsChange() { // Used when provider settings are updated from UI this.settings.provider_endpoint = $('#xtts_tts_endpoint').val(); this.settings.language = $('#xtts_api_language').val(); + + // Update the default TTS settings based on input fields + this.settings.speed = $('#xtts_speed').val(); + this.settings.temperature = $('#xtts_temperature').val(); + this.settings.length_penalty = $('#xtts_length_penalty').val(); + this.settings.repetition_penalty = $('#xtts_repetition_penalty').val(); + this.settings.top_k = $('#xtts_top_k').val(); + this.settings.top_p = $('#xtts_top_p').val(); + this.settings.stream_chunk_size = $('#xtts_stream_chunk_size').val(); + this.settings.enable_text_splitting = $('#xtts_enable_text_splitting').is(':checked'); + this.settings.streaming = $('#xtts_tts_streaming').is(':checked'); + + // Update the UI to reflect changes + $('#xtts_tts_speed_output').text(this.settings.speed); + $('#xtts_tts_temperature_output').text(this.settings.temperature); + $('#xtts_length_penalty_output').text(this.settings.length_penalty); + $('#xtts_repetition_penalty_output').text(this.settings.repetition_penalty); + $('#xtts_top_k_output').text(this.settings.top_k); + $('#xtts_top_p_output').text(this.settings.top_p); + $('#xtts_stream_chunk_size_output').text(this.settings.stream_chunk_size); + saveTtsProviderSettings(); + this.changeTTSSettings(); } async loadSettings(settings) { @@ -121,10 +174,40 @@ class XTTSTtsProvider { } }, 2000); + // Set initial values from the settings $('#xtts_tts_endpoint').val(this.settings.provider_endpoint); - $('#xtts_tts_endpoint').on('input', () => { this.onSettingsChange(); }); $('#xtts_api_language').val(this.settings.language); + $('#xtts_speed').val(this.settings.speed); + $('#xtts_temperature').val(this.settings.temperature); + $('#xtts_length_penalty').val(this.settings.length_penalty); + $('#xtts_repetition_penalty').val(this.settings.repetition_penalty); + $('#xtts_top_k').val(this.settings.top_k); + $('#xtts_top_p').val(this.settings.top_p); + $('#xtts_enable_text_splitting').prop('checked', this.settings.enable_text_splitting); + $('#xtts_stream_chunk_size').val(this.settings.stream_chunk_size); + $('#xtts_tts_streaming').prop('checked', this.settings.streaming); + + // Update the UI to reflect changes + $('#xtts_tts_speed_output').text(this.settings.speed); + $('#xtts_tts_temperature_output').text(this.settings.temperature); + $('#xtts_length_penalty_output').text(this.settings.length_penalty); + $('#xtts_repetition_penalty_output').text(this.settings.repetition_penalty); + $('#xtts_top_k_output').text(this.settings.top_k); + $('#xtts_top_p_output').text(this.settings.top_p); + $('#xtts_stream_chunk_size_output').text(this.settings.stream_chunk_size); + + // Register input/change event listeners to update settings on user interaction + $('#xtts_tts_endpoint').on('input', () => { this.onSettingsChange(); }); $('#xtts_api_language').on('change', () => { this.onSettingsChange(); }); + $('#xtts_speed').on('input', () => { this.onSettingsChange(); }); + $('#xtts_temperature').on('input', () => { this.onSettingsChange(); }); + $('#xtts_length_penalty').on('input', () => { this.onSettingsChange(); }); + $('#xtts_repetition_penalty').on('input', () => { this.onSettingsChange(); }); + $('#xtts_top_k').on('input', () => { this.onSettingsChange(); }); + $('#xtts_top_p').on('input', () => { this.onSettingsChange(); }); + $('#xtts_enable_text_splitting').on('change', () => { this.onSettingsChange(); }); + $('#xtts_stream_chunk_size').on('input', () => { this.onSettingsChange(); }); + $('#xtts_tts_streaming').on('change', () => { this.onSettingsChange(); }); await this.checkReady(); @@ -133,7 +216,7 @@ class XTTSTtsProvider { // Perform a simple readiness check by trying to fetch voiceIds async checkReady() { - await this.fetchTtsVoiceObjects(); + await Promise.allSettled([this.fetchTtsVoiceObjects(), this.changeTTSSettings()]); } async onRefreshClick() { @@ -174,8 +257,46 @@ class XTTSTtsProvider { return responseJson; } + // Each time a parameter is changed, we change the configuration + async changeTTSSettings() { + if (!this.settings.provider_endpoint) { + return; + } + + const response = await doExtrasFetch( + `${this.settings.provider_endpoint}/set_tts_settings`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-cache', + }, + body: JSON.stringify({ + 'temperature': this.settings.temperature, + 'speed': this.settings.speed, + 'length_penalty': this.settings.length_penalty, + 'repetition_penalty': this.settings.repetition_penalty, + 'top_p': this.settings.top_p, + 'top_k': this.settings.top_k, + 'enable_text_splitting': this.settings.enable_text_splitting, + 'stream_chunk_size': this.settings.stream_chunk_size, + }), + }, + ); + return response; + } + async fetchTtsGeneration(inputText, voiceId) { console.info(`Generating new TTS for voice_id ${voiceId}`); + + if (this.settings.streaming) { + const params = new URLSearchParams(); + params.append('text', inputText); + params.append('speaker_wav', voiceId); + params.append('language', this.settings.language); + return `${this.settings.provider_endpoint}/tts_stream/?${params.toString()}`; + } + const response = await doExtrasFetch( `${this.settings.provider_endpoint}/tts_to_audio/`, { diff --git a/public/scripts/kai-settings.js b/public/scripts/kai-settings.js index d88a6ee87..f2f295dc3 100644 --- a/public/scripts/kai-settings.js +++ b/public/scripts/kai-settings.js @@ -4,7 +4,6 @@ import { getStoppingStrings, substituteParams, api_server, - main_api, } from '../script.js'; import { @@ -142,7 +141,6 @@ export function getKoboldGenerationData(finalPrompt, settings, maxLength, maxCon sampler_seed: kai_settings.seed >= 0 ? kai_settings.seed : undefined, api_server, - main_api, }; return generate_data; } diff --git a/public/scripts/openai.js b/public/scripts/openai.js index 750c040a8..6d354ef17 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -235,6 +235,7 @@ const default_settings = { use_google_tokenizer: false, exclude_assistant: false, claude_use_sysprompt: false, + claude_exclude_prefixes: false, use_alt_scale: false, squash_system_messages: false, image_inlining: false, @@ -299,6 +300,7 @@ const oai_settings = { use_google_tokenizer: false, exclude_assistant: false, claude_use_sysprompt: false, + claude_exclude_prefixes: false, use_alt_scale: false, squash_system_messages: false, image_inlining: false, @@ -1573,6 +1575,7 @@ async function sendOpenAIRequest(type, messages, signal) { generate_data['top_k'] = Number(oai_settings.top_k_openai); generate_data['exclude_assistant'] = oai_settings.exclude_assistant; generate_data['claude_use_sysprompt'] = oai_settings.claude_use_sysprompt; + generate_data['claude_exclude_prefixes'] = oai_settings.claude_exclude_prefixes; generate_data['stop'] = getCustomStoppingStrings(); // Claude shouldn't have limits on stop strings. generate_data['human_sysprompt_message'] = substituteParams(oai_settings.human_sysprompt_message); // Don't add a prefill on quiet gens (summarization) @@ -2396,6 +2399,7 @@ function loadOpenAISettings(data, settings) { if (settings.use_google_tokenizer !== undefined) oai_settings.use_google_tokenizer = !!settings.use_google_tokenizer; if (settings.exclude_assistant !== undefined) oai_settings.exclude_assistant = !!settings.exclude_assistant; if (settings.claude_use_sysprompt !== undefined) oai_settings.claude_use_sysprompt = !!settings.claude_use_sysprompt; + if (settings.claude_exclude_prefixes !== undefined) oai_settings.claude_exclude_prefixes = !!settings.claude_exclude_prefixes; if (settings.use_alt_scale !== undefined) { oai_settings.use_alt_scale = !!settings.use_alt_scale; updateScaleForm(); } $('#stream_toggle').prop('checked', oai_settings.stream_openai); $('#api_url_scale').val(oai_settings.api_url_scale); @@ -2435,6 +2439,7 @@ function loadOpenAISettings(data, settings) { $('#use_google_tokenizer').prop('checked', oai_settings.use_google_tokenizer); $('#exclude_assistant').prop('checked', oai_settings.exclude_assistant); $('#claude_use_sysprompt').prop('checked', oai_settings.claude_use_sysprompt); + $('#claude_exclude_prefixes').prop('checked', oai_settings.claude_exclude_prefixes); $('#scale-alt').prop('checked', oai_settings.use_alt_scale); $('#openrouter_use_fallback').prop('checked', oai_settings.openrouter_use_fallback); $('#openrouter_force_instruct').prop('checked', oai_settings.openrouter_force_instruct); @@ -2648,6 +2653,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { use_google_tokenizer: settings.use_google_tokenizer, exclude_assistant: settings.exclude_assistant, claude_use_sysprompt: settings.claude_use_sysprompt, + claude_exclude_prefixes: settings.claude_exclude_prefixes, use_alt_scale: settings.use_alt_scale, squash_system_messages: settings.squash_system_messages, image_inlining: settings.image_inlining, @@ -3020,6 +3026,7 @@ function onSettingsPresetChange() { use_google_tokenizer: ['#use_google_tokenizer', 'use_google_tokenizer', true], exclude_assistant: ['#exclude_assistant', 'exclude_assistant', true], claude_use_sysprompt: ['#claude_use_sysprompt', 'claude_use_sysprompt', true], + claude_exclude_prefixes: ['#claude_exclude_prefixes', 'claude_exclude_prefixes', true], use_alt_scale: ['#use_alt_scale', 'use_alt_scale', true], squash_system_messages: ['#squash_system_messages', 'squash_system_messages', true], image_inlining: ['#openai_image_inlining', 'image_inlining', true], @@ -3747,6 +3754,11 @@ $(document).ready(async function () { saveSettingsDebounced(); }); + $('#claude_exclude_prefixes').on('change', function () { + oai_settings.claude_exclude_prefixes = !!$('#claude_exclude_prefixes').prop('checked'); + saveSettingsDebounced(); + }); + $('#names_in_completion').on('change', function () { oai_settings.names_in_completion = !!$('#names_in_completion').prop('checked'); saveSettingsDebounced(); diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index d4378a71a..84fad8c65 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -520,7 +520,7 @@ async function switchZenSliders() { $('#clickSlidersTips').hide(); $('#pro-settings-block input[type=\'number\']').hide(); //hide number inputs that are not 'seed' inputs - $(`#textgenerationwebui_api-settings :input[type='number']:not([id^='seed']), + $(`#textgenerationwebui_api-settings :input[type='number']:not([id^='seed']):not([id^='n_']), #kobold_api-settings :input[type='number']:not([id^='seed'])`).hide(); //hide original sliders $(`#textgenerationwebui_api-settings input[type='range'], @@ -1848,8 +1848,8 @@ export function renderStoryString(params) { // substitute {{macro}} params that are not defined in the story string output = substituteParams(output, params.user, params.char); - // remove leading whitespace - output = output.trimStart(); + // remove leading newlines + output = output.replace(/^\n+/, ''); // add a newline to the end of the story string if it doesn't have one if (output.length > 0 && !output.endsWith('\n')) { diff --git a/src/endpoints/backends/chat-completions.js b/src/endpoints/backends/chat-completions.js index 6996f5698..b1bde2149 100644 --- a/src/endpoints/backends/chat-completions.js +++ b/src/endpoints/backends/chat-completions.js @@ -36,9 +36,10 @@ async function sendClaudeRequest(request, response) { }); const isSysPromptSupported = request.body.model === 'claude-2' || request.body.model === 'claude-2.1'; - const requestPrompt = convertClaudePrompt(request.body.messages, !request.body.exclude_assistant, request.body.assistant_prefill, isSysPromptSupported, request.body.claude_use_sysprompt, request.body.human_sysprompt_message); + const requestPrompt = convertClaudePrompt(request.body.messages, !request.body.exclude_assistant, request.body.assistant_prefill, isSysPromptSupported, request.body.claude_use_sysprompt, request.body.human_sysprompt_message, request.body.claude_exclude_prefixes); // Check Claude messages sequence and prefixes presence. + let sequenceError = []; const sequence = requestPrompt.split('\n').filter(x => x.startsWith('Human:') || x.startsWith('Assistant:')); const humanFound = sequence.some(line => line.startsWith('Human:')); const assistantFound = sequence.some(line => line.startsWith('Assistant:')); @@ -56,20 +57,20 @@ async function sendClaudeRequest(request, response) { } if (!humanFound) { - console.log(color.red(`${divider}\nWarning: No 'Human:' prefix found in the prompt.\n${divider}`)); + sequenceError.push(`${divider}\nWarning: No 'Human:' prefix found in the prompt.\n${divider}`); } if (!assistantFound) { - console.log(color.red(`${divider}\nWarning: No 'Assistant: ' prefix found in the prompt.\n${divider}`)); + sequenceError.push(`${divider}\nWarning: No 'Assistant: ' prefix found in the prompt.\n${divider}`); } - if (!sequence[0].startsWith('Human:')) { - console.log(color.red(`${divider}\nWarning: The messages sequence should start with 'Human:' prefix.\nMake sure you have 'Human:' prefix at the very beggining of the prompt, or after the system prompt.\n${divider}`)); + if (sequence[0] && !sequence[0].startsWith('Human:')) { + sequenceError.push(`${divider}\nWarning: The messages sequence should start with 'Human:' prefix.\nMake sure you have '\\n\\nHuman:' prefix at the very beggining of the prompt, or after the system prompt.\n${divider}`); } if (humanErrorCount > 0 || assistantErrorCount > 0) { - console.log(color.red(`${divider}\nWarning: Detected incorrect Prefix sequence(s).`)); - console.log(color.red(`Incorrect "Human:" prefix(es): ${humanErrorCount}.\nIncorrect "Assistant: " prefix(es): ${assistantErrorCount}.`)); - console.log(color.red('Check the prompt above and fix it in the SillyTavern.')); - console.log(color.red('\nThe correct sequence should look like this:\nSystem prompt <-(for the sysprompt format only, else have 2 empty lines above the first human\'s message.)')); - console.log(color.red(` <-----(Each message beginning with the "Assistant:/Human:" prefix must have one empty line above.)\nHuman:\n\nAssistant:\n...\n\nHuman:\n\nAssistant:\n${divider}`)); + sequenceError.push(`${divider}\nWarning: Detected incorrect Prefix sequence(s).`); + sequenceError.push(`Incorrect "Human:" prefix(es): ${humanErrorCount}.\nIncorrect "Assistant: " prefix(es): ${assistantErrorCount}.`); + sequenceError.push('Check the prompt above and fix it in the SillyTavern.'); + sequenceError.push('\nThe correct sequence in the console should look like this:\n(System prompt msg) <-(for the sysprompt format only, else have \\n\\n above the first human\'s message.)'); + sequenceError.push(`\\n + <-----(Each message beginning with the "Assistant:/Human:" prefix must have \\n\\n before it.)\n\\n +\nHuman: \\n +\n\\n +\nAssistant: \\n +\n...\n\\n +\nHuman: \\n +\n\\n +\nAssistant: \n${divider}`); } // Add custom stop sequences @@ -91,6 +92,10 @@ async function sendClaudeRequest(request, response) { console.log('Claude request:', requestBody); + sequenceError.forEach(sequenceError => { + console.log(color.red(sequenceError)); + }); + const generateResponse = await fetch(apiUrl + '/complete', { method: 'POST', signal: controller.signal, diff --git a/src/endpoints/prompt-converters.js b/src/endpoints/prompt-converters.js index 12efd1cdc..33ccb9578 100644 --- a/src/endpoints/prompt-converters.js +++ b/src/endpoints/prompt-converters.js @@ -5,15 +5,21 @@ * @param {string} addAssistantPrefill Add Assistant prefill after the assistant postfix. * @param {boolean} withSysPromptSupport Indicates if the Claude model supports the system prompt format. * @param {boolean} useSystemPrompt Indicates if the system prompt format should be used. + * @param {boolean} excludePrefixes Exlude Human/Assistant prefixes. * @param {string} addSysHumanMsg Add Human message between system prompt and assistant. * @returns {string} Prompt for Claude * @copyright Prompt Conversion script taken from RisuAI by kwaroran (GPLv3). */ -function convertClaudePrompt(messages, addAssistantPostfix, addAssistantPrefill, withSysPromptSupport, useSystemPrompt, addSysHumanMsg) { +function convertClaudePrompt(messages, addAssistantPostfix, addAssistantPrefill, withSysPromptSupport, useSystemPrompt, addSysHumanMsg, excludePrefixes) { //Prepare messages for claude. + //When 'Exclude Human/Assistant prefixes' checked, setting messages role to the 'system'(last message is exception). if (messages.length > 0) { - messages[0].role = 'system'; + if (excludePrefixes) { + messages.slice(0, -1).forEach(message => message.role = 'system'); + } else { + messages[0].role = 'system'; + } //Add the assistant's message to the end of messages. if (addAssistantPostfix) { messages.push({ @@ -29,7 +35,7 @@ function convertClaudePrompt(messages, addAssistantPostfix, addAssistantPrefill, } return message.role === 'assistant' && i > 0; }); - // When 2.1+ and 'Use system prompt" checked, switches to the system prompt format by setting the first message's role to the 'system'. + // When 2.1+ and 'Use system prompt' checked, switches to the system prompt format by setting the first message's role to the 'system'. // Inserts the human's message before the first the assistant one, if there are no such message or prefix found. if (withSysPromptSupport && useSystemPrompt) { messages[0].role = 'system'; @@ -43,7 +49,7 @@ function convertClaudePrompt(messages, addAssistantPostfix, addAssistantPrefill, // Otherwise, use the default message format by setting the first message's role to 'user'(compatible with all claude models including 2.1.) messages[0].role = 'user'; // Fix messages order for default message format when(messages > Context Size) by merging two messages with "\n\nHuman: " prefixes into one, before the first Assistant's message. - if (firstAssistantIndex > 0) { + if (firstAssistantIndex > 0 && !excludePrefixes) { messages[firstAssistantIndex - 1].role = firstAssistantIndex - 1 !== 0 && messages[firstAssistantIndex - 1].role === 'user' ? 'FixHumMsg' : messages[firstAssistantIndex - 1].role; } } @@ -51,11 +57,11 @@ function convertClaudePrompt(messages, addAssistantPostfix, addAssistantPrefill, // Convert messages to the prompt. let requestPrompt = messages.map((v, i) => { - // Set prefix according to the role. + // Set prefix according to the role. Also, when "Exclude Human/Assistant prefixes" is checked, names are added via the system prefix. let prefix = { 'assistant': '\n\nAssistant: ', 'user': '\n\nHuman: ', - 'system': i === 0 ? '' : v.name === 'example_assistant' ? '\n\nA: ' : v.name === 'example_user' ? '\n\nH: ' : '\n\n', + 'system': i === 0 ? '' : v.name === 'example_assistant' ? '\n\nA: ' : v.name === 'example_user' ? '\n\nH: ' : excludePrefixes && v.name ? `\n\n${v.name}: ` : '\n\n', 'FixHumMsg': '\n\nFirst message: ', }[v.role] ?? ''; // Claude doesn't support message names, so we'll just add them to the message content.