This commit is contained in:
justumen
2024-09-09 22:38:49 +02:00
parent c7faf321ff
commit c80563376f
7 changed files with 137 additions and 4 deletions

View File

@@ -1,4 +1,4 @@
# 🔗 Comfyui : Bjornulf_custom_nodes v0.16 🔗
# 🔗 Comfyui : Bjornulf_custom_nodes v0.17 🔗
# Dependencies
@@ -26,6 +26,7 @@
- **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.16**: Big changes on Character Description Generator
- **v0.17**: New loop node, combine by lines.
# 📝 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.
❗ 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.
### 33 - ♻ Loop (All Lines from input 🔗 combine by lines)
![loop combined](screenshots/loop_combined.png)
**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.

View File

@@ -37,6 +37,7 @@ from .load_image_alpha import LoadImageWithTransparency
from .image_mask_cutter import ImageMaskCutter
from .character_description import CharacterDescriptionGenerator
from .text_to_speech import TextToSpeech
from .loop_combine_texts_by_lines import CombineTextsByLines
# from .check_black_image import CheckBlackImage
# from .clear_vram import ClearVRAM
@@ -45,6 +46,7 @@ from .text_to_speech import TextToSpeech
NODE_CLASS_MAPPINGS = {
# "Bjornulf_CustomStringType": CustomStringType,
"Bjornulf_ollamaLoader": ollamaLoader,
"Bjornulf_CombineTextsByLines": CombineTextsByLines,
"Bjornulf_TextToSpeech": TextToSpeech,
"Bjornulf_CharacterDescriptionGenerator": CharacterDescriptionGenerator,
"Bjornulf_ImageMaskCutter": ImageMaskCutter,
@@ -90,6 +92,7 @@ NODE_CLASS_MAPPINGS = {
NODE_DISPLAY_NAME_MAPPINGS = {
# "Bjornulf_CustomStringType": "!!! CUSTOM STRING TYPE !!!",
"Bjornulf_ollamaLoader": "🦙 Ollama (Description)",
"Bjornulf_CombineTextsByLines": "♻ Loop (All Lines from input 🔗 combine by lines)",
"Bjornulf_TextToSpeech": "🔊 TTS - Text to Speech",
"Bjornulf_CharacterDescriptionGenerator": "🧑📝 Character Description Generator",
"Bjornulf_ImageMaskCutter": "🖼✂ Cut Image with Mask",

View 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

View File

@@ -1,7 +1,7 @@
[project]
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, ..."
version = "0.16"
version = "0.17"
license = {file = "LICENSE"}
[project.urls]

Binary file not shown.

After

Width:  |  Height:  |  Size: 453 KiB

View File

@@ -40,7 +40,7 @@ class TextToSpeech:
RETURN_TYPES = ("AUDIO",)
FUNCTION = "generate_audio"
CATEGORY = "audio"
CATEGORY = "Bjornulf"
def generate_audio(self, text, language, speaker_wav):
# Check if a valid speaker_wav was selected

View 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);
}
}
});