| 7025 | 7025 | $('#select_chat_div').empty(); |
| 7026 | 7026 | $('#select_chat_search').val('').off('input'); |
| 7027 | 7027 | |
| 7028 | | - const data = await (selected_group ? getGroupPastChats(selected_group) : getPastCharacterChats()); |
| 7029 | | - |
| 7030 | | - if (!data) { |
| 7031 | | - toastr.error(t`Could not load chat data. Try reloading the page.`); |
| 7032 | | - return; |
| 7033 | | - } |
| 7034 | | - |
| 7035 | 7028 | const chatDetails = getCurrentChatDetails(); |
| 7036 | | - const group = chatDetails.group; |
| 7037 | 7029 | const currentChat = chatDetails.sessionName; |
| 7038 | 7030 | const displayName = chatDetails.characterName; |
| 7039 | 7031 | const avatarImg = chatDetails.avatarImgURL; |
| 7040 | 7032 | |
| 7041 | 7033 | constawait rawChatsdisplayChats('', =currentChat, awaitdisplayName, getChatsFromFiles(dataavatarImg, selected_group); |
| 7042 | | - |
| 7043 | | - // Sort by last message date descending |
| 7044 | | - data.sort((a, b) => sortMoments(timestampToMoment(a.last_mes), timestampToMoment(b.last_mes))); |
| 7045 | | - console.log(data); |
| 7046 | | - $('#load_select_chat_div').css('display', 'none'); |
| 7047 | | - $('#ChatHistoryCharName').text(`${displayName}'s `); |
| 7048 | 7034 | |
| 7049 | 7035 | const displayChatsdebouncedDisplay = debounce((searchQuery) => { |
| 7050 | | - $('#select_chat_div').empty(); // Clear the current chats before appending filtered chats |
| 7036 | + displayChats(searchQuery, currentChat, displayName, avatarImg, selected_group); |
| 7037 | + }); |
| 7051 | 7038 | |
| 7052 | | - const filteredData = data.filter(chat => { |
| 7039 | + // Define the search input listener |
| 7053 | | - const fileName = chat['file_name']; |
| 7040 | + $('#select_chat_search').on('input', function () { |
| 7054 | | - const chatContent = rawChats[fileName]; |
| 7041 | + const searchQuery = $(this).val(); |
| 7042 | + debouncedDisplay(searchQuery); |
| 7043 | + }); |
| 7055 | 7044 | |
| 7056 | 7045 | // MakeUX sureconvenience: emptyFocus chatsthe aresearch displayedfield when therethe isManage noChat searchFiles queryview opens. |
| 7057 | | - if (Array.isArray(chatContent) && !chatContent.length && !searchQuery) { |
| 7046 | + setTimeout(function () { |
| 7058 | | - return true; |
| 7047 | + const textSearchElement = $('#select_chat_search'); |
| 7048 | + textSearchElement.click(); |
| 7049 | + textSearchElement.focus(); |
| 7050 | + textSearchElement.select(); // select content (if any) for easy erasing |
| 7051 | + }, 200); |
| 7059 | 7052 | } |
| 7060 | 7053 | |
| 7061 | | - // // Uncomment this to return to old behavior (classical full-substring search). |
| 7054 | +async function displayChats(searchQuery, currentChat, displayName, avatarImg, selected_group) { |
| 7062 | | - // return chatContent && Object.values(chatContent).some(message => message?.mes?.toLowerCase()?.includes(searchQuery.toLowerCase())); |
| 7055 | + try { |
| 7056 | + const response = await fetch('/api/chats/search', { |
| 7057 | + method: 'POST', |
| 7058 | + headers: getRequestHeaders(), |
| 7059 | + body: JSON.stringify({ |
| 7060 | + query: searchQuery, |
| 7061 | + avatar_url: selected_group ? null : characters[this_chid].avatar, |
| 7062 | + group_id: selected_group || null |
| 7063 | + }), |
| 7064 | + }); |
| 7063 | 7065 | |
| 7064 | | - // Fragment search a.k.a. swoop (as in `helm-swoop` in the Helm package of Emacs). |
| 7066 | + if (!response.ok) { |
| 7065 | | - // Split a `query` {string} into its fragments {string[]}. |
| 7067 | + throw new Error('Search failed'); |
| 7066 | | - function makeQueryFragments(query) { |
| 7067 | | - let fragments = query.trim().split(/\s+/).map(str => str.trim().toLowerCase()).filter(onlyUnique); |
| 7068 | | - // fragments = fragments.filter( function(str) { return str.length >= 3; } ); // Helm does this, but perhaps better if we don't. |
| 7069 | | - return fragments; |
| 7070 | | - } |
| 7071 | | - // Check whether `text` {string} includes all of the `fragments` {string[]}. |
| 7072 | | - function matchFragments(fragments, text) { |
| 7073 | | - if (!text || !text.toLowerCase) return false; |
| 7074 | | - return fragments.every(item => text.toLowerCase().includes(item)); |
| 7075 | 7068 | } |
| 7076 | | - const fragments = makeQueryFragments(searchQuery); |
| 7077 | | - // At least one chat message must match *all* the fragments. |
| 7078 | | - // Currently, this doesn't match if the fragment matches are distributed across several chat messages. |
| 7079 | | - return chatContent && Object.values(chatContent).some(message => matchFragments(fragments, message?.mes)); |
| 7080 | | - }); |
| 7081 | 7069 | |
| 7082 | | - console.debug(filteredData); |
| 7070 | + const filteredData = await response.json(); |
| 7083 | | - for (const value of filteredData.values()) { |
| 7071 | + $('#select_chat_div').empty(); |
| 7084 | | - let strlen = 300; |
| 7085 | | - let mes = value['mes']; |
| 7086 | 7072 | |
| 7087 | 7073 | if for (mesconst !==chat undefinedof filteredData) { |
| 7088 | | - if (mes.length > strlen) { |
| 7089 | | - mes = '...' + mes.substring(mes.length - strlen); |
| 7090 | | - } |
| 7091 | | - const fileSize = value['file_size']; |
| 7092 | | - const fileName = value['file_name']; |
| 7093 | | - const chatItems = rawChats[fileName].length; |
| 7094 | | - const timestamp = timestampToMoment(value['last_mes']).format('lll'); |
| 7095 | 7074 | const template = $('#past_chat_template .select_chat_block_wrapper').clone(); |
| 7096 | 7075 | template.find('.select_chat_block').attr('file_name', fileNamechat.file_name); |
| 7097 | 7076 | template.find('.avatar img').attr('src', avatarImg); |
| 7098 | 7077 | template.find('.select_chat_block_filename').text(fileNamechat.file_name); |
| 7099 | 7078 | template.find('.chat_file_size').text(`(${fileSizechat.file_size},`); |
| 7100 | 7079 | template.find('.chat_messages_num').text(`${chatItemschat.message_count}💬)`); |
| 7101 | 7080 | template.find('.select_chat_block_mes').text(meschat.preview_message); |
| 7102 | 7081 | template.find('.PastChat_cross').attr('file_name', fileNamechat.file_name); |
| 7103 | 7082 | template.find('.chat_messages_date').text(timestamptimestampToMoment(chat.last_mes).format('lll')); |
| 7104 | | - |
| 7105 | | - if (selected_group) { |
| 7106 | | - template.find('.avatar img').replaceWith(getGroupAvatar(group)); |
| 7107 | | - } |
| 7108 | 7083 | |
| 7109 | 7084 | $('#select_chat_div').append(template); |
| 7110 | 7085 | |
| 7111 | 7086 | if (currentChat === fileName.toString().replace('chat.jsonl', '')file_name) { |
| 7112 | 7087 | $('#select_chat_div').find('.select_chat_block:last').attr('highlight', String(true)); |
| 7113 | 7088 | } |
| 7114 | 7089 | } |
| 7090 | + } catch (error) { |
| 7091 | + console.error('Error loading chats:', error); |
| 7092 | + toastr.error('Could not load chat data. Try reloading the page.'); |
| 7115 | 7093 | } |
| 7116 | | - }; |
| 7117 | | - displayChats(''); // Display all by default |
| 7118 | | - |
| 7119 | | - const debouncedDisplay = debounce((searchQuery) => { |
| 7120 | | - displayChats(searchQuery); |
| 7121 | | - }); |
| 7122 | | - |
| 7123 | | - // Define the search input listener |
| 7124 | | - $('#select_chat_search').on('input', function () { |
| 7125 | | - const searchQuery = $(this).val(); |
| 7126 | | - debouncedDisplay(searchQuery); |
| 7127 | | - }); |
| 7128 | | - |
| 7129 | | - // UX convenience: Focus the search field when the Manage Chat Files view opens. |
| 7130 | | - setTimeout(function () { |
| 7131 | | - const textSearchElement = $('#select_chat_search'); |
| 7132 | | - textSearchElement.click(); |
| 7133 | | - textSearchElement.focus(); |
| 7134 | | - textSearchElement.select(); // select content (if any) for easy erasing |
| 7135 | | - }, 200); |
| 7136 | 7094 | } |
| 7137 | 7095 | |
| 7138 | 7096 | export function selectRightMenuWithAnimation(selectedMenuId) { |