mirror of
https://github.com/justUmen/Bjornulf_custom_nodes.git
synced 2026-03-26 14:48:51 -03:00
0.17
This commit is contained in:
11
README.md
11
README.md
@@ -1,4 +1,4 @@
|
|||||||
# 🔗 Comfyui : Bjornulf_custom_nodes v0.16 🔗
|
# 🔗 Comfyui : Bjornulf_custom_nodes v0.17 🔗
|
||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@
|
|||||||
- **v0.14**: Add a new node: Cut image from a mask
|
- **v0.14**: Add a new node: Cut image from a mask
|
||||||
- **v0.15**: Add two new nodes: TTS - Text to Speech and Character Description Generator
|
- **v0.15**: Add two new nodes: TTS - Text to Speech and Character Description Generator
|
||||||
- **v0.16**: Big changes on Character Description Generator
|
- **v0.16**: Big changes on Character Description Generator
|
||||||
|
- **v0.17**: New loop node, combine by lines.
|
||||||
|
|
||||||
# 📝 Nodes descriptions
|
# 📝 Nodes descriptions
|
||||||
|
|
||||||
@@ -264,3 +265,11 @@ Generate a character description based on a json file in the folder `characters`
|
|||||||
Make your own json file with your own characters, and use this node to generate a description.
|
Make your own json file with your own characters, and use this node to generate a description.
|
||||||
❗ For now it's very basic node, a lot of things are going to be added and changed !!!
|
❗ For now it's very basic node, a lot of things are going to be added and changed !!!
|
||||||
Some details are unusable for some checkpoints, very much a work in progress, the json structure isn't set in stone either.
|
Some details are unusable for some checkpoints, very much a work in progress, the json structure isn't set in stone either.
|
||||||
|
|
||||||
|
### 33 - ♻ Loop (All Lines from input 🔗 combine by lines)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
Sometimes you want to loop over several inputs but you also want to separate different lines of your output.
|
||||||
|
So with this node, you can have the number of inputs and outputs you want. See example for usage.
|
||||||
@@ -37,6 +37,7 @@ from .load_image_alpha import LoadImageWithTransparency
|
|||||||
from .image_mask_cutter import ImageMaskCutter
|
from .image_mask_cutter import ImageMaskCutter
|
||||||
from .character_description import CharacterDescriptionGenerator
|
from .character_description import CharacterDescriptionGenerator
|
||||||
from .text_to_speech import TextToSpeech
|
from .text_to_speech import TextToSpeech
|
||||||
|
from .loop_combine_texts_by_lines import CombineTextsByLines
|
||||||
# from .check_black_image import CheckBlackImage
|
# from .check_black_image import CheckBlackImage
|
||||||
# from .clear_vram import ClearVRAM
|
# from .clear_vram import ClearVRAM
|
||||||
|
|
||||||
@@ -45,6 +46,7 @@ from .text_to_speech import TextToSpeech
|
|||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
# "Bjornulf_CustomStringType": CustomStringType,
|
# "Bjornulf_CustomStringType": CustomStringType,
|
||||||
"Bjornulf_ollamaLoader": ollamaLoader,
|
"Bjornulf_ollamaLoader": ollamaLoader,
|
||||||
|
"Bjornulf_CombineTextsByLines": CombineTextsByLines,
|
||||||
"Bjornulf_TextToSpeech": TextToSpeech,
|
"Bjornulf_TextToSpeech": TextToSpeech,
|
||||||
"Bjornulf_CharacterDescriptionGenerator": CharacterDescriptionGenerator,
|
"Bjornulf_CharacterDescriptionGenerator": CharacterDescriptionGenerator,
|
||||||
"Bjornulf_ImageMaskCutter": ImageMaskCutter,
|
"Bjornulf_ImageMaskCutter": ImageMaskCutter,
|
||||||
@@ -90,6 +92,7 @@ NODE_CLASS_MAPPINGS = {
|
|||||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
# "Bjornulf_CustomStringType": "!!! CUSTOM STRING TYPE !!!",
|
# "Bjornulf_CustomStringType": "!!! CUSTOM STRING TYPE !!!",
|
||||||
"Bjornulf_ollamaLoader": "🦙 Ollama (Description)",
|
"Bjornulf_ollamaLoader": "🦙 Ollama (Description)",
|
||||||
|
"Bjornulf_CombineTextsByLines": "♻ Loop (All Lines from input 🔗 combine by lines)",
|
||||||
"Bjornulf_TextToSpeech": "🔊 TTS - Text to Speech",
|
"Bjornulf_TextToSpeech": "🔊 TTS - Text to Speech",
|
||||||
"Bjornulf_CharacterDescriptionGenerator": "🧑📝 Character Description Generator",
|
"Bjornulf_CharacterDescriptionGenerator": "🧑📝 Character Description Generator",
|
||||||
"Bjornulf_ImageMaskCutter": "🖼✂ Cut Image with Mask",
|
"Bjornulf_ImageMaskCutter": "🖼✂ Cut Image with Mask",
|
||||||
|
|||||||
49
loop_combine_texts_by_lines.py
Normal file
49
loop_combine_texts_by_lines.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
class CombineTextsByLines:
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"number_of_inputs": ("INT", {"default": 2, "min": 1, "max": 10, "step": 1}),
|
||||||
|
"number_of_lines": ("INT", {"default": 3, "min": 1, "max": 20, "step": 1}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = tuple(["STRING"] * 20) # Maximum 20 lines
|
||||||
|
RETURN_NAMES = tuple([f"line_{i+1}" for i in range(20)])
|
||||||
|
FUNCTION = "extract_lines"
|
||||||
|
OUTPUT_NODE = True
|
||||||
|
CATEGORY = "text"
|
||||||
|
OUTPUT_IS_LIST = tuple([True] * 20) # Indicate that all outputs are lists
|
||||||
|
|
||||||
|
def extract_lines(self, number_of_inputs, number_of_lines, **kwargs):
|
||||||
|
grouped_lines = [[] for _ in range(number_of_lines)]
|
||||||
|
|
||||||
|
for i in range(1, number_of_inputs + 1):
|
||||||
|
text_key = f"text_{i}"
|
||||||
|
if text_key in kwargs and kwargs[text_key]:
|
||||||
|
lines = kwargs[text_key].split('\n')
|
||||||
|
lines = [line.strip() for line in lines if line.strip()]
|
||||||
|
for j, line in enumerate(lines[:number_of_lines]):
|
||||||
|
grouped_lines[j].append(line)
|
||||||
|
|
||||||
|
outputs = []
|
||||||
|
for group in grouped_lines:
|
||||||
|
# Instead of joining the lines, keep them as a list
|
||||||
|
outputs.append(group)
|
||||||
|
|
||||||
|
# Pad the output to always return 20 items
|
||||||
|
outputs.extend([[] for _ in range(20 - len(outputs))])
|
||||||
|
|
||||||
|
return tuple(outputs)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def IS_CHANGED(cls, number_of_inputs, number_of_lines, ** kwargs):
|
||||||
|
return float("NaN") # This forces the node to always update
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def VALIDATE_INPUTS(cls, number_of_inputs, number_of_lines, **kwargs):
|
||||||
|
if number_of_lines < 1 or number_of_lines > 20:
|
||||||
|
return "Number of lines must be between 1 and 20"
|
||||||
|
if number_of_inputs < 1 or number_of_inputs > 10:
|
||||||
|
return "Number of inputs must be between 1 and 10"
|
||||||
|
return True
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "bjornulf_custom_nodes"
|
name = "bjornulf_custom_nodes"
|
||||||
description = "Nodes: Ollama, Text to Speech, Save image for Bjornulf LobeChat, Text with random Seed, Random line from input, Combine images (Background+Overlay alpha), Image to grayscale (black & white), Remove image Transparency (alpha), Resize Image, ..."
|
description = "Nodes: Ollama, Text to Speech, Save image for Bjornulf LobeChat, Text with random Seed, Random line from input, Combine images (Background+Overlay alpha), Image to grayscale (black & white), Remove image Transparency (alpha), Resize Image, ..."
|
||||||
version = "0.16"
|
version = "0.17"
|
||||||
license = {file = "LICENSE"}
|
license = {file = "LICENSE"}
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|||||||
BIN
screenshots/loop_combined.png
Normal file
BIN
screenshots/loop_combined.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 453 KiB |
@@ -40,7 +40,7 @@ class TextToSpeech:
|
|||||||
|
|
||||||
RETURN_TYPES = ("AUDIO",)
|
RETURN_TYPES = ("AUDIO",)
|
||||||
FUNCTION = "generate_audio"
|
FUNCTION = "generate_audio"
|
||||||
CATEGORY = "audio"
|
CATEGORY = "Bjornulf"
|
||||||
|
|
||||||
def generate_audio(self, text, language, speaker_wav):
|
def generate_audio(self, text, language, speaker_wav):
|
||||||
# Check if a valid speaker_wav was selected
|
# Check if a valid speaker_wav was selected
|
||||||
|
|||||||
72
web/js/loop_combine_texts_by_lines.js
Normal file
72
web/js/loop_combine_texts_by_lines.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
import { app } from "../../../scripts/app.js";
|
||||||
|
|
||||||
|
app.registerExtension({
|
||||||
|
name: "Bjornulf.CombineTextsByLines",
|
||||||
|
async nodeCreated(node) {
|
||||||
|
if (node.comfyClass === "Bjornulf_CombineTextsByLines") {
|
||||||
|
const updateInputsAndOutputs = () => {
|
||||||
|
const numInputsWidget = node.widgets.find(w => w.name === "number_of_inputs");
|
||||||
|
const numLinesWidget = node.widgets.find(w => w.name === "number_of_lines");
|
||||||
|
if (!numInputsWidget || !numLinesWidget) return;
|
||||||
|
|
||||||
|
const numInputs = numInputsWidget.value;
|
||||||
|
const numLines = numLinesWidget.value;
|
||||||
|
|
||||||
|
// Update inputs
|
||||||
|
if (!node.inputs) {
|
||||||
|
node.inputs = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove excess inputs
|
||||||
|
node.inputs = node.inputs.filter(input => !input.name.startsWith('text_') || parseInt(input.name.split('_')[1]) <= numInputs);
|
||||||
|
|
||||||
|
// Add new inputs if needed
|
||||||
|
for (let i = node.inputs.length; i < numInputs; i++) {
|
||||||
|
const inputName = `text_${i + 1}`;
|
||||||
|
if (!node.inputs.find(input => input.name === inputName)) {
|
||||||
|
node.addInput(inputName, "STRING");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update outputs
|
||||||
|
if (!node.outputs) {
|
||||||
|
node.outputs = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove excess outputs
|
||||||
|
while (node.outputs.length > numLines) {
|
||||||
|
node.removeOutput(node.outputs.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new outputs if needed
|
||||||
|
while (node.outputs.length < numLines) {
|
||||||
|
node.addOutput(`Line ${node.outputs.length + 1}`, "STRING", { array: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update output labels and types
|
||||||
|
node.outputs.forEach((output, index) => {
|
||||||
|
output.name = `line_${index + 1}`;
|
||||||
|
output.label = `Line ${index + 1}`;
|
||||||
|
output.type = "STRING";
|
||||||
|
output.array = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
node.setSize(node.computeSize());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Move control widgets to the top and remove any text area widgets
|
||||||
|
node.widgets = node.widgets.filter(w => w.name === "number_of_inputs" || w.name === "number_of_lines");
|
||||||
|
|
||||||
|
// Set up callbacks
|
||||||
|
node.widgets.forEach(w => {
|
||||||
|
w.callback = () => {
|
||||||
|
updateInputsAndOutputs();
|
||||||
|
app.graph.setDirtyCanvas(true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initial update
|
||||||
|
setTimeout(updateInputsAndOutputs, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user