Chat without character selected (#2757) * WIP: Enable chatting without character selected * Add burger menu item * Neutral assistant chat space * Revert "Neutral assistant chat space" This reverts commit be2da4a629fb8cfef2f7387272eec9d88b9c4328. * Revert "Add burger menu item" This reverts commit d4e8d990c1ae847a4bc18ee0d4b886cbcd065b7f. * Use simple ephemeral chats * Only start a new assistant chat if not already in it * Don't emit event not to clear pending files * Allow edits, disable checkpoints and branches * Exclude from tags, allow copy * Allow hide/unhide * Allow zooming avatar * Suppress warning * Rename neutral character * Rename neutral back to Assistant
Signed| @@ -484,9 +484,10 @@ const promptStorage = new localforage.createInstance({ name: 'SillyTavern_Prompt | ||
| 484 | 484 | export let itemizedPrompts = []; |
| 485 | 485 | |
| 486 | 486 | export const systemUserName = 'SillyTavern System'; |
| 487 | +export const neutralCharacterName = 'Assistant'; | |
| 487 | 488 | let default_user_name = 'User'; |
| 488 | 489 | export let name1 = default_user_name; |
| 489 | 490 | export let name2 = 'SillyTavern System'systemUserName; |
| 490 | 491 | export let chat = []; |
| 491 | 492 | let chatSaveTimeout; |
| 492 | 493 | let importFlashTimeout; |
| @@ -563,6 +564,8 @@ export const system_message_types = { | ||
| 563 | 564 | FORMATTING: 'formatting', |
| 564 | 565 | HOTKEYS: 'hotkeys', |
| 565 | 566 | MACROS: 'macros', |
| 567 | + WELCOME_PROMPT: 'welcome_prompt', | |
| 568 | + ASSISTANT_NOTE: 'assistant_note', | |
| 566 | 569 | }; |
| 567 | 570 | |
| 568 | 571 | /** |
| @@ -680,6 +683,26 @@ async function getSystemMessages() { | ||
| 680 | 683 | is_system: true, |
| 681 | 684 | mes: 'Click here to return to the previous chat: <a class="bookmark_link" file_name="{0}" href="javascript:void(null);">Return</a>', |
| 682 | 685 | }, |
| 686 | + welcome_prompt: { | |
| 687 | + name: systemUserName, | |
| 688 | + force_avatar: system_avatar, | |
| 689 | + is_user: false, | |
| 690 | + is_system: true, | |
| 691 | + mes: await renderTemplateAsync('welcomePrompt'), | |
| 692 | + extra: { | |
| 693 | + isSmallSys: true, | |
| 694 | + }, | |
| 695 | + }, | |
| 696 | + assistant_note: { | |
| 697 | + name: systemUserName, | |
| 698 | + force_avatar: system_avatar, | |
| 699 | + is_user: false, | |
| 700 | + is_system: true, | |
| 701 | + mes: await renderTemplateAsync('assistantNote'), | |
| 702 | + extra: { | |
| 703 | + isSmallSys: true, | |
| 704 | + }, | |
| 705 | + }, | |
| 683 | 706 | }; |
| 684 | 707 | } |
| 685 | 708 | |
| @@ -924,6 +947,7 @@ async function firstLoadInit() { | ||
| 924 | 947 | initTextGenModels(); |
| 925 | 948 | await getSystemMessages(); |
| 926 | 949 | sendSystemMessage(system_message_types.WELCOME); |
| 950 | + sendSystemMessage(system_message_types.WELCOME_PROMPT); | |
| 927 | 951 | await getSettings(); |
| 928 | 952 | initKeyboard(); |
| 929 | 953 | initDynamicStyles(); |
| @@ -1849,7 +1873,7 @@ export async function reloadCurrentChat() { | ||
| 1849 | 1873 | /** |
| 1850 | 1874 | * Send the message currently typed into the chat box. |
| 1851 | 1875 | */ |
| 1852 | 1876 | export async function sendTextareaMessage() { |
| 1853 | 1877 | if (is_send_press) return; |
| 1854 | 1878 | if (isExecutingCommandsFromChatInput) return; |
| 1855 | 1879 | |
| @@ -1867,6 +1891,10 @@ export function sendTextareaMessage() { | ||
| 1867 | 1891 | generateType = 'continue'; |
| 1868 | 1892 | } |
| 1869 | 1893 | |
| 1894 | + if (textareaText && !selected_group && this_chid === undefined && name2 !== neutralCharacterName) { | |
| 1895 | + await newAssistantChat(); | |
| 1896 | + } | |
| 1897 | + | |
| 1870 | 1898 | Generate(generateType); |
| 1871 | 1899 | } |
| 1872 | 1900 | |
| @@ -1946,9 +1974,7 @@ export function messageFormatting(mes, ch_name, isSystem, isUser, messageId) { | ||
| 1946 | 1974 | mes = mes.replaceAll('<', '<').replaceAll('>', '>'); |
| 1947 | 1975 | } |
| 1948 | 1976 | |
| 1949 | 1977 | if (this_chid === undefined && !selected_groupisSystem) { |
| 1950 | - mes = mes.replace(/\*\*(.+?)\*\*/g, '<b>$1</b>'); | |
| 1951 | - } else if (!isSystem) { | |
| 1952 | 1978 | // Save double quotes in tags as a special character to prevent them from being encoded |
| 1953 | 1979 | if (!power_user.encode_tags) { |
| 1954 | 1980 | mes = mes.replace(/<([^>]+)>/g, function (_, contents) { |
| @@ -1987,13 +2013,6 @@ export function messageFormatting(mes, ch_name, isSystem, isUser, messageId) { | ||
| 1987 | 2013 | }); |
| 1988 | 2014 | } |
| 1989 | 2015 | |
| 1990 | - /* | |
| 1991 | - // Hides bias from empty messages send with slash commands | |
| 1992 | - if (isSystem) { | |
| 1993 | - mes = mes.replace(/\{\{[\s\S]*?\}\}/gm, ""); | |
| 1994 | - } | |
| 1995 | - */ | |
| 1996 | - | |
| 1997 | 2016 | if (!power_user.allow_name2_display && ch_name && !isUser && !isSystem) { |
| 1998 | 2017 | mes = mes.replace(new RegExp(`(^|\n)${escapeRegex(ch_name)}:`, 'g'), '$1'); |
| 1999 | 2018 | } |
| @@ -3400,14 +3419,11 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 3400 | 3419 | quiet_prompt = main_api == 'novel' && !quietToLoud ? adjustNovelInstructionPrompt(quiet_prompt) : quiet_prompt; |
| 3401 | 3420 | } |
| 3402 | 3421 | |
| 3403 | 3422 | const isChatValidhasBackendConnection = online_status !== 'no_connection' && this_chid !== undefined; |
| 3404 | 3423 | |
| 3405 | 3424 | // We can't do anything because we're not in a chat right now. (Unless it's a dry run, in which case we need to |
| 3406 | 3425 | // assemble the prompt so we can count its tokens regardless of whether a chat is active.) |
| 3407 | 3426 | if (!dryRun && !isChatValidhasBackendConnection) { |
| 3408 | - if (this_chid === undefined) { | |
| 3409 | - toastr.warning('Сharacter is not selected'); | |
| 3410 | - } | |
| 3411 | 3427 | is_send_press = false; |
| 3412 | 3428 | return Promise.resolve(); |
| 3413 | 3429 | } |
| @@ -3493,9 +3509,9 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 3493 | 3509 | setExtensionPrompt('DEPTH_PROMPT_' + index, value.text, extension_prompt_types.IN_CHAT, value.depth, extension_settings.note.allowWIScan, role); |
| 3494 | 3510 | }); |
| 3495 | 3511 | } else { |
| 3496 | 3512 | const depthPromptText = baseChatReplace(characters[this_chid]?.data?.extensions?.depth_prompt?.prompt?.trim(), name1, name2) || ''; |
| 3497 | 3513 | const depthPromptDepth = characters[this_chid]?.data?.extensions?.depth_prompt?.depth ?? depth_prompt_depth_default; |
| 3498 | 3514 | const depthPromptRole = getExtensionPromptRoleByName(characters[this_chid]?.data?.extensions?.depth_prompt?.role ?? depth_prompt_role_default); |
| 3499 | 3515 | setExtensionPrompt('DEPTH_PROMPT', depthPromptText, extension_prompt_types.IN_CHAT, depthPromptDepth, extension_settings.note.allowWIScan, depthPromptRole); |
| 3500 | 3516 | } |
| 3501 | 3517 | |
| @@ -5905,11 +5921,16 @@ export function saveChatDebounced() { | ||
| 5905 | 5921 | }, 1000); |
| 5906 | 5922 | } |
| 5907 | 5923 | |
| 5908 | 5924 | export async function saveChat(chat_namechatName, withMetadata, mesId) { |
| 5909 | 5925 | const metadata = { ...chat_metadata, ...(withMetadata || {}) }; |
| 5910 | 5926 | letconst file_namefileName = chat_namechatName ?? characters[this_chid]?.chat; |
| 5911 | 5927 | |
| 5912 | 5928 | if (!file_namefileName && name2 === neutralCharacterName) { |
| 5929 | + // TODO: Do something for a temporary chat with no character. | |
| 5930 | + return; | |
| 5931 | + } | |
| 5932 | + | |
| 5933 | + if (!fileName) { | |
| 5913 | 5934 | console.warn('saveChat called without chat_name and no chat file found'); |
| 5914 | 5935 | return; |
| 5915 | 5936 | } |
| @@ -5950,7 +5971,7 @@ export async function saveChat(chat_name, withMetadata, mesId) { | ||
| 5950 | 5971 | url: '/api/chats/save', |
| 5951 | 5972 | data: JSON.stringify({ |
| 5952 | 5973 | ch_name: characters[this_chid].name, |
| 5953 | 5974 | file_name: file_namefileName, |
| 5954 | 5975 | chat: save_chat, |
| 5955 | 5976 | avatar_url: characters[this_chid].avatar, |
| 5956 | 5977 | }), |
| @@ -6665,7 +6686,7 @@ function updateMessage(div) { | ||
| 6665 | 6686 | function openMessageDelete(fromSlashCommand) { |
| 6666 | 6687 | closeMessageEditor(); |
| 6667 | 6688 | hideSwipeButtons(); |
| 6668 | 6689 | if (fromSlashCommand || (this_chid != undefined && !is_send_press) || (selected_group && !is_group_generating)) { |
| 6669 | 6690 | $('#dialogue_del_mes').css('display', 'block'); |
| 6670 | 6691 | $('#send_form').css('display', 'none'); |
| 6671 | 6692 | $('.del_checkbox').each(function () { |
| @@ -8218,6 +8239,11 @@ function swipe_left() { // when we swipe left..but no generation. | ||
| 8218 | 8239 | * @returns {Promise<string>} Branch file name |
| 8219 | 8240 | */ |
| 8220 | 8241 | async function branchChat(mesId) { |
| 8242 | + if (this_chid === undefined && !selected_group) { | |
| 8243 | + toastr.info('No character selected.', 'Branch creation aborted'); | |
| 8244 | + return; | |
| 8245 | + } | |
| 8246 | + | |
| 8221 | 8247 | const fileName = await createBranch(mesId); |
| 8222 | 8248 | await saveItemizedPrompts(fileName); |
| 8223 | 8249 | |
| @@ -8955,6 +8981,14 @@ async function removeCharacterFromUI() { | ||
| 8955 | 8981 | saveSettingsDebounced(); |
| 8956 | 8982 | } |
| 8957 | 8983 | |
| 8984 | +async function newAssistantChat() { | |
| 8985 | + await clearChat(); | |
| 8986 | + chat.splice(0, chat.length); | |
| 8987 | + chat_metadata = {}; | |
| 8988 | + setCharacterName(neutralCharacterName); | |
| 8989 | + sendSystemMessage(system_message_types.ASSISTANT_NOTE); | |
| 8990 | +} | |
| 8991 | + | |
| 8958 | 8992 | function doTogglePanels() { |
| 8959 | 8993 | $('#option_settings').trigger('click'); |
| 8960 | 8994 | return ''; |
| @@ -9800,6 +9834,9 @@ jQuery(async function () { | ||
| 9800 | 9834 | |
| 9801 | 9835 | await doNewChat({ deleteCurrentChat: deleteCurrentChat }); |
| 9802 | 9836 | } |
| 9837 | + if (!selected_group && this_chid === undefined && !is_send_press) { | |
| 9838 | + await newAssistantChat(); | |
| 9839 | + } | |
| 9803 | 9840 | } |
| 9804 | 9841 | |
| 9805 | 9842 | else if (id == 'option_regenerate') { |
| @@ -9850,6 +9887,7 @@ jQuery(async function () { | ||
| 9850 | 9887 | $('#rm_button_selected_ch').children('h2').text(''); |
| 9851 | 9888 | select_rm_characters(); |
| 9852 | 9889 | sendSystemMessage(system_message_types.WELCOME); |
| 9890 | + sendSystemMessage(system_message_types.WELCOME_PROMPT); | |
| 9853 | 9891 | eventSource.emit(event_types.CHAT_CHANGED, getCurrentChatId()); |
| 9854 | 9892 | await getClientVersion(); |
| 9855 | 9893 | } else { |
| @@ -10048,7 +10086,7 @@ jQuery(async function () { | ||
| 10048 | 10086 | } |
| 10049 | 10087 | else { |
| 10050 | 10088 | $(document).on('pointerup', '.mes_copy', function () { |
| 10051 | 10089 | if (this_chid !== undefined || selected_group || name2 === neutralCharacterName) { |
| 10052 | 10090 | try { |
| 10053 | 10091 | const messageId = $(this).closest('.mes').attr('mesid'); |
| 10054 | 10092 | const text = chat[messageId]['mes']; |
| @@ -10072,7 +10110,7 @@ jQuery(async function () { | ||
| 10072 | 10110 | //******************** |
| 10073 | 10111 | //***Message Editor*** |
| 10074 | 10112 | $(document).on('click', '.mes_edit', async function () { |
| 10075 | 10113 | if (this_chid !== undefined || selected_group || name2 === neutralCharacterName) { |
| 10076 | 10114 | // Previously system messages we're allowed to be edited |
| 10077 | 10115 | /*const message = $(this).closest(".mes"); |
| 10078 | 10116 | |
| @@ -10664,7 +10702,7 @@ jQuery(async function () { | ||
| 10664 | 10702 | }); |
| 10665 | 10703 | } |
| 10666 | 10704 | |
| 10667 | 10705 | const avatarSrc = (isDataURL(thumbURL) || /^\/?img\/(?:.+)/.test(thumbURL)) ? thumbURL : charsPath + targetAvatarImg; |
| 10668 | 10706 | if ($(`.zoomed_avatar[forChar="${charname}"]`).length) { |
| 10669 | 10707 | console.debug('removing container as it already existed'); |
| 10670 | 10708 | $(`.zoomed_avatar[forChar="${charname}"]`).fadeOut(animation_duration, () => { |
| @@ -168,6 +168,11 @@ export async function createBranch(mesId) { | ||
| 168 | 168 | } |
| 169 | 169 | |
| 170 | 170 | async function createNewBookmark(mesId) { |
| 171 | + if (this_chid === undefined && !selected_group) { | |
| 172 | + toastr.info('No character selected.', 'Checkpoint creation aborted'); | |
| 173 | + return; | |
| 174 | + } | |
| 175 | + | |
| 171 | 176 | if (!chat.length) { |
| 172 | 177 | toastr.warning('The chat is empty.', 'Checkpoint creation failed'); |
| 173 | 178 | return; |
| @@ -125,8 +125,6 @@ function getConverter(type) { | ||
| 125 | 125 | * @returns {Promise<void>} |
| 126 | 126 | */ |
| 127 | 127 | export async function hideChatMessageRange(start, end, unhide) { |
| 128 | - if (!getCurrentChatId()) return; | |
| 129 | - | |
| 130 | 128 | if (isNaN(start)) return; |
| 131 | 129 | if (!end) end = start; |
| 132 | 130 | const hide = !unhide; |
| @@ -0,0 +1,3 @@ | ||
| 1 | +<div> | |
| 2 | + <b>Note:</b> this chat is temporary and will be deleted as soon as you leave it. | |
| 3 | +</div> | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +<strong data-i18n="Connect to an API and ask me anything!"> | |
| 2 | + Connect to an API and ask me anything! | |
| 3 | +</strong> | |