Compare commits

...

2 Commits

Author SHA1 Message Date
Cohee d9d76ba16d #2164 Add error toasts to VecStore 2024-04-30 00:17:39 +03:00
Cohee 993284f9c1 #2164 Disable-able data bank attachments 2024-04-30 00:06:14 +03:00
5 changed files with 96 additions and 11 deletions

View File

@ -685,6 +685,30 @@ async function downloadAttachment(attachment) {
URL.revokeObjectURL(url);
}
/**
* Removes an attachment from the disabled list.
* @param {FileAttachment} attachment Attachment to enable
* @param {function} callback Success callback
*/
function enableAttachment(attachment, callback) {
ensureAttachmentsExist();
extension_settings.disabled_attachments = extension_settings.disabled_attachments.filter(url => url !== attachment.url);
saveSettingsDebounced();
callback();
}
/**
* Adds an attachment to the disabled list.
* @param {FileAttachment} attachment Attachment to disable
* @param {function} callback Success callback
*/
function disableAttachment(attachment, callback) {
ensureAttachmentsExist();
extension_settings.disabled_attachments.push(attachment.url);
saveSettingsDebounced();
callback();
}
/**
* Moves a file attachment to a different source.
* @param {FileAttachment} attachment Attachment to moves
@ -752,11 +776,25 @@ async function deleteAttachment(attachment, source, callback, confirm = true) {
break;
}
if (Array.isArray(extension_settings.disabled_attachments) && extension_settings.disabled_attachments.includes(attachment.url)) {
extension_settings.disabled_attachments = extension_settings.disabled_attachments.filter(url => url !== attachment.url);
saveSettingsDebounced();
}
const silent = confirm === false;
await deleteFileFromServer(attachment.url, silent);
callback();
}
/**
* Determines if the attachment is disabled.
* @param {FileAttachment} attachment Attachment to check
* @returns {boolean} True if attachment is disabled, false otherwise.
*/
function isAttachmentDisabled(attachment) {
return extension_settings.disabled_attachments.some(url => url === attachment?.url);
}
/**
* Opens the attachment manager.
*/
@ -806,7 +844,9 @@ async function openAttachmentManager() {
const sortedAttachmentList = attachments.slice().filter(filterFn).sort(sortFn);
for (const attachment of sortedAttachmentList) {
const isDisabled = isAttachmentDisabled(attachment);
const attachmentTemplate = template.find('.attachmentListItemTemplate .attachmentListItem').clone();
attachmentTemplate.toggleClass('disabled', isDisabled);
attachmentTemplate.find('.attachmentFileIcon').attr('title', attachment.url);
attachmentTemplate.find('.attachmentListItemName').text(attachment.name);
attachmentTemplate.find('.attachmentListItemSize').text(humanFileSize(attachment.size));
@ -816,6 +856,8 @@ async function openAttachmentManager() {
attachmentTemplate.find('.deleteAttachmentButton').on('click', () => deleteAttachment(attachment, source, renderAttachments));
attachmentTemplate.find('.downloadAttachmentButton').on('click', () => downloadAttachment(attachment));
attachmentTemplate.find('.moveAttachmentButton').on('click', () => moveAttachment(attachment, source, renderAttachments));
attachmentTemplate.find('.enableAttachmentButton').toggle(isDisabled).on('click', () => enableAttachment(attachment, renderAttachments));
attachmentTemplate.find('.disableAttachmentButton').toggle(!isDisabled).on('click', () => disableAttachment(attachment, renderAttachments));
template.find(sources[source]).append(attachmentTemplate);
}
}
@ -1117,6 +1159,10 @@ export async function uploadFileAttachmentToServer(file, target) {
}
function ensureAttachmentsExist() {
if (!Array.isArray(extension_settings.disabled_attachments)) {
extension_settings.disabled_attachments = [];
}
if (!Array.isArray(extension_settings.attachments)) {
extension_settings.attachments = [];
}
@ -1137,7 +1183,7 @@ function ensureAttachmentsExist() {
}
/**
* Gets all currently available attachments.
* Gets all currently available attachments. Ignores disabled attachments.
* @returns {FileAttachment[]} List of attachments
*/
export function getDataBankAttachments() {
@ -1146,11 +1192,11 @@ export function getDataBankAttachments() {
const chatAttachments = chat_metadata.attachments ?? [];
const characterAttachments = extension_settings.character_attachments?.[characters[this_chid]?.avatar] ?? [];
return [...globalAttachments, ...chatAttachments, ...characterAttachments];
return [...globalAttachments, ...chatAttachments, ...characterAttachments].filter(x => !isAttachmentDisabled(x));
}
/**
* Gets all attachments for a specific source.
* Gets all attachments for a specific source. Includes disabled attachments.
* @param {string} source Attachment source
* @returns {FileAttachment[]} List of attachments
*/
@ -1165,6 +1211,8 @@ export function getDataBankAttachmentsForSource(source) {
case ATTACHMENT_SOURCE.CHARACTER:
return extension_settings.character_attachments?.[characters[this_chid]?.avatar] ?? [];
}
return [];
}
/**

View File

@ -145,8 +145,18 @@ const extension_settings = {
variables: {
global: {},
},
/**
* @type {import('./chats.js').FileAttachment[]}
*/
attachments: [],
/**
* @type {Record<string, import('./chats.js').FileAttachment[]>}
*/
character_attachments: {},
/**
* @type {string[]}
*/
disabled_attachments: [],
};
let modules = [];

View File

@ -106,11 +106,13 @@
<div class="attachmentListItemName flex1"></div>
<small class="attachmentListItemCreated"></small>
<small class="attachmentListItemSize"></small>
<div class="viewAttachmentButton right_menu_button fa-solid fa-magnifying-glass" title="View attachment content"></div>
<div class="moveAttachmentButton right_menu_button fa-solid fa-arrows-alt" title="Move attachment"></div>
<div class="editAttachmentButton right_menu_button fa-solid fa-pencil" title="Edit attachment"></div>
<div class="downloadAttachmentButton right_menu_button fa-solid fa-download" title="Download attachment"></div>
<div class="deleteAttachmentButton right_menu_button fa-solid fa-trash" title="Delete attachment"></div>
<div class="viewAttachmentButton right_menu_button fa-fw fa-solid fa-magnifying-glass" title="View attachment content"></div>
<div class="disableAttachmentButton right_menu_button fa-fw fa-solid fa-comment" title="Disable attachment"></div>
<div class="enableAttachmentButton right_menu_button fa-fw fa-solid fa-comment-slash" title="Enable attachment"></div>
<div class="moveAttachmentButton right_menu_button fa-fw fa-solid fa-arrows-alt" title="Move attachment"></div>
<div class="editAttachmentButton right_menu_button fa-fw fa-solid fa-pencil" title="Edit attachment"></div>
<div class="downloadAttachmentButton right_menu_button fa-fw fa-solid fa-download" title="Download attachment"></div>
<div class="deleteAttachmentButton right_menu_button fa-fw fa-solid fa-trash" title="Delete attachment"></div>
</div>
</div>

View File

@ -19,6 +19,16 @@
padding: 10px;
}
.attachmentListItem.disabled .attachmentListItemName {
text-decoration: line-through;
opacity: 0.75;
}
.attachmentListItem.disabled .attachmentFileIcon {
opacity: 0.75;
cursor: not-allowed;
}
.attachmentListItemSize {
min-width: 4em;
text-align: right;

View File

@ -281,7 +281,7 @@ async function synchronizeChat(batchSize = 5) {
console.error('Vectors: Failed to synchronize chat', error);
const message = getErrorMessage(error.cause);
toastr.error(message, 'Vectorization failed');
toastr.error(message, 'Vectorization failed', { preventDuplicates: true });
return -1;
} finally {
syncBlocked = false;
@ -444,6 +444,7 @@ async function retrieveFileChunks(queryText, collectionId) {
* @param {string} fileName File name
* @param {string} collectionId File collection ID
* @param {number} chunkSize Chunk size
* @returns {Promise<boolean>} True if successful, false if not
*/
async function vectorizeFile(fileText, fileName, collectionId, chunkSize) {
try {
@ -462,8 +463,11 @@ async function vectorizeFile(fileText, fileName, collectionId, chunkSize) {
toastr.clear(toast);
console.log(`Vectors: Inserted ${chunks.length} vector items for file ${fileName} into ${collectionId}`);
return true;
} catch (error) {
toastr.error(String(error), 'Failed to vectorize file', { preventDuplicates: true });
console.error('Vectors: Failed to vectorize file', error);
return false;
}
}
@ -546,6 +550,7 @@ async function rearrangeChat(chat) {
const insertedText = getPromptText(queriedMessages);
setExtensionPrompt(EXTENSION_PROMPT_TAG, insertedText, settings.position, settings.depth, settings.include_wi);
} catch (error) {
toastr.error('Generation interceptor aborted. Check browser console for more details.', 'Vector Storage');
console.error('Vectors: Failed to rearrange chat', error);
}
}
@ -911,6 +916,8 @@ async function onVectorizeAllFilesClick() {
const chatAttachments = getContext().chat.filter(x => x.extra?.file).map(x => x.extra.file);
const allFiles = [...dataBank, ...chatAttachments];
let allSuccess = true;
for (const file of allFiles) {
const text = await getFileAttachment(file.url);
const collectionId = getFileCollectionId(file.url);
@ -921,10 +928,18 @@ async function onVectorizeAllFilesClick() {
continue;
}
await vectorizeFile(text, file.name, collectionId, settings.chunk_size);
const result = await vectorizeFile(text, file.name, collectionId, settings.chunk_size);
if (!result) {
allSuccess = false;
}
}
toastr.success('All files vectorized', 'Vectorization successful');
if (allSuccess) {
toastr.success('All files vectorized', 'Vectorization successful');
} else {
toastr.warning('Some files failed to vectorize. Check browser console for more details.', 'Vector Storage');
}
} catch (error) {
console.error('Vectors: Failed to vectorize all files', error);
toastr.error('Failed to vectorize all files', 'Vectorization failed');