diff --git a/__init__.py b/__init__.py index 1da6262..4e850c0 100644 --- a/__init__.py +++ b/__init__.py @@ -14,6 +14,8 @@ from .nodes.metadata_extract_by_seed import MetadataExtractorBySeed from .nodes.resize_image_proportionally import ResizeImageProportionally from .nodes.image_metadata_extractor import ImageMetadataExtractor from .nodes.workspace_node import WorkspaceNode +from .nodes.input_node import InputNode +from .nodes.output_node import OutputNode # Node mappings NODE_CLASS_MAPPINGS = { @@ -21,7 +23,9 @@ NODE_CLASS_MAPPINGS = { "MetadataExtractBySeed": MetadataExtractorBySeed, "ResizeImageProportionally": ResizeImageProportionally, "ImageMetadataExtractor": ImageMetadataExtractor, - "WorkspaceNode": WorkspaceNode + "WorkspaceNode": WorkspaceNode, + "InputNode": InputNode, + "OutputNode": OutputNode } NODE_DISPLAY_NAME_MAPPINGS = { @@ -29,8 +33,9 @@ NODE_DISPLAY_NAME_MAPPINGS = { "MetadataExtractBySeed": "Metadata Extract by Seed", "ResizeImageProportionally": "Resize Image Proportionally", "ImageMetadataExtractor": "Image Metadata Extractor", - "WorkspaceNode": "Workspace Node" + "WorkspaceNode": "Workspace Node", + "InputNode": "Input Node", + "OutputNode": "Output Node" } - __all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] diff --git a/nodes/image_metadata_extractor.py b/nodes/image_metadata_extractor.py index e8d9359..f9bcfe9 100644 --- a/nodes/image_metadata_extractor.py +++ b/nodes/image_metadata_extractor.py @@ -2,7 +2,7 @@ import os from PIL import Image, ImageOps import torch import numpy as np -from sd_parsers import ParserManager # , PromptInfo +from sd_parsers import ParserManager, PromptInfo import folder_paths from typing import Any, Dict, List diff --git a/nodes/input_node.py b/nodes/input_node.py new file mode 100644 index 0000000..a8fb449 --- /dev/null +++ b/nodes/input_node.py @@ -0,0 +1,24 @@ +class InputNode: + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "input_int": ("INT", {"default": 0, "min": 0, "max": 1000, "step": 1, "display": "number"}) + } + } + + RETURN_TYPES = ("INT",) + FUNCTION = "process_input" + CATEGORY = "Custom Nodes" + + def process_input(self, input_int): + self.input_value = input_int + return (input_int,) + +NODE_CLASS_MAPPINGS = { + "InputNode": InputNode +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "InputNode": "Input Node" +} diff --git a/nodes/output_node.py b/nodes/output_node.py new file mode 100644 index 0000000..7fbc7c9 --- /dev/null +++ b/nodes/output_node.py @@ -0,0 +1,24 @@ +class OutputNode: + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "output_int": ("INT", {"default": 0, "min": 0, "max": 1000, "step": 1, "display": "number"}) + } + } + + RETURN_TYPES = () + FUNCTION = "process_output" + CATEGORY = "Custom Nodes" + + def process_output(self, output_int): + self.output_value = output_int + return () + +NODE_CLASS_MAPPINGS = { + "OutputNode": OutputNode +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "OutputNode": "Output Node" +} diff --git a/nodes/workspace_node.py b/nodes/workspace_node.py index ad45a04..96c5225 100644 --- a/nodes/workspace_node.py +++ b/nodes/workspace_node.py @@ -1,9 +1,6 @@ +import importlib.util import os -from typing import Dict, Any import json -from aiohttp import web -from PIL import Image - class WorkspaceNode: @classmethod @@ -15,22 +12,26 @@ class WorkspaceNode: } } - RETURN_TYPES = ("INT",) + RETURN_TYPES = ("STRING",) FUNCTION = "process_workspace" CATEGORY = "Custom Nodes" def process_workspace(self, input_int, workspace_path): - # Example processing: double the input integer - output_int = input_int * 2 + if not os.path.exists(workspace_path) or not workspace_path.endswith(".json"): + raise ValueError("Invalid workspace path") - # Load the workspace JSON (if exists) and print its content for now - if os.path.exists(workspace_path) and workspace_path.endswith(".json"): - with open(workspace_path, "r") as file: - workspace_data = json.load(file) - print(workspace_data) # You can process this JSON as needed + with open(workspace_path, "r") as file: + workflow = json.load(file) - return (output_int,) + # Inject input_int into the InputNode + for node in workflow["nodes"]: + if node["type"] == "InputNode": + node["properties"]["input_int"] = input_int + # Print the workflow JSON data + print(json.dumps(workflow, indent=4)) + + return (json.dumps(workflow, indent=4),) NODE_CLASS_MAPPINGS = { "WorkspaceNode": WorkspaceNode @@ -40,16 +41,45 @@ NODE_DISPLAY_NAME_MAPPINGS = { "WorkspaceNode": "Workspace Node" } -# Add custom API routes, using router -from aiohttp import web -from server import PromptServer +def load_custom_nodes(custom_nodes_path="custom_nodes"): + for filename in os.listdir(custom_nodes_path): + if filename.endswith(".py"): + module_name = filename[:-3] + module_path = os.path.join(custom_nodes_path, filename) + spec = importlib.util.spec_from_file_location(module_name, module_path) + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + for class_name, cls in module.NODE_CLASS_MAPPINGS.items(): + NODE_CLASS_MAPPINGS[class_name] = cls + for display_name, display_value in module.NODE_DISPLAY_NAME_MAPPINGS.items(): + NODE_DISPLAY_NAME_MAPPINGS[display_name] = display_value +def execute_node(node): + node_type = node["type"] + if node_type in NODE_CLASS_MAPPINGS: + node_class = NODE_CLASS_MAPPINGS[node_type] + node_instance = node_class() + func = getattr(node_instance, node_class.FUNCTION) + input_args = node["properties"] + output = func(**input_args) + return output + else: + raise ValueError(f"Unknown node type: {node_type}") -@PromptServer.instance.routes.get("/select_workspace_path") -async def select_workspace_path(request): - # Implement the logic to handle workspace path selection - return web.json_response({"message": "Workspace path selected"}) +def load_and_process_workflow(main_workflow_path): + with open(main_workflow_path, "r") as file: + main_workflow = json.load(file) + for node in main_workflow["nodes"]: + if node["type"] == "WorkspaceNode": + workspace_node = WorkspaceNode() + input_int = node["properties"]["input_int"] + workspace_path = node["properties"]["workspace_path"] + workspace_workflow = workspace_node.process_workspace(input_int, workspace_path) -# Set the web directory, any .js file in that directory will be loaded by the frontend as a frontend extension -WEB_DIRECTORY = "./somejs" + main_workflow["nodes"].extend(workspace_workflow["nodes"]) + + for node in main_workflow["nodes"]: + execute_node(node) + + return main_workflow diff --git a/requirements.txt b/requirements.txt index c7e538d..856aab6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -sd_parsers \ No newline at end of file +sd_parsers==0.3.1 \ No newline at end of file