mirror of
				https://github.com/SillyTavern/SillyTavern.git
				synced 2025-06-05 21:59:27 +02:00 
			
		
		
		
	#2187 Add negative prefix arg to /sd command
This commit is contained in:
		| @@ -26,6 +26,7 @@ import { SECRET_KEYS, secret_state } from '../../secrets.js'; | ||||
| import { getNovelUnlimitedImageGeneration, getNovelAnlas, loadNovelSubscriptionData } from '../../nai-settings.js'; | ||||
| import { getMultimodalCaption } from '../shared.js'; | ||||
| import { registerSlashCommand } from '../../slash-commands.js'; | ||||
| import { resolveVariable } from '../../variables.js'; | ||||
| export { MODULE_NAME }; | ||||
|  | ||||
| // 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. | ||||
|  * @param {string} prompt Prompt to refine | ||||
|  * @param {boolean} allowExpand Whether to allow auto-expansion | ||||
|  * @param {boolean} isNegative Whether the prompt is a negative one | ||||
|  * @returns {Promise<string>} Refined prompt | ||||
|  */ | ||||
| async function refinePrompt(prompt, allowExpand) { | ||||
| async function refinePrompt(prompt, allowExpand, isNegative = false) { | ||||
|     if (allowExpand && extension_settings.sd.expand) { | ||||
|         prompt = await expandPrompt(prompt); | ||||
|     } | ||||
|  | ||||
|     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) { | ||||
|             return refinedPrompt; | ||||
| @@ -1967,9 +1970,9 @@ async function generatePicture(args, trigger, message, callback) { | ||||
|             eventSource.emit(event_types.FORCE_SET_BACKGROUND, { url: imgUrl, path: imagePath }); | ||||
|  | ||||
|             if (typeof callbackOriginal === 'function') { | ||||
|                 callbackOriginal(prompt, imagePath, generationType); | ||||
|                 callbackOriginal(prompt, imagePath, generationType, negativePromptPrefix); | ||||
|             } else { | ||||
|                 sendMessage(prompt, imagePath, generationType); | ||||
|                 sendMessage(prompt, imagePath, generationType, negativePromptPrefix); | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| @@ -1978,6 +1981,7 @@ async function generatePicture(args, trigger, message, callback) { | ||||
|         callback = () => { }; | ||||
|     } | ||||
|  | ||||
|     const negativePromptPrefix = resolveVariable(args?.negative) || ''; | ||||
|     const dimensions = setTypeSpecificDimensions(generationType); | ||||
|     let imagePath = ''; | ||||
|  | ||||
| @@ -1988,7 +1992,7 @@ async function generatePicture(args, trigger, message, callback) { | ||||
|         context.deactivateSendButtons(); | ||||
|         hideSwipeButtons(); | ||||
|  | ||||
|         imagePath = await sendGenerationRequest(generationType, prompt, characterName, callback); | ||||
|         imagePath = await sendGenerationRequest(generationType, prompt, negativePromptPrefix, characterName, callback); | ||||
|     } catch (err) { | ||||
|         console.trace(err); | ||||
|         throw new Error('SD prompt text generation failed.'); | ||||
| @@ -2183,17 +2187,26 @@ async function generatePrompt(quietPrompt) { | ||||
|     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 prefix = noCharPrefix.includes(generationType) | ||||
|         ? extension_settings.sd.prompt_prefix | ||||
|         : 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 negativePrompt = substituteParams(noCharPrefix.includes(generationType) | ||||
|         ? extension_settings.sd.negative_prompt | ||||
|         : combinePrefixes(extension_settings.sd.negative_prompt, getCharacterNegativePrefix())); | ||||
|     const negativePrompt = substituteParams(combinePrefixes(additionalNegativePrefix, negativePrefix)); | ||||
|  | ||||
|     let result = { format: '', data: '' }; | ||||
|     const currentChatId = getCurrentChatId(); | ||||
| @@ -2249,7 +2262,7 @@ async function sendGenerationRequest(generationType, prompt, characterName = nul | ||||
|  | ||||
|     const filename = `${characterName}_${humanizedDateTime()}`; | ||||
|     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; | ||||
| } | ||||
|  | ||||
| @@ -2722,6 +2735,9 @@ async function onComfyOpenWorkflowEditorClick() { | ||||
|         $('#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').on('input', function () { | ||||
|             if (!(this instanceof HTMLInputElement)) { | ||||
|                 return; | ||||
|             } | ||||
|             placeholder.find = this.value; | ||||
|             el.find('.sd_comfy_workflow_editor_custom_final').text(`"%${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').on('input', function () { | ||||
|             if (!(this instanceof HTMLInputElement)) { | ||||
|                 return; | ||||
|             } | ||||
|             placeholder.replace = this.value; | ||||
|             saveSettingsDebounced(); | ||||
|         }); | ||||
| @@ -2819,7 +2838,14 @@ async function onComfyDeleteWorkflowClick() { | ||||
|     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 messageText = `[${context.name2} sends a picture that contains: ${prompt}]`; | ||||
|     const message = { | ||||
| @@ -2832,6 +2858,7 @@ async function sendMessage(prompt, image, generationType) { | ||||
|             image: image, | ||||
|             title: prompt, | ||||
|             generationType: generationType, | ||||
|             negative: additionalNegativePrefix, | ||||
|         }, | ||||
|     }; | ||||
|     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 messageText = message?.mes; | ||||
|     const hasSavedImage = message?.extra?.image && message?.extra?.title; | ||||
|     const hasSavedNegative = message?.extra?.negative; | ||||
|  | ||||
|     if ($icon.hasClass(busyClass)) { | ||||
|         console.log('Previous image is still being generated...'); | ||||
| @@ -2963,13 +2991,14 @@ async function sdMessageButton(e) { | ||||
|     try { | ||||
|         setBusyIcon(true); | ||||
|         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; | ||||
|  | ||||
|             const generationType = message?.extra?.generationType ?? generationMode.FREE; | ||||
|             console.log('Regenerating an image, using existing prompt:', prompt); | ||||
|             dimensions = setTypeSpecificDimensions(generationType); | ||||
|             await sendGenerationRequest(generationType, prompt, characterFileName, saveGeneratedImage); | ||||
|             await sendGenerationRequest(generationType, prompt, negative, characterFileName, saveGeneratedImage); | ||||
|         } | ||||
|         else { | ||||
|             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 | ||||
|         if (typeof message.extra !== 'object') { | ||||
|             message.extra = {}; | ||||
| @@ -2998,6 +3027,7 @@ async function sdMessageButton(e) { | ||||
|         message.extra.image = image; | ||||
|         message.extra.title = prompt; | ||||
|         message.extra.generationType = generationType; | ||||
|         message.extra.negative = negative; | ||||
|         appendMediaToMessage(message, $mes); | ||||
|  | ||||
|         context.saveChat(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user