Skip to content

Commit

Permalink
New files
Browse files Browse the repository at this point in the history
  • Loading branch information
filliptm committed Aug 7, 2024
1 parent bba8e84 commit df45207
Show file tree
Hide file tree
Showing 72 changed files with 3,592 additions and 289 deletions.
23 changes: 23 additions & 0 deletions ManagerUtils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import os
import json

def get_workflows_directory():
# Change this to the desired location within your ComfyUI directory
return os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "FL_WorkflowManager")

def get_workflow_path(name):
workflows_dir = get_workflows_directory()
return os.path.abspath(os.path.join(workflows_dir, f"{name}.json"))

def save_workflow(name, workflow_data):
file_path = get_workflow_path(name)
os.makedirs(os.path.dirname(file_path), exist_ok=True)
with open(file_path, "w") as f:
json.dump(workflow_data, f, indent=2)

def load_workflow(name):
file_path = get_workflow_path(name)
if not os.path.exists(file_path):
return None
with open(file_path, "r") as f:
return json.load(f)
86 changes: 63 additions & 23 deletions __init__.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
from .nodes.fl_image_randomizer import FL_ImageRandomizer
from .nodes.fl_image_caption_saver import FL_ImageCaptionSaver
from .nodes.FL_Image_Caption_Saver import FL_ImageCaptionSaver
from .nodes.fl_image_dimension_display import FL_ImageDimensionDisplay
#from .nodes.fl_audio_frame_calculator import FL_AudioFrameCalculator
#from .nodes.fl_audio_preview import FL_AudioPreview
#from .nodes.fl_image_duration_sync import FL_ImageDurationSync
#from .nodes.fl_vhs_audio import FL_AudioConverter
from .nodes.fl_code_node import FL_CodeNode
from .nodes.FL_Code_Node import FL_CodeNode
from .nodes.fl_image_pixelator import FL_ImagePixelator
from .nodes.fl_directorycrawl import FL_DirectoryCrawl
from .nodes.fl_ascii import FL_Ascii
from .nodes.fl_glitch import FL_Glitch
from .nodes.FL_DirectoryCrawl import FL_DirectoryCrawl
from .nodes.FL_Ascii import FL_Ascii
from .nodes.FL_Glitch import FL_Glitch
from .nodes.fl_ripple import FL_Ripple
from .nodes.fl_pixelsort import FL_PixelSort
from .nodes.fl_hexagonalpattern import FL_HexagonalPattern
from .nodes.FL_HexagonalPattern import FL_HexagonalPattern
from .nodes.fl_nftgenerator import FL_NFTGenerator
from .nodes.fl_halftone import FL_HalftonePattern
from .nodes.FL_HalfTone import FL_HalftonePattern
from .nodes.fl_randomrange import FL_RandomNumber
from .nodes.fl_promptselector import FL_PromptSelector
from .nodes.fl_shader import FL_Shadertoy
Expand All @@ -29,23 +25,37 @@
from .nodes.fl_inpaintcrop import FL_InpaintCrop
from .nodes.fl_inpaintcrop import FL_Inpaint_Stitch
from .nodes.fl_sdultimate_slices import FL_SDUltimate_Slices
from .nodes.fl_batchaligned import FL_BatchAlign
from .nodes.FL_BatchAligned import FL_BatchAlign
from .nodes.fl_videocropnstitch import FL_VideoCropMask
from .nodes.fl_videocropnstitch import FL_VideoRecompose
from .nodes.fl_separatemasks import FL_SeparateMaskComponents
from .nodes.fl_pasteoncanvas import FL_PasteOnCanvas
from .nodes.fl_bullethellgame import FL_BulletHellGame
from .nodes.FL_BulletHellGame import FL_BulletHellGame
from .nodes.fl_tetrisgame import FL_TetrisGame
from .nodes.FL_Dither import FL_Dither
from .nodes.FL_SystemCheck import FL_SystemCheck
from .nodes.FL_ColorPicker import FL_ColorPicker
from .nodes.GradientImageGenerator import GradientImageGenerator
from .nodes.FL_MirrorAndAppendCaptions import FL_MirrorAndAppendCaptions
from .nodes.FL_ImageCaptionLayout import FL_ImageCaptionLayout
from .nodes.FL_HFHubModelUploader import FL_HFHubModelUploader
from .nodes.FL_ZipDirectory import FL_ZipDirectory
from .nodes.FL_ZipSave import FL_ZipSave
from .nodes.FL_GPT_Vision import FL_GPT_Vision
from .nodes.FL_TimeLine import FL_TimeLine
from .nodes.FL_SimpleGPTVision import FL_SimpleGPTVision
from .nodes.FL_DiscordWebhook import FL_SendToDiscordWebhook
from .nodes.FL_HF_Character import FL_HF_Character
from .nodes.FL_CaptionToCSV import FL_CaptionToCSV
from .nodes.FL_KsamplerPlus import FL_KsamplerPlus




