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);
}