#2187 Add negative prefix arg to /sd command
This commit is contained in:
parent
c73bfbd7b0
commit
12eabd167d
|
@ -26,6 +26,7 @@ import { SECRET_KEYS, secret_state } from '../../secrets.js';
|
||||||
import { getNovelUnlimitedImageGeneration, getNovelAnlas, loadNovelSubscriptionData } from '../../nai-settings.js';
|
import { getNovelUnlimitedImageGeneration, getNovelAnlas, loadNovelSubscriptionData } from '../../nai-settings.js';
|
||||||
import { getMultimodalCaption } from '../shared.js';
|
import { getMultimodalCaption } from '../shared.js';
|
||||||
import { registerSlashCommand } from '../../slash-commands.js';
|
import { registerSlashCommand } from '../../slash-commands.js';
|
||||||
|
import { resolveVariable } from '../../variables.js';
|
||||||
export { MODULE_NAME };
|
export { MODULE_NAME };
|
||||||
|
|
||||||
// Wraps a string into monospace font-face span
|
// Wraps a string into monospace font-face span
|
||||||
|
@ -589,15 +590,17 @@ async function expandPrompt(prompt) {
|
||||||
* Modifies prompt based on auto-expansion and user inputs.
|
* Modifies prompt based on auto-expansion and user inputs.
|
||||||
* @param {string} prompt Prompt to refine
|
* @param {string} prompt Prompt to refine
|
||||||
* @param {boolean} allowExpand Whether to allow auto-expansion
|
* @param {boolean} allowExpand Whether to allow auto-expansion
|
||||||
|
* @param {boolean} isNegative Whether the prompt is a negative one
|
||||||
* @returns {Promise<string>} Refined prompt
|
* @returns {Promise<string>} Refined prompt
|
||||||
*/
|
*/
|
||||||
async function refinePrompt(prompt, allowExpand) {
|
async function refinePrompt(prompt, allowExpand, isNegative = false) {
|
||||||
if (allowExpand && extension_settings.sd.expand) {
|
if (allowExpand && extension_settings.sd.expand) {
|
||||||
prompt = await expandPrompt(prompt);
|
prompt = await expandPrompt(prompt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extension_settings.sd.refine_mode) {
|
if (extension_settings.sd.refine_mode) {
|
||||||
const refinedPrompt = await callPopup('<h3>Review and edit the prompt:</h3>Press "Cancel" to abort the image generation.', 'input', prompt.trim(), { rows: 5, okButton: 'Generate' });
|
const text = isNegative ? '<h3>Review and edit the <i>negative</i> prompt:</h3>' : '<h3>Review and edit the prompt:</h3>';
|
||||||
|
const refinedPrompt = await callPopup(text + 'Press "Cancel" to abort the image generation.', 'input', prompt.trim(), { rows: 5, okButton: 'Continue' });
|
||||||
|
|
||||||
if (refinedPrompt) {
|
if (refinedPrompt) {
|
||||||
return refinedPrompt;
|
return refinedPrompt;
|
||||||
|
@ -1967,9 +1970,9 @@ async function generatePicture(args, trigger, message, callback) {
|
||||||
eventSource.emit(event_types.FORCE_SET_BACKGROUND, { url: imgUrl, path: imagePath });
|
eventSource.emit(event_types.FORCE_SET_BACKGROUND, { url: imgUrl, path: imagePath });
|
||||||
|
|
||||||
if (typeof callbackOriginal === 'function') {
|
if (typeof callbackOriginal === 'function') {
|
||||||
callbackOriginal(prompt, imagePath, generationType);
|
callbackOriginal(prompt, imagePath, generationType, negativePromptPrefix);
|
||||||
} else {
|
} else {
|
||||||
sendMessage(prompt, imagePath, generationType);
|
sendMessage(prompt, imagePath, generationType, negativePromptPrefix);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1978,6 +1981,7 @@ async function generatePicture(args, trigger, message, callback) {
|
||||||
callback = () => { };
|
callback = () => { };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const negativePromptPrefix = resolveVariable(args?.negative) || '';
|
||||||
const dimensions = setTypeSpecificDimensions(generationType);
|
const dimensions = setTypeSpecificDimensions(generationType);
|
||||||
let imagePath = '';
|
let imagePath = '';
|
||||||
|
|
||||||
|
@ -1988,7 +1992,7 @@ async function generatePicture(args, trigger, message, callback) {
|
||||||
context.deactivateSendButtons();
|
context.deactivateSendButtons();
|
||||||
hideSwipeButtons();
|
hideSwipeButtons();
|
||||||
|
|
||||||
imagePath = await sendGenerationRequest(generationType, prompt, characterName, callback);
|
imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.trace(err);
|
console.trace(err);
|
||||||
throw new Error('SD prompt text generation failed.');
|
throw new Error('SD prompt text generation failed.');
|
||||||
|
@ -2183,17 +2187,26 @@ async function generatePrompt(quietPrompt) {
|
||||||
return processedReply;
|
return processedReply;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendGenerationRequest(generationType, prompt, characterName = null, callback) {
|
/**
|
||||||
|
* Sends a request to image generation endpoint and processes the result.
|
||||||
|
* @param {number} generationType Type of image generation
|
||||||
|
* @param {string} prompt Prompt to be used for image generation
|
||||||
|
* @param {string} additionalNegativePrefix Additional negative prompt to be used for image generation
|
||||||
|
* @param {string} [characterName] Name of the character
|
||||||
|
* @param {function} [callback] Callback function to be called after image generation
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function sendGenerationRequest(generationType, prompt, additionalNegativePrefix, characterName = null, callback) {
|
||||||
const noCharPrefix = [generationMode.FREE, generationMode.BACKGROUND, generationMode.USER, generationMode.USER_MULTIMODAL];
|
const noCharPrefix = [generationMode.FREE, generationMode.BACKGROUND, generationMode.USER, generationMode.USER_MULTIMODAL];
|
||||||
const prefix = noCharPrefix.includes(generationType)
|
const prefix = noCharPrefix.includes(generationType)
|
||||||
? extension_settings.sd.prompt_prefix
|
? extension_settings.sd.prompt_prefix
|
||||||
: combinePrefixes(extension_settings.sd.prompt_prefix, getCharacterPrefix());
|
: combinePrefixes(extension_settings.sd.prompt_prefix, getCharacterPrefix());
|
||||||
|
const negativePrefix = noCharPrefix.includes(generationType)
|
||||||
|
? extension_settings.sd.negative_prompt
|
||||||
|
: combinePrefixes(extension_settings.sd.negative_prompt, getCharacterNegativePrefix());
|
||||||
|
|
||||||
const prefixedPrompt = substituteParams(combinePrefixes(prefix, prompt, '{prompt}'));
|
const prefixedPrompt = substituteParams(combinePrefixes(prefix, prompt, '{prompt}'));
|
||||||
|
const negativePrompt = substituteParams(combinePrefixes(additionalNegativePrefix, negativePrefix));
|
||||||
const negativePrompt = substituteParams(noCharPrefix.includes(generationType)
|
|
||||||
? extension_settings.sd.negative_prompt
|
|
||||||
: combinePrefixes(extension_settings.sd.negative_prompt, getCharacterNegativePrefix()));
|
|
||||||
|
|
||||||
let result = { format: '', data: '' };
|
let result = { format: '', data: '' };
|
||||||
const currentChatId = getCurrentChatId();
|
const currentChatId = getCurrentChatId();
|
||||||
|
@ -2249,7 +2262,7 @@ async function sendGenerationRequest(generationType, prompt, characterName = nul
|
||||||
|
|
||||||
const filename = `${characterName}_${humanizedDateTime()}`;
|
const filename = `${characterName}_${humanizedDateTime()}`;
|
||||||
const base64Image = await saveBase64AsFile(result.data, characterName, filename, result.format);
|
const base64Image = await saveBase64AsFile(result.data, characterName, filename, result.format);
|
||||||
callback ? callback(prompt, base64Image, generationType) : sendMessage(prompt, base64Image, generationType);
|
callback ? callback(prompt, base64Image, generationType, additionalNegativePrefix) : sendMessage(prompt, base64Image, generationType, additionalNegativePrefix);
|
||||||
return base64Image;
|
return base64Image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2722,6 +2735,9 @@ async function onComfyOpenWorkflowEditorClick() {
|
||||||
$('#sd_comfy_workflow_editor_placeholder_list_custom').append(el);
|
$('#sd_comfy_workflow_editor_placeholder_list_custom').append(el);
|
||||||
el.find('.sd_comfy_workflow_editor_custom_find').val(placeholder.find);
|
el.find('.sd_comfy_workflow_editor_custom_find').val(placeholder.find);
|
||||||
el.find('.sd_comfy_workflow_editor_custom_find').on('input', function () {
|
el.find('.sd_comfy_workflow_editor_custom_find').on('input', function () {
|
||||||
|
if (!(this instanceof HTMLInputElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
placeholder.find = this.value;
|
placeholder.find = this.value;
|
||||||
el.find('.sd_comfy_workflow_editor_custom_final').text(`"%${this.value}%"`);
|
el.find('.sd_comfy_workflow_editor_custom_final').text(`"%${this.value}%"`);
|
||||||
el.attr('data-placeholder', `${this.value}`);
|
el.attr('data-placeholder', `${this.value}`);
|
||||||
|
@ -2730,6 +2746,9 @@ async function onComfyOpenWorkflowEditorClick() {
|
||||||
});
|
});
|
||||||
el.find('.sd_comfy_workflow_editor_custom_replace').val(placeholder.replace);
|
el.find('.sd_comfy_workflow_editor_custom_replace').val(placeholder.replace);
|
||||||
el.find('.sd_comfy_workflow_editor_custom_replace').on('input', function () {
|
el.find('.sd_comfy_workflow_editor_custom_replace').on('input', function () {
|
||||||
|
if (!(this instanceof HTMLInputElement)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
placeholder.replace = this.value;
|
placeholder.replace = this.value;
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
});
|
});
|
||||||
|
@ -2819,7 +2838,14 @@ async function onComfyDeleteWorkflowClick() {
|
||||||
onComfyWorkflowChange();
|
onComfyWorkflowChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendMessage(prompt, image, generationType) {
|
/**
|
||||||
|
* Sends a chat message with the generated image.
|
||||||
|
* @param {string} prompt Prompt used for the image generation
|
||||||
|
* @param {string} image Base64 encoded image
|
||||||
|
* @param {number} generationType Generation type of the image
|
||||||
|
* @param {string} additionalNegativePrefix Additional negative prompt used for the image generation
|
||||||
|
*/
|
||||||
|
async function sendMessage(prompt, image, generationType, additionalNegativePrefix) {
|
||||||
const context = getContext();
|
const context = getContext();
|
||||||
const messageText = `[${context.name2} sends a picture that contains: ${prompt}]`;
|
const messageText = `[${context.name2} sends a picture that contains: ${prompt}]`;
|
||||||
const message = {
|
const message = {
|
||||||
|
@ -2832,6 +2858,7 @@ async function sendMessage(prompt, image, generationType) {
|
||||||
image: image,
|
image: image,
|
||||||
title: prompt,
|
title: prompt,
|
||||||
generationType: generationType,
|
generationType: generationType,
|
||||||
|
negative: additionalNegativePrefix,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
context.chat.push(message);
|
context.chat.push(message);
|
||||||
|
@ -2952,6 +2979,7 @@ async function sdMessageButton(e) {
|
||||||
const characterFileName = context.characterId ? context.characters[context.characterId].name : context.groups[Object.keys(context.groups).filter(x => context.groups[x].id === context.groupId)[0]]?.id?.toString();
|
const characterFileName = context.characterId ? context.characters[context.characterId].name : context.groups[Object.keys(context.groups).filter(x => context.groups[x].id === context.groupId)[0]]?.id?.toString();
|
||||||
const messageText = message?.mes;
|
const messageText = message?.mes;
|
||||||
const hasSavedImage = message?.extra?.image && message?.extra?.title;
|
const hasSavedImage = message?.extra?.image && message?.extra?.title;
|
||||||
|
const hasSavedNegative = message?.extra?.negative;
|
||||||
|
|
||||||
if ($icon.hasClass(busyClass)) {
|
if ($icon.hasClass(busyClass)) {
|
||||||
console.log('Previous image is still being generated...');
|
console.log('Previous image is still being generated...');
|
||||||
|
@ -2963,13 +2991,14 @@ async function sdMessageButton(e) {
|
||||||
try {
|
try {
|
||||||
setBusyIcon(true);
|
setBusyIcon(true);
|
||||||
if (hasSavedImage) {
|
if (hasSavedImage) {
|
||||||
const prompt = await refinePrompt(message.extra.title, false);
|
const prompt = await refinePrompt(message.extra.title, false, false);
|
||||||
|
const negative = hasSavedNegative ? await refinePrompt(message.extra.negative, false, true) : '';
|
||||||
message.extra.title = prompt;
|
message.extra.title = prompt;
|
||||||
|
|
||||||
const generationType = message?.extra?.generationType ?? generationMode.FREE;
|
const generationType = message?.extra?.generationType ?? generationMode.FREE;
|
||||||
console.log('Regenerating an image, using existing prompt:', prompt);
|
console.log('Regenerating an image, using existing prompt:', prompt);
|
||||||
dimensions = setTypeSpecificDimensions(generationType);
|
dimensions = setTypeSpecificDimensions(generationType);
|
||||||
await sendGenerationRequest(generationType, prompt, characterFileName, saveGeneratedImage);
|
await sendGenerationRequest(generationType, prompt, negative, characterFileName, saveGeneratedImage);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
console.log('doing /sd raw last');
|
console.log('doing /sd raw last');
|
||||||
|
@ -2987,7 +3016,7 @@ async function sdMessageButton(e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveGeneratedImage(prompt, image, generationType) {
|
function saveGeneratedImage(prompt, image, generationType, negative) {
|
||||||
// Some message sources may not create the extra object
|
// Some message sources may not create the extra object
|
||||||
if (typeof message.extra !== 'object') {
|
if (typeof message.extra !== 'object') {
|
||||||
message.extra = {};
|
message.extra = {};
|
||||||
|
@ -2998,6 +3027,7 @@ async function sdMessageButton(e) {
|
||||||
message.extra.image = image;
|
message.extra.image = image;
|
||||||
message.extra.title = prompt;
|
message.extra.title = prompt;
|
||||||
message.extra.generationType = generationType;
|
message.extra.generationType = generationType;
|
||||||
|
message.extra.negative = negative;
|
||||||
appendMediaToMessage(message, $mes);
|
appendMediaToMessage(message, $mes);
|
||||||
|
|
||||||
context.saveChat();
|
context.saveChat();
|
||||||
|
|
Loading…
Reference in New Issue