NODE_CLASS_MAPPINGS = {
"FL_ImageRandomizer": FL_ImageRandomizer,
"FL_ImageCaptionSaver": FL_ImageCaptionSaver,
"FL_ImageDimensionDisplay": FL_ImageDimensionDisplay,
#"FL_AudioPreview": FL_AudioPreview,
#"FL_ImageDurationSync": FL_ImageDurationSync,
#"FL_AudioConverter": FL_AudioConverter,
#"FL_AudioFrameCalculator": FL_AudioFrameCalculator,
"FL_CodeNode": FL_CodeNode,
"FL_ImagePixelator": FL_ImagePixelator,
"FL_DirectoryCrawl": FL_DirectoryCrawl,
Expand Down Expand Up @@ -76,17 +86,30 @@
"FL_SeparateMaskComponents": FL_SeparateMaskComponents,
"FL_PasteOnCanvas": FL_PasteOnCanvas,
"FL_BulletHellGame": FL_BulletHellGame,
"FL_TetrisGame": FL_TetrisGame
"FL_TetrisGame": FL_TetrisGame,
"FL_Dither": FL_Dither,
"FL_SystemCheck": FL_SystemCheck,
"FL_ColorPicker": FL_ColorPicker,
"GradientImageGenerator": GradientImageGenerator,
"FL_MirrorAndAppendCaptions": FL_MirrorAndAppendCaptions,
"FL_ImageCaptionLayout": FL_ImageCaptionLayout,
"FL_HFHubModelUploader": FL_HFHubModelUploader,
"FL_ZipDirectory": FL_ZipDirectory,
"FL_ZipSave": FL_ZipSave,
"FL_GPT_Vision": FL_GPT_Vision,
"FL_TimeLine": FL_TimeLine,
"FL_SimpleGPTVision": FL_SimpleGPTVision,
"FL_SendToDiscordWebhook": FL_SendToDiscordWebhook,
"FL_HF_Character": FL_HF_Character,
"FL_CaptionToCSV": FL_CaptionToCSV,
"FL_KsamplerPlus": FL_KsamplerPlus,

}

NODE_DISPLAY_NAME_MAPPINGS = {
"FL_ImageRandomizer": "FL Image Randomizer",
"FL_ImageCaptionSaver": "FL Image Caption Saver",
"FL_ImageDimensionDisplay": "FL Image Size",
#"FL_AudioPreview": "FL Audio Preview",
#"FL_ImageDurationSync": "FL Image Duration Sync",
#"FL_AudioConverter": "FL VHS Audio Converter",
#"FL_AudioFrameCalculator": "FL Audio Scanner",
"FL_CodeNode": "FL Code Node",
"FL_ImagePixelator": "FL Image Pixelator",
"FL_DirectoryCrawl": "FL Directory Crawl",
Expand Down Expand Up @@ -117,7 +140,24 @@
"FL_SeparateMaskComponents": "FL Separate Mask Components",
"FL_PasteOnCanvas": "FL Paste On Canvas",
"FL_BulletHellGame": "FL BulletHell Game",
"FL_TetrisGame": "FL Tetris Game"
"FL_TetrisGame": "FL Tetris Game",
"FL_Dither": "FL Dither",
"FL_SystemCheck": "FL System Check",
"FL_ColorPicker": "FL Color Picker",
"GradientImageGenerator": "GradientImageGenerator",
"FL_MirrorAndAppendCaptions": "FL Mirror And Append Captions",
"FL_ImageCaptionLayout": "FL Image Caption Layout",
"FL_HFHubModelUploader": "FL HFHub Model Uploader",
"FL_ZipDirectory": "FL Zip Directory",
"FL_ZipSave": "FL_ZipSave",
"FL_GPT_Vision": "FL GPT Captions",
"FL_TimeLine": "FL Time Line",
"FL_SimpleGPTVision": "FL Simple GPT Vision",
"FL_SendToDiscordWebhook": "FL Kytra Discord Webhook",
"FL_HF_Character": "FL HF Character",
"FL_CaptionToCSV": "FL Caption To CSV",
"FL_KsamplerPlus": "FL Ksampler Plus",

}


