Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32d42bf472 | ||
|
|
281b8408c9 | ||
|
|
b215c83b76 | ||
|
|
76bc1c343e | ||
|
|
42bc6926ae | ||
|
|
351a68831d | ||
|
|
1c0585fabe | ||
|
|
60d55d904b | ||
|
|
3a5ef069d9 | ||
|
|
77a493f0eb | ||
|
|
2f6a649801 | ||
|
|
4d0de66b0b | ||
|
|
0aa2747736 | ||
|
|
0351a2eaab | ||
|
|
4276ddbfb1 | ||
|
|
0094c08d1c | ||
|
|
14824e3473 | ||
|
|
ea32a8fbbe | ||
|
|
e7363070f1 | ||
|
|
39c22295bc | ||
|
|
881e48a10c | ||
|
|
dc6b71b494 | ||
|
|
d938df9f4f | ||
|
|
9ea8e993c4 | ||
|
|
cdca60ff04 |
@@ -0,0 +1,25 @@
|
||||
name: Publish to Comfy registry
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "pyproject.toml"
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
publish-node:
|
||||
name: Publish Custom Node to registry
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.repository_owner == 'pydn' }}
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Publish Custom Node
|
||||
uses: Comfy-Org/publish-node-action@v1
|
||||
with:
|
||||
## Add your own personal access token to your Github Repository secrets and reference it here.
|
||||
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
|
||||
+18
-2
@@ -11,7 +11,8 @@ from argparse import ArgumentParser
|
||||
|
||||
import black
|
||||
|
||||
|
||||
# Add current directory to Python path
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from comfyui_to_python_utils import (
|
||||
import_custom_nodes,
|
||||
find_path,
|
||||
@@ -211,8 +212,18 @@ class CodeGenerator:
|
||||
for idx, data, is_special_function in load_order:
|
||||
# Generate class definition and inputs from the data
|
||||
inputs, class_type = data["inputs"], data["class_type"]
|
||||
input_types = self.node_class_mappings[class_type].INPUT_TYPES()
|
||||
class_def = self.node_class_mappings[class_type]()
|
||||
|
||||
# If required inputs are not present, skip the node as it will break the code if passed through to the script
|
||||
missing_required_variable = False
|
||||
if "required" in input_types.keys():
|
||||
for required in input_types["required"]:
|
||||
if required not in inputs.keys():
|
||||
missing_required_variable = True
|
||||
if missing_required_variable:
|
||||
continue
|
||||
|
||||
# If the class hasn't been initialized yet, initialize it and generate the import statements
|
||||
if class_type not in initialized_objects:
|
||||
# No need to use preview image nodes since we are executing the script in a terminal
|
||||
@@ -242,7 +253,12 @@ class CodeGenerator:
|
||||
if no_params or key in class_def_params
|
||||
}
|
||||
# Deal with hidden variables
|
||||
if class_def_params is not None:
|
||||
if (
|
||||
"hidden" in input_types.keys()
|
||||
and "unique_id" in input_types["hidden"].keys()
|
||||
):
|
||||
inputs["unique_id"] = random.randint(1, 2**64)
|
||||
elif class_def_params is not None:
|
||||
if "unique_id" in class_def_params:
|
||||
inputs["unique_id"] = random.randint(1, 2**64)
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ def import_custom_nodes() -> None:
|
||||
import asyncio
|
||||
import execution
|
||||
from nodes import init_extra_nodes
|
||||
sys.path.insert(0, find_path("ComfyUI"))
|
||||
import server
|
||||
|
||||
# Creating a new event loop and setting it as the default loop
|
||||
@@ -23,7 +24,7 @@ def import_custom_nodes() -> None:
|
||||
execution.PromptQueue(server_instance)
|
||||
|
||||
# Initializing custom nodes
|
||||
init_extra_nodes()
|
||||
asyncio.run(init_extra_nodes())
|
||||
|
||||
|
||||
def find_path(name: str, path: str = None) -> str:
|
||||
|
||||
+48
-44
@@ -1,56 +1,60 @@
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { api } from "../../scripts/api.js";
|
||||
import { app } from "../../scripts/app.js";
|
||||
import { $el } from "../../scripts/ui.js";
|
||||
|
||||
app.registerExtension({
|
||||
const extension = {
|
||||
name: "Comfy.SaveAsScript",
|
||||
commands: [
|
||||
{
|
||||
id: "triggerSaveAsScript",
|
||||
label: "Save As Script",
|
||||
function: () => { extension.savePythonScript(); }
|
||||
}
|
||||
],
|
||||
menuCommands: [
|
||||
{
|
||||
path: ["File"],
|
||||
commands: ["triggerSaveAsScript"]
|
||||
}
|
||||
],
|
||||
init() {
|
||||
$el("style", {
|
||||
parent: document.head,
|
||||
});
|
||||
},
|
||||
async setup() {
|
||||
const menu = document.querySelector(".comfy-menu");
|
||||
const separator = document.createElement("hr");
|
||||
|
||||
separator.style.margin = "20px 0";
|
||||
separator.style.width = "100%";
|
||||
menu.append(separator);
|
||||
|
||||
const saveButton = document.createElement("button");
|
||||
saveButton.textContent = "Save as Script";
|
||||
saveButton.onclick = () => {
|
||||
var filename = prompt("Save script as:");
|
||||
if(filename === undefined || filename === null || filename === "") {
|
||||
return
|
||||
}
|
||||
|
||||
app.graphToPrompt().then(async (p) => {
|
||||
const json = JSON.stringify({name: filename + ".json", workflow: JSON.stringify(p.output, null, 2)}, null, 2); // convert the data to a JSON string
|
||||
var response = await api.fetchApi(`/saveasscript`, { method: "POST", body: json });
|
||||
if(response.status == 200) {
|
||||
const blob = new Blob([await response.text()], {type: "text/python;charset=utf-8"});
|
||||
const url = URL.createObjectURL(blob);
|
||||
if(!filename.endsWith(".py")) {
|
||||
filename += ".py";
|
||||
}
|
||||
|
||||
const a = $el("a", {
|
||||
href: url,
|
||||
download: filename,
|
||||
style: {display: "none"},
|
||||
parent: document.body,
|
||||
});
|
||||
a.click();
|
||||
setTimeout(function () {
|
||||
a.remove();
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
menu.append(saveButton);
|
||||
savePythonScript() {
|
||||
var filename = prompt("Save script as:");
|
||||
if(filename === undefined || filename === null || filename === "") {
|
||||
return
|
||||
}
|
||||
|
||||
app.graphToPrompt().then(async (p) => {
|
||||
const json = JSON.stringify({name: filename + ".json", workflow: JSON.stringify(p.output, null, 2)}, null, 2); // convert the data to a JSON string
|
||||
var response = await api.fetchApi(`/saveasscript`, { method: "POST", body: json });
|
||||
if(response.status == 200) {
|
||||
const blob = new Blob([await response.text()], {type: "text/python;charset=utf-8"});
|
||||
const url = URL.createObjectURL(blob);
|
||||
if(!filename.endsWith(".py")) {
|
||||
filename += ".py";
|
||||
}
|
||||
|
||||
const a = $el("a", {
|
||||
href: url,
|
||||
download: filename,
|
||||
style: {display: "none"},
|
||||
parent: document.body,
|
||||
});
|
||||
a.click();
|
||||
setTimeout(function () {
|
||||
a.remove();
|
||||
window.URL.revokeObjectURL(url);
|
||||
}, 0);
|
||||
}
|
||||
});
|
||||
},
|
||||
async setup() {
|
||||
console.log("SaveAsScript loaded");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
app.registerExtension(extension);
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
[project]
|
||||
name = "comfyui-to-python-extension"
|
||||
description = "This custom node allows you to generate pure python code from your ComfyUI workflow with the click of a button. Great for rapid experimentation or production deployment."
|
||||
version = "1.3.1"
|
||||
license = { text = "MIT License" }
|
||||
dependencies = ["black"]
|
||||
|
||||
[project.urls]
|
||||
Repository = "https://github.com/pydn/ComfyUI-to-Python-Extension"
|
||||
# Used by Comfy Registry https://comfyregistry.org
|
||||
|
||||
[tool.comfy]
|
||||
PublisherId = "pydn"
|
||||
DisplayName = "ComfyUI-to-Python-Extension"
|
||||
Icon = ""
|
||||
Reference in New Issue
Block a user