+
diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js
index 2d4f2bbbf..eb8d75a61 100644
--- a/public/scripts/group-chats.js
+++ b/public/scripts/group-chats.js
@@ -101,6 +101,11 @@ export const group_activation_strategy = {
LIST: 1,
};
+export const group_generation_mode = {
+ SWAP: 0,
+ APPEND: 1,
+}
+
export const groupCandidatesFilter = new FilterHelper(debounce(printGroupCandidates, 100));
const groupAutoModeInterval = setInterval(groupChatAutoModeWorker, 5000);
const saveGroupDebounced = debounce(async (group, reload) => await _save(group, reload), 500);
@@ -922,6 +927,14 @@ async function onGroupActivationStrategyInput(e) {
}
}
+async function onGroupGenerationModeInput(e) {
+ if (openGroupId) {
+ let _thisGroup = groups.find((x) => x.id == openGroupId);
+ _thisGroup.generation_mode = Number(e.target.value);
+ await editGroup(openGroupId, false, false);
+ }
+}
+
async function onGroupNameInput() {
if (openGroupId) {
let _thisGroup = groups.find((x) => x.id == openGroupId);
@@ -1085,12 +1098,16 @@ function select_group_chats(groupId, skipAnimation) {
const group = openGroupId && groups.find((x) => x.id == openGroupId);
const groupName = group?.name ?? "";
const replyStrategy = Number(group?.activation_strategy ?? group_activation_strategy.NATURAL);
+ const generationMode = Number(group?.generation_mode ?? group_generation_mode.DEFAULT);
setMenuType(!!group ? 'group_edit' : 'group_create');
$("#group_avatar_preview").empty().append(getGroupAvatar(group));
$("#rm_group_restore_avatar").toggle(!!group && isValidImageUrl(group.avatar_url));
$("#rm_group_filter").val("").trigger("input");
- $(`input[name="rm_group_activation_strategy"][value="${replyStrategy}"]`).prop('checked', true);
+ $("#rm_group_activation_strategy").val(replyStrategy);
+ $(`#rm_group_activation_strategy option[value="${replyStrategy}"]`).prop('selected', true);
+ $("#rm_group_generation_mode").val(generationMode);
+ $(`#rm_group_generation_mode option[value="${generationMode}"]`).prop('selected', true);
$("#rm_group_chat_name").val(groupName);
if (!skipAnimation) {
@@ -1311,8 +1328,9 @@ function filterGroupMembers() {
async function createGroup() {
let name = $("#rm_group_chat_name").val();
- let allow_self_responses = !!$("#rm_group_allow_self_responses").prop("checked");
- let activation_strategy = $('input[name="rm_group_activation_strategy"]:checked').val() ?? group_activation_strategy.NATURAL;
+ let allowSelfResponses = !!$("#rm_group_allow_self_responses").prop("checked");
+ let activationStrategy = Number($('#rm_group_activation_strategy').find(':selected').val()) ?? group_activation_strategy.NATURAL;
+ let generationMode = Number($('#rm_group_generation_mode').find(':selected').val()) ?? group_generation_mode.SWAP;
const members = newGroupMembers;
const memberNames = characters.filter(x => members.includes(x.avatar)).map(x => x.name).join(", ");
@@ -1332,8 +1350,9 @@ async function createGroup() {
name: name,
members: members,
avatar_url: isValidImageUrl(avatar_url) ? avatar_url : default_avatar,
- allow_self_responses: allow_self_responses,
- activation_strategy: activation_strategy,
+ allow_self_responses: allowSelfResponses,
+ activation_strategy: activationStrategy,
+ generation_mode: generationMode,
disabled_members: [],
chat_metadata: {},
fav: fav_grp_checked,
@@ -1605,7 +1624,8 @@ jQuery(() => {
$("#rm_group_delete").off().on("click", onDeleteGroupClick);
$("#group_favorite_button").on('click', onFavoriteGroupClick);
$("#rm_group_allow_self_responses").on("input", onGroupSelfResponsesClick);
- $('input[name="rm_group_activation_strategy"]').on("input", onGroupActivationStrategyInput);
+ $("#rm_group_activation_strategy").on("change", onGroupActivationStrategyInput);
+ $("#rm_group_generation_mode").on("change", onGroupGenerationModeInput);
$("#group_avatar_button").on("input", uploadGroupAvatar);
$("#rm_group_restore_avatar").on("click", restoreGroupAvatar);
$(document).on("click", ".group_member .right_menu_button", onGroupActionClick);
diff --git a/server.js b/server.js
index dec4ae0a6..94dcc9ace 100644
--- a/server.js
+++ b/server.js
@@ -2573,6 +2573,7 @@ app.post('/creategroup', jsonParser, (request, response) => {
avatar_url: request.body.avatar_url,
allow_self_responses: !!request.body.allow_self_responses,
activation_strategy: request.body.activation_strategy ?? 0,
+ generation_mode: request.body.generation_mode ?? 0,
disabled_members: request.body.disabled_members ?? [],
chat_metadata: request.body.chat_metadata ?? {},
fav: request.body.fav,
From 8dcfe578887f4348212a104672888d9a69fc72aa Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Thu, 26 Oct 2023 00:09:22 +0300
Subject: [PATCH 6/8] #1268 Add group card amalgamation mode
---
public/script.js | 22 +++++++++++----
public/scripts/group-chats.js | 50 ++++++++++++++++++++++++++++++++++-
2 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/public/script.js b/public/script.js
index 5227fb1c6..98708b6c0 100644
--- a/public/script.js
+++ b/public/script.js
@@ -59,6 +59,7 @@ import {
importGroupChat,
getGroupBlock,
getGroupChatNames,
+ getGroupCharacterCards,
} from "./scripts/group-chats.js";
import {
@@ -2036,7 +2037,7 @@ function getExtensionPrompt(position = 0, depth = undefined, separator = "\n") {
return extension_prompt;
}
-function baseChatReplace(value, name1, name2) {
+export function baseChatReplace(value, name1, name2) {
if (value !== undefined && value.length > 0) {
value = substituteParams(value, name1, name2);
@@ -2539,17 +2540,28 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
const scenarioText = chat_metadata['scenario'] || characters[this_chid].scenario;
let charDescription = baseChatReplace(characters[this_chid].description.trim(), name1, name2);
let charPersonality = baseChatReplace(characters[this_chid].personality.trim(), name1, name2);
- let personaDescription = baseChatReplace(power_user.persona_description.trim(), name1, name2);
- let Scenario = baseChatReplace(scenarioText.trim(), name1, name2);
+ let scenario = baseChatReplace(scenarioText.trim(), name1, name2);
let mesExamples = baseChatReplace(characters[this_chid].mes_example.trim(), name1, name2);
let systemPrompt = power_user.prefer_character_prompt ? baseChatReplace(characters[this_chid].data?.system_prompt?.trim(), name1, name2) : '';
let jailbreakPrompt = power_user.prefer_character_jailbreak ? baseChatReplace(characters[this_chid].data?.post_history_instructions?.trim(), name1, name2) : '';
+ let personaDescription = baseChatReplace(power_user.persona_description.trim(), name1, name2);
if (isInstruct) {
systemPrompt = power_user.prefer_character_prompt && systemPrompt ? systemPrompt : baseChatReplace(power_user.instruct.system_prompt, name1, name2);
systemPrompt = formatInstructModeSystemPrompt(substituteParams(systemPrompt, name1, name2, power_user.instruct.system_prompt));
}
+ if (selected_group) {
+ const groupCards = getGroupCharacterCards(selected_group);
+
+ if (groupCards) {
+ charDescription = groupCards.description;
+ charPersonality = groupCards.personality;
+ scenario = groupCards.scenario;
+ mesExamples = groupCards.mesExample;
+ }
+ }
+
// Depth prompt (character-specific A/N)
const depthPromptText = baseChatReplace(characters[this_chid].data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2) || '';
const depthPromptDepth = characters[this_chid].data?.extensions?.depth_prompt?.depth ?? depth_prompt_depth_default;
@@ -2682,7 +2694,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
description: charDescription,
personality: charPersonality,
persona: personaDescription,
- scenario: Scenario,
+ scenario: scenario,
system: isInstruct ? systemPrompt : '',
char: name2,
user: name1,
@@ -3112,7 +3124,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
name2: name2,
charDescription: charDescription,
charPersonality: charPersonality,
- Scenario: Scenario,
+ Scenario: scenario,
worldInfoBefore: worldInfoBefore,
worldInfoAfter: worldInfoAfter,
extensionPrompts: extension_prompts,
diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js
index eb8d75a61..bcf985276 100644
--- a/public/scripts/group-chats.js
+++ b/public/scripts/group-chats.js
@@ -66,6 +66,7 @@ import {
system_avatar,
isChatSaving,
setExternalAbortController,
+ baseChatReplace,
} from "../script.js";
import { appendTagToList, createTagMapFromList, getTagsList, applyTagsOnCharacterSelect, tag_map, printTagFilters } from './tags.js';
import { FILTER_TYPES, FilterHelper } from './filters.js';
@@ -198,6 +199,53 @@ export async function getGroupChat(groupId) {
eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId());
}
+/**
+ * Combines group members info a single string. Only for groups with generation mode set to APPEND.
+ * @param {string} groupId Group ID
+ * @returns {{description: string, personality: string, scenario: string, mesExample: string}} Group character cards combined
+ */
+export function getGroupCharacterCards(groupId) {
+ console.debug('getGroupCharacterCards entered for group: ', groupId);
+ const group = groups.find(x => x.id === groupId);
+
+ if (!group || group?.generation_mode !== group_generation_mode.APPEND || !Array.isArray(group.members) || !group.members.length) {
+ return null;
+ }
+
+ const scenarioOverride = chat_metadata['scenario'];
+
+ let descriptions = [];
+ let personalities = [];
+ let scenarios = [];
+ let mesExamples = [];
+
+ for (const member of group.members) {
+ if (group.disabled_members.includes(member)) {
+ console.debug(`Skipping disabled group member: ${member}`);
+ continue;
+ }
+
+ const character = characters.find(x => x.avatar === member);
+
+ if (!character) {
+ console.debug(`Skipping missing member: ${member}`);
+ continue;
+ }
+
+ descriptions.push(baseChatReplace(character.description.trim(), name1, character.name));
+ personalities.push(baseChatReplace(character.personality.trim(), name1, character.name));
+ scenarios.push(baseChatReplace(character.scenario.trim(), name1, character.name));
+ mesExamples.push(baseChatReplace(character.mes_example.trim(), name1, character.name));
+ }
+
+ const description = descriptions.join('\n');
+ const personality = personalities.join('\n');
+ const scenario = scenarioOverride?.trim() || scenarios.join('\n');
+ const mesExample = mesExamples.join('\n');
+
+ return { description, personality, scenario, mesExample };
+}
+
function getFirstCharacterMessage(character) {
let messageText = character.first_mes;
@@ -1098,7 +1146,7 @@ function select_group_chats(groupId, skipAnimation) {
const group = openGroupId && groups.find((x) => x.id == openGroupId);
const groupName = group?.name ?? "";
const replyStrategy = Number(group?.activation_strategy ?? group_activation_strategy.NATURAL);
- const generationMode = Number(group?.generation_mode ?? group_generation_mode.DEFAULT);
+ const generationMode = Number(group?.generation_mode ?? group_generation_mode.SWAP);
setMenuType(!!group ? 'group_edit' : 'group_create');
$("#group_avatar_preview").empty().append(getGroupAvatar(group));
From 5cdc3d1d186fdb175813becbc24b7636af18c480 Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Thu, 26 Oct 2023 00:39:11 +0300
Subject: [PATCH 7/8] Smudge groups depth prompts in Join mode.
---
public/script.js | 30 +++++++++++++++++++---
public/scripts/group-chats.js | 48 +++++++++++++++++++++++++++++++++++
public/scripts/world-info.js | 12 ++++++---
3 files changed, 82 insertions(+), 8 deletions(-)
diff --git a/public/script.js b/public/script.js
index 98708b6c0..6284f35dd 100644
--- a/public/script.js
+++ b/public/script.js
@@ -60,6 +60,7 @@ import {
getGroupBlock,
getGroupChatNames,
getGroupCharacterCards,
+ getGroupDepthPrompts,
} from "./scripts/group-chats.js";
import {
@@ -599,7 +600,7 @@ function getCurrentChatId() {
}
const talkativeness_default = 0.5;
-const depth_prompt_depth_default = 4;
+export const depth_prompt_depth_default = 4;
const per_page_default = 50;
var is_advanced_char_open = false;
@@ -2563,9 +2564,18 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
}
// Depth prompt (character-specific A/N)
- const depthPromptText = baseChatReplace(characters[this_chid].data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2) || '';
- const depthPromptDepth = characters[this_chid].data?.extensions?.depth_prompt?.depth ?? depth_prompt_depth_default;
- setExtensionPrompt('DEPTH_PROMPT', depthPromptText, extension_prompt_types.IN_CHAT, depthPromptDepth);
+ removeDepthPrompts();
+ const groupDepthPrompts = getGroupDepthPrompts(selected_group);
+
+ if (selected_group && Array.isArray(groupDepthPrompts) && groupDepthPrompts.length > 0) {
+ groupDepthPrompts.forEach((value, index) => {
+ setExtensionPrompt('DEPTH_PROMPT_' + index, value.text, extension_prompt_types.IN_CHAT, value.depth);
+ });
+ } else {
+ const depthPromptText = baseChatReplace(characters[this_chid].data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2) || '';
+ const depthPromptDepth = characters[this_chid].data?.extensions?.depth_prompt?.depth ?? depth_prompt_depth_default;
+ setExtensionPrompt('DEPTH_PROMPT', depthPromptText, extension_prompt_types.IN_CHAT, depthPromptDepth);
+ }
// Parse example messages
if (!mesExamples.startsWith('
')) {
@@ -5762,6 +5772,18 @@ export function setExtensionPrompt(key, value, position, depth) {
extension_prompts[key] = { value: String(value), position: Number(position), depth: Number(depth) };
}
+/**
+ * Removes all char A/N prompt injections from the chat.
+ * To clean up when switching from groups to solo and vice versa.
+ */
+export function removeDepthPrompts() {
+ for (const key of Object.keys(extension_prompts)) {
+ if (key.startsWith('DEPTH_PROMPT')) {
+ delete extension_prompts[key];
+ }
+ }
+}
+
/**
* Adds or updates the metadata for the currently active chat.
* @param {Object} newValues An object with collection of new values to be added into the metadata.
diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js
index bcf985276..84d5bfa93 100644
--- a/public/scripts/group-chats.js
+++ b/public/scripts/group-chats.js
@@ -67,6 +67,7 @@ import {
isChatSaving,
setExternalAbortController,
baseChatReplace,
+ depth_prompt_depth_default,
} from "../script.js";
import { appendTagToList, createTagMapFromList, getTagsList, applyTagsOnCharacterSelect, tag_map, printTagFilters } from './tags.js';
import { FILTER_TYPES, FilterHelper } from './filters.js';
@@ -199,6 +200,53 @@ export async function getGroupChat(groupId) {
eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId());
}
+/**
+ * Gets depth prompts for group members.
+ * @param {string} groupId Group ID
+ * @returns {{depth: number, text: string}[]} Array of depth prompts
+ */
+export function getGroupDepthPrompts(groupId) {
+ if (!groupId) {
+ return [];
+ }
+
+ console.debug('getGroupDepthPrompts entered for group: ', groupId);
+ const group = groups.find(x => x.id === groupId);
+
+ if (!group || !Array.isArray(group.members) || !group.members.length) {
+ return [];
+ }
+
+ if (group.generation_mode === group_generation_mode.SWAP) {
+ return [];
+ }
+
+ const depthPrompts = [];
+
+ for (const member of group.members) {
+ if (group.disabled_members.includes(member)) {
+ console.debug(`Skipping disabled group member: ${member}`);
+ continue;
+ }
+
+ const character = characters.find(x => x.avatar === member);
+
+ if (!character) {
+ console.debug(`Skipping missing member: ${member}`);
+ continue;
+ }
+
+ const depthPromptText = baseChatReplace(character.data?.extensions?.depth_prompt?.prompt?.trim(), name1, character.name) || '';
+ const depthPromptDepth = character.data?.extensions?.depth_prompt?.depth ?? depth_prompt_depth_default;
+
+ if (depthPromptText) {
+ depthPrompts.push({ text: depthPromptText, depth: depthPromptDepth });
+ }
+ }
+
+ return depthPrompts;
+}
+
/**
* Combines group members info a single string. Only for groups with generation mode set to APPEND.
* @param {string} groupId Group ID
diff --git a/public/scripts/world-info.js b/public/scripts/world-info.js
index fd16fa7d7..fcff2a57c 100644
--- a/public/scripts/world-info.js
+++ b/public/scripts/world-info.js
@@ -1383,12 +1383,16 @@ async function checkWorldInfo(chat, maxContext) {
// Add the depth or AN if enabled
// Put this code here since otherwise, the chat reference is modified
if (extension_settings.note.allowWIScan) {
- let depthPrompt = getExtensionPromptByName("DEPTH_PROMPT")
- if (depthPrompt) {
- textToScan = `${depthPrompt}\n${textToScan}`
+ for (const key of Object.keys(context.extensionPrompts)) {
+ if (key.startsWith('DEPTH_PROMPT')) {
+ const depthPrompt = getExtensionPromptByName(key)
+ if (depthPrompt) {
+ textToScan = `${depthPrompt}\n${textToScan}`
+ }
+ }
}
- let anPrompt = getExtensionPromptByName(NOTE_MODULE_NAME);
+ const anPrompt = getExtensionPromptByName(NOTE_MODULE_NAME);
if (anPrompt) {
textToScan = `${anPrompt}\n${textToScan}`
}
From 339dcaf5063d5c4817b058382bea990658818e72 Mon Sep 17 00:00:00 2001
From: Cohee <18619528+Cohee1207@users.noreply.github.com>
Date: Thu, 26 Oct 2023 02:10:14 +0300
Subject: [PATCH 8/8] Fix message trigger on disabled character in amalgamate
group mode
---
public/script.js | 4 ++--
public/scripts/group-chats.js | 32 ++++++++++++++++++--------------
2 files changed, 20 insertions(+), 16 deletions(-)
diff --git a/public/script.js b/public/script.js
index 6284f35dd..b8bcbdfd9 100644
--- a/public/script.js
+++ b/public/script.js
@@ -2553,7 +2553,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
}
if (selected_group) {
- const groupCards = getGroupCharacterCards(selected_group);
+ const groupCards = getGroupCharacterCards(selected_group, Number(this_chid));
if (groupCards) {
charDescription = groupCards.description;
@@ -2565,7 +2565,7 @@ async function Generate(type, { automatic_trigger, force_name2, resolve, reject,
// Depth prompt (character-specific A/N)
removeDepthPrompts();
- const groupDepthPrompts = getGroupDepthPrompts(selected_group);
+ const groupDepthPrompts = getGroupDepthPrompts(selected_group, Number(this_chid));
if (selected_group && Array.isArray(groupDepthPrompts) && groupDepthPrompts.length > 0) {
groupDepthPrompts.forEach((value, index) => {
diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js
index 84d5bfa93..b22577959 100644
--- a/public/scripts/group-chats.js
+++ b/public/scripts/group-chats.js
@@ -203,9 +203,10 @@ export async function getGroupChat(groupId) {
/**
* Gets depth prompts for group members.
* @param {string} groupId Group ID
+ * @param {number} characterId Current Character ID
* @returns {{depth: number, text: string}[]} Array of depth prompts
*/
-export function getGroupDepthPrompts(groupId) {
+export function getGroupDepthPrompts(groupId, characterId) {
if (!groupId) {
return [];
}
@@ -224,15 +225,16 @@ export function getGroupDepthPrompts(groupId) {
const depthPrompts = [];
for (const member of group.members) {
- if (group.disabled_members.includes(member)) {
- console.debug(`Skipping disabled group member: ${member}`);
+ const index = characters.findIndex(x => x.avatar === member);
+ const character = characters[index];
+
+ if (index === -1 || !character) {
+ console.debug(`Skipping missing member: ${member}`);
continue;
}
- const character = characters.find(x => x.avatar === member);
-
- if (!character) {
- console.debug(`Skipping missing member: ${member}`);
+ if (group.disabled_members.includes(member) && characterId !== index) {
+ console.debug(`Skipping disabled group member: ${member}`);
continue;
}
@@ -250,9 +252,10 @@ export function getGroupDepthPrompts(groupId) {
/**
* Combines group members info a single string. Only for groups with generation mode set to APPEND.
* @param {string} groupId Group ID
+ * @param {number} characterId Current Character ID
* @returns {{description: string, personality: string, scenario: string, mesExample: string}} Group character cards combined
*/
-export function getGroupCharacterCards(groupId) {
+export function getGroupCharacterCards(groupId, characterId) {
console.debug('getGroupCharacterCards entered for group: ', groupId);
const group = groups.find(x => x.id === groupId);
@@ -268,15 +271,16 @@ export function getGroupCharacterCards(groupId) {
let mesExamples = [];
for (const member of group.members) {
- if (group.disabled_members.includes(member)) {
- console.debug(`Skipping disabled group member: ${member}`);
+ const index = characters.findIndex(x => x.avatar === member);
+ const character = characters[index];
+
+ if (index === -1 || !character) {
+ console.debug(`Skipping missing member: ${member}`);
continue;
}
- const character = characters.find(x => x.avatar === member);
-
- if (!character) {
- console.debug(`Skipping missing member: ${member}`);
+ if (group.disabled_members.includes(member) && characterId !== index) {
+ console.debug(`Skipping disabled group member: ${member}`);
continue;
}