From a12c443cf85ea973a11b41aa8ee19991f7472fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Tue, 6 Aug 2024 09:47:51 +0200 Subject: [PATCH 01/16] Fix typos --- .../{worflows/character_text.yml => workflows/character_test.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{worflows/character_text.yml => workflows/character_test.yml} (100%) diff --git a/.github/worflows/character_text.yml b/.github/workflows/character_test.yml similarity index 100% rename from .github/worflows/character_text.yml rename to .github/workflows/character_test.yml From 4221f31a3cdf2c970172d5ea70a7cdd728577d12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Tue, 6 Aug 2024 09:51:11 +0200 Subject: [PATCH 02/16] Update character_test.yml --- .github/workflows/character_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/character_test.yml b/.github/workflows/character_test.yml index 6c98c2c..9bad4a9 100644 --- a/.github/workflows/character_test.yml +++ b/.github/workflows/character_test.yml @@ -12,7 +12,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.10 + python-version: 3.10.9 - name: Install dependencies run: | From 19e36af4c171ef81d2f0eed19d3dde68c24c4ed4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Tue, 6 Aug 2024 09:54:23 +0200 Subject: [PATCH 03/16] Run only if characters.json is changed --- .github/workflows/character_test.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/character_test.yml b/.github/workflows/character_test.yml index 9bad4a9..3539c15 100644 --- a/.github/workflows/character_test.yml +++ b/.github/workflows/character_test.yml @@ -1,6 +1,12 @@ name: Run Character Tag Validator -on: [push, pull_request] +on: + push: + paths: + - 'web/settings/characters.json' + pull_request: + paths: + - 'web/settings/characters.json' jobs: build: From 5e3def35883e6bfa38cf3631054595d4e97c853b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Tue, 6 Aug 2024 09:47:51 +0200 Subject: [PATCH 04/16] Fix typos --- .../{worflows/character_text.yml => workflows/character_test.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{worflows/character_text.yml => workflows/character_test.yml} (100%) diff --git a/.github/worflows/character_text.yml b/.github/workflows/character_test.yml similarity index 100% rename from .github/worflows/character_text.yml rename to .github/workflows/character_test.yml From e693693ca748e43d6157921cd721de67d21d3b3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Tue, 6 Aug 2024 09:51:11 +0200 Subject: [PATCH 05/16] Update character_test.yml --- .github/workflows/character_test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/character_test.yml b/.github/workflows/character_test.yml index 6c98c2c..9bad4a9 100644 --- a/.github/workflows/character_test.yml +++ b/.github/workflows/character_test.yml @@ -12,7 +12,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v4 with: - python-version: 3.10 + python-version: 3.10.9 - name: Install dependencies run: | From b650b0f3b776e6071f78cc40ff6a65dcc1c501aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Tue, 6 Aug 2024 09:54:23 +0200 Subject: [PATCH 06/16] Run only if characters.json is changed --- .github/workflows/character_test.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/character_test.yml b/.github/workflows/character_test.yml index 9bad4a9..3539c15 100644 --- a/.github/workflows/character_test.yml +++ b/.github/workflows/character_test.yml @@ -1,6 +1,12 @@ name: Run Character Tag Validator -on: [push, pull_request] +on: + push: + paths: + - 'web/settings/characters.json' + pull_request: + paths: + - 'web/settings/characters.json' jobs: build: From 5095a449f43ff6353dcc5cfad9408545addec1ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Tue, 6 Aug 2024 11:20:05 +0200 Subject: [PATCH 07/16] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index a1cb9cd..70f0e3f 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ src/custom_schedulers/mixed_decay_growth.py src/prompt_combine_testing.py web/settings/sn0w_settings.json testing/test_scheduler.py +update-dev.bat From 1c2426f1a69f55c71f11442bf63fe6aebe6788ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Tue, 6 Aug 2024 22:28:08 +0200 Subject: [PATCH 08/16] Update characters.json --- web/settings/characters.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/settings/characters.json b/web/settings/characters.json index fd48a99..d3e189f 100644 --- a/web/settings/characters.json +++ b/web/settings/characters.json @@ -159,6 +159,11 @@ "associated_string": "shylily, shylily \\(bikini\\), indie virtual youtuber", "prompt": "ahoge, blue hair, large breasts, long hair, multicolored hair, purple eyes, two-tone hair, virtual youtuber, white hair, animal ears, facial mark, orca girl" }, + { + "name": "Akuma Nihmune (Vtuber)", + "associated_string": "akuma nihmune, indie virtual youtuber", + "prompt": "demon horns, mole under eye, heart tattoo, ear piercing, earrings" + }, { "name": "Hasumi (Blue Archive)", "associated_string": "hasumi \\(blue archive\\), blue archive", From 04943da21a16252ffe6c0453cbeed1ea316d598c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Wed, 7 Aug 2024 16:01:31 +0200 Subject: [PATCH 09/16] Add option to favourite loras in lora stack. --- web/js/loraContextMenu.js | 57 ++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/web/js/loraContextMenu.js b/web/js/loraContextMenu.js index 83c7c5b..0b6184a 100644 --- a/web/js/loraContextMenu.js +++ b/web/js/loraContextMenu.js @@ -67,30 +67,55 @@ app.registerExtension({ const original_getNodeMenuOptions = app.canvas.getNodeMenuOptions; app.canvas.getNodeMenuOptions = function (node) { const options = original_getNodeMenuOptions.apply(this, arguments); + + // Collect all Lora widgets. + const loraWidgets = node.widgets.filter(widget => widget.name.includes("lora") && widget.type === "combo"); + const totalLoras = loraWidgets.length; + if (loraLoaders.includes(node.type)) { const settingUtils = new SettingUtils(); const nullIndex = options.indexOf(null); + let optionsArr = [] - // Check if the filename is in the existingList - const selectedLora = node.widgets[0].value; - const pathArray = selectedLora.split('\\'); - const filename = pathArray[pathArray.length - 1]; - const isFavourite = existingList.includes(filename); + loraWidgets.forEach(widget => { + const selectedLora = widget.value; + const pathArray = selectedLora.split('\\'); + const filename = pathArray[pathArray.length - 1]; + if (filename == "None") { + return; + } + const isFavourite = existingList.includes(filename); - // Create the new menu item - const newMenuItem = { - content: isFavourite ? 'Unfavourite Lora ☆' : 'Favourite Lora ★', - disabled: false, - callback: () => { - SettingUtils.toggleFavourite(existingList, filename, favouriteLoraId); - settingUtils.refreshComboInSingleNode(app, node.title); - }, - }; + const newMenuItem = { + content: (isFavourite ? 'Unfavourite ' : 'Favourite ') + filename.split(".")[0] + (isFavourite ? ' ☆' : ' ★'), + disabled: false, + callback: () => { + SettingUtils.toggleFavourite(existingList, filename, favouriteLoraId); + settingUtils.refreshComboInSingleNode(app, node.title); + }, + }; + + optionsArr.push(newMenuItem); + }); + + let menuItem + if (totalLoras === 1) { + menuItem = optionsArr[0] + } else if (totalLoras > 1) { + menuItem = { + content: "Favourite", + disabled: false, + has_submenu: true, + submenu: { + options: optionsArr + } + } + } if (nullIndex !== -1) { - options.splice(nullIndex, 0, newMenuItem); + options.splice(nullIndex, 0, menuItem); } else { - options.push(newMenuItem); + options.push(menuItem); } } return options; From ab89d340c1fbecb206f1ccc388caad16b57a89b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Wed, 7 Aug 2024 17:25:24 +0200 Subject: [PATCH 10/16] Add associated string if in custom_characters.json If the same character is in both normal and custom characters, add both the prompt and associated strings together. --- src/character_select.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/character_select.py b/src/character_select.py index 29ed3d9..6f34c16 100644 --- a/src/character_select.py +++ b/src/character_select.py @@ -69,13 +69,16 @@ class CharacterSelectNode: custom_json_path = os.path.join(dir_path, CUSTOM_CHARACTER_FILE_PATH) if not os.path.exists(custom_json_path): - cls.logger.log(f"Custom character file doesn't exist. Please create the json file at: {custom_json_path}", "WARNING") + cls.logger.log( + f"Custom character file doesn't exist. Please create the json file at: {custom_json_path}", "WARNING" + ) else: with open(custom_json_path, "r", encoding="utf-8") as file: custom_character_data = json.load(file) for custom_character in custom_character_data: for character in character_data: if custom_character["name"] == character["name"]: + character["associated_string"] += ", " + custom_character["associated_string"] character["prompt"] += ", " + custom_character["prompt"] break else: From cf6dfac1f088a953c3d0b4cafc202a1726f27520 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Wed, 7 Aug 2024 17:25:27 +0200 Subject: [PATCH 11/16] Update characters.json --- web/settings/characters.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/settings/characters.json b/web/settings/characters.json index d3e189f..d23ea5c 100644 --- a/web/settings/characters.json +++ b/web/settings/characters.json @@ -162,7 +162,7 @@ { "name": "Akuma Nihmune (Vtuber)", "associated_string": "akuma nihmune, indie virtual youtuber", - "prompt": "demon horns, mole under eye, heart tattoo, ear piercing, earrings" + "prompt": "purple hair, demon horns, mole under eye, heart tattoo, ear piercing, earrings" }, { "name": "Hasumi (Blue Archive)", From b872eaa71ac28da23f03cda27890ef307dbbdbc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Wed, 7 Aug 2024 18:11:16 +0200 Subject: [PATCH 12/16] Fix loading on new comfyui frontend --- web/js/simpleKSampler.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/web/js/simpleKSampler.js b/web/js/simpleKSampler.js index 522a8ee..f209590 100644 --- a/web/js/simpleKSampler.js +++ b/web/js/simpleKSampler.js @@ -23,13 +23,13 @@ app.registerExtension({ }; nodeType.prototype.onNodeCreated = function () { - this.inputs[3].type = ['STRING', 'CONDITIONING']; - this.inputs[4].type = ['STRING', 'CONDITIONING']; + //this.inputs[3].type = ['STRING', 'CONDITIONING']; + //this.inputs[4].type = ['STRING', 'CONDITIONING']; }; nodeType.prototype.onConfigure = function () { - this.inputs[3].type = ['STRING', 'CONDITIONING']; - this.inputs[4].type = ['STRING', 'CONDITIONING']; + //this.inputs[3].type = ['STRING', 'CONDITIONING']; + //this.inputs[4].type = ['STRING', 'CONDITIONING']; }; } }, From de8b09bab0427d1a89b5ef5ca0b5ebd1e840be47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Wed, 7 Aug 2024 18:11:33 +0200 Subject: [PATCH 13/16] If no chosen loras disable option --- web/js/loraContextMenu.js | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/web/js/loraContextMenu.js b/web/js/loraContextMenu.js index 0b6184a..5b1369a 100644 --- a/web/js/loraContextMenu.js +++ b/web/js/loraContextMenu.js @@ -62,7 +62,6 @@ app.registerExtension({ // Combine the existing custom loaders with the fetched ones loraLoaders = loraLoaders.concat(...customLoraLoadersArrays); - addLoraLoaders(loraLoaders); const original_getNodeMenuOptions = app.canvas.getNodeMenuOptions; app.canvas.getNodeMenuOptions = function (node) { @@ -99,17 +98,24 @@ app.registerExtension({ }); let menuItem - if (totalLoras === 1) { - menuItem = optionsArr[0] - } else if (totalLoras > 1) { - menuItem = { - content: "Favourite", - disabled: false, - has_submenu: true, - submenu: { - options: optionsArr + if (optionsArr.length > 0) { + if (totalLoras === 1) { + menuItem = optionsArr[0] + } else if (totalLoras > 1) { + menuItem = { + content: "Favourite", + disabled: false, + has_submenu: true, + submenu: { + options: optionsArr + } } } + } else { + menuItem = { + content: "No lora selected", + disabled: true, + } } if (nullIndex !== -1) { From d3a80eb10cd40ec68dd1be43f7dd8420ef6f250f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Wed, 7 Aug 2024 18:45:14 +0200 Subject: [PATCH 14/16] Use custom fetchApi as workaround to comfys not working --- web/js/customLoraLoaders.js | 13 +----------- web/js/sn0w.js | 40 ++++++++++++++++++++++++++++++------- web/js/textbox.js | 10 ++-------- 3 files changed, 36 insertions(+), 27 deletions(-) diff --git a/web/js/customLoraLoaders.js b/web/js/customLoraLoaders.js index ce6acc9..10f2476 100644 --- a/web/js/customLoraLoaders.js +++ b/web/js/customLoraLoaders.js @@ -3,18 +3,7 @@ import { app } from '../../../scripts/app.js'; import { api } from '../../../scripts/api.js'; async function fetchExtensionSettings() { - try { - const response = await api.fetchApi( - '/extensions/ComfyUI-Sn0w-Scripts/settings/sn0w_settings.json' - ); - if (!response.ok) { - throw new Error('Network response was not ok ' + response.statusText); - } - const data = await response.json(); - return data; - } catch (error) { - console.error('There was a problem with the fetch operation:', error); - } + return SettingUtils.fetchApi("/extensions/ComfyUI-Sn0w-Scripts/settings/sn0w_settings.json"); } const sn0wSettings = await fetchExtensionSettings(); diff --git a/web/js/sn0w.js b/web/js/sn0w.js index 4de6a8c..fe6e1c4 100644 --- a/web/js/sn0w.js +++ b/web/js/sn0w.js @@ -19,6 +19,23 @@ export class SettingUtils { } } + static async fetchApi(route, options) { + if (!options) { + options = {}; + } + if (!options.headers) { + options.headers = {}; + } + const url = `${location.protocol}//${location.host}${route}`; + try { + const response = await fetch(url, options); + const data = await response.json(); + return data; + } catch (error) { + console.error('There was a problem with the fetch operation:', error); + } + } + // Callback function to add or remove the filename from the settings list static async toggleFavourite(existingList, filename, setting) { try { @@ -54,28 +71,26 @@ export class SettingUtils { textarea.id = uniqueId; textarea.value = value; const maxLines = 10; - const lineHeight = 15; // Function to set the height based on the number of lines const adjustHeight = () => { + textarea.style.height = ''; // Allow to shrink const lines = textarea.value.split('\n').length; + const scrollHeight = textarea.scrollHeight + 3; if (lines > maxLines) { + const height = (scrollHeight / lines) * maxLines textarea.setAttribute( 'style', - `width: 100%; height: ${lineHeight * maxLines}px; resize: none;` + `width: 100%; height: ${height}px; resize: none;` ); return; } - const height = lines * lineHeight; - textarea.setAttribute('style', `width: 100%; height: ${height}px; resize: none;`); + textarea.setAttribute('style', `width: 100%; height: ${scrollHeight}px; resize: none;`); }; adjustHeight(); textarea.onchange = () => setter(textarea.value); textarea.addEventListener('input', adjustHeight); - // Apply event handler - textarea.onchange = () => setter(textarea.value); - // Apply additional attributes for (const [key, val] of Object.entries(attrs)) { textarea.setAttribute(key, val); @@ -94,6 +109,17 @@ export class SettingUtils { label.className = 'comfy-tooltip-indicator'; } + // Update height when settings are opened + const dialog = document.getElementById('comfy-settings-dialog'); + const observer = new MutationObserver(mutations => { + mutations.forEach(mutation => { + if (mutation.type === 'attributes' && mutation.attributeName === 'open') { + adjustHeight(); + } + }); + }); + observer.observe(dialog, { attributes: true }); + return tr; } diff --git a/web/js/textbox.js b/web/js/textbox.js index d556174..63ca543 100644 --- a/web/js/textbox.js +++ b/web/js/textbox.js @@ -464,15 +464,9 @@ app.registerExtension({ } async function getValidFiles(type) { - const apiRequest = await api.fetchApi(`${SettingUtils.API_PREFIX}/${type}`, { + return await SettingUtils.fetchApi(`${SettingUtils.API_PREFIX}/${type}`, { method: "GET", - }) - if (!apiRequest.ok) { - console.error('API request failed:', apiRequest.statusText); - } else { - const responseBody = await apiRequest.json(); - return responseBody; - } + }); } nodeType.prototype.onNodeCreated = function () { From 0cbdb5eeaec2c5349ae91001ae0259d217f3a90f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Wed, 7 Aug 2024 19:01:39 +0200 Subject: [PATCH 15/16] replaceAll --- web/js/sn0w.js | 4 ++-- web/js/textbox.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web/js/sn0w.js b/web/js/sn0w.js index fe6e1c4..8551d6c 100644 --- a/web/js/sn0w.js +++ b/web/js/sn0w.js @@ -64,7 +64,7 @@ export class SettingUtils { const textarea = document.createElement('textarea'); // Generate a unique ID for associating the label with the textarea - const uniqueId = `${name.replaceAll(' ', '').replace('[', '').replace(']', '-')}`; + const uniqueId = `${name.replaceAll(' ', '').replaceAll('[', '').replaceAll(']', '-')}`; label.setAttribute('for', uniqueId); label.textContent = name; @@ -134,7 +134,7 @@ export class SettingUtils { const label = document.createElement('label'); // Generate a unique ID for the setting container - const uniqueId = `${name.replaceAll(' ', '').replace('[', '').replace(']', '-')}`; + const uniqueId = `${name.replaceAll(' ', '').replaceAll('[', '').replaceAll(']', '-')}`; label.setAttribute('for', uniqueId); label.textContent = name; diff --git a/web/js/textbox.js b/web/js/textbox.js index 63ca543..bfce349 100644 --- a/web/js/textbox.js +++ b/web/js/textbox.js @@ -228,7 +228,7 @@ app.registerExtension({ let trimmedTag = tag.trim(); // Remove HTML tags - trimmedTag = trimmedTag.replace(/<[^>]*>/g, ''); + trimmedTag = trimmedTag.replaceAll(/<[^>]*>/g, ''); // Remove the first character if it is a parenthesis if (trimmedTag.startsWith('(')) { From 90e5ad106e434fb416e7dcb4f369dfd6da2a9a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lucas=20=20Sk=C3=B6ld?= Date: Wed, 7 Aug 2024 19:06:40 +0200 Subject: [PATCH 16/16] CodeQL --- web/js/textbox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/js/textbox.js b/web/js/textbox.js index bfce349..a79e697 100644 --- a/web/js/textbox.js +++ b/web/js/textbox.js @@ -228,7 +228,7 @@ app.registerExtension({ let trimmedTag = tag.trim(); // Remove HTML tags - trimmedTag = trimmedTag.replaceAll(/<[^>]*>/g, ''); + trimmedTag = trimmedTag.replace(/<|>/g, ""); // Remove the first character if it is a parenthesis if (trimmedTag.startsWith('(')) {