Expand Down
54 changes: 54 additions & 0 deletions nodes/FL_CaptionToCSV.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os
import csv
import io


class FL_CaptionToCSV:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"image_directory": ("STRING", {"default": ""}),
},
}

RETURN_TYPES = ("CSV",)
FUNCTION = "create_csv"
CATEGORY = "🏵️Fill Nodes/Captioning"
OUTPUT_NODE = True

def create_csv(self, image_directory):
# Get all image files and their corresponding caption files
image_files = [f for f in os.listdir(image_directory) if f.lower().endswith(('.png', '.jpg', '.jpeg'))]
image_files.sort() # Sort files to ensure consistent order

# Prepare CSV data
csv_data = []
for image_file in image_files:
caption_file = os.path.splitext(image_file)[0] + '.txt'
caption_path = os.path.join(image_directory, caption_file)
try:
with open(caption_path, 'r', encoding='utf-8') as f:
caption = f.read().strip()
except FileNotFoundError:
caption = "No caption found"

csv_data.append([image_file, caption])

# Create CSV in memory
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(['image_file', 'caption']) # Header
writer.writerows(csv_data)

# Get the CSV content as a string
csv_content = output.getvalue()

# Convert to bytes for compatibility with other nodes
csv_bytes = csv_content.encode('utf-8')

return (csv_bytes,)

@classmethod
def IS_CHANGED(cls, image_directory):
return float("NaN")
15 changes: 15 additions & 0 deletions nodes/FL_ColorPicker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class FL_ColorPicker:
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"selected_color": ("STRING", {"default": "#FF0000"})
}
}

RETURN_TYPES = ("STRING",)
FUNCTION = "get_color"
CATEGORY = "ui"

def get_color(self, selected_color):
return (selected_color,)
80 changes: 80 additions & 0 deletions nodes/FL_DiscordWebhook.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import os
import numpy as np
import requests
from PIL import Image
from moviepy.editor import ImageSequenceClip
import torch
import tempfile
import json


class FL_SendToDiscordWebhook:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"images": ("IMAGE",),
"webhook_url": ("STRING", {"default": "https://discord.com/api/webhooks/YOUR_WEBHOOK_HASH"}),
"frame_rate": ("INT", {"default": 12, "min": 1, "max": 60, "step": 1}),
"save_locally": ("BOOLEAN", {"default": True}),
"bot_username": ("STRING", {"default": "ComfyUI Bot"}),
"message": ("STRING", {"default": "Here's your image/video:", "multiline": True}),
}
}

RETURN_TYPES = ("STRING",)
FUNCTION = "generate_and_upload"
CATEGORY = "🏵️Fill Nodes/Discord"
OUTPUT_NODE = True

def generate_and_upload(self, images, webhook_url: str, frame_rate: int, save_locally: bool, bot_username: str,
message: str):
if save_locally:
output_dir = os.path.join(os.path.dirname(__file__), "outputs")
os.makedirs(output_dir, exist_ok=True)
else:
output_dir = tempfile.gettempdir()

filename = f"discord_upload_{int(torch.rand(1).item() * 10000)}"

# Prepare the webhook data
webhook_data = {
"username": bot_username,
"content": message,
}

if len(images) == 1:
file_path = os.path.join(output_dir, f"{filename}.png")
single_image = 255.0 * images[0].cpu().numpy()
single_image_pil = Image.fromarray(single_image.astype(np.uint8))
single_image_pil.save(file_path)

with open(file_path, "rb") as file_data:
files = {
"payload_json": (None, json.dumps(webhook_data)),
"file": (f"{filename}.png", file_data)
}
response = requests.post(webhook_url, files=files)
else:
frames = [255.0 * image.cpu().numpy() for image in images]
file_path = os.path.join(output_dir, f"{filename}.mp4")

clip = ImageSequenceClip(frames, fps=frame_rate)
clip.write_videofile(file_path, codec="libx264", fps=frame_rate)

with open(file_path, 'rb') as file_data:
files = {
"payload_json": (None, json.dumps(webhook_data)),
"file": (f"{filename}.mp4", file_data)
}
response = requests.post(webhook_url, files=files)

if response.status_code == 204:
message = "Successfully uploaded to Discord."
else:
message = f"Failed to upload. Status code: {response.status_code} - {response.text}"

if not save_locally:
os.remove(file_path)

return (message,)
Loading

0 comments on commit df45207

Please sign in to comment.