diff --git a/public/index.html b/public/index.html index 7a8327cf0..24bf7c48b 100644 --- a/public/index.html +++ b/public/index.html @@ -2459,13 +2459,17 @@ placeholder="Describe your character's physical and mental traits here." class="margin-bot-10px" name="description" placeholder=""> -
- First message - - ? - - +
+ + First message + + ? + + +
+
+ +
CHAR is typing
@@ -3221,7 +3255,7 @@ Convert to group - + Start new chat diff --git a/public/script.js b/public/script.js index 4cf3dd061..5d0f786d1 100644 --- a/public/script.js +++ b/public/script.js @@ -563,6 +563,7 @@ let create_save_avatar = ""; let create_save_scenario = ""; let create_save_mes_example = ""; let create_save_talkativeness = talkativeness_default; +let create_save_alternate_greetings = []; //animation right menu let animation_duration = 250; @@ -3647,13 +3648,26 @@ async function getChatResult() { name2 = characters[this_chid].name; if (chat.length === 0) { const firstMes = characters[this_chid].first_mes || default_ch_mes; + const alternateGreetings = characters[this_chid]?.data?.alternate_greetings; + chat[0] = { name: name2, is_user: false, is_name: true, send_date: humanizedDateTime(), - mes: firstMes + mes: firstMes, }; + + if (Array.isArray(alternateGreetings) && alternateGreetings.length > 0) { + chat[0]['swipe_id'] = 0; + chat[0]['swipes'] = []; + chat[0]['swipes'][0] = chat[0]['mes']; + + for (let i = 0; i < alternateGreetings.length; i++) { + const alternateGreeting = alternateGreetings[i]; + chat[0]['swipes'].push(substituteParams(alternateGreeting)); + } + } } printMessages(); select_selected_character(this_chid); @@ -4431,6 +4445,7 @@ export function select_selected_character(chid) { $("#name_div").removeClass('displayBlock'); $("#name_div").addClass('displayNone'); $("#renameCharButton").css("display", ""); + $('.open_alternate_greetings').data('chid', chid); $("#form_create").attr("actiontype", "editcharacter"); saveSettingsDebounced(); @@ -4479,6 +4494,7 @@ function select_rm_create() { $("#renameCharButton").css('display', 'none'); $("#name_div").removeClass('displayNone'); $("#name_div").addClass('displayBlock'); + $('.open_alternate_greetings').data('chid', undefined); updateFavButtonState(false); $("#form_create").attr("actiontype", "createcharacter"); @@ -4517,6 +4533,7 @@ function callPopup(text, type, inputValue = '') { $("#dialogue_popup_ok").text("Ok"); $("#dialogue_popup_cancel").css("display", "none"); case "text": + case "alternate_greeting": case "char_not_selected": $("#dialogue_popup_ok").text("Ok"); $("#dialogue_popup_cancel").css("display", "none"); @@ -4628,13 +4645,18 @@ function showSwipeButtons() { if ( chat[chat.length - 1].is_system || !swipes || - $('.mes:last').attr('mesid') <= 0 || + $('.mes:last').attr('mesid') < 0 || chat[chat.length - 1].is_user || chat[chat.length - 1].extra?.image || - count_view_mes <= 1 || + count_view_mes < 1 || (selected_group && is_group_generating) ) { return; } + // swipe_id should be set if alternate greetings are added + if (chat.length == 1 && chat[0].swipe_id === undefined) { + return; + } + //had to add this to make the swipe counter work //(copied from the onclick functions for swipe buttons.. //don't know why the array isn't set for non-swipe messsages in Generate or addOneMessage..) @@ -4813,6 +4835,241 @@ function enlargeMessageImage() { callPopup(img.outerHTML, 'text'); } +function updateAlternateGreetingsHintVisibility(root) { + const numberOfGreetings = root.find('.alternate_greetings_list .alternate_greeting').length; + $(root).find('.alternate_grettings_hint').toggle(numberOfGreetings == 0); +} + +function openAlternateGreetings() { + const chid = $('.open_alternate_greetings').data('chid'); + + if (menu_type != 'create' && chid === undefined) { + toastr.error('Does not have an Id for this character in editor menu.'); + return; + } else { + // If the character does not have alternate greetings, create an empty array + if (Array.isArray(characters[chid].data.alternate_greetings) == false) { + characters[chid].data.alternate_greetings = []; + } + } + + const template = $('#alternate_greetings_template .alternate_grettings').clone(); + const getArray = () => menu_type == 'create' ? create_save_alternate_greetings : characters[chid].data.alternate_greetings; + + for (let index = 0; index < getArray().length; index++) { + addAlternateGreeting(template, getArray()[index], index, getArray); + } + + template.find('.add_alternate_greeting').on('click', function () { + const array = getArray(); + const index = array.length; + array.push(default_ch_mes); + addAlternateGreeting(template, default_ch_mes, index, getArray); + updateAlternateGreetingsHintVisibility(template); + }); + + updateAlternateGreetingsHintVisibility(template); + callPopup(template, 'alternate_greeting'); +} + +function addAlternateGreeting(template, greeting, index, getArray) { + const greetingBlock = $('#alternate_greeting_form_template .alternate_greeting').clone(); + greetingBlock.find('.alternate_greeting_text').on('input', async function() { + const value = $(this).val(); + const array = getArray(); + array[index] = value; + }).val(greeting); + greetingBlock.find('.greeting_index').text(index + 1); + greetingBlock.find('.delete_alternate_greeting').on('click', async function () { + if (confirm('Are you sure you want to delete this alternate greeting?')) { + const array = getArray(); + array.splice(index, 1); + // We need to reopen the popup to update the index numbers + openAlternateGreetings(); + } + }); + template.find('.alternate_greetings_list').append(greetingBlock); +} + +async function createOrEditCharacter(e) { + $("#rm_info_avatar").html(""); + let save_name = create_save_name; + var formData = new FormData($("#form_create").get(0)); + formData.set('fav', fav_ch_checked); + if ($("#form_create").attr("actiontype") == "createcharacter") { + if ($("#character_name_pole").val().length > 0) { + //if the character name text area isn't empty (only posible when creating a new character) + let url = "/createcharacter"; + + if (crop_data != undefined) { + url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`; + } + + formData.delete('alternate_greetings'); + for (const value of create_save_alternate_greetings) { + formData.append('alternate_greetings', value); + } + + await jQuery.ajax({ + type: "POST", + url: url, + data: formData, + beforeSend: function () { + $("#create_button").attr("disabled", true); + $("#create_button").attr("value", "⏳"); + }, + cache: false, + contentType: false, + processData: false, + success: async function (html) { + $("#character_cross").trigger('click'); //closes the advanced character editing popup + const fields = [ + { id: '#character_name_pole', callback: value => create_save_name = value }, + { id: '#description_textarea', callback: value => create_save_description = value }, + { id: '#creator_notes_textarea', callback: value => create_save_creator_notes = value }, + { id: '#character_version_textarea', callback: value => create_save_character_version = value }, + { id: '#post_history_instructions_textarea', callback: value => create_save_post_history_instructions = value }, + { id: '#system_prompt_textarea', callback: value => create_save_system_prompt = value }, + { id: '#tags_textarea', callback: value => create_save_tags = value }, + { id: '#creator_textarea', callback: value => create_save_creator = value }, + { id: '#personality_textarea', callback: value => create_save_personality = value }, + { id: '#firstmessage_textarea', callback: value => create_save_first_message = value }, + { id: '#talkativeness_slider', callback: value => create_save_talkativeness = value, defaultValue: talkativeness_default }, + { id: '#scenario_pole', callback: value => create_save_scenario = value }, + { id: '#mes_example_textarea', callback: value => create_save_mes_example = value }, + { id: '#character_json_data', callback: () => { } }, + { id: '#alternate_greetings_template', callback: value => create_save_alternate_greetings = value, defaultValue: [] }, + ]; + + fields.forEach(field => { + const fieldValue = field.defaultValue !== undefined ? field.defaultValue : ''; + $(field.id).val(fieldValue); + field.callback && field.callback(fieldValue); + }); + + $("#character_popup_text_h3").text("Create character"); + + create_save_avatar = ""; + + $("#create_button").removeAttr("disabled"); + $("#add_avatar_button").replaceWith( + $("#add_avatar_button").val("").clone(true) + ); + + $("#create_button").attr("value", "✅"); + let oldSelectedChar = null; + if (this_chid != undefined && this_chid != "invalid-safety-id") { + oldSelectedChar = characters[this_chid].avatar; + } + + console.log(`new avatar id: ${html}`); + createTagMapFromList("#tagList", html); + await getCharacters(); + + $("#rm_info_block").transition({ opacity: 0, duration: 0 }); + var $prev_img = $("#avatar_div_div").clone(); + $("#rm_info_avatar").append($prev_img); + select_rm_info(`char_create`, html, oldSelectedChar); + + $("#rm_info_block").transition({ opacity: 1.0, duration: 2000 }); + crop_data = undefined; + }, + error: function (jqXHR, exception) { + $("#create_button").removeAttr("disabled"); + }, + }); + } else { + $("#result_info").html("Name not entered"); + } + } else { + let url = '/editcharacter'; + + if (crop_data != undefined) { + url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`; + } + + formData.delete('alternate_greetings'); + const chid = $('.open_alternate_greetings').data('chid'); + if (Array.isArray(characters[chid]?.data?.alternate_greetings)) { + for (const value of characters[chid].data.alternate_greetings) { + formData.append('alternate_greetings', value); + } + } + + await jQuery.ajax({ + type: "POST", + url: url, + data: formData, + beforeSend: function () { + $("#create_button").attr("disabled", true); + $("#create_button").attr("value", "Save"); + }, + cache: false, + contentType: false, + processData: false, + success: async function (html) { + if (chat.length === 1 && !selected_group) { + var this_ch_mes = default_ch_mes; + if ($("#firstmessage_textarea").val() != "") { + this_ch_mes = $("#firstmessage_textarea").val(); + } + if ( + this_ch_mes != + $.trim( + $("#chat") + .children(".mes") + .children(".mes_block") + .children(".mes_text") + .text() + ) + ) { + clearChat(); + chat.length = 0; + chat[0] = {}; + chat[0]["name"] = name2; + chat[0]["is_user"] = false; + chat[0]["is_name"] = true; + chat[0]["mes"] = this_ch_mes; + chat[0]["extra"] = {}; + + const alternateGreetings = characters[this_chid]?.data?.alternate_greetings; + + if (Array.isArray(alternateGreetings) && alternateGreetings.length > 0) { + chat[0]['swipe_id'] = 0; + chat[0]['swipes'] = []; + chat[0]['swipes'][0] = chat[0]['mes']; + + for (let i = 0; i < alternateGreetings.length; i++) { + const alternateGreeting = alternateGreetings[i]; + chat[0]['swipes'].push(substituteParams(alternateGreeting)); + } + } + + add_mes_without_animation = true; + //console.log('form create submission calling addOneMessage'); + addOneMessage(chat[0]); + await eventSource.emit(event_types.MESSAGE_RECEIVED, (chat.length - 1)); + } + } + $("#create_button").removeAttr("disabled"); + await getCharacters(); + + $("#add_avatar_button").replaceWith( + $("#add_avatar_button").val("").clone(true) + ); + $("#create_button").attr("value", "Save"); + crop_data = undefined; + }, + error: function (jqXHR, exception) { + $("#create_button").removeAttr("disabled"); + $("#result_info").html("Error: no connection"); + console.log('Error! Either a file with the same name already existed, or the image file provided was in an invalid format. Double check that the image is not a webp.'); + toastr.error('Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.'); + }, + }); + } +} + window["SillyTavern"].getContext = function () { return { chat: chat, @@ -4968,6 +5225,13 @@ const swipe_right = () => { return; } + if (chat.length == 1) { + if (chat[0]['swipe_id'] !== undefined && chat[0]['swipe_id'] == chat[0]['swipes'].length - 1) { + toastr.info('Add more alternative greetings to swipe through', 'That\'s all for now'); + return; + } + } + const swipe_duration = 200; const swipe_range = 700; //console.log(swipe_range); @@ -5330,7 +5594,7 @@ $(document).ready(function () { return; } - if (this_chid !== $(this).attr("chid")) { + if (selected_group || this_chid !== $(this).attr("chid")) { //if clicked on a different character from what was currently selected if (!is_send_press) { cancelTtsPlay(); @@ -5605,6 +5869,9 @@ $(document).ready(function () { if (popup_type === "world_imported") { selectImportedWorldInfo(); } + if (popup_type == "alternate_greeting" && menu_type !== "create") { + createOrEditCharacter(); + } if (popup_type === "del_world" && world_info) { deleteWorldInfo(world_info); } @@ -5654,7 +5921,6 @@ $(document).ready(function () { dialogueResolve = null; } - }); $("#dialogue_popup_cancel").click(function (e) { $("#shadow_popup").transition({ @@ -5686,155 +5952,7 @@ $(document).ready(function () { read_avatar_load(this); }); - $("#form_create").submit(function (e) { - $("#rm_info_avatar").html(""); - let save_name = create_save_name; - var formData = new FormData($("#form_create").get(0)); - formData.set('fav', fav_ch_checked); - if ($("#form_create").attr("actiontype") == "createcharacter") { - if ($("#character_name_pole").val().length > 0) { - //if the character name text area isn't empty (only posible when creating a new character) - let url = "/createcharacter"; - - if (crop_data != undefined) { - url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`; - } - - jQuery.ajax({ - type: "POST", - url: url, - data: formData, - beforeSend: function () { - $("#create_button").attr("disabled", true); - $("#create_button").attr("value", "⏳"); - }, - cache: false, - contentType: false, - processData: false, - success: async function (html) { - $("#character_cross").trigger('click'); //closes the advanced character editing popup - const fields = [ - { id: '#character_name_pole', callback: value => create_save_name = value }, - { id: '#description_textarea', callback: value => create_save_description = value }, - { id: '#creator_notes_textarea', callback: value => create_save_creator_notes = value }, - { id: '#character_version_textarea', callback: value => create_save_character_version = value }, - { id: '#post_history_instructions_textarea', callback: value => create_save_post_history_instructions = value }, - { id: '#system_prompt_textarea', callback: value => create_save_system_prompt = value }, - { id: '#tags_textarea', callback: value => create_save_tags = value }, - { id: '#creator_textarea', callback: value => create_save_creator = value }, - { id: '#personality_textarea', callback: value => create_save_personality = value }, - { id: '#firstmessage_textarea', callback: value => create_save_first_message = value }, - { id: '#talkativeness_slider', callback: value => create_save_talkativeness = value, defaultValue: talkativeness_default }, - { id: '#scenario_pole', callback: value => create_save_scenario = value }, - { id: '#mes_example_textarea', callback: value => create_save_mes_example = value }, - { id: '#character_json_data', callback: () => { } }, - ]; - - fields.forEach(field => { - const fieldValue = field.defaultValue !== undefined ? field.defaultValue : ''; - $(field.id).val(fieldValue); - field.callback && field.callback(fieldValue); - }); - - $("#character_popup_text_h3").text("Create character"); - - create_save_avatar = ""; - - $("#create_button").removeAttr("disabled"); - $("#add_avatar_button").replaceWith( - $("#add_avatar_button").val("").clone(true) - ); - - $("#create_button").attr("value", "✅"); - let oldSelectedChar = null; - if (this_chid != undefined && this_chid != "invalid-safety-id") { - oldSelectedChar = characters[this_chid].avatar; - } - - console.log(`new avatar id: ${html}`); - createTagMapFromList("#tagList", html); - await getCharacters(); - - $("#rm_info_block").transition({ opacity: 0, duration: 0 }); - var $prev_img = $("#avatar_div_div").clone(); - $("#rm_info_avatar").append($prev_img); - select_rm_info(`char_create`, html, oldSelectedChar); - - $("#rm_info_block").transition({ opacity: 1.0, duration: 2000 }); - crop_data = undefined; - }, - error: function (jqXHR, exception) { - $("#create_button").removeAttr("disabled"); - }, - }); - } else { - $("#result_info").html("Name not entered"); - } - } else { - let url = '/editcharacter'; - - if (crop_data != undefined) { - url += `?crop=${encodeURIComponent(JSON.stringify(crop_data))}`; - } - - jQuery.ajax({ - type: "POST", - url: url, - data: formData, - beforeSend: function () { - $("#create_button").attr("disabled", true); - $("#create_button").attr("value", "Save"); - }, - cache: false, - contentType: false, - processData: false, - success: async function (html) { - if (chat.length === 1) { - var this_ch_mes = default_ch_mes; - if ($("#firstmessage_textarea").val() != "") { - this_ch_mes = $("#firstmessage_textarea").val(); - } - if ( - this_ch_mes != - $.trim( - $("#chat") - .children(".mes") - .children(".mes_block") - .children(".mes_text") - .text() - ) - ) { - clearChat(); - chat.length = 0; - chat[0] = {}; - chat[0]["name"] = name2; - chat[0]["is_user"] = false; - chat[0]["is_name"] = true; - chat[0]["mes"] = this_ch_mes; - add_mes_without_animation = true; - //console.log('form create submission calling addOneMessage'); - addOneMessage(chat[0]); - await eventSource.emit(event_types.MESSAGE_RECEIVED, (chat.length - 1)); - } - } - $("#create_button").removeAttr("disabled"); - await getCharacters(); - - $("#add_avatar_button").replaceWith( - $("#add_avatar_button").val("").clone(true) - ); - $("#create_button").attr("value", "Save"); - crop_data = undefined; - }, - error: function (jqXHR, exception) { - $("#create_button").removeAttr("disabled"); - $("#result_info").html("Error: no connection"); - console.log('Error! Either a file with the same name already existed, or the image file provided was in an invalid format. Double check that the image is not a webp.'); - toastr.error('Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.'); - }, - }); - } - }); + $("#form_create").submit(createOrEditCharacter); $("#delete_button").click(function () { popup_type = "del_ch"; @@ -6918,6 +7036,7 @@ $(document).ready(function () { $(document).on('click', '#CloseAllWIEntries', function () { $("#world_popup_entries_list").children().find('.up').click() }); + $(document).on('click', '.open_alternate_greetings', openAlternateGreetings); $(document).keyup(function (e) { if (e.key === "Escape") { diff --git a/public/scripts/group-chats.js b/public/scripts/group-chats.js index 8a1a6db46..5915bb473 100644 --- a/public/scripts/group-chats.js +++ b/public/scripts/group-chats.js @@ -179,6 +179,14 @@ export async function getGroupChat(groupId) { } function getFirstCharacterMessage(character) { + let messageText = character.first_mes; + + // if there are alternate greetings, pick one at random + if (Array.isArray(character.data?.alternate_greetings)) { + const messageTexts = [character.first_mes, ...character.data.alternate_greetings].filter(x => x); + messageText = messageTexts[Math.floor(Math.random() * messageTexts.length)]; + } + const mes = {}; mes["is_user"] = false; mes["is_system"] = false; @@ -187,8 +195,8 @@ function getFirstCharacterMessage(character) { mes["send_date"] = humanizedDateTime(); mes["original_avatar"] = character.avatar; mes["extra"] = { "gen_id": Date.now() * Math.random() * 1000000 }; - mes["mes"] = character.first_mes - ? substituteParams(character.first_mes.trim(), name1, character.name) + mes["mes"] = messageText + ? substituteParams(messageText.trim(), name1, character.name) : default_ch_mes; mes["force_avatar"] = character.avatar != "none"