From 9fee731cacda05f069840507efb2689801faf064 Mon Sep 17 00:00:00 2001 From: LenAnderson Date: Thu, 18 Apr 2024 09:23:52 -0400 Subject: [PATCH 01/10] only close last popup with escape --- public/scripts/popup.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/public/scripts/popup.js b/public/scripts/popup.js index 4e75431f4..d29b2514d 100644 --- a/public/scripts/popup.js +++ b/public/scripts/popup.js @@ -22,6 +22,10 @@ export const POPUP_RESULT = { export class Popup { + /**@type {Popup[]}*/ + static stack = []; + + /**@type {POPUP_TYPE}*/ type; /**@type {HTMLElement}*/ dom; @@ -119,11 +123,13 @@ export class Popup { const keyListener = (evt) => { switch (evt.key) { case 'Escape': { - evt.preventDefault(); - evt.stopPropagation(); - this.completeCancelled(); - window.removeEventListener('keydown', keyListenerBound); - break; + if (Popup.stack.slice(-1)[0] == this) { + evt.preventDefault(); + evt.stopPropagation(); + this.completeCancelled(); + window.removeEventListener('keydown', keyListenerBound); + break; + } } } }; @@ -132,6 +138,7 @@ export class Popup { } async show() { + Popup.stack.push(this); document.body.append(this.dom); this.dom.style.display = 'block'; switch (this.type) { @@ -198,6 +205,7 @@ export class Popup { hide() { + Popup.stack.splice(Popup.stack.indexOf(this), 1); $(this.dom).transition({ opacity: 0, duration: animation_duration, From 0ab5ddf763a9108936afc6d9822e06683e95036c Mon Sep 17 00:00:00 2001 From: LenAnderson Date: Thu, 18 Apr 2024 14:00:27 -0400 Subject: [PATCH 02/10] use elementFromPoint instead of popup stack --- public/scripts/popup.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/public/scripts/popup.js b/public/scripts/popup.js index d29b2514d..c69aa6e60 100644 --- a/public/scripts/popup.js +++ b/public/scripts/popup.js @@ -22,10 +22,6 @@ export const POPUP_RESULT = { export class Popup { - /**@type {Popup[]}*/ - static stack = []; - - /**@type {POPUP_TYPE}*/ type; /**@type {HTMLElement}*/ dom; @@ -123,7 +119,9 @@ export class Popup { const keyListener = (evt) => { switch (evt.key) { case 'Escape': { - if (Popup.stack.slice(-1)[0] == this) { + // does it really matter where we check? + const topModal = document.elementFromPoint(window.innerWidth / 2, window.innerHeight / 2)?.closest('.shadow_popup'); + if (topModal == this.dom) { evt.preventDefault(); evt.stopPropagation(); this.completeCancelled(); @@ -138,7 +136,6 @@ export class Popup { } async show() { - Popup.stack.push(this); document.body.append(this.dom); this.dom.style.display = 'block'; switch (this.type) { @@ -205,7 +202,6 @@ export class Popup { hide() { - Popup.stack.splice(Popup.stack.indexOf(this), 1); $(this.dom).transition({ opacity: 0, duration: animation_duration, From 3822ae9356dd3dcf80eb8f9c41ed061cd3fb53dc Mon Sep 17 00:00:00 2001 From: Isaac McFadyen Date: Thu, 18 Apr 2024 15:50:27 -0400 Subject: [PATCH 03/10] Switched fs.renameSync to fs.copyFileSync --- post-install.js | 3 ++- src/endpoints/assets.js | 3 ++- src/endpoints/backgrounds.js | 6 ++++-- src/endpoints/characters.js | 3 ++- src/endpoints/chats.js | 3 ++- src/users.js | 6 ++++-- 6 files changed, 16 insertions(+), 8 deletions(-) diff --git a/post-install.js b/post-install.js index 645085a8a..f787eeba3 100644 --- a/post-install.js +++ b/post-install.js @@ -60,7 +60,8 @@ function convertConfig() { try { console.log(color.blue('Converting config.conf to config.yaml. Your old config.conf will be renamed to config.conf.bak')); const config = require(path.join(process.cwd(), './config.conf')); - fs.renameSync('./config.conf', './config.conf.bak'); + fs.copyFileSync('./config.conf', './config.conf.bak'); + fs.rmSync('./config.conf'); fs.writeFileSync('./config.yaml', yaml.stringify(config)); console.log(color.green('Conversion successful. Please check your config.yaml and fix it if necessary.')); } catch (error) { diff --git a/src/endpoints/assets.js b/src/endpoints/assets.js index a9dc317d6..78f5270a7 100644 --- a/src/endpoints/assets.js +++ b/src/endpoints/assets.js @@ -227,7 +227,8 @@ router.post('/download', jsonParser, async (request, response) => { // Move into asset place console.debug('Download finished, moving file from', temp_path, 'to', file_path); - fs.renameSync(temp_path, file_path); + fs.copyFileSync(temp_path, file_path); + fs.rmSync(temp_path); response.sendStatus(200); } catch (error) { diff --git a/src/endpoints/backgrounds.js b/src/endpoints/backgrounds.js index 33419ef4f..b8965ab5f 100644 --- a/src/endpoints/backgrounds.js +++ b/src/endpoints/backgrounds.js @@ -51,7 +51,8 @@ router.post('/rename', jsonParser, function (request, response) { return response.sendStatus(400); } - fs.renameSync(oldFileName, newFileName); + fs.copyFileSync(oldFileName, newFileName); + fs.rmSync(oldFileName); invalidateThumbnail(request.user.directories, 'bg', request.body.old_bg); return response.send('ok'); }); @@ -63,7 +64,8 @@ router.post('/upload', urlencodedParser, function (request, response) { const filename = request.file.originalname; try { - fs.renameSync(img_path, path.join(request.user.directories.backgrounds, filename)); + fs.copyFileSync(img_path, path.join(request.user.directories.backgrounds, filename)); + fs.rmSync(img_path); invalidateThumbnail(request.user.directories, 'bg', filename); response.send(filename); } catch (err) { diff --git a/src/endpoints/characters.js b/src/endpoints/characters.js index f9ff18688..3fa022a8e 100644 --- a/src/endpoints/characters.js +++ b/src/endpoints/characters.js @@ -680,7 +680,8 @@ router.post('/rename', jsonParser, async function (request, response) { // Rename chats folder if (fs.existsSync(oldChatsPath) && !fs.existsSync(newChatsPath)) { - fs.renameSync(oldChatsPath, newChatsPath); + fs.cpSync(oldChatsPath, newChatsPath); + fs.rmSync(oldChatsPath, { recursive: true, force: true }); } // Remove the old character file diff --git a/src/endpoints/chats.js b/src/endpoints/chats.js index 49cf98e01..ff55d3ff0 100644 --- a/src/endpoints/chats.js +++ b/src/endpoints/chats.js @@ -213,8 +213,9 @@ router.post('/rename', jsonParser, async function (request, response) { return response.status(400).send({ error: true }); } + fs.copyFileSync(pathToOriginalFile, pathToRenamedFile); + fs.rmSync(pathToOriginalFile); console.log('Successfully renamed.'); - fs.renameSync(pathToOriginalFile, pathToRenamedFile); return response.send({ ok: true }); }); diff --git a/src/users.js b/src/users.js index 8781334e3..8e2394fc5 100644 --- a/src/users.js +++ b/src/users.js @@ -286,12 +286,14 @@ async function migrateUserData() { // Copy the file to the new location fs.cpSync(migration.old, migration.new, { force: true }); // Move the file to the backup location - fs.renameSync(migration.old, path.join(backupDirectory, path.basename(migration.old))); + fs.cpSync(migration.old, path.join(backupDirectory, path.basename(migration.old))); + fs.rmSync(migration.old, { recursive: true, force: true }); } else { // Copy the directory to the new location fs.cpSync(migration.old, migration.new, { recursive: true, force: true }); // Move the directory to the backup location - fs.renameSync(migration.old, path.join(backupDirectory, path.basename(migration.old))); + fs.cpSync(migration.old, path.join(backupDirectory, path.basename(migration.old))); + fs.rmSync(migration.old, { recursive: true, force: true }); } } catch (error) { console.error(color.red(`Error migrating ${migration.old} to ${migration.new}:`), error.message); From 15a8adb0b926fba8b40072ec25f01b3b87a65b96 Mon Sep 17 00:00:00 2001 From: Isaac McFadyen Date: Thu, 18 Apr 2024 16:04:04 -0400 Subject: [PATCH 04/10] Changed fs.cpSync to use recursive copying --- src/endpoints/characters.js | 2 +- src/users.js | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/endpoints/characters.js b/src/endpoints/characters.js index 3fa022a8e..556a8fecc 100644 --- a/src/endpoints/characters.js +++ b/src/endpoints/characters.js @@ -680,7 +680,7 @@ router.post('/rename', jsonParser, async function (request, response) { // Rename chats folder if (fs.existsSync(oldChatsPath) && !fs.existsSync(newChatsPath)) { - fs.cpSync(oldChatsPath, newChatsPath); + fs.cpSync(oldChatsPath, newChatsPath, { recursive: true }); fs.rmSync(oldChatsPath, { recursive: true, force: true }); } diff --git a/src/users.js b/src/users.js index 8e2394fc5..831ff09d5 100644 --- a/src/users.js +++ b/src/users.js @@ -286,13 +286,21 @@ async function migrateUserData() { // Copy the file to the new location fs.cpSync(migration.old, migration.new, { force: true }); // Move the file to the backup location - fs.cpSync(migration.old, path.join(backupDirectory, path.basename(migration.old))); + fs.cpSync( + migration.old, + path.join(backupDirectory, path.basename(migration.old)), + { recursive: true, force: true } + ); fs.rmSync(migration.old, { recursive: true, force: true }); } else { // Copy the directory to the new location fs.cpSync(migration.old, migration.new, { recursive: true, force: true }); // Move the directory to the backup location - fs.cpSync(migration.old, path.join(backupDirectory, path.basename(migration.old))); + fs.cpSync( + migration.old, + path.join(backupDirectory, path.basename(migration.old)), + { recursive: true, force: true } + ); fs.rmSync(migration.old, { recursive: true, force: true }); } } catch (error) { From 0faa7d3c758bdee35e98d4bd6197092110d38cfc Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Thu, 18 Apr 2024 23:15:24 +0300 Subject: [PATCH 05/10] Replace {{name}} macro in system prompt prefix --- public/scripts/instruct-mode.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/public/scripts/instruct-mode.js b/public/scripts/instruct-mode.js index ba1b1506e..3837cd7eb 100644 --- a/public/scripts/instruct-mode.js +++ b/public/scripts/instruct-mode.js @@ -354,7 +354,9 @@ export function formatInstructModeSystemPrompt(systemPrompt) { const separator = power_user.instruct.wrap ? '\n' : ''; if (power_user.instruct.system_sequence_prefix) { - systemPrompt = power_user.instruct.system_sequence_prefix + separator + systemPrompt; + // TODO: Replace with a proper 'System' prompt entity name input + const prefix = power_user.instruct.system_sequence_prefix.replace(/{{name}}/gi, 'System'); + systemPrompt = prefix + separator + systemPrompt; } if (power_user.instruct.system_sequence_suffix) { From 25cb598694b971efe0283270c75193c063ae41fb Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 19 Apr 2024 00:07:12 +0300 Subject: [PATCH 06/10] Add Cohere as embedding source --- public/scripts/extensions/vectors/index.js | 24 ++++++- .../scripts/extensions/vectors/settings.html | 21 +++++- src/endpoints/vectors.js | 49 +++++++++----- src/vectors/cohere-vectors.js | 65 +++++++++++++++++++ src/{ => vectors}/embedding.js | 2 +- src/{ => vectors}/extras-vectors.js | 0 src/{ => vectors}/makersuite-vectors.js | 6 +- src/{ => vectors}/nomicai-vectors.js | 6 +- src/{ => vectors}/openai-vectors.js | 6 +- 9 files changed, 147 insertions(+), 32 deletions(-) create mode 100644 src/vectors/cohere-vectors.js rename src/{ => vectors}/embedding.js (94%) rename src/{ => vectors}/extras-vectors.js (100%) rename src/{ => vectors}/makersuite-vectors.js (85%) rename src/{ => vectors}/nomicai-vectors.js (88%) rename src/{ => vectors}/openai-vectors.js (91%) diff --git a/public/scripts/extensions/vectors/index.js b/public/scripts/extensions/vectors/index.js index 377878d8b..7e7fd0137 100644 --- a/public/scripts/extensions/vectors/index.js +++ b/public/scripts/extensions/vectors/index.js @@ -35,6 +35,7 @@ const settings = { include_wi: false, togetherai_model: 'togethercomputer/m2-bert-80M-32k-retrieval', openai_model: 'text-embedding-ada-002', + cohere_model: 'embed-english-v3.0', summarize: false, summarize_sent: false, summary_source: 'main', @@ -598,6 +599,9 @@ function getVectorHeaders() { case 'openai': addOpenAiHeaders(headers); break; + case 'cohere': + addCohereHeaders(headers); + break; default: break; } @@ -636,6 +640,16 @@ function addOpenAiHeaders(headers) { }); } +/** + * Add headers for the Cohere API source. + * @param {object} headers Header object + */ +function addCohereHeaders(headers) { + Object.assign(headers, { + 'X-Cohere-Model': extension_settings.vectors.cohere_model, + }); +} + /** * Inserts vector items into a collection * @param {string} collectionId - The collection to insert into @@ -647,7 +661,8 @@ async function insertVectorItems(collectionId, items) { settings.source === 'palm' && !secret_state[SECRET_KEYS.MAKERSUITE] || settings.source === 'mistral' && !secret_state[SECRET_KEYS.MISTRALAI] || settings.source === 'togetherai' && !secret_state[SECRET_KEYS.TOGETHERAI] || - settings.source === 'nomicai' && !secret_state[SECRET_KEYS.NOMICAI]) { + settings.source === 'nomicai' && !secret_state[SECRET_KEYS.NOMICAI] || + settings.source === 'cohere' && !secret_state[SECRET_KEYS.COHERE]) { throw new Error('Vectors: API key missing', { cause: 'api_key_missing' }); } @@ -816,6 +831,7 @@ function toggleSettings() { $('#vectors_chats_settings').toggle(!!settings.enabled_chats); $('#together_vectorsModel').toggle(settings.source === 'togetherai'); $('#openai_vectorsModel').toggle(settings.source === 'openai'); + $('#cohere_vectorsModel').toggle(settings.source === 'cohere'); $('#nomicai_apiKey').toggle(settings.source === 'nomicai'); } @@ -913,6 +929,12 @@ jQuery(async () => { Object.assign(extension_settings.vectors, settings); saveSettingsDebounced(); }); + $('#vectors_cohere_model').val(settings.cohere_model).on('change', () => { + $('#vectors_modelWarning').show(); + settings.cohere_model = String($('#vectors_cohere_model').val()); + Object.assign(extension_settings.vectors, settings); + saveSettingsDebounced(); + }); $('#vectors_template').val(settings.template).on('input', () => { settings.template = String($('#vectors_template').val()); Object.assign(extension_settings.vectors, settings); diff --git a/public/scripts/extensions/vectors/settings.html b/public/scripts/extensions/vectors/settings.html index 98c807cd9..4b86323e0 100644 --- a/public/scripts/extensions/vectors/settings.html +++ b/public/scripts/extensions/vectors/settings.html @@ -10,13 +10,14 @@ Vectorization Source
@@ -29,6 +30,20 @@
+
+ + +
+
+ + +

From 901ffa3cdc1f17d4e225e5ca5ea86683f15d94b9 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 19 Apr 2024 00:32:38 +0300 Subject: [PATCH 08/10] Add char and user avatar placeholders to ComfyUI workflow editor They resolve to base64 encoded data URIs of respective avatars. --- .../stable-diffusion/comfyWorkflowEditor.html | 2 + .../extensions/stable-diffusion/index.js | 48 ++++++++++++++----- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/public/scripts/extensions/stable-diffusion/comfyWorkflowEditor.html b/public/scripts/extensions/stable-diffusion/comfyWorkflowEditor.html index 784419d39..b510f29d9 100644 --- a/public/scripts/extensions/stable-diffusion/comfyWorkflowEditor.html +++ b/public/scripts/extensions/stable-diffusion/comfyWorkflowEditor.html @@ -19,6 +19,8 @@
  • "%scale%"
  • "%width%"
  • "%height%"
  • +
  • "%user_avatar%"
  • +
  • "%char_avatar%"

  • "%seed%" diff --git a/public/scripts/extensions/stable-diffusion/index.js b/public/scripts/extensions/stable-diffusion/index.js index ee3e9a477..f4a8b25b7 100644 --- a/public/scripts/extensions/stable-diffusion/index.js +++ b/public/scripts/extensions/stable-diffusion/index.js @@ -2111,21 +2111,11 @@ async function generateMultimodalPrompt(generationType, quietPrompt) { let avatarUrl; if (generationType == generationMode.USER_MULTIMODAL) { - avatarUrl = getUserAvatar(user_avatar); + avatarUrl = getUserAvatarUrl(); } if (generationType == generationMode.CHARACTER_MULTIMODAL || generationType === generationMode.FACE_MULTIMODAL) { - const context = getContext(); - - if (context.groupId) { - const groupMembers = context.groups.find(x => x.id === context.groupId)?.members; - const lastMessageAvatar = context.chat?.filter(x => !x.is_system && !x.is_user)?.slice(-1)[0]?.original_avatar; - const randomMemberAvatar = Array.isArray(groupMembers) ? groupMembers[Math.floor(Math.random() * groupMembers.length)]?.avatar : null; - const avatarToUse = lastMessageAvatar || randomMemberAvatar; - avatarUrl = formatCharacterAvatar(avatarToUse); - } else { - avatarUrl = getCharacterAvatar(context.characterId); - } + avatarUrl = getCharacterAvatarUrl(); } try { @@ -2152,6 +2142,24 @@ async function generateMultimodalPrompt(generationType, quietPrompt) { } } +function getCharacterAvatarUrl() { + const context = getContext(); + + if (context.groupId) { + const groupMembers = context.groups.find(x => x.id === context.groupId)?.members; + const lastMessageAvatar = context.chat?.filter(x => !x.is_system && !x.is_user)?.slice(-1)[0]?.original_avatar; + const randomMemberAvatar = Array.isArray(groupMembers) ? groupMembers[Math.floor(Math.random() * groupMembers.length)]?.avatar : null; + const avatarToUse = lastMessageAvatar || randomMemberAvatar; + return formatCharacterAvatar(avatarToUse); + } else { + return getCharacterAvatar(context.characterId); + } +} + +function getUserAvatarUrl() { + return getUserAvatar(user_avatar); +} + /** * Generates a prompt using the main LLM API. * @param {string} quietPrompt - The prompt to use for the image generation. @@ -2636,6 +2644,22 @@ async function generateComfyImage(prompt, negativePrompt) { (extension_settings.sd.comfy_placeholders ?? []).forEach(ph => { workflow = workflow.replace(`"%${ph.find}%"`, JSON.stringify(substituteParams(ph.replace))); }); + if (/%user_avatar%/gi.test(workflow)) { + const response = await fetch(getUserAvatarUrl()); + if (response.ok) { + const avatarBlob = await response.blob(); + const avatarBase64 = await getBase64Async(avatarBlob); + workflow = workflow.replace('"%user_avatar%"', JSON.stringify(avatarBase64)); + } + } + if (/%char_avatar%/gi.test(workflow)) { + const response = await fetch(getCharacterAvatarUrl()); + if (response.ok) { + const avatarBlob = await response.blob(); + const avatarBase64 = await getBase64Async(avatarBlob); + workflow = workflow.replace('"%char_avatar%"', JSON.stringify(avatarBase64)); + } + } console.log(`{ "prompt": ${workflow} }`); From eab545cafc6ab24668356a7fe4d1b308591da81b Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 19 Apr 2024 00:39:04 +0300 Subject: [PATCH 09/10] Error handling for Comfy request --- public/scripts/extensions/stable-diffusion/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/scripts/extensions/stable-diffusion/index.js b/public/scripts/extensions/stable-diffusion/index.js index f4a8b25b7..6618b66d4 100644 --- a/public/scripts/extensions/stable-diffusion/index.js +++ b/public/scripts/extensions/stable-diffusion/index.js @@ -2673,6 +2673,10 @@ async function generateComfyImage(prompt, negativePrompt) { }`, }), }); + if (!promptResult.ok) { + const text = await promptResult.text(); + throw new Error(text); + } return { format: 'png', data: await promptResult.text() }; } From 2333fe64d0e043e0d5c09a186746979c558d4e4f Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:46:15 +0300 Subject: [PATCH 10/10] #2107 Check for null reference in prompt manager settings init --- public/scripts/PromptManager.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/scripts/PromptManager.js b/public/scripts/PromptManager.js index 295c12123..4ab734156 100644 --- a/public/scripts/PromptManager.js +++ b/public/scripts/PromptManager.js @@ -841,7 +841,7 @@ class PromptManager { const promptReferences = this.getPromptOrderForCharacter(this.activeCharacter); for (let i = promptReferences.length - 1; i >= 0; i--) { const reference = promptReferences[i]; - if (-1 === this.serviceSettings.prompts.findIndex(prompt => prompt.identifier === reference.identifier)) { + if (reference && -1 === this.serviceSettings.prompts.findIndex(prompt => prompt.identifier === reference.identifier)) { promptReferences.splice(i, 1); this.log('Removed unused reference: ' + reference.identifier); }