mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Permanent assistant autocreation and temporary chat restore
This commit is contained in:
@ -23,6 +23,9 @@ import {
|
||||
neutralCharacterName,
|
||||
updateChatMetadata,
|
||||
system_message_types,
|
||||
getSystemMessageByType,
|
||||
printMessages,
|
||||
clearChat,
|
||||
} from '../script.js';
|
||||
import { selected_group } from './group-chats.js';
|
||||
import { power_user } from './power-user.js';
|
||||
@ -37,6 +40,7 @@ import {
|
||||
saveBase64AsFile,
|
||||
extractTextFromOffice,
|
||||
download,
|
||||
getFileText,
|
||||
} from './utils.js';
|
||||
import { extension_settings, renderExtensionTemplateAsync, saveMetadataDebounced } from './extensions.js';
|
||||
import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
|
||||
@ -1497,6 +1501,35 @@ jQuery(function () {
|
||||
download(chatToSave.map((m) => JSON.stringify(m)).join('\n'), `Assistant - ${humanizedDateTime()}.jsonl`, 'application/json');
|
||||
});
|
||||
|
||||
$(document).on('click', '.assistant_note_import', async function () {
|
||||
const importFile = async () => {
|
||||
const file = fileInput.files[0];
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const text = await getFileText(file);
|
||||
const lines = text.split('\n').filter(line => line.trim() !== '');
|
||||
const messages = lines.map(line => JSON.parse(line));
|
||||
const metadata = messages.shift()?.chat_metadata || {};
|
||||
messages.unshift(getSystemMessageByType(system_message_types.ASSISTANT_NOTE));
|
||||
await clearChat();
|
||||
chat.splice(0, chat.length, ...messages);
|
||||
updateChatMetadata(metadata, true);
|
||||
await printMessages();
|
||||
} catch (error) {
|
||||
console.error('Error importing assistant chat:', error);
|
||||
toastr.error(t`It's either corrupted or not a valid JSONL file.`, t`Failed to import chat`);
|
||||
}
|
||||
};
|
||||
const fileInput = document.createElement('input');
|
||||
fileInput.type = 'file';
|
||||
fileInput.accept = '.jsonl';
|
||||
fileInput.addEventListener('change', importFile);
|
||||
fileInput.click();
|
||||
});
|
||||
|
||||
// Do not change. #attachFile is added by extension.
|
||||
$(document).on('click', '#attachFile', function () {
|
||||
$('#file_form_input').trigger('click');
|
||||
|
@ -1,9 +1,13 @@
|
||||
<div data-type="assistant_note">
|
||||
<div>
|
||||
<div class="assistant_note_title">
|
||||
<b data-i18n="Note:">Note:</b> <span data-i18n="this chat is temporary and will be deleted as soon as you leave it.">this chat is temporary and will be deleted as soon as you leave it.</span>
|
||||
<span data-i18n="Click the button to save it as a file.">Click the button to save it as a file.</span>
|
||||
</div>
|
||||
<div class="assistant_note_export menu_button menu_button_icon" data-i18n="[title]Export as JSONL" title="Export as JSONL">
|
||||
<button class="assistant_note_import menu_button menu_button_icon margin0" data-i18n="[title]Import from JSONL" title="Import from JSONL">
|
||||
<i class="fa-solid fa-file-import"></i>
|
||||
<span data-i18n="Load">Load</span>
|
||||
</button>
|
||||
<button class="assistant_note_export menu_button menu_button_icon margin0" data-i18n="[title]Export as JSONL" title="Export as JSONL">
|
||||
<i class="fa-solid fa-file-export"></i>
|
||||
</div>
|
||||
<span data-i18n="Save">Save</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,21 +1,28 @@
|
||||
import {
|
||||
characters,
|
||||
displayVersion,
|
||||
doNewChat,
|
||||
event_types,
|
||||
eventSource,
|
||||
getCharacters,
|
||||
getCurrentChatId,
|
||||
getRequestHeaders,
|
||||
getThumbnailUrl,
|
||||
is_send_press,
|
||||
neutralCharacterName,
|
||||
newAssistantChat,
|
||||
openCharacterChat,
|
||||
selectCharacterById,
|
||||
sendSystemMessage,
|
||||
system_message_types,
|
||||
} from '../script.js';
|
||||
import { is_group_generating } from './group-chats.js';
|
||||
import { t } from './i18n.js';
|
||||
import { renderTemplateAsync } from './templates.js';
|
||||
import { timestampToMoment } from './utils.js';
|
||||
|
||||
const permanentAssistantAvatar = 'default_Assistant.png';
|
||||
|
||||
export async function openWelcomeScreen() {
|
||||
const currentChatId = getCurrentChatId();
|
||||
if (currentChatId !== undefined) {
|
||||
@ -28,7 +35,7 @@ export async function openWelcomeScreen() {
|
||||
|
||||
async function sendWelcomePanel() {
|
||||
try {
|
||||
const chatElement = document.getElementById('chat');
|
||||
const chatElement = document.getElementById('chat');
|
||||
if (!chatElement) {
|
||||
console.error('Chat element not found');
|
||||
return;
|
||||
@ -36,7 +43,7 @@ async function sendWelcomePanel() {
|
||||
const chats = await getRecentChats();
|
||||
const templateData = {
|
||||
chats,
|
||||
empty: !chats.length ,
|
||||
empty: !chats.length,
|
||||
version: displayVersion,
|
||||
};
|
||||
const template = await renderTemplateAsync('welcomePanel', templateData);
|
||||
@ -51,7 +58,7 @@ async function sendWelcomePanel() {
|
||||
});
|
||||
});
|
||||
fragment.querySelector('button.openTemporaryChat').addEventListener('click', () => {
|
||||
void newAssistantChat();
|
||||
void newAssistantChat({ temporary: true });
|
||||
});
|
||||
chatElement.append(fragment.firstChild);
|
||||
} catch (error) {
|
||||
@ -114,7 +121,7 @@ async function getRecentChats() {
|
||||
/** @type {RecentChat[]} */
|
||||
const data = await response.json();
|
||||
|
||||
data.sort((a, b) => b.last_mes - a.last_mes).forEach((chat, index) => {
|
||||
data.sort((a, b) => b.last_mes - a.last_mes).forEach((chat, index) => {
|
||||
const character = characters.find(x => x.avatar === chat.avatar);
|
||||
if (!character) {
|
||||
console.warn(`Character not found for chat: ${chat.file_name}`);
|
||||
@ -133,6 +140,72 @@ async function getRecentChats() {
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function openPermanentAssistantChat({ tryCreate = true } = {}) {
|
||||
const characterId = characters.findIndex(x => x.avatar === permanentAssistantAvatar);
|
||||
if (characterId === -1) {
|
||||
if (!tryCreate) {
|
||||
console.error(`Character not found for avatar ID: ${permanentAssistantAvatar}. Cannot create.`);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`Character not found for avatar ID: ${permanentAssistantAvatar}. Creating new assistant.`);
|
||||
await createPermanentAssistant();
|
||||
return openPermanentAssistantChat({ tryCreate: false });
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error creating permanent assistant:', error);
|
||||
toastr.error(t`Failed to create ${neutralCharacterName}. See console for details.`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await selectCharacterById(characterId);
|
||||
await doNewChat({ deleteCurrentChat: false });
|
||||
console.log(`Opened permanent assistant chat for ${neutralCharacterName}.`, getCurrentChatId());
|
||||
} catch (error) {
|
||||
console.error('Error opening permanent assistant chat:', error);
|
||||
toastr.error(t`Failed to open permanent assistant chat. See console for details.`);
|
||||
}
|
||||
}
|
||||
|
||||
async function createPermanentAssistant() {
|
||||
if (is_group_generating || is_send_press) {
|
||||
throw new Error(t`Cannot create while generating.`);
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('ch_name', neutralCharacterName);
|
||||
formData.append('file_name', permanentAssistantAvatar.replace('.png', ''));
|
||||
|
||||
const headers = getRequestHeaders();
|
||||
delete headers['Content-Type'];
|
||||
|
||||
const fetchResult = await fetch('/api/characters/create', {
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
body: formData,
|
||||
cache: 'no-cache',
|
||||
});
|
||||
|
||||
if (!fetchResult.ok) {
|
||||
throw new Error(t`Creation request did not succeed.`);
|
||||
}
|
||||
|
||||
await getCharacters();
|
||||
}
|
||||
|
||||
export async function openPermanentAssistantCard() {
|
||||
const characterId = characters.findIndex(x => x.avatar === permanentAssistantAvatar);
|
||||
if (characterId === -1) {
|
||||
toastr.info(t`Assistant not found. Try sending a chat message.`);
|
||||
return;
|
||||
}
|
||||
|
||||
await selectCharacterById(characterId);
|
||||
}
|
||||
|
||||
export function initWelcomeScreen() {
|
||||
const events = [event_types.CHAT_CHANGED, event_types.APP_READY];
|
||||
for (const event of events) {
|
||||
|
Reference in New Issue
Block a user