| 8724 | * @returns {string} The formatted counter. | 8753 | * @returns {string} The formatted counter. |
| 8725 | */ | 8754 | */ |
| 8726 | function formatSwipeCounter(current, total) { | 8755 | function formatSwipeCounter(current, total) { |
| 8727 | if (isNaN(current) || isNaN(total)) { | 8756 | if (isNaN(current) && isNaN(total)) { |
| 8728 | return ''; | 8757 | return ''; |
| 8729 | } | 8758 | } |
| 8730 | | 8759 | return `${!isNaN(current) ? current : '?'}\u200b/\u200b${!isNaN(total) ? total : '?'}`; |
| 8731 | return `${current}\u200b/\u200b${total}`; | | |
| 8732 | } | 8760 | } |
| 8733 | | 8761 | |
| 8734 | /** | 8762 | /** |
| 8735 | * Handles the swipe to the left event. | 8763 | * Handles the swipe event. |
| 8736 | * @param {JQuery.Event} _event Event. | 8764 | * @param {JQuery.Event} _event Event. |
| | 8765 | * @param {'left'|'right'} direction The direction to swipe. |
| 8737 | * @param {object} params Additional parameters. | 8766 | * @param {object} params Additional parameters. |
| 8738 | * @param {string} [params.source] The source of the swipe event. | 8767 | * @param {string} [params.source] The source of the swipe event. |
| 8739 | * @param {boolean} [params.repeated] Is the swipe event repeated. | 8768 | * @param {boolean} [params.repeated] Is the swipe event repeated. |
| | 8769 | * @param {object} [params.message=chat[chat.length - 1]] The chat message to swipe. |
| 8740 | */ | 8770 | */ |
| 8741 | export function swipe_left(_event, { source, repeated } = {}) { | 8771 | export async function swipe(_event, direction, { source, repeated, message = chat[chat.length - 1] } = {}) { |
| 8742 | if (chat.length - 1 === Number(this_edit_mes_id)) { | 8772 | if (chat.length === 0) { |
| 8743 | closeMessageEditor(); | 8773 | console.warn('Swipe was called on an empty chat.'); |
| | 8774 | return; |
| 8744 | } | 8775 | } |
| 8745 | if (isStreamingEnabled() && streamingProcessor) { | 8776 | |
| 8746 | streamingProcessor.onStopStreaming(); | 8777 | //Only allow one concurrent swipe. |
| | 8778 | if (!isSwipingAllowed) { |
| | 8779 | console.info('The swipe has been ignored because another is in progress.'); |
| | 8780 | return; |
| 8747 | } | 8781 | } |
| | 8782 | isSwipingAllowed = false; |
| 8748 | | 8783 | |
| 8749 | // Make sure ad-hoc changes to extras are saved before swiping away | 8784 | let generation; |
| 8750 | syncMesToSwipe(); | 8785 | let messageIndex; |
| 8751 | | 8786 | |
| 8752 | // If the user is holding down the key and we're at the first swipe, don't do anything | 8787 | //Only set messageIndex if message exists because -1 is truthy. |
| 8753 | if (source === 'keyboard' && repeated && chat[chat.length - 1].swipe_id === 0) { | 8788 | if (message) { |
| | 8789 | messageIndex = chat.indexOf(message); |
| | 8790 | if (messageIndex === -1) { |
| | 8791 | console.error(`The message must exist in chat. ${message};`); |
| 8754 | return; | 8792 | return; |
| 8755 | } | 8793 | } |
| | 8794 | } |
| 8756 | | 8795 | |
| 8757 | const swipe_duration = 120; | 8796 | const mesId = Number($(this).closest('.mes').attr('mesid') ?? messageIndex ?? chat.length - 1); |
| 8758 | const swipe_range = '700px'; | | |
| 8759 | chat[chat.length - 1]['swipe_id']--; | | |
| 8760 | | 8797 | |
| 8761 | if (chat[chat.length - 1]['swipe_id'] < 0) { | 8798 | const thisMesDiv = chatElement.children().filter(`.mes[mesid="${mesId}"]`); |
| 8762 | chat[chat.length - 1]['swipe_id'] = chat[chat.length - 1]['swipes'].length - 1; | 8799 | const thisMesText = thisMesDiv.find('.mes_block .mes_text'); |
| | 8800 | const thisMesDivHeight = thisMesDiv[0]?.scrollHeight; |
| | 8801 | const thisMesTextHeight = thisMesText[0]?.scrollHeight; |
| | 8802 | if (![thisMesDiv.length, thisMesText.length].every(num => num > 0 )) { |
| | 8803 | console.error(`Message #${mesId}'s DOM element is not valid.`); |
| | 8804 | return; |
| 8763 | } | 8805 | } |
| | 8806 | const originalSwipeId = Number(chat[mesId]?.['swipe_id'] ?? 0); |
| | 8807 | let newSwipeId = Number(originalSwipeId); |
| 8764 | | 8808 | |
| 8765 | if (chat[chat.length - 1]['swipe_id'] >= 0) { | 8809 | const isPristine = !chat_metadata?.tainted; |
| 8766 | /*$(this).parent().children('swipe_right').css('display', 'flex'); | 8810 | const swipeDuration = Math.round(animation_duration * 1.25); |
| 8767 | if (chat[chat.length - 1]['swipe_id'] === 0) { | 8811 | const swipeRange = direction === SWIPE_DIRECTION.RIGHT ? -700 : 700; |
| 8768 | $(this).css('display', 'none'); | 8812 | |
| 8769 | }*/ // Just in case | 8813 | async function endSwipe() { |
| 8770 | if (!Array.isArray(chat[chat.length - 1]['swipe_info'])) { | 8814 | //Wait for the generation to end. |
| 8771 | chat[chat.length - 1]['swipe_info'] = []; | 8815 | try { |
| 8772 | } | 8816 | await generation; |
| 8773 | let this_mes_div = $(this).parent(); | | |
| 8774 | let this_mes_block = $(this).parent().children('.mes_block').children('.mes_text'); | | |
| 8775 | const this_mes_div_height = this_mes_div[0].scrollHeight; | | |
| 8776 | this_mes_div.css('height', this_mes_div_height); | | |
| 8777 | const this_mes_block_height = this_mes_block[0].scrollHeight; | | |
| 8778 | chat[chat.length - 1]['mes'] = chat[chat.length - 1]['swipes'][chat[chat.length - 1]['swipe_id']]; | | |
| 8779 | chat[chat.length - 1]['send_date'] = chat[chat.length - 1].swipe_info[chat[chat.length - 1]['swipe_id']]?.send_date || chat[chat.length - 1].send_date; //load the last mes box with the latest generation | | |
| 8780 | chat[chat.length - 1]['extra'] = structuredClone(chat[chat.length - 1].swipe_info[chat[chat.length - 1]['swipe_id']]?.extra || chat[chat.length - 1].extra); | | |
| 8781 | | | |
| 8782 | if (chat[chat.length - 1].extra) { | | |
| 8783 | // if message has memory attached - remove it to allow regen | | |
| 8784 | if (chat[chat.length - 1].extra.memory) { | | |
| 8785 | delete chat[chat.length - 1].extra.memory; | | |
| 8786 | } | 8817 | } |
| 8787 | // ditto for display text | 8818 | catch (error) { |
| 8788 | if (chat[chat.length - 1].extra.display_text) { | 8819 | console.warn(`Swipe failed, Swiping back. ${error}`); |
| 8789 | delete chat[chat.length - 1].extra.display_text; | | |
| 8790 | } | 8820 | } |
| | 8821 | //Allow for another swipe. |
| | 8822 | showSwipeButtons(); |
| | 8823 | |
| | 8824 | //Clamp Id between swipes. |
| | 8825 | let clampedId = clamp(chat[mesId]['swipe_id'], 0, Math.max(0, chat[mesId]['swipes'].length - 1)); |
| | 8826 | |
| | 8827 | //If the id is not within bounds, Swipe back. |
| | 8828 | if (chat[mesId]['swipe_id'] !== clampedId) { |
| | 8829 | chat[mesId]['swipe_id'] = clampedId; |
| | 8830 | syncSwipeToMes(mesId); |
| | 8831 | addOneMessage(chat[mesId], { type: 'swipe', forceId: mesId, scroll: false }); |
| 8791 | } | 8832 | } |
| 8792 | $(this).parent().children('.mes_block').transition({ | | |
| 8793 | x: swipe_range, | | |
| 8794 | duration: animation_duration > 0 ? swipe_duration : 0, | | |
| 8795 | easing: animation_easing, | | |
| 8796 | queue: false, | | |
| 8797 | complete: async function () { | | |
| 8798 | const is_animation_scroll = ($('#chat').scrollTop() >= ($('#chat').prop('scrollHeight') - $('#chat').outerHeight()) - 10); | | |
| 8799 | //console.log('on left swipe click calling addOneMessage'); | | |
| 8800 | addOneMessage(chat[chat.length - 1], { type: 'swipe' }); | | |
| 8801 | | 8833 | |
| 8802 | if (power_user.message_token_count_enabled) { | 8834 | await updateSwipeCounter(mesId); |
| 8803 | if (!chat[chat.length - 1].extra) { | 8835 | //Fallback. |
| 8804 | chat[chat.length - 1].extra = {}; | 8836 | if (mesId != chat.length - 1) { |
| | 8837 | await updateSwipeCounter(chat.length - 1); |
| | 8838 | } |
| 8805 | } | 8839 | } |
| 8806 | | 8840 | |
| 8807 | const swipeMessage = $('#chat').find(`[mesid="${chat.length - 1}"]`); | 8841 | async function standardSwipe() { |
| 8808 | const tokenCountText = (chat[chat.length - 1]?.extra?.reasoning || '') + chat[chat.length - 1].mes; | 8842 | //If swipe_id has changed, or the source is being deleted. |
| 8809 | const tokenCount = await getTokenCountAsync(tokenCountText, 0); | 8843 | if (newSwipeId !== originalSwipeId || source == 'delete') |
| 8810 | chat[chat.length - 1]['extra']['token_count'] = tokenCount; | 8844 | { |
| 8811 | swipeMessage.find('.tokenCounterDisplay').text(`${tokenCount}t`); | 8845 | //Update the chat. |
| | 8846 | await loadFromSwipeId(mesId, newSwipeId); |
| | 8847 | //Transition to the new chat. |
| | 8848 | await animateSwipe(); |
| | 8849 | } |
| | 8850 | await endSwipe(); |
| 8812 | } | 8851 | } |
| 8813 | | 8852 | |
| 8814 | let new_height = this_mes_div_height - (this_mes_block_height - this_mes_block[0].scrollHeight); | 8853 | /** |
| 8815 | if (new_height < 103) new_height = 103; | 8854 | * Sets the message to the newSwipeId and loads it. |
| 8816 | this_mes_div.animate({ height: new_height + 'px' }, { | 8855 | * @param {number} mesId |
| 8817 | duration: 0, //used to be 100 | 8856 | * @param {number} newSwipeId |
| 8818 | queue: false, | 8857 | */ |
| 8819 | progress: function () { | 8858 | async function loadFromSwipeId(mesId, newSwipeId) { |
| 8820 | // Scroll the chat down as the message expands | 8859 | //Update the swipe_id. |
| | 8860 | chat[mesId]['swipe_id'] = newSwipeId; |
| 8821 | | 8861 | |
| 8822 | if (is_animation_scroll) $('#chat').scrollTop($('#chat')[0].scrollHeight); | 8862 | if (chat[mesId].extra) { |
| 8823 | }, | 8863 | // if message has memory attached - remove it to allow regen |
| 8824 | complete: function () { | 8864 | delete chat[mesId].extra.memory; |
| 8825 | this_mes_div.css('height', 'auto'); | 8865 | |
| 8826 | // Scroll the chat down to the bottom once the animation is complete | 8866 | // ditto for display text |
| 8827 | if (is_animation_scroll) $('#chat').scrollTop($('#chat')[0].scrollHeight); | 8867 | delete chat[mesId].extra.display_text; |
| 8828 | }, | 8868 | |
| 8829 | }); | 8869 | delete chat[mesId].extra.image; |
| 8830 | $(this).parent().children('.mes_block').transition({ | 8870 | delete chat[mesId].extra.image_swipes; |
| 8831 | x: '-' + swipe_range, | 8871 | delete chat[mesId].extra.video; |
| 8832 | duration: 0, | 8872 | delete chat[mesId].extra.inline_image; |
| 8833 | easing: animation_easing, | 8873 | } |
| 8834 | queue: false, | 8874 | delete chat[mesId].gen_started; |
| 8835 | complete: function () { | 8875 | delete chat[mesId].gen_finished; |
| 8836 | $(this).parent().children('.mes_block').transition({ | 8876 | //load from swipes. |
| 8837 | x: '0px', | 8877 | syncSwipeToMes(mesId, chat[mesId]['swipe_id']); |
| 8838 | duration: animation_duration > 0 ? swipe_duration : 0, | 8878 | } |
| 8839 | easing: animation_easing, | 8879 | |
| 8840 | queue: false, | 8880 | //Deepseek-V3.1 |
| 8841 | complete: async function () { | 8881 | // Helper function to convert transition to promise |
| 8842 | appendMediaToMessage(chat[chat.length - 1], $(this).parent().children('.mes_block')); | 8882 | const transitionPromise = (element, properties) => { |
| 8843 | await eventSource.emit(event_types.MESSAGE_SWIPED, (chat.length - 1)); | 8883 | return new Promise((resolve) => { |
| 8844 | saveChatDebounced(); | 8884 | element.transition({ |
| 8845 | }, | 8885 | ...properties, |
| | 8886 | complete: resolve, |
| 8846 | }); | 8887 | }); |
| 8847 | }, | | |
| 8848 | }); | 8888 | }); |
| 8849 | }, | 8889 | }; |
| | 8890 | |
| | 8891 | /** |
| | 8892 | * Animates a swipe for all messages >= mesId. |
| | 8893 | * @param {number} mesId |
| | 8894 | * @param {number} x |
| | 8895 | * @param {number} duration |
| | 8896 | */ |
| | 8897 | async function animateSwipeTransition(mesId, x, duration) { |
| | 8898 | //Selects the swiped message. |
| | 8899 | const swipedMessagesDiv = chatElement.children().filter((index, div) => { |
| | 8900 | const $div = $(div); |
| | 8901 | return mesId === Number($div.attr('mesid')); |
| 8850 | }); | 8902 | }); |
| | 8903 | const swipedElementsDiv = swipedMessagesDiv.children('.mes_block, .mesAvatarWrapper'); |
| 8851 | | 8904 | |
| 8852 | $(this).parent().children('.avatar').transition({ | 8905 | //Swipe. |
| 8853 | x: swipe_range, | 8906 | await transitionPromise(swipedElementsDiv, { |
| 8854 | duration: animation_duration > 0 ? swipe_duration : 0, | 8907 | x: x, |
| 8855 | easing: animation_easing, | 8908 | duration: duration, |
| 8856 | queue: false, | | |
| 8857 | complete: function () { | | |
| 8858 | $(this).parent().children('.avatar').transition({ | | |
| 8859 | x: '-' + swipe_range, | | |
| 8860 | duration: 0, | | |
| 8861 | easing: animation_easing, | 8909 | easing: animation_easing, |
| 8862 | queue: false, | 8910 | queue: false, |
| 8863 | complete: function () { | 8911 | }); |
| 8864 | $(this).parent().children('.avatar').transition({ | 8912 | } |
| 8865 | x: '0px', | 8913 | |
| 8866 | duration: animation_duration > 0 ? swipe_duration : 0, | 8914 | function getMessageBottomHeight(thisMesDiv) { |
| 8867 | easing: animation_easing, | 8915 | const thisMesRect = thisMesDiv[0].getBoundingClientRect(); |
| | 8916 | //Scroll position + Chat height = Bottom of chat height. |
| | 8917 | const chatBottom = chatElement.scrollTop() - chatElement.height(); |
| | 8918 | //Message offset from viewport top + height = Bottom of message offset. |
| | 8919 | const messageBottom = thisMesRect.top + thisMesDiv.height(); |
| | 8920 | // Bottom of chat + Bottom of message offset = target scroll position. |
| | 8921 | const scrollHeight = (chatBottom + messageBottom); |
| | 8922 | return scrollHeight; |
| | 8923 | } |
| | 8924 | |
| | 8925 | function expandNewMessage(thisMesDiv) { |
| | 8926 | //Only scroll if the view is not near the bottom. |
| | 8927 | const is_animation_scroll = (chatElement.scrollTop() >= (chatElement.prop('scrollHeight') - chatElement.outerHeight()) - 10); |
| | 8928 | |
| | 8929 | let new_height = thisMesDivHeight - (thisMesTextHeight - thisMesText[0].scrollHeight); |
| | 8930 | if (new_height < 103) new_height = 103; |
| | 8931 | |
| | 8932 | //Keep the swipe buttons at the same height when scrolling is finished. |
| | 8933 | |
| | 8934 | //Expand new message. |
| | 8935 | thisMesDiv.animate({ height: new_height + 'px' }, { |
| | 8936 | duration: 0, //used to be 100 //Disabled on Cohee's request. https://github.com/SillyTavern/SillyTavern/pull/4610/files#r2408731744 |
| 8868 | queue: false, | 8937 | queue: false, |
| 8869 | complete: function () { | 8938 | progress: function (animation, progress, remainingMs) { |
| 8870 | | 8939 | |
| | 8940 | if (is_animation_scroll) chatElement.scrollTop(getMessageBottomHeight(thisMesDiv)); |
| 8871 | }, | 8941 | }, |
| 8872 | }); | 8942 | complete: function () { |
| 8873 | }, | 8943 | thisMesDiv.css('height', 'auto'); |
| 8874 | }); | 8944 | //Correct height auto offset. |
| | 8945 | if (is_animation_scroll) chatElement.scrollTop(getMessageBottomHeight(thisMesDiv)); |
| 8875 | }, | 8946 | }, |
| 8876 | }); | 8947 | }); |
| 8877 | } | 8948 | } |
| 8878 | if (chat[chat.length - 1]['swipe_id'] < 0) { | | |
| 8879 | chat[chat.length - 1]['swipe_id'] = 0; | | |
| 8880 | } | | |
| 8881 | } | | |
| 8882 | | 8949 | |
| 8883 | /** | 8950 | /** |
| 8884 | * Handles the swipe to the right event. | 8951 | * Anime a swipe, optionally running a generation. |
| 8885 | * @param {JQuery.Event} [_event] Event. | 8952 | * @param {boolean} run_generate |
| 8886 | * @param {object} params Additional parameters. | | |
| 8887 | * @param {string} [params.source] The source of the swipe event. | | |
| 8888 | * @param {boolean} [params.repeated] Is the swipe event repeated. | | |
| 8889 | */ | 8953 | */ |
| 8890 | //MARK: swipe_right | 8954 | async function animateSwipe(run_generate = false) { |
| 8891 | export function swipe_right(_event = null, { source, repeated } = {}) { | 8955 | |
| 8892 | if (chat.length - 1 === Number(this_edit_mes_id)) { | 8956 | //Swipe out. |
| | 8957 | await animateSwipeTransition(mesId, swipeRange, swipeDuration); |
| | 8958 | |
| | 8959 | if (run_generate) { |
| | 8960 | await updateSwipeCounter(mesId); |
| | 8961 | //shows "..." while generating |
| | 8962 | thisMesDiv.find('.mes_text').html('...'); |
| | 8963 | // resets the timer |
| | 8964 | thisMesDiv.find('.mes_timer').html(''); |
| | 8965 | thisMesDiv.find('.tokenCounterDisplay').text(''); |
| | 8966 | updateReasoningUI(thisMesDiv, { reset: true }); |
| | 8967 | } else { |
| | 8968 | //console.log('showing previously generated swipe candidate, or "..."'); |
| | 8969 | //console.log('onclick right swipe calling addOneMessage'); |
| | 8970 | |
| | 8971 | //Only scroll when swiping the last message. |
| | 8972 | const scroll = (mesId == chat.length - 1); |
| | 8973 | addOneMessage(chat[mesId], { type: 'swipe', forceId: mesId, scroll: scroll }); |
| | 8974 | |
| | 8975 | if (power_user.message_token_count_enabled) { |
| | 8976 | if (!chat[mesId].extra) { |
| | 8977 | chat[mesId].extra = {}; |
| | 8978 | } |
| | 8979 | |
| | 8980 | const tokenCountText = (chat[mesId]?.extra?.reasoning || '') + chat[mesId].mes; |
| | 8981 | const tokenCount = await getTokenCountAsync(tokenCountText, 0); |
| | 8982 | chat[mesId]['extra']['token_count'] = tokenCount; |
| | 8983 | thisMesDiv.find('.tokenCounterDisplay').text(`${tokenCount}t`); |
| | 8984 | } |
| | 8985 | } |
| | 8986 | |
| | 8987 | //Animate expanding to the new message height. |
| | 8988 | thisMesDiv.css('height', thisMesDivHeight); |
| | 8989 | expandNewMessage(thisMesDiv); |
| | 8990 | |
| | 8991 | |
| | 8992 | //Jump to the opposite side. |
| | 8993 | await animateSwipeTransition(mesId, -swipeRange, 0); |
| | 8994 | |
| | 8995 | appendMediaToMessage(chat[mesId], thisMesDiv); |
| | 8996 | |
| | 8997 | await eventSource.emit(event_types.MESSAGE_SWIPED, (mesId)); |
| | 8998 | |
| | 8999 | if (run_generate && !is_send_press) { |
| | 9000 | is_send_press = true; |
| | 9001 | generation = Generate('swipe'); |
| | 9002 | } else if (parseInt(chat[mesId]['swipe_id']) !== chat[mesId]['swipes'].length) { |
| | 9003 | saveChatDebounced(); |
| | 9004 | } |
| | 9005 | |
| | 9006 | //Swipe in. |
| | 9007 | await animateSwipeTransition(mesId, 0, swipeDuration); |
| | 9008 | } |
| | 9009 | |
| | 9010 | if (mesId === Number(this_edit_mes_id)) { |
| 8893 | closeMessageEditor(); | 9011 | closeMessageEditor(); |
| 8894 | } | 9012 | } |
| | 9013 | if (isStreamingEnabled() && streamingProcessor) { |
| | 9014 | streamingProcessor.onStopStreaming(); |
| | 9015 | } |
| 8895 | | 9016 | |
| 8896 | if (isHordeGenerationNotAllowed()) { | 9017 | if (isHordeGenerationNotAllowed()) { |
| 8897 | return unblockGeneration(); | 9018 | return unblockGeneration(); |
| 8898 | } | 9019 | } |
| 8899 | | 9020 | |
| 8900 | // Make sure ad-hoc changes to extras are saved before swiping away | 9021 | //If the swipe is not being deleted. |
| 8901 | syncMesToSwipe(); | 9022 | if (source != 'delete') { |
| 8902 | | 9023 | |
| 8903 | const isPristine = !chat_metadata?.tainted; | 9024 | // Make sure ad-hoc changes to extras are saved before swiping away |
| 8904 | const swipe_duration = 200; | 9025 | syncMesToSwipe(mesId); |
| 8905 | const swipe_range = 700; | 9026 | |
| 8906 | //console.log(swipe_range); | 9027 | if (chat[mesId]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array |
| 8907 | let run_generate = false; | 9028 | chat[mesId]['swipe_id'] = 0; // set it to id 0 |
| 8908 | let run_swipe_right = false; | 9029 | chat[mesId]['swipes'] = []; // empty the array |
| 8909 | if (chat[chat.length - 1]['swipe_id'] === undefined) { // if there is no swipe-message in the last spot of the chat array | 9030 | chat[mesId]['swipe_info'] = []; |
| 8910 | chat[chat.length - 1]['swipe_id'] = 0; // set it to id 0 | 9031 | chat[mesId]['swipes'][0] = chat[mesId]['mes']; //assign swipe array with last chat[mesId] from chat |
| 8911 | chat[chat.length - 1]['swipes'] = []; // empty the array | 9032 | chat[mesId]['swipe_info'][0] = { |
| 8912 | chat[chat.length - 1]['swipe_info'] = []; | 9033 | 'send_date': chat[mesId]['send_date'], |
| 8913 | chat[chat.length - 1]['swipes'][0] = chat[chat.length - 1]['mes']; //assign swipe array with last message from chat | 9034 | 'gen_started': chat[mesId]['gen_started'], |
| 8914 | chat[chat.length - 1]['swipe_info'][0] = { | 9035 | 'gen_finished': chat[mesId]['gen_finished'], |
| 8915 | 'send_date': chat[chat.length - 1]['send_date'], | 9036 | 'extra': structuredClone(chat[mesId]['extra']), |
| 8916 | 'gen_started': chat[chat.length - 1]['gen_started'], | | |
| 8917 | 'gen_finished': chat[chat.length - 1]['gen_finished'], | | |
| 8918 | 'extra': structuredClone(chat[chat.length - 1]['extra']), | | |
| 8919 | }; | 9037 | }; |
| 8920 | //assign swipe info array with last message from chat | | |
| 8921 | } | 9038 | } |
| 8922 | // if swipe_right is called on the last alternate greeting in pristine chats, loop back around | 9039 | // If the user is holding down the key and we're at the last or first swipe, don't do anything. |
| 8923 | if (chat.length === 1 && chat[0]['swipe_id'] !== undefined && chat[0]['swipe_id'] === chat[0]['swipes'].length - 1 && isPristine) { | 9040 | let isLastSwipe = (direction === SWIPE_DIRECTION.RIGHT) ? (chat[mesId].swipe_id === Math.max(0, chat[mesId]['swipes'].length - 1)) : chat[mesId].swipe_id === 0; |
| 8924 | chat[0]['swipe_id'] = 0; | 9041 | if (source === 'keyboard' && repeated && isLastSwipe) { |
| 8925 | } else { | 9042 | await endSwipe(); |
| 8926 | // If the user is holding down the key and we're at the last swipe, don't do anything | | |
| 8927 | if (source === 'keyboard' && repeated && chat[chat.length - 1].swipe_id === chat[chat.length - 1].swipes.length - 1) { | | |
| 8928 | return; | 9043 | return; |
| 8929 | } | 9044 | } |
| 8930 | // make new slot in array | 9045 | } else if (source == 'delete') { |
| 8931 | chat[chat.length - 1]['swipe_id']++; | 9046 | //If the swipe is being deleted. |
| 8932 | } | 9047 | await standardSwipe(); |
| 8933 | if (chat[chat.length - 1].extra) { | 9048 | return; |
| 8934 | // if message has memory attached - remove it to allow regen | | |
| 8935 | if (chat[chat.length - 1].extra.memory) { | | |
| 8936 | delete chat[chat.length - 1].extra.memory; | | |
| 8937 | } | 9049 | } |
| 8938 | // ditto for display text | | |
| 8939 | if (chat[chat.length - 1].extra.display_text) { | | |
| 8940 | delete chat[chat.length - 1].extra.display_text; | | |
| 8941 | } | | |
| 8942 | | | |
| 8943 | delete chat[chat.length - 1].extra.image; | | |
| 8944 | delete chat[chat.length - 1].extra.image_swipes; | | |
| 8945 | delete chat[chat.length - 1].extra.video; | | |
| 8946 | delete chat[chat.length - 1].extra.inline_image; | | |
| 8947 | } | | |
| 8948 | if (!Array.isArray(chat[chat.length - 1]['swipe_info'])) { | | |
| 8949 | chat[chat.length - 1]['swipe_info'] = []; | | |
| 8950 | } | | |
| 8951 | //if swipe id of last message is the same as the length of the 'swipes' array and not the greeting | | |
| 8952 | if (parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length && (chat.length !== 1 || !isPristine)) { | | |
| 8953 | delete chat[chat.length - 1].gen_started; | | |
| 8954 | delete chat[chat.length - 1].gen_finished; | | |
| 8955 | run_generate = true; | | |
| 8956 | } else if (parseInt(chat[chat.length - 1]['swipe_id']) < chat[chat.length - 1]['swipes'].length) { //otherwise, if the id is less than the number of swipes | | |
| 8957 | chat[chat.length - 1]['mes'] = chat[chat.length - 1]['swipes'][chat[chat.length - 1]['swipe_id']]; //load the last mes box with the latest generation | | |
| 8958 | chat[chat.length - 1]['send_date'] = chat[chat.length - 1]?.swipe_info[chat[chat.length - 1]['swipe_id']]?.send_date || chat[chat.length - 1]['send_date']; //update send date | | |
| 8959 | chat[chat.length - 1]['extra'] = structuredClone(chat[chat.length - 1].swipe_info[chat[chat.length - 1]['swipe_id']]?.extra || chat[chat.length - 1].extra || []); | | |
| 8960 | run_swipe_right = true; //then prepare to do normal right swipe to show next message | | |
| 8961 | } | | |
| 8962 | | | |
| 8963 | const currentMessage = $('#chat').children().filter(`[mesid="${chat.length - 1}"]`); | | |
| 8964 | let this_div = currentMessage.find('.swipe_right'); | | |
| 8965 | let this_mes_div = this_div.parent().parent(); | | |
| 8966 | | | |
| 8967 | if (chat[chat.length - 1]['swipe_id'] > chat[chat.length - 1]['swipes'].length) { //if we swipe right while generating (the swipe ID is greater than what we are viewing now) | | |
| 8968 | chat[chat.length - 1]['swipe_id'] = chat[chat.length - 1]['swipes'].length; //show that message slot (will be '...' while generating) | | |
| 8969 | } | | |
| 8970 | if (run_generate) { //hide swipe arrows while generating | | |
| 8971 | this_div.css('display', 'none'); | | |
| 8972 | } | | |
| 8973 | // handles animated transitions when swipe right, specifically height transitions between messages | | |
| 8974 | if (run_generate || run_swipe_right) { | | |
| 8975 | let this_mes_block = this_mes_div.find('.mes_block .mes_text'); | | |
| 8976 | const this_mes_div_height = this_mes_div[0].scrollHeight; | | |
| 8977 | const this_mes_block_height = this_mes_block[0].scrollHeight; | | |
| 8978 | | | |
| 8979 | this_mes_div.children('.swipe_left').css('display', 'flex'); | | |
| 8980 | this_mes_div.children('.mes_block').transition({ // this moves the div back and forth | | |
| 8981 | x: '-' + swipe_range, | | |
| 8982 | duration: animation_duration > 0 ? swipe_duration : 0, | | |
| 8983 | easing: animation_easing, | | |
| 8984 | queue: false, | | |
| 8985 | complete: async function () { | | |
| 8986 | const is_animation_scroll = (chatElement.scrollTop() >= (chatElement.prop('scrollHeight') - chatElement.outerHeight()) - 10); | | |
| 8987 | //console.log(parseInt(chat[chat.length-1]['swipe_id'])); | | |
| 8988 | //console.log(chat[chat.length-1]['swipes'].length); | | |
| 8989 | const swipeMessage = chatElement.find('[mesid="' + (chat.length - 1) + '"]'); | | |
| 8990 | if (run_generate && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { | | |
| 8991 | //shows "..." while generating | | |
| 8992 | swipeMessage.find('.mes_text').html('...'); | | |
| 8993 | // resets the timer | | |
| 8994 | swipeMessage.find('.mes_timer').html(''); | | |
| 8995 | swipeMessage.find('.tokenCounterDisplay').text(''); | | |
| 8996 | updateReasoningUI(swipeMessage, { reset: true }); | | |
| 8997 | } else { | | |
| 8998 | //console.log('showing previously generated swipe candidate, or "..."'); | | |
| 8999 | //console.log('onclick right swipe calling addOneMessage'); | | |
| 9000 | addOneMessage(chat[chat.length - 1], { type: 'swipe' }); | | |
| 9001 | | 9050 | |
| 9002 | if (power_user.message_token_count_enabled) { | 9051 | //If swiping left. |
| 9003 | if (!chat[chat.length - 1].extra) { | 9052 | if (direction === SWIPE_DIRECTION.LEFT) { |
| 9004 | chat[chat.length - 1].extra = {}; | 9053 | newSwipeId--; |
| | 9054 | //Loop to last swipe if negative. |
| | 9055 | if (newSwipeId < 0) { |
| | 9056 | newSwipeId = Math.max(0, chat[mesId]['swipes'].length - 1); |
| 9005 | } | 9057 | } |
| 9006 | | 9058 | //Limit swipe_id to swipes. |
| 9007 | const tokenCountText = (chat[chat.length - 1]?.extra?.reasoning || '') + chat[chat.length - 1].mes; | 9059 | if (newSwipeId > chat[mesId]['swipes'].length - 1) { |
| 9008 | const tokenCount = await getTokenCountAsync(tokenCountText, 0); | 9060 | toastr.warning(`The swipe_id for message #${mesId} was ${newSwipeId}. It has been reset to ${chat[mesId]['swipes'].length - 1}.`); |
| 9009 | chat[chat.length - 1]['extra']['token_count'] = tokenCount; | 9061 | chat[mesId]['swipe_id'] = chat[mesId]['swipes'].length - 1; |
| 9010 | swipeMessage.find('.tokenCounterDisplay').text(`${tokenCount}t`); | 9062 | await endSwipe(); |
| | 9063 | return; |
| 9011 | } | 9064 | } |
| | 9065 | await standardSwipe(); |
| | 9066 | return; |
| 9012 | } | 9067 | } |
| 9013 | let new_height = this_mes_div_height - (this_mes_block_height - this_mes_block[0].scrollHeight); | 9068 | //If swiping right. |
| 9014 | if (new_height < 103) new_height = 103; | 9069 | else if (direction === SWIPE_DIRECTION.RIGHT) { |
| | 9070 | // make new slot in array |
| | 9071 | newSwipeId++; |
| 9015 | | 9072 | |
| | 9073 | //Minimum of zero. |
| | 9074 | if (newSwipeId < 0) { |
| | 9075 | toastr.warning(`The swipe_id for message #${mesId} was ${newSwipeId}. It has been reset to zero.`); |
| | 9076 | chat[mesId]['swipe_id'] = 0; |
| | 9077 | await endSwipe(); |
| | 9078 | return; |
| | 9079 | } |
| 9016 | | 9080 | |
| 9017 | this_mes_div.animate({ height: new_height + 'px' }, { | 9081 | //if swipe id of last message is the same as the length of the 'swipes' array and not the greeting. |
| 9018 | duration: 0, //used to be 100 | 9082 | if (newSwipeId >= chat[mesId]['swipes'].length && ((chat.length !== 1 || !isPristine))) { |
| 9019 | queue: false, | 9083 | newSwipeId = chat[mesId]['swipes'].length; |
| 9020 | progress: function () { | 9084 | |
| 9021 | // Scroll the chat down as the message expands | 9085 | //Update the swipe_id. |
| 9022 | if (is_animation_scroll) chatElement.scrollTop(chatElement[0].scrollHeight); | 9086 | chat[mesId]['swipe_id'] = newSwipeId; |
| 9023 | }, | 9087 | |
| 9024 | complete: function () { | 9088 | //Cancel the generation if it's a user message or the first message in a pristine chat. |
| 9025 | this_mes_div.css('height', 'auto'); | 9089 | if (chat[mesId].is_user || (mesId === 0 && isPristine)) { |
| 9026 | // Scroll the chat down to the bottom once the animation is complete | 9090 | //Cancel swipe. |
| 9027 | if (is_animation_scroll) chatElement.scrollTop(chatElement[0].scrollHeight); | 9091 | chat[mesId]['swipe_id'] = originalSwipeId; |
| 9028 | }, | 9092 | await endSwipe(); |
| 9029 | }); | 9093 | return; |
| 9030 | this_mes_div.children('.mes_block').transition({ | 9094 | //Generate. |
| 9031 | x: swipe_range, | | |
| 9032 | duration: 0, | | |
| 9033 | easing: animation_easing, | | |
| 9034 | queue: false, | | |
| 9035 | complete: function () { | | |
| 9036 | this_mes_div.children('.mes_block').transition({ | | |
| 9037 | x: '0px', | | |
| 9038 | duration: animation_duration > 0 ? swipe_duration : 0, | | |
| 9039 | easing: animation_easing, | | |
| 9040 | queue: false, | | |
| 9041 | complete: async function () { | | |
| 9042 | appendMediaToMessage(chat[chat.length - 1], swipeMessage); | | |
| 9043 | await eventSource.emit(event_types.MESSAGE_SWIPED, (chat.length - 1)); | | |
| 9044 | if (run_generate && !is_send_press && parseInt(chat[chat.length - 1]['swipe_id']) === chat[chat.length - 1]['swipes'].length) { | | |
| 9045 | console.debug('caught here 2'); | | |
| 9046 | is_send_press = true; | | |
| 9047 | await Generate('swipe'); | | |
| 9048 | } else { | 9095 | } else { |
| 9049 | if (parseInt(chat[chat.length - 1]['swipe_id']) !== chat[chat.length - 1]['swipes'].length) { | 9096 | await loadFromSwipeId(mesId, newSwipeId); |
| 9050 | saveChatDebounced(); | 9097 | let run_generate = true; |
| | 9098 | await animateSwipe(run_generate); |
| | 9099 | await endSwipe(); |
| | 9100 | return; |
| | 9101 | } |
| | 9102 | } |
| | 9103 | else { |
| | 9104 | // if swipe_right is called on the last alternate greeting in pristine chats, loop back around |
| | 9105 | if (chat.length === 1 && newSwipeId !== undefined && newSwipeId === chat[0]['swipes'].length && isPristine) { |
| | 9106 | newSwipeId = 0; |
| | 9107 | } |
| | 9108 | } |
| | 9109 | await standardSwipe(); |
| | 9110 | return; |
| 9051 | } | 9111 | } |
| 9052 | } | 9112 | } |
| 9053 | }, | | |
| 9054 | }); | | |
| 9055 | }, | | |
| 9056 | }); | | |
| 9057 | }, | | |
| 9058 | }); | | |
| 9059 | this_mes_div.children('.avatar').transition({ // moves avatar along with swipe | | |
| 9060 | x: '-' + swipe_range, | | |
| 9061 | duration: animation_duration > 0 ? swipe_duration : 0, | | |
| 9062 | easing: animation_easing, | | |
| 9063 | queue: false, | | |
| 9064 | complete: function () { | | |
| 9065 | this_mes_div.children('.avatar').transition({ | | |
| 9066 | x: swipe_range, | | |
| 9067 | duration: 0, | | |
| 9068 | easing: animation_easing, | | |
| 9069 | queue: false, | | |
| 9070 | complete: function () { | | |
| 9071 | this_mes_div.children('.avatar').transition({ | | |
| 9072 | x: '0px', | | |
| 9073 | duration: animation_duration > 0 ? swipe_duration : 0, | | |
| 9074 | easing: animation_easing, | | |
| 9075 | queue: false, | | |
| 9076 | complete: function () { | | |
| 9077 | | 9113 | |
| 9078 | }, | 9114 | /** |
| 9079 | }); | 9115 | * @deprecated Use `swipe` instead. |
| 9080 | }, | 9116 | * Handles the swipe to the left event. |
| 9081 | }); | 9117 | * @param {JQuery.Event} _event Event. |
| 9082 | }, | 9118 | * @param {object} params Additional parameters. |
| 9083 | }); | 9119 | * @param {string} [params.source] The source of the swipe event. |
| | 9120 | * @param {boolean} [params.repeated] Is the swipe event repeated. |
| | 9121 | * @param {object} [params.message] The chat message to swipe. |
| | 9122 | */ |
| | 9123 | export async function swipe_left(_event, { source, repeated, message } = {}) { |
| | 9124 | await swipe.call(this, _event, SWIPE_DIRECTION.LEFT, { source: source, repeated: repeated, message: message }); |
| 9084 | } | 9125 | } |
| | 9126 | |
| | 9127 | /** |
| | 9128 | * @deprecated Use `swipe` instead. |
| | 9129 | * Handles the swipe to the right event. |
| | 9130 | * @param {JQuery.Event} [_event] Event. |
| | 9131 | * @param {object} params Additional parameters. |
| | 9132 | * @param {string} [params.source] The source of the swipe event. |
| | 9133 | * @param {boolean} [params.repeated] Is the swipe event repeated. |
| | 9134 | * @param {object} [params.message] The chat message to swipe. |
| | 9135 | */ |
| | 9136 | //MARK: swipe_right |
| | 9137 | export async function swipe_right(_event = null, { source, repeated, message } = {}) { |
| | 9138 | await swipe.call(this, _event, SWIPE_DIRECTION.RIGHT, { source: source, repeated: repeated, message: message }); |
| 9085 | } | 9139 | } |
| 9086 | | 9140 | |
| 9087 | /** | 9141 | /** |