From e3714e9b6aaea7119a0de37d6b8f473054e3ec98 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Fri, 21 Jun 2024 22:31:34 +0300 Subject: [PATCH 01/11] Fix search provider --- src/endpoints/search.js | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/src/endpoints/search.js b/src/endpoints/search.js index 7f08d89c8..457124228 100644 --- a/src/endpoints/search.js +++ b/src/endpoints/search.js @@ -147,25 +147,36 @@ router.post('/searxng', jsonParser, async (request, response) => { console.log('SearXNG query', baseUrl, query); - const url = new URL(baseUrl); - const params = new URLSearchParams(); - params.append('q', query); - params.append('format', 'html'); - url.pathname = '/search'; - url.search = params.toString(); + const mainPageUrl = new URL(baseUrl); + const mainPageRequest = await fetch(mainPageUrl, { headers: visitHeaders }); - const result = await fetch(url, { - method: 'POST', - headers: visitHeaders, - }); - - if (!result.ok) { - const text = await result.text(); - console.log('SearXNG request failed', result.statusText, text); + if (!mainPageRequest.ok) { + console.log('SearXNG request failed', mainPageRequest.statusText); return response.sendStatus(500); } - const data = await result.text(); + const mainPageText = await mainPageRequest.text(); + const clientHref = mainPageText.match(/href="(\/client.+\.css)"/)?.[1]; + + if (clientHref) { + const clientUrl = new URL(clientHref, baseUrl); + await fetch(clientUrl, { headers: visitHeaders }); + } + + const searchUrl = new URL('/search', baseUrl); + const searchParams = new URLSearchParams(); + searchParams.append('q', query); + searchUrl.search = searchParams.toString(); + + const searchResult = await fetch(searchUrl, { headers: visitHeaders }); + + if (!searchResult.ok) { + const text = await searchResult.text(); + console.log('SearXNG request failed', searchResult.statusText, text); + return response.sendStatus(500); + } + + const data = await searchResult.text(); return response.send(data); } catch (error) { console.log('SearXNG request failed', error); From a00560d2b379dddb7f7f4bd53bc0e842f6027f3e Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sat, 22 Jun 2024 00:36:29 +0300 Subject: [PATCH 02/11] Ensure format supported before captioning --- public/scripts/extensions/caption/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/scripts/extensions/caption/index.js b/public/scripts/extensions/caption/index.js index d981c15a6..d7a167fd4 100644 --- a/public/scripts/extensions/caption/index.js +++ b/public/scripts/extensions/caption/index.js @@ -1,4 +1,4 @@ -import { getBase64Async, isTrueBoolean, saveBase64AsFile } from '../../utils.js'; +import { ensureImageFormatSupported, getBase64Async, isTrueBoolean, saveBase64AsFile } from '../../utils.js'; import { getContext, getApiUrl, doExtrasFetch, extension_settings, modules, renderExtensionTemplateAsync } from '../../extensions.js'; import { callPopup, getRequestHeaders, saveSettingsDebounced, substituteParamsExtended } from '../../../script.js'; import { getMessageTimeStamp } from '../../RossAscends-mods.js'; @@ -272,7 +272,7 @@ async function getCaptionForFile(file, prompt, quiet) { try { setSpinnerIcon(); const context = getContext(); - const fileData = await getBase64Async(file); + const fileData = await getBase64Async(await ensureImageFormatSupported(file)); const base64Format = fileData.split(',')[0].split(';')[0].split('/')[1]; const base64Data = fileData.split(',')[1]; const { caption } = await doCaptionRequest(base64Data, fileData, prompt); From 9c2de78ad3d73c55d777fbef13f4282da38c5fc3 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sat, 22 Jun 2024 01:42:28 +0300 Subject: [PATCH 03/11] Fix OpenRouter caption headers --- src/endpoints/openai.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/endpoints/openai.js b/src/endpoints/openai.js index 9488d03e6..75de75b7b 100644 --- a/src/endpoints/openai.js +++ b/src/endpoints/openai.js @@ -6,6 +6,7 @@ const fs = require('fs'); const { jsonParser, urlencodedParser } = require('../express-common'); const { getConfigValue, mergeObjectWithYaml, excludeKeysByYaml, trimV1 } = require('../util'); const { setAdditionalHeaders } = require('../additional-headers'); +const { OPENROUTER_HEADERS } = require('../constants'); const router = express.Router(); @@ -80,7 +81,7 @@ router.post('/caption-image', jsonParser, async (request, response) => { if (request.body.api === 'openrouter') { apiUrl = 'https://openrouter.ai/api/v1/chat/completions'; - headers['HTTP-Referer'] = request.headers.referer; + Object.assign(headers, OPENROUTER_HEADERS); } if (request.body.api === 'openai') { From 473e11c773de10685022afc7a9ba17cc263407b0 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sat, 22 Jun 2024 02:03:39 +0300 Subject: [PATCH 04/11] New OpenRouter providers --- public/scripts/textgen-models.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/scripts/textgen-models.js b/public/scripts/textgen-models.js index d8f36cf45..5f663c816 100644 --- a/public/scripts/textgen-models.js +++ b/public/scripts/textgen-models.js @@ -39,6 +39,8 @@ const OPENROUTER_PROVIDERS = [ 'Novita', 'Lynn', 'Lynn 2', + 'DeepSeek', + 'Infermatic', ]; export async function loadOllamaModels(data) { From 7c2b475e4653852a3b30902554bb7e4a6d3a2cd5 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Sat, 22 Jun 2024 04:54:13 +0200 Subject: [PATCH 05/11] Improve popup class with close event handlers --- public/scripts/popup.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/public/scripts/popup.js b/public/scripts/popup.js index be460feb6..6e388839c 100644 --- a/public/scripts/popup.js +++ b/public/scripts/popup.js @@ -28,6 +28,8 @@ export const POPUP_RESULT = { * @property {boolean?} [allowVerticalScrolling] - Whether to allow vertical scrolling in the popup * @property {POPUP_RESULT|number?} [defaultResult] - The default result of this popup when Enter is pressed. Can be changed from `POPUP_RESULT.AFFIRMATIVE`. * @property {CustomPopupButton[]|string[]?} [customButtons] - Custom buttons to add to the popup. If only strings are provided, the buttons will be added with default options, and their result will be in order from `2` onward. + * @property {(popup: Popup) => boolean?} [onClosing] - Handler called before the popup closes, return `false` to cancel the close + * @property {(popup: Popup) => void?} [onClose] - Handler called after the popup closes, but before the DOM is cleaned up */ /** @@ -78,6 +80,9 @@ export class Popup { /** @type {POPUP_RESULT|number?} */ defaultResult; /** @type {CustomPopupButton[]|string[]?} */ customButtons; + /** @type {(popup: Popup) => boolean?} */ onClosing; + /** @type {(popup: Popup) => void?} */ onClose; + /** @type {POPUP_RESULT|number} */ result; /** @type {any} */ value; @@ -94,13 +99,17 @@ export class Popup { * @param {string} [inputValue=''] - The initial value of the input field * @param {PopupOptions} [options={}] - Additional options for the popup */ - constructor(content, type, inputValue = '', { okButton = null, cancelButton = null, rows = 1, wide = false, wider = false, large = false, allowHorizontalScrolling = false, allowVerticalScrolling = false, defaultResult = POPUP_RESULT.AFFIRMATIVE, customButtons = null } = {}) { + constructor(content, type, inputValue = '', { okButton = null, cancelButton = null, rows = 1, wide = false, wider = false, large = false, allowHorizontalScrolling = false, allowVerticalScrolling = false, defaultResult = POPUP_RESULT.AFFIRMATIVE, customButtons = null, onClosing = null, onClose = null } = {}) { Popup.util.popups.push(this); // Make this popup uniquely identifiable this.id = uuidv4(); this.type = type; + // Utilize event handlers being passed in + this.onClosing = onClosing; + this.onClose = onClose; + /**@type {HTMLTemplateElement}*/ const template = document.querySelector('#popup_template'); // @ts-ignore @@ -317,6 +326,12 @@ export class Popup { this.value = value; this.result = result; + + if (this.onClosing) { + const shouldClose = this.onClosing(this); + if (!shouldClose) return; + } + Popup.util.lastResult = { value, result }; this.hide(); } @@ -337,6 +352,11 @@ export class Popup { // Call the close on the dialog this.dlg.close(); + // Run a possible custom handler right before DOM removal + if (this.onClose) { + this.onClose(this); + } + // Remove it from the dom this.dlg.remove(); From d64b265a398073a7822aa718e001b44a2b0887e0 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Sat, 22 Jun 2024 05:03:05 +0200 Subject: [PATCH 06/11] Tag import popup improvements - Save "remember" setting of tag import popup - Add user option to change the tag import setting - Improve tag import popup with adding drilled down bogus folders as auto-added tags - Extract tag import popup to template - Force-open popup no matter the setting on char dropdown button option --- public/index.html | 17 ++- public/script.js | 11 +- public/scripts/power-user.js | 19 ++- public/scripts/tags.js | 153 ++++++++++---------- public/scripts/templates/charTagImport.html | 35 +++++ 5 files changed, 143 insertions(+), 92 deletions(-) create mode 100644 public/scripts/templates/charTagImport.html diff --git a/public/index.html b/public/index.html index 97c2f3ec4..5096da04e 100644 --- a/public/index.html +++ b/public/index.html @@ -3923,13 +3923,22 @@

Character Handling

-
+
-
+
+ + +
-
-
+
@@ -5766,7 +5766,7 @@
-
+
@@ -5784,7 +5784,7 @@
-
+
diff --git a/public/script.js b/public/script.js index ca2765ef8..4b877c3d4 100644 --- a/public/script.js +++ b/public/script.js @@ -1368,7 +1368,7 @@ export async function printCharacters(fullRefresh = false) { nextText: '>', formatNavigator: PAGINATION_TEMPLATE, showNavigator: true, - callback: function (data) { + callback: function (/** @type {Entity[]} */ data) { $(listId).empty(); if (power_user.bogus_folders && isBogusFolderOpen()) { $(listId).append(getBackBlock()); @@ -1388,7 +1388,7 @@ export async function printCharacters(fullRefresh = false) { displayCount++; break; case 'tag': - $(listId).append(getTagBlock(i.item, i.entities, i.hidden)); + $(listId).append(getTagBlock(i.item, i.entities, i.hidden, i.isUseless)); break; } } @@ -1442,8 +1442,9 @@ function verifyCharactersSearchSortRule() { * @property {Character|Group|import('./scripts/tags.js').Tag|*} item - The item * @property {string|number} id - The id * @property {'character'|'group'|'tag'} type - The type of this entity (character, group, tag) - * @property {Entity[]} [entities] - An optional list of entities relevant for this item - * @property {number} [hidden] - An optional number representing how many hidden entities this entity contains + * @property {Entity[]?} [entities=null] - An optional list of entities relevant for this item + * @property {number?} [hidden=null] - An optional number representing how many hidden entities this entity contains + * @property {boolean?} [isUseless=null] - Specifies if the entity is useless (not relevant, but should still be displayed for consistency) and should be displayed greyed out */ /** @@ -1538,6 +1539,15 @@ export function getEntitiesList({ doFilter = false, doSort = true } = {}) { } } + // Final step, updating some properties after the last filter run + const nonTagEntitiesCount = entities.filter(entity => entity.type !== 'tag').length; + for (const entity of entities) { + if (entity.type === 'tag') { + if (entity.entities?.length == nonTagEntitiesCount) entity.isUseless = true; + } + } + + // Sort before returning if requested if (doSort) { sortEntitiesList(entities); } diff --git a/public/scripts/tags.js b/public/scripts/tags.js index 519fc47eb..9175ee284 100644 --- a/public/scripts/tags.js +++ b/public/scripts/tags.js @@ -283,11 +283,12 @@ function chooseBogusFolder(source, tagId, remove = false) { * Builds the tag block for the specified item. * * @param {Tag} tag The tag item - * @param {*} entities The list ob sub items for this tag - * @param {*} hidden A count of how many sub items are hidden + * @param {any[]} entities The list ob sub items for this tag + * @param {number} hidden A count of how many sub items are hidden + * @param {boolean} isUseless Whether the tag is useless (should be displayed greyed out) * @returns The html for the tag block */ -function getTagBlock(tag, entities, hidden = 0) { +function getTagBlock(tag, entities, hidden = 0, isUseless = false) { let count = entities.length; const tagFolder = TAG_FOLDER_TYPES[tag.folder_type]; @@ -300,6 +301,7 @@ function getTagBlock(tag, entities, hidden = 0) { template.find('.bogus_folder_hidden_counter').text(hidden > 0 ? `${hidden} hidden` : ''); template.find('.bogus_folder_counter').text(`${count} ${count != 1 ? 'characters' : 'character'}`); template.find('.bogus_folder_icon').addClass(tagFolder.fa_icon); + if (isUseless) template.addClass('useless'); // Fill inline character images buildAvatarList(template.find('.bogus_folder_avatars_block'), entities); diff --git a/public/style.css b/public/style.css index 75a77295d..6ca69bcf7 100644 --- a/public/style.css +++ b/public/style.css @@ -2363,6 +2363,10 @@ input[type="file"] { padding: 1px; } +#rm_print_characters_block .entity_block.useless { + opacity: 0.25; +} + #rm_ch_create_block { display: none; overflow-y: auto; From c79f1e4360019ce78efbed28face56b4de0a617c Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Sat, 22 Jun 2024 08:52:13 +0200 Subject: [PATCH 08/11] Fix image enlarge popup image sizing --- public/style.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/public/style.css b/public/style.css index 75a77295d..896b9665f 100644 --- a/public/style.css +++ b/public/style.css @@ -368,6 +368,8 @@ input[type='checkbox']:focus-visible { .img_enlarged_container { padding: 10px; + height: 100%; + width: 100%; } .img_enlarged_container pre code, From 07da2461d00dee9b1acbe677963d6ce4c42e97c9 Mon Sep 17 00:00:00 2001 From: Wolfsblvt Date: Sat, 22 Jun 2024 10:04:14 +0200 Subject: [PATCH 09/11] Fix vertical scaling of images in enlarge popup --- public/style.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/style.css b/public/style.css index 896b9665f..ad905cf2f 100644 --- a/public/style.css +++ b/public/style.css @@ -367,6 +367,9 @@ input[type='checkbox']:focus-visible { } .img_enlarged_container { + display: flex; + flex-direction: column; + justify-content: flex-end; padding: 10px; height: 100%; width: 100%; @@ -4481,7 +4484,7 @@ a { max-height: 100%; border-radius: 2px; border: 1px solid transparent; - outline: 1px solid var(--SmartThemeBorderColor); + object-fit: contain; } .cropper-container { From aa16ac446d90712ad9b112f21ba04da6e784d554 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sat, 22 Jun 2024 12:53:03 +0300 Subject: [PATCH 10/11] Migrate preference for existing users --- public/scripts/power-user.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/public/scripts/power-user.js b/public/scripts/power-user.js index eb0438c15..bc43a8ca0 100644 --- a/public/scripts/power-user.js +++ b/public/scripts/power-user.js @@ -1564,7 +1564,10 @@ function loadPowerUserSettings(settings, data) { } // Clean up old/legacy settings - delete power_user.import_card_tags; + if (power_user.import_card_tags !== undefined) { + power_user.tag_import_setting = power_user.import_card_tags ? tag_import_setting.ASK : tag_import_setting.NONE; + delete power_user.import_card_tags; + } $('#single_line').prop('checked', power_user.single_line); $('#relaxed_api_urls').prop('checked', power_user.relaxed_api_urls); From 36ecf8a7174bd8c91a9f5c43a421e33d302adbf8 Mon Sep 17 00:00:00 2001 From: Cohee <18619528+Cohee1207@users.noreply.github.com> Date: Sat, 22 Jun 2024 12:56:57 +0300 Subject: [PATCH 11/11] Update UI when remembering tag import setting --- public/scripts/tags.js | 1 + 1 file changed, 1 insertion(+) diff --git a/public/scripts/tags.js b/public/scripts/tags.js index 176c46960..24a57a9c0 100644 --- a/public/scripts/tags.js +++ b/public/scripts/tags.js @@ -778,6 +778,7 @@ async function showTagImportPopup(character, existingTags, newTags, folderTags) const setting = buttonSettingsMap[popup.result]; if (!setting) return; power_user.tag_import_setting = setting; + $('#tag_import_setting').val(power_user.tag_import_setting); saveSettingsDebounced(); console.log('Remembered tag import setting:', Object.entries(tag_import_setting).find(x => x[1] === setting)[0], setting); }