mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Add group chats creation
This commit is contained in:
1
public/img/minus-solid.svg
Normal file
1
public/img/minus-solid.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M416 256c0 17.7-14.3 32-32 32L32 288c-17.7 0-32-14.3-32-32s14.3-32 32-32l352 0c17.7 0 32 14.3 32 32z"/></svg>
|
After Width: | Height: | Size: 348 B |
1
public/img/plus-solid.svg
Normal file
1
public/img/plus-solid.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M240 80c0-17.7-14.3-32-32-32s-32 14.3-32 32V224H32c-17.7 0-32 14.3-32 32s14.3 32 32 32H176V432c0 17.7 14.3 32 32 32s32-14.3 32-32V288H384c17.7 0 32-14.3 32-32s-14.3-32-32-32H240V80z"/></svg>
|
After Width: | Height: | Size: 429 B |
1
public/img/user-group-solid.svg
Normal file
1
public/img/user-group-solid.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.3.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc. --><path d="M96 128a128 128 0 1 1 256 0A128 128 0 1 1 96 128zM0 482.3C0 383.8 79.8 304 178.3 304h91.4C368.2 304 448 383.8 448 482.3c0 16.4-13.3 29.7-29.7 29.7H29.7C13.3 512 0 498.7 0 482.3zM609.3 512H471.4c5.4-9.4 8.6-20.3 8.6-32v-8c0-60.7-27.1-115.2-69.8-151.8c2.4-.1 4.7-.2 7.1-.2h61.4C567.8 320 640 392.2 640 481.3c0 17-13.8 30.7-30.7 30.7zM432 256c-31 0-59-12.6-79.3-32.9C372.4 196.5 384 163.6 384 128c0-26.8-6.6-52.1-18.3-74.3C384.3 40.1 407.2 32 432 32c61.9 0 112 50.1 112 112s-50.1 112-112 112z"/></svg>
|
After Width: | Height: | Size: 737 B |
@ -62,6 +62,8 @@
|
||||
var mesStr = '';
|
||||
var generatedPromtCache = '';
|
||||
var characters = [];
|
||||
let groups = [];
|
||||
let selected_group = null;
|
||||
var this_chid;
|
||||
var backgrounds = [];
|
||||
var default_avatar = 'img/fluffy.png';
|
||||
@ -72,6 +74,7 @@
|
||||
const system_message_types = {
|
||||
HELP: 'help',
|
||||
WELCOME: 'welcome',
|
||||
GROUP: 'group',
|
||||
};
|
||||
|
||||
const system_messages = {
|
||||
@ -83,6 +86,14 @@
|
||||
"is_name":true,
|
||||
"mes": "Hi there! The following chat formatting commands are supported in TavernAI:<br><ul><li><tt>*text*</tt> – format the actions that your character does</li><li><tt>{*text*}</tt> – set the behavioral bias for your character</li></ul><p>Need more help? Visit our wiki – <a href=\"https://github.com/TavernAI/TavernAI/wiki\">TavernAI Wiki</a>!</p>"
|
||||
},
|
||||
'group': {
|
||||
"name": systemUserName,
|
||||
"force_avatar": "img/chloe.png",
|
||||
"is_user":false,
|
||||
"is_system": true,
|
||||
"is_name": true,
|
||||
"mes": "Group chat created. Say 'Hi' to lovely people!"
|
||||
}
|
||||
};
|
||||
|
||||
const world_info_position = {
|
||||
@ -106,6 +117,7 @@
|
||||
|
||||
var timerSaveEdit;
|
||||
var timerWorldSave;
|
||||
var timerGroupSave;
|
||||
var durationSaveEdit = 200;
|
||||
//animation right menu
|
||||
var animation_rm_duration = 200;
|
||||
@ -433,11 +445,16 @@
|
||||
$("#rm_print_characters_block").prepend('<div class=character_select chid='+i+'><div class=avatar><img src="'+this_avatar+'"></div><div class=ch_name>'+item.name+'</div></div>');
|
||||
//console.log(item.name);
|
||||
});
|
||||
|
||||
|
||||
for (let group of groups) {
|
||||
const template = $('#group_list_template .group_select').clone();
|
||||
template.data('id', group.id);
|
||||
template.find('.avatar img').attr('src', group.avatar_url);
|
||||
template.find('.ch_name').html(group.name);
|
||||
$('#rm_print_characters_block').prepend(template);
|
||||
}
|
||||
}
|
||||
async function getCharacters() {
|
||||
|
||||
await getGroups();
|
||||
const response = await fetch("/getcharacters", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
@ -1491,7 +1508,7 @@
|
||||
//maybe a way to simulate this would be to disable the eventListener for people iOS.
|
||||
|
||||
$("#send_textarea").keydown(function (e) {
|
||||
if(e.which === 13 && e.shiftKey && is_send_press == false) {
|
||||
if(e.which === 13 && !e.shiftKey && is_send_press == false) {
|
||||
is_send_press = true;
|
||||
e.preventDefault();
|
||||
Generate();
|
||||
@ -1520,6 +1537,7 @@
|
||||
|
||||
$( "#rm_ch_create_block" ).css("display", "none");
|
||||
$( "#rm_info_block" ).css("display", "none");
|
||||
$("#rm_group_chats_block").css("display", "none");
|
||||
|
||||
$( "#rm_button_characters" ).children("h2").css(deselected_button_style);
|
||||
$( "#rm_button_settings" ).children("h2").css(selected_button_style);
|
||||
@ -1541,6 +1559,280 @@
|
||||
selected_button = 'character_edit';
|
||||
select_selected_character(this_chid);
|
||||
});
|
||||
$(document).on('click', '.group_select', async function() {
|
||||
const id = $(this).data('id');
|
||||
selected_button = 'group_chats';
|
||||
|
||||
if (selected_group !== id){
|
||||
if(!is_send_press){
|
||||
selected_group = id;
|
||||
this_edit_mes_id = undefined;
|
||||
clearChat();
|
||||
chat.length = 0;
|
||||
await getGroupChat(id);
|
||||
}
|
||||
}
|
||||
|
||||
select_group_chats(id);
|
||||
});
|
||||
$("#rm_button_group_chats").click(function() {
|
||||
selected_button = 'group_chats';
|
||||
select_group_chats();
|
||||
});
|
||||
$( "#rm_button_back_from_group" ).click(function() {
|
||||
selected_button = 'characters';
|
||||
select_rm_characters();
|
||||
});
|
||||
$('#rm_group_filter').on('input', function() {
|
||||
const searchValue = $(this).val().trim().toLowerCase();
|
||||
|
||||
if (!searchValue) {
|
||||
$("#rm_group_add_members .group_member").show();
|
||||
} else {
|
||||
$("#rm_group_add_members .group_member").each(function () {
|
||||
$(this).children('.ch_name').text().toLowerCase().includes(searchValue)
|
||||
? $(this).show()
|
||||
: $(this).hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
$('#rm_group_submit').click(async function() {
|
||||
let name = $('#rm_group_chat_name').val();
|
||||
const members = $('#rm_group_members .group_member').map((_, x) => $(x).data('id')).toArray();
|
||||
|
||||
if (!name) {
|
||||
name = `Chat with ${members.join(', ')}`;
|
||||
}
|
||||
|
||||
// placeholder
|
||||
const avatar_url = '/img/five.png';
|
||||
|
||||
const createGroupResponse = await fetch('/creategroup', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRF-Token": token,
|
||||
},
|
||||
body: JSON.stringify({ name: name, members: members, avatar_url: avatar_url }),
|
||||
});
|
||||
|
||||
if (createGroupResponse.ok) {
|
||||
const createGroupData = await createGroupResponse.json();
|
||||
const id = createGroupData.id;
|
||||
|
||||
await getCharacters();
|
||||
$('#rm_info_avatar').html('');
|
||||
var avatar = $('#avatar_div_div').clone();
|
||||
avatar.find('img').attr('src', avatar_url);
|
||||
$('#rm_info_avatar').append(avatar);
|
||||
$('#rm_info_block').transition({ opacity: 0 ,duration: 0});
|
||||
select_rm_info("Group chat created");
|
||||
$('#rm_info_block').transition({ opacity: 1.0 ,duration: 2000});
|
||||
}
|
||||
});
|
||||
async function getGroupChat(id) {
|
||||
const response = await fetch('/getgroupchat', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRF-Token": token,
|
||||
},
|
||||
body: JSON.stringify({ id: id }),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
if(Array.isArray(data) && data.length) {
|
||||
for (let key of data) {
|
||||
chat.push(key);
|
||||
}
|
||||
printMessages();
|
||||
}
|
||||
else {
|
||||
sendSystemMessage(system_message_types.GROUP);
|
||||
}
|
||||
|
||||
await saveGroupChat(id);
|
||||
}
|
||||
}
|
||||
async function saveGroupChat(id) {
|
||||
const response = await fetch('/savegroupchat', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRF-Token": token,
|
||||
},
|
||||
body: JSON.stringify({id: id, chat: [...chat]})
|
||||
});
|
||||
}
|
||||
async function getGroups() {
|
||||
const response = await fetch('/getgroups', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRF-Token": token,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
groups = data.sort((a,b) => a.id - b.id);
|
||||
}
|
||||
}
|
||||
async function deleteGroup(id) {
|
||||
const response = await fetch('/deletegroup', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRF-Token": token,
|
||||
},
|
||||
body: JSON.stringify({id : id}),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
await getCharacters();
|
||||
$('#rm_info_avatar').html('');
|
||||
$('#rm_info_block').transition({ opacity: 0 ,duration: 0});
|
||||
select_rm_info("Group deleted!");
|
||||
$('#rm_info_block').transition({ opacity: 1.0 ,duration: 2000});
|
||||
}
|
||||
|
||||
}
|
||||
async function editGroup(id, immediately) {
|
||||
const group = groups.find(x => x.id == id);
|
||||
|
||||
if (!group) {
|
||||
return;
|
||||
}
|
||||
|
||||
async function _save() {
|
||||
const response = await fetch('/editgroup', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRF-Token": token,
|
||||
},
|
||||
body: JSON.stringify(group),
|
||||
});
|
||||
}
|
||||
|
||||
if (immediately) {
|
||||
return await _save();
|
||||
}
|
||||
|
||||
clearTimeout(timerGroupSave);
|
||||
timerGroupSave = setTimeout(async () => await _save(), durationSaveEdit);
|
||||
}
|
||||
|
||||
function select_group_chats(chat_id) {
|
||||
menu_type = 'group_chats';
|
||||
const group = chat_id && groups.find(x => x.id == chat_id);
|
||||
const groupName = group?.name ?? '';
|
||||
|
||||
$('#rm_group_chat_name').val(groupName);
|
||||
$('#rm_group_chat_name').off();
|
||||
$('#rm_group_chat_name').on('input', async function() {
|
||||
if (chat_id) {
|
||||
group.name = $(this).val();
|
||||
await editGroup(chat_id);
|
||||
}
|
||||
});
|
||||
$('#rm_group_filter').val('').trigger('input');
|
||||
$("#rm_group_chats_block").css("display", "flex");
|
||||
$('#rm_group_chats_block').css('opacity', 0.0);
|
||||
$('#rm_group_chats_block').transition({
|
||||
opacity: 1.0,
|
||||
duration: animation_rm_duration,
|
||||
easing: animation_rm_easing,
|
||||
complete: function() { }
|
||||
});
|
||||
|
||||
$("#rm_ch_create_block").css("display", "none");
|
||||
$("#rm_characters_block" ).css("display", "none");
|
||||
|
||||
async function memberClickHandler() {
|
||||
const id = $(this).data('id');
|
||||
const isDelete = !!($(this).closest('#rm_group_members').length);
|
||||
const template = $(this).clone();
|
||||
template.data('id', id);
|
||||
template.click(memberClickHandler);
|
||||
|
||||
if (isDelete) {
|
||||
template.find('.plus').show();
|
||||
template.find('.minus').hide();
|
||||
$('#rm_group_add_members').prepend(template);
|
||||
} else {
|
||||
template.find('.plus').hide();
|
||||
template.find('.minus').show();
|
||||
$('#rm_group_members').prepend(template);
|
||||
}
|
||||
|
||||
if (group) {
|
||||
if (isDelete) {
|
||||
const index = group.members.findIndex(x => x === id);
|
||||
if (index !== -1) {
|
||||
group.members.splice(index, 1);
|
||||
}
|
||||
} else {
|
||||
group.members.push(id);
|
||||
}
|
||||
await editGroup(chat_id);
|
||||
}
|
||||
|
||||
$(this).remove();
|
||||
const groupHasMembers = !!$('#rm_group_members').children().length;
|
||||
$("#rm_group_submit").prop('disabled', !groupHasMembers);
|
||||
}
|
||||
|
||||
// render characters list
|
||||
$('#rm_group_add_members').empty();
|
||||
$('#rm_group_members').empty();
|
||||
for (let character of characters) {
|
||||
const avatar = character.avatar != 'none' ? `characters/${character.avatar}#${Date.now()}` : default_avatar;
|
||||
const template = $('#group_member_template .group_member').clone();
|
||||
template.data('id', character.name);
|
||||
template.find('.avatar img').attr('src', avatar);
|
||||
template.find('.ch_name').html(character.name);
|
||||
template.click(memberClickHandler);
|
||||
|
||||
if (group && Array.isArray(group.members) && group.members.includes(character.name)) {
|
||||
template.find('.plus').hide();
|
||||
template.find('.minus').show();
|
||||
$('#rm_group_members').append(template);
|
||||
} else {
|
||||
template.find('.plus').show();
|
||||
template.find('.minus').hide();
|
||||
$('#rm_group_add_members').append(template);
|
||||
}
|
||||
}
|
||||
|
||||
const groupHasMembers = !!$('#rm_group_members').children().length;
|
||||
$("#rm_group_submit").prop('disabled', !groupHasMembers);
|
||||
|
||||
// bottom buttons
|
||||
if (chat_id) {
|
||||
$('#rm_group_submit').hide();
|
||||
$('#rm_group_delete').show();
|
||||
} else {
|
||||
$('#rm_group_submit').show();
|
||||
$('#rm_group_delete').hide();
|
||||
}
|
||||
|
||||
$('#rm_group_delete').off();
|
||||
$('#rm_group_delete').on('click', function() {
|
||||
popup_type = 'del_group';
|
||||
$('#dialogue_popup').data('group_id', chat_id);
|
||||
callPopup('<h3>Delete the group?</h3>');
|
||||
});
|
||||
|
||||
// top bar
|
||||
if (group) {
|
||||
var display_name = groupName;
|
||||
$("#rm_button_selected_ch").children("h2").css(deselected_button_style);
|
||||
$("#rm_button_selected_ch").children("h2").text('');
|
||||
}
|
||||
}
|
||||
|
||||
function select_rm_create(){
|
||||
menu_type = 'create';
|
||||
if(selected_button == 'create'){
|
||||
@ -1553,6 +1845,7 @@
|
||||
$( "#rm_characters_block" ).css("display", "none");
|
||||
$( "#rm_api_block" ).css("display", "none");
|
||||
$( "#rm_ch_create_block" ).css("display", "block");
|
||||
$("#rm_group_chats_block").css("display", "none");
|
||||
|
||||
$('#rm_ch_create_block').css('opacity',0.0);
|
||||
$('#rm_ch_create_block').transition({
|
||||
@ -1606,6 +1899,7 @@
|
||||
$( "#rm_api_block" ).css("display", "none");
|
||||
$( "#rm_ch_create_block" ).css("display", "none");
|
||||
$( "#rm_info_block" ).css("display", "none");
|
||||
$("#rm_group_chats_block").css("display", "none");
|
||||
|
||||
$( "#rm_button_characters" ).children("h2").css(selected_button_style);
|
||||
$( "#rm_button_settings" ).children("h2").css(deselected_button_style);
|
||||
@ -1615,6 +1909,7 @@
|
||||
$( "#rm_characters_block" ).css("display", "none");
|
||||
$( "#rm_api_block" ).css("display", "none");
|
||||
$( "#rm_ch_create_block" ).css("display", "none");
|
||||
$("#rm_group_chats_block").css("display", "none");
|
||||
$( "#rm_info_block" ).css("display", "flex");
|
||||
|
||||
$("#rm_info_text").html('<h3>'+text+'</h3>');
|
||||
@ -1671,6 +1966,7 @@
|
||||
$("#form_create").attr("actiontype", "editcharacter");
|
||||
}
|
||||
$(document).on('click', '.character_select', function(){
|
||||
selected_group = null;
|
||||
if(this_chid !== $(this).attr("chid")){
|
||||
if(!is_send_press){
|
||||
this_edit_mes_id = undefined;
|
||||
@ -1869,6 +2165,13 @@
|
||||
if (popup_type === 'del_world' && world_info) {
|
||||
deleteWorldInfo(world_info);
|
||||
}
|
||||
if (popup_type === 'del_group') {
|
||||
const groupId = $('#dialogue_popup').data('group_id');
|
||||
|
||||
if (groupId) {
|
||||
deleteGroup(groupId);
|
||||
}
|
||||
}
|
||||
if(popup_type == 'new_chat' && this_chid != undefined && menu_type != "create"){//Fix it; New chat doesn't create while open create character menu
|
||||
clearChat();
|
||||
chat.length = 0;
|
||||
@ -1901,6 +2204,7 @@
|
||||
$("#dialogue_popup_ok").text("Yes");
|
||||
break;
|
||||
case 'del_world':
|
||||
case 'del_group':
|
||||
default:
|
||||
$("#dialogue_popup_ok").css("background-color", "#791b31");
|
||||
$("#dialogue_popup_ok").text("Delete");
|
||||
@ -4005,6 +4309,54 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div id="rm_group_chats_block" class="right_menu">
|
||||
<div id="rm_group_top_bar">
|
||||
<div id="rm_button_back_from_group" class="right_menu_button">
|
||||
<h2 style="color: rgb(188, 193, 200, 0.5);">⇐</h2>
|
||||
</div>
|
||||
<input id="rm_group_chat_name" class="text_pole" type="text" name="chat_name" placeholder="Chat Name (Optional)"/>
|
||||
</div>
|
||||
<div id="rm_group_add_members_header">
|
||||
<h3>Add Members</h3>
|
||||
<input id="rm_group_filter" class="text_pole" type="search" placeholder="Filter..."/>
|
||||
</div>
|
||||
<!-- !!!Don't break line after div!!! -->
|
||||
<div id="rm_group_add_members"></div>
|
||||
<h3>Members</h3>
|
||||
<!-- !!!Don't break line after div!!! -->
|
||||
<div id="rm_group_members"></div>
|
||||
|
||||
<div id="group_member_template">
|
||||
<div class="group_member">
|
||||
<div class="avatar">
|
||||
<img src="" />
|
||||
</div>
|
||||
<div class="ch_name"></div>
|
||||
<div class="group_member_icon">
|
||||
<img class="minus" src="img/minus-solid.svg" >
|
||||
<img class="plus" src="img/plus-solid.svg" >
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="group_list_template">
|
||||
<div class="group_select">
|
||||
<div class="avatar">
|
||||
<img src="">
|
||||
</div>
|
||||
<div class="group_icon">
|
||||
<img src="img/user-group-solid.svg">
|
||||
</div>
|
||||
<div class="ch_name"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="rm_group_buttons">
|
||||
<input id="rm_group_submit" type="button" value="Create">
|
||||
<div id="rm_group_buttons_expander"> </div>
|
||||
<input id="rm_group_delete" type="button" value="Delete">
|
||||
</div>
|
||||
</div>
|
||||
<div id="rm_api_block" class="right_menu" >
|
||||
|
||||
<h3 id="title_api">API</h3>
|
||||
@ -4162,6 +4514,7 @@
|
||||
<div id="rm_characters_block" class="right_menu">
|
||||
<div id="rm_button_create" class="right_menu_button"><h2>+New Character</h2></div>
|
||||
<div id="character_import_button" class="right_menu_button"><h2>+Import</h2></div>
|
||||
<div id="rm_button_group_chats" class="right_menu_button"><h2>+New Group</h2></div>
|
||||
|
||||
<div id="characloud_url" title="Find more characters on CharaCloud (coming soon)">
|
||||
<img src="img/cloud_logo.png">
|
||||
|
154
public/style.css
154
public/style.css
@ -756,7 +756,7 @@ display: none;
|
||||
padding-left: 0.75em;
|
||||
}
|
||||
|
||||
#character_search_bar::-webkit-search-cancel-button {
|
||||
input[type=search]::-webkit-search-cancel-button {
|
||||
-webkit-appearance: none;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
@ -769,7 +769,7 @@ display: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#character_search_bar:focus::-webkit-search-cancel-button {
|
||||
input[type=search]:focus::-webkit-search-cancel-button {
|
||||
opacity: .3;
|
||||
pointer-events: all;
|
||||
}
|
||||
@ -2486,3 +2486,153 @@ body {
|
||||
-webkit-transition: width 0s ease;
|
||||
transition: width 0s ease;
|
||||
}
|
||||
|
||||
/* GROUP CHATS */
|
||||
|
||||
#rm_group_top_bar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
width: 100%;
|
||||
}
|
||||
#rm_button_group_chats{
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
}
|
||||
#rm_button_group_chats h2{
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
font-size: 16px;
|
||||
color: rgb(188, 193, 200, 1);
|
||||
border: 1px solid #333;
|
||||
background-color: rgba(0,0,0,0.3);
|
||||
padding:6px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
#rm_group_chats_block {
|
||||
display: none;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
#rm_group_chat_name {
|
||||
width: 90%;
|
||||
}
|
||||
#rm_group_buttons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
}
|
||||
#rm_group_buttons > input {
|
||||
font-size: 16px;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
#rm_group_buttons > input:disabled {
|
||||
filter: brightness(0.3);
|
||||
cursor: unset;
|
||||
}
|
||||
#rm_group_members, #rm_group_add_members {
|
||||
margin-top: 0.25rem;
|
||||
margin-bottom: 0.25rem;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
}
|
||||
#rm_group_buttons_expander {
|
||||
flex-grow: 1;
|
||||
}
|
||||
#rm_group_delete {
|
||||
color: rgb(190, 0, 0);
|
||||
}
|
||||
#rm_group_members:empty {
|
||||
width: 100%;
|
||||
}
|
||||
#rm_group_members:empty::before {
|
||||
content: 'Group is empty';
|
||||
font-size: 1rem;
|
||||
font-weight: bolder;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0.8;
|
||||
}
|
||||
#rm_group_add_members:empty {
|
||||
width: 100%;
|
||||
}
|
||||
#rm_group_add_members_header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
#rm_group_add_members_header input {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
#rm_group_add_members:empty::before {
|
||||
content: 'No characters available';
|
||||
font-size: 1rem;
|
||||
font-weight: bolder;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
opacity: 0.8;
|
||||
}
|
||||
.group_member_icon {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin: 0 10px;
|
||||
}
|
||||
.group_member_icon img {
|
||||
filter: invert(1);
|
||||
}
|
||||
.group_member {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
cursor:pointer;
|
||||
}
|
||||
.group_member .ch_name {
|
||||
flex-grow: 1;
|
||||
margin-left: 10px;
|
||||
}
|
||||
.group_member:hover{
|
||||
background-color: #ffffff11;
|
||||
}
|
||||
#group_member_template {
|
||||
display: none !important;
|
||||
}
|
||||
#group_list_template {
|
||||
display: none !important;
|
||||
}
|
||||
.group_select {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.group_select:hover {
|
||||
background-color: #ffffff11;
|
||||
}
|
||||
.group_select .group_icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 0 10px;
|
||||
}
|
||||
.group_select .ch_name {
|
||||
flex-grow: 1;
|
||||
}
|
||||
.group_select .group_icon img {
|
||||
filter: invert(1);
|
||||
}
|
113
server.js
113
server.js
@ -61,7 +61,12 @@ if (is_colab && process.env.googledrive == 2){
|
||||
const jsonParser = express.json({limit: '100mb'});
|
||||
const urlencodedParser = express.urlencoded({extended: true, limit: '100mb'});
|
||||
const baseRequestArgs = { headers: { "Content-Type": "application/json" } };
|
||||
const directories = { worlds: 'public/worlds/', avatars: 'public/User Avatars' };
|
||||
const directories = {
|
||||
worlds: 'public/worlds/',
|
||||
avatars: 'public/User Avatars',
|
||||
groups: 'public/groups/',
|
||||
groupChats: 'public/group chats',
|
||||
};
|
||||
|
||||
// CSRF Protection //
|
||||
const doubleCsrf = require('csrf-csrf').doubleCsrf;
|
||||
@ -1294,6 +1299,112 @@ app.post('/uploaduseravatar', urlencodedParser, async (request, response) => {
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/getgroups', jsonParser, (_, response) => {
|
||||
const groups = [];
|
||||
|
||||
if (!fs.existsSync(directories.groups)) {
|
||||
fs.mkdirSync(directories.groups);
|
||||
}
|
||||
|
||||
const files = fs.readdirSync(directories.groups);
|
||||
files.forEach(function(file) {
|
||||
const fileContents = fs.readFileSync(path.join(directories.groups, file), 'utf8');
|
||||
const group = JSON.parse(fileContents);
|
||||
groups.push(group);
|
||||
});
|
||||
|
||||
return response.send(groups);
|
||||
});
|
||||
|
||||
app.post('/creategroup', jsonParser, (request, response) => {
|
||||
if (!request.body) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const id = Date.now();
|
||||
const chatMetadata = { id: id, name: request.body.name ?? 'New Group', members: request.body.members ?? [], avatar_url: request.body.avatar_url };
|
||||
const pathToFile = path.join(directories.groups, `${id}.json`);
|
||||
const fileData = JSON.stringify(chatMetadata);
|
||||
|
||||
if (!fs.existsSync(directories.groups)) {
|
||||
fs.mkdirSync(directories.groups);
|
||||
}
|
||||
|
||||
fs.writeFileSync(pathToFile, fileData);
|
||||
return response.send(chatMetadata);
|
||||
});
|
||||
|
||||
app.post('/editgroup', jsonParser, (request, response) => {
|
||||
if (!request.body || !request.body.id) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const id = request.body.id;
|
||||
const pathToFile = path.join(directories.groups, `${id}.json`);
|
||||
const fileData = JSON.stringify(request.body);
|
||||
|
||||
fs.writeFileSync(pathToFile, fileData);
|
||||
return response.send({ok: true});
|
||||
});
|
||||
|
||||
app.post('/getgroupchat', 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)) {
|
||||
const data = fs.readFileSync(pathToFile, 'utf8');
|
||||
const lines = data.split('\n');
|
||||
|
||||
// Iterate through the array of strings and parse each line as JSON
|
||||
const jsonData = lines.map(JSON.parse);
|
||||
return response.send(jsonData);
|
||||
} else {
|
||||
return response.send([]);
|
||||
}
|
||||
});
|
||||
|
||||
app.post('/savegroupchat', 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(directories.groupChats)) {
|
||||
fs.mkdirSync(directories.groupChats);
|
||||
}
|
||||
|
||||
let chat_data = request.body.chat;
|
||||
let jsonlData = chat_data.map(JSON.stringify).join('\n');
|
||||
fs.writeFileSync(pathToFile, jsonlData, 'utf8');
|
||||
return response.send({ok: true});
|
||||
});
|
||||
|
||||
app.post('/deletegroup', jsonParser, async (request, response) => {
|
||||
if (!request.body || !request.body.id) {
|
||||
return response.sendStatus(400);
|
||||
}
|
||||
|
||||
const id = request.body.id;
|
||||
const pathToGroup = path.join(directories.groups, `${id}.json`);
|
||||
const pathToChat = path.join(directories.groupChats, `${id}.jsonl`);
|
||||
|
||||
if (fs.existsSync(pathToGroup)) {
|
||||
fs.rmSync(pathToGroup);
|
||||
}
|
||||
|
||||
if (fs.existsSync(pathToChat)) {
|
||||
fs.rmSync(pathToChat);
|
||||
}
|
||||
|
||||
return response.send({ok: true});
|
||||
});
|
||||
|
||||
// ** REST CLIENT ASYNC WRAPPERS **
|
||||
function deleteAsync(url, args) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
Reference in New Issue
Block a user