Add Variety Boost option for NovelAI image generation. (#4417) Co-authored-by: sirius422 <sirius42@gfw.moe>

4d9f229383ad0b3cd85385d63ac92ba64b2e954e

sirius422 <38351200+sirius422@users.noreply.github.com>

Signed
3 files changed, +36 -0Ignore whitespace
public/scripts/extensions/stable-diffusion/index.js+9 -0
@@ -306,6 +306,7 @@ const defaultSettings = {
306306 novel_sm: false,
307307 novel_sm_dyn: false,
308308 novel_decrisper: false,
309+ novel_variety_boost: false,
309310
310311 // OpenAI settings
311312 openai_style: 'vivid',
@@ -482,6 +483,7 @@ async function loadSettings() {
482483 $('#sd_novel_sm_dyn').prop('checked', extension_settings.sd.novel_sm_dyn);
483484 $('#sd_novel_sm_dyn').prop('disabled', !extension_settings.sd.novel_sm);
484485 $('#sd_novel_decrisper').prop('checked', extension_settings.sd.novel_decrisper);
486+ $('#sd_novel_variety_boost').prop('checked', extension_settings.sd.novel_variety_boost);
485487 $('#sd_pollinations_enhance').prop('checked', extension_settings.sd.pollinations_enhance);
486488 $('#sd_horde').prop('checked', extension_settings.sd.horde);
487489 $('#sd_horde_nsfw').prop('checked', extension_settings.sd.horde_nsfw);
@@ -1055,6 +1057,11 @@ function onNovelDecrisperInput() {
10551057 saveSettingsDebounced();
10561058}
10571059
1060+function onNovelVarietyBoostInput() {
1061+ extension_settings.sd.novel_variety_boost = !!$('#sd_novel_variety_boost').prop('checked');
1062+ saveSettingsDebounced();
1063+}
1064+
10581065function onPollinationsEnhanceInput() {
10591066 extension_settings.sd.pollinations_enhance = !!$('#sd_pollinations_enhance').prop('checked');
10601067 saveSettingsDebounced();
@@ -3234,6 +3241,7 @@ async function generateNovelImage(prompt, negativePrompt, signal) {
32343241 negative_prompt: negativePrompt,
32353242 upscale_ratio: extension_settings.sd.hr_scale,
32363243 decrisper: extension_settings.sd.novel_decrisper,
3244+ variety_boost: extension_settings.sd.novel_variety_boost,
32373245 sm: sm,
32383246 sm_dyn: sm_dyn,
32393247 seed: extension_settings.sd.seed >= 0 ? extension_settings.sd.seed : undefined,
@@ -4654,6 +4662,7 @@ jQuery(async () => {
46544662 $('#sd_novel_sm').on('input', onNovelSmInput);
46554663 $('#sd_novel_sm_dyn').on('input', onNovelSmDynInput);
46564664 $('#sd_novel_decrisper').on('input', onNovelDecrisperInput);
4665+ $('#sd_novel_variety_boost').on('input', onNovelVarietyBoostInput);
46574666 $('#sd_pollinations_enhance').on('input', onPollinationsEnhanceInput);
46584667 $('#sd_comfy_validate').on('click', validateComfyUrl);
46594668 $('#sd_comfy_url').on('input', onComfyUrlInput);
public/scripts/extensions/stable-diffusion/settings.html+4 -0
@@ -451,6 +451,10 @@
451451 <input id="sd_novel_decrisper" type="checkbox" />
452452 <small data-i18n="Decrisper">Decrisper</small>
453453 </label>
454+ <label class="flex1 checkbox_label" data-i18n="[title]Enable guidance only after body has been formed, to improve diversity and saturation of samples. May reduce relevance" title="Enable guidance only after body has been formed, to improve diversity and saturation of samples. May reduce relevance">
455+ <input id="sd_novel_variety_boost" type="checkbox" />
456+ <small data-i18n="Variety+">Variety+</small>
457+ </label>
454458 </div>
455459
456460 <div data-sd-source="novel,togetherai,pollinations,comfy,drawthings,vlad,auto,horde,extras,stability,bfl" class="marginTop5">
src/endpoints/novelai.js+23 -0
@@ -11,6 +11,11 @@ const API_NOVELAI = 'https://api.novelai.net';
1111const TEXT_NOVELAI = 'https://text.novelai.net';
1212const IMAGE_NOVELAI = 'https://image.novelai.net';
1313
14+// Constants for skip_cfg_above_sigma (Variety+) calculation
15+const REFERENCE_PIXEL_COUNT = 1011712; // 832 * 1216 reference image size
16+const SIGMA_MAGIC_NUMBER = 19; // Base sigma multiplier for V3 and V4 models
17+const SIGMA_MAGIC_NUMBER_V4_5 = 58; // Base sigma multiplier for V4.5 models
18+
1419// Ban bracket generation, plus defaults
1520const badWordsList = [
1621 [3], [49356], [1431], [31715], [34387], [20765], [30702], [10691], [49333], [1266],
@@ -112,6 +117,17 @@ function getRepPenaltyWhitelist(model) {
112117 return null;
113118}
114119
120+function calculateSkipCfgAboveSigma(width, height, modelName) {
121+ const magicConstant = modelName?.includes('nai-diffusion-4-5')
122+ ? SIGMA_MAGIC_NUMBER_V4_5
123+ : SIGMA_MAGIC_NUMBER;
124+
125+ const pixelCount = width * height;
126+ const ratio = pixelCount / REFERENCE_PIXEL_COUNT;
127+
128+ return Math.pow(ratio, 0.5) * magicConstant;
129+}
130+
115131export const router = express.Router();
116132
117133router.post('/status', async function (req, res) {
@@ -332,6 +348,13 @@ router.post('/generate-image', async (request, response) => {
332348 sm: request.body.sm ?? false,
333349 sm_dyn: request.body.sm_dyn ?? false,
334350 uncond_scale: 1,
351+ skip_cfg_above_sigma: request.body.variety_boost
352+ ? calculateSkipCfgAboveSigma(
353+ request.body.width ?? 512,
354+ request.body.height ?? 512,
355+ request.body.model ?? 'nai-diffusion',
356+ )
357+ : null,
335358 use_coords: false,
336359 characterPrompts: [],
337360 reference_image_multiple: [],