diff --git a/public/index.html b/public/index.html index cb857346a..ca09563f0 100644 --- a/public/index.html +++ b/public/index.html @@ -1733,20 +1733,46 @@ ? -
-

- Send on Enter -

- -
+ + +
+ +
+

+ Send on Enter +

+ +
+ +
+ Auto-swipe +
+
+
+ + +
Minimum generated message length
+ +
Blacklisted words
+
+ +
Blacklisted word count to swipe
+ +
+
+
+

Name

diff --git a/public/script.js b/public/script.js index 4f7044208..b703f279c 100644 --- a/public/script.js +++ b/public/script.js @@ -1231,7 +1231,6 @@ function substituteParams(content, _name1, _name2) { _name1 = _name1 ?? name1; _name2 = _name2 ?? name2; if (!content) { - console.warn("No content on substituteParams") return '' } @@ -1522,13 +1521,46 @@ class StreamingProcessor { this.hideStopButton(this.messageId); this.onProgressStreaming(messageId, text, true); addCopyToCodeBlocks($(`#chat .mes[mesid="${messageId}"]`)); - playMessageSound(); saveChatConditional(); activateSendButtons(); showSwipeButtons(); setGenerationProgress(0); $('.mes_buttons:last').show(); generatedPromtCache = ''; + + console.log("Generated text size:", text.length, text) + + if (power_user.auto_swipe) { + function containsBlacklistedWords(str, blacklist, threshold) { + const regex = new RegExp(`\\b(${blacklist.join('|')})\\b`, 'gi'); + const matches = str.match(regex) || []; + return matches.length >= threshold; + } + + const generatedTextFiltered = (text) => { + if (text) { + if (power_user.auto_swipe_minimum_length) { + if (text.length < power_user.auto_swipe_minimum_length && text.length !== 0) { + console.log("Generated text size too small") + return true + } + } + if (power_user.auto_swipe_blacklist_threshold) { + if (containsBlacklistedWords(text, power_user.auto_swipe_blacklist, power_user.auto_swipe_blacklist_threshold)) { + console.log("Generated text has blacklisted words") + return true + } + } + } + return false + } + + if (generatedTextFiltered(text)) { + swipe_right() + return + } + } + playMessageSound(); } onErrorStreaming() { @@ -4473,7 +4505,162 @@ window["SillyTavern"].getContext = function () { }; }; +// when we click swipe right button +const swipe_right = () => { + if (chat.length - 1 === Number(this_edit_mes_id)) { + closeMessageEditor(); + } + if (isHordeGenerationNotAllowed()) { + return; + } + + const swipe_duration = 200; + const swipe_range = 700; + //console.log(swipe_range); + let run_generate = false; + let run_swipe_right = false; + if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array + chat[chat.length - 1]['swipe_id'] = 0; // set it to id 0 + chat[chat.length - 1]['swipes'] = []; // empty the array + chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat + } + chat[chat.length - 1]['swipe_id']++; //make new slot in array + // if message has memory attached - remove it to allow regen + if (chat[chat.length - 1].extra && chat[chat.length - 1].extra.memory) { + delete chat[chat.length - 1].extra.memory; + } + //console.log(chat[chat.length-1]['swipes']); + if (parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { //if swipe id of last message is the same as the length of the 'swipes' array + delete chat[chat.length - 1].gen_started; + delete chat[chat.length - 1].gen_finished; + run_generate = true; + } else if (parseInt(chat[chat.length - 1]['swipe_id']) < chat[chat.length - 1]['swipes'].length) { //otherwise, if the id is less than the number of swipes + chat[chat.length - 1]['mes'] = chat[chat.length - 1]['swipes'][chat[chat.length - 1]['swipe_id']]; //load the last mes box with the latest generation + run_swipe_right = true; //then prepare to do normal right swipe to show next message + } + + const currentMessage = $("#chat").children().filter(`[mesid="${count_view_mes - 1}"]`); + let this_div = currentMessage.children('.swipe_right'); + let this_mes_div = this_div.parent(); + + if (chat[chat.length - 1]['swipe_id'] > chat[chat.length - 1]['swipes'].length) { //if we swipe right while generating (the swipe ID is greater than what we are viewing now) + chat[chat.length - 1]['swipe_id'] = chat[chat.length - 1]['swipes'].length; //show that message slot (will be '...' while generating) + } + if (run_generate) { //hide swipe arrows while generating + this_div.css('display', 'none'); + } + // handles animated transitions when swipe right, specifically height transitions between messages + if (run_generate || run_swipe_right) { + let this_mes_block = this_mes_div.children('.mes_block').children('.mes_text'); + const this_mes_div_height = this_mes_div[0].scrollHeight; + const this_mes_block_height = this_mes_block[0].scrollHeight; + + this_mes_div.children('.swipe_left').css('display', 'flex'); + this_mes_div.children('.mes_block').transition({ // this moves the div back and forth + x: '-' + swipe_range, + duration: swipe_duration, + easing: animation_easing, + queue: false, + complete: function () { + /*if (!selected_group) { + var typingIndicator = $("#typing_indicator_template .typing_indicator").clone(); + typingIndicator.find(".typing_indicator_name").text(characters[this_chid].name); + } */ + /* $("#chat").append(typingIndicator); */ + const is_animation_scroll = ($('#chat').scrollTop() >= ($('#chat').prop("scrollHeight") - $('#chat').outerHeight()) - 10); + //console.log(parseInt(chat[chat.length-1]['swipe_id'])); + //console.log(chat[chat.length-1]['swipes'].length); + if (run_generate && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { + //console.log('showing ""..."'); + /* if (!selected_group) { + } else { */ + $("#chat") + .find('[mesid="' + (count_view_mes - 1) + '"]') + .find('.mes_text') + .html('...'); //shows "..." while generating + $("#chat") + .find('[mesid="' + (count_view_mes - 1) + '"]') + .find('.mes_timer') + .html(''); // resets the timer + /* } */ + } else { + //console.log('showing previously generated swipe candidate, or "..."'); + //console.log('onclick right swipe calling addOneMessage'); + addOneMessage(chat[chat.length - 1], { type: 'swipe' }); + } + let new_height = this_mes_div_height - (this_mes_block_height - this_mes_block[0].scrollHeight); + if (new_height < 103) new_height = 103; + + + this_mes_div.animate({ height: new_height + 'px' }, { + duration: 0, //used to be 100 + queue: false, + progress: function () { + // Scroll the chat down as the message expands + if (is_animation_scroll) $("#chat").scrollTop($("#chat")[0].scrollHeight); + }, + complete: function () { + this_mes_div.css('height', 'auto'); + // Scroll the chat down to the bottom once the animation is complete + if (is_animation_scroll) $("#chat").scrollTop($("#chat")[0].scrollHeight); + } + }); + this_mes_div.children('.mes_block').transition({ + x: swipe_range, + duration: 0, + easing: animation_easing, + queue: false, + complete: function () { + this_mes_div.children('.mes_block').transition({ + x: '0px', + duration: swipe_duration, + easing: animation_easing, + queue: false, + complete: function () { + if (run_generate && !is_send_press && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { + console.log('caught here 2'); + is_send_press = true; + $('.mes_buttons:last').hide(); + Generate('swipe'); + } else { + if (parseInt(chat[chat.length - 1]['swipe_id']) !== chat[chat.length - 1]['swipes'].length) { + saveChatConditional(); + } + } + } + }); + } + }); + } + }); + this_mes_div.children('.avatar').transition({ // moves avatar along with swipe + x: '-' + swipe_range, + duration: swipe_duration, + easing: animation_easing, + queue: false, + complete: function () { + this_mes_div.children('.avatar').transition({ + x: swipe_range, + duration: 0, + easing: animation_easing, + queue: false, + complete: function () { + this_mes_div.children('.avatar').transition({ + x: '0px', + duration: swipe_duration, + easing: animation_easing, + queue: false, + complete: function () { + + } + }); + } + }); + } + }); + } +} $(document).ready(function () { @@ -4520,160 +4707,7 @@ $(document).ready(function () { ///// SWIPE BUTTON CLICKS /////// - $(document).on('click', '.swipe_right', function () { //when we click swipe right button - if (chat.length - 1 === Number(this_edit_mes_id)) { - closeMessageEditor(); - } - - if (isHordeGenerationNotAllowed()) { - return; - } - - const swipe_duration = 200; - const swipe_range = 700; - //console.log(swipe_range); - let run_generate = false; - let run_swipe_right = false; - if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array - chat[chat.length - 1]['swipe_id'] = 0; // set it to id 0 - chat[chat.length - 1]['swipes'] = []; // empty the array - chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat - } - chat[chat.length - 1]['swipe_id']++; //make new slot in array - // if message has memory attached - remove it to allow regen - if (chat[chat.length - 1].extra && chat[chat.length - 1].extra.memory) { - delete chat[chat.length - 1].extra.memory; - } - //console.log(chat[chat.length-1]['swipes']); - if (parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { //if swipe id of last message is the same as the length of the 'swipes' array - delete chat[chat.length - 1].gen_started; - delete chat[chat.length - 1].gen_finished; - run_generate = true; - } else if (parseInt(chat[chat.length - 1]['swipe_id']) < chat[chat.length - 1]['swipes'].length) { //otherwise, if the id is less than the number of swipes - chat[chat.length - 1]['mes'] = chat[chat.length - 1]['swipes'][chat[chat.length - 1]['swipe_id']]; //load the last mes box with the latest generation - run_swipe_right = true; //then prepare to do normal right swipe to show next message - } - - if (chat[chat.length - 1]['swipe_id'] > chat[chat.length - 1]['swipes'].length) { //if we swipe right while generating (the swipe ID is greater than what we are viewing now) - chat[chat.length - 1]['swipe_id'] = chat[chat.length - 1]['swipes'].length; //show that message slot (will be '...' while generating) - } - if (run_generate) { //hide swipe arrows while generating - $(this).css('display', 'none'); - } - if (run_generate || run_swipe_right) { // handles animated transitions when swipe right, specifically height transitions between messages - - let this_mes_div = $(this).parent(); - let this_mes_block = $(this).parent().children('.mes_block').children('.mes_text'); - const this_mes_div_height = this_mes_div[0].scrollHeight; - const this_mes_block_height = this_mes_block[0].scrollHeight; - - this_mes_div.children('.swipe_left').css('display', 'flex'); - this_mes_div.children('.mes_block').transition({ // this moves the div back and forth - x: '-' + swipe_range, - duration: swipe_duration, - easing: animation_easing, - queue: false, - complete: function () { - /*if (!selected_group) { - var typingIndicator = $("#typing_indicator_template .typing_indicator").clone(); - typingIndicator.find(".typing_indicator_name").text(characters[this_chid].name); - } */ - /* $("#chat").append(typingIndicator); */ - const is_animation_scroll = ($('#chat').scrollTop() >= ($('#chat').prop("scrollHeight") - $('#chat').outerHeight()) - 10); - //console.log(parseInt(chat[chat.length-1]['swipe_id'])); - //console.log(chat[chat.length-1]['swipes'].length); - if (run_generate && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { - //console.log('showing ""..."'); - /* if (!selected_group) { - } else { */ - $("#chat") - .find('[mesid="' + (count_view_mes - 1) + '"]') - .find('.mes_text') - .html('...'); //shows "..." while generating - $("#chat") - .find('[mesid="' + (count_view_mes - 1) + '"]') - .find('.mes_timer') - .html(''); // resets the timer - /* } */ - } else { - //console.log('showing previously generated swipe candidate, or "..."'); - //console.log('onclick right swipe calling addOneMessage'); - addOneMessage(chat[chat.length - 1], { type: 'swipe' }); - } - let new_height = this_mes_div_height - (this_mes_block_height - this_mes_block[0].scrollHeight); - if (new_height < 103) new_height = 103; - - - this_mes_div.animate({ height: new_height + 'px' }, { - duration: 0, //used to be 100 - queue: false, - progress: function () { - // Scroll the chat down as the message expands - if (is_animation_scroll) $("#chat").scrollTop($("#chat")[0].scrollHeight); - }, - complete: function () { - this_mes_div.css('height', 'auto'); - // Scroll the chat down to the bottom once the animation is complete - if (is_animation_scroll) $("#chat").scrollTop($("#chat")[0].scrollHeight); - } - }); - this_mes_div.children('.mes_block').transition({ - x: swipe_range, - duration: 0, - easing: animation_easing, - queue: false, - complete: function () { - this_mes_div.children('.mes_block').transition({ - x: '0px', - duration: swipe_duration, - easing: animation_easing, - queue: false, - complete: function () { - if (run_generate && !is_send_press && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { - console.log('caught here 2'); - is_send_press = true; - $('.mes_buttons:last').hide(); - Generate('swipe'); - } else { - if (parseInt(chat[chat.length - 1]['swipe_id']) !== chat[chat.length - 1]['swipes'].length) { - saveChatConditional(); - } - } - } - }); - } - }); - } - }); - - $(this).parent().children('.avatar').transition({ // moves avatar aong with swipe - x: '-' + swipe_range, - duration: swipe_duration, - easing: animation_easing, - queue: false, - complete: function () { - $(this).parent().children('.avatar').transition({ - x: swipe_range, - duration: 0, - easing: animation_easing, - queue: false, - complete: function () { - $(this).parent().children('.avatar').transition({ - x: '0px', - duration: swipe_duration, - easing: animation_easing, - queue: false, - complete: function () { - - } - }); - } - }); - } - }); - } - - }); + $(document).on('click', '.swipe_right', swipe_right); $(document).on('click', '.swipe_left', function () { // when we swipe left..but no generation. if (chat.length - 1 === Number(this_edit_mes_id)) { diff --git a/public/scripts/extensions/stable-diffusion/index.js b/public/scripts/extensions/stable-diffusion/index.js index ad12381a7..c4af71d2b 100644 --- a/public/scripts/extensions/stable-diffusion/index.js +++ b/public/scripts/extensions/stable-diffusion/index.js @@ -3,9 +3,11 @@ import { saveSettingsDebounced, systemUserName, hideSwipeButtons, - showSwipeButtons + showSwipeButtons, + callPopup, + getRequestHeaders } from "../../../script.js"; -import { getApiUrl, getContext, extension_settings, defaultRequestArgs } from "../../extensions.js"; +import { getApiUrl, getContext, extension_settings, defaultRequestArgs, modules } from "../../extensions.js"; import { stringFormat, initScrollHeight, resetScrollHeight } from "../../utils.js"; export { MODULE_NAME }; @@ -94,6 +96,9 @@ const defaultSettings = { negative_prompt: 'lowres, bad anatomy, bad hands, text, error, cropped, worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry', sampler: 'DDIM', model: '', + + horde: false, + horde_nsfw: false, } async function loadSettings() { @@ -107,11 +112,10 @@ async function loadSettings() { $('#sd_negative_prompt').val(extension_settings.sd.negative_prompt).trigger('input'); $('#sd_width').val(extension_settings.sd.width).trigger('input'); $('#sd_height').val(extension_settings.sd.height).trigger('input'); - + $('#sd_horde').prop('checked', extension_settings.sd.horde); + $('#sd_horde_nsfw').prop('checked', extension_settings.sd.horde_nsfw); await Promise.all([loadSamplers(), loadModels()]); - - } function onScaleInput() { @@ -155,10 +159,29 @@ function onHeightInput() { saveSettingsDebounced(); } +async function onHordeInput() { + extension_settings.sd.model = null; + extension_settings.sd.sampler = null; + extension_settings.sd.horde = !!$(this).prop('checked'); + saveSettingsDebounced(); + await Promise.all([loadModels(), loadSamplers()]); +} + +async function onHordeNsfwInput() { + extension_settings.sd.horde_nsfw = !!$(this).prop('checked'); + saveSettingsDebounced(); +} + async function onModelChange() { extension_settings.sd.model = $('#sd_model').find(':selected').val(); saveSettingsDebounced(); + if (extension_settings.sd.horde == false) { + await updateExtrasRemoteModel(); + } +} + +async function updateExtrasRemoteModel() { const url = new URL(getApiUrl()); url.pathname = '/api/image/model'; const getCurrentModelResult = await fetch(url, { @@ -173,25 +196,86 @@ async function onModelChange() { } async function loadSamplers() { + $('#sd_sampler').empty(); + let samplers = []; + + if (extension_settings.sd.horde) { + samplers = await loadHordeSamplers(); + } else { + samplers = await loadExtrasSamplers(); + } + + for (const sampler of samplers) { + const option = document.createElement('option'); + option.innerText = sampler; + option.value = sampler; + option.selected = sampler === extension_settings.sd.sampler; + $('#sd_sampler').append(option); + } +} + +async function loadHordeSamplers() { + const result = await fetch('/horde_samplers', { + method: 'POST', + headers: getRequestHeaders(), + }); + + if (result.ok) { + const data = await result.json(); + return data; + } + + return []; +} + +async function loadExtrasSamplers() { const url = new URL(getApiUrl()); url.pathname = '/api/image/samplers'; const result = await fetch(url, defaultRequestArgs); if (result.ok) { const data = await result.json(); - const samplers = data.samplers; - - for (const sampler of samplers) { - const option = document.createElement('option'); - option.innerText = sampler; - option.value = sampler; - option.selected = sampler === extension_settings.sd.sampler; - $('#sd_sampler').append(option); - } + return data.samplers; } + + return []; } async function loadModels() { + $('#sd_model').empty(); + let models = []; + + if (extension_settings.sd.horde) { + models = await loadHordeModels(); + } else { + models = await loadExtrasModels(); + } + + for (const model of models) { + const option = document.createElement('option'); + option.innerText = model.text; + option.value = model.value; + option.selected = model.value === extension_settings.sd.model; + $('#sd_model').append(option); + } +} + +async function loadHordeModels() { + const result = await fetch('/horde_models', { + method: 'POST', + headers: getRequestHeaders(), + }); + + if (result.ok) { + const data = await result.json(); + const models = data.map(x => ({ value: x.name, text: `${x.name} (ETA: ${x.eta}s, Queue: ${x.queued}, Workers: ${x.count})` })); + return models; + } + + return []; +} + +async function loadExtrasModels() { const url = new URL(getApiUrl()); url.pathname = '/api/image/model'; const getCurrentModelResult = await fetch(url, defaultRequestArgs); @@ -206,16 +290,11 @@ async function loadModels() { if (getModelsResult.ok) { const data = await getModelsResult.json(); - const models = data.models; - - for (const model of models) { - const option = document.createElement('option'); - option.innerText = model; - option.value = model; - option.selected = model === extension_settings.sd.model; - $('#sd_model').append(option); - } + const view_models = data.models.map(x => ({ value: x, text: x })); + return view_models; } + + return []; } function getGenerationType(prompt) { @@ -257,6 +336,14 @@ async function generatePicture(_, trigger) { return; } + if (!modules.includes('sd') && !extension_settings.sd.horde) { + callPopup("Extensions API is not connected or doesn't provide SD module. Enable Stable Horde to generate images.", 'text'); + return; + } + + extension_settings.sd.sampler = $('#sd_sampler').find(':selected').val(); + extension_settings.sd.model = $('#sd_model').find(':selected').val(); + trigger = trigger.trim(); const generationMode = getGenerationType(trigger); console.log('Generation mode', generationMode, 'triggered with', trigger); @@ -279,30 +366,10 @@ async function generatePicture(_, trigger) { console.log('Processed Stable Diffusion prompt:', prompt); - const url = new URL(getApiUrl()); - url.pathname = '/api/image'; - const result = await fetch(url, { - method: 'POST', - headers: postHeaders, - body: JSON.stringify({ - prompt: prompt, - sampler: extension_settings.sd.sampler, - steps: extension_settings.sd.steps, - scale: extension_settings.sd.scale, - width: extension_settings.sd.width, - height: extension_settings.sd.height, - prompt_prefix: extension_settings.sd.prompt_prefix, - negative_prompt: extension_settings.sd.negative_prompt, - restore_faces: true, - face_restoration_model: 'GFPGAN', - - }), - }); - - if (result.ok) { - const data = await result.json(); - const base64Image = `data:image/jpeg;base64,${data.image}`; - sendMessage(prompt, base64Image); + if (extension_settings.sd.horde) { + await generateHordeImage(prompt); + } else { + await generateExtrasImage(prompt); } } catch (err) { console.trace(err); @@ -314,6 +381,59 @@ async function generatePicture(_, trigger) { } } +async function generateExtrasImage(prompt) { + const url = new URL(getApiUrl()); + url.pathname = '/api/image'; + const result = await fetch(url, { + method: 'POST', + headers: postHeaders, + body: JSON.stringify({ + prompt: prompt, + sampler: extension_settings.sd.sampler, + steps: extension_settings.sd.steps, + scale: extension_settings.sd.scale, + width: extension_settings.sd.width, + height: extension_settings.sd.height, + prompt_prefix: extension_settings.sd.prompt_prefix, + negative_prompt: extension_settings.sd.negative_prompt, + restore_faces: true, + face_restoration_model: 'GFPGAN', + }), + }); + + + if (result.ok) { + const data = await result.json(); + const base64Image = `data:image/jpeg;base64,${data.image}`; + sendMessage(prompt, base64Image); + } +} + +async function generateHordeImage(prompt) { + const result = await fetch('/horde_generateimage', { + method: 'POST', + headers: getRequestHeaders(), + body: JSON.stringify({ + prompt: prompt, + sampler: extension_settings.sd.sampler, + steps: extension_settings.sd.steps, + scale: extension_settings.sd.scale, + width: extension_settings.sd.width, + height: extension_settings.sd.height, + prompt_prefix: extension_settings.sd.prompt_prefix, + negative_prompt: extension_settings.sd.negative_prompt, + model: extension_settings.sd.model, + nsfw: extension_settings.sd.horde_nsfw, + }), + }); + + if (result.ok) { + const data = await result.text(); + const base64Image = `data:image/webp;base64,${data}`; + sendMessage(prompt, base64Image); + } +} + async function sendMessage(prompt, image) { const context = getContext(); const messageText = `[${context.name2} sends a picture that contains: ${prompt}]`; @@ -386,16 +506,6 @@ function addSDGenButtons() { async function moduleWorker() { const context = getContext(); - /* if (context.onlineStatus === 'no_connection') { - $('#sd_gen').hide(200); - } else if ($("#send_but").css('display') === 'flex') { - $('#sd_gen').show(200); - $("#sd_gen_wait").hide(200); - } else { - $('#sd_gen').hide(200); - $("#sd_gen_wait").show(200); - } */ - context.onlineStatus === 'no_connection' ? $('#sd_gen').hide(200) : $('#sd_gen').show(200) @@ -444,6 +554,16 @@ jQuery(async () => {
Use slash commands to generate images. Type /help in chat for more details +
+ Hint: Save an API key in Horde KoboldAI API settings to use it here. + + @@ -472,6 +592,8 @@ jQuery(async () => { $('#sd_negative_prompt').on('input', onNegativePromptInput); $('#sd_width').on('input', onWidthInput); $('#sd_height').on('input', onHeightInput); + $('#sd_horde').on('input', onHordeInput); + $('#sd_horde_nsfw').on('input', onHordeNsfwInput); $('.sd_settings .inline-drawer-toggle').on('click', function () { initScrollHeight($("#sd_prompt_prefix")); diff --git a/public/scripts/extensions/stable-diffusion/style.css b/public/scripts/extensions/stable-diffusion/style.css index 5d26a2ad3..3cb72e138 100644 --- a/public/scripts/extensions/stable-diffusion/style.css +++ b/public/scripts/extensions/stable-diffusion/style.css @@ -1,4 +1,4 @@ -.sd_settings label { +.sd_settings label:not(.checkbox_label) { display: block; } @@ -16,7 +16,6 @@ display: flex; align-items: center; justify-content: center; - } #sd_gen:hover { diff --git a/public/scripts/openai.js b/public/scripts/openai.js index a4db5fa9e..74b0b99f6 100644 --- a/public/scripts/openai.js +++ b/public/scripts/openai.js @@ -300,7 +300,7 @@ async function prepareOpenAIMessages(name2, storyString, worldInfoBefore, worldI let whole_prompt = getSystemPrompt(nsfw_toggle_prompt, enhance_definitions_prompt, wiBefore, storyString, wiAfter, extensionPrompt, isImpersonate); // Join by a space and replace placeholders with real user/char names - storyString = substituteParams(whole_prompt.join(" ")).replace(/\r/gm, '').trim(); + storyString = substituteParams(whole_prompt.join("\n")).replace(/\r/gm, '').trim(); let prompt_msg = { "role": "system", "content": storyString } let examples_tosend = []; @@ -469,7 +469,7 @@ function getSystemPrompt(nsfw_toggle_prompt, enhance_definitions_prompt, wiBefor whole_prompt = [nsfw_toggle_prompt, oai_settings.main_prompt, enhance_definitions_prompt + "\n\n" + wiBefore, storyString, wiAfter, extensionPrompt]; } else { - whole_prompt = [oai_settings.main_prompt, nsfw_toggle_prompt, enhance_definitions_prompt + "\n\n" + wiBefore, storyString, wiAfter, extensionPrompt]; + whole_prompt = [oai_settings.main_prompt, nsfw_toggle_prompt, enhance_definitions_prompt, "\n", wiBefore, storyString, wiAfter, extensionPrompt].filter(elem => elem); } } return whole_prompt; diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index a0bbb9c94..2e448e684 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -109,6 +109,10 @@ let power_user = { noShadows: false, theme: 'Default (Dark)', + auto_swipe: false, + auto_swipe_minimum_length: 0, + auto_swipe_blacklist: [], + auto_swipe_blacklist_threshold: 2, auto_scroll_chat_to_bottom: true, auto_fix_generated_markdown: true, send_on_enter: send_on_enter_options.AUTO, @@ -480,6 +484,11 @@ function loadPowerUserSettings(settings, data) { power_user.font_scale = Number(localStorage.getItem(storage_keys.font_scale) ?? 1); power_user.blur_strength = Number(localStorage.getItem(storage_keys.blur_strength) ?? 10); + $('#auto_swipe').prop("checked", power_user.auto_swipe); + $('#auto_swipe_minimum_length').val(power_user.auto_swipe_minimum_length); + $('#auto_swipe_blacklist').val(power_user.auto_swipe_blacklist.join(", ")); + $('#auto_swipe_blacklist_threshold').val(power_user.auto_swipe_blacklist_threshold); + $("#console_log_prompts").prop("checked", power_user.console_log_prompts); $('#auto_fix_generated_markdown').prop("checked", power_user.auto_fix_generated_markdown); $('#auto_scroll_chat_to_bottom').prop("checked", power_user.auto_scroll_chat_to_bottom); @@ -1042,6 +1051,36 @@ $(document).ready(() => { saveSettingsDebounced(); }); + $('#auto_swipe').on('input', function () { + power_user.auto_swipe = !!$(this).prop('checked'); + saveSettingsDebounced(); + }); + + $('#auto_swipe_blacklist').on('input', function () { + power_user.auto_swipe_blacklist = $(this).val() + .split(",") + .map(str => str.trim()) + .filter(str => str); + console.log("power_user.auto_swipe_blacklist", power_user.auto_swipe_blacklist) + saveSettingsDebounced(); + }); + + $('#auto_swipe_minimum_length').on('input', function () { + const number = parseInt($(this).val()); + if (!isNaN(number)) { + power_user.auto_swipe_minimum_length = number; + saveSettingsDebounced(); + } + }); + + $('#auto_swipe_blacklist_threshold').on('input', function () { + const number = parseInt($(this).val()); + if (!isNaN(number)) { + power_user.auto_swipe_blacklist_threshold = number; + saveSettingsDebounced(); + } + }); + $('#auto_fix_generated_markdown').on('input', function () { power_user.auto_fix_generated_markdown = !!$(this).prop('checked'); reloadCurrentChat(); diff --git a/server.js b/server.js index 05d584028..c4e577a7a 100644 --- a/server.js +++ b/server.js @@ -2925,10 +2925,21 @@ app.post('/viewsecrets', jsonParser, async (_, response) => { } }); -app.post('/horde_generateimage', async (request, response) => { +app.post('/horde_samplers', jsonParser, async (_, response) => { + const samplers = Object.values(ai_horde.ModelGenerationInputStableSamplers); + response.send(samplers); +}); + +app.post('/horde_models', jsonParser, async (_, response) => { + const models = await ai_horde.getModels(); + response.send(models); +}); + +app.post('/horde_generateimage', jsonParser, async (request, response) => { const MAX_ATTEMPTS = 100; const CHECK_INTERVAL = 3000; const api_key_horde = readSecret(SECRET_KEYS.HORDE) || ANONYMOUS_KEY; + console.log('Stable Horde request:', request.body); const generation = await ai_horde.postAsyncImageGenerate( { prompt: `${request.body.prompt_prefix} ${request.body.prompt} ### ${request.body.negative_prompt}`, @@ -2950,12 +2961,17 @@ app.post('/horde_generateimage', async (request, response) => { for (let attempt = 0; attempt < MAX_ATTEMPTS; attempt++) { await delay(CHECK_INTERVAL); const check = await ai_horde.getImageGenerationCheck(generation.id); + console.log(check); if (check.done) { const result = await ai_horde.getImageGenerationStatus(generation.id); return response.send(result.generations[0].img); } + if (!check.is_possible) { + return response.sendStatus(503); + } + if (check.faulted) { return response.sendStatus(500); }