diff --git a/__init__.py b/__init__.py index 2d605f3..11c5fd5 100644 --- a/__init__.py +++ b/__init__.py @@ -5,97 +5,75 @@ @description: This extension offers various nodes that allow you to work with LLMs using the Griptape Python Framework (https://griptape.ai) """ -import json import os from dotenv import load_dotenv -from .nodes.agent.convert_agent_to_tool import gtUIConvertAgentToTool - # Load the griptape_config.json data from .nodes.agent.create_agent import CreateAgent from .nodes.agent.expand_agent import ExpandAgent from .nodes.agent.run_agent import RunAgent from .nodes.agent.set_default_agent import gtUISetDefaultAgent -from .nodes.audio_drivers import gtUIOpenAiAudioTranscriptionDriver -from .nodes.audio_nodes import gtUILoadAudio -from .nodes.combine_nodes import MergeTexts, RulesList, ToolList, gtUIMergeInputs -from .nodes.config.amazon_bedrock_config import gtUIAmazonBedrockStructureConfig -from .nodes.config.anthropic_config import gtUIAnthropicStructureConfig -from .nodes.config.azure_openai_config import gtUIAzureOpenAiStructureConfig -from .nodes.config.google_config import gtUIGoogleStructureConfig -from .nodes.config.huggingface_config import gtUIHuggingFaceStructureConfig -from .nodes.config.lmstudio_config import gtUILMStudioStructureConfig -from .nodes.config.ollama_config import gtUIOllamaStructureConfig -from .nodes.config.openai_compatable_config import gtUIOpenAiCompatableConfig -from .nodes.config.openai_config import gtUIOpenAiStructureConfig -from .nodes.display_nodes import ( - # gtUIOutputArtifactNode, - gtUIOutputDataNode, - gtUIOutputImageNode, - gtUIOutputStringNode, -) -from .nodes.image_drivers import ( +from .nodes.combine.MergeInputs import gtUIMergeInputs +from .nodes.combine.MergeTexts import MergeTexts +from .nodes.combine.RulesList import RulesList +from .nodes.combine.ToolList import ToolList +from .nodes.config.AmazonBedrockStructureConfig import gtUIAmazonBedrockStructureConfig +from .nodes.config.AnthropicStructureConfig import gtUIAnthropicStructureConfig +from .nodes.config.AzureOpenAiStructureConfig import gtUIAzureOpenAiStructureConfig +from .nodes.config.GoogleStructureConfig import gtUIGoogleStructureConfig +from .nodes.config.HuggingFaceStructureConfig import gtUIHuggingFaceStructureConfig +from .nodes.config.LmStudioStructureConfig import gtUILMStudioStructureConfig +from .nodes.config.OllamaStructureConfig import gtUIOllamaStructureConfig +from .nodes.config.OpenAiCompatableConfig import gtUIOpenAiCompatableConfig +from .nodes.config.OpenAiConfig import gtUIOpenAiStructureConfig +from .nodes.convert.TextToClipEncode import gtUITextToClipEncode +from .nodes.convert.TextToCombo import gtUITextToCombo +from .nodes.display.OutputArtifactNode import gtUIOutputArtifactNode +from .nodes.display.OutputDataNode import gtUIOutputDataNode +from .nodes.display.OutputImageNode import gtUIOutputImageNode +from .nodes.display.OutputStringNode import gtUIOutputStringNode +from .nodes.drivers.AmazonBedrockStableDiffusionImageGenerationDriver import ( gtUIAmazonBedrockStableDiffusionImageGenerationDriver, +) +from .nodes.drivers.AmazonBedrockTitanImageGenerationDriver import ( gtUIAmazonBedrockTitanImageGenerationDriver, +) +from .nodes.drivers.DuckDuckGoWebSearchDriver import gtUIDuckDuckGoWebSearchDriver +from .nodes.drivers.GoogleWebSearchDriver import gtUIGoogleWebSearchDriver +from .nodes.drivers.LonardoImageGenerationDriver import ( gtUILeonardoImageGenerationDriver, - gtUIOpenAiImageGenerationDriver, ) -from .nodes.image_nodes import ( - gtUIFetchImage, +from .nodes.drivers.OpenAiAudioTranscriptionDriver import ( + gtUIOpenAiAudioTranscriptionDriver, ) -from .nodes.rules import gtUIRule - -# from .nodes.structure_nodes import ( -# gtUICreatePipeline, -# gtUIPipelineAddTask, -# gtUIPipelineInsertTask, -# gtUIRunStructure, -# ) -from .nodes.tasks.audio_transcription_task import gtUIAudioTranscriptionTask +from .nodes.drivers.OpenAiImageGenerationDriver import gtUIOpenAiImageGenerationDriver +from .nodes.loaders.FetchImage import gtUIFetchImage +from .nodes.loaders.LoadAudio import gtUILoadAudio +from .nodes.rules.Rule import gtUIRule +from .nodes.tasks.AudioTranscriptionTask import gtUIAudioTranscriptionTask # from .nodes.tasks.csv_extraction_task import gtUICSVExtractionTask -from .nodes.tasks.image_query_task import gtUIImageQueryTask +from .nodes.tasks.ImageQueryTask import gtUIImageQueryTask # from .nodes.tasks.json_extraction_task import gtUIJSONExtractionTask -from .nodes.tasks.parallel_image_query_task import gtUIParallelImageQueryTask -from .nodes.tasks.prompt_image_generation_task import gtUIPromptImageGenerationTask -from .nodes.tasks.prompt_image_variation_task import gtUIPromptImageVariationTask -from .nodes.tasks.prompt_task import gtUIPromptTask -from .nodes.tasks.text_summary_task import gtUITextSummaryTask -from .nodes.tasks.tool_task import gtUIToolTask -from .nodes.tasks.toolkit_task import gtUIToolkitTask - -# from .nodes.tasks import ( -# gtUIAudioTranscriptionTask, -# gtUIImageQueryTask, -# gtUIParallelImageQueryTask, -# gtUIPromptImageGenerationTask, -# gtUIPromptImageVariationTask, -# # gtUIPromptTask, -# gtUITextSummaryTask, -# gtUIToolkitTask, -# gtUIToolTask, -# ) -from .nodes.text_nodes import ( - gtUICLIPTextEncode, - gtUIInputStringNode, - gtUITextToClipEncode, - gtUITextToCombo, -) -from .nodes.tools import ( - gtUIAudioTranscriptionClient, - gtUICalculator, - gtUIDateTime, - gtUIFileManager, - gtUIKnowledgeBaseTool, - gtUIWebScraper, - gtUIWebSearch, -) -from .nodes.websearch_drivers import ( - gtUIDuckDuckGoWebSearchDriver, - gtUIGoogleWebSearchDriver, -) +from .nodes.tasks.ParallelImageQueryTask import gtUIParallelImageQueryTask +from .nodes.tasks.PromptImageGenerationTask import gtUIPromptImageGenerationTask +from .nodes.tasks.PromptImageVariationTask import gtUIPromptImageVariationTask +from .nodes.tasks.PromptTask import gtUIPromptTask +from .nodes.tasks.TextSummaryTask import gtUITextSummaryTask +from .nodes.tasks.ToolkitTask import gtUIToolkitTask +from .nodes.tasks.ToolTask import gtUIToolTask +from .nodes.text.CLIPTextEncode import gtUICLIPTextEncode +from .nodes.text.InputStringNode import gtUIInputStringNode +from .nodes.tools.AudioTranscriptionClient import gtUIAudioTranscriptionClient +from .nodes.tools.Calculator import gtUICalculator +from .nodes.tools.ConvertAgentToTool import gtUIConvertAgentToTool +from .nodes.tools.DateTime import gtUIDateTime +from .nodes.tools.FileManager import gtUIFileManager +from .nodes.tools.KnowledgeBaseTool import gtUIKnowledgeBaseTool +from .nodes.tools.WebScraper import gtUIWebScraper +from .nodes.tools.WebSearch import gtUIWebSearch from .py.griptape_config import ( load_and_prepare_config, set_environment_variables_from_config, @@ -198,51 +176,6 @@ NODE_CLASS_MAPPINGS = { # "Griptape Config: Environment Variables": gtUIEnv, } -# NODE_DISPLAY_NAME_MAPPINGS = { -# "gtUIInputNode": "Griptape Create: Text", -# "gtUICLIPTextEncode": "Griptape Create: CLIP Text Encode", -# "gtUITextToClipEncode": "Griptape Convert: Text to CLIP Encode", -# "gtUIFetchImage": "Griptape Load: Image From URL", -# "CreateAgent": "Griptape Create: Agent", -# "RunAgent": "Griptape Run: Agent", -# "PromptImageGenerationTask": "Griptape Create: Image from Text", -# "PromptImageVariationTask": "Griptape Create: Image Variation", -# "Rule": "Griptape Create: Rules", -# "RulesList": "Griptape Create: Rules List", -# "gtUIOpenAiAudioTranscriptionDriver": "Griptape Driver: OpenAI", -# "gtUIAmazonBedrockStableDiffusionImageGenerationDriver": "Griptape Driver: Amazon Bedrock Stable Diffusion", -# "gtUIAmazonBedrockTitanImageGenerationDriver": "Griptape Driver: Amazon Bedrock Titan", -# "gtUILeonardoImageGenerationDriver": "Griptape Driver: Leonardo.AI", -# "gtUIOutputStringNode": "Griptape Display: Text", -# "gtUIOutputImageNode": "Griptape Display: Image", -# "gtUIOutputArtifactNode": "Griptape Display: Artifact", -# "ImageQueryTask": "Griptape Run: Image Description", -# "ParallelImageQueryTask": "Griptape Run: Parallel Image Description", -# "PromptTask": "Griptape Run: Prompt Task", -# "ToolTask": "Griptape Run: Tool Task", -# "ToolkitTask": "Griptape Run: Toolkit Task", -# "TextSummaryTask": "Griptape Run: Text Summary", -# "AudioTranscriptionTask": "Griptape Run: Audio Transcription", -# "ExpandAgent": "Griptape Expand: Agent Nodes", -# "gtUIOpenAiStructureConfig": "Griptape Agent Config: OpenAI", -# "gtUIAmazonBedrockStructureConfig": "Griptape Agent Config: Amazon Bedrock", -# "gtUIGoogleStructureConfig": "Griptape Agent Config: Google", -# "gtUIAnthropicStructureConfig": "Griptape Agent Config: Anthropic", -# "gtUIOllamaStructureConfig": "Griptape Agent Config: Ollama", -# "gtUILMStudioStructureConfig": "Griptape Agent Config: LM Studio", -# "Calculator": "Griptape Tool: Calculator", -# "DateTime": "Griptape Tool: DateTime", -# "WebScraper": "Griptape Tool: WebScraper", -# "gtUIFileManager": "Griptape Tool: FileManager", -# "gtAudioTranscriptionClient": "Griptape Tool: Audio Transcription", -# "gtUIKnowledgeBaseTool": "Griptape Tool: Griptape Cloud KnowledgeBase", -# "gtUIWebSearch": "Griptape Tool: WebSearch", -# "ToolList": "Griptape Combine: Tool List", -# "MergeTexts": "Griptape Combine: Merge Texts", -# "EnvironmentConfig": "Griptape Config: Environment Variables", -# "gtUIOpenAiImageGenerationDriver": "Griptape Audio Driver: OpenAI", -# "gtUILoadAudio": "Griptape Load: Audio", -# } __all__ = ["NODE_CLASS_MAPPINGS", "WEB_DIRECTORY"] print(" \033[34m- \033[92mDone!\033[0m\n") diff --git a/js/gtUINodes.js b/js/gtUINodes.js index 0f1390b..cddfb29 100644 --- a/js/gtUINodes.js +++ b/js/gtUINodes.js @@ -490,7 +490,6 @@ app.registerExtension({ gtUIAddUploadWidget(nodeType, nodeData, "audio", "audio") } - // Display Artifact Node if (nodeData.name === "Griptape Display: Artifact") { const onNodeCreated = nodeType.prototype.onNodeCreated; @@ -664,9 +663,6 @@ app.registerExtension({ if(!link_info) return; if(type==1) { - console.log("link_info", link_info); - console.log("connected", connected); - console.log("index", index); const node = app.graph.getNodeById(link_info.origin_id); let origin_type = node.outputs[link_info.origin_slot].type; diff --git a/nodes/combine/MergeInputs.py b/nodes/combine/MergeInputs.py new file mode 100644 index 0000000..24f3562 --- /dev/null +++ b/nodes/combine/MergeInputs.py @@ -0,0 +1,34 @@ +class gtUIMergeInputs: + """ + Takes any inputs and merges them.. like strings, but just any inputs instead. + """ + + DESCRIPTION = "Merge multiple inputs into one." + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "required": {}, + "optional": { + "input_1": ("*",), + }, + } + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("OUTPUT",) + FUNCTION = "create" + + CATEGORY = "Griptape/Text" + + def create( + self, + **kwargs, + ): + concatenated_value = "" + inputs = [value for value in kwargs.values()] + for input in inputs: + concatenated_value += "\n\n" + str(input) + return (concatenated_value,) diff --git a/nodes/combine/MergeTexts.py b/nodes/combine/MergeTexts.py new file mode 100644 index 0000000..0d4043e --- /dev/null +++ b/nodes/combine/MergeTexts.py @@ -0,0 +1,42 @@ +class MergeTexts: + """ + Merge Texts + """ + + DESCRIPTION = "Merge multiple strings into one." + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "required": {}, + "optional": { + "merge_string": ("STRING", {"default": "\\n\\n"}), + "input_1": ( + "STRING", + {"multiline": False, "default": "", "forceInput": True}, + ), + }, + } + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("OUTPUT",) + FUNCTION = "create" + + CATEGORY = "Griptape/Text" + + def create( + self, + **kwargs, + ): + merged_text = "" + + sep = kwargs["merge_string"].replace("\\n", "\n") + del kwargs["merge_string"] + + inputs = [value for value in kwargs.values()] + + merged_text = sep.join(inputs) + return (merged_text.strip(),) diff --git a/nodes/combine/RulesList.py b/nodes/combine/RulesList.py new file mode 100644 index 0000000..9c42180 --- /dev/null +++ b/nodes/combine/RulesList.py @@ -0,0 +1,34 @@ +class RulesList: + """ + Griptape Lists of Rules + """ + + DESCRIPTION = "Combine rules to give an agent a more complex set of rules." + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "optional": { + "rules_1": ("RULESET",), + } + } + + RETURN_TYPES = ("RULESET",) + RETURN_NAMES = ("RULESET",) + FUNCTION = "create" + + CATEGORY = "Griptape/Agent Rules" + + def create(self, **kwargs): + # Clear the rule_list + rule_list = [] + + rules = [value for value in kwargs.values()] + if len(rules) > 0: + for rule in rules: + rule_list.append(rule[0]) + # rule_list = [rule[0] for rule in [kwargs.values()] if rule is not None] + return (rule_list,) diff --git a/nodes/combine/ToolList.py b/nodes/combine/ToolList.py new file mode 100644 index 0000000..985ff11 --- /dev/null +++ b/nodes/combine/ToolList.py @@ -0,0 +1,32 @@ +class ToolList: + """ + Griptape Tool List + """ + + DESCRIPTION = "Combine tools to give an agent a more complex set of tools." + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "optional": { + "tool_1": ("TOOL_LIST",), + } + } + + RETURN_TYPES = ("TOOL_LIST",) + RETURN_NAMES = ("TOOL_LIST",) + FUNCTION = "create" + + CATEGORY = "Griptape/Agent Tools" + + def create(self, **kwargs): + tool_list = [] + + tools = [value for value in kwargs.values()] + if len(tools) > 0: + for tool in tools: + tool_list.append(tool[0]) + return (tool_list,) diff --git a/nodes/combine/__init__.py b/nodes/combine/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nodes/combine_nodes.py b/nodes/combine_nodes.py deleted file mode 100644 index 688b573..0000000 --- a/nodes/combine_nodes.py +++ /dev/null @@ -1,148 +0,0 @@ -class MergeTexts: - """ - Merge Texts - """ - - DESCRIPTION = "Merge multiple strings into one." - - def __init__(self): - pass - - @classmethod - def INPUT_TYPES(s): - return { - "required": {}, - "optional": { - "merge_string": ("STRING", {"default": "\\n\\n"}), - "input_1": ( - "STRING", - {"multiline": False, "default": "", "forceInput": True}, - ), - }, - } - - RETURN_TYPES = ("STRING",) - RETURN_NAMES = ("OUTPUT",) - FUNCTION = "create" - - CATEGORY = "Griptape/Text" - - def create( - self, - **kwargs, - ): - merged_text = "" - - sep = kwargs["merge_string"].replace("\\n", "\n") - del kwargs["merge_string"] - - inputs = [value for value in kwargs.values()] - - merged_text = sep.join(inputs) - return (merged_text.strip(),) - - -class gtUIMergeInputs: - """ - Takes any inputs and merges them.. like strings, but just any inputs instead. - """ - - DESCRIPTION = "Merge multiple inputs into one." - - def __init__(self): - pass - - @classmethod - def INPUT_TYPES(s): - return { - "required": {}, - "optional": { - "input_1": ("*",), - }, - } - - RETURN_TYPES = ("STRING",) - RETURN_NAMES = ("OUTPUT",) - FUNCTION = "create" - - CATEGORY = "Griptape/Text" - - def create( - self, - **kwargs, - ): - concatenated_value = "" - inputs = [value for value in kwargs.values()] - for input in inputs: - concatenated_value += "\n\n" + str(input) - return (concatenated_value,) - - -class RulesList: - """ - Griptape Lists of Rules - """ - - DESCRIPTION = "Combine rules to give an agent a more complex set of rules." - - def __init__(self): - pass - - @classmethod - def INPUT_TYPES(s): - return { - "optional": { - "rules_1": ("RULESET",), - } - } - - RETURN_TYPES = ("RULESET",) - RETURN_NAMES = ("RULESET",) - FUNCTION = "create" - - CATEGORY = "Griptape/Agent Rules" - - def create(self, **kwargs): - # Clear the rule_list - rule_list = [] - - rules = [value for value in kwargs.values()] - if len(rules) > 0: - for rule in rules: - rule_list.append(rule[0]) - # rule_list = [rule[0] for rule in [kwargs.values()] if rule is not None] - return (rule_list,) - - -class ToolList: - """ - Griptape Tool List - """ - - DESCRIPTION = "Combine tools to give an agent a more complex set of tools." - - def __init__(self): - pass - - @classmethod - def INPUT_TYPES(s): - return { - "optional": { - "tool_1": ("TOOL_LIST",), - } - } - - RETURN_TYPES = ("TOOL_LIST",) - RETURN_NAMES = ("TOOL_LIST",) - FUNCTION = "create" - - CATEGORY = "Griptape/Agent Tools" - - def create(self, **kwargs): - tool_list = [] - - tools = [value for value in kwargs.values()] - if len(tools) > 0: - for tool in tools: - tool_list.append(tool[0]) - return (tool_list,) diff --git a/nodes/config/amazon_bedrock_config.py b/nodes/config/AmazonBedrockStructureConfig.py similarity index 92% rename from nodes/config/amazon_bedrock_config.py rename to nodes/config/AmazonBedrockStructureConfig.py index 9837b9f..5bc56a1 100644 --- a/nodes/config/amazon_bedrock_config.py +++ b/nodes/config/AmazonBedrockStructureConfig.py @@ -9,7 +9,7 @@ from griptape.drivers import ( BedrockClaudeImageQueryModelDriver, ) -from .base_config import gtUIBaseConfig +from .BaseConfig import gtUIBaseConfig amazonBedrockPromptModels = [ "anthropic.claude-3-5-sonnet-20240620-v1:0", @@ -54,11 +54,6 @@ class gtUIAmazonBedrockStructureConfig(gtUIBaseConfig): def create( self, - prompt_model, - image_query_model, - temperature, - seed, - image_generation_driver=None, **kwargs, ): prompt_model = kwargs.get("prompt_model", amazonBedrockPromptModels[0]) @@ -66,7 +61,6 @@ class gtUIAmazonBedrockStructureConfig(gtUIBaseConfig): "image_query_model", amazonBedrockImageQueryModels[0] ) temperature = kwargs.get("temperature", 0.7) - seed = kwargs.get("seed", 12341) image_generation_driver = kwargs.get("image_generation_driver", None) max_attempts = kwargs.get("max_attempts_on_fail", 10) diff --git a/nodes/config/anthropic_config.py b/nodes/config/AnthropicStructureConfig.py similarity index 90% rename from nodes/config/anthropic_config.py rename to nodes/config/AnthropicStructureConfig.py index 931775b..5d1a82c 100644 --- a/nodes/config/anthropic_config.py +++ b/nodes/config/AnthropicStructureConfig.py @@ -9,7 +9,7 @@ from griptape.drivers import ( DummyImageGenerationDriver, ) -from .base_config import gtUIBaseConfig +from .BaseConfig import gtUIBaseConfig anthropicPromptModels = [ "claude-3-5-sonnet-20240620", @@ -56,11 +56,6 @@ class gtUIAnthropicStructureConfig(gtUIBaseConfig): def create( self, - prompt_model, - image_query_model, - temperature, - seed, - image_generation_driver=DummyImageGenerationDriver(), **kwargs, ): prompt_model = kwargs.get("prompt_model", anthropicPromptModels[0]) @@ -68,7 +63,6 @@ class gtUIAnthropicStructureConfig(gtUIBaseConfig): "image_query_model", anthropicImageQueryModels[0] ) temperature = kwargs.get("temperature", 0.7) - seed = kwargs.get("seed", 12341) image_generation_driver = kwargs.get( "image_generation_driver", DummyImageGenerationDriver() ) diff --git a/nodes/config/azure_openai_config.py b/nodes/config/AzureOpenAiStructureConfig.py similarity index 98% rename from nodes/config/azure_openai_config.py rename to nodes/config/AzureOpenAiStructureConfig.py index 1b2068f..49fd620 100644 --- a/nodes/config/azure_openai_config.py +++ b/nodes/config/AzureOpenAiStructureConfig.py @@ -9,7 +9,7 @@ from griptape.drivers import ( ) from ...py.griptape_config import get_config -from .base_config import gtUIBaseConfig +from .BaseConfig import gtUIBaseConfig class gtUIAzureOpenAiStructureConfig(gtUIBaseConfig): diff --git a/nodes/config/base_config.py b/nodes/config/BaseConfig.py similarity index 100% rename from nodes/config/base_config.py rename to nodes/config/BaseConfig.py diff --git a/nodes/config/env_config.py b/nodes/config/EnvConfig.py similarity index 100% rename from nodes/config/env_config.py rename to nodes/config/EnvConfig.py diff --git a/nodes/config/google_config.py b/nodes/config/GoogleStructureConfig.py similarity index 95% rename from nodes/config/google_config.py rename to nodes/config/GoogleStructureConfig.py index a9fa0ed..28a103b 100644 --- a/nodes/config/google_config.py +++ b/nodes/config/GoogleStructureConfig.py @@ -8,7 +8,7 @@ from griptape.drivers import ( GooglePromptDriver, ) -from .base_config import gtUIBaseConfig +from .BaseConfig import gtUIBaseConfig google_models = [ "gemini-1.5-pro", @@ -45,7 +45,6 @@ class gtUIGoogleStructureConfig(gtUIBaseConfig): **kwargs, ): temperature = kwargs.get("temperature", 0.7) - seed = kwargs.get("seed", 12341) prompt_model = kwargs.get("prompt_model", google_models[0]) image_generation_driver = kwargs.get( "image_generation_driver", DummyImageGenerationDriver() diff --git a/nodes/config/huggingface_config.py b/nodes/config/HuggingFaceStructureConfig.py similarity index 97% rename from nodes/config/huggingface_config.py rename to nodes/config/HuggingFaceStructureConfig.py index adc7607..3ec703e 100644 --- a/nodes/config/huggingface_config.py +++ b/nodes/config/HuggingFaceStructureConfig.py @@ -10,7 +10,7 @@ from griptape.drivers import ( HuggingFaceHubPromptDriver, ) -from .base_config import gtUIBaseConfig +from .BaseConfig import gtUIBaseConfig load_dotenv() diff --git a/nodes/config/lmstudio_config.py b/nodes/config/LmStudioStructureConfig.py similarity index 96% rename from nodes/config/lmstudio_config.py rename to nodes/config/LmStudioStructureConfig.py index 0209294..6e5a5e0 100644 --- a/nodes/config/lmstudio_config.py +++ b/nodes/config/LmStudioStructureConfig.py @@ -9,7 +9,7 @@ from griptape.drivers import ( ) from ..utilities import get_lmstudio_models -from .base_config import gtUIBaseConfig +from .BaseConfig import gtUIBaseConfig lmstudio_models = get_lmstudio_models(port="1234") lmstudio_models.append("") @@ -50,7 +50,6 @@ class gtUILMStudioStructureConfig(gtUIBaseConfig): base_url = kwargs.get("base_url", lmstudio_base_url) port = kwargs.get("port", lmstudio_port) temperature = kwargs.get("temperature", 0.7) - seed = kwargs.get("seed", 12341) image_generation_driver = kwargs.get( "image_generation_driver", DummyImageGenerationDriver() ) diff --git a/nodes/config/ollama_config.py b/nodes/config/OllamaStructureConfig.py similarity index 95% rename from nodes/config/ollama_config.py rename to nodes/config/OllamaStructureConfig.py index 28bce94..4f377f2 100644 --- a/nodes/config/ollama_config.py +++ b/nodes/config/OllamaStructureConfig.py @@ -9,7 +9,7 @@ from griptape.drivers import ( ) from ..utilities import get_ollama_models -from .base_config import gtUIBaseConfig +from .BaseConfig import gtUIBaseConfig ollama_models = get_ollama_models() ollama_models.append("") @@ -44,7 +44,6 @@ class gtUIOllamaStructureConfig(gtUIBaseConfig): temperature = kwargs.get("temperature", 0.7) base_url = kwargs.get("base_url", ollama_base_url) port = kwargs.get("port", ollama_port) - seed = kwargs.get("seed", 12341) image_generation_driver = kwargs.get( "image_generation_driver", DummyImageGenerationDriver() diff --git a/nodes/config/openai_compatable_config.py b/nodes/config/OpenAiCompatableConfig.py similarity index 98% rename from nodes/config/openai_compatable_config.py rename to nodes/config/OpenAiCompatableConfig.py index fc83517..ae9c614 100644 --- a/nodes/config/openai_compatable_config.py +++ b/nodes/config/OpenAiCompatableConfig.py @@ -13,7 +13,7 @@ from griptape.drivers import ( OpenAiTextToSpeechDriver, ) -from .base_config import gtUIBaseConfig +from .BaseConfig import gtUIBaseConfig load_dotenv() diff --git a/nodes/config/openai_config.py b/nodes/config/OpenAiConfig.py similarity index 98% rename from nodes/config/openai_config.py rename to nodes/config/OpenAiConfig.py index 5fea4d6..1823cb7 100644 --- a/nodes/config/openai_config.py +++ b/nodes/config/OpenAiConfig.py @@ -11,7 +11,7 @@ from griptape.drivers import ( ) from ...py.griptape_config import get_config -from .base_config import gtUIBaseConfig +from .BaseConfig import gtUIBaseConfig default_prompt_model = "gpt-4o" default_image_query_model = "gpt-4o" diff --git a/nodes/convert/TextToClipEncode.py b/nodes/convert/TextToClipEncode.py new file mode 100644 index 0000000..1fc394f --- /dev/null +++ b/nodes/convert/TextToClipEncode.py @@ -0,0 +1,35 @@ +from ..tasks.BaseTask import gtUIBaseTask + + +class AnyType(str): + def __ne__(self, __value: object) -> bool: + return False + + +any = AnyType("*") + + +class gtUITextToClipEncode(gtUIBaseTask): + DESCRIPTION = "Convert text to a CLIP conditioning" + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "STRING": ("STRING", {"forceInput": True}), + "clip": ("CLIP",), + }, + } + + RETURN_TYPES = ("CONDITIONING",) + + FUNCTION = "run" + OUTPUT_NODE = True + + CATEGORY = "Griptape/Text" + FUNCTION = "encode" + + def encode(self, STRING, clip): + tokens = clip.tokenize(STRING) + cond, pooled = clip.encode_from_tokens(tokens, return_pooled=True) + return ([[cond, {"pooled_output": pooled}]],) diff --git a/nodes/convert/TextToCombo.py b/nodes/convert/TextToCombo.py new file mode 100644 index 0000000..8f87e7c --- /dev/null +++ b/nodes/convert/TextToCombo.py @@ -0,0 +1,30 @@ +class AnyType(str): + def __ne__(self, __value: object) -> bool: + return False + + +any = AnyType("*") + + +class gtUITextToCombo: + DESCRIPTION = "Convert text to a Combo conditioning" + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "STRING": ("STRING", {"forceInput": True}), + }, + } + + RETURN_TYPES = (any,) + RETURN_NAMES = ("combo",) + + FUNCTION = "run" + OUTPUT_NODE = True + + CATEGORY = "Griptape/Text" + FUNCTION = "convert" + + def convert(self, STRING): + return (STRING,) diff --git a/nodes/convert/__init__.py b/nodes/convert/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nodes/display/OutputArtifactNode.py b/nodes/display/OutputArtifactNode.py new file mode 100644 index 0000000..6f06b16 --- /dev/null +++ b/nodes/display/OutputArtifactNode.py @@ -0,0 +1,34 @@ +from griptape.artifacts import TextArtifact + + +class gtUIOutputArtifactNode: + CATEGORY = "Griptape/Display" + + @classmethod + def INPUT_TYPES(s): + return { + "required": {}, + "optional": {"INPUT": ("ARTIFACT", {"forceInput": True})}, + } + + RETURN_TYPES = ("ARTIFACT",) + RETURN_NAMES = ("OUTPUT",) + FUNCTION = "func" + OUTPUT_NODE = True + + def func(self, INPUT=None): + if INPUT: + input_type = type(INPUT) + if isinstance(INPUT, TextArtifact): + to_display = f"{repr(INPUT)}" + else: + to_display = f"{input_type=}" + return { + "ui": {"INPUT": str(to_display)}, # UI message for the frontend + "result": (INPUT,), + } + else: + return { + "ui": {"INPUT": ""}, + "result": ("",), + } diff --git a/nodes/display/OutputDataNode.py b/nodes/display/OutputDataNode.py new file mode 100644 index 0000000..4a41601 --- /dev/null +++ b/nodes/display/OutputDataNode.py @@ -0,0 +1,25 @@ +class gtUIOutputDataNode: + NAME = "Griptape Display: Data" + DESCRIPTION = "Display output data." + CATEGORY = "Griptape/Display" + + @classmethod + def INPUT_TYPES(s): + return {"required": {}, "optional": {"INPUT": ("*", {"forceInput": True})}} + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("OUTPUT",) + FUNCTION = "func" + OUTPUT_NODE = True + + def func(self, INPUT=None): + if INPUT: + return { + "ui": {"INPUT": str(INPUT)}, # UI message for the frontend + "result": (str(INPUT),), + } + else: + return { + "ui": {"INPUT": ""}, + "result": ("",), + } diff --git a/nodes/display/OutputImageNode.py b/nodes/display/OutputImageNode.py new file mode 100644 index 0000000..ce30c46 --- /dev/null +++ b/nodes/display/OutputImageNode.py @@ -0,0 +1,32 @@ +import random + +import folder_paths + +from .SaveImageNode import gtUISaveImageNode + + +# From PreviewImage +class gtUIOutputImageNode(gtUISaveImageNode): + DESCRIPTION = "Display image output." + + def __init__(self): + self.output_dir = folder_paths.get_temp_directory() + self.type = "temp" + self.prefix_append = "_temp_" + "".join( + random.choice("abcdefghijklmnopqrstupvxyz") for x in range(5) + ) + self.compress_level = 1 + + CATEGORY = "Griptape/Display" + + @classmethod + def INPUT_TYPES(s): + return { + "required": {}, + "optional": {"images": ("IMAGE", {"forceInput": True})}, + "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}, + } + + RETURN_TYPES = ("IMAGE",) + RETURN_NAMES = ("OUTPUT",) + OUTPUT_NODE = True diff --git a/nodes/display/OutputStringNode.py b/nodes/display/OutputStringNode.py new file mode 100644 index 0000000..7154d89 --- /dev/null +++ b/nodes/display/OutputStringNode.py @@ -0,0 +1,34 @@ +class gtUIOutputStringNode: + NAME = "Griptape Display: Text" + DESCRIPTION = "Display string output." + CATEGORY = "Griptape/Display" + + @classmethod + def INPUT_TYPES(s): + return { + "required": {}, + "optional": { + "INPUT": ("STRING", {"forceInput": True}), + "STRING": ("STRING", {"multiline": True}), + }, + } + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("OUTPUT",) + FUNCTION = "func" + OUTPUT_NODE = True + + def func(self, INPUT=None, STRING=None): + if INPUT is not None: + # Input is connected, use it's value + return { + "ui": {"INPUT": str(INPUT)}, # UI message for the frontend + "result": (str(INPUT),), + } + else: + return { + "ui": { + "STRING": str(STRING) if STRING is not None else "", + }, + "result": (str(STRING) if STRING is not None else "",), + } diff --git a/nodes/display/SaveImageNode.py b/nodes/display/SaveImageNode.py new file mode 100644 index 0000000..61bd4ad --- /dev/null +++ b/nodes/display/SaveImageNode.py @@ -0,0 +1,49 @@ +import json +import os + +import folder_paths +import numpy as np +from comfy.cli_args import args +from PIL import Image +from PIL.PngImagePlugin import PngInfo + +from nodes import SaveImage + + +# From SaveImage +class gtUISaveImageNode(SaveImage): + def save_images( + self, images, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None + ): + filename_prefix += self.prefix_append + full_output_folder, filename, counter, subfolder, filename_prefix = ( + folder_paths.get_save_image_path( + filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0] + ) + ) + results = list() + for batch_number, image in enumerate(images): + i = 255.0 * image.cpu().numpy() + img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8)) + metadata = None + if not args.disable_metadata: + metadata = PngInfo() + if prompt is not None: + metadata.add_text("prompt", json.dumps(prompt)) + if extra_pnginfo is not None: + for x in extra_pnginfo: + metadata.add_text(x, json.dumps(extra_pnginfo[x])) + + filename_with_batch_num = filename.replace("%batch_num%", str(batch_number)) + file = f"{filename_with_batch_num}_{counter:05}_.png" + img.save( + os.path.join(full_output_folder, file), + pnginfo=metadata, + compress_level=self.compress_level, + ) + results.append( + {"filename": file, "subfolder": subfolder, "type": self.type} + ) + counter += 1 + + return {"ui": {"images": results}, "result": (images,)} diff --git a/nodes/display/__init__.py b/nodes/display/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nodes/display_nodes.py b/nodes/display_nodes.py deleted file mode 100644 index 847582d..0000000 --- a/nodes/display_nodes.py +++ /dev/null @@ -1,174 +0,0 @@ -import json -import os -import random - -import folder_paths -import numpy as np -from comfy.cli_args import args -from griptape.artifacts import TextArtifact -from PIL import Image -from PIL.PngImagePlugin import PngInfo - -from nodes import SaveImage - - -class gtUIOutputArtifactNode: - CATEGORY = "Griptape/Display" - - @classmethod - def INPUT_TYPES(s): - return { - "required": {}, - "optional": {"INPUT": ("ARTIFACT", {"forceInput": True})}, - } - - RETURN_TYPES = ("ARTIFACT",) - RETURN_NAMES = ("OUTPUT",) - FUNCTION = "func" - OUTPUT_NODE = True - - def func(self, INPUT=None): - if INPUT: - input_type = type(INPUT) - if isinstance(INPUT, TextArtifact): - to_display = f"{repr(INPUT)}" - else: - to_display = f"{input_type=}" - return { - "ui": {"INPUT": str(to_display)}, # UI message for the frontend - "result": (INPUT,), - } - else: - return { - "ui": {"INPUT": ""}, - "result": ("",), - } - - -class gtUIOutputStringNode: - NAME = "Griptape Display: Text" - DESCRIPTION = "Display string output." - CATEGORY = "Griptape/Display" - - @classmethod - def INPUT_TYPES(s): - return { - "required": {}, - "optional": { - "INPUT": ("STRING", {"forceInput": True}), - "STRING": ("STRING", {"multiline": True}), - }, - } - - RETURN_TYPES = ("STRING",) - RETURN_NAMES = ("OUTPUT",) - FUNCTION = "func" - OUTPUT_NODE = True - - def func(self, INPUT=None, STRING=None): - if INPUT is not None: - # Input is connected, use it's value - return { - "ui": {"INPUT": str(INPUT)}, # UI message for the frontend - "result": (str(INPUT),), - } - else: - return { - "ui": { - "STRING": str(STRING) if STRING is not None else "", - }, - "result": (str(STRING) if STRING is not None else "",), - } - - -class gtUIOutputDataNode: - NAME = "Griptape Display: Data" - DESCRIPTION = "Display output data." - CATEGORY = "Griptape/Display" - - @classmethod - def INPUT_TYPES(s): - return {"required": {}, "optional": {"INPUT": ("*", {"forceInput": True})}} - - RETURN_TYPES = ("STRING",) - RETURN_NAMES = ("OUTPUT",) - FUNCTION = "func" - OUTPUT_NODE = True - - def func(self, INPUT=None): - if INPUT: - return { - "ui": {"INPUT": str(INPUT)}, # UI message for the frontend - "result": (str(INPUT),), - } - else: - return { - "ui": {"INPUT": ""}, - "result": ("",), - } - - -# From SaveImage -class gtUISaveImageNode(SaveImage): - def save_images( - self, images, filename_prefix="ComfyUI", prompt=None, extra_pnginfo=None - ): - filename_prefix += self.prefix_append - full_output_folder, filename, counter, subfolder, filename_prefix = ( - folder_paths.get_save_image_path( - filename_prefix, self.output_dir, images[0].shape[1], images[0].shape[0] - ) - ) - results = list() - for batch_number, image in enumerate(images): - i = 255.0 * image.cpu().numpy() - img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8)) - metadata = None - if not args.disable_metadata: - metadata = PngInfo() - if prompt is not None: - metadata.add_text("prompt", json.dumps(prompt)) - if extra_pnginfo is not None: - for x in extra_pnginfo: - metadata.add_text(x, json.dumps(extra_pnginfo[x])) - - filename_with_batch_num = filename.replace("%batch_num%", str(batch_number)) - file = f"{filename_with_batch_num}_{counter:05}_.png" - img.save( - os.path.join(full_output_folder, file), - pnginfo=metadata, - compress_level=self.compress_level, - ) - results.append( - {"filename": file, "subfolder": subfolder, "type": self.type} - ) - counter += 1 - - return {"ui": {"images": results}, "result": (images,)} - - -# From PreviewImage -class gtUIOutputImageNode(gtUISaveImageNode): - DESCRIPTION = "Display image output." - - def __init__(self): - self.output_dir = folder_paths.get_temp_directory() - self.type = "temp" - self.prefix_append = "_temp_" + "".join( - random.choice("abcdefghijklmnopqrstupvxyz") for x in range(5) - ) - self.compress_level = 1 - - CATEGORY = "Griptape/Display" - - @classmethod - def INPUT_TYPES(s): - return { - "required": {}, - "optional": {"images": ("IMAGE", {"forceInput": True})}, - "hidden": {"prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO"}, - } - - RETURN_TYPES = ("IMAGE",) - RETURN_NAMES = ("OUTPUT",) - OUTPUT_NODE = True diff --git a/nodes/drivers/AmazonBedrockStableDiffusionImageGenerationDriver.py b/nodes/drivers/AmazonBedrockStableDiffusionImageGenerationDriver.py new file mode 100644 index 0000000..8030471 --- /dev/null +++ b/nodes/drivers/AmazonBedrockStableDiffusionImageGenerationDriver.py @@ -0,0 +1,66 @@ +from griptape.drivers import ( + AmazonBedrockImageGenerationDriver, + BedrockStableDiffusionImageGenerationModelDriver, +) + +from .BaseImageDriver import gtUIBaseImageGenerationDriver + + +class gtUIAmazonBedrockStableDiffusionImageGenerationDriver( + gtUIBaseImageGenerationDriver +): + DESCRIPTION = "Amazon Bedrock Stable Diffusion Image Generation Driver" + + @classmethod + def INPUT_TYPES(s): + style_presets = [ + "", + "3d-model", + "analog-film", + "anime", + "cinematic", + "comic-book", + "digital-art", + "enhance", + "fantasy-art", + "isometric", + "line-art", + "low-poly", + "modeling-compound", + "neon-punk", + "origami", + "photographic", + "pixel-art", + "tile-texture", + ] + inputs = super().INPUT_TYPES() + inputs["optional"].update( + { + "style_preset": (style_presets, {"default": style_presets[4]}), + "width": ( + "INT", + {"default": 512, "min": 64, "max": 2048, "step": 64}, + ), + "height": ( + "INT", + {"default": 512, "min": 64, "max": 2048, "step": 64}, + ), + "seed": ("INT", {"default": 12345}), + } + ) + return inputs + + def create(self, style_preset, width, height, seed, prompt): + if style_preset == "": + style_preset = None + model_driver = BedrockStableDiffusionImageGenerationModelDriver( + style_preset=style_preset, + ) + driver = AmazonBedrockImageGenerationDriver( + image_generation_model_driver=model_driver, + model="stability.stable-diffusion-xl-v1", + image_width=width, + image_height=height, + seed=seed, + ) + return (driver,) diff --git a/nodes/drivers/AmazonBedrockTitanImageGenerationDriver.py b/nodes/drivers/AmazonBedrockTitanImageGenerationDriver.py new file mode 100644 index 0000000..abb8528 --- /dev/null +++ b/nodes/drivers/AmazonBedrockTitanImageGenerationDriver.py @@ -0,0 +1,34 @@ +from griptape.drivers import ( + AmazonBedrockImageGenerationDriver, + BedrockTitanImageGenerationModelDriver, +) + +from .BaseImageDriver import gtUIBaseImageGenerationDriver + + +class gtUIAmazonBedrockTitanImageGenerationDriver(gtUIBaseImageGenerationDriver): + DESCRIPTION = "Amazon Bedrock Titan Image Generation Driver" + + @classmethod + def INPUT_TYPES(s): + sizes = ["512x512", "1024x1024"] + inputs = super().INPUT_TYPES() + inputs["required"].update( + { + "size": (sizes, {"default": sizes[0]}), + "seed": ("INT", {"default": 10342349342}), + } + ) + return inputs + + def create(self, size, seed, prompt): + width, height = size.split("x") + model_driver = BedrockTitanImageGenerationModelDriver() + driver = AmazonBedrockImageGenerationDriver( + image_generation_model_driver=model_driver, + model="amazon.titan-image-generator-v1", + image_width=int(width), + image_height=int(height), + seed=seed, + ) + return (driver,) diff --git a/nodes/drivers/BaseAudioTranscriptionDriver.py b/nodes/drivers/BaseAudioTranscriptionDriver.py new file mode 100644 index 0000000..1c21ebc --- /dev/null +++ b/nodes/drivers/BaseAudioTranscriptionDriver.py @@ -0,0 +1,23 @@ +from griptape.drivers import OpenAiAudioTranscriptionDriver + + +class gtUIBaseAudioTranscriptionDriver: + @classmethod + def INPUT_TYPES(s): + return { + "required": {}, + "optional": {}, + } + + RETURN_TYPES = ("DRIVER",) + RETURN_NAMES = ("DRIVER",) + + FUNCTION = "create" + + CATEGORY = "Griptape/Audio Drivers" + + def create( + self, + ): + driver = OpenAiAudioTranscriptionDriver(model="whisper-1") + return (driver,) diff --git a/nodes/base_driver.py b/nodes/drivers/BaseImageDriver.py similarity index 52% rename from nodes/base_driver.py rename to nodes/drivers/BaseImageDriver.py index dce8b7d..9971f59 100644 --- a/nodes/base_driver.py +++ b/nodes/drivers/BaseImageDriver.py @@ -1,26 +1,4 @@ -from griptape.drivers import OpenAiAudioTranscriptionDriver, OpenAiImageGenerationDriver - - -class gtUIBaseAudioTranscriptionDriver: - @classmethod - def INPUT_TYPES(s): - return { - "required": {}, - "optional": {}, - } - - RETURN_TYPES = ("DRIVER",) - RETURN_NAMES = ("DRIVER",) - - FUNCTION = "create" - - CATEGORY = "Griptape/Audio Drivers" - - def create( - self, - ): - driver = OpenAiAudioTranscriptionDriver(model="whisper-1") - return (driver,) +from griptape.drivers import OpenAiImageGenerationDriver class gtUIBaseImageGenerationDriver: diff --git a/nodes/base_websearch_driver.py b/nodes/drivers/BaseWebSearchDriver.py similarity index 100% rename from nodes/base_websearch_driver.py rename to nodes/drivers/BaseWebSearchDriver.py diff --git a/nodes/drivers/DuckDuckGoWebSearchDriver.py b/nodes/drivers/DuckDuckGoWebSearchDriver.py new file mode 100644 index 0000000..80f23f8 --- /dev/null +++ b/nodes/drivers/DuckDuckGoWebSearchDriver.py @@ -0,0 +1,13 @@ +from griptape.drivers import DuckDuckGoWebSearchDriver + +from .BaseWebSearchDriver import gtUIBaseWebSearchDriver + + +class gtUIDuckDuckGoWebSearchDriver(gtUIBaseWebSearchDriver): + DESCRIPTION = "DuckDuckGo Web Search Driver" + + def create( + self, + ): + driver = DuckDuckGoWebSearchDriver() + return (driver,) diff --git a/nodes/websearch_drivers.py b/nodes/drivers/GoogleWebSearchDriver.py similarity index 79% rename from nodes/websearch_drivers.py rename to nodes/drivers/GoogleWebSearchDriver.py index 8003793..2d85344 100644 --- a/nodes/websearch_drivers.py +++ b/nodes/drivers/GoogleWebSearchDriver.py @@ -1,17 +1,7 @@ -from griptape.drivers import DuckDuckGoWebSearchDriver, GoogleWebSearchDriver +from griptape.drivers import GoogleWebSearchDriver -from ..py.griptape_config import get_config -from .base_websearch_driver import gtUIBaseWebSearchDriver - - -class gtUIDuckDuckGoWebSearchDriver(gtUIBaseWebSearchDriver): - DESCRIPTION = "DuckDuckGo Web Search Driver" - - def create( - self, - ): - driver = DuckDuckGoWebSearchDriver() - return (driver,) +from ...py.griptape_config import get_config +from .BaseWebSearchDriver import gtUIBaseWebSearchDriver class gtUIGoogleWebSearchDriver(gtUIBaseWebSearchDriver): diff --git a/nodes/drivers/LocalStructureRunDriver.py b/nodes/drivers/LocalStructureRunDriver.py new file mode 100644 index 0000000..2d2a8f2 --- /dev/null +++ b/nodes/drivers/LocalStructureRunDriver.py @@ -0,0 +1,34 @@ +from griptape.drivers import LocalStructureRunDriver + + +class gtUILocalStructureRunDriver: + def __init__(self): + pass + + DESCRIPTION = "Local Structure Run Driver" + + @classmethod + def INPUT_TYPES(s): + return { + "required": {}, + "optional": {"agent": ("AGENT", {"forceInput": True, "default": None})}, + } + + RETURN_TYPES = ("ARTIFACT",) + RETURN_NAMES = ("OUTPUT",) + + FUNCTION = "run" + OUTPUT_NODE = True + + CATEGORY = "Griptape/Agent Structures" + + def run( + self, + agent=None, + ): + if agent: + # Create a local structure function + driver = LocalStructureRunDriver(structure_factory_fn=lambda: agent) + return (driver,) + else: + return None diff --git a/nodes/drivers/LonardoImageGenerationDriver.py b/nodes/drivers/LonardoImageGenerationDriver.py new file mode 100644 index 0000000..021fe17 --- /dev/null +++ b/nodes/drivers/LonardoImageGenerationDriver.py @@ -0,0 +1,102 @@ +from griptape.drivers import ( + LeonardoImageGenerationDriver, +) + +from ...py.griptape_config import get_config +from .BaseImageDriver import gtUIBaseImageGenerationDriver + +leonardo_models = [ + { + "name": "default", + "model": "1e60896f-3c26-4296-8ecc-53e2afecc132", + "url": "https://app.leonardo.ai/models/1e60896f-3c26-4296-8ecc-53e2afecc132", + }, + { + "name": "Leonardo Anime XL", + "model": "e71a1c2f-4f80-4800-934f-2c68979d8cc8", + "url": "https://app.leonardo.ai/models/e71a1c2f-4f80-4800-934f-2c68979d8cc8", + }, + { + "name": "Leonardo Lightning XL", + "model": "b24e16ff-06e3-43eb-8d33-4416c2d75876", + "url": "https://app.leonardo.ai/models/b24e16ff-06e3-43eb-8d33-4416c2d75876", + }, + { + "name": "Leonardo Kino XL", + "model": "aa77f04e-3eec-4034-9c07-d0f619684628", + "url": "https://app.leonardo.ai/models/aa77f04e-3eec-4034-9c07-d0f619684628", + }, + { + "name": "SDXL 1.0", + "model": "16e7060a-803e-4df3-97ee-edcfa5dc9cc8", + "url": "https://app.leonardo.ai/models/16e7060a-803e-4df3-97ee-edcfa5dc9cc8", + }, + { + "name": "Leonardo Vision XL", + "model": "5c232a9e-9061-4777-980a-ddc8e65647c6", + "url": "https://app.leonardo.ai/models/5c232a9e-9061-4777-980a-ddc8e65647c6", + }, + { + "name": "AlbedoBase XL", + "model": "2067ae52-33fd-4a82-bb92-c2c55e7d2786", + }, + { + "name": "Retro illustrations", + "model": "133a8391-de9e-49e1-aee6-12d375cdef14", + "url": "https://app.leonardo.ai/models133a8391-de9e-49e1-aee6-12d375cdef14", + }, + { + "name": "mon prefere artiste", + "model": "bb18b23f-d86e-4280-9a0c-8e7c051e3daf", + "url": "https://app.leonardo.ai/models/bb18b23f-d86e-4280-9a0c-8e7c051e3daf", + }, + { + "name": "Watercolor sketch", + "model": "966002a0-9d71-42ca-922d-233a5781dd8c", + "url": "https://app.leonardo.ai/models/966002a0-9d71-42ca-922d-233a5781dd8c", + }, + { + "name": "ArchDwg", + "model": "cce5a67f-9f7c-48a7-baf7-bd32c55745f5", + "url": "https://app.leonardo.ai/models/cce5a67f-9f7c-48a7-baf7-bd32c55745f5", + }, +] + + +class gtUILeonardoImageGenerationDriver(gtUIBaseImageGenerationDriver): + DESCRIPTION = ( + "Leonardo.AI Image Generation Driver. Learn more at http://leonardo.ai" + ) + + @classmethod + def INPUT_TYPES(s): + models = [] + for model in leonardo_models: + models.append(model["name"]) + + inputs = super().INPUT_TYPES() + inputs["required"].update( + { + "model": (models, {"default": models[0]}), + "use_custom_model": ("BOOLEAN", {"default": False}), + "custom_model": ("STRING", {"default": ""}), + } + ) + return inputs + + def get_model_by_name(self, name): + for model in leonardo_models: + if model["name"] == name: + return model["model"] + return None + + def create(self, model, prompt, use_custom_model=False, custom_model=""): + if use_custom_model and custom_model != "": + m = custom_model + else: + m = self.get_model_by_name(model) + driver = LeonardoImageGenerationDriver( + api_key=get_config(key="env.LEONARDO_API_KEY", default=None), + model=m, + ) + return (driver,) diff --git a/nodes/audio_drivers.py b/nodes/drivers/OpenAiAudioTranscriptionDriver.py similarity index 90% rename from nodes/audio_drivers.py rename to nodes/drivers/OpenAiAudioTranscriptionDriver.py index 3bb7961..83fc195 100644 --- a/nodes/audio_drivers.py +++ b/nodes/drivers/OpenAiAudioTranscriptionDriver.py @@ -1,6 +1,6 @@ from griptape.drivers import OpenAiAudioTranscriptionDriver -from .base_driver import gtUIBaseAudioTranscriptionDriver +from .BaseAudioTranscriptionDriver import gtUIBaseAudioTranscriptionDriver openAiAudioTranscriptionModels = ["whisper-1"] diff --git a/nodes/drivers/OpenAiImageGenerationDriver.py b/nodes/drivers/OpenAiImageGenerationDriver.py new file mode 100644 index 0000000..2a595a9 --- /dev/null +++ b/nodes/drivers/OpenAiImageGenerationDriver.py @@ -0,0 +1,38 @@ +from griptape.drivers import ( + OpenAiImageGenerationDriver, +) + +from .BaseImageDriver import gtUIBaseImageGenerationDriver + + +class gtUIOpenAiImageGenerationDriver(gtUIBaseImageGenerationDriver): + DESCRIPTION = "OpenAI Image Generation Driver" + + @classmethod + def INPUT_TYPES(s): + models = ["dall-e-3", "dall-e-2"] + sizes = ["256x256", "512x512", "1024x1024", "1024x1792", "1792x1024"] + + inputs = super().INPUT_TYPES() + inputs["required"].update( + { + "model": (models, {"default": models[0]}), + "size": (sizes, {"default": sizes[2]}), + } + ) + return inputs + + def adjust_size_based_on_model(self, model, size): + # pick the approprite size based on the model + if model == "dall-e-2": + if size in ["1024x1792", "1792x1024"]: + size = "1024x1024" + if model == "dall-e-3": + if size in ["256x256", "512x512"]: + size = "1024x1024" + return size + + def create(self, model, size, prompt): + size = self.adjust_size_based_on_model(model, size) + driver = OpenAiImageGenerationDriver(model=model, image_size=size) + return (driver,) diff --git a/nodes/drivers/__init__.py b/nodes/drivers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nodes/image_drivers.py b/nodes/image_drivers.py deleted file mode 100644 index 0b29699..0000000 --- a/nodes/image_drivers.py +++ /dev/null @@ -1,227 +0,0 @@ -from griptape.drivers import ( - AmazonBedrockImageGenerationDriver, - BedrockStableDiffusionImageGenerationModelDriver, - BedrockTitanImageGenerationModelDriver, - LeonardoImageGenerationDriver, - OpenAiImageGenerationDriver, -) - -from ..py.griptape_config import get_config -from .base_driver import gtUIBaseImageGenerationDriver - -leonardo_models = [ - { - "name": "default", - "model": "1e60896f-3c26-4296-8ecc-53e2afecc132", - "url": "https://app.leonardo.ai/models/1e60896f-3c26-4296-8ecc-53e2afecc132", - }, - { - "name": "Leonardo Anime XL", - "model": "e71a1c2f-4f80-4800-934f-2c68979d8cc8", - "url": "https://app.leonardo.ai/models/e71a1c2f-4f80-4800-934f-2c68979d8cc8", - }, - { - "name": "Leonardo Lightning XL", - "model": "b24e16ff-06e3-43eb-8d33-4416c2d75876", - "url": "https://app.leonardo.ai/models/b24e16ff-06e3-43eb-8d33-4416c2d75876", - }, - { - "name": "Leonardo Kino XL", - "model": "aa77f04e-3eec-4034-9c07-d0f619684628", - "url": "https://app.leonardo.ai/models/aa77f04e-3eec-4034-9c07-d0f619684628", - }, - { - "name": "SDXL 1.0", - "model": "16e7060a-803e-4df3-97ee-edcfa5dc9cc8", - "url": "https://app.leonardo.ai/models/16e7060a-803e-4df3-97ee-edcfa5dc9cc8", - }, - { - "name": "Leonardo Vision XL", - "model": "5c232a9e-9061-4777-980a-ddc8e65647c6", - "url": "https://app.leonardo.ai/models/5c232a9e-9061-4777-980a-ddc8e65647c6", - }, - { - "name": "AlbedoBase XL", - "model": "2067ae52-33fd-4a82-bb92-c2c55e7d2786", - }, - { - "name": "Retro illustrations", - "model": "133a8391-de9e-49e1-aee6-12d375cdef14", - "url": "https://app.leonardo.ai/models133a8391-de9e-49e1-aee6-12d375cdef14", - }, - { - "name": "mon prefere artiste", - "model": "bb18b23f-d86e-4280-9a0c-8e7c051e3daf", - "url": "https://app.leonardo.ai/models/bb18b23f-d86e-4280-9a0c-8e7c051e3daf", - }, - { - "name": "Watercolor sketch", - "model": "966002a0-9d71-42ca-922d-233a5781dd8c", - "url": "https://app.leonardo.ai/models/966002a0-9d71-42ca-922d-233a5781dd8c", - }, - { - "name": "ArchDwg", - "model": "cce5a67f-9f7c-48a7-baf7-bd32c55745f5", - "url": "https://app.leonardo.ai/models/cce5a67f-9f7c-48a7-baf7-bd32c55745f5", - }, -] - - -class gtUIOpenAiImageGenerationDriver(gtUIBaseImageGenerationDriver): - DESCRIPTION = "OpenAI Image Generation Driver" - - @classmethod - def INPUT_TYPES(s): - models = ["dall-e-3", "dall-e-2"] - sizes = ["256x256", "512x512", "1024x1024", "1024x1792", "1792x1024"] - - inputs = super().INPUT_TYPES() - inputs["required"].update( - { - "model": (models, {"default": models[0]}), - "size": (sizes, {"default": sizes[2]}), - } - ) - return inputs - - def adjust_size_based_on_model(self, model, size): - # pick the approprite size based on the model - if model == "dall-e-2": - if size in ["1024x1792", "1792x1024"]: - size = "1024x1024" - if model == "dall-e-3": - if size in ["256x256", "512x512"]: - size = "1024x1024" - return size - - def create(self, model, size, prompt): - size = self.adjust_size_based_on_model(model, size) - driver = OpenAiImageGenerationDriver(model=model, image_size=size) - return (driver,) - - -class gtUILeonardoImageGenerationDriver(gtUIBaseImageGenerationDriver): - DESCRIPTION = ( - "Leonardo.AI Image Generation Driver. Learn more at http://leonardo.ai" - ) - - @classmethod - def INPUT_TYPES(s): - models = [] - for model in leonardo_models: - models.append(model["name"]) - - inputs = super().INPUT_TYPES() - inputs["required"].update( - { - "model": (models, {"default": models[0]}), - "use_custom_model": ("BOOLEAN", {"default": False}), - "custom_model": ("STRING", {"default": ""}), - } - ) - return inputs - - def get_model_by_name(self, name): - for model in leonardo_models: - if model["name"] == name: - return model["model"] - return None - - def create(self, model, prompt, use_custom_model=False, custom_model=""): - if use_custom_model and custom_model != "": - m = custom_model - else: - m = self.get_model_by_name(model) - driver = LeonardoImageGenerationDriver( - api_key=get_config(key="env.LEONARDO_API_KEY", default=None), - model=m, - ) - return (driver,) - - -class gtUIAmazonBedrockStableDiffusionImageGenerationDriver( - gtUIBaseImageGenerationDriver -): - DESCRIPTION = "Amazon Bedrock Stable Diffusion Image Generation Driver" - - @classmethod - def INPUT_TYPES(s): - style_presets = [ - "", - "3d-model", - "analog-film", - "anime", - "cinematic", - "comic-book", - "digital-art", - "enhance", - "fantasy-art", - "isometric", - "line-art", - "low-poly", - "modeling-compound", - "neon-punk", - "origami", - "photographic", - "pixel-art", - "tile-texture", - ] - inputs = super().INPUT_TYPES() - inputs["optional"].update( - { - "style_preset": (style_presets, {"default": style_presets[4]}), - "width": ( - "INT", - {"default": 512, "min": 64, "max": 2048, "step": 64}, - ), - "height": ( - "INT", - {"default": 512, "min": 64, "max": 2048, "step": 64}, - ), - "seed": ("INT", {"default": 12345}), - } - ) - return inputs - - def create(self, style_preset, width, height, seed, prompt): - if style_preset == "": - style_preset = None - model_driver = BedrockStableDiffusionImageGenerationModelDriver( - style_preset=style_preset, - ) - driver = AmazonBedrockImageGenerationDriver( - image_generation_model_driver=model_driver, - model="stability.stable-diffusion-xl-v1", - image_width=width, - image_height=height, - seed=seed, - ) - return (driver,) - - -class gtUIAmazonBedrockTitanImageGenerationDriver(gtUIBaseImageGenerationDriver): - DESCRIPTION = "Amazon Bedrock Titan Image Generation Driver" - - @classmethod - def INPUT_TYPES(s): - sizes = ["512x512", "1024x1024"] - inputs = super().INPUT_TYPES() - inputs["required"].update( - { - "size": (sizes, {"default": sizes[0]}), - "seed": ("INT", {"default": 10342349342}), - } - ) - return inputs - - def create(self, size, seed, prompt): - width, height = size.split("x") - model_driver = BedrockTitanImageGenerationModelDriver() - driver = AmazonBedrockImageGenerationDriver( - image_generation_model_driver=model_driver, - model="amazon.titan-image-generator-v1", - image_width=int(width), - image_height=int(height), - seed=seed, - ) - return (driver,) diff --git a/nodes/base_loader.py b/nodes/loaders/BaseLoader.py similarity index 100% rename from nodes/base_loader.py rename to nodes/loaders/BaseLoader.py diff --git a/nodes/image_nodes.py b/nodes/loaders/FetchImage.py similarity index 100% rename from nodes/image_nodes.py rename to nodes/loaders/FetchImage.py diff --git a/nodes/audio_nodes.py b/nodes/loaders/LoadAudio.py similarity index 100% rename from nodes/audio_nodes.py rename to nodes/loaders/LoadAudio.py diff --git a/nodes/loaders/__init__.py b/nodes/loaders/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nodes/rules.py b/nodes/rules/Rule.py similarity index 100% rename from nodes/rules.py rename to nodes/rules/Rule.py diff --git a/nodes/rules/__init__.py b/nodes/rules/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nodes/structure_nodes.py b/nodes/structure_nodes.py deleted file mode 100644 index c72bf59..0000000 --- a/nodes/structure_nodes.py +++ /dev/null @@ -1,229 +0,0 @@ -from random import randint - -from griptape.artifacts import AudioArtifact, ImageArtifact, TextArtifact -from griptape.structures import Pipeline -from griptape.tasks import PromptTask - -from .base_structure import gtUIBaseStructure -from .utilities import image_to_comfyui - - -class AnyType(str): - def __ne__(self, __value: object) -> bool: - return False - - -any = AnyType("*") - - -class gtUICreatePipeline(gtUIBaseStructure): - def __init__(self): - pass - - DESCRIPTION = "Create a Pipeline." - - @classmethod - def INPUT_TYPES(s): - inputs = super().INPUT_TYPES() - inputs["optional"].update({"task_1": ("TASK",)}) - del inputs["required"]["STRING"] - del inputs["optional"]["input_string"] - - return inputs - - RETURN_TYPES = ("STRUCTURE",) - RETURN_NAMES = ("STRUCTURE",) - - FUNCTION = "run" - OUTPUT_NODE = False - - @classmethod - def IS_CHANGED(s, int_field): - return randint(0, 1000) - - def run( - self, - **kwargs, - ): - tasks = [] - for i, (key, value) in enumerate(kwargs.items()): - if value is not None: - if i == 0: - # append " {{ args[0] }}" to the first task if it's not there. - tasks.append(value) - structure = Pipeline(tasks=tasks) - return (structure,) - - -class gtUIPipelineAddTask(gtUIBaseStructure): - DESCRIPTION = "Add a task to the end of a pipeline." - - @classmethod - def INPUT_TYPES(s): - inputs = super().INPUT_TYPES() - inputs["required"].update({"structure": ("STRUCTURE",)}) - inputs["optional"].update( - { - "task": ("TASK", {}), - "append_parent_output": ("BOOLEAN", {"default": True}), - } - ) - return inputs - - @classmethod - def IS_CHANGED(s, int_field): - return randint(0, 1000) - - RETURN_TYPES = ("STRUCTURE",) - RETURN_NAMES = ("STRUCTURE",) - - FUNCTION = "run" - # OUTPUT_NODE = Tru - - def run(self, **kwargs): - structure = kwargs.get("structure") - append_parent_output = kwargs.get("append_parent_output", True) - task = kwargs.get("task") - - if task: - if isinstance(task, PromptTask): - if append_parent_output: - prev_value = task.input.value - task = PromptTask( - "{{ prev_value}}\n\n{{ parent_output }}", - context={"prev_value": prev_value}, - ) - # print(task.input.value) - # print(type(task.input.value)) - - # task.prompt = task.prompt.value + "\n\n" + task.input.value - structure.add_task(task) - return (structure,) - - -class gtUIPipelineInsertTask(gtUIBaseStructure): - DESCRIPTION = "Insert a task into a pipeline." - - @classmethod - def INPUT_TYPES(s): - inputs = super().INPUT_TYPES() - inputs["required"].update({"structure": ("STRUCTURE",)}) - inputs["optional"].update( - { - "parent_task": ("TASK", {}), - "task": ("TASK", {}), - "append_parent_output": ("BOOLEAN", {"default": True}), - }, - ) - return inputs - - @classmethod - def IS_CHANGED(s, int_field): - return randint(0, 1000) - - RETURN_TYPES = ("STRUCTURE",) - RETURN_NAMES = ("STRUCTURE",) - - FUNCTION = "run" - # OUTPUT_NODE = True - - def run( - self, - **kwargs, - ): - structure = kwargs.get("structure") - parent_task = kwargs.get("parent_task") - task = kwargs.get("task") - append_parent_output = kwargs.get("append_parent_output", True) - - if task and parent_task: - if isinstance(task, PromptTask): - if append_parent_output: - prev_value = task.input.value - task = PromptTask( - "{{ prev_value}}\n\n{{ parent_output }}", - context={"prev_value": prev_value}, - ) - # print(task.input.value) - # print(type(task.input.value)) - - # task.prompt = task.prompt.value + "\n\n" + task.input.value - structure.insert_task(parent_task, task) - return (structure,) - - -class gtUIRunStructure(gtUIBaseStructure): - def __init__(self): - pass - - DESCRIPTION = "Run a Structure." - - @classmethod - def INPUT_TYPES(s): - inputs = super().INPUT_TYPES() - inputs["required"].update({"structure": ("STRUCTURE",)}) - inputs["optional"].update( - { - "STRING": ("STRING", {"default": "", "multiline": True}), - } - ) - return inputs - - RETURN_TYPES = ( - any, - "STRING", - "STRUCTURE", - ) - RETURN_NAMES = ( - "OUTPUT", - "TASK_OUTPUTS", - "STRUCTURE", - ) - - FUNCTION = "run" - OUTPUT_NODE = True - - def append_prompt_text(self, structure, prompt_text): - if prompt_text.strip() != "": - # Check and see if the first task has an input - if structure.tasks: - first_task = structure.tasks[0] - if isinstance(first_task.input, TextArtifact): - new_artifact = TextArtifact( - first_task.input.value + "\n\n {{ args[0] }}" - ) - first_task.input = new_artifact - structure.tasks[0] = first_task - - return structure - - def run(self, **kwargs): - STRING = kwargs.get("STRING", "") - structure = kwargs.get("structure") - input_string = kwargs.get("input_string", "") - - prompt_text = self.get_prompt_text(STRING, input_string) - - # If prompt_text isn't empty, we'll need to add it to the first task if we can. - structure = self.append_prompt_text(structure, prompt_text) - # Run the structure - result = structure.run(prompt_text) - - # Handle the results - task_outputs = repr( - [ - {"input": task.input.value, "output": task.output.value} - for task in structure.tasks - ] - ) - - # Depending on the type of output, we'll need to adjust it - if isinstance(result.output_task.output, str): - output = result.output_task.output - elif isinstance(result.output_task.output, TextArtifact): - output = result.output_task.output.value - elif isinstance(result.output_task.output, ImageArtifact): - output, output_mask = image_to_comfyui(result.output_task.output.value) - elif isinstance(result.output_task.output, AudioArtifact): - output = type(result.output_task.output) - return (output, task_outputs, structure) diff --git a/nodes/base_structure.py b/nodes/structures/BaseStructure.py similarity index 100% rename from nodes/base_structure.py rename to nodes/structures/BaseStructure.py diff --git a/nodes/structures/CreatePipeline.py b/nodes/structures/CreatePipeline.py new file mode 100644 index 0000000..ae6b655 --- /dev/null +++ b/nodes/structures/CreatePipeline.py @@ -0,0 +1,52 @@ +from random import randint + +from griptape.structures import Pipeline + +from .BaseStructure import gtUIBaseStructure + + +class AnyType(str): + def __ne__(self, __value: object) -> bool: + return False + + +any = AnyType("*") + + +class gtUICreatePipeline(gtUIBaseStructure): + def __init__(self): + pass + + DESCRIPTION = "Create a Pipeline." + + @classmethod + def INPUT_TYPES(s): + inputs = super().INPUT_TYPES() + inputs["optional"].update({"task_1": ("TASK",)}) + del inputs["required"]["STRING"] + del inputs["optional"]["input_string"] + + return inputs + + RETURN_TYPES = ("STRUCTURE",) + RETURN_NAMES = ("STRUCTURE",) + + FUNCTION = "run" + OUTPUT_NODE = False + + @classmethod + def IS_CHANGED(s, int_field): + return randint(0, 1000) + + def run( + self, + **kwargs, + ): + tasks = [] + for i, (key, value) in enumerate(kwargs.items()): + if value is not None: + if i == 0: + # append " {{ args[0] }}" to the first task if it's not there. + tasks.append(value) + structure = Pipeline(tasks=tasks) + return (structure,) diff --git a/nodes/structures/PipelineAddTask.py b/nodes/structures/PipelineAddTask.py new file mode 100644 index 0000000..85f8c7d --- /dev/null +++ b/nodes/structures/PipelineAddTask.py @@ -0,0 +1,59 @@ +from random import randint + +from griptape.tasks import PromptTask + +from .BaseStructure import gtUIBaseStructure + + +class AnyType(str): + def __ne__(self, __value: object) -> bool: + return False + + +any = AnyType("*") + + +class gtUIPipelineAddTask(gtUIBaseStructure): + DESCRIPTION = "Add a task to the end of a pipeline." + + @classmethod + def INPUT_TYPES(s): + inputs = super().INPUT_TYPES() + inputs["required"].update({"structure": ("STRUCTURE",)}) + inputs["optional"].update( + { + "task": ("TASK", {}), + "append_parent_output": ("BOOLEAN", {"default": True}), + } + ) + return inputs + + @classmethod + def IS_CHANGED(s, int_field): + return randint(0, 1000) + + RETURN_TYPES = ("STRUCTURE",) + RETURN_NAMES = ("STRUCTURE",) + + FUNCTION = "run" + # OUTPUT_NODE = Tru + + def run(self, **kwargs): + structure = kwargs.get("structure") + append_parent_output = kwargs.get("append_parent_output", True) + task = kwargs.get("task") + + if task: + if isinstance(task, PromptTask): + if append_parent_output: + prev_value = task.input.value + task = PromptTask( + "{{ prev_value}}\n\n{{ parent_output }}", + context={"prev_value": prev_value}, + ) + # print(task.input.value) + # print(type(task.input.value)) + + # task.prompt = task.prompt.value + "\n\n" + task.input.value + structure.add_task(task) + return (structure,) diff --git a/nodes/structures/PipelineInsertTask.py b/nodes/structures/PipelineInsertTask.py new file mode 100644 index 0000000..755a8be --- /dev/null +++ b/nodes/structures/PipelineInsertTask.py @@ -0,0 +1,64 @@ +from random import randint + +from griptape.tasks import PromptTask + +from .BaseStructure import gtUIBaseStructure + + +class AnyType(str): + def __ne__(self, __value: object) -> bool: + return False + + +any = AnyType("*") + + +class gtUIPipelineInsertTask(gtUIBaseStructure): + DESCRIPTION = "Insert a task into a pipeline." + + @classmethod + def INPUT_TYPES(s): + inputs = super().INPUT_TYPES() + inputs["required"].update({"structure": ("STRUCTURE",)}) + inputs["optional"].update( + { + "parent_task": ("TASK", {}), + "task": ("TASK", {}), + "append_parent_output": ("BOOLEAN", {"default": True}), + }, + ) + return inputs + + @classmethod + def IS_CHANGED(s, int_field): + return randint(0, 1000) + + RETURN_TYPES = ("STRUCTURE",) + RETURN_NAMES = ("STRUCTURE",) + + FUNCTION = "run" + # OUTPUT_NODE = True + + def run( + self, + **kwargs, + ): + structure = kwargs.get("structure") + parent_task = kwargs.get("parent_task") + task = kwargs.get("task") + append_parent_output = kwargs.get("append_parent_output", True) + + if task and parent_task: + if isinstance(task, PromptTask): + if append_parent_output: + prev_value = task.input.value + task = PromptTask( + "{{ prev_value}}\n\n{{ parent_output }}", + context={"prev_value": prev_value}, + ) + # print(task.input.value) + # print(type(task.input.value)) + + # task.prompt = task.prompt.value + "\n\n" + task.input.value + structure.insert_task(parent_task, task) + return (structure,) diff --git a/nodes/structures/RunStructure.py b/nodes/structures/RunStructure.py new file mode 100644 index 0000000..d5f5957 --- /dev/null +++ b/nodes/structures/RunStructure.py @@ -0,0 +1,89 @@ +from griptape.artifacts import AudioArtifact, ImageArtifact, TextArtifact + +from ..utilities import image_to_comfyui +from .BaseStructure import gtUIBaseStructure + + +class AnyType(str): + def __ne__(self, __value: object) -> bool: + return False + + +any = AnyType("*") + + +class gtUIRunStructure(gtUIBaseStructure): + def __init__(self): + pass + + DESCRIPTION = "Run a Structure." + + @classmethod + def INPUT_TYPES(s): + inputs = super().INPUT_TYPES() + inputs["required"].update({"structure": ("STRUCTURE",)}) + inputs["optional"].update( + { + "STRING": ("STRING", {"default": "", "multiline": True}), + } + ) + return inputs + + RETURN_TYPES = ( + any, + "STRING", + "STRUCTURE", + ) + RETURN_NAMES = ( + "OUTPUT", + "TASK_OUTPUTS", + "STRUCTURE", + ) + + FUNCTION = "run" + OUTPUT_NODE = True + + def append_prompt_text(self, structure, prompt_text): + if prompt_text.strip() != "": + # Check and see if the first task has an input + if structure.tasks: + first_task = structure.tasks[0] + if isinstance(first_task.input, TextArtifact): + new_artifact = TextArtifact( + first_task.input.value + "\n\n {{ args[0] }}" + ) + first_task.input = new_artifact + structure.tasks[0] = first_task + + return structure + + def run(self, **kwargs): + STRING = kwargs.get("STRING", "") + structure = kwargs.get("structure") + input_string = kwargs.get("input_string", "") + + prompt_text = self.get_prompt_text(STRING, input_string) + + # If prompt_text isn't empty, we'll need to add it to the first task if we can. + structure = self.append_prompt_text(structure, prompt_text) + # Run the structure + result = structure.run(prompt_text) + + # Handle the results + task_outputs = repr( + [ + {"input": task.input.value, "output": task.output.value} + for task in structure.tasks + ] + ) + + # Depending on the type of output, we'll need to adjust it + if isinstance(result.output_task.output, str): + output = result.output_task.output + elif isinstance(result.output_task.output, TextArtifact): + output = result.output_task.output.value + elif isinstance(result.output_task.output, ImageArtifact): + output, output_mask = image_to_comfyui(result.output_task.output.value) + elif isinstance(result.output_task.output, AudioArtifact): + output = type(result.output_task.output) + return (output, task_outputs, structure) diff --git a/nodes/structures/__init__.py b/nodes/structures/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nodes/tasks/audio_transcription_task.py b/nodes/tasks/AudioTranscriptionTask.py similarity index 98% rename from nodes/tasks/audio_transcription_task.py rename to nodes/tasks/AudioTranscriptionTask.py index 922e943..baeea8b 100644 --- a/nodes/tasks/audio_transcription_task.py +++ b/nodes/tasks/AudioTranscriptionTask.py @@ -15,7 +15,7 @@ from griptape.tasks import ( from griptape.utils import load_file from ...py.griptape_config import get_config -from ..base_audio_task import gtUIBaseAudioTask +from .BaseAudioTask import gtUIBaseAudioTask default_prompt = "{{ input_string }}" OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/base_audio_task.py b/nodes/tasks/BaseAudioTask.py similarity index 92% rename from nodes/base_audio_task.py rename to nodes/tasks/BaseAudioTask.py index 3c9fd7b..2287178 100644 --- a/nodes/base_audio_task.py +++ b/nodes/tasks/BaseAudioTask.py @@ -4,7 +4,7 @@ import tempfile import torchaudio from griptape.drivers import OpenAiAudioTranscriptionDriver -from .tasks.base_task import gtUIBaseTask +from .BaseTask import gtUIBaseTask class gtUIBaseAudioTask(gtUIBaseTask): @@ -56,8 +56,6 @@ class gtUIBaseAudioTask(gtUIBaseTask): return temp_files def run(self, **kwargs): - audio = kwargs.get("audio", None) - audio_filepath = kwargs.get("audio_filepath", None) driver = kwargs.get("driver", None) if not driver: diff --git a/nodes/base_image_task.py b/nodes/tasks/BaseImageTask.py similarity index 92% rename from nodes/base_image_task.py rename to nodes/tasks/BaseImageTask.py index a66180d..04df17c 100644 --- a/nodes/base_image_task.py +++ b/nodes/tasks/BaseImageTask.py @@ -1,4 +1,4 @@ -from .tasks.base_task import gtUIBaseTask +from .BaseTask import gtUIBaseTask class gtUIBaseImageTask(gtUIBaseTask): diff --git a/nodes/tasks/base_task.py b/nodes/tasks/BaseTask.py similarity index 100% rename from nodes/tasks/base_task.py rename to nodes/tasks/BaseTask.py diff --git a/nodes/tasks/csv_extraction_task.py b/nodes/tasks/CsvExtractionTask.py similarity index 98% rename from nodes/tasks/csv_extraction_task.py rename to nodes/tasks/CsvExtractionTask.py index 7a3f33d..7565a13 100644 --- a/nodes/tasks/csv_extraction_task.py +++ b/nodes/tasks/CsvExtractionTask.py @@ -4,7 +4,7 @@ from griptape.tasks import ( from ...py.griptape_config import get_config from ..agent.agent import gtComfyAgent as Agent -from .base_task import gtUIBaseTask +from .BaseTask import gtUIBaseTask OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/tasks/image_query_task.py b/nodes/tasks/ImageQueryTask.py similarity index 97% rename from nodes/tasks/image_query_task.py rename to nodes/tasks/ImageQueryTask.py index 3bf1cc3..e9d459a 100644 --- a/nodes/tasks/image_query_task.py +++ b/nodes/tasks/ImageQueryTask.py @@ -8,10 +8,10 @@ from griptape.loaders import ImageLoader from ...py.griptape_config import get_config from ..agent.agent import gtComfyAgent as Agent -from ..base_image_task import gtUIBaseImageTask from ..utilities import ( convert_tensor_to_base_64, ) +from .BaseImageTask import gtUIBaseImageTask default_prompt = "{{ input_string }}" OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/tasks/json_extraction_task.py b/nodes/tasks/JsonExtractionTask.py similarity index 98% rename from nodes/tasks/json_extraction_task.py rename to nodes/tasks/JsonExtractionTask.py index 4c8b98c..c445d1c 100644 --- a/nodes/tasks/json_extraction_task.py +++ b/nodes/tasks/JsonExtractionTask.py @@ -5,7 +5,7 @@ from schema import Schema from ...py.griptape_config import get_config from ..agent.agent import gtComfyAgent as Agent -from .base_task import gtUIBaseTask +from .BaseTask import gtUIBaseTask OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/tasks/parallel_image_query_task.py b/nodes/tasks/ParallelImageQueryTask.py similarity index 98% rename from nodes/tasks/parallel_image_query_task.py rename to nodes/tasks/ParallelImageQueryTask.py index 0e95051..7dafe1d 100644 --- a/nodes/tasks/parallel_image_query_task.py +++ b/nodes/tasks/ParallelImageQueryTask.py @@ -20,10 +20,10 @@ from griptape.tasks import ( from ...py.griptape_config import get_config from ..agent.agent import gtComfyAgent as Agent -from ..base_image_task import gtUIBaseImageTask from ..utilities import ( convert_tensor_to_base_64, ) +from .BaseImageTask import gtUIBaseImageTask default_prompt = "{{ input_string }}" OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/tasks/prompt_image_generation_task.py b/nodes/tasks/PromptImageGenerationTask.py similarity index 98% rename from nodes/tasks/prompt_image_generation_task.py rename to nodes/tasks/PromptImageGenerationTask.py index 9817a54..1e912c2 100644 --- a/nodes/tasks/prompt_image_generation_task.py +++ b/nodes/tasks/PromptImageGenerationTask.py @@ -17,7 +17,7 @@ from ..agent.agent import gtComfyAgent as Agent from ..utilities import ( image_path_to_output, ) -from .base_task import gtUIBaseTask +from .BaseTask import gtUIBaseTask default_prompt = "{{ input_string }}" OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/tasks/prompt_image_variation_task.py b/nodes/tasks/PromptImageVariationTask.py similarity index 98% rename from nodes/tasks/prompt_image_variation_task.py rename to nodes/tasks/PromptImageVariationTask.py index 8d468ce..59be29f 100644 --- a/nodes/tasks/prompt_image_variation_task.py +++ b/nodes/tasks/PromptImageVariationTask.py @@ -15,11 +15,11 @@ from griptape.tasks import ( from ...py.griptape_config import get_config from ..agent.agent import gtComfyAgent as Agent -from ..base_image_task import gtUIBaseImageTask from ..utilities import ( convert_tensor_to_base_64, image_path_to_output, ) +from .BaseImageTask import gtUIBaseImageTask default_prompt = "{{ input_string }}" OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/tasks/prompt_task.py b/nodes/tasks/PromptTask.py similarity index 83% rename from nodes/tasks/prompt_task.py rename to nodes/tasks/PromptTask.py index 7a45f43..988a240 100644 --- a/nodes/tasks/prompt_task.py +++ b/nodes/tasks/PromptTask.py @@ -1,5 +1,5 @@ from ...py.griptape_config import get_config -from .base_task import gtUIBaseTask +from .BaseTask import gtUIBaseTask default_prompt = "{{ input_string }}" OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/tasks/text_summary_task.py b/nodes/tasks/TextSummaryTask.py similarity index 96% rename from nodes/tasks/text_summary_task.py rename to nodes/tasks/TextSummaryTask.py index 9ebd815..9ab62b7 100644 --- a/nodes/tasks/text_summary_task.py +++ b/nodes/tasks/TextSummaryTask.py @@ -4,7 +4,7 @@ from griptape.tasks import ( from ...py.griptape_config import get_config from ..agent.agent import gtComfyAgent as Agent -from .base_task import gtUIBaseTask +from .BaseTask import gtUIBaseTask default_prompt = "{{ input_string }}" OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/tasks/tool_task.py b/nodes/tasks/ToolTask.py similarity index 98% rename from nodes/tasks/tool_task.py rename to nodes/tasks/ToolTask.py index 5605c53..1a528f2 100644 --- a/nodes/tasks/tool_task.py +++ b/nodes/tasks/ToolTask.py @@ -5,7 +5,7 @@ from griptape.tasks import ( from ...py.griptape_config import get_config from ..agent.agent import gtComfyAgent as Agent -from .base_task import gtUIBaseTask +from .BaseTask import gtUIBaseTask default_prompt = "{{ input_string }}" OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/tasks/toolkit_task.py b/nodes/tasks/ToolkitTask.py similarity index 97% rename from nodes/tasks/toolkit_task.py rename to nodes/tasks/ToolkitTask.py index 389ebf4..dc70168 100644 --- a/nodes/tasks/toolkit_task.py +++ b/nodes/tasks/ToolkitTask.py @@ -4,7 +4,7 @@ from griptape.tasks import ( from ...py.griptape_config import get_config from ..agent.agent import gtComfyAgent as Agent -from .base_task import gtUIBaseTask +from .BaseTask import gtUIBaseTask default_prompt = "{{ input_string }}" OPENAI_API_KEY = get_config("env.OPENAI_API_KEY") diff --git a/nodes/text/CLIPTextEncode.py b/nodes/text/CLIPTextEncode.py new file mode 100644 index 0000000..3180e15 --- /dev/null +++ b/nodes/text/CLIPTextEncode.py @@ -0,0 +1,31 @@ +from ..tasks.BaseTask import gtUIBaseTask + + +class AnyType(str): + def __ne__(self, __value: object) -> bool: + return False + + +any = AnyType("*") + + +class gtUICLIPTextEncode(gtUIBaseTask): + DESCRIPTION = "Create a text string and convert it to a CLIP conditioning." + + @classmethod + def INPUT_TYPES(s): + inputs = super().INPUT_TYPES() + inputs["optional"].update({"clip": ("CLIP",)}) + del inputs["optional"]["agent"] + return inputs + + RETURN_TYPES = ("CONDITIONING",) + FUNCTION = "encode" + + CATEGORY = "Griptape/Text" + + def encode(self, STRING, clip, input_string=None): + prompt_text = self.get_prompt_text(STRING, input_string) + tokens = clip.tokenize(prompt_text) + cond, pooled = clip.encode_from_tokens(tokens, return_pooled=True) + return ([[cond, {"pooled_output": pooled}]],) diff --git a/nodes/text/InputStringNode.py b/nodes/text/InputStringNode.py new file mode 100644 index 0000000..aad4fed --- /dev/null +++ b/nodes/text/InputStringNode.py @@ -0,0 +1,34 @@ +class AnyType(str): + def __ne__(self, __value: object) -> bool: + return False + + +any = AnyType("*") + + +class gtUIInputStringNode: + NAME = "Griptape Create: Text" + DESCRIPTION = "Create a text string" + + def __init__(self): + pass + + @classmethod + def INPUT_TYPES(s): + return { + "required": {}, + "optional": { + "STRING": ("STRING", {"multiline": True, "dynamicPrompts": True}) + }, + } + + RETURN_TYPES = ("STRING",) + RETURN_NAMES = ("OUTPUT",) + + FUNCTION = "run" + OUTPUT_NODE = True + + CATEGORY = "Griptape/Text" + + def run(self, STRING): + return (STRING,) diff --git a/nodes/text/__init__.py b/nodes/text/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nodes/text_nodes.py b/nodes/text_nodes.py deleted file mode 100644 index 320b807..0000000 --- a/nodes/text_nodes.py +++ /dev/null @@ -1,109 +0,0 @@ -from .tasks.base_task import gtUIBaseTask - - -class AnyType(str): - def __ne__(self, __value: object) -> bool: - return False - - -any = AnyType("*") - - -class gtUIInputStringNode: - NAME = "Griptape Create: Text" - DESCRIPTION = "Create a text string" - - def __init__(self): - pass - - @classmethod - def INPUT_TYPES(s): - return { - "required": {}, - "optional": { - "STRING": ("STRING", {"multiline": True, "dynamicPrompts": True}) - }, - } - - RETURN_TYPES = ("STRING",) - RETURN_NAMES = ("OUTPUT",) - - FUNCTION = "run" - OUTPUT_NODE = True - - CATEGORY = "Griptape/Text" - - def run(self, STRING): - return (STRING,) - - -class gtUITextToCombo: - DESCRIPTION = "Convert text to a Combo conditioning" - - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "STRING": ("STRING", {"forceInput": True}), - }, - } - - RETURN_TYPES = (any,) - RETURN_NAMES = ("combo",) - - FUNCTION = "run" - OUTPUT_NODE = True - - CATEGORY = "Griptape/Text" - FUNCTION = "convert" - - def convert(self, STRING): - return (STRING,) - - -class gtUITextToClipEncode(gtUIBaseTask): - DESCRIPTION = "Convert text to a CLIP conditioning" - - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "STRING": ("STRING", {"forceInput": True}), - "clip": ("CLIP",), - }, - } - - RETURN_TYPES = ("CONDITIONING",) - - FUNCTION = "run" - OUTPUT_NODE = True - - CATEGORY = "Griptape/Text" - FUNCTION = "encode" - - def encode(self, STRING, clip): - tokens = clip.tokenize(STRING) - cond, pooled = clip.encode_from_tokens(tokens, return_pooled=True) - return ([[cond, {"pooled_output": pooled}]],) - - -class gtUICLIPTextEncode(gtUIBaseTask): - DESCRIPTION = "Create a text string and convert it to a CLIP conditioning." - - @classmethod - def INPUT_TYPES(s): - inputs = super().INPUT_TYPES() - inputs["optional"].update({"clip": ("CLIP",)}) - del inputs["optional"]["agent"] - return inputs - - RETURN_TYPES = ("CONDITIONING",) - FUNCTION = "encode" - - CATEGORY = "Griptape/Text" - - def encode(self, STRING, clip, input_string=None): - prompt_text = self.get_prompt_text(STRING, input_string) - tokens = clip.tokenize(prompt_text) - cond, pooled = clip.encode_from_tokens(tokens, return_pooled=True) - return ([[cond, {"pooled_output": pooled}]],) diff --git a/nodes/tools.py b/nodes/tools.py deleted file mode 100644 index aea496b..0000000 --- a/nodes/tools.py +++ /dev/null @@ -1,205 +0,0 @@ -import requests -from griptape.drivers import DuckDuckGoWebSearchDriver, OpenAiAudioTranscriptionDriver -from griptape.engines import AudioTranscriptionEngine -from griptape.tools import ( - Calculator, - DateTime, - FileManager, - GriptapeCloudKnowledgeBaseClient, - WebScraper, - WebSearch, -) -from griptape.tools.audio_transcription_client.tool import AudioTranscriptionClient - -from ..py.griptape_config import get_config -from .base_tool import gtUIBaseTool - - -class gtUIAudioTranscriptionClient(gtUIBaseTool): - """ - Griptape AudioTranscriptionClient Tool - """ - - DESCRIPTION = "Transcribe audio to text" - - @classmethod - def INPUT_TYPES(s): - # inputs = super().INPUT_TYPES() - # inputs["optional"].update({"driver": ("DRIVER",)}) - # return inputs - - return { - "required": {"off_prompt": ("BOOLEAN", {"default": True})}, - "optional": {"driver": ("DRIVER", {"default": None})}, - } - - def create(self, off_prompt, driver=None): - if not driver: - driver = OpenAiAudioTranscriptionDriver(model="whisper-1") - - tool = AudioTranscriptionClient( - off_prompt=off_prompt, - engine=AudioTranscriptionEngine( - audio_transcription_driver=driver, - ), - ) - - return ([tool],) - - -class gtUIFileManager(gtUIBaseTool): - """ - The Griptape File Manager Tool - """ - - DESCRIPTION = "Access files on disk." - - @classmethod - def INPUT_TYPES(s): - return { - "required": {"off_prompt": ("BOOLEAN", {"default": True})}, - } - - def create(self, off_prompt, workdir=""): - tool = FileManager(off_prompt=off_prompt) - return ([tool],) - - -class gtUICalculator(gtUIBaseTool): - """ - The Griptape Calculator Tool - """ - - DESCRIPTION = "Perform calculations." - - def create(self, off_prompt): - tool = Calculator(off_prompt=off_prompt) - return ([tool],) - - -class gtUIWebSearch(gtUIBaseTool): - """ - The Griptape Web Search Tool - """ - - DESCRIPTION = "Search the web." - - @classmethod - def INPUT_TYPES(s): - inputs = super().INPUT_TYPES() - inputs["optional"].update( - { - "driver": ("DRIVER", {"default": None}), - } - ) - return inputs - - def create(self, off_prompt, driver=None): - if not driver: - driver = DuckDuckGoWebSearchDriver() - tool = WebSearch( - web_search_driver=driver, - off_prompt=off_prompt, - ) - return ([tool],) - - -# class gtUIImageQueryClient(gtUIBaseTool): -# """ -# The Griptape Image Query Tool -# """ - -# def create(self, off_prompt): -# tool = ImageQueryClient(off_prompt=off_prompt) -# return ([tool],) - - -class gtUIWebScraper(gtUIBaseTool): - """ - The Griptape WebScraper Tool - """ - - DESCRIPTION = "Scrape the web for information." - - def create(self, off_prompt): - tool = WebScraper( - off_prompt=off_prompt, - ) - return ([tool],) - - -class gtUIDateTime(gtUIBaseTool): - """ - The Griptape DateTime Tool - """ - - DESCRIPTION = "Get the current date and time." - - def create(self, off_prompt): - tool = DateTime(off_prompt=off_prompt) - return ([tool],) - - -class gtUIKnowledgeBaseTool(gtUIBaseTool): - """ - The Griptape Knowledge Base Tool - """ - - DESCRIPTION = "Access a Griptape Cloud Knowledge Base. Learn more at https://cloud.griptape.ai" - - @classmethod - def INPUT_TYPES(s): - return { - "required": { - "off_prompt": ("BOOLEAN", {"default": False}), - "api_key_environment_variable": ( - "STRING", - {"default": "GRIPTAPE_API_KEY"}, - ), - "base_url": ("STRING", {"default": "https://cloud.griptape.ai"}), - "knowledge_base_id": ("STRING", {"default": ""}), - }, - } - - def getKnowledgeBaseInfo(self, api_key, base_url, knowledge_base_id): - headers = { - "Authorization": f"Bearer {api_key}", - } - try: - response = requests.get( - f"{base_url}/api/knowledge-bases/{knowledge_base_id}", headers=headers - ) - except requests.exceptions.RequestException as e: - print(e) - return - # Check if the request was successful - if response.status_code == 200: - # Parse the JSON response - data = response.json() - return data - else: - print(f"Failed to get knowledge base info: {response.status_code}") - - def create( - self, - off_prompt, - api_key_environment_variable, - base_url, - knowledge_base_id, - ): - api_key = get_config(f"env.{api_key_environment_variable}") - - # Use the Griptape API to grab the name and description of the knowledge base - data = self.getKnowledgeBaseInfo(api_key, base_url, knowledge_base_id) - name = data.get("name", "Griptape Knowledge Base") - description = data.get("description", "Contains helpful information") - - tool = GriptapeCloudKnowledgeBaseClient( - name=name, - description=description, - off_prompt=off_prompt, - api_key=api_key, - base_url=base_url, - knowledge_base_id=knowledge_base_id, - ) - return ([tool],) diff --git a/nodes/tools/AudioTranscriptionClient.py b/nodes/tools/AudioTranscriptionClient.py new file mode 100644 index 0000000..549ddde --- /dev/null +++ b/nodes/tools/AudioTranscriptionClient.py @@ -0,0 +1,37 @@ +from griptape.drivers import OpenAiAudioTranscriptionDriver +from griptape.engines import AudioTranscriptionEngine +from griptape.tools.audio_transcription_client.tool import AudioTranscriptionClient + +from .BaseTool import gtUIBaseTool + + +class gtUIAudioTranscriptionClient(gtUIBaseTool): + """ + Griptape AudioTranscriptionClient Tool + """ + + DESCRIPTION = "Transcribe audio to text" + + @classmethod + def INPUT_TYPES(s): + # inputs = super().INPUT_TYPES() + # inputs["optional"].update({"driver": ("DRIVER",)}) + # return inputs + + return { + "required": {"off_prompt": ("BOOLEAN", {"default": True})}, + "optional": {"driver": ("DRIVER", {"default": None})}, + } + + def create(self, off_prompt, driver=None): + if not driver: + driver = OpenAiAudioTranscriptionDriver(model="whisper-1") + + tool = AudioTranscriptionClient( + off_prompt=off_prompt, + engine=AudioTranscriptionEngine( + audio_transcription_driver=driver, + ), + ) + + return ([tool],) diff --git a/nodes/base_tool.py b/nodes/tools/BaseTool.py similarity index 100% rename from nodes/base_tool.py rename to nodes/tools/BaseTool.py diff --git a/nodes/tools/Calculator.py b/nodes/tools/Calculator.py new file mode 100644 index 0000000..d1860e5 --- /dev/null +++ b/nodes/tools/Calculator.py @@ -0,0 +1,17 @@ +from griptape.tools import ( + Calculator, +) + +from .BaseTool import gtUIBaseTool + + +class gtUICalculator(gtUIBaseTool): + """ + The Griptape Calculator Tool + """ + + DESCRIPTION = "Perform calculations." + + def create(self, off_prompt): + tool = Calculator(off_prompt=off_prompt) + return ([tool],) diff --git a/nodes/agent/convert_agent_to_tool.py b/nodes/tools/ConvertAgentToTool.py similarity index 64% rename from nodes/agent/convert_agent_to_tool.py rename to nodes/tools/ConvertAgentToTool.py index 58a899f..705f855 100644 --- a/nodes/agent/convert_agent_to_tool.py +++ b/nodes/tools/ConvertAgentToTool.py @@ -1,40 +1,7 @@ from griptape.drivers import LocalStructureRunDriver from griptape.tools import StructureRunClient -from ..base_tool import gtUIBaseTool - - -class gtUILocalStructureRunDriver: - def __init__(self): - pass - - DESCRIPTION = "Local Structure Run Driver" - - @classmethod - def INPUT_TYPES(s): - return { - "required": {}, - "optional": {"agent": ("AGENT", {"forceInput": True, "default": None})}, - } - - RETURN_TYPES = ("ARTIFACT",) - RETURN_NAMES = ("OUTPUT",) - - FUNCTION = "run" - OUTPUT_NODE = True - - CATEGORY = "Griptape/Agent Structures" - - def run( - self, - agent=None, - ): - if agent: - # Create a local structure function - driver = LocalStructureRunDriver(structure_factory_fn=lambda: agent) - return (driver,) - else: - return None +from .BaseTool import gtUIBaseTool class gtUIConvertAgentToTool(gtUIBaseTool): diff --git a/nodes/tools/DateTime.py b/nodes/tools/DateTime.py new file mode 100644 index 0000000..1590ea1 --- /dev/null +++ b/nodes/tools/DateTime.py @@ -0,0 +1,17 @@ +from griptape.tools import ( + DateTime, +) + +from .BaseTool import gtUIBaseTool + + +class gtUIDateTime(gtUIBaseTool): + """ + The Griptape DateTime Tool + """ + + DESCRIPTION = "Get the current date and time." + + def create(self, off_prompt): + tool = DateTime(off_prompt=off_prompt) + return ([tool],) diff --git a/nodes/tools/FileManager.py b/nodes/tools/FileManager.py new file mode 100644 index 0000000..7a9073a --- /dev/null +++ b/nodes/tools/FileManager.py @@ -0,0 +1,23 @@ +from griptape.tools import ( + FileManager, +) + +from .BaseTool import gtUIBaseTool + + +class gtUIFileManager(gtUIBaseTool): + """ + The Griptape File Manager Tool + """ + + DESCRIPTION = "Access files on disk." + + @classmethod + def INPUT_TYPES(s): + return { + "required": {"off_prompt": ("BOOLEAN", {"default": True})}, + } + + def create(self, off_prompt, workdir=""): + tool = FileManager(off_prompt=off_prompt) + return ([tool],) diff --git a/nodes/tools/KnowledgeBaseTool.py b/nodes/tools/KnowledgeBaseTool.py new file mode 100644 index 0000000..9bd04d6 --- /dev/null +++ b/nodes/tools/KnowledgeBaseTool.py @@ -0,0 +1,72 @@ +import requests +from griptape.tools import ( + GriptapeCloudKnowledgeBaseClient, +) + +from ...py.griptape_config import get_config +from .BaseTool import gtUIBaseTool + + +class gtUIKnowledgeBaseTool(gtUIBaseTool): + """ + The Griptape Knowledge Base Tool + """ + + DESCRIPTION = "Access a Griptape Cloud Knowledge Base. Learn more at https://cloud.griptape.ai" + + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "off_prompt": ("BOOLEAN", {"default": False}), + "api_key_environment_variable": ( + "STRING", + {"default": "GRIPTAPE_API_KEY"}, + ), + "base_url": ("STRING", {"default": "https://cloud.griptape.ai"}), + "knowledge_base_id": ("STRING", {"default": ""}), + }, + } + + def getKnowledgeBaseInfo(self, api_key, base_url, knowledge_base_id): + headers = { + "Authorization": f"Bearer {api_key}", + } + try: + response = requests.get( + f"{base_url}/api/knowledge-bases/{knowledge_base_id}", headers=headers + ) + except requests.exceptions.RequestException as e: + print(e) + return + # Check if the request was successful + if response.status_code == 200: + # Parse the JSON response + data = response.json() + return data + else: + print(f"Failed to get knowledge base info: {response.status_code}") + + def create( + self, + off_prompt, + api_key_environment_variable, + base_url, + knowledge_base_id, + ): + api_key = get_config(f"env.{api_key_environment_variable}") + + # Use the Griptape API to grab the name and description of the knowledge base + data = self.getKnowledgeBaseInfo(api_key, base_url, knowledge_base_id) + name = data.get("name", "Griptape Knowledge Base") + description = data.get("description", "Contains helpful information") + + tool = GriptapeCloudKnowledgeBaseClient( + name=name, + description=description, + off_prompt=off_prompt, + api_key=api_key, + base_url=base_url, + knowledge_base_id=knowledge_base_id, + ) + return ([tool],) diff --git a/nodes/tools/WebScraper.py b/nodes/tools/WebScraper.py new file mode 100644 index 0000000..3e2da4f --- /dev/null +++ b/nodes/tools/WebScraper.py @@ -0,0 +1,19 @@ +from griptape.tools import ( + WebScraper, +) + +from .BaseTool import gtUIBaseTool + + +class gtUIWebScraper(gtUIBaseTool): + """ + The Griptape WebScraper Tool + """ + + DESCRIPTION = "Scrape the web for information." + + def create(self, off_prompt): + tool = WebScraper( + off_prompt=off_prompt, + ) + return ([tool],) diff --git a/nodes/tools/WebSearch.py b/nodes/tools/WebSearch.py new file mode 100644 index 0000000..e69f202 --- /dev/null +++ b/nodes/tools/WebSearch.py @@ -0,0 +1,33 @@ +from griptape.drivers import DuckDuckGoWebSearchDriver +from griptape.tools import ( + WebSearch, +) + +from .BaseTool import gtUIBaseTool + + +class gtUIWebSearch(gtUIBaseTool): + """ + The Griptape Web Search Tool + """ + + DESCRIPTION = "Search the web." + + @classmethod + def INPUT_TYPES(s): + inputs = super().INPUT_TYPES() + inputs["optional"].update( + { + "driver": ("DRIVER", {"default": None}), + } + ) + return inputs + + def create(self, off_prompt, driver=None): + if not driver: + driver = DuckDuckGoWebSearchDriver() + tool = WebSearch( + web_search_driver=driver, + off_prompt=off_prompt, + ) + return ([tool],) diff --git a/nodes/tools/__init__.py b/nodes/tools/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nodes/utilities.py b/nodes/utilities.py index 67a2022..9b43c90 100644 --- a/nodes/utilities.py +++ b/nodes/utilities.py @@ -129,36 +129,6 @@ def convert_tensor_batch_to_base_64(image_batch): return None -# def convert_tensor_to_base_64(image): -# if isinstance(image, torch.Tensor): -# # Convert to base64 -# print("Converting to base64") - -# # Ensure it's on CPU and remove batch dimension if there's one -# if image.dim() == 4 and image.shape[0] == 1: -# image = image.squeeze(0) # Removes batch dimension if it's 1 - -# # Permute the dimensions if necessary (from C, H, W to H, W, C) -# if image.shape[0] < image.shape[2]: # Assuming channel-first ordering -# image = image.permute(1, 2, 0) # Change to (Height, Width, Channels) - -# # Scale to 0-255 and convert to uint8 -# image = (255.0 * image).clamp(0, 255).numpy().astype(np.uint8) - -# # Create PIL Image from array -# img = Image.fromarray(image) - -# # Save the image to a buffer -# buffer = BytesIO() -# img.save(buffer, format="PNG") - - -# # Encode to base64 -# final_image = base64.b64encode(buffer.getvalue()).decode("utf-8") -# print("Base64 Conversion Successful") -# return final_image -# else: -# return None def convert_tensor_to_base_64(image): if not isinstance(image, torch.Tensor): raise TypeError("Input must be a PyTorch tensor")