@@ -2,14 +2,16 @@
|
||||
|
||||
This repo creates a series of nodes that enable you to utilize the [Griptape Python Framework](https://github.com/griptape-ai/griptape/) with [ComfyUI](https://github.com/comfyanonymous/ComfyUI), integrating LLMs (Large Language Models) and AI into your workflow.
|
||||
|
||||
This example creates two [Griptape Agents](https://docs.griptape.ai/stable/griptape-framework/structures/agents/) - a Writer and an Editor. The writer has a [WebScraper](https://docs.griptape.ai/stable/griptape-tools/official-tools/web-scraper/) tool and gets a description of a website. It then generates blog topic ideas and passes them to_ the Editor Agent. The editor chooses the top 3 topics, and generates outlines and next actions for the next two. A third Agent generates thumbnail images for each blog post using a [Prompt Image Generation Task](https://docs.griptape.ai/stable/griptape-framework/structures/tasks/#prompt-image-generation-task) based on the outlines.
|
||||
### Instructions and tutorials
|
||||
|
||||

|
||||
Watch the trailer and all the instructional videos on our [YouTube Playlist](https://www.youtube.com/playlist?list=PLZRzNKLLiEyeK9VN-i53sUU1v5vBLl-nG).
|
||||
|
||||
[](https://www.youtube.com/playlist?list=PLZRzNKLLiEyeK9VN-i53sUU1v5vBLl-nG)
|
||||
|
||||
The repo currently has a subset of Griptape nodes, with more to come soon. Current nodes can:
|
||||
|
||||
* Create [Agents](https://docs.griptape.ai/stable/griptape-framework/structures/agents/) using these models:
|
||||
* Local - via Ollama
|
||||
* Local - via **Ollama** and **LM Studio**
|
||||
* Llama 3
|
||||
* Mistral
|
||||
* etc..
|
||||
@@ -58,10 +60,16 @@ In this example, we're using three `Image Description` nodes to describe the giv
|
||||
4. Griptape Tools - Featuring Task Memory and Off-Prompt: https://youtu.be/TvEbv0vTZ5Q
|
||||
5. Griptape Rulesets, and Image Creation: https://youtu.be/DK16ouQ_vSs
|
||||
6. Image Generation with multiple drivers: https://youtu.be/Y4vxJmAZcho
|
||||
7. Image Description, Parallel Image Description: https://youtu.be/OgYKIluSWWs?si=JUNxhvGohYM0YQaK
|
||||
8. Audio Transcription: https://youtu.be/P4GVmm122B0?si=24b9c4v1LWk_n80T
|
||||
9. Using Ollama as a Configuration Driver: https://youtu.be/jIq_TL5xmX0?si=ilfomN6Ka1G4hIEp
|
||||
10. Combining Rulesets: https://youtu.be/3LDdiLwexp8?si=Oeb6ApEUTqIz6J6O
|
||||
11. Integrating Text: https://youtu.be/_TVr2zZORnA?si=c6tN4pCEE3Qp0sBI
|
||||
12. New Nodes & Quality of life improvements: https://youtu.be/M2YBxCfyPVo?si=pj3AFAhl2Tjpd_hw
|
||||
13. Merge Input Data: https://youtu.be/wQ9lKaGWmZo?si=FgboU5iUg82pXRkC
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
#### 1. ComfyUI
|
||||
|
||||
Install [ComfyUI](https://github.com/comfyanonymous/ComfyUI) using the [instructions](https://github.com/comfyanonymous/ComfyUI?tab=readme-ov-file#installing) for your particular operating system.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 454 KiB |
@@ -600,6 +600,96 @@ app.registerExtension({
|
||||
this?.graph?.setDirtyCanvas(true, true);
|
||||
};
|
||||
};
|
||||
|
||||
// Combine: Merge Texts
|
||||
if ( nodeData.name === "Griptape Combine: Merge Texts" ||
|
||||
nodeData.name === "Griptape Combine: Merge Inputs" ||
|
||||
nodeData.name === "Griptape Combine: Rules List" ||
|
||||
nodeData.name === "Griptape Combine: Tool List") {
|
||||
|
||||
// Set the base name of the input node
|
||||
var input_name = "input_";
|
||||
|
||||
switch (nodeData.name) {
|
||||
case 'Griptape Combine: Rules List':
|
||||
input_name = "rules_";
|
||||
break;
|
||||
case 'Griptape Combine: Tool List':
|
||||
input_name = "tool_";
|
||||
break;
|
||||
}
|
||||
|
||||
const onConnectionsChange = nodeType.prototype.onConnectionsChange;
|
||||
nodeType.prototype.onConnectionsChange = function (type, index, connected, link_info) {
|
||||
if(!link_info)
|
||||
return;
|
||||
|
||||
if(type==1) {
|
||||
const node = app.graph.getNodeById(link_info.origin_id);
|
||||
let origin_type = node.outputs[link_info.origin_slot].type;
|
||||
|
||||
if(origin_type == '*') {
|
||||
this.disconnectInput(link_info.target_slot);
|
||||
}
|
||||
|
||||
for(let i in this.inputs) {
|
||||
let input_i = this.inputs[i];
|
||||
for(let i in this.inputs) {
|
||||
let input_i = this.inputs[i];
|
||||
if(input_i.name != 'select' && input_i.name != 'sel_mode')
|
||||
input_i.type = origin_type;
|
||||
}
|
||||
|
||||
this.outputs[0].type = origin_type;
|
||||
this.outputs[0].label = origin_type;
|
||||
this.outputs[0].name = origin_type;
|
||||
}
|
||||
}
|
||||
|
||||
let select_slot = this.inputs.find(x => x.name == "select");
|
||||
let mode_slot = this.inputs.find(x => x.name == "sel_mode");
|
||||
|
||||
let converted_count = 0;
|
||||
converted_count += select_slot?1:0;
|
||||
converted_count += mode_slot?1:0;
|
||||
|
||||
if (!connected && (this.inputs.length > 1+converted_count)) {
|
||||
const stackTrace = new Error().stack;
|
||||
|
||||
if(
|
||||
!stackTrace.includes('LGraphNode.prototype.connect') && // for touch device
|
||||
!stackTrace.includes('LGraphNode.connect') && // for mouse device
|
||||
!stackTrace.includes('loadGraphData') &&
|
||||
this.inputs[index].name != 'select') {
|
||||
this.removeInput(index);
|
||||
}
|
||||
}
|
||||
|
||||
let slot_i = 1;
|
||||
for (let i = 0; i < this.inputs.length; i++) {
|
||||
let input_i = this.inputs[i];
|
||||
if(input_i.name != 'select'&& input_i.name != 'sel_mode') {
|
||||
input_i.name = `${input_name}${slot_i}`
|
||||
slot_i++;
|
||||
}
|
||||
}
|
||||
|
||||
let last_slot = this.inputs[this.inputs.length - 1];
|
||||
if (
|
||||
(last_slot.name == 'select' && last_slot.name != 'sel_mode' && this.inputs[this.inputs.length - 2].link != undefined)
|
||||
|| (last_slot.name != 'select' && last_slot.name != 'sel_mode' && last_slot.link != undefined)) {
|
||||
this.addInput(`${input_name}${slot_i}`, this.outputs[0].type);
|
||||
}
|
||||
|
||||
if(this.widgets) {
|
||||
this.widgets[0].options.max = select_slot?this.inputs.length-1:this.inputs.length;
|
||||
this.widgets[0].value = Math.min(this.widgets[0].value, this.widgets[0].options.max);
|
||||
if(this.widgets[0].options.max > 0 && this.widgets[0].value == 0)
|
||||
this.widgets[0].value = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ class BaseAgent:
|
||||
def __init__(self):
|
||||
self.default_prompt = default_prompt
|
||||
self.agent = gtComfyAgent()
|
||||
# self.agent.set_default_config()
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
@@ -41,13 +40,12 @@ class BaseAgent:
|
||||
"STRING",
|
||||
{
|
||||
"forceInput": True,
|
||||
"dynamicPrompts": True,
|
||||
},
|
||||
),
|
||||
"STRING": (
|
||||
"STRING",
|
||||
{
|
||||
"multiline": True,
|
||||
},
|
||||
{"multiline": True, "dynamicPrompts": True},
|
||||
),
|
||||
},
|
||||
}
|
||||
@@ -115,6 +113,7 @@ class BaseAgent:
|
||||
self.agent.tools = tools
|
||||
if len(rulesets) > 0:
|
||||
self.agent.rulesets = rulesets
|
||||
print(self.agent.rulesets)
|
||||
|
||||
# Warn for models
|
||||
model, simple_model = self.agent.model_check()
|
||||
|
||||
+9
-54
@@ -1,74 +1,29 @@
|
||||
from griptape.structures import Agent
|
||||
from griptape.tasks import PromptTask
|
||||
from griptape.artifacts import BaseArtifact
|
||||
|
||||
|
||||
class gtUIBaseTask:
|
||||
class gtUIBaseLoader:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
DESCRIPTION = "Run a PromptTask."
|
||||
DESCRIPTION = "Loader"
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"STRING": (
|
||||
"STRING",
|
||||
{
|
||||
"multiline": True,
|
||||
},
|
||||
),
|
||||
},
|
||||
"optional": {
|
||||
"input_string": (
|
||||
"STRING",
|
||||
{
|
||||
"forceInput": True,
|
||||
},
|
||||
),
|
||||
"agent": ("AGENT",),
|
||||
},
|
||||
"required": {},
|
||||
"optional": {},
|
||||
}
|
||||
|
||||
RETURN_TYPES = (
|
||||
"STRING",
|
||||
"AGENT",
|
||||
)
|
||||
RETURN_NAMES = (
|
||||
"OUTPUT",
|
||||
"AGENT",
|
||||
)
|
||||
RETURN_TYPES = ("ARTIFACT",)
|
||||
RETURN_NAMES = ("OUTPUT",)
|
||||
|
||||
FUNCTION = "run"
|
||||
OUTPUT_NODE = True
|
||||
|
||||
CATEGORY = "Griptape/Agent Tasks"
|
||||
|
||||
def get_prompt_text(self, STRING, input_string):
|
||||
# Get the prompt text
|
||||
if not input_string:
|
||||
prompt_text = STRING
|
||||
else:
|
||||
prompt_text = STRING + "\n\n" + input_string
|
||||
|
||||
return prompt_text
|
||||
|
||||
def run(
|
||||
self,
|
||||
STRING,
|
||||
input_string=None,
|
||||
agent=None,
|
||||
):
|
||||
if not agent:
|
||||
agent = Agent()
|
||||
|
||||
prompt_text = self.get_prompt_text(STRING, input_string)
|
||||
try:
|
||||
agent.add_task(PromptTask(prompt_text))
|
||||
except Exception as e:
|
||||
print(e)
|
||||
result = agent.run()
|
||||
return (
|
||||
result.output_task.output.value,
|
||||
agent,
|
||||
)
|
||||
artifact = BaseArtifact()
|
||||
return (artifact,)
|
||||
|
||||
+2
-6
@@ -15,17 +15,13 @@ class gtUIBaseTask:
|
||||
"required": {
|
||||
"STRING": (
|
||||
"STRING",
|
||||
{
|
||||
"multiline": True,
|
||||
},
|
||||
{"multiline": True, "dynamicPrompts": True},
|
||||
),
|
||||
},
|
||||
"optional": {
|
||||
"input_string": (
|
||||
"STRING",
|
||||
{
|
||||
"forceInput": True,
|
||||
},
|
||||
{"forceInput": True, "dynamicPrompts": True},
|
||||
),
|
||||
"agent": ("AGENT",),
|
||||
},
|
||||
|
||||
+29
-115
@@ -17,26 +17,6 @@ class MergeTexts:
|
||||
"STRING",
|
||||
{"multiline": False, "default": "", "forceInput": True},
|
||||
),
|
||||
"input_2": (
|
||||
"STRING",
|
||||
{"multiline": False, "default": "", "forceInput": True},
|
||||
),
|
||||
"input_3": (
|
||||
"STRING",
|
||||
{"multiline": False, "default": "", "forceInput": True},
|
||||
),
|
||||
"input_4": (
|
||||
"STRING",
|
||||
{"multiline": False, "default": "", "forceInput": True},
|
||||
),
|
||||
"input_5": (
|
||||
"STRING",
|
||||
{"multiline": False, "default": "", "forceInput": True},
|
||||
),
|
||||
"input_6": (
|
||||
"STRING",
|
||||
{"multiline": False, "default": "", "forceInput": True},
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -48,23 +28,15 @@ class MergeTexts:
|
||||
|
||||
def create(
|
||||
self,
|
||||
input_1="",
|
||||
input_2="",
|
||||
input_3="",
|
||||
input_4="",
|
||||
input_5="",
|
||||
input_6="",
|
||||
**kwargs,
|
||||
):
|
||||
# Join strings by newline
|
||||
concatenated_string = "\n\n".join(
|
||||
[
|
||||
string
|
||||
for string in [input_1, input_2, input_3, input_4, input_5, input_6]
|
||||
if not string == ""
|
||||
],
|
||||
)
|
||||
merged_text = ""
|
||||
|
||||
return (concatenated_string,)
|
||||
inputs = [value for value in kwargs.values()]
|
||||
|
||||
for input in inputs:
|
||||
merged_text += "\n\n" + input
|
||||
return (merged_text,)
|
||||
|
||||
|
||||
class gtUIMergeInputs:
|
||||
@@ -83,11 +55,6 @@ class gtUIMergeInputs:
|
||||
"required": {},
|
||||
"optional": {
|
||||
"input_1": ("*",),
|
||||
"input_2": ("*",),
|
||||
"input_3": ("*",),
|
||||
"input_4": ("*",),
|
||||
"input_5": ("*",),
|
||||
"input_6": ("*",),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -99,30 +66,13 @@ class gtUIMergeInputs:
|
||||
|
||||
def create(
|
||||
self,
|
||||
input_1="",
|
||||
input_2="",
|
||||
input_3="",
|
||||
input_4="",
|
||||
input_5="",
|
||||
input_6="",
|
||||
**kwargs,
|
||||
):
|
||||
# Join strings by newline
|
||||
concatenated_string = "\n\n".join(
|
||||
[
|
||||
string
|
||||
for string in [
|
||||
str(input_1),
|
||||
str(input_2),
|
||||
str(input_3),
|
||||
str(input_4),
|
||||
str(input_5),
|
||||
str(input_6),
|
||||
]
|
||||
if not string == ""
|
||||
],
|
||||
)
|
||||
|
||||
return (concatenated_string,)
|
||||
concatenated_value = ""
|
||||
inputs = [value for value in kwargs.values()]
|
||||
for input in inputs:
|
||||
concatenated_value += "\n\n" + str(input)
|
||||
return (concatenated_value,)
|
||||
|
||||
|
||||
class RulesList:
|
||||
@@ -140,11 +90,6 @@ class RulesList:
|
||||
return {
|
||||
"optional": {
|
||||
"rules_1": ("RULESET",),
|
||||
"rules_2": ("RULESET",),
|
||||
"rules_3": ("RULESET",),
|
||||
"rules_4": ("RULESET",),
|
||||
"rules_5": ("RULESET",),
|
||||
"rules_6": ("RULESET",),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,27 +99,15 @@ class RulesList:
|
||||
|
||||
CATEGORY = "Griptape/Agent Rules"
|
||||
|
||||
def create(
|
||||
self,
|
||||
rules_1=None,
|
||||
rules_2=None,
|
||||
rules_3=None,
|
||||
rules_4=None,
|
||||
rules_5=None,
|
||||
rules_6=None,
|
||||
):
|
||||
rule_list = [
|
||||
rule[0]
|
||||
for rule in [
|
||||
rules_1,
|
||||
rules_2,
|
||||
rules_3,
|
||||
rules_4,
|
||||
rules_5,
|
||||
rules_6,
|
||||
]
|
||||
if rule is not None
|
||||
]
|
||||
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,)
|
||||
|
||||
|
||||
@@ -193,11 +126,6 @@ class ToolList:
|
||||
return {
|
||||
"optional": {
|
||||
"tool_1": ("TOOL_LIST",),
|
||||
"tool_2": ("TOOL_LIST",),
|
||||
"tool_3": ("TOOL_LIST",),
|
||||
"tool_4": ("TOOL_LIST",),
|
||||
"tool_5": ("TOOL_LIST",),
|
||||
"tool_6": ("TOOL_LIST",),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,25 +135,11 @@ class ToolList:
|
||||
|
||||
CATEGORY = "Griptape/Agent Tools"
|
||||
|
||||
def create(
|
||||
self,
|
||||
tool_1=None,
|
||||
tool_2=None,
|
||||
tool_3=None,
|
||||
tool_4=None,
|
||||
tool_5=None,
|
||||
tool_6=None,
|
||||
):
|
||||
tool_list = [
|
||||
tool[0]
|
||||
for tool in [
|
||||
tool_1,
|
||||
tool_2,
|
||||
tool_3,
|
||||
tool_4,
|
||||
tool_5,
|
||||
tool_6,
|
||||
]
|
||||
if tool is not None
|
||||
]
|
||||
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,)
|
||||
|
||||
@@ -64,6 +64,7 @@ class gtUICsvExtractionTask(gtUIBaseTask):
|
||||
"STRING",
|
||||
{
|
||||
"multiline": False,
|
||||
"dynamicPrompts": True,
|
||||
"default": "Column 1, Column 2, Column 3",
|
||||
},
|
||||
),
|
||||
@@ -115,6 +116,7 @@ class gtUIJsonExtractionTask(gtUIBaseTask):
|
||||
"STRING",
|
||||
{
|
||||
"multiline": True,
|
||||
"dynamicPrompts": True,
|
||||
"default": default_schema,
|
||||
},
|
||||
),
|
||||
|
||||
+3
-1
@@ -12,7 +12,9 @@ class gtUIInputStringNode:
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {},
|
||||
"optional": {"STRING": ("STRING", {"multiline": True})},
|
||||
"optional": {
|
||||
"STRING": ("STRING", {"multiline": True, "dynamicPrompts": True})
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
|
||||
Reference in New Issue
Block a user