Permanent assistant autocreation and temporary chat restore

This commit is contained in:
Cohee
2025-05-12 02:14:54 +03:00
parent 61f69aa674
commit 31e2cf714a
6 changed files with 160 additions and 21 deletions

View File

@ -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');

View File

@ -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>

View File

@ -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) {