CFG: Add insertion depth and custom separator

Insertion depth allows for CFG to variably inject itself into the
negative prompt. This is similar to how Author's note works.

However, this method of insertion depth conflicts with AN and
world info where negatives can be meshed between two lines
of those specific insertions.

A custom separator must be wrapped in quotes, otherwise the default
separator is a newline for negative cascading.

Signed-off-by: kingbri <bdashore3@proton.me>
This commit is contained in:
kingbri
2023-08-19 01:19:22 -04:00
parent cdbca6d9fd
commit 7191f7a8ad
6 changed files with 79 additions and 45 deletions

View File

@ -164,7 +164,6 @@ import { deviceInfo } from "./scripts/RossAscends-mods.js";
import { registerPromptManagerMigration } from "./scripts/PromptManager.js"; import { registerPromptManagerMigration } from "./scripts/PromptManager.js";
import { getRegexedString, regex_placement } from "./scripts/extensions/regex/engine.js"; import { getRegexedString, regex_placement } from "./scripts/extensions/regex/engine.js";
import { FILTER_TYPES, FilterHelper } from "./scripts/filters.js"; import { FILTER_TYPES, FilterHelper } from "./scripts/filters.js";
import { getCfg, getNegativePrompt } from "./scripts/extensions/cfg/util.js";
//exporting functions and vars for mods //exporting functions and vars for mods
export { export {
@ -2906,8 +2905,6 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
let this_amount_gen = parseInt(amount_gen); // how many tokens the AI will be requested to generate let this_amount_gen = parseInt(amount_gen); // how many tokens the AI will be requested to generate
let this_settings = koboldai_settings[koboldai_setting_names[preset_settings]]; let this_settings = koboldai_settings[koboldai_setting_names[preset_settings]];
const cfgValues = getCfg(finalPromt);
if (isMultigenEnabled() && type !== 'quiet') { if (isMultigenEnabled() && type !== 'quiet') {
// if nothing has been generated yet.. // if nothing has been generated yet..
this_amount_gen = getMultigenAmount(); this_amount_gen = getMultigenAmount();
@ -2938,7 +2935,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
} }
} }
else if (main_api == 'textgenerationwebui') { else if (main_api == 'textgenerationwebui') {
generate_data = getTextGenGenerationData(finalPromt, this_amount_gen, isImpersonate, cfgValues); generate_data = getTextGenGenerationData(finalPromt, this_amount_gen, isImpersonate);
generate_data.use_mancer = api_use_mancer_webui; generate_data.use_mancer = api_use_mancer_webui;
} }
else if (main_api == 'novel') { else if (main_api == 'novel') {

View File

@ -182,6 +182,24 @@ function loadSettings() {
}); });
} }
// Display the negative separator in quotes if not quoted already
let negativeSeparatorDisplay = [];
const negativeSeparator = chat_metadata[metadataKeys.negative_separator];
if (negativeSeparator) {
negativeSeparatorDisplay.push(negativeSeparator);
if (!negativeSeparator.startsWith(`"`)) {
negativeSeparatorDisplay.unshift(`"`);
}
if (!negativeSeparator.endsWith(`"`)) {
negativeSeparatorDisplay.push(`"`);
}
}
$('#cfg_negative_separator').val(negativeSeparatorDisplay.length === 0 ? '' : negativeSeparatorDisplay.join(''));
$('#cfg_negative_insertion_depth').val(chat_metadata[metadataKeys.negative_insertion_depth] ?? 1);
// Set character CFG if it exists // Set character CFG if it exists
if (!selected_group) { if (!selected_group) {
const charaCfg = extension_settings.cfg.chara.find((e) => e.name === getCharaFilename()); const charaCfg = extension_settings.cfg.chara.find((e) => e.name === getCharaFilename());
@ -273,7 +291,6 @@ jQuery(async () => {
saveSettingsDebounced(); saveSettingsDebounced();
}); });
// TODO: Add negative insertion depth
windowHtml.find('#global_cfg_negative_prompt').on('input', function() { windowHtml.find('#global_cfg_negative_prompt').on('input', function() {
extension_settings.cfg.global.negative_prompt = $(this).val(); extension_settings.cfg.global.negative_prompt = $(this).val();
saveSettingsDebounced(); saveSettingsDebounced();
@ -290,6 +307,16 @@ jQuery(async () => {
saveMetadataDebounced(); saveMetadataDebounced();
}); });
windowHtml.find(`#cfg_negative_insertion_depth`).on('input', function() {
chat_metadata[metadataKeys.negative_insertion_depth] = Number($(this).val());
saveMetadataDebounced();
});
windowHtml.find(`#cfg_negative_separator`).on('input', function() {
chat_metadata[metadataKeys.negative_separator] = $(this).val();
saveMetadataDebounced();
});
windowHtml.find('#groupchat_cfg_use_chara').on('input', function() { windowHtml.find('#groupchat_cfg_use_chara').on('input', function() {
const checked = !!$(this).prop('checked'); const checked = !!$(this).prop('checked');
chat_metadata[metadataKeys.groupchat_individual_chars] = checked chat_metadata[metadataKeys.groupchat_individual_chars] = checked

View File

@ -1,4 +1,4 @@
import { chat_metadata, this_chid } from "../../../script.js"; import { chat_metadata, substituteParams, this_chid } from "../../../script.js";
import { extension_settings, getContext } from "../../extensions.js" import { extension_settings, getContext } from "../../extensions.js"
import { selected_group } from "../../group-chats.js"; import { selected_group } from "../../group-chats.js";
import { getCharaFilename } from "../../utils.js"; import { getCharaFilename } from "../../utils.js";
@ -13,13 +13,14 @@ export const metadataKeys = {
negative_prompt: "cfg_negative_prompt", negative_prompt: "cfg_negative_prompt",
negative_combine: "cfg_negative_combine", negative_combine: "cfg_negative_combine",
groupchat_individual_chars: "cfg_groupchat_individual_chars", groupchat_individual_chars: "cfg_groupchat_individual_chars",
negative_insertion_depth: "cfg_negative_insertion_depth" negative_insertion_depth: "cfg_negative_insertion_depth",
negative_separator: "cfg_negative_separator"
} }
// Gets the CFG value from hierarchy of chat -> character -> global // Gets the CFG value from hierarchy of chat -> character -> global
// Returns undefined values which should be handled in the respective backend APIs // Returns undefined values which should be handled in the respective backend APIs
// TODO: Include a custom negative separator
// TODO: Maybe use existing prompt building/substitution? // TODO: Maybe use existing prompt building/substitution?
// TODO: Insertion depth conflicts with author's note. Shouldn't matter though since CFG is prompt mixing.
export function getCfg(prompt) { export function getCfg(prompt) {
const splitPrompt = prompt?.split("\n") ?? []; const splitPrompt = prompt?.split("\n") ?? [];
let splitNegativePrompt = []; let splitNegativePrompt = [];
@ -28,23 +29,24 @@ export function getCfg(prompt) {
const chatNegativeCombine = chat_metadata[metadataKeys.negative_combine] ?? []; const chatNegativeCombine = chat_metadata[metadataKeys.negative_combine] ?? [];
// If there's a guidance scale, continue. Otherwise assume undefined // If there's a guidance scale, continue. Otherwise assume undefined
// TODO: Run substitute params
if (guidanceScale?.value && guidanceScale?.value !== 1) { if (guidanceScale?.value && guidanceScale?.value !== 1) {
if (guidanceScale.type === cfgType.chat || chatNegativeCombine.includes(cfgType.chat)) { if (guidanceScale.type === cfgType.chat || chatNegativeCombine.includes(cfgType.chat)) {
splitNegativePrompt.push(chat_metadata[metadataKeys.negative_prompt]?.trim()); splitNegativePrompt.unshift(substituteParams(chat_metadata[metadataKeys.negative_prompt])?.trim());
} }
if (guidanceScale.type === cfgType.chara || chatNegativeCombine.includes(cfgType.chara)) { if (guidanceScale.type === cfgType.chara || chatNegativeCombine.includes(cfgType.chara)) {
splitNegativePrompt.push(charaCfg.negative_prompt?.trim()) splitNegativePrompt.unshift(substituteParams(charaCfg.negative_prompt)?.trim())
} }
if (guidanceScale.type === cfgType.global || chatNegativeCombine.includes(cfgType.global)) { if (guidanceScale.type === cfgType.global || chatNegativeCombine.includes(cfgType.global)) {
splitNegativePrompt.push(extension_settings.cfg.global.negative_prompt?.trim()); splitNegativePrompt.unshift(substituteParams(extension_settings.cfg.global.negative_prompt)?.trim());
} }
// TODO: use a custom separator for join // This line is a bit hacky with a JSON.stringify and JSON.parse. Fix this if possible.
const combinedNegatives = splitNegativePrompt.filter((e) => e.length > 0).join("\n"); const negativeSeparator = JSON.parse(chat_metadata[metadataKeys.negative_separator] || JSON.stringify("\n")) ?? "\n";
const combinedNegatives = splitNegativePrompt.filter((e) => e.length > 0).join(negativeSeparator);
const insertionDepth = chat_metadata[metadataKeys.negative_insertion_depth] ?? 1; const insertionDepth = chat_metadata[metadataKeys.negative_insertion_depth] ?? 1;
console.log(insertionDepth)
splitPrompt.splice(splitPrompt.length - insertionDepth, 0, combinedNegatives); splitPrompt.splice(splitPrompt.length - insertionDepth, 0, combinedNegatives);
console.log(`Setting CFG with guidance scale: ${guidanceScale.value}, negatives: ${combinedNegatives}`); console.log(`Setting CFG with guidance scale: ${guidanceScale.value}, negatives: ${combinedNegatives}`);
@ -78,12 +80,3 @@ function getGuidanceScale(charaCfg) {
value: extension_settings.cfg.global.guidance_scale value: extension_settings.cfg.global.guidance_scale
}; };
} }
export function getNegativePrompt(prompt) {
const splitPrompt = prompt.split("\n");
const insertionDepth = chat_metadata[metadataKeys.negative_insertion_depth] ?? 1;
splitPrompt.splice(splitPrompt.length - insertionDepth, 0, "Test negative list");
console.log(splitPrompt);
const negativePrompt = splitPrompt.join("\n");
//console.log(negativePrompt);
}

View File

@ -117,27 +117,39 @@
<div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div> <div class="inline-drawer-icon fa-solid fa-circle-chevron-down down"></div>
</div> </div>
<div class="inline-drawer-content"> <div class="inline-drawer-content">
<small> <div class="flex-container flexFlowColumn">
<b>Combine negative prompts from other boxes.</b> <small>
<br /> <b>Combine negative prompts from other boxes.</b>
For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string. <br />
</small> For example, ticking the chat, global, and character boxes combine all negative prompts into a comma-separated string.
</small>
</div>
<br /> <br />
<label for="cfg_negative_combine"> <div class="flex-container flexFlowColumn">
<span data-i18n="Scale">Always Include</span> <label for="cfg_negative_combine">
</label> <span data-i18n="Scale">Always Include</span>
<label class="checkbox_label"> </label>
<input type="checkbox" name="cfg_negative_combine" value="0" /> <label class="checkbox_label">
<span data-i18n="Chat Negatives">Chat Negatives</span> <input type="checkbox" name="cfg_negative_combine" value="0" />
</label> <span data-i18n="Chat Negatives">Chat Negatives</span>
<label class="checkbox_label"> </label>
<input type="checkbox" name="cfg_negative_combine" value="1" /> <label class="checkbox_label">
<span data-i18n="Character Negatives">Character Negatives</span> <input type="checkbox" name="cfg_negative_combine" value="1" />
</label> <span data-i18n="Character Negatives">Character Negatives</span>
<label class="checkbox_label"> </label>
<input type="checkbox" name="cfg_negative_combine" value="2" /> <label class="checkbox_label">
<span data-i18n="Global Negatives">Global Negatives</span> <input type="checkbox" name="cfg_negative_combine" value="2" />
</label> <span data-i18n="Global Negatives">Global Negatives</span>
</label>
</div>
<div class="flex-container flexFlowColumn">
<label>
Custom Separator: <input id="cfg_negative_separator" class="text_pole textarea_compact widthUnset" placeholder="&quot;\n&quot;" type="text" />
</label>
<label>
Insertion Depth: <input id="cfg_negative_insertion_depth" class="text_pole widthUnset" type="number" min="0" max="99" />
</label>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -410,7 +410,7 @@ export function getNovelGenerationData(finalPrompt, this_settings, this_amount_g
: undefined; : undefined;
const prefix = selectPrefix(nai_settings.prefix, finalPrompt); const prefix = selectPrefix(nai_settings.prefix, finalPrompt);
const cfgSettings = getCfg(); const cfgSettings = getCfg(finalPrompt);
let logitBias = []; let logitBias = [];
if (tokenizerType !== tokenizers.NONE && Array.isArray(nai_settings.logit_bias) && nai_settings.logit_bias.length) { if (tokenizerType !== tokenizers.NONE && Array.isArray(nai_settings.logit_bias) && nai_settings.logit_bias.length) {

View File

@ -235,7 +235,12 @@ async function generateTextGenWithStreaming(generate_data, signal) {
} }
} }
export function getTextGenGenerationData(finalPromt, this_amount_gen, isImpersonate, cfgValues) { export function getTextGenGenerationData(finalPromt, this_amount_gen, isImpersonate) {
let cfgValues = {};
if (!isImpersonate) {
cfgValues = getCfg(finalPromt);
}
return { return {
'prompt': finalPromt, 'prompt': finalPromt,
'max_new_tokens': this_amount_gen, 'max_new_tokens': this_amount_gen,