Comfy2go
Comfy2go is a Go-based API that acts as a bridge to ComfyUI, a powerful and modular stable diffusion GUI and backend. Designed to alleviate the complexities of working directly with ComfyUI's intricate API, Comfy2go offers a more user-friendly way to access the advanced features and functionalities of ComfyUI.
Table of Contents
Overview
Comfy2go allows for developers to harness ComfyUI's powerful features in a more accessible way. Comfy2go is comprised of two main parts:
GraphAPI
The GraphAPI approximates the functionality of ComfyUI's front-end graph-based pipeline. While it does not allow for creating or editing existing workflows, it does allow for quickly finding, and setting the various inputs of each node in a workflow.
ClientAPI
The ClientAPI interoperates with the ComfyUI backend, offering:
- Backend system statistics
- Concurrent access to mulitple instances of ComfyUI
- Image and mask uploading/downloading
- Creating and queuing prompts from GraphAPI workflows
- Managing Queues
- Retreival of Prompt histories
- Loading workflows from PNG
- and quite a bit more
Installation
First, use 'go get' to install the latest version of the library.
go get -u github.com/richinsley/comfy2go@latest
Next, include Comfy2go client (and optionally the graph) APIs in your application:
import "github.com/richinsley/comfy2go/client"
import "github.com/richinsley/comfy2go/graphapi"
Usage
An IMPORTANT note is that Comfy2go works with full ComfyUI workflows, not workflows saved with "Save (API Format)"
Load a workflow from a png and queue it to a ComfyUI instance
package main
import (
"log"
"os"
"github.com/richinsley/comfy2go/client"
)
func main() {
clientaddr := "127.0.0.1"
clientport := 8188
pngpath := "my_cool_workflow.png"
// create a new ComgyGo client
c := client.NewComfyClient(clientaddr, clientport, nil)
// the ComgyGo client needs to be in an initialized state before
// we can create and queue graphs
if !c.IsInitialized() {
log.Printf("Initialize Client with ID: %s\n", c.ClientID())
err := c.Init()
if err != nil {
log.Println("Error initializing client:", err)
os.Exit(1)
}
}
// create a graph from the png file
graph, err := c.NewGraphFromPNGFile(pngpath)
if err != nil {
log.Println("Failed to get workflow graph from png file:", err)
os.Exit(1)
}
// queue the prompt and get the resulting image
item, err := c.QueuePrompt(graph)
if err != nil {
log.Println("Failed to queue prompt:", err)
os.Exit(1)
}
// continuously read messages from the QueuedItem until we get the "stopped" message type
for continueLoop := true; continueLoop; {
msg := <-item.Messages
switch msg.Type {
case "stopped":
// if we were stopped for an exception, display the exception message
qm := msg.ToPromptMessageStopped()
if qm.Exception != nil {
log.Println(qm.Exception)
os.Exit(1)
}
continueLoop = false
case "data":
qm := msg.ToPromptMessageData()
// data objects have the fields: Filename, Subfolder, Type
// * Subfolder is the subfolder in the output directory
// * Type is the type of the image temp/
for k, v := range qm.Data {
if k == "images" || k == "gifs" {
for _, output := range v {
img_data, err := c.GetImage(output)
if err != nil {
log.Println("Failed to get image:", err)
os.Exit(1)
}
f, err := os.Create(output.Filename)
if err != nil {
log.Println("Failed to write image:", err)
os.Exit(1)
}
f.Write(*img_data)
f.Close()
log.Println("Got image: ", output.Filename)
}
}
}
}
}
}