diff --git a/public/script.js b/public/script.js
index dbc83d23a..2b4b5d65e 100644
--- a/public/script.js
+++ b/public/script.js
@@ -42,6 +42,11 @@ import {
getGroupChat,
renameGroupMember,
createNewGroupChat,
+ getGroupPastChats,
+ getGroupAvatar,
+ openGroupChat,
+ editGroup,
+ deleteGroupChat,
} from "./scripts/group-chats.js";
import {
@@ -852,20 +857,10 @@ async function delChat(chatfile) {
}),
});
if (response.ok === true) {
- //close past chat popup
- $("#select_chat_cross").click();
-
// choose another chat if current was deleted
if (chatfile.replace('.jsonl', '') === characters[this_chid].chat) {
await replaceCurrentChat();
}
-
- //open the history view again after 100ms
- //hide option popup menu
- setTimeout(function () {
- $("#option_select_chat").click();
- $("#options").hide();
- }, 100);
}
}
@@ -2707,8 +2702,6 @@ async function openCharacterChat(file_name) {
await getChat();
$("#selected_chat_pole").val(file_name);
$("#create_button").click();
- $("#shadow_select_chat_popup").css("display", "none");
- $("#load_select_chat_div").css("display", "block");
}
////////// OPTIMZED MAIN API CHANGE FUNCTION ////////////
@@ -3164,67 +3157,63 @@ function messageEditDone(div) {
saveChatConditional();
}
-async function getAllCharaChats() {
- //console.log('getAllCharaChats() pinging server for character chat history.');
- $("#select_chat_div").html("");
- //console.log(characters[this_chid].chat);
- jQuery.ajax({
- type: "POST",
- url: "/getallchatsofcharacter",
- data: JSON.stringify({ avatar_url: characters[this_chid].avatar }),
- beforeSend: function () {
-
- },
- cache: false,
- dataType: "json",
- contentType: "application/json",
- success: function (data) {
- $("#load_select_chat_div").css("display", "none");
- let dataArr = Object.values(data);
- data = dataArr.sort((a, b) =>
- a["file_name"].localeCompare(b["file_name"])
- );
- data = data.reverse();
- $("#ChatHistoryCharName").html(characters[this_chid].name);
- for (const key in data) {
- let strlen = 300;
- let mes = data[key]["mes"];
- if (mes !== undefined) {
- if (mes.length > strlen) {
- mes = "..." + mes.substring(mes.length - strlen);
- }
- $("#select_chat_div").append(
- '
' +
- '
' +
- '
' +
- '
' + data[key]["file_name"] + '
' +
- '
' +
- mes +
- "
" +
- "
" +
- '
' +
- '
'
-
-
- );
- if (
- characters[this_chid]["chat"] ==
- data[key]["file_name"].replace(".jsonl", "")
- ) {
- //children().last()
- $("#select_chat_div")
- .find(".select_chat_block:last")
- .attr("highlight", true);
- }
- }
- }
- },
- error: function (jqXHR, exception) {
-
- console.log(exception);
- console.log(jqXHR);
- },
+async function getPastCharacterChats() {
+ const response = await fetch("/getallchatsofcharacter", {
+ method: 'POST',
+ body: JSON.stringify({ avatar_url: characters[this_chid].avatar }),
+ headers: getRequestHeaders(),
});
+
+ if (!response.ok) {
+ return;
+ }
+
+ let data = await response.json();
+ data = Object.values(data);
+ data = data.sort((a, b) => a["file_name"].localeCompare(b["file_name"])).reverse();
+ return data;
+}
+
+async function displayPastChats() {
+ $("#select_chat_div").empty();
+
+ const group = selected_group ? groups.find(x => x.id === selected_group) : null;
+ const data = await (selected_group ? getGroupPastChats(selected_group) : getPastCharacterChats());
+ const currentChat = selected_group ? group?.chat_id : characters[this_chid]["chat"];
+ const displayName = selected_group ? group?.name : characters[this_chid].name;
+ const avatarImg = selected_group ? group?.avatar_url : getThumbnailUrl('avatar', characters[this_chid]['avatar']);
+
+ $("#load_select_chat_div").css("display", "none");
+ $("#ChatHistoryCharName").text(displayName);
+
+ for (const key in data) {
+ let strlen = 300;
+ let mes = data[key]["mes"];
+
+ if (mes !== undefined) {
+ if (mes.length > strlen) {
+ mes = "..." + mes.substring(mes.length - strlen);
+ }
+
+ const fileName = data[key]['file_name'];
+ const template = $('#past_chat_template .select_chat_block_wrapper').clone();
+ template.find('.select_chat_block').attr('file_name', fileName);
+ template.find('.avatar img').attr('src', avatarImg);
+ template.find('.select_chat_block_filename').text(fileName);
+ template.find('.select_chat_block_mes').text(mes);
+ template.find('.PastChat_cross').attr('file_name', fileName);
+
+ if (selected_group) {
+ template.find('.avatar img').replaceWith(getGroupAvatar(group));
+ }
+
+ $("#select_chat_div").append(template);
+
+ if (currentChat === fileName.replace(".jsonl", "")) {
+ $("#select_chat_div").find(".select_chat_block:last").attr("highlight", true);
+ }
+ }
+ }
}
//************************************************************
@@ -3542,6 +3531,10 @@ function read_bg_load(input) {
}
function showSwipeButtons() {
+ if (chat.length === 0) {
+ return;
+ }
+
if (
chat[chat.length - 1].is_system ||
!swipes ||
@@ -3592,12 +3585,21 @@ function hideSwipeButtons() {
$("#chat").children().filter(`[mesid="${count_view_mes - 1}"]`).children('.swipe_left').css('display', 'none');
}
-function saveChatConditional() {
+async function saveMetadata() {
if (selected_group) {
- saveGroupChat(selected_group);
+ await editGroup(selected_group, true, false);
}
else {
- saveChat();
+ await saveChat();
+ }
+}
+
+async function saveChatConditional() {
+ if (selected_group) {
+ await saveGroupChat(selected_group, true);
+ }
+ else {
+ await saveChat();
}
}
@@ -3681,6 +3683,7 @@ window["SillyTavern"].getContext = function () {
setExtensionPrompt: setExtensionPrompt,
updateChatMetadata: updateChatMetadata,
saveChat: saveChatConditional,
+ saveMetadata: saveMetadata,
sendSystemMessage: sendSystemMessage,
activateSendButtons,
deactivateSendButtons,
@@ -4226,7 +4229,7 @@ $(document).ready(function () {
is_advanced_char_open = false;
$("#character_popup").css("display", "none");
});
- $("#dialogue_popup_ok").click(function (e) {
+ $("#dialogue_popup_ok").click(async function (e) {
$("#shadow_popup").transition({
opacity: 0,
duration: 200,
@@ -4239,9 +4242,21 @@ $(document).ready(function () {
bg_file_for_del.parent().remove();
}
if (popup_type == "del_chat") {
+ //close past chat popup
+ $("#select_chat_cross").click();
- delChat(chat_file_for_del);
+ if (selected_group) {
+ await deleteGroupChat(selected_group, chat_file_for_del);
+ } else {
+ await delChat(chat_file_for_del);
+ }
+ //open the history view again after 100ms
+ //hide option popup menu
+ setTimeout(function () {
+ $("#option_select_chat").click();
+ $("#options").hide();
+ }, 100);
}
if (popup_type == "del_ch") {
console.log(
@@ -4312,7 +4327,7 @@ $(document).ready(function () {
chat.length = 0;
if (selected_group) {
- createNewGroupChat();
+ createNewGroupChat(selected_group);
}
else {
//RossAscends: added character name to new chat filenames and replaced Date.now() with humanizedDateTime;
@@ -4652,14 +4667,8 @@ $(document).ready(function () {
$("#options [id]").on("click", function () {
var id = $(this).attr("id");
if (id == "option_select_chat") {
- if (selected_group) {
- // will open a chat selection screen
- /* openNavToggle(); */
- $("#rm_button_characters").trigger("click");
- return;
- }
- if (this_chid != undefined && !is_send_press) {
- getAllCharaChats();
+ if ((selected_group && !is_group_generating) || (this_chid !== undefined && !is_send_press)) {
+ displayPastChats();
$("#shadow_select_chat_popup").css("display", "block");
$("#shadow_select_chat_popup").css("opacity", 0.0);
$("#shadow_select_chat_popup").transition({
@@ -5266,7 +5275,7 @@ $(document).ready(function () {
success: function (data) {
//console.log(data);
if (data.res) {
- getAllCharaChats();
+ displayPastChats();
}
},
error: function (jqXHR, exception) {
@@ -5287,7 +5296,15 @@ $(document).ready(function () {
$(document).on("click", ".select_chat_block, .bookmark_link", async function () {
let file_name = $(this).attr("file_name").replace(".jsonl", "");
- openCharacterChat(file_name);
+
+ if (selected_group) {
+ await openGroupChat(selected_group, file_name);
+ } else {
+ await openCharacterChat(file_name);
+ }
+
+ $("#shadow_select_chat_popup").css("display", "none");
+ $("#load_select_chat_div").css("display", "block");
});
$(document).on("click", ".mes_stop", function () {
diff --git a/public/scripts/extensions/backgrounds/index.js b/public/scripts/extensions/backgrounds/index.js
index 5363b1113..e9a1c541d 100644
--- a/public/scripts/extensions/backgrounds/index.js
+++ b/public/scripts/extensions/backgrounds/index.js
@@ -51,13 +51,13 @@ function hasCustomBackground() {
function saveBackgroundMetadata(file) {
const context = getContext();
context.chatMetadata[METADATA_KEY] = file;
- context.saveChat();
+ context.saveMetadata();
}
function removeBackgroundMetadata() {
const context = getContext();
delete context.chatMetadata[METADATA_KEY];
- context.saveChat();
+ context.saveMetadata();
}
function setCustomBackground() {
diff --git a/public/scripts/extensions/floating-prompt/index.js b/public/scripts/extensions/floating-prompt/index.js
index da8563777..c1fc3d87b 100644
--- a/public/scripts/extensions/floating-prompt/index.js
+++ b/public/scripts/extensions/floating-prompt/index.js
@@ -3,7 +3,7 @@ import { extension_settings, getContext } from "../../extensions.js";
import { debounce } from "../../utils.js";
export { MODULE_NAME };
-const saveChatDebounced = debounce(async () => await getContext().saveChat(), 1000);
+const saveMetadataDebounced = debounce(async () => await getContext().saveMetadata(), 1000);
const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory
const UPDATE_INTERVAL = 1000;
@@ -21,12 +21,12 @@ const metadata_keys = {
async function onExtensionFloatingPromptInput() {
chat_metadata[metadata_keys.prompt] = $(this).val();
- saveChatDebounced();
+ saveMetadataDebounced();
}
async function onExtensionFloatingIntervalInput() {
chat_metadata[metadata_keys.interval] = Number($(this).val());
- saveChatDebounced();
+ saveMetadataDebounced();
}
async function onExtensionFloatingDepthInput() {
@@ -38,12 +38,12 @@ async function onExtensionFloatingDepthInput() {
}
chat_metadata[metadata_keys.depth] = value;
- saveChatDebounced();
+ saveMetadataDebounced();
}
async function onExtensionFloatingPositionInput(e) {
chat_metadata[metadata_keys.position] = e.target.value;
- saveChatDebounced();
+ saveMetadataDebounced();
}
function onExtensionFloatingDefaultInput() {
diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js
index 639fe6b1d..4cbefd100 100644
--- a/public/scripts/group-chats.js
+++ b/public/scripts/group-chats.js
@@ -81,16 +81,17 @@ export const group_activation_strategy = {
const groupAutoModeInterval = setInterval(groupChatAutoModeWorker, 5000);
const saveGroupDebounced = debounce(async (group) => await _save(group), 500);
-async function _save(group) {
+async function _save(group, reload = true) {
await fetch("/editgroup", {
method: "POST",
headers: getRequestHeaders(),
body: JSON.stringify(group),
});
- await getCharacters();
+ if (reload) {
+ await getCharacters();
+ }
}
-
// Group chats
async function regenerateGroup() {
let generationId = getLastMessageGenerationId();
@@ -114,47 +115,55 @@ async function regenerateGroup() {
generateGroupWrapper();
}
-export async function getGroupChat(groupId) {
- const group = groups.find((x) => x.id === groupId);
- const chat_id = group.chat_id;
+async function loadGroupChat(chatId) {
const response = await fetch("/getgroupchat", {
method: "POST",
headers: getRequestHeaders(),
- body: JSON.stringify({ id: chat_id }),
+ body: JSON.stringify({ id: chatId }),
});
if (response.ok) {
const data = await response.json();
- if (Array.isArray(data) && data.length) {
- data[0].is_group = true;
- for (let key of data) {
- chat.push(key);
- }
- printMessages();
- } else {
- sendSystemMessage(system_message_types.GROUP);
- if (group && Array.isArray(group.members)) {
- for (let member of group.members) {
- const character = characters.find(x => x.avatar === member || x.name === member);
-
- if (!character) {
- continue;
- }
-
- const mes = getFirstCharacterMessage(character);
- chat.push(mes);
- addOneMessage(mes);
- }
- }
- }
-
- if (group) {
- let metadata = group.chat_metadata ?? {};
- updateChatMetadata(metadata, true);
- }
-
- await saveGroupChat(groupId, true);
+ return data;
}
+
+ return [];
+}
+
+export async function getGroupChat(groupId) {
+ const group = groups.find((x) => x.id === groupId);
+ const chat_id = group.chat_id;
+ const data = await loadGroupChat(chat_id);
+
+ if (Array.isArray(data) && data.length) {
+ data[0].is_group = true;
+ for (let key of data) {
+ chat.push(key);
+ }
+ printMessages();
+ } else {
+ sendSystemMessage(system_message_types.GROUP);
+ if (group && Array.isArray(group.members)) {
+ for (let member of group.members) {
+ const character = characters.find(x => x.avatar === member || x.name === member);
+
+ if (!character) {
+ continue;
+ }
+
+ const mes = getFirstCharacterMessage(character);
+ chat.push(mes);
+ addOneMessage(mes);
+ }
+ }
+ }
+
+ if (group) {
+ let metadata = group.chat_metadata ?? {};
+ updateChatMetadata(metadata, true);
+ }
+
+ await saveGroupChat(groupId, true);
}
function getFirstCharacterMessage(character) {
@@ -197,7 +206,6 @@ export async function renameGroupMember(oldAvatar, newAvatar, newName) {
// Scan every group for our renamed character
for (const group of groups) {
try {
-
// Try finding the member by old avatar link
const memberIndex = group.members.findIndex(x => x == oldAvatar);
@@ -213,33 +221,26 @@ export async function renameGroupMember(oldAvatar, newAvatar, newName) {
// Load all chats from this group
for (const chatId of group.chats) {
- const getChatResponse = await fetch("/getgroupchat", {
- method: "POST",
- headers: getRequestHeaders(),
- body: JSON.stringify({ id: chatId }),
- });
+ const messages = await loadGroupChat(chatId);
- if (getChatResponse.ok) {
- // Only save the chat if there were any changes to the chat content
- let hadChanges = false;
- const messages = await getChatResponse.json();
- // Chat shouldn't be empty
- if (Array.isArray(messages) && messages.length) {
- // Iterate over every chat message
- for (const message of messages) {
- // Only look at character messages
- if (message.is_user || message.is_system) {
- continue;
- }
+ // Only save the chat if there were any changes to the chat content
+ let hadChanges = false;
+ // Chat shouldn't be empty
+ if (Array.isArray(messages) && messages.length) {
+ // Iterate over every chat message
+ for (const message of messages) {
+ // Only look at character messages
+ if (message.is_user || message.is_system) {
+ continue;
+ }
- // Message belonged to the old-named character:
- // Update name, avatar thumbnail URL and original avatar link
- if (message.force_avatar && message.force_avatar.indexOf(encodeURIComponent(oldAvatar)) !== -1) {
- message.name = newName;
- message.force_avatar = message.force_avatar.replace(encodeURIComponent(oldAvatar), encodeURIComponent(newAvatar));
- message.original_avatar = newAvatar;
- hadChanges = true;
- }
+ // Message belonged to the old-named character:
+ // Update name, avatar thumbnail URL and original avatar link
+ if (message.force_avatar && message.force_avatar.indexOf(encodeURIComponent(oldAvatar)) !== -1) {
+ message.name = newName;
+ message.force_avatar = message.force_avatar.replace(encodeURIComponent(oldAvatar), encodeURIComponent(newAvatar));
+ message.original_avatar = newAvatar;
+ hadChanges = true;
}
}
@@ -284,6 +285,9 @@ async function getGroups() {
.filter(x => x)
.filter(onlyUnique)
}
+ if (group.past_metadata == undefined) {
+ group.past_metadata = {};
+ }
}
}
}
@@ -696,16 +700,17 @@ async function deleteGroup(id) {
}
}
-async function editGroup(id, immediately) {
- let group = groups.find((x) => x.id == id);
- group = { ...group, chat_metadata };
+export async function editGroup(id, immediately, reload=true) {
+ let group = groups.find((x) => x.id === id);
if (!group) {
return;
}
+ group['chat_metadata'] = chat_metadata;
+
if (immediately) {
- return await _save(group);
+ return await _save(group, reload);
}
saveGroupDebounced(group);
@@ -1077,8 +1082,8 @@ function filterMembersByFavorites(value) {
}
}
-export async function createNewGroupChat() {
- const group = groups.find(x => x.id === selected_group);
+export async function createNewGroupChat(groupId) {
+ const group = groups.find(x => x.id === groupId);
if (!group) {
return;
@@ -1091,7 +1096,11 @@ export async function createNewGroupChat() {
group.past_metadata = {};
}
- group.past_metadata[oldChatName] = Object.assign({}, chat_metadata);
+ clearChat();
+ chat.length = 0;
+ if (oldChatName) {
+ group.past_metadata[oldChatName] = Object.assign({}, chat_metadata);
+ }
group.chats.push(newChatName);
group.chat_id = newChatName;
group.chat_metadata = {};
@@ -1101,6 +1110,76 @@ export async function createNewGroupChat() {
await getGroupChat(group.id);
}
+export async function getGroupPastChats(groupId) {
+ const group = groups.find(x => x.id === groupId);
+
+ if (!group) {
+ return [];
+ }
+
+ const chats = [];
+
+ try {
+ for (const chatId of group.chats) {
+ const messages = await loadGroupChat(chatId);
+ const lastMessage = messages.length ? messages[messages.length - 1].mes : '[The chat is empty]';
+ chats.push({ 'file_name': chatId, 'mes': lastMessage });
+ }
+ } catch (err) {
+ console.error(err);
+ }
+ finally {
+ return chats;
+ }
+}
+
+export async function openGroupChat(groupId, chatId) {
+ const group = groups.find(x => x.id === groupId);
+
+ if (!group || !group.chats.includes(chatId)) {
+ return;
+ }
+
+ clearChat();
+ chat.length = 0;
+ const previousChat = group.chat_id;
+ group.past_metadata[previousChat] = Object.assign({}, chat_metadata);
+ group.chat_id = chatId;
+ group.chat_metadata = group.past_metadata[chatId] || {};
+ updateChatMetadata(group.chat_metadata, true);
+
+ await editGroup(groupId, true);
+ await getGroupChat(groupId);
+}
+
+export async function deleteGroupChat(groupId, chatId) {
+ const group = groups.find(x => x.id === groupId);
+
+ if (!group || !group.chats.includes(chatId)) {
+ return;
+ }
+
+ group.chats.splice(group.chats.indexOf(chatId), 1);
+ group.chat_metadata = {};
+ group.chat_id = '';
+ delete group.past_metadata[chatId];
+ updateChatMetadata(group.chat_metadata, true);
+
+ const response = await fetch('/deletegroupchat', {
+ method: 'POST',
+ headers: getRequestHeaders(),
+ body: JSON.stringify({ id: chatId }),
+ });
+
+ if (response.ok) {
+ if (group.chats.length) {
+ await openGroupChat(groupId, group.chats[0]);
+ } else {
+ await createNewGroupChat(groupId);
+ }
+ }
+}
+
$(document).ready(() => {
$(document).on("click", ".group_select", selectGroup);
$("#rm_group_filter").on("input", filterGroupMembers);
diff --git a/server.js b/server.js
index c0df4c220..66baa5087 100644
--- a/server.js
+++ b/server.js
@@ -1381,22 +1381,19 @@ app.post("/getallchatsofcharacter", jsonParser, function (request, response) {
lastLine = line;
});
rl.on('close', () => {
+ ii--;
if (lastLine) {
let jsonData = json5.parse(lastLine);
- if (jsonData.name !== undefined) {
+ if (jsonData.name !== undefined || jsonData.character_name !== undefined) {
chatData[i] = {};
chatData[i]['file_name'] = file;
- chatData[i]['mes'] = jsonData['mes'];
- ii--;
- if (ii === 0) {
- console.log('ii count went to zero, responding with chatData');
- response.send(chatData);
- }
- } else {
- console.log('just returning from getallchatsofcharacter');
- return;
+ chatData[i]['mes'] = jsonData['mes'] || '[The chat is empty]';
}
}
+ if (ii === 0) {
+ console.log('ii count went to zero, responding with chatData');
+ response.send(chatData);
+ }
console.log('successfully closing getallchatsofcharacter');
rl.close();
});
@@ -1794,6 +1791,22 @@ app.post('/getgroupchat', jsonParser, (request, response) => {
}
});
+app.post('/deletegroupchat', jsonParser, (request, response) => {
+ if (!request.body || !request.body.id) {
+ return response.sendStatus(400);
+ }
+
+ const id = request.body.id;
+ const pathToFile = path.join(directories.groupChats, `${id}.jsonl`);
+
+ if (fs.existsSync(pathToFile)) {
+ fs.rmSync(pathToFile);
+ return response.send({ ok: true });
+ }
+
+ return response.send({ error: true });
+});
+
app.post('/savegroupchat', jsonParser, (request, response) => {
if (!request.body || !request.body.id) {
return response.sendStatus(400);