From bdfcb679235e09297eb137f151bad3df0e5abfce Mon Sep 17 00:00:00 2001 From: Jason Schleifer Date: Wed, 26 Feb 2025 08:57:30 +1300 Subject: [PATCH] ### Added - `GriptapeCloudPromptDriver` and `GriptapeCloudDriversConfig`. These nodes allow you to use your Griptape Cloud API key to run OpenAI `gpt-4o`. We'll be adding more models soon - but you no longer need a separate Griptape Cloud API key and OpenAI API key to run a simple agent! - `GrokPromptDriver` and `GrokDriversConfig`. These nodes allow you to use Grok to run their latest chat and vision models. You will require a `GROK_API_KEY` available at https://console.x.ai. ### Changed - `Griptape Display: Text` now displays Markdown properly to make output look nicer. --- CHANGELOG.md | 7 ++ __init__.py | 10 ++ js/apiKeyButtons.js | 1 + js/griptape_api_keys.js | 1 + .../config/gtUIGriptapeCloudDriversConfig.py | 68 +++++++++++++ nodes/config/gtUIGrokDriversConfig.py | 68 +++++++++++++ nodes/display/gtUIOutputStringNode.py | 2 +- .../drivers/gtUIGriptapeCloudPromptDriver.py | 96 +++++++++++++++++++ nodes/drivers/gtUIGrokPromptDriver.py | 96 +++++++++++++++++++ pyproject.toml | 8 +- requirements.txt | 2 +- 11 files changed, 353 insertions(+), 6 deletions(-) create mode 100644 nodes/config/gtUIGriptapeCloudDriversConfig.py create mode 100644 nodes/config/gtUIGrokDriversConfig.py create mode 100644 nodes/drivers/gtUIGriptapeCloudPromptDriver.py create mode 100644 nodes/drivers/gtUIGrokPromptDriver.py diff --git a/CHANGELOG.md b/CHANGELOG.md index f6f4936..4795736 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed ### Security --> +## [2.2.08] - 2025-25-02 +### Added +- `GriptapeCloudPromptDriver` and `GriptapeCloudDriversConfig`. These nodes allow you to use your Griptape Cloud API key to run OpenAI `gpt-4o`. We'll be adding more models soon - but you no longer need a separate Griptape Cloud API key and OpenAI API key to run a simple agent! +- `GrokPromptDriver` and `GrokDriversConfig`. These nodes allow you to use Grok to run their latest chat and vision models. You will require a `GROK_API_KEY` available at https://console.x.ai. +### Changed +- `Griptape Display: Text` now displays Markdown properly to make output look nicer. + ## [2.2.07] - 2025-25-02 ### Added - Added `Workflow` nodes for a `Start Workflow` and `End Workflow`. These nodes are the start of being able to drive a ComfyUI Workflow externally, giving the user specific properties they can set and specific output results when they're done. This is just getting started and there is nothing specific available to use the feature, but wanted to get it checked in. diff --git a/__init__.py b/__init__.py index 23b47c7..1c92f18 100644 --- a/__init__.py +++ b/__init__.py @@ -53,6 +53,8 @@ from .nodes.config.gtUIAzureOpenAiDriversConfig import gtUIAzureOpenAiDriversCon from .nodes.config.gtUICohereDriversConfig import gtUICohereDriversConfig from .nodes.config.gtUIEnvConfig import gtUIEnvConfig from .nodes.config.gtUIGoogleDriversConfig import gtUIGoogleDriversConfig +from .nodes.config.gtUIGriptapeCloudDriversConfig import gtUIGriptapeCloudDriversConfig +from .nodes.config.gtUIGrokDriversConfig import gtUIGrokDriversConfig from .nodes.config.gtUIGroqDriversConfig import gtUIGroqDriversConfig from .nodes.config.gtUIHuggingFaceDriversConfig import gtUIHuggingFaceDriversConfig from .nodes.config.gtUILMStudioDriversConfig import gtUILMStudioDriversConfig @@ -142,11 +144,15 @@ from .nodes.drivers.gtUIExaWebSearchDriver import gtUIExaWebSearchDriver from .nodes.drivers.gtUIGoogleEmbeddingDriver import gtUIGoogleEmbeddingDriver from .nodes.drivers.gtUIGooglePromptDriver import gtUIGooglePromptDriver from .nodes.drivers.gtUIGoogleWebSearchDriver import gtUIGoogleWebSearchDriver +from .nodes.drivers.gtUIGriptapeCloudPromptDriver import gtUIGriptapeCloudPromptDriver # - Griptape from .nodes.drivers.gtUIGriptapeCloudVectorStoreDriver import ( gtUIGriptapeCloudVectorStoreDriver, ) + +# - Grok +from .nodes.drivers.gtUIGrokPromptDriver import gtUIGrokPromptDriver from .nodes.drivers.gtUIGroqAudioTranscriptionDriver import ( gtUIGroqAudioTranscriptionDriver, ) @@ -346,7 +352,9 @@ NODE_CLASS_MAPPINGS = { "Griptape Agent Config: Anthropic Drivers": gtUIAnthropicDriversConfig, "Griptape Agent Config: Azure OpenAI Drivers": gtUIAzureOpenAiDriversConfig, "Griptape Agent Config: Cohere Drivers": gtUICohereDriversConfig, + "Griptape Agent Config: Griptape Cloud": gtUIGriptapeCloudDriversConfig, "Griptape Agent Config: Google Drivers": gtUIGoogleDriversConfig, + "Griptape Agent Config: Grok Drivers": gtUIGrokDriversConfig, "Griptape Agent Config: Groq Drivers": gtUIGroqDriversConfig, "Griptape Agent Config: HuggingFace Drivers": gtUIHuggingFaceDriversConfig, "Griptape Agent Config: LM Studio Drivers": gtUILMStudioDriversConfig, @@ -369,8 +377,10 @@ NODE_CLASS_MAPPINGS = { "Griptape Prompt Driver: Anthropic": gtUIAnthropicPromptDriver, "Griptape Prompt Driver: Azure OpenAI": gtUIAzureOpenAiChatPromptDriver, "Griptape Prompt Driver: Cohere": gtUICoherePromptDriver, + "Griptape Prompt Driver: Grok": gtUIGrokPromptDriver, "Griptape Prompt Driver: Groq": gtUIGroqChatPromptDriver, "Griptape Prompt Driver: Google": gtUIGooglePromptDriver, + "Griptape Prompt Driver: Griptape Cloud": gtUIGriptapeCloudPromptDriver, "Griptape Prompt Driver: HuggingFace": gtUIHuggingFaceHubPromptDriver, "Griptape Prompt Driver: LM Studio": gtUILMStudioChatPromptDriver, "Griptape Prompt Driver: Ollama": gtUIOllamaPromptDriver, diff --git a/js/apiKeyButtons.js b/js/apiKeyButtons.js index bf3ea87..7eec0c1 100644 --- a/js/apiKeyButtons.js +++ b/js/apiKeyButtons.js @@ -14,6 +14,7 @@ const API_PROVIDERS = { ElevenLabs: { url: "https://elevenlabs.io/app/settings/api-keys" }, Google: { url: "https://console.cloud.google.com/apis/credentials" }, LeonardoAI: { url: "https://app.leonardo.ai/api-access" }, + Grok: { url: "https://console.x.ai" }, Groq: { url: "https://console.groq.com/keys" }, Serper: { url: "https://serper.dev/api-key" }, OpenAI: { url: "https://platform.openai.com/account/api-keys" }, diff --git a/js/griptape_api_keys.js b/js/griptape_api_keys.js index 995cd28..5d9da2e 100644 --- a/js/griptape_api_keys.js +++ b/js/griptape_api_keys.js @@ -20,6 +20,7 @@ export const keys_organized = { Cohere: ["COHERE_API_KEY"], "Eleven Labs": ["ELEVEN_LABS_API_KEY"], Exa: ["EXA_API_KEY"], + Grok: ["GROK_API_KEY"], Groq: ["GROQ_API_KEY"], Google: ["GOOGLE_API_KEY", "GOOGLE_API_SEARCH_ID"], Huggingface: ["HUGGINGFACE_HUB_ACCESS_TOKEN"], diff --git a/nodes/config/gtUIGriptapeCloudDriversConfig.py b/nodes/config/gtUIGriptapeCloudDriversConfig.py new file mode 100644 index 0000000..5f91a8a --- /dev/null +++ b/nodes/config/gtUIGriptapeCloudDriversConfig.py @@ -0,0 +1,68 @@ +# pyright: reportMissingImports=false +import logging + +from comfy_execution.graph import ExecutionBlocker +from griptape.configs import Defaults +from griptape.configs.drivers import ( + DriversConfig, +) + +# StructureGlobalDriversConfig, +from griptape.drivers.prompt.griptape_cloud import GriptapeCloudPromptDriver + +from ..drivers.gtUIGriptapeCloudPromptDriver import gtUIGriptapeCloudPromptDriver +from .gtUIBaseDriversConfig import ( + add_optional_inputs, + add_required_inputs, + gtUIBaseDriversConfig, +) + +drivers = [ + ("prompt", gtUIGriptapeCloudPromptDriver), +] + + +class gtUIGriptapeCloudDriversConfig(gtUIBaseDriversConfig): + """ + The Griptape Cloud Structure Config + """ + + DESCRIPTION = "Griptape Cloud Driver Configs. Griptape Cloud requires a GT_CLOUD_API_KEY available at https://cloud.griptape.ai" + + @classmethod + def INPUT_TYPES(cls): + inputs = super().INPUT_TYPES() + + inputs["optional"] = {} + + inputs = add_required_inputs(inputs, drivers) + inputs = add_optional_inputs(inputs, drivers) + + return inputs + + def create(self, **kwargs): + drivers_config_params = {} + + try: + # Create instances of the driver classes + prompt_driver_builder = gtUIGriptapeCloudPromptDriver() + + # Build parameters for drivers + prompt_driver_params = prompt_driver_builder.build_params(**kwargs) + if "model" not in prompt_driver_params: + custom_config = ExecutionBlocker( + "Please provide a model for the prompt driver." + ) + return (custom_config,) + + # Create Driver Configs + drivers_config_params["prompt_driver"] = GriptapeCloudPromptDriver( + **prompt_driver_params + ) + Defaults.drivers_config = DriversConfig(**drivers_config_params) + custom_config = Defaults.drivers_config + except Exception as e: + custom_config = ExecutionBlocker(f"{e}") + logging.error(e) + + return (custom_config,) diff --git a/nodes/config/gtUIGrokDriversConfig.py b/nodes/config/gtUIGrokDriversConfig.py new file mode 100644 index 0000000..fb41553 --- /dev/null +++ b/nodes/config/gtUIGrokDriversConfig.py @@ -0,0 +1,68 @@ +# pyright: reportMissingImports=false +import logging + +from comfy_execution.graph import ExecutionBlocker +from griptape.configs import Defaults +from griptape.configs.drivers import ( + DriversConfig, +) + +# StructureGlobalDriversConfig, +from griptape.drivers.prompt.grok import GrokPromptDriver + +from ..drivers.gtUIGrokPromptDriver import gtUIGrokPromptDriver +from .gtUIBaseDriversConfig import ( + add_optional_inputs, + add_required_inputs, + gtUIBaseDriversConfig, +) + +drivers = [ + ("prompt", gtUIGrokPromptDriver), +] + + +class gtUIGrokDriversConfig(gtUIBaseDriversConfig): + """ + The Grok Structure Config + """ + + DESCRIPTION = "Grok Cloud Driver Configs. Grok requires a GROK_API_KEY available at https://console.x.ai" + + @classmethod + def INPUT_TYPES(cls): + inputs = super().INPUT_TYPES() + + inputs["optional"] = {} + + inputs = add_required_inputs(inputs, drivers) + inputs = add_optional_inputs(inputs, drivers) + + return inputs + + def create(self, **kwargs): + drivers_config_params = {} + + try: + # Create instances of the driver classes + prompt_driver_builder = gtUIGrokPromptDriver() + + # Build parameters for drivers + prompt_driver_params = prompt_driver_builder.build_params(**kwargs) + if "model" not in prompt_driver_params: + custom_config = ExecutionBlocker( + "Please provide a model for the prompt driver." + ) + return (custom_config,) + + # Create Driver Configs + drivers_config_params["prompt_driver"] = GrokPromptDriver( + **prompt_driver_params + ) + Defaults.drivers_config = DriversConfig(**drivers_config_params) + custom_config = Defaults.drivers_config + except Exception as e: + custom_config = ExecutionBlocker(f"{e}") + logging.error(e) + + return (custom_config,) diff --git a/nodes/display/gtUIOutputStringNode.py b/nodes/display/gtUIOutputStringNode.py index 7bf408f..433dd39 100644 --- a/nodes/display/gtUIOutputStringNode.py +++ b/nodes/display/gtUIOutputStringNode.py @@ -9,7 +9,7 @@ class gtUIOutputStringNode: "required": {}, "optional": { "INPUT": ("STRING", {"forceInput": True, "multiline": True}), - "STRING": ("STRING", {"multiline": True}), + "STRING": ("MARKDOWN", {"multiline": True}), }, } diff --git a/nodes/drivers/gtUIGriptapeCloudPromptDriver.py b/nodes/drivers/gtUIGriptapeCloudPromptDriver.py new file mode 100644 index 0000000..8d8edd7 --- /dev/null +++ b/nodes/drivers/gtUIGriptapeCloudPromptDriver.py @@ -0,0 +1,96 @@ +from griptape.drivers.prompt.griptape_cloud import GriptapeCloudPromptDriver + +from .gtUIBasePromptDriver import gtUIBasePromptDriver + +# models = get_available_models("ChatModel") + +DEFAULT_MODEL = "gpt-4o" +DEFAULT_API_KEY = "GT_CLOUD_API_KEY" + +models = ["gpt-4o"] + + +class gtUIGriptapeCloudPromptDriver(gtUIBasePromptDriver): + @classmethod + def INPUT_TYPES(cls): + inputs = super().INPUT_TYPES() + + # Get the base required and optional inputs + base_required_inputs = inputs["required"] + base_optional_inputs = inputs["optional"] + + # Clear the required and optional inputs + inputs["required"] = {} + inputs["optional"] = {} + + # Add the base required inputs to the inputs + inputs["required"].update(base_required_inputs) + + # Add the optional inputs + inputs["optional"].update(base_optional_inputs) + + # Set model default + inputs["optional"]["model"] = (models, {"default": DEFAULT_MODEL}) + inputs["optional"].update( + { + "response_format": ( + ["default", "json_object"], + {"default": "default", "tooltip": "Format of the response"}, + ), + "api_key_env_var": ( + "STRING", + { + "default": DEFAULT_API_KEY, + "tooltip": "Enter the environment variable name, not the actual API key", + }, + ), + } + ) + + return inputs + + FUNCTION = "create" + + def build_params(self, **kwargs): + api_key = self.getenv(kwargs.get("api_key_env_var", DEFAULT_API_KEY)) + model = kwargs.get("model", DEFAULT_MODEL) + response_format = kwargs.get("response_format", None) + seed = kwargs.get("seed", None) + stream = kwargs.get("stream", False) + temperature = kwargs.get("temperature", None) + max_attempts = kwargs.get("max_attempts_on_fail", None) + use_native_tools = kwargs.get("use_native_tools", False) + max_tokens = kwargs.get("max_tokens", None) + params = {} + params["extra_params"] = {} + + if api_key: + params["api_key"] = api_key + if model: + params["model"] = model + if response_format == "json_object": + response_format = {"type": "json_object"} + params["response_format"] = response_format + if seed: + params["extra_params"]["seed"] = seed + if stream: + params["stream"] = stream + if temperature: + params["temperature"] = temperature + if max_attempts: + params["max_attempts"] = max_attempts + if use_native_tools: + params["use_native_tools"] = use_native_tools + if max_tokens > 0: + params["max_tokens"] = max_tokens + + return params + + def create(self, **kwargs): + params = self.build_params(**kwargs) + try: + driver = GriptapeCloudPromptDriver(**params) + return (driver,) + except Exception as e: + print(f"Error creating driver: {e}") + return (None, str(e)) diff --git a/nodes/drivers/gtUIGrokPromptDriver.py b/nodes/drivers/gtUIGrokPromptDriver.py new file mode 100644 index 0000000..02bce12 --- /dev/null +++ b/nodes/drivers/gtUIGrokPromptDriver.py @@ -0,0 +1,96 @@ +from griptape.drivers.prompt.grok import GrokPromptDriver + +from .gtUIBasePromptDriver import gtUIBasePromptDriver + +# models = get_available_models("ChatModel") + +DEFAULT_MODEL = "grok-beta" +DEFAULT_API_KEY = "GROK_API_KEY" + +models = ["grok-beta", "grok-vision-beta", "grok-2-latest", "grok-2-vision-latest"] + + +class gtUIGrokPromptDriver(gtUIBasePromptDriver): + @classmethod + def INPUT_TYPES(cls): + inputs = super().INPUT_TYPES() + + # Get the base required and optional inputs + base_required_inputs = inputs["required"] + base_optional_inputs = inputs["optional"] + + # Clear the required and optional inputs + inputs["required"] = {} + inputs["optional"] = {} + + # Add the base required inputs to the inputs + inputs["required"].update(base_required_inputs) + + # Add the optional inputs + inputs["optional"].update(base_optional_inputs) + + # Set model default + inputs["optional"]["model"] = (models, {"default": DEFAULT_MODEL}) + inputs["optional"].update( + { + "response_format": ( + ["default", "json_object"], + {"default": "default", "tooltip": "Format of the response"}, + ), + "api_key_env_var": ( + "STRING", + { + "default": DEFAULT_API_KEY, + "tooltip": "Enter the environment variable name, not the actual API key", + }, + ), + } + ) + + return inputs + + FUNCTION = "create" + + def build_params(self, **kwargs): + api_key = self.getenv(kwargs.get("api_key_env_var", DEFAULT_API_KEY)) + model = kwargs.get("model", DEFAULT_MODEL) + response_format = kwargs.get("response_format", None) + seed = kwargs.get("seed", None) + stream = kwargs.get("stream", False) + temperature = kwargs.get("temperature", None) + max_attempts = kwargs.get("max_attempts_on_fail", None) + use_native_tools = kwargs.get("use_native_tools", False) + max_tokens = kwargs.get("max_tokens", None) + params = {} + params["extra_params"] = {} + + if api_key: + params["api_key"] = api_key + if model: + params["model"] = model + if response_format == "json_object": + response_format = {"type": "json_object"} + params["response_format"] = response_format + if seed: + params["extra_params"]["seed"] = seed + if stream: + params["stream"] = stream + if temperature: + params["temperature"] = temperature + if max_attempts: + params["max_attempts"] = max_attempts + if use_native_tools: + params["use_native_tools"] = use_native_tools + if max_tokens > 0: + params["max_tokens"] = max_tokens + + return params + + def create(self, **kwargs): + params = self.build_params(**kwargs) + try: + driver = GrokPromptDriver(**params) + return (driver,) + except Exception as e: + print(f"Error creating driver: {e}") + return (None, str(e)) diff --git a/pyproject.toml b/pyproject.toml index 576a99e..e966484 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "comfyui-griptape" -version = "2.2.07" +version = "2.2.08" description = "Griptape LLM(Large Language Model) Nodes for ComfyUI." authors = ["Jason Schleifer "] readme = "README.md" @@ -9,9 +9,9 @@ readme = "README.md" [project] name = "comfyui-griptape" description = "Griptape LLM(Large Language Model) Nodes for ComfyUI." -version = "2.2.07" +version = "2.2.08" license = {file = "LICENSE"} -dependencies = ["attrs>=24.3.0,<26.0.0", "openai>=1.58.1,<2.0.0", "griptape[all]>=1.3.1", "python-dotenv", "poetry==1.8.5", "griptape-black-forest @ git+https://github.com/griptape-ai/griptape-black-forest.git", "griptape_serper_driver_extension @ git+https://github.com/mertdeveci5/griptape-serper-driver-extension.git"] +dependencies = ["attrs>=24.3.0,<26.0.0", "openai>=1.58.1,<2.0.0", "griptape[all]>=1.4.0", "python-dotenv", "poetry==1.8.5", "griptape-black-forest @ git+https://github.com/griptape-ai/griptape-black-forest.git", "griptape_serper_driver_extension @ git+https://github.com/mertdeveci5/griptape-serper-driver-extension.git"] [project.urls] Repository = "https://github.com/griptape-ai/ComfyUI-Griptape" @@ -21,7 +21,7 @@ Repository = "https://github.com/griptape-ai/ComfyUI-Griptape" python = "^3.11" python-dotenv = "^1.0.1" attrs = ">=24.3.0,<26.0.0" -griptape = { version = "^1.3.1", extras = ["all"]} +griptape = { version = "^1.4.0", extras = ["all"]} griptape-black-forest = {git = "https://github.com/griptape-ai/griptape-black-forest.git"} griptape_serper_driver_extension = {git = "https://github.com/mertdeveci5/griptape-serper-driver-extension.git"} [tool.poetry.group.dev] diff --git a/requirements.txt b/requirements.txt index 09d728d..67168de 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ attrs>=25.1.0 openai>=1.58.1 -griptape[all]>=1.3.1 +griptape[all]>=1.4.0 python-dotenv poetry==1.8.5 git+https://github.com/griptape-ai/griptape-black-forest.git