Support multiple chats per group. Fix A/N metadata not saving for groups.

This commit is contained in:
SillyLossy
2023-05-02 16:01:23 +03:00
parent dce309f0d9
commit 28627e7e51
6 changed files with 296 additions and 174 deletions

View File

@ -1786,6 +1786,19 @@
<!-- templates for JS to reuse when needed --> <!-- templates for JS to reuse when needed -->
<div id="past_chat_template" class="template_element">
<div class="select_chat_block_wrapper">
<div class="select_chat_block" file_name="">
<div class="avatar">
<img src="">
</div>
<div class="select_chat_block_filename"></div>
<div class="select_chat_block_mes"></div>
</div>
<div file_name="" class="PastChat_cross fa-solid fa-circle-xmark"></div>
</div>
</div>
<div id="tag_view_template" class="template_element"> <div id="tag_view_template" class="template_element">
<div class="tag_view_item"> <div class="tag_view_item">
<div class="tag_view_name" contenteditable="true"></div> <div class="tag_view_name" contenteditable="true"></div>

View File

@ -42,6 +42,11 @@ import {
getGroupChat, getGroupChat,
renameGroupMember, renameGroupMember,
createNewGroupChat, createNewGroupChat,
getGroupPastChats,
getGroupAvatar,
openGroupChat,
editGroup,
deleteGroupChat,
} from "./scripts/group-chats.js"; } from "./scripts/group-chats.js";
import { import {
@ -852,20 +857,10 @@ async function delChat(chatfile) {
}), }),
}); });
if (response.ok === true) { if (response.ok === true) {
//close past chat popup
$("#select_chat_cross").click();
// choose another chat if current was deleted // choose another chat if current was deleted
if (chatfile.replace('.jsonl', '') === characters[this_chid].chat) { if (chatfile.replace('.jsonl', '') === characters[this_chid].chat) {
await replaceCurrentChat(); 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(); await getChat();
$("#selected_chat_pole").val(file_name); $("#selected_chat_pole").val(file_name);
$("#create_button").click(); $("#create_button").click();
$("#shadow_select_chat_popup").css("display", "none");
$("#load_select_chat_div").css("display", "block");
} }
////////// OPTIMZED MAIN API CHANGE FUNCTION //////////// ////////// OPTIMZED MAIN API CHANGE FUNCTION ////////////
@ -3164,67 +3157,63 @@ function messageEditDone(div) {
saveChatConditional(); saveChatConditional();
} }
async function getAllCharaChats() { async function getPastCharacterChats() {
//console.log('getAllCharaChats() pinging server for character chat history.'); const response = await fetch("/getallchatsofcharacter", {
$("#select_chat_div").html(""); method: 'POST',
//console.log(characters[this_chid].chat); body: JSON.stringify({ avatar_url: characters[this_chid].avatar }),
jQuery.ajax({ headers: getRequestHeaders(),
type: "POST", });
url: "/getallchatsofcharacter",
data: JSON.stringify({ avatar_url: characters[this_chid].avatar }), if (!response.ok) {
beforeSend: function () { 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']);
},
cache: false,
dataType: "json",
contentType: "application/json",
success: function (data) {
$("#load_select_chat_div").css("display", "none"); $("#load_select_chat_div").css("display", "none");
let dataArr = Object.values(data); $("#ChatHistoryCharName").text(displayName);
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) { for (const key in data) {
let strlen = 300; let strlen = 300;
let mes = data[key]["mes"]; let mes = data[key]["mes"];
if (mes !== undefined) { if (mes !== undefined) {
if (mes.length > strlen) { if (mes.length > strlen) {
mes = "..." + mes.substring(mes.length - strlen); mes = "..." + mes.substring(mes.length - strlen);
} }
$("#select_chat_div").append(
'<div class="select_chat_block_wrapper">' +
'<div class="select_chat_block" file_name="' + data[key]["file_name"] + '">' +
'<div class=avatar><img src="characters/' + characters[this_chid]["avatar"] + '""></div >' +
'<div class="select_chat_block_filename">' + data[key]["file_name"] + '</div>' +
'<div class="select_chat_block_mes">' +
mes +
"</div>" +
"</div >" +
'<div file_name="' + data[key]["file_name"] + '" class="PastChat_cross fa-solid fa-circle-xmark"></div>' +
'</div>'
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) {
if ( template.find('.avatar img').replaceWith(getGroupAvatar(group));
characters[this_chid]["chat"] == }
data[key]["file_name"].replace(".jsonl", "")
) { $("#select_chat_div").append(template);
//children().last()
$("#select_chat_div") if (currentChat === fileName.replace(".jsonl", "")) {
.find(".select_chat_block:last") $("#select_chat_div").find(".select_chat_block:last").attr("highlight", true);
.attr("highlight", true);
} }
} }
} }
},
error: function (jqXHR, exception) {
console.log(exception);
console.log(jqXHR);
},
});
} }
//************************************************************ //************************************************************
@ -3542,6 +3531,10 @@ function read_bg_load(input) {
} }
function showSwipeButtons() { function showSwipeButtons() {
if (chat.length === 0) {
return;
}
if ( if (
chat[chat.length - 1].is_system || chat[chat.length - 1].is_system ||
!swipes || !swipes ||
@ -3592,12 +3585,21 @@ function hideSwipeButtons() {
$("#chat").children().filter(`[mesid="${count_view_mes - 1}"]`).children('.swipe_left').css('display', 'none'); $("#chat").children().filter(`[mesid="${count_view_mes - 1}"]`).children('.swipe_left').css('display', 'none');
} }
function saveChatConditional() { async function saveMetadata() {
if (selected_group) { if (selected_group) {
saveGroupChat(selected_group); await editGroup(selected_group, true, false);
} }
else { 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, setExtensionPrompt: setExtensionPrompt,
updateChatMetadata: updateChatMetadata, updateChatMetadata: updateChatMetadata,
saveChat: saveChatConditional, saveChat: saveChatConditional,
saveMetadata: saveMetadata,
sendSystemMessage: sendSystemMessage, sendSystemMessage: sendSystemMessage,
activateSendButtons, activateSendButtons,
deactivateSendButtons, deactivateSendButtons,
@ -4226,7 +4229,7 @@ $(document).ready(function () {
is_advanced_char_open = false; is_advanced_char_open = false;
$("#character_popup").css("display", "none"); $("#character_popup").css("display", "none");
}); });
$("#dialogue_popup_ok").click(function (e) { $("#dialogue_popup_ok").click(async function (e) {
$("#shadow_popup").transition({ $("#shadow_popup").transition({
opacity: 0, opacity: 0,
duration: 200, duration: 200,
@ -4239,9 +4242,21 @@ $(document).ready(function () {
bg_file_for_del.parent().remove(); bg_file_for_del.parent().remove();
} }
if (popup_type == "del_chat") { 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") { if (popup_type == "del_ch") {
console.log( console.log(
@ -4312,7 +4327,7 @@ $(document).ready(function () {
chat.length = 0; chat.length = 0;
if (selected_group) { if (selected_group) {
createNewGroupChat(); createNewGroupChat(selected_group);
} }
else { else {
//RossAscends: added character name to new chat filenames and replaced Date.now() with humanizedDateTime; //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 () { $("#options [id]").on("click", function () {
var id = $(this).attr("id"); var id = $(this).attr("id");
if (id == "option_select_chat") { if (id == "option_select_chat") {
if (selected_group) { if ((selected_group && !is_group_generating) || (this_chid !== undefined && !is_send_press)) {
// will open a chat selection screen displayPastChats();
/* openNavToggle(); */
$("#rm_button_characters").trigger("click");
return;
}
if (this_chid != undefined && !is_send_press) {
getAllCharaChats();
$("#shadow_select_chat_popup").css("display", "block"); $("#shadow_select_chat_popup").css("display", "block");
$("#shadow_select_chat_popup").css("opacity", 0.0); $("#shadow_select_chat_popup").css("opacity", 0.0);
$("#shadow_select_chat_popup").transition({ $("#shadow_select_chat_popup").transition({
@ -5266,7 +5275,7 @@ $(document).ready(function () {
success: function (data) { success: function (data) {
//console.log(data); //console.log(data);
if (data.res) { if (data.res) {
getAllCharaChats(); displayPastChats();
} }
}, },
error: function (jqXHR, exception) { error: function (jqXHR, exception) {
@ -5287,7 +5296,15 @@ $(document).ready(function () {
$(document).on("click", ".select_chat_block, .bookmark_link", async function () { $(document).on("click", ".select_chat_block, .bookmark_link", async function () {
let file_name = $(this).attr("file_name").replace(".jsonl", ""); 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 () { $(document).on("click", ".mes_stop", function () {

View File

@ -51,13 +51,13 @@ function hasCustomBackground() {
function saveBackgroundMetadata(file) { function saveBackgroundMetadata(file) {
const context = getContext(); const context = getContext();
context.chatMetadata[METADATA_KEY] = file; context.chatMetadata[METADATA_KEY] = file;
context.saveChat(); context.saveMetadata();
} }
function removeBackgroundMetadata() { function removeBackgroundMetadata() {
const context = getContext(); const context = getContext();
delete context.chatMetadata[METADATA_KEY]; delete context.chatMetadata[METADATA_KEY];
context.saveChat(); context.saveMetadata();
} }
function setCustomBackground() { function setCustomBackground() {

View File

@ -3,7 +3,7 @@ import { extension_settings, getContext } from "../../extensions.js";
import { debounce } from "../../utils.js"; import { debounce } from "../../utils.js";
export { MODULE_NAME }; 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 MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory
const UPDATE_INTERVAL = 1000; const UPDATE_INTERVAL = 1000;
@ -21,12 +21,12 @@ const metadata_keys = {
async function onExtensionFloatingPromptInput() { async function onExtensionFloatingPromptInput() {
chat_metadata[metadata_keys.prompt] = $(this).val(); chat_metadata[metadata_keys.prompt] = $(this).val();
saveChatDebounced(); saveMetadataDebounced();
} }
async function onExtensionFloatingIntervalInput() { async function onExtensionFloatingIntervalInput() {
chat_metadata[metadata_keys.interval] = Number($(this).val()); chat_metadata[metadata_keys.interval] = Number($(this).val());
saveChatDebounced(); saveMetadataDebounced();
} }
async function onExtensionFloatingDepthInput() { async function onExtensionFloatingDepthInput() {
@ -38,12 +38,12 @@ async function onExtensionFloatingDepthInput() {
} }
chat_metadata[metadata_keys.depth] = value; chat_metadata[metadata_keys.depth] = value;
saveChatDebounced(); saveMetadataDebounced();
} }
async function onExtensionFloatingPositionInput(e) { async function onExtensionFloatingPositionInput(e) {
chat_metadata[metadata_keys.position] = e.target.value; chat_metadata[metadata_keys.position] = e.target.value;
saveChatDebounced(); saveMetadataDebounced();
} }
function onExtensionFloatingDefaultInput() { function onExtensionFloatingDefaultInput() {

View File

@ -81,15 +81,16 @@ export const group_activation_strategy = {
const groupAutoModeInterval = setInterval(groupChatAutoModeWorker, 5000); const groupAutoModeInterval = setInterval(groupChatAutoModeWorker, 5000);
const saveGroupDebounced = debounce(async (group) => await _save(group), 500); const saveGroupDebounced = debounce(async (group) => await _save(group), 500);
async function _save(group) { async function _save(group, reload = true) {
await fetch("/editgroup", { await fetch("/editgroup", {
method: "POST", method: "POST",
headers: getRequestHeaders(), headers: getRequestHeaders(),
body: JSON.stringify(group), body: JSON.stringify(group),
}); });
if (reload) {
await getCharacters(); await getCharacters();
} }
}
// Group chats // Group chats
async function regenerateGroup() { async function regenerateGroup() {
@ -114,17 +115,26 @@ async function regenerateGroup() {
generateGroupWrapper(); generateGroupWrapper();
} }
export async function getGroupChat(groupId) { async function loadGroupChat(chatId) {
const group = groups.find((x) => x.id === groupId);
const chat_id = group.chat_id;
const response = await fetch("/getgroupchat", { const response = await fetch("/getgroupchat", {
method: "POST", method: "POST",
headers: getRequestHeaders(), headers: getRequestHeaders(),
body: JSON.stringify({ id: chat_id }), body: JSON.stringify({ id: chatId }),
}); });
if (response.ok) { if (response.ok) {
const data = await response.json(); const data = await response.json();
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) { if (Array.isArray(data) && data.length) {
data[0].is_group = true; data[0].is_group = true;
for (let key of data) { for (let key of data) {
@ -155,7 +165,6 @@ export async function getGroupChat(groupId) {
await saveGroupChat(groupId, true); await saveGroupChat(groupId, true);
} }
}
function getFirstCharacterMessage(character) { function getFirstCharacterMessage(character) {
const mes = {}; const mes = {};
@ -197,7 +206,6 @@ export async function renameGroupMember(oldAvatar, newAvatar, newName) {
// Scan every group for our renamed character // Scan every group for our renamed character
for (const group of groups) { for (const group of groups) {
try { try {
// Try finding the member by old avatar link // Try finding the member by old avatar link
const memberIndex = group.members.findIndex(x => x == oldAvatar); const memberIndex = group.members.findIndex(x => x == oldAvatar);
@ -213,16 +221,10 @@ export async function renameGroupMember(oldAvatar, newAvatar, newName) {
// Load all chats from this group // Load all chats from this group
for (const chatId of group.chats) { for (const chatId of group.chats) {
const getChatResponse = await fetch("/getgroupchat", { const messages = await loadGroupChat(chatId);
method: "POST",
headers: getRequestHeaders(),
body: JSON.stringify({ id: chatId }),
});
if (getChatResponse.ok) {
// Only save the chat if there were any changes to the chat content // Only save the chat if there were any changes to the chat content
let hadChanges = false; let hadChanges = false;
const messages = await getChatResponse.json();
// Chat shouldn't be empty // Chat shouldn't be empty
if (Array.isArray(messages) && messages.length) { if (Array.isArray(messages) && messages.length) {
// Iterate over every chat message // Iterate over every chat message
@ -241,7 +243,6 @@ export async function renameGroupMember(oldAvatar, newAvatar, newName) {
hadChanges = true; hadChanges = true;
} }
} }
}
if (hadChanges) { if (hadChanges) {
const saveChatResponse = await fetch("/savegroupchat", { const saveChatResponse = await fetch("/savegroupchat", {
@ -284,6 +285,9 @@ async function getGroups() {
.filter(x => x) .filter(x => x)
.filter(onlyUnique) .filter(onlyUnique)
} }
if (group.past_metadata == undefined) {
group.past_metadata = {};
}
} }
} }
} }
@ -696,16 +700,17 @@ async function deleteGroup(id) {
} }
} }
async function editGroup(id, immediately) { export async function editGroup(id, immediately, reload=true) {
let group = groups.find((x) => x.id == id); let group = groups.find((x) => x.id === id);
group = { ...group, chat_metadata };
if (!group) { if (!group) {
return; return;
} }
group['chat_metadata'] = chat_metadata;
if (immediately) { if (immediately) {
return await _save(group); return await _save(group, reload);
} }
saveGroupDebounced(group); saveGroupDebounced(group);
@ -1077,8 +1082,8 @@ function filterMembersByFavorites(value) {
} }
} }
export async function createNewGroupChat() { export async function createNewGroupChat(groupId) {
const group = groups.find(x => x.id === selected_group); const group = groups.find(x => x.id === groupId);
if (!group) { if (!group) {
return; return;
@ -1091,7 +1096,11 @@ export async function createNewGroupChat() {
group.past_metadata = {}; group.past_metadata = {};
} }
clearChat();
chat.length = 0;
if (oldChatName) {
group.past_metadata[oldChatName] = Object.assign({}, chat_metadata); group.past_metadata[oldChatName] = Object.assign({}, chat_metadata);
}
group.chats.push(newChatName); group.chats.push(newChatName);
group.chat_id = newChatName; group.chat_id = newChatName;
group.chat_metadata = {}; group.chat_metadata = {};
@ -1101,6 +1110,76 @@ export async function createNewGroupChat() {
await getGroupChat(group.id); 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).ready(() => {
$(document).on("click", ".group_select", selectGroup); $(document).on("click", ".group_select", selectGroup);
$("#rm_group_filter").on("input", filterGroupMembers); $("#rm_group_filter").on("input", filterGroupMembers);

View File

@ -1381,22 +1381,19 @@ app.post("/getallchatsofcharacter", jsonParser, function (request, response) {
lastLine = line; lastLine = line;
}); });
rl.on('close', () => { rl.on('close', () => {
ii--;
if (lastLine) { if (lastLine) {
let jsonData = json5.parse(lastLine); let jsonData = json5.parse(lastLine);
if (jsonData.name !== undefined) { if (jsonData.name !== undefined || jsonData.character_name !== undefined) {
chatData[i] = {}; chatData[i] = {};
chatData[i]['file_name'] = file; chatData[i]['file_name'] = file;
chatData[i]['mes'] = jsonData['mes']; chatData[i]['mes'] = jsonData['mes'] || '[The chat is empty]';
ii--; }
}
if (ii === 0) { if (ii === 0) {
console.log('ii count went to zero, responding with chatData'); console.log('ii count went to zero, responding with chatData');
response.send(chatData); response.send(chatData);
} }
} else {
console.log('just returning from getallchatsofcharacter');
return;
}
}
console.log('successfully closing getallchatsofcharacter'); console.log('successfully closing getallchatsofcharacter');
rl.close(); 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) => { app.post('/savegroupchat', jsonParser, (request, response) => {
if (!request.body || !request.body.id) { if (!request.body || !request.body.id) {
return response.sendStatus(400); return response.sendStatus(400);