mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Merge branch 'staging' into swipe-nums-for-all-mes
This commit is contained in:
@@ -2,17 +2,26 @@
|
|||||||
pushd %~dp0
|
pushd %~dp0
|
||||||
git --version > nul 2>&1
|
git --version > nul 2>&1
|
||||||
if %errorlevel% neq 0 (
|
if %errorlevel% neq 0 (
|
||||||
echo Git is not installed on this system. Skipping update.
|
echo [91mGit is not installed on this system.[0m
|
||||||
echo If you installed with a zip file, you will need to download the new zip and install it manually.
|
echo Install it from https://git-scm.com/downloads
|
||||||
|
goto end
|
||||||
) else (
|
) else (
|
||||||
|
if not exist .git (
|
||||||
|
echo [91mNot running from a Git repository. Reinstall using an officially supported method to get updates.[0m
|
||||||
|
echo See: https://docs.sillytavern.app/installation/windows/
|
||||||
|
goto end
|
||||||
|
)
|
||||||
call git pull --rebase --autostash
|
call git pull --rebase --autostash
|
||||||
if %errorlevel% neq 0 (
|
if %errorlevel% neq 0 (
|
||||||
REM incase there is still something wrong
|
REM incase there is still something wrong
|
||||||
echo There were errors while updating. Please download the latest version manually.
|
echo [91mThere were errors while updating.[0m
|
||||||
|
echo See the update FAQ at https://docs.sillytavern.app/usage/update/#common-update-problems
|
||||||
|
goto end
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
set NODE_ENV=production
|
set NODE_ENV=production
|
||||||
call npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev
|
call npm install --no-audit --no-fund --loglevel=error --no-progress --omit=dev
|
||||||
node server.js %*
|
node server.js %*
|
||||||
|
:end
|
||||||
pause
|
pause
|
||||||
popd
|
popd
|
||||||
|
@@ -5,8 +5,14 @@ pushd %~dp0
|
|||||||
echo Checking Git installation
|
echo Checking Git installation
|
||||||
git --version > nul 2>&1
|
git --version > nul 2>&1
|
||||||
if %errorlevel% neq 0 (
|
if %errorlevel% neq 0 (
|
||||||
echo Git is not installed on this system. Skipping update.
|
echo [91mGit is not installed on this system.[0m
|
||||||
echo If you installed with a zip file, you will need to download the new zip and install it manually.
|
echo Install it from https://git-scm.com/downloads
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if not exist .git (
|
||||||
|
echo [91mNot running from a Git repository. Reinstall using an officially supported method to get updates.[0m
|
||||||
|
echo See: https://docs.sillytavern.app/installation/windows/
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -89,7 +95,8 @@ git pull --rebase --autostash origin %TARGET_BRANCH%
|
|||||||
|
|
||||||
:install
|
:install
|
||||||
if %errorlevel% neq 0 (
|
if %errorlevel% neq 0 (
|
||||||
echo There were errors while updating. Please check manually.
|
echo [91mThere were errors while updating.[0m
|
||||||
|
echo See the update FAQ at https://docs.sillytavern.app/usage/update/#common-update-problems
|
||||||
goto end
|
goto end
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@@ -118,7 +118,6 @@ extras:
|
|||||||
classificationModel: Cohee/distilbert-base-uncased-go-emotions-onnx
|
classificationModel: Cohee/distilbert-base-uncased-go-emotions-onnx
|
||||||
captioningModel: Xenova/vit-gpt2-image-captioning
|
captioningModel: Xenova/vit-gpt2-image-captioning
|
||||||
embeddingModel: Cohee/jina-embeddings-v2-base-en
|
embeddingModel: Cohee/jina-embeddings-v2-base-en
|
||||||
promptExpansionModel: Cohee/fooocus_expansion-onnx
|
|
||||||
speechToTextModel: Xenova/whisper-small
|
speechToTextModel: Xenova/whisper-small
|
||||||
textToSpeechModel: Xenova/speecht5_tts
|
textToSpeechModel: Xenova/speecht5_tts
|
||||||
# -- OPENAI CONFIGURATION --
|
# -- OPENAI CONFIGURATION --
|
||||||
|
@@ -4797,7 +4797,7 @@ export function removeMacros(str) {
|
|||||||
* @param {boolean} [compact] Send as a compact display message.
|
* @param {boolean} [compact] Send as a compact display message.
|
||||||
* @param {string} [name] Name of the user sending the message. Defaults to name1.
|
* @param {string} [name] Name of the user sending the message. Defaults to name1.
|
||||||
* @param {string} [avatar] Avatar of the user sending the message. Defaults to user_avatar.
|
* @param {string} [avatar] Avatar of the user sending the message. Defaults to user_avatar.
|
||||||
* @returns {Promise<void>} A promise that resolves when the message is inserted.
|
* @returns {Promise<any>} A promise that resolves to the message when it is inserted.
|
||||||
*/
|
*/
|
||||||
export async function sendMessageAsUser(messageText, messageBias, insertAt = null, compact = false, name = name1, avatar = user_avatar) {
|
export async function sendMessageAsUser(messageText, messageBias, insertAt = null, compact = false, name = name1, avatar = user_avatar) {
|
||||||
messageText = getRegexedString(messageText, regex_placement.USER_INPUT);
|
messageText = getRegexedString(messageText, regex_placement.USER_INPUT);
|
||||||
@@ -4844,6 +4844,8 @@ export async function sendMessageAsUser(messageText, messageBias, insertAt = nul
|
|||||||
await eventSource.emit(event_types.USER_MESSAGE_RENDERED, chat_id);
|
await eventSource.emit(event_types.USER_MESSAGE_RENDERED, chat_id);
|
||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -12,6 +12,8 @@ import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '
|
|||||||
import { isFunctionCallingSupported } from '../../openai.js';
|
import { isFunctionCallingSupported } from '../../openai.js';
|
||||||
import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
|
import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js';
|
||||||
import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||||
|
import { slashCommandReturnHelper } from '../../slash-commands/SlashCommandReturnHelper.js';
|
||||||
|
import { SlashCommandClosure } from '../../slash-commands/SlashCommandClosure.js';
|
||||||
export { MODULE_NAME };
|
export { MODULE_NAME };
|
||||||
|
|
||||||
const MODULE_NAME = 'expressions';
|
const MODULE_NAME = 'expressions';
|
||||||
@@ -2134,18 +2136,42 @@ function migrateSettings() {
|
|||||||
name: 'classify-expressions',
|
name: 'classify-expressions',
|
||||||
aliases: ['expressions'],
|
aliases: ['expressions'],
|
||||||
callback: async (args) => {
|
callback: async (args) => {
|
||||||
const list = await getExpressionsList();
|
/** @type {import('../../slash-commands/SlashCommandReturnHelper.js').SlashCommandReturnType} */
|
||||||
switch (String(args.format).toLowerCase()) {
|
// @ts-ignore
|
||||||
|
let returnType = args.return;
|
||||||
|
|
||||||
|
// Old legacy return type handling
|
||||||
|
if (args.format) {
|
||||||
|
toastr.warning(`Legacy argument 'format' with value '${args.format}' is deprecated. Please use 'return' instead. Routing to the correct return type...`, 'Deprecation warning');
|
||||||
|
const type = String(args?.format).toLowerCase().trim();
|
||||||
|
switch (type) {
|
||||||
case 'json':
|
case 'json':
|
||||||
return JSON.stringify(list);
|
returnType = 'object';
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return list.join(', ');
|
returnType = 'pipe';
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now the actual new return type handling
|
||||||
|
const list = await getExpressionsList();
|
||||||
|
|
||||||
|
return await slashCommandReturnHelper.doReturn(returnType ?? 'pipe', list, { objectToStringFunc: list => list.join(', ') });
|
||||||
},
|
},
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'return',
|
||||||
|
description: 'The way how you want the return value to be provided',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
defaultValue: 'pipe',
|
||||||
|
enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
|
||||||
|
forceEnum: true,
|
||||||
|
}),
|
||||||
|
// TODO remove some day
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'format',
|
name: 'format',
|
||||||
description: 'The format to return the list in: comma-separated plain text or JSON array. Default is plain text.',
|
description: '!!! DEPRECATED - use "return" instead !!! The format to return the list in: comma-separated plain text or JSON array. Default is plain text.',
|
||||||
typeList: [ARGUMENT_TYPE.STRING],
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
enumList: [
|
enumList: [
|
||||||
new SlashCommandEnumValue('plain', null, enumTypes.enum, ', '),
|
new SlashCommandEnumValue('plain', null, enumTypes.enum, ', '),
|
||||||
|
@@ -20,7 +20,7 @@ import {
|
|||||||
} from '../../../script.js';
|
} from '../../../script.js';
|
||||||
import { getApiUrl, getContext, extension_settings, doExtrasFetch, modules, renderExtensionTemplateAsync, writeExtensionField } from '../../extensions.js';
|
import { getApiUrl, getContext, extension_settings, doExtrasFetch, modules, renderExtensionTemplateAsync, writeExtensionField } from '../../extensions.js';
|
||||||
import { selected_group } from '../../group-chats.js';
|
import { selected_group } from '../../group-chats.js';
|
||||||
import { stringFormat, initScrollHeight, resetScrollHeight, getCharaFilename, saveBase64AsFile, getBase64Async, delay, isTrueBoolean, debounce } from '../../utils.js';
|
import { stringFormat, initScrollHeight, resetScrollHeight, getCharaFilename, saveBase64AsFile, getBase64Async, delay, isTrueBoolean, debounce, isFalseBoolean } from '../../utils.js';
|
||||||
import { getMessageTimeStamp, humanizedDateTime } from '../../RossAscends-mods.js';
|
import { getMessageTimeStamp, humanizedDateTime } from '../../RossAscends-mods.js';
|
||||||
import { SECRET_KEYS, secret_state, writeSecret } from '../../secrets.js';
|
import { SECRET_KEYS, secret_state, writeSecret } from '../../secrets.js';
|
||||||
import { getNovelUnlimitedImageGeneration, getNovelAnlas, loadNovelSubscriptionData } from '../../nai-settings.js';
|
import { getNovelUnlimitedImageGeneration, getNovelAnlas, loadNovelSubscriptionData } from '../../nai-settings.js';
|
||||||
@@ -31,6 +31,7 @@ import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '
|
|||||||
import { debounce_timeout } from '../../constants.js';
|
import { debounce_timeout } from '../../constants.js';
|
||||||
import { SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';
|
import { SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';
|
||||||
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from '../../popup.js';
|
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from '../../popup.js';
|
||||||
|
import { commonEnumProviders } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||||
export { MODULE_NAME };
|
export { MODULE_NAME };
|
||||||
|
|
||||||
const MODULE_NAME = 'sd';
|
const MODULE_NAME = 'sd';
|
||||||
@@ -221,7 +222,6 @@ const defaultSettings = {
|
|||||||
|
|
||||||
// Refine mode
|
// Refine mode
|
||||||
refine_mode: false,
|
refine_mode: false,
|
||||||
expand: false,
|
|
||||||
interactive_mode: false,
|
interactive_mode: false,
|
||||||
multimodal_captioning: false,
|
multimodal_captioning: false,
|
||||||
snap: false,
|
snap: false,
|
||||||
@@ -240,7 +240,7 @@ const defaultSettings = {
|
|||||||
drawthings_auth: '',
|
drawthings_auth: '',
|
||||||
|
|
||||||
hr_upscaler: 'Latent',
|
hr_upscaler: 'Latent',
|
||||||
hr_scale: 2.0,
|
hr_scale: 1.0,
|
||||||
hr_scale_min: 1.0,
|
hr_scale_min: 1.0,
|
||||||
hr_scale_max: 4.0,
|
hr_scale_max: 4.0,
|
||||||
hr_scale_step: 0.1,
|
hr_scale_step: 0.1,
|
||||||
@@ -260,10 +260,6 @@ const defaultSettings = {
|
|||||||
clip_skip: 1,
|
clip_skip: 1,
|
||||||
|
|
||||||
// NovelAI settings
|
// NovelAI settings
|
||||||
novel_upscale_ratio_min: 1.0,
|
|
||||||
novel_upscale_ratio_max: 4.0,
|
|
||||||
novel_upscale_ratio_step: 0.1,
|
|
||||||
novel_upscale_ratio: 1.0,
|
|
||||||
novel_anlas_guard: false,
|
novel_anlas_guard: false,
|
||||||
novel_sm: false,
|
novel_sm: false,
|
||||||
novel_sm_dyn: false,
|
novel_sm_dyn: false,
|
||||||
@@ -416,7 +412,6 @@ async function loadSettings() {
|
|||||||
$('#sd_hr_scale').val(extension_settings.sd.hr_scale).trigger('input');
|
$('#sd_hr_scale').val(extension_settings.sd.hr_scale).trigger('input');
|
||||||
$('#sd_denoising_strength').val(extension_settings.sd.denoising_strength).trigger('input');
|
$('#sd_denoising_strength').val(extension_settings.sd.denoising_strength).trigger('input');
|
||||||
$('#sd_hr_second_pass_steps').val(extension_settings.sd.hr_second_pass_steps).trigger('input');
|
$('#sd_hr_second_pass_steps').val(extension_settings.sd.hr_second_pass_steps).trigger('input');
|
||||||
$('#sd_novel_upscale_ratio').val(extension_settings.sd.novel_upscale_ratio).trigger('input');
|
|
||||||
$('#sd_novel_anlas_guard').prop('checked', extension_settings.sd.novel_anlas_guard);
|
$('#sd_novel_anlas_guard').prop('checked', extension_settings.sd.novel_anlas_guard);
|
||||||
$('#sd_novel_sm').prop('checked', extension_settings.sd.novel_sm);
|
$('#sd_novel_sm').prop('checked', extension_settings.sd.novel_sm);
|
||||||
$('#sd_novel_sm_dyn').prop('checked', extension_settings.sd.novel_sm_dyn);
|
$('#sd_novel_sm_dyn').prop('checked', extension_settings.sd.novel_sm_dyn);
|
||||||
@@ -430,7 +425,6 @@ async function loadSettings() {
|
|||||||
$('#sd_restore_faces').prop('checked', extension_settings.sd.restore_faces);
|
$('#sd_restore_faces').prop('checked', extension_settings.sd.restore_faces);
|
||||||
$('#sd_enable_hr').prop('checked', extension_settings.sd.enable_hr);
|
$('#sd_enable_hr').prop('checked', extension_settings.sd.enable_hr);
|
||||||
$('#sd_refine_mode').prop('checked', extension_settings.sd.refine_mode);
|
$('#sd_refine_mode').prop('checked', extension_settings.sd.refine_mode);
|
||||||
$('#sd_expand').prop('checked', extension_settings.sd.expand);
|
|
||||||
$('#sd_multimodal_captioning').prop('checked', extension_settings.sd.multimodal_captioning);
|
$('#sd_multimodal_captioning').prop('checked', extension_settings.sd.multimodal_captioning);
|
||||||
$('#sd_auto_url').val(extension_settings.sd.auto_url);
|
$('#sd_auto_url').val(extension_settings.sd.auto_url);
|
||||||
$('#sd_auto_auth').val(extension_settings.sd.auto_auth);
|
$('#sd_auto_auth').val(extension_settings.sd.auto_auth);
|
||||||
@@ -644,37 +638,13 @@ async function onSaveStyleClick() {
|
|||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function expandPrompt(prompt) {
|
|
||||||
try {
|
|
||||||
const response = await fetch('/api/sd/expand', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: getRequestHeaders(),
|
|
||||||
body: JSON.stringify({ prompt: prompt }),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('API returned an error.');
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
return data.prompt;
|
|
||||||
} catch {
|
|
||||||
return prompt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modifies prompt based on auto-expansion and user inputs.
|
* Modifies prompt based on user inputs.
|
||||||
* @param {string} prompt Prompt to refine
|
* @param {string} prompt Prompt to refine
|
||||||
* @param {boolean} allowExpand Whether to allow auto-expansion
|
|
||||||
* @param {boolean} isNegative Whether the prompt is a negative one
|
* @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, isNegative = false) {
|
async function refinePrompt(prompt, isNegative) {
|
||||||
if (allowExpand && extension_settings.sd.expand) {
|
|
||||||
prompt = await expandPrompt(prompt);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extension_settings.sd.refine_mode) {
|
if (extension_settings.sd.refine_mode) {
|
||||||
const text = isNegative ? '<h3>Review and edit the <i>negative</i> prompt:</h3>' : '<h3>Review and edit the prompt:</h3>';
|
const text = isNegative ? '<h3>Review and edit the <i>negative</i> prompt:</h3>' : '<h3>Review and edit the prompt:</h3>';
|
||||||
const refinedPrompt = await callGenericPopup(text + 'Press "Cancel" to abort the image generation.', POPUP_TYPE.INPUT, prompt.trim(), { rows: 5, okButton: 'Continue' });
|
const refinedPrompt = await callGenericPopup(text + 'Press "Cancel" to abort the image generation.', POPUP_TYPE.INPUT, prompt.trim(), { rows: 5, okButton: 'Continue' });
|
||||||
@@ -800,11 +770,6 @@ function combinePrefixes(str1, str2, macro = '') {
|
|||||||
return process(result);
|
return process(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onExpandInput() {
|
|
||||||
extension_settings.sd.expand = !!$(this).prop('checked');
|
|
||||||
saveSettingsDebounced();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onRefineModeInput() {
|
function onRefineModeInput() {
|
||||||
extension_settings.sd.refine_mode = !!$('#sd_refine_mode').prop('checked');
|
extension_settings.sd.refine_mode = !!$('#sd_refine_mode').prop('checked');
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
@@ -969,12 +934,6 @@ async function onViewAnlasClick() {
|
|||||||
toastr.info(`Free image generation: ${unlimitedGeneration ? 'Yes' : 'No'}`, `Anlas: ${anlas}`);
|
toastr.info(`Free image generation: ${unlimitedGeneration ? 'Yes' : 'No'}`, `Anlas: ${anlas}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onNovelUpscaleRatioInput() {
|
|
||||||
extension_settings.sd.novel_upscale_ratio = Number($('#sd_novel_upscale_ratio').val());
|
|
||||||
$('#sd_novel_upscale_ratio_value').val(extension_settings.sd.novel_upscale_ratio.toFixed(1));
|
|
||||||
saveSettingsDebounced();
|
|
||||||
}
|
|
||||||
|
|
||||||
function onNovelAnlasGuardInput() {
|
function onNovelAnlasGuardInput() {
|
||||||
extension_settings.sd.novel_anlas_guard = !!$('#sd_novel_anlas_guard').prop('checked');
|
extension_settings.sd.novel_anlas_guard = !!$('#sd_novel_anlas_guard').prop('checked');
|
||||||
saveSettingsDebounced();
|
saveSettingsDebounced();
|
||||||
@@ -2272,6 +2231,25 @@ function getRawLastMessage() {
|
|||||||
return `((${processReply(lastMessage.mes)})), (${processReply(character.scenario)}:0.7), (${processReply(character.description)}:0.5)`;
|
return `((${processReply(lastMessage.mes)})), (${processReply(character.scenario)}:0.7), (${processReply(character.description)}:0.5)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure that the selected option exists in the dropdown.
|
||||||
|
* @param {string} setting Setting key
|
||||||
|
* @param {string} selector Dropdown selector
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function ensureSelectionExists(setting, selector) {
|
||||||
|
/** @type {HTMLSelectElement} */
|
||||||
|
const selectElement = document.querySelector(selector);
|
||||||
|
if (!selectElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const options = Array.from(selectElement.options);
|
||||||
|
const value = extension_settings.sd[setting];
|
||||||
|
if (selectElement.selectedOptions.length && !options.some(option => option.value === value)) {
|
||||||
|
extension_settings.sd[setting] = selectElement.selectedOptions[0].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an image based on the given trigger word.
|
* Generates an image based on the given trigger word.
|
||||||
* @param {string} initiator The initiator of the image generation
|
* @param {string} initiator The initiator of the image generation
|
||||||
@@ -2292,8 +2270,8 @@ async function generatePicture(initiator, args, trigger, message, callback) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension_settings.sd.sampler = $('#sd_sampler').find(':selected').val();
|
ensureSelectionExists('sampler', '#sd_sampler');
|
||||||
extension_settings.sd.model = $('#sd_model').find(':selected').val();
|
ensureSelectionExists('model', '#sd_model');
|
||||||
|
|
||||||
trigger = trigger.trim();
|
trigger = trigger.trim();
|
||||||
const generationType = getGenerationType(trigger);
|
const generationType = getGenerationType(trigger);
|
||||||
@@ -2441,7 +2419,7 @@ async function getPrompt(generationType, message, trigger, quietPrompt, combineN
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (generationType !== generationMode.FREE) {
|
if (generationType !== generationMode.FREE) {
|
||||||
prompt = await refinePrompt(prompt, true);
|
prompt = await refinePrompt(prompt, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return prompt;
|
return prompt;
|
||||||
@@ -2469,7 +2447,7 @@ function generateFreeModePrompt(trigger, combineNegatives) {
|
|||||||
return message.original_avatar.replace(/\.[^/.]+$/, '');
|
return message.original_avatar.replace(/\.[^/.]+$/, '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error('No usable messages found.');
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
const key = getLastCharacterKey();
|
const key = getLastCharacterKey();
|
||||||
@@ -3031,7 +3009,7 @@ async function generateNovelImage(prompt, negativePrompt, signal) {
|
|||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
negative_prompt: negativePrompt,
|
negative_prompt: negativePrompt,
|
||||||
upscale_ratio: extension_settings.sd.novel_upscale_ratio,
|
upscale_ratio: extension_settings.sd.hr_scale,
|
||||||
decrisper: extension_settings.sd.novel_decrisper,
|
decrisper: extension_settings.sd.novel_decrisper,
|
||||||
sm: sm,
|
sm: sm,
|
||||||
sm_dyn: sm_dyn,
|
sm_dyn: sm_dyn,
|
||||||
@@ -3613,8 +3591,8 @@ async function sdMessageButton(e) {
|
|||||||
try {
|
try {
|
||||||
setBusyIcon(true);
|
setBusyIcon(true);
|
||||||
if (hasSavedImage) {
|
if (hasSavedImage) {
|
||||||
const prompt = await refinePrompt(message.extra.title, false, false);
|
const prompt = await refinePrompt(message.extra.title, false);
|
||||||
const negative = hasSavedNegative ? await refinePrompt(message.extra.negative, false, true) : '';
|
const negative = hasSavedNegative ? await refinePrompt(message.extra.negative, true) : '';
|
||||||
message.extra.title = prompt;
|
message.extra.title = prompt;
|
||||||
|
|
||||||
const generationType = message?.extra?.generationType ?? generationMode.FREE;
|
const generationType = message?.extra?.generationType ?? generationMode.FREE;
|
||||||
@@ -3756,8 +3734,8 @@ async function onImageSwiped({ message, element, direction }) {
|
|||||||
eventSource.once(CUSTOM_STOP_EVENT, stopListener);
|
eventSource.once(CUSTOM_STOP_EVENT, stopListener);
|
||||||
const callback = () => { };
|
const callback = () => { };
|
||||||
const hasNegative = message.extra.negative;
|
const hasNegative = message.extra.negative;
|
||||||
const prompt = await refinePrompt(message.extra.title, false, false);
|
const prompt = await refinePrompt(message.extra.title, false);
|
||||||
const negativePromptPrefix = hasNegative ? await refinePrompt(message.extra.negative, false, true) : '';
|
const negativePromptPrefix = hasNegative ? await refinePrompt(message.extra.negative, true) : '';
|
||||||
const characterName = context.groupId
|
const characterName = context.groupId
|
||||||
? context.groups[Object.keys(context.groups).filter(x => context.groups[x].id === context.groupId)[0]]?.id?.toString()
|
? context.groups[Object.keys(context.groups).filter(x => context.groups[x].id === context.groupId)[0]]?.id?.toString()
|
||||||
: context.characters[context.characterId]?.name;
|
: context.characters[context.characterId]?.name;
|
||||||
@@ -3788,12 +3766,85 @@ async function onImageSwiped({ message, element, direction }) {
|
|||||||
await context.saveChat();
|
await context.saveChat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies the command arguments to the extension settings.
|
||||||
|
* @typedef {import('../../slash-commands/SlashCommand.js').NamedArguments} NamedArguments
|
||||||
|
* @typedef {import('../../slash-commands/SlashCommand.js').NamedArgumentsCapture} NamedArgumentsCapture
|
||||||
|
* @param {NamedArguments | NamedArgumentsCapture} args - Command arguments
|
||||||
|
* @returns {Record<string, any>} - Current settings before applying the command arguments
|
||||||
|
*/
|
||||||
|
function applyCommandArguments(args) {
|
||||||
|
const overrideSettings = {};
|
||||||
|
const currentSettings = {};
|
||||||
|
const settingMap = {
|
||||||
|
'edit': 'refine_mode',
|
||||||
|
'extend': 'free_extend',
|
||||||
|
'multimodal': 'multimodal_captioning',
|
||||||
|
'seed': 'seed',
|
||||||
|
'width': 'width',
|
||||||
|
'height': 'height',
|
||||||
|
'steps': 'steps',
|
||||||
|
'cfg': 'scale',
|
||||||
|
'skip': 'clip_skip',
|
||||||
|
'model': 'model',
|
||||||
|
'sampler': 'sampler',
|
||||||
|
'scheduler': 'scheduler',
|
||||||
|
'vae': 'vae',
|
||||||
|
'upscaler': 'hr_upscaler',
|
||||||
|
'scale': 'hr_scale',
|
||||||
|
'hires': 'enable_hr',
|
||||||
|
'denoise': 'denoising_strength',
|
||||||
|
'2ndpass': 'hr_second_pass_steps',
|
||||||
|
'faces': 'restore_faces',
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [param, setting] of Object.entries(settingMap)) {
|
||||||
|
if (args[param] === undefined || defaultSettings[setting] === undefined) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
currentSettings[setting] = extension_settings.sd[setting];
|
||||||
|
const value = String(args[param]);
|
||||||
|
const type = typeof defaultSettings[setting];
|
||||||
|
switch (type) {
|
||||||
|
case 'boolean':
|
||||||
|
overrideSettings[setting] = isTrueBoolean(value) || !isFalseBoolean(value);
|
||||||
|
break;
|
||||||
|
case 'number':
|
||||||
|
overrideSettings[setting] = Number(value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
overrideSettings[setting] = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(extension_settings.sd, overrideSettings);
|
||||||
|
return currentSettings;
|
||||||
|
}
|
||||||
|
|
||||||
jQuery(async () => {
|
jQuery(async () => {
|
||||||
await addSDGenButtons();
|
await addSDGenButtons();
|
||||||
|
|
||||||
|
const getSelectEnumProvider = (id, text) => () => Array.from(document.querySelectorAll(`#${id} > [value]`)).map(x => new SlashCommandEnumValue(x.getAttribute('value'), text ? x.textContent : null));
|
||||||
|
|
||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
name: 'imagine',
|
name: 'imagine',
|
||||||
callback: (args, trigger) => generatePicture(initiators.command, args, String(trigger)),
|
returns: 'URL of the generated image, or an empty string if the generation failed',
|
||||||
|
callback: async (args, trigger) => {
|
||||||
|
const currentSettings = applyCommandArguments(args);
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await generatePicture(initiators.command, args, String(trigger));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to generate image:', error);
|
||||||
|
return '';
|
||||||
|
} finally {
|
||||||
|
if (Object.keys(currentSettings).length) {
|
||||||
|
Object.assign(extension_settings.sd, currentSettings);
|
||||||
|
saveSettingsDebounced();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
aliases: ['sd', 'img', 'image'],
|
aliases: ['sd', 'img', 'image'],
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
new SlashCommandNamedArgument(
|
new SlashCommandNamedArgument(
|
||||||
@@ -3803,6 +3854,164 @@ jQuery(async () => {
|
|||||||
name: 'negative',
|
name: 'negative',
|
||||||
description: 'negative prompt prefix',
|
description: 'negative prompt prefix',
|
||||||
typeList: [ARGUMENT_TYPE.STRING],
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
isRequired: false,
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'extend',
|
||||||
|
description: 'auto-extend free mode prompts with the LLM',
|
||||||
|
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||||
|
enumProvider: commonEnumProviders.boolean('trueFalse'),
|
||||||
|
isRequired: false,
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'edit',
|
||||||
|
description: 'edit the prompt before generation',
|
||||||
|
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||||
|
enumProvider: commonEnumProviders.boolean('trueFalse'),
|
||||||
|
isRequired: false,
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'multimodal',
|
||||||
|
description: 'use multimodal captioning (for portraits only)',
|
||||||
|
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||||
|
enumProvider: commonEnumProviders.boolean('trueFalse'),
|
||||||
|
isRequired: false,
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'snap',
|
||||||
|
description: 'snap auto-adjusted dimensions to the nearest known resolution (portraits and backgrounds only)',
|
||||||
|
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||||
|
enumProvider: commonEnumProviders.boolean('trueFalse'),
|
||||||
|
isRequired: false,
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'seed',
|
||||||
|
description: 'random seed',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'width',
|
||||||
|
description: 'image width',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'height',
|
||||||
|
description: 'image height',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'steps',
|
||||||
|
description: 'number of steps',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'cfg',
|
||||||
|
description: 'CFG scale',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'skip',
|
||||||
|
description: 'CLIP skip layers',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'model',
|
||||||
|
description: 'model override',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
forceEnum: true,
|
||||||
|
enumProvider: getSelectEnumProvider('sd_model', true),
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'sampler',
|
||||||
|
description: 'sampler override',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
forceEnum: true,
|
||||||
|
enumProvider: getSelectEnumProvider('sd_sampler', false),
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'scheduler',
|
||||||
|
description: 'scheduler override',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
forceEnum: true,
|
||||||
|
enumProvider: getSelectEnumProvider('sd_scheduler', false),
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'vae',
|
||||||
|
description: 'VAE name override',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
forceEnum: true,
|
||||||
|
enumProvider: getSelectEnumProvider('sd_vae', false),
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'upscaler',
|
||||||
|
description: 'upscaler override',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
forceEnum: true,
|
||||||
|
enumProvider: getSelectEnumProvider('sd_hr_upscaler', false),
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'hires',
|
||||||
|
description: 'enable high-res fix',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
enumProvider: commonEnumProviders.boolean('trueFalse'),
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'scale',
|
||||||
|
description: 'upscale amount',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'denoise',
|
||||||
|
description: 'denoising strength',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: '2ndpass',
|
||||||
|
description: 'second pass steps',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'faces',
|
||||||
|
description: 'restore faces',
|
||||||
|
isRequired: false,
|
||||||
|
typeList: [ARGUMENT_TYPE.BOOLEAN],
|
||||||
|
acceptsMultiple: false,
|
||||||
|
enumProvider: commonEnumProviders.boolean('trueFalse'),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
@@ -3823,6 +4032,66 @@ jQuery(async () => {
|
|||||||
`,
|
`,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
|
name: 'imagine-source',
|
||||||
|
aliases: ['sd-source', 'img-source'],
|
||||||
|
returns: 'a name of the current generation source',
|
||||||
|
unnamedArgumentList: [
|
||||||
|
SlashCommandArgument.fromProps({
|
||||||
|
description: 'source name',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
isRequired: false,
|
||||||
|
forceEnum: true,
|
||||||
|
enumProvider: getSelectEnumProvider('sd_source', true),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
helpString: 'If an argument is provided, change the source of the image generation, e.g. <code>/imagine-source comfy</code>. Returns the current source.',
|
||||||
|
callback: async (_args, name) => {
|
||||||
|
if (!name) {
|
||||||
|
return extension_settings.sd.source;
|
||||||
|
}
|
||||||
|
const isKnownSource = Object.keys(sources).includes(String(name));
|
||||||
|
if (!isKnownSource) {
|
||||||
|
throw new Error('The value provided is not a valid image generation source.');
|
||||||
|
}
|
||||||
|
const option = document.querySelector(`#sd_source [value="${name}"]`);
|
||||||
|
if (!(option instanceof HTMLOptionElement)) {
|
||||||
|
throw new Error('Could not find the source option in the dropdown.');
|
||||||
|
}
|
||||||
|
option.selected = true;
|
||||||
|
await onSourceChange();
|
||||||
|
return extension_settings.sd.source;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
|
name: 'imagine-style',
|
||||||
|
aliases: ['sd-style', 'img-style'],
|
||||||
|
returns: 'a name of the current style',
|
||||||
|
unnamedArgumentList: [
|
||||||
|
SlashCommandArgument.fromProps({
|
||||||
|
description: 'style name',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
isRequired: false,
|
||||||
|
forceEnum: true,
|
||||||
|
enumProvider: getSelectEnumProvider('sd_style', false),
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
helpString: 'If an argument is provided, change the style of the image generation, e.g. <code>/imagine-style MyStyle</code>. Returns the current style.',
|
||||||
|
callback: async (_args, name) => {
|
||||||
|
if (!name) {
|
||||||
|
return extension_settings.sd.style;
|
||||||
|
}
|
||||||
|
const option = document.querySelector(`#sd_style [value="${name}"]`);
|
||||||
|
if (!(option instanceof HTMLOptionElement)) {
|
||||||
|
throw new Error('Could not find the style option in the dropdown.');
|
||||||
|
}
|
||||||
|
option.selected = true;
|
||||||
|
onStyleSelect();
|
||||||
|
return extension_settings.sd.style;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
name: 'imagine-comfy-workflow',
|
name: 'imagine-comfy-workflow',
|
||||||
callback: changeComfyWorkflow,
|
callback: changeComfyWorkflow,
|
||||||
@@ -3832,7 +4101,7 @@ jQuery(async () => {
|
|||||||
description: 'workflow name',
|
description: 'workflow name',
|
||||||
typeList: [ARGUMENT_TYPE.STRING],
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: () => Array.from(document.querySelectorAll('#sd_comfy_workflow > [value]')).map(x => x.getAttribute('value')).map(workflow => new SlashCommandEnumValue(workflow)),
|
enumProvider: getSelectEnumProvider('sd_comfy_workflow', false),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
helpString: '(workflowName) - change the workflow to be used for image generation with ComfyUI, e.g. <pre><code>/imagine-comfy-workflow MyWorkflow</code></pre>',
|
helpString: '(workflowName) - change the workflow to be used for image generation with ComfyUI, e.g. <pre><code>/imagine-comfy-workflow MyWorkflow</code></pre>',
|
||||||
@@ -3874,7 +4143,6 @@ jQuery(async () => {
|
|||||||
$('#sd_hr_scale').on('input', onHrScaleInput);
|
$('#sd_hr_scale').on('input', onHrScaleInput);
|
||||||
$('#sd_denoising_strength').on('input', onDenoisingStrengthInput);
|
$('#sd_denoising_strength').on('input', onDenoisingStrengthInput);
|
||||||
$('#sd_hr_second_pass_steps').on('input', onHrSecondPassStepsInput);
|
$('#sd_hr_second_pass_steps').on('input', onHrSecondPassStepsInput);
|
||||||
$('#sd_novel_upscale_ratio').on('input', onNovelUpscaleRatioInput);
|
|
||||||
$('#sd_novel_anlas_guard').on('input', onNovelAnlasGuardInput);
|
$('#sd_novel_anlas_guard').on('input', onNovelAnlasGuardInput);
|
||||||
$('#sd_novel_view_anlas').on('click', onViewAnlasClick);
|
$('#sd_novel_view_anlas').on('click', onViewAnlasClick);
|
||||||
$('#sd_novel_sm').on('input', onNovelSmInput);
|
$('#sd_novel_sm').on('input', onNovelSmInput);
|
||||||
@@ -3887,7 +4155,6 @@ jQuery(async () => {
|
|||||||
$('#sd_comfy_open_workflow_editor').on('click', onComfyOpenWorkflowEditorClick);
|
$('#sd_comfy_open_workflow_editor').on('click', onComfyOpenWorkflowEditorClick);
|
||||||
$('#sd_comfy_new_workflow').on('click', onComfyNewWorkflowClick);
|
$('#sd_comfy_new_workflow').on('click', onComfyNewWorkflowClick);
|
||||||
$('#sd_comfy_delete_workflow').on('click', onComfyDeleteWorkflowClick);
|
$('#sd_comfy_delete_workflow').on('click', onComfyDeleteWorkflowClick);
|
||||||
$('#sd_expand').on('input', onExpandInput);
|
|
||||||
$('#sd_style').on('change', onStyleSelect);
|
$('#sd_style').on('change', onStyleSelect);
|
||||||
$('#sd_save_style').on('click', onSaveStyleClick);
|
$('#sd_save_style').on('click', onSaveStyleClick);
|
||||||
$('#sd_delete_style').on('click', onDeleteStyleClick);
|
$('#sd_delete_style').on('click', onDeleteStyleClick);
|
||||||
|
@@ -27,11 +27,6 @@
|
|||||||
<span data-i18n="sd_free_extend_txt">Extend free mode prompts</span>
|
<span data-i18n="sd_free_extend_txt">Extend free mode prompts</span>
|
||||||
<small data-i18n="sd_free_extend_small">(interactive/commands)</small>
|
<small data-i18n="sd_free_extend_small">(interactive/commands)</small>
|
||||||
</label>
|
</label>
|
||||||
<label for="sd_expand" class="checkbox_label" data-i18n="[title]sd_expand" title="Automatically extend prompts using text generation model">
|
|
||||||
<input id="sd_expand" type="checkbox" />
|
|
||||||
<span data-i18n="sd_expand_txt">Auto-extend prompts</span>
|
|
||||||
<span class="right_menu_button fa-solid fa-triangle-exclamation" data-i18n="[title]sd_expand_warning" title="May produce unexpected results. Manual prompt editing is recommended."></span>
|
|
||||||
</label>
|
|
||||||
<label for="sd_snap" class="checkbox_label" data-i18n="[title]sd_snap" title="Snap generation requests with a forced aspect ratio (portraits, backgrounds) to the nearest known resolution, while trying to preserve the absolute pixel counts (recommended for SDXL).">
|
<label for="sd_snap" class="checkbox_label" data-i18n="[title]sd_snap" title="Snap generation requests with a forced aspect ratio (portraits, backgrounds) to the nearest known resolution, while trying to preserve the absolute pixel counts (recommended for SDXL).">
|
||||||
<input id="sd_snap" type="checkbox" />
|
<input id="sd_snap" type="checkbox" />
|
||||||
<span data-i18n="sd_snap_txt">Snap auto-adjusted resolutions</span>
|
<span data-i18n="sd_snap_txt">Snap auto-adjusted resolutions</span>
|
||||||
@@ -308,7 +303,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex-container">
|
<div class="flex-container">
|
||||||
<div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" data-sd-source="auto,vlad,drawthings">
|
<div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" data-sd-source="auto,vlad,drawthings,novel">
|
||||||
<small>
|
<small>
|
||||||
<span data-i18n="Upscale by">Upscale by</span>
|
<span data-i18n="Upscale by">Upscale by</span>
|
||||||
</small>
|
</small>
|
||||||
@@ -332,14 +327,6 @@
|
|||||||
<input class="neo-range-input" type="number" id="sd_hr_second_pass_steps_value" data-for="sd_hr_second_pass_steps" max="{{hr_second_pass_steps_max}}" step="{{hr_second_pass_steps_step}}" value="{{hr_second_pass_steps}}" >
|
<input class="neo-range-input" type="number" id="sd_hr_second_pass_steps_value" data-for="sd_hr_second_pass_steps" max="{{hr_second_pass_steps_max}}" step="{{hr_second_pass_steps_step}}" value="{{hr_second_pass_steps}}" >
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" data-sd-source="novel">
|
|
||||||
<small>
|
|
||||||
<span data-i18n="Upscale by">Upscale by</span>
|
|
||||||
</small>
|
|
||||||
<input class="neo-range-slider" type="range" id="sd_novel_upscale_ratio" name="sd_novel_upscale_ratio" min="{{novel_upscale_ratio_min}}" max="{{novel_upscale_ratio_max}}" step="{{novel_upscale_ratio_step}}" value="{{novel_upscale_ratio}}" >
|
|
||||||
<input class="neo-range-input" type="number" id="sd_novel_upscale_ratio_value" data-for="sd_novel_upscale_ratio" min="{{novel_upscale_ratio_min}}" max="{{novel_upscale_ratio_max}}" step="{{novel_upscale_ratio_step}}" value="{{novel_upscale_ratio}}" >
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" data-sd-source="auto,vlad,comfy,horde,drawthings,extras">
|
<div class="alignitemscenter flex-container flexFlowColumn flexGrow flexShrink gap0 flexBasis48p" data-sd-source="auto,vlad,comfy,horde,drawthings,extras">
|
||||||
<small>
|
<small>
|
||||||
<span data-i18n="CLIP Skip">CLIP Skip</span>
|
<span data-i18n="CLIP Skip">CLIP Skip</span>
|
||||||
|
@@ -384,6 +384,10 @@ export function formatInstructModeChat(name, mes, isUser, isNarrator, forceAvata
|
|||||||
* @returns {string} Formatted instruct mode system prompt.
|
* @returns {string} Formatted instruct mode system prompt.
|
||||||
*/
|
*/
|
||||||
export function formatInstructModeSystemPrompt(systemPrompt) {
|
export function formatInstructModeSystemPrompt(systemPrompt) {
|
||||||
|
if (!systemPrompt) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
const separator = power_user.instruct.wrap ? '\n' : '';
|
const separator = power_user.instruct.wrap ? '\n' : '';
|
||||||
|
|
||||||
if (power_user.instruct.system_sequence_prefix) {
|
if (power_user.instruct.system_sequence_prefix) {
|
||||||
|
@@ -70,6 +70,7 @@ import { POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
|
|||||||
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||||
import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakController.js';
|
import { SlashCommandBreakController } from './slash-commands/SlashCommandBreakController.js';
|
||||||
import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js';
|
import { SlashCommandExecutionError } from './slash-commands/SlashCommandExecutionError.js';
|
||||||
|
import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js';
|
||||||
export {
|
export {
|
||||||
executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,
|
executeSlashCommands, executeSlashCommandsWithOptions, getSlashCommandsHelp, registerSlashCommand,
|
||||||
};
|
};
|
||||||
@@ -242,6 +243,7 @@ export function initDefaultSlashCommands() {
|
|||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
name: 'sendas',
|
name: 'sendas',
|
||||||
callback: sendMessageAs,
|
callback: sendMessageAs,
|
||||||
|
returns: 'Optionally the text of the sent message, if specified in the "return" argument',
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'name',
|
name: 'name',
|
||||||
@@ -269,6 +271,14 @@ export function initDefaultSlashCommands() {
|
|||||||
typeList: [ARGUMENT_TYPE.NUMBER],
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
||||||
}),
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'return',
|
||||||
|
description: 'The way how you want the return value to be provided',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
defaultValue: 'none',
|
||||||
|
enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
|
||||||
|
forceEnum: true,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument(
|
new SlashCommandArgument(
|
||||||
@@ -301,6 +311,7 @@ export function initDefaultSlashCommands() {
|
|||||||
name: 'sys',
|
name: 'sys',
|
||||||
callback: sendNarratorMessage,
|
callback: sendNarratorMessage,
|
||||||
aliases: ['nar'],
|
aliases: ['nar'],
|
||||||
|
returns: 'Optionally the text of the sent message, if specified in the "return" argument',
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
new SlashCommandNamedArgument(
|
new SlashCommandNamedArgument(
|
||||||
'compact',
|
'compact',
|
||||||
@@ -316,6 +327,14 @@ export function initDefaultSlashCommands() {
|
|||||||
typeList: [ARGUMENT_TYPE.NUMBER],
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
||||||
}),
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'return',
|
||||||
|
description: 'The way how you want the return value to be provided',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
defaultValue: 'none',
|
||||||
|
enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
|
||||||
|
forceEnum: true,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument(
|
new SlashCommandArgument(
|
||||||
@@ -355,6 +374,7 @@ export function initDefaultSlashCommands() {
|
|||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
name: 'comment',
|
name: 'comment',
|
||||||
callback: sendCommentMessage,
|
callback: sendCommentMessage,
|
||||||
|
returns: 'Optionally the text of the sent message, if specified in the "return" argument',
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
new SlashCommandNamedArgument(
|
new SlashCommandNamedArgument(
|
||||||
'compact',
|
'compact',
|
||||||
@@ -370,6 +390,14 @@ export function initDefaultSlashCommands() {
|
|||||||
typeList: [ARGUMENT_TYPE.NUMBER],
|
typeList: [ARGUMENT_TYPE.NUMBER],
|
||||||
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
enumProvider: commonEnumProviders.messages({ allowIdAfter: true }),
|
||||||
}),
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'return',
|
||||||
|
description: 'The way how you want the return value to be provided',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
defaultValue: 'none',
|
||||||
|
enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
|
||||||
|
forceEnum: true,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument(
|
new SlashCommandArgument(
|
||||||
@@ -509,7 +537,7 @@ export function initDefaultSlashCommands() {
|
|||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
name: 'ask',
|
name: 'ask',
|
||||||
callback: askCharacter,
|
callback: askCharacter,
|
||||||
returns: 'the generated text',
|
returns: 'Optionally the text of the sent message, if specified in the "return" argument',
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'name',
|
name: 'name',
|
||||||
@@ -518,6 +546,14 @@ export function initDefaultSlashCommands() {
|
|||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.characters('character'),
|
enumProvider: commonEnumProviders.characters('character'),
|
||||||
}),
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'return',
|
||||||
|
description: 'The way how you want the return value to be provided',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
defaultValue: 'pipe',
|
||||||
|
enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
|
||||||
|
forceEnum: true,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument(
|
new SlashCommandArgument(
|
||||||
@@ -556,6 +592,7 @@ export function initDefaultSlashCommands() {
|
|||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
name: 'send',
|
name: 'send',
|
||||||
callback: sendUserMessageCallback,
|
callback: sendUserMessageCallback,
|
||||||
|
returns: 'Optionally the text of the sent message, if specified in the "return" argument',
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
new SlashCommandNamedArgument(
|
new SlashCommandNamedArgument(
|
||||||
'compact',
|
'compact',
|
||||||
@@ -578,6 +615,14 @@ export function initDefaultSlashCommands() {
|
|||||||
defaultValue: '{{user}}',
|
defaultValue: '{{user}}',
|
||||||
enumProvider: commonEnumProviders.personas,
|
enumProvider: commonEnumProviders.personas,
|
||||||
}),
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'return',
|
||||||
|
description: 'The way how you want the return value to be provided',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
defaultValue: 'none',
|
||||||
|
enumList: slashCommandReturnHelper.enumList({ allowObject: true }),
|
||||||
|
forceEnum: true,
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
new SlashCommandArgument(
|
new SlashCommandArgument(
|
||||||
@@ -1568,12 +1613,21 @@ export function initDefaultSlashCommands() {
|
|||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
name: 'listinjects',
|
name: 'listinjects',
|
||||||
callback: listInjectsCallback,
|
callback: listInjectsCallback,
|
||||||
helpString: 'Lists all script injections for the current chat. Displays injects in a popup by default. Use the <code>format</code> argument to change the output format.',
|
helpString: 'Lists all script injections for the current chat. Displays injects in a popup by default. Use the <code>return</code> argument to change the return type.',
|
||||||
returns: 'JSON object of script injections',
|
returns: 'Optionalls the JSON object of script injections',
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'return',
|
||||||
|
description: 'The way how you want the return value to be provided',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
defaultValue: 'popup-html',
|
||||||
|
enumList: slashCommandReturnHelper.enumList({ allowPipe: false, allowObject: true, allowChat: true, allowPopup: true, allowTextVersion: false }),
|
||||||
|
forceEnum: true,
|
||||||
|
}),
|
||||||
|
// TODO remove some day
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'format',
|
name: 'format',
|
||||||
description: 'output format',
|
description: '!!! DEPRECATED - use "return" instead !!! output format',
|
||||||
typeList: [ARGUMENT_TYPE.STRING],
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
forceEnum: true,
|
forceEnum: true,
|
||||||
@@ -1842,37 +1896,43 @@ function injectCallback(args, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function listInjectsCallback(args) {
|
async function listInjectsCallback(args) {
|
||||||
|
/** @type {import('./slash-commands/SlashCommandReturnHelper.js').SlashCommandReturnType} */
|
||||||
|
let returnType = args.return;
|
||||||
|
|
||||||
|
// Old legacy return type handling
|
||||||
|
if (args.format) {
|
||||||
|
toastr.warning(`Legacy argument 'format' with value '${args.format}' is deprecated. Please use 'return' instead. Routing to the correct return type...`, 'Deprecation warning');
|
||||||
const type = String(args?.format).toLowerCase().trim();
|
const type = String(args?.format).toLowerCase().trim();
|
||||||
if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) {
|
if (!chat_metadata.script_injects || !Object.keys(chat_metadata.script_injects).length) {
|
||||||
type !== 'none' && toastr.info('No script injections for the current chat');
|
type !== 'none' && toastr.info('No script injections for the current chat');
|
||||||
return JSON.stringify({});
|
}
|
||||||
|
switch (type) {
|
||||||
|
case 'none':
|
||||||
|
returnType = 'none';
|
||||||
|
break;
|
||||||
|
case 'chat':
|
||||||
|
returnType = 'chat-html';
|
||||||
|
break;
|
||||||
|
case 'popup':
|
||||||
|
default:
|
||||||
|
returnType = 'popup-html';
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const injects = Object.entries(chat_metadata.script_injects)
|
// Now the actual new return type handling
|
||||||
|
const buildTextValue = (injects) => {
|
||||||
|
const injectsStr = Object.entries(injects)
|
||||||
.map(([id, inject]) => {
|
.map(([id, inject]) => {
|
||||||
const position = Object.entries(extension_prompt_types);
|
const position = Object.entries(extension_prompt_types);
|
||||||
const positionName = position.find(([_, value]) => value === inject.position)?.[0] ?? 'unknown';
|
const positionName = position.find(([_, value]) => value === inject.position)?.[0] ?? 'unknown';
|
||||||
return `* **${id}**: <code>${inject.value}</code> (${positionName}, depth: ${inject.depth}, scan: ${inject.scan ?? false}, role: ${inject.role ?? extension_prompt_roles.SYSTEM})`;
|
return `* **${id}**: <code>${inject.value}</code> (${positionName}, depth: ${inject.depth}, scan: ${inject.scan ?? false}, role: ${inject.role ?? extension_prompt_roles.SYSTEM})`;
|
||||||
})
|
})
|
||||||
.join('\n');
|
.join('\n');
|
||||||
|
return `### Script injections:\n${injectsStr || 'No script injections for the current chat'}`;
|
||||||
|
};
|
||||||
|
|
||||||
const converter = new showdown.Converter();
|
return await slashCommandReturnHelper.doReturn(returnType ?? 'popup-html', chat_metadata.script_injects ?? {}, { objectToStringFunc: buildTextValue });
|
||||||
const messageText = `### Script injections:\n${injects}`;
|
|
||||||
const htmlMessage = DOMPurify.sanitize(converter.makeHtml(messageText));
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 'none':
|
|
||||||
break;
|
|
||||||
case 'chat':
|
|
||||||
sendSystemMessage(system_message_types.GENERIC, htmlMessage);
|
|
||||||
break;
|
|
||||||
case 'popup':
|
|
||||||
default:
|
|
||||||
await callGenericPopup(htmlMessage, POPUP_TYPE.TEXT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.stringify(chat_metadata.script_injects);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2559,7 +2619,7 @@ async function askCharacter(args, text) {
|
|||||||
// Not supported in group chats
|
// Not supported in group chats
|
||||||
// TODO: Maybe support group chats?
|
// TODO: Maybe support group chats?
|
||||||
if (selected_group) {
|
if (selected_group) {
|
||||||
toastr.error('Cannot run /ask command in a group chat!');
|
toastr.warning('Cannot run /ask command in a group chat!');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2633,7 +2693,9 @@ async function askCharacter(args, text) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return askResult;
|
const message = askResult ? chat[chat.length - 1] : null;
|
||||||
|
|
||||||
|
return await slashCommandReturnHelper.doReturn(args.return ?? 'pipe', message, { objectToStringFunc: x => x.mes });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function hideMessageCallback(_, arg) {
|
async function hideMessageCallback(_, arg) {
|
||||||
@@ -2908,7 +2970,7 @@ function findPersonaByName(name) {
|
|||||||
|
|
||||||
async function sendUserMessageCallback(args, text) {
|
async function sendUserMessageCallback(args, text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
console.warn('WARN: No text provided for /send command');
|
toastr.warning('You must specify text to send');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2924,16 +2986,17 @@ async function sendUserMessageCallback(args, text) {
|
|||||||
insertAt = chat.length + insertAt;
|
insertAt = chat.length + insertAt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let message;
|
||||||
if ('name' in args) {
|
if ('name' in args) {
|
||||||
const name = args.name || '';
|
const name = args.name || '';
|
||||||
const avatar = findPersonaByName(name) || user_avatar;
|
const avatar = findPersonaByName(name) || user_avatar;
|
||||||
await sendMessageAsUser(text, bias, insertAt, compact, name, avatar);
|
message = await sendMessageAsUser(text, bias, insertAt, compact, name, avatar);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
await sendMessageAsUser(text, bias, insertAt, compact);
|
message = await sendMessageAsUser(text, bias, insertAt, compact);
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return await slashCommandReturnHelper.doReturn(args.return ?? 'none', message, { objectToStringFunc: x => x.mes });
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteMessagesByNameCallback(_, name) {
|
async function deleteMessagesByNameCallback(_, name) {
|
||||||
@@ -3027,7 +3090,7 @@ async function continueChatCallback(args, prompt) {
|
|||||||
resolve();
|
resolve();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error running /continue command:', error);
|
console.error('Error running /continue command:', error);
|
||||||
reject();
|
reject(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -3221,30 +3284,20 @@ export function getNameAndAvatarForMessage(character, name = null) {
|
|||||||
|
|
||||||
export async function sendMessageAs(args, text) {
|
export async function sendMessageAs(args, text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
|
toastr.warning('You must specify text to send as');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let name;
|
let name = args.name?.trim();
|
||||||
let mesText;
|
let mesText;
|
||||||
|
|
||||||
if (args.name) {
|
if (!name) {
|
||||||
name = args.name.trim();
|
|
||||||
|
|
||||||
if (!name && !text) {
|
|
||||||
toastr.warning('You must specify a name and text to send as');
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const namelessWarningKey = 'sendAsNamelessWarningShown';
|
const namelessWarningKey = 'sendAsNamelessWarningShown';
|
||||||
if (localStorage.getItem(namelessWarningKey) !== 'true') {
|
if (localStorage.getItem(namelessWarningKey) !== 'true') {
|
||||||
toastr.warning('To avoid confusion, please use /sendas name="Character Name"', 'Name defaulted to {{char}}', { timeOut: 10000 });
|
toastr.warning('To avoid confusion, please use /sendas name="Character Name"', 'Name defaulted to {{char}}', { timeOut: 10000 });
|
||||||
localStorage.setItem(namelessWarningKey, 'true');
|
localStorage.setItem(namelessWarningKey, 'true');
|
||||||
}
|
}
|
||||||
name = name2;
|
name = name2;
|
||||||
if (!text) {
|
|
||||||
toastr.warning('You must specify text to send as');
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mesText = text.trim();
|
mesText = text.trim();
|
||||||
@@ -3321,11 +3374,12 @@ export async function sendMessageAs(args, text) {
|
|||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return await slashCommandReturnHelper.doReturn(args.return ?? 'none', message, { objectToStringFunc: x => x.mes });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendNarratorMessage(args, text) {
|
export async function sendNarratorMessage(args, text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
|
toastr.warning('You must specify text to send');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3374,7 +3428,7 @@ export async function sendNarratorMessage(args, text) {
|
|||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return await slashCommandReturnHelper.doReturn(args.return ?? 'none', message, { objectToStringFunc: x => x.mes });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function promptQuietForLoudResponse(who, text) {
|
export async function promptQuietForLoudResponse(who, text) {
|
||||||
@@ -3420,6 +3474,7 @@ export async function promptQuietForLoudResponse(who, text) {
|
|||||||
|
|
||||||
async function sendCommentMessage(args, text) {
|
async function sendCommentMessage(args, text) {
|
||||||
if (!text) {
|
if (!text) {
|
||||||
|
toastr.warning('You must specify text to send');
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3462,7 +3517,7 @@ async function sendCommentMessage(args, text) {
|
|||||||
await saveChatConditional();
|
await saveChatConditional();
|
||||||
}
|
}
|
||||||
|
|
||||||
return '';
|
return await slashCommandReturnHelper.doReturn(args.return ?? 'none', message, { objectToStringFunc: x => x.mes });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -508,6 +508,14 @@ export class SlashCommandClosure {
|
|||||||
return v;
|
return v;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
value ??= '';
|
||||||
|
|
||||||
|
// Make sure that if unnamed args are split, it should always return an array
|
||||||
|
if (executor.command.splitUnnamedArgument && !Array.isArray(value)) {
|
||||||
|
value = [value];
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -36,6 +36,7 @@ export const enumIcons = {
|
|||||||
message: '💬',
|
message: '💬',
|
||||||
voice: '🎤',
|
voice: '🎤',
|
||||||
server: '🖥️',
|
server: '🖥️',
|
||||||
|
popup: '🗔',
|
||||||
|
|
||||||
true: '✔️',
|
true: '✔️',
|
||||||
false: '❌',
|
false: '❌',
|
||||||
@@ -152,6 +153,35 @@ export const commonEnumProviders = {
|
|||||||
].filter((item, idx, list)=>idx == list.findIndex(it=>it.value == item.value));
|
].filter((item, idx, list)=>idx == list.findIndex(it=>it.value == item.value));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enum values for numbers and variable names
|
||||||
|
*
|
||||||
|
* Includes all variable names and the ability to specify any number
|
||||||
|
*
|
||||||
|
* @param {SlashCommandExecutor} executor - The executor of the slash command
|
||||||
|
* @param {SlashCommandScope} scope - The scope of the slash command
|
||||||
|
* @returns {SlashCommandEnumValue[]} The enum values
|
||||||
|
*/
|
||||||
|
numbersAndVariables: (executor, scope) => [
|
||||||
|
...commonEnumProviders.variables('all')(executor, scope),
|
||||||
|
new SlashCommandEnumValue(
|
||||||
|
'any variable name',
|
||||||
|
null,
|
||||||
|
enumTypes.variable,
|
||||||
|
enumIcons.variable,
|
||||||
|
(input) => /^\w*$/.test(input),
|
||||||
|
(input) => input,
|
||||||
|
),
|
||||||
|
new SlashCommandEnumValue(
|
||||||
|
'any number',
|
||||||
|
null,
|
||||||
|
enumTypes.number,
|
||||||
|
enumIcons.number,
|
||||||
|
(input) => input == '' || !Number.isNaN(Number(input)),
|
||||||
|
(input) => input,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All possible char entities, like characters and groups. Can be filtered down to just one type.
|
* All possible char entities, like characters and groups. Can be filtered down to just one type.
|
||||||
*
|
*
|
||||||
|
80
public/scripts/slash-commands/SlashCommandReturnHelper.js
Normal file
80
public/scripts/slash-commands/SlashCommandReturnHelper.js
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
import { sendSystemMessage, system_message_types } from '../../script.js';
|
||||||
|
import { callGenericPopup, POPUP_TYPE } from '../popup.js';
|
||||||
|
import { escapeHtml } from '../utils.js';
|
||||||
|
import { enumIcons } from './SlashCommandCommonEnumsProvider.js';
|
||||||
|
import { enumTypes, SlashCommandEnumValue } from './SlashCommandEnumValue.js';
|
||||||
|
|
||||||
|
/** @typedef {'pipe'|'object'|'chat-html'|'chat-text'|'popup-html'|'popup-text'|'toast-html'|'toast-text'|'console'|'none'} SlashCommandReturnType */
|
||||||
|
|
||||||
|
export const slashCommandReturnHelper = {
|
||||||
|
// Without this, VSCode formatter fucks up JS docs. Don't ask me why.
|
||||||
|
_: false,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets/creates the enum list of types of return relevant for a slash command
|
||||||
|
*
|
||||||
|
* @param {object} [options={}] Options
|
||||||
|
* @param {boolean} [options.allowPipe=true] Allow option to pipe the return value
|
||||||
|
* @param {boolean} [options.allowObject=false] Allow option to return the value as an object
|
||||||
|
* @param {boolean} [options.allowChat=false] Allow option to return the value as a chat message
|
||||||
|
* @param {boolean} [options.allowPopup=false] Allow option to return the value as a popup
|
||||||
|
* @param {boolean}[options.allowTextVersion=true] Used in combination with chat/popup/toast, some of them do not make sense for text versions, e.g.if you are building a HTML string anyway
|
||||||
|
* @returns {SlashCommandEnumValue[]} The enum list
|
||||||
|
*/
|
||||||
|
enumList: ({ allowPipe = true, allowObject = false, allowChat = false, allowPopup = false, allowTextVersion = true } = {}) => [
|
||||||
|
allowPipe && new SlashCommandEnumValue('pipe', 'Return to the pipe for the next command', enumTypes.name, '|'),
|
||||||
|
allowObject && new SlashCommandEnumValue('object', 'Return as an object (or array) to the pipe for the next command', enumTypes.variable, enumIcons.dictionary),
|
||||||
|
allowChat && new SlashCommandEnumValue('chat-html', 'Sending a chat message with the return value - Can display HTML', enumTypes.command, enumIcons.message),
|
||||||
|
allowChat && allowTextVersion && new SlashCommandEnumValue('chat-text', 'Sending a chat message with the return value - Will only display as text', enumTypes.qr, enumIcons.message),
|
||||||
|
allowPopup && new SlashCommandEnumValue('popup-html', 'Showing as a popup with the return value - Can display HTML', enumTypes.command, enumIcons.popup),
|
||||||
|
allowPopup && allowTextVersion && new SlashCommandEnumValue('popup-text', 'Showing as a popup with the return value - Will only display as text', enumTypes.qr, enumIcons.popup),
|
||||||
|
new SlashCommandEnumValue('toast-html', 'Show the return value as a toast notification - Can display HTML', enumTypes.command, 'ℹ️'),
|
||||||
|
allowTextVersion && new SlashCommandEnumValue('toast-text', 'Show the return value as a toast notification - Will only display as text', enumTypes.qr, 'ℹ️'),
|
||||||
|
new SlashCommandEnumValue('console', 'Log the return value (object, if it can be one) to the console', enumTypes.enum, '>'),
|
||||||
|
new SlashCommandEnumValue('none', 'No return value'),
|
||||||
|
].filter(x => !!x),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the return value based on the specified type
|
||||||
|
*
|
||||||
|
* @param {SlashCommandReturnType} type The type of return
|
||||||
|
* @param {object|number|string} value The value to return
|
||||||
|
* @param {object} [options={}] Options
|
||||||
|
* @param {(o: object) => string} [options.objectToStringFunc=null] Function to convert the object to a string, if object was provided and 'object' was not the chosen return type
|
||||||
|
* @param {(o: object) => string} [options.objectToHtmlFunc=null] Analog to 'objectToStringFunc', which will be used here if not provided - but can do a different string layout if HTML is requested
|
||||||
|
* @returns {Promise<*>} The processed return value
|
||||||
|
*/
|
||||||
|
async doReturn(type, value, { objectToStringFunc = o => o?.toString(), objectToHtmlFunc = null } = {}) {
|
||||||
|
const shouldHtml = type.endsWith('html');
|
||||||
|
const actualConverterFunc = shouldHtml && objectToHtmlFunc ? objectToHtmlFunc : objectToStringFunc;
|
||||||
|
const stringValue = typeof value !== 'string' ? actualConverterFunc(value) : value;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 'popup-html':
|
||||||
|
case 'popup-text':
|
||||||
|
case 'chat-text':
|
||||||
|
case 'chat-html':
|
||||||
|
case 'toast-text':
|
||||||
|
case 'toast-html': {
|
||||||
|
const htmlOrNotHtml = shouldHtml ? DOMPurify.sanitize((new showdown.Converter()).makeHtml(stringValue)) : escapeHtml(stringValue);
|
||||||
|
|
||||||
|
if (type.startsWith('popup')) await callGenericPopup(htmlOrNotHtml, POPUP_TYPE.TEXT);
|
||||||
|
if (type.startsWith('chat')) sendSystemMessage(system_message_types.GENERIC, htmlOrNotHtml);
|
||||||
|
if (type.startsWith('toast')) toastr.info(htmlOrNotHtml, null, { escapeHtml: !shouldHtml });
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
case 'pipe':
|
||||||
|
return stringValue ?? '';
|
||||||
|
case 'object':
|
||||||
|
return JSON.stringify(value);
|
||||||
|
case 'console':
|
||||||
|
console.info(value);
|
||||||
|
return '';
|
||||||
|
case 'none':
|
||||||
|
return '';
|
||||||
|
default:
|
||||||
|
throw new Error(`Unknown return type: ${type}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
@@ -11,6 +11,7 @@ import { SlashCommandClosureResult } from './slash-commands/SlashCommandClosureR
|
|||||||
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
import { commonEnumProviders, enumIcons } from './slash-commands/SlashCommandCommonEnumsProvider.js';
|
||||||
import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
|
import { SlashCommandEnumValue, enumTypes } from './slash-commands/SlashCommandEnumValue.js';
|
||||||
import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
import { PARSER_FLAG, SlashCommandParser } from './slash-commands/SlashCommandParser.js';
|
||||||
|
import { slashCommandReturnHelper } from './slash-commands/SlashCommandReturnHelper.js';
|
||||||
import { SlashCommandScope } from './slash-commands/SlashCommandScope.js';
|
import { SlashCommandScope } from './slash-commands/SlashCommandScope.js';
|
||||||
import { isFalseBoolean, convertValueType, isTrueBoolean } from './utils.js';
|
import { isFalseBoolean, convertValueType, isTrueBoolean } from './utils.js';
|
||||||
|
|
||||||
@@ -305,7 +306,28 @@ export function replaceVariableMacros(input) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function listVariablesCallback(args) {
|
async function listVariablesCallback(args) {
|
||||||
const type = String(args?.format || '').toLowerCase().trim() || 'popup';
|
/** @type {import('./slash-commands/SlashCommandReturnHelper.js').SlashCommandReturnType} */
|
||||||
|
let returnType = args.return;
|
||||||
|
|
||||||
|
// Old legacy return type handling
|
||||||
|
if (args.format) {
|
||||||
|
toastr.warning(`Legacy argument 'format' with value '${args.format}' is deprecated. Please use 'return' instead. Routing to the correct return type...`, 'Deprecation warning');
|
||||||
|
const type = String(args?.format).toLowerCase().trim();
|
||||||
|
switch (type) {
|
||||||
|
case 'none':
|
||||||
|
returnType = 'none';
|
||||||
|
break;
|
||||||
|
case 'chat':
|
||||||
|
returnType = 'chat-html';
|
||||||
|
break;
|
||||||
|
case 'popup':
|
||||||
|
default:
|
||||||
|
returnType = 'popup-html';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now the actual new return type handling
|
||||||
const scope = String(args?.scope || '').toLowerCase().trim() || 'all';
|
const scope = String(args?.scope || '').toLowerCase().trim() || 'all';
|
||||||
if (!chat_metadata.variables) {
|
if (!chat_metadata.variables) {
|
||||||
chat_metadata.variables = {};
|
chat_metadata.variables = {};
|
||||||
@@ -317,35 +339,24 @@ async function listVariablesCallback(args) {
|
|||||||
const localVariables = includeLocalVariables ? Object.entries(chat_metadata.variables).map(([name, value]) => `${name}: ${value}`) : [];
|
const localVariables = includeLocalVariables ? Object.entries(chat_metadata.variables).map(([name, value]) => `${name}: ${value}`) : [];
|
||||||
const globalVariables = includeGlobalVariables ? Object.entries(extension_settings.variables.global).map(([name, value]) => `${name}: ${value}`) : [];
|
const globalVariables = includeGlobalVariables ? Object.entries(extension_settings.variables.global).map(([name, value]) => `${name}: ${value}`) : [];
|
||||||
|
|
||||||
|
const buildTextValue = (_) => {
|
||||||
|
const localVariablesString = localVariables.length > 0 ? localVariables.join('\n\n') : 'No local variables';
|
||||||
|
const globalVariablesString = globalVariables.length > 0 ? globalVariables.join('\n\n') : 'No global variables';
|
||||||
|
const chatName = getCurrentChatId();
|
||||||
|
|
||||||
|
const message = [
|
||||||
|
includeLocalVariables ? `### Local variables (${chatName}):\n${localVariablesString}` : '',
|
||||||
|
includeGlobalVariables ? `### Global variables:\n${globalVariablesString}` : '',
|
||||||
|
].filter(x => x).join('\n\n');
|
||||||
|
return message;
|
||||||
|
};
|
||||||
|
|
||||||
const jsonVariables = [
|
const jsonVariables = [
|
||||||
...Object.entries(chat_metadata.variables).map(x => ({ key: x[0], value: x[1], scope: 'local' })),
|
...Object.entries(chat_metadata.variables).map(x => ({ key: x[0], value: x[1], scope: 'local' })),
|
||||||
...Object.entries(extension_settings.variables.global).map(x => ({ key: x[0], value: x[1], scope: 'global' })),
|
...Object.entries(extension_settings.variables.global).map(x => ({ key: x[0], value: x[1], scope: 'global' })),
|
||||||
];
|
];
|
||||||
|
|
||||||
const localVariablesString = localVariables.length > 0 ? localVariables.join('\n\n') : 'No local variables';
|
return await slashCommandReturnHelper.doReturn(returnType ?? 'popup-html', jsonVariables, { objectToStringFunc: buildTextValue });
|
||||||
const globalVariablesString = globalVariables.length > 0 ? globalVariables.join('\n\n') : 'No global variables';
|
|
||||||
const chatName = getCurrentChatId();
|
|
||||||
|
|
||||||
const converter = new showdown.Converter();
|
|
||||||
const message = [
|
|
||||||
includeLocalVariables ? `### Local variables (${chatName}):\n${localVariablesString}` : '',
|
|
||||||
includeGlobalVariables ? `### Global variables:\n${globalVariablesString}` : '',
|
|
||||||
].filter(x => x).join('\n\n');
|
|
||||||
const htmlMessage = DOMPurify.sanitize(converter.makeHtml(message));
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case 'none':
|
|
||||||
break;
|
|
||||||
case 'chat':
|
|
||||||
sendSystemMessage(system_message_types.GENERIC, htmlMessage);
|
|
||||||
break;
|
|
||||||
case 'popup':
|
|
||||||
default:
|
|
||||||
await callGenericPopup(htmlMessage, POPUP_TYPE.TEXT);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return JSON.stringify(jsonVariables);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -669,8 +680,8 @@ function deleteGlobalVariable(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a series of numeric values from a string.
|
* Parses a series of numeric values from a string or a string array.
|
||||||
* @param {string} value A space-separated list of numeric values or variable names
|
* @param {string|string[]} value A space-separated list of numeric values or variable names
|
||||||
* @param {SlashCommandScope} scope Scope
|
* @param {SlashCommandScope} scope Scope
|
||||||
* @returns {number[]} An array of numeric values
|
* @returns {number[]} An array of numeric values
|
||||||
*/
|
*/
|
||||||
@@ -679,11 +690,17 @@ function parseNumericSeries(value, scope = null) {
|
|||||||
return [value];
|
return [value];
|
||||||
}
|
}
|
||||||
|
|
||||||
const array = value
|
/** @type {(string|number)[]} */
|
||||||
.split(' ')
|
let values = Array.isArray(value) ? value : value.split(' ');
|
||||||
.map(i => i.trim())
|
|
||||||
|
// If a JSON array was provided as the only value, convert it to an array
|
||||||
|
if (values.length === 1 && typeof values[0] === 'string' && values[0].startsWith('[')) {
|
||||||
|
values = convertValueType(values[0], 'array');
|
||||||
|
}
|
||||||
|
|
||||||
|
const array = values.map(i => typeof i === 'string' ? i.trim() : i)
|
||||||
.filter(i => i !== '')
|
.filter(i => i !== '')
|
||||||
.map(i => isNaN(Number(i)) ? Number(resolveVariable(i, scope)) : Number(i))
|
.map(i => isNaN(Number(i)) ? Number(resolveVariable(String(i), scope)) : Number(i))
|
||||||
.filter(i => !isNaN(i));
|
.filter(i => !isNaN(i));
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
@@ -703,7 +720,7 @@ function performOperation(value, operation, singleOperand = false, scope = null)
|
|||||||
|
|
||||||
const result = singleOperand ? operation(array[0]) : operation(array);
|
const result = singleOperand ? operation(array[0]) : operation(array);
|
||||||
|
|
||||||
if (isNaN(result) || !isFinite(result)) {
|
if (isNaN(result)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -731,7 +748,7 @@ function maxValuesCallback(args, value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function subValuesCallback(args, value) {
|
function subValuesCallback(args, value) {
|
||||||
return performOperation(value, (array) => array[0] - array[1], false, args._scope);
|
return performOperation(value, (array) => array.reduce((a, b) => a - b, array.shift() ?? 0), false, args._scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
function divValuesCallback(args, value) {
|
function divValuesCallback(args, value) {
|
||||||
@@ -910,7 +927,7 @@ export function registerVariableCommands() {
|
|||||||
name: 'listvar',
|
name: 'listvar',
|
||||||
callback: listVariablesCallback,
|
callback: listVariablesCallback,
|
||||||
aliases: ['listchatvar'],
|
aliases: ['listchatvar'],
|
||||||
helpString: 'List registered chat variables. Displays variables in a popup by default. Use the <code>format</code> argument to change the output format.',
|
helpString: 'List registered chat variables. Displays variables in a popup by default. Use the <code>return</code> argument to change the return type.',
|
||||||
returns: 'JSON list of local variables',
|
returns: 'JSON list of local variables',
|
||||||
namedArgumentList: [
|
namedArgumentList: [
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
@@ -926,9 +943,18 @@ export function registerVariableCommands() {
|
|||||||
new SlashCommandEnumValue('global', 'Global variables', enumTypes.enum, enumIcons.globalVariable),
|
new SlashCommandEnumValue('global', 'Global variables', enumTypes.enum, enumIcons.globalVariable),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
SlashCommandNamedArgument.fromProps({
|
||||||
|
name: 'return',
|
||||||
|
description: 'The way how you want the return value to be provided',
|
||||||
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
|
defaultValue: 'popup-html',
|
||||||
|
enumList: slashCommandReturnHelper.enumList({ allowPipe: false, allowObject: true, allowChat: true, allowPopup: true, allowTextVersion: false }),
|
||||||
|
forceEnum: true,
|
||||||
|
}),
|
||||||
|
// TODO remove some day
|
||||||
SlashCommandNamedArgument.fromProps({
|
SlashCommandNamedArgument.fromProps({
|
||||||
name: 'format',
|
name: 'format',
|
||||||
description: 'output format',
|
description: '!!! DEPRECATED - use "return" instead !!! output format',
|
||||||
typeList: [ARGUMENT_TYPE.STRING],
|
typeList: [ARGUMENT_TYPE.STRING],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
forceEnum: true,
|
forceEnum: true,
|
||||||
@@ -1595,36 +1621,15 @@ export function registerVariableCommands() {
|
|||||||
}));
|
}));
|
||||||
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
|
||||||
name: 'add',
|
name: 'add',
|
||||||
callback: (args, /**@type {string[]}*/value) => addValuesCallback(args, value.join(' ')),
|
callback: (args, value) => addValuesCallback(args, value),
|
||||||
returns: 'sum of the provided values',
|
returns: 'sum of the provided values',
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
SlashCommandArgument.fromProps({
|
SlashCommandArgument.fromProps({
|
||||||
description: 'values to sum',
|
description: 'values to sum',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
acceptsMultiple: true,
|
acceptsMultiple: true,
|
||||||
enumProvider: (executor, scope) => {
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
const vars = commonEnumProviders.variables('all')(executor, scope);
|
|
||||||
vars.push(
|
|
||||||
new SlashCommandEnumValue(
|
|
||||||
'any variable name',
|
|
||||||
null,
|
|
||||||
enumTypes.variable,
|
|
||||||
enumIcons.variable,
|
|
||||||
(input) => /^\w*$/.test(input),
|
|
||||||
(input) => input,
|
|
||||||
),
|
|
||||||
new SlashCommandEnumValue(
|
|
||||||
'any number',
|
|
||||||
null,
|
|
||||||
enumTypes.number,
|
|
||||||
enumIcons.number,
|
|
||||||
(input) => input == '' || !Number.isNaN(Number(input)),
|
|
||||||
(input) => input,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
return vars;
|
|
||||||
},
|
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -1632,7 +1637,9 @@ export function registerVariableCommands() {
|
|||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
Performs an addition of the set of values and passes the result down the pipe.
|
Performs an addition of the set of values and passes the result down the pipe.
|
||||||
Can use variable names.
|
</div>
|
||||||
|
<div>
|
||||||
|
Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Example:</strong>
|
<strong>Example:</strong>
|
||||||
@@ -1640,6 +1647,9 @@ export function registerVariableCommands() {
|
|||||||
<li>
|
<li>
|
||||||
<pre><code class="language-stscript">/add 10 i 30 j</code></pre>
|
<pre><code class="language-stscript">/add 10 i 30 j</code></pre>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<pre><code class="language-stscript">/add ["count", 15, 2, "i"]</code></pre>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
@@ -1651,16 +1661,20 @@ export function registerVariableCommands() {
|
|||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
SlashCommandArgument.fromProps({
|
SlashCommandArgument.fromProps({
|
||||||
description: 'values to multiply',
|
description: 'values to multiply',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
acceptsMultiple: true,
|
acceptsMultiple: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
splitUnnamedArgument: true,
|
||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
Performs a multiplication of the set of values and passes the result down the pipe. Can use variable names.
|
Performs a multiplication of the set of values and passes the result down the pipe.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Examples:</strong>
|
<strong>Examples:</strong>
|
||||||
@@ -1668,6 +1682,9 @@ export function registerVariableCommands() {
|
|||||||
<li>
|
<li>
|
||||||
<pre><code class="language-stscript">/mul 10 i 30 j</code></pre>
|
<pre><code class="language-stscript">/mul 10 i 30 j</code></pre>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<pre><code class="language-stscript">/mul ["count", 15, 2, "i"]</code></pre>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
@@ -1679,16 +1696,20 @@ export function registerVariableCommands() {
|
|||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
SlashCommandArgument.fromProps({
|
SlashCommandArgument.fromProps({
|
||||||
description: 'values to find the max',
|
description: 'values to find the max',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
acceptsMultiple: true,
|
acceptsMultiple: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
splitUnnamedArgument: true,
|
||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
Returns the maximum value of the set of values and passes the result down the pipe. Can use variable names.
|
Returns the maximum value of the set of values and passes the result down the pipe.
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Examples:</strong>
|
<strong>Examples:</strong>
|
||||||
@@ -1696,6 +1717,9 @@ export function registerVariableCommands() {
|
|||||||
<li>
|
<li>
|
||||||
<pre><code class="language-stscript">/max 10 i 30 j</code></pre>
|
<pre><code class="language-stscript">/max 10 i 30 j</code></pre>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<pre><code class="language-stscript">/max ["count", 15, 2, "i"]</code></pre>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
@@ -1707,17 +1731,20 @@ export function registerVariableCommands() {
|
|||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
SlashCommandArgument.fromProps({
|
SlashCommandArgument.fromProps({
|
||||||
description: 'values to find the min',
|
description: 'values to find the min',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
acceptsMultiple: true,
|
acceptsMultiple: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
splitUnnamedArgument: true,
|
||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
Returns the minimum value of the set of values and passes the result down the pipe.
|
Returns the minimum value of the set of values and passes the result down the pipe.
|
||||||
Can use variable names.
|
</div>
|
||||||
|
<div>
|
||||||
|
Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Example:</strong>
|
<strong>Example:</strong>
|
||||||
@@ -1725,6 +1752,9 @@ export function registerVariableCommands() {
|
|||||||
<li>
|
<li>
|
||||||
<pre><code class="language-stscript">/min 10 i 30 j</code></pre>
|
<pre><code class="language-stscript">/min 10 i 30 j</code></pre>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<pre><code class="language-stscript">/min ["count", 15, 2, "i"]</code></pre>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
@@ -1735,18 +1765,21 @@ export function registerVariableCommands() {
|
|||||||
returns: 'difference of the provided values',
|
returns: 'difference of the provided values',
|
||||||
unnamedArgumentList: [
|
unnamedArgumentList: [
|
||||||
SlashCommandArgument.fromProps({
|
SlashCommandArgument.fromProps({
|
||||||
description: 'values to find the difference',
|
description: 'values to subtract, starting form the first provided value',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME, ARGUMENT_TYPE.LIST],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
acceptsMultiple: true,
|
acceptsMultiple: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
splitUnnamedArgument: true,
|
||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
Performs a subtraction of the set of values and passes the result down the pipe.
|
Performs a subtraction of the set of values and passes the result down the pipe.
|
||||||
Can use variable names.
|
</div>
|
||||||
|
<div>
|
||||||
|
Can use variable names, or a JSON array consisting of numbers and variables (with quotes).
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<strong>Example:</strong>
|
<strong>Example:</strong>
|
||||||
@@ -1754,6 +1787,9 @@ export function registerVariableCommands() {
|
|||||||
<li>
|
<li>
|
||||||
<pre><code class="language-stscript">/sub i 5</code></pre>
|
<pre><code class="language-stscript">/sub i 5</code></pre>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<pre><code class="language-stscript">/sub ["count", 4, "i"]</code></pre>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
@@ -1767,17 +1803,18 @@ export function registerVariableCommands() {
|
|||||||
description: 'dividend',
|
description: 'dividend',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
SlashCommandArgument.fromProps({
|
SlashCommandArgument.fromProps({
|
||||||
description: 'divisor',
|
description: 'divisor',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
splitUnnamedArgument: true,
|
||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
Performs a division of two values and passes the result down the pipe.
|
Performs a division of two values and passes the result down the pipe.
|
||||||
@@ -1802,17 +1839,18 @@ export function registerVariableCommands() {
|
|||||||
description: 'dividend',
|
description: 'dividend',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
SlashCommandArgument.fromProps({
|
SlashCommandArgument.fromProps({
|
||||||
description: 'divisor',
|
description: 'divisor',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
splitUnnamedArgument: true,
|
||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
Performs a modulo operation of two values and passes the result down the pipe.
|
Performs a modulo operation of two values and passes the result down the pipe.
|
||||||
@@ -1837,17 +1875,18 @@ export function registerVariableCommands() {
|
|||||||
description: 'base',
|
description: 'base',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
SlashCommandArgument.fromProps({
|
SlashCommandArgument.fromProps({
|
||||||
description: 'exponent',
|
description: 'exponent',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
splitUnnamedArgument: true,
|
||||||
helpString: `
|
helpString: `
|
||||||
<div>
|
<div>
|
||||||
Performs a power operation of two values and passes the result down the pipe.
|
Performs a power operation of two values and passes the result down the pipe.
|
||||||
@@ -1872,7 +1911,7 @@ export function registerVariableCommands() {
|
|||||||
description: 'value',
|
description: 'value',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -1900,7 +1939,7 @@ export function registerVariableCommands() {
|
|||||||
description: 'value',
|
description: 'value',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -1929,7 +1968,7 @@ export function registerVariableCommands() {
|
|||||||
description: 'value',
|
description: 'value',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -1957,7 +1996,7 @@ export function registerVariableCommands() {
|
|||||||
description: 'value',
|
description: 'value',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -1985,7 +2024,7 @@ export function registerVariableCommands() {
|
|||||||
description: 'value',
|
description: 'value',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
@@ -2013,7 +2052,7 @@ export function registerVariableCommands() {
|
|||||||
description: 'value',
|
description: 'value',
|
||||||
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
typeList: [ARGUMENT_TYPE.NUMBER, ARGUMENT_TYPE.VARIABLE_NAME],
|
||||||
isRequired: true,
|
isRequired: true,
|
||||||
enumProvider: commonEnumProviders.variables('all'),
|
enumProvider: commonEnumProviders.numbersAndVariables,
|
||||||
forceEnum: false,
|
forceEnum: false,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
@@ -323,7 +323,7 @@ async function sendMakerSuiteRequest(request, response) {
|
|||||||
? (stream ? 'streamGenerateContent' : 'generateContent')
|
? (stream ? 'streamGenerateContent' : 'generateContent')
|
||||||
: (isText ? 'generateText' : 'generateMessage');
|
: (isText ? 'generateText' : 'generateMessage');
|
||||||
|
|
||||||
const generateResponse = await fetch(`${apiUrl.origin}/${apiVersion}/models/${model}:${responseType}?key=${apiKey}${stream ? '&alt=sse' : ''}`, {
|
const generateResponse = await fetch(`${apiUrl}/${apiVersion}/models/${model}:${responseType}?key=${apiKey}${stream ? '&alt=sse' : ''}`, {
|
||||||
body: JSON.stringify(body),
|
body: JSON.stringify(body),
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
@@ -9,41 +9,6 @@ const { jsonParser } = require('../express-common');
|
|||||||
const { readSecret, SECRET_KEYS } = require('./secrets.js');
|
const { readSecret, SECRET_KEYS } = require('./secrets.js');
|
||||||
const FormData = require('form-data');
|
const FormData = require('form-data');
|
||||||
|
|
||||||
/**
|
|
||||||
* Sanitizes a string.
|
|
||||||
* @param {string} x String to sanitize
|
|
||||||
* @returns {string} Sanitized string
|
|
||||||
*/
|
|
||||||
function safeStr(x) {
|
|
||||||
x = String(x);
|
|
||||||
x = x.replace(/ +/g, ' ');
|
|
||||||
x = x.trim();
|
|
||||||
x = x.replace(/^[\s,.]+|[\s,.]+$/g, '');
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
const splitStrings = [
|
|
||||||
', extremely',
|
|
||||||
', intricate,',
|
|
||||||
];
|
|
||||||
|
|
||||||
const dangerousPatterns = '[]【】()()|::';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes patterns from a string.
|
|
||||||
* @param {string} x String to sanitize
|
|
||||||
* @param {string} pattern Pattern to remove
|
|
||||||
* @returns {string} Sanitized string
|
|
||||||
*/
|
|
||||||
function removePattern(x, pattern) {
|
|
||||||
for (let i = 0; i < pattern.length; i++) {
|
|
||||||
let p = pattern[i];
|
|
||||||
let regex = new RegExp('\\' + p, 'g');
|
|
||||||
x = x.replace(regex, '');
|
|
||||||
}
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the comfy workflows.
|
* Gets the comfy workflows.
|
||||||
* @param {import('../users.js').UserDirectoryList} directories
|
* @param {import('../users.js').UserDirectoryList} directories
|
||||||
@@ -391,40 +356,6 @@ router.post('/sd-next/upscalers', jsonParser, async (request, response) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
|
||||||
* SD prompt expansion using GPT-2 text generation model.
|
|
||||||
* Adapted from: https://github.com/lllyasviel/Fooocus/blob/main/modules/expansion.py
|
|
||||||
*/
|
|
||||||
router.post('/expand', jsonParser, async (request, response) => {
|
|
||||||
const originalPrompt = request.body.prompt;
|
|
||||||
|
|
||||||
if (!originalPrompt) {
|
|
||||||
console.warn('No prompt provided for SD expansion.');
|
|
||||||
return response.send({ prompt: '' });
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('Refine prompt input:', originalPrompt);
|
|
||||||
const splitString = splitStrings[Math.floor(Math.random() * splitStrings.length)];
|
|
||||||
let prompt = safeStr(originalPrompt) + splitString;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const task = 'text-generation';
|
|
||||||
const module = await import('../transformers.mjs');
|
|
||||||
const pipe = await module.default.getPipeline(task);
|
|
||||||
|
|
||||||
const result = await pipe(prompt, { num_beams: 1, max_new_tokens: 256, do_sample: true });
|
|
||||||
|
|
||||||
const newText = result[0].generated_text;
|
|
||||||
const newPrompt = safeStr(removePattern(newText, dangerousPatterns));
|
|
||||||
console.log('Refine prompt output:', newPrompt);
|
|
||||||
|
|
||||||
return response.send({ prompt: newPrompt });
|
|
||||||
} catch {
|
|
||||||
console.warn('Failed to load transformers.js pipeline.');
|
|
||||||
return response.send({ prompt: originalPrompt });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const comfy = express.Router();
|
const comfy = express.Router();
|
||||||
|
|
||||||
comfy.post('/ping', jsonParser, async (request, response) => {
|
comfy.post('/ping', jsonParser, async (request, response) => {
|
||||||
|
@@ -31,12 +31,6 @@ const tasks = {
|
|||||||
configField: 'extras.embeddingModel',
|
configField: 'extras.embeddingModel',
|
||||||
quantized: true,
|
quantized: true,
|
||||||
},
|
},
|
||||||
'text-generation': {
|
|
||||||
defaultModel: 'Cohee/fooocus_expansion-onnx',
|
|
||||||
pipeline: null,
|
|
||||||
configField: 'extras.promptExpansionModel',
|
|
||||||
quantized: false,
|
|
||||||
},
|
|
||||||
'automatic-speech-recognition': {
|
'automatic-speech-recognition': {
|
||||||
defaultModel: 'Xenova/whisper-small',
|
defaultModel: 'Xenova/whisper-small',
|
||||||
pipeline: null,
|
pipeline: null,
|
||||||
|
Reference in New Issue
Block a user