Skip to content

Commit

Permalink
0.65
Browse files Browse the repository at this point in the history
  • Loading branch information
justUmen committed Jan 11, 2025
1 parent 38b83ed commit efd4105
Show file tree
Hide file tree
Showing 20 changed files with 366 additions and 19 deletions.
72 changes: 69 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# 🔗 Comfyui : Bjornulf_custom_nodes v0.64 🔗
# 🔗 Comfyui : Bjornulf_custom_nodes v0.65 🔗

A list of 110 custom nodes for Comfyui : Display, manipulate, create and edit text, images, videos, loras, generate characters and more.
A list of 116 custom nodes for Comfyui : Display, manipulate, create and edit text, images, videos, loras, generate characters and more.
You can manage looping operations, generate randomized content, trigger logical conditions, pause and manually control your workflows and even work with external AI tools, like Ollama or Text To Speech.

# Coffee : ☕☕☕☕☕ 5/5
Expand Down Expand Up @@ -36,6 +36,12 @@ Support me and my work : ❤️❤️❤️ <https://ko-fi.com/bjornulf> ❤️
`67.` [📝➜✨ Text to Anything](#67----text-to-anything)
`68.` [✨➜📝 Anything to Text](#68----anything-to-text)
`75.` [📝➜📝 Replace text](#75----replace-text)
`15.` [💾 Save Text](#15----save-text)
`111.` [✨➜🔢 Anything to Int](#)
`112.` [✨➜🔢 Anything to Float](#)
`113.` [📝🔪 Text split in 5](#)
`115.` [📥 Load Text From Bjornulf Folder](#)
`116.` [📥 Load Text From Path](#)

## 🔥 Text Generator 🔥
`81.` [🔥📝 Text Generator 📝🔥](#81----text-generator-)
Expand Down Expand Up @@ -131,6 +137,7 @@ Support me and my work : ❤️❤️❤️ <https://ko-fi.com/bjornulf> ❤️
## 🚀 Load loras 🚀
`54.` [♻ Loop Lora Selector](#54----loop-lora-selector)
`55.` [🎲 Random Lora@ Selector](#55----random-lora-selector)
`114.` [📥👑 Load Lora with Path]()

## ☁ Image Creation : API / cloud / remote ☁
`106.` [☁🎨 API Image Generator (FalAI) ☁](#10)
Expand Down Expand Up @@ -345,6 +352,7 @@ cd /where/you/installed/ComfyUI && python main.py
- **0.62**: MASSIVE update, Text Generator nodes. (15 nodes), API nodes generate (civitai / black forest labs / fal.ai), API civit ai download models nodes, lora
- **0.63**: delete long file, useless
- **0.64**: remove "import wget", added some keywords to text generators.
- **0.65**: ❗Breaking changes : Combine Text inputs are now all optional (PLease remake your nodes, sorry.) Add 6 new nodes : any2int, any2float, load text from folder, load text from path, load lora from path. Also upgraded the Save text node.

# 📝 Nodes descriptions

Expand Down Expand Up @@ -491,6 +499,7 @@ Resize an image to exact dimensions. The other node will save the image to the e
**Description:**
Save the given text input to a file. Useful for logging and storing text data.
If the file already exist, it will add the text at the end of the file.
I recommend you to keep saving them in "Bjornulf/Text" (Which is in the Comfyui folder, next to output), this is where the node 116 `Load text from folder` is looking for text files.

![Save Text](screenshots/save_text.png)

Expand Down Expand Up @@ -1574,4 +1583,61 @@ Generate an image with the Black Forest Labs API. (flux)
**Description:**
Generate an image with the Stability API. (sd3)

![api stability](screenshots/api_stability.png)
![api stability](screenshots/api_stability.png)

#### 111 - ✨➜🔢 Anything to Int

**Description:**

Just convert anything to a valid INT. (integer)

![Anything to Int](screenshots/anything_to_int.png)

#### 112 - ✨➜🔢 Anything to Float

**Description:**

Just convert anything to a valid FLOAT. (floating number)

![Anything to Float](screenshots/anything_to_float.png)

#### 113 - 📝🔪 Text split in 5

**Description:**

Take a single input and split it in 5 with a delimiter (newline by default).
It can also ignore everything on the left side of a `=` symbol if you want to use a "variable type format".

![Text split in 5](screenshots/split_in_5.png)

#### 114 - 📥👑 Load Lora with Path

**Description:**

Load a lora by using it's path.

![load lora with path](screenshots/load_lora_with_path.png)

Here is a complex practical example using node 113, 114, 112 :
![load lora with path](screenshots/load_lora_with_path_COMPLEX.png)

#### 115 - 📥 Load Text From Bjornulf Folder

**Description:**

Just select a file from the folder `Bjornulf/Text` folder, it will recover its content.
It is made to be used with node 15 `Save Text`.

![Load Text](screenshots/load_text_from_Bjornulf.png)

#### 116 - 📥 Load Text From Path

**Description:**

Just give the path of the file, it will recover its content.

![Load Text](screenshots/load_text_requirements.png)

If you want, with `Load Text From Path` you can also recover the elements in "Bjornulf/Text" by just adding it:

![Load Text](screenshots/load_text_PATH.png)
18 changes: 17 additions & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@
from .speech_to_text import SpeechToText
from .text_to_anything import TextToAnything
from .anything_to_text import AnythingToText
from .anything_to_int import AnythingToInt
from .anything_to_float import AnythingToFloat
from .add_line_numbers import AddLineNumbers
from .ffmpeg_convert import ConvertVideo
# from .hiresfix import HiResFix
Expand All @@ -88,9 +90,16 @@
from .API_civitai import APIGenerateCivitAI, APIGenerateCivitAIAddLORA, CivitAIModelSelectorPony, CivitAIModelSelectorSD15, CivitAIModelSelectorSDXL, CivitAIModelSelectorFLUX_S, CivitAIModelSelectorFLUX_D, CivitAILoraSelectorSD15, CivitAILoraSelectorSDXL, CivitAILoraSelectorPONY
from .API_falAI import APIGenerateFalAI
from .latent_resolution_selector import LatentResolutionSelector
from .loader_lora_with_path import LoaderLoraWithPath
from .load_text import LoadTextFromFolder, LoadTextFromPath
from .string_splitter import TextSplitin5

NODE_CLASS_MAPPINGS = {
"Bjornulf_LatentResolutionSelector": LatentResolutionSelector,
"Bjornulf_LoaderLoraWithPath": LoaderLoraWithPath,
"Bjornulf_LoadTextFromPath": LoadTextFromPath,
"Bjornulf_LoadTextFromFolder": LoadTextFromFolder,
"Bjornulf_TextSplitin5": TextSplitin5,
"Bjornulf_APIGenerateFlux": APIGenerateFlux,
"Bjornulf_APIGenerateFalAI": APIGenerateFalAI,
"Bjornulf_APIGenerateStability": APIGenerateStability,
Expand Down Expand Up @@ -134,6 +143,8 @@
"Bjornulf_AddLineNumbers": AddLineNumbers,
"Bjornulf_TextToAnything": TextToAnything,
"Bjornulf_AnythingToText": AnythingToText,
"Bjornulf_AnythingToInt": AnythingToInt,
"Bjornulf_AnythingToFloat": AnythingToFloat,
"Bjornulf_SpeechToText": SpeechToText,
"Bjornulf_OllamaConfig": OllamaConfig,
"Bjornulf_OllamaSystemPersonaSelector": OllamaSystemPersonaSelector,
Expand Down Expand Up @@ -211,6 +222,8 @@
# "Bjornulf_ImageBlend": "🎨 Image Blend",
# "Bjornulf_APIHiResCivitAI": "🎨➜🎨 API Image hires fix (CivitAI)",
# "Bjornulf_CivitAILoraSelector": "lora Civit",
"Bjornulf_LoaderLoraWithPath": "📥👑 Load Lora with Path",
"Bjornulf_TextSplitin5": "📝🔪 Text split in 5",
"Bjornulf_LatentResolutionSelector": "🩷 Empty Latent Selector",
"Bjornulf_CivitAIModelSelectorSD15": "📥 Load checkpoint SD1.5 (+Download from CivitAi)",
"Bjornulf_CivitAIModelSelectorSDXL": "📥 Load checkpoint SDXL (+Download from CivitAi)",
Expand Down Expand Up @@ -255,6 +268,8 @@
"Bjornulf_TextToSpeech": "📝➜🔊 TTS - Text to Speech",
"Bjornulf_TextToAnything": "📝➜✨ Text to Anything",
"Bjornulf_AnythingToText": "✨➜📝 Anything to Text",
"Bjornulf_AnythingToInt": "✨➜🔢 Anything to Int",
"Bjornulf_AnythingToFloat": "✨➜🔢 Anything to Float",
"Bjornulf_TextReplace": "📝➜📝 Replace text",
"Bjornulf_AddLineNumbers": "🔢 Add line numbers",
"Bjornulf_FFmpegConfig": "⚙📹 FFmpeg Configuration 📹⚙",
Expand Down Expand Up @@ -311,7 +326,8 @@
"Bjornulf_SaveImageToFolder": "💾🖼📁 Save Image(s) to a folder",
"Bjornulf_SaveTmpImage": "💾🖼 Save Image (tmp_api.png) ⚠️💣",
"Bjornulf_SaveText": "💾 Save Text",
# "Bjornulf_LoadText": "📥 Load Text",
"Bjornulf_LoadTextFromPath": "📥 Load Text From Path",
"Bjornulf_LoadTextFromFolder": "📥 Load Text From Bjornulf Folder",
"Bjornulf_CombineTexts": "🔗 Combine (Texts)",
"Bjornulf_imagesToVideo": "📹 images to video (FFmpeg)",
"Bjornulf_VideoPingPong": "📹 video PingPong",
Expand Down
28 changes: 28 additions & 0 deletions anything_to_float.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class Everything(str):
def __ne__(self, __value: object) -> bool:
return False

class AnythingToFloat:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"anything": (Everything("*"), {"forceInput": True}),
},
}

@classmethod
def VALIDATE_INPUTS(s, input_types):
return True

RETURN_TYPES = ("FLOAT",)
RETURN_NAMES = ("float",)
FUNCTION = "any_to_float"
CATEGORY = "Bjornulf"

def any_to_float(self, anything):
try:
return (float(anything),)
except (ValueError, TypeError):
# Return 0.0 if conversion fails
return (0.0,)
32 changes: 32 additions & 0 deletions anything_to_int.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class Everything(str):
def __ne__(self, __value: object) -> bool:
return False

class AnythingToInt:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"anything": (Everything("*"), {"forceInput": True}),
},
}

@classmethod
def VALIDATE_INPUTS(s, input_types):
return True

RETURN_TYPES = ("INT",)
RETURN_NAMES = ("integer",)
FUNCTION = "any_to_int"
CATEGORY = "Bjornulf"

def any_to_int(self, anything):
try:
# Handle string inputs that might be floats
if isinstance(anything, str) and '.' in anything:
return (int(float(anything)),)
# Handle other types
return (int(anything),)
except (ValueError, TypeError):
# Return 0 if conversion fails
return (0,)
10 changes: 4 additions & 6 deletions anything_to_text.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
class Everything(str):
def __ne__(self, __value: object) -> bool:
return False
class AnythingToText:
@classmethod
def INPUT_TYPES(s):
Expand All @@ -18,9 +21,4 @@ def VALIDATE_INPUTS(s, input_types):

def any_to_text(self, anything):
# Convert the input to string representation
return (str(anything),)

# Keep the Everything class definition as it's needed for type handling
class Everything(str):
def __ne__(self, __value: object) -> bool:
return False
return (str(anything),)
4 changes: 1 addition & 3 deletions combine_texts.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ def INPUT_TYPES(cls):
"required": {
"number_of_inputs": ("INT", {"default": 2, "min": 2, "max": 50, "step": 1}),
"delimiter": (["newline", "comma", "space", "slash", "nothing"], {"default": "newline"}),
"text_1": ("STRING", {"forceInput": True}),
"text_2": ("STRING", {"forceInput": True}),
},
"hidden": {
**{f"text_{i}": ("STRING", {"forceInput": True}) for i in range(3, 51)}
**{f"text_{i}": ("STRING", {"forceInput": True}) for i in range(1, 51)}
}
}

Expand Down
92 changes: 92 additions & 0 deletions load_text.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import os

class LoadTextFromFolder:
@classmethod
def INPUT_TYPES(cls):
"""Define input parameters for the node"""
default_dir = "Bjornulf/Text"
available_files = []

if os.path.exists(default_dir):
available_files = [f for f in os.listdir(default_dir)
if f.lower().endswith('.txt')]

if not available_files:
available_files = ["no_files_found"]

return {
"required": {
"text_file": (available_files, {"default": available_files[0]}),
}
}

RETURN_TYPES = ("STRING", "STRING", "STRING")
RETURN_NAMES = ("text", "filename", "full_path")
FUNCTION = "load_text"
CATEGORY = "Bjornulf"

def load_text(self, text_file):
try:
if text_file == "no_files_found":
raise ValueError("No text files found in Bjornulf/Text folder")

filepath = os.path.join("Bjornulf/Text", text_file)

# Check if file exists
if not os.path.exists(filepath):
raise ValueError(f"File not found: {filepath}")

# Get absolute path
full_path = os.path.abspath(filepath)

# Get just the filename
filename = os.path.basename(filepath)

# Read text from file
with open(filepath, 'r', encoding='utf-8') as file:
text = file.read()

return (text, filename, full_path)

except (OSError, IOError) as e:
raise ValueError(f"Error loading file: {str(e)}")

class LoadTextFromPath:
@classmethod
def INPUT_TYPES(cls):
"""Define input parameters for the node"""
return {
"required": {
"file_path": ("STRING", {"default": "Bjornulf/Text/example.txt"}),
}
}

RETURN_TYPES = ("STRING", "STRING", "STRING")
RETURN_NAMES = ("text", "filename", "full_path")
FUNCTION = "load_text"
CATEGORY = "Bjornulf"

def load_text(self, file_path):
try:
# Validate file extension
if not file_path.lower().endswith('.txt'):
raise ValueError("File must be a .txt file")

# Check if file exists
if not os.path.exists(file_path):
raise ValueError(f"File not found: {file_path}")

# Get absolute path
full_path = os.path.abspath(file_path)

# Get just the filename
filename = os.path.basename(file_path)

# Read text from file
with open(file_path, 'r', encoding='utf-8') as file:
text = file.read()

return (text, filename, full_path)

except (OSError, IOError) as e:
raise ValueError(f"Error loading file: {str(e)}")
Loading

0 comments on commit efd4105

Please sign in to comment.