Bugfixes for args, updated the README

This commit is contained in:
atmaranto
2024-03-09 05:32:08 -06:00
parent 793854d21b
commit 0b4788d2af
4 changed files with 42 additions and 14 deletions
+28 -7
View File
@@ -2,7 +2,7 @@
Let me know of any major issues by submitting an Issue.
I plan to do some fresh install testing when I have time.
## ComfyUI-to-Python-Extension (SaveAsScript version)
## ComfyUI-SaveAsScript
This is a fork maintained by Anthony Maranto of the original [ComfyUI-To-Python-Extension](https://github.com/pydn/ComfyUI-to-Python-Extension) by Peyton DeNiro. It provides a more robust command-line interface and the ability to export your current workflow as a script directly from the ComfyUI web interface.
@@ -38,15 +38,36 @@ options:
Overwrite the output file if it exists
```
### Arguments
It is now possible to pass command-line arguments to a generated script file. Any time a **required** input variable for *any* node in your the ComfyUI workflow is left unfilled, SaveAsScript will automatically convert that node into an argument.
For instance, if you have a simple default workflow, but have converted the text widget of the positive prompt into an input and left it unfilled like so:
![An altered version of the default ComfyUI workflow](images/default_altered.png)
Then the unfilled required variable will be available as an argument:
```bash
usage: default-workflow.py [-h] text1
A converted ComfyUI workflow. Required inputs listed below. Values passed should be in JSON
positional arguments:
text1 Argument 0, input `text` for node "CLIP Text Encode (Prompt)" id 6 (autogenerated)
options:
-h, --help show this help message and exit
```
Arguments are new. **If you have any suggestions on how to improve them or on how to effectively specify defaults in the workflow and override in the command-line**, feel free to suggest that in an Issue.
### Other Changes
I also fixed what seemed to be a minor bug with exporting certain Crystools nodes, possibly due to their unusual name.
#### Bugfixes
- Windows paths are now properly escaped.
- I also fixed what seemed to be a minor bug with exporting certain Crystools nodes, possibly due to their unusual name.
### Improvement TODO
Disable export of invalid nodes (ones for which required args are not satisfied) and log a warning to the console.
## Description of ComfyUI-to-Python-Extension (usage altered)
## Old Description of ComfyUI-to-Python-Extension (usage altered)
The `ComfyUI-to-Python-Extension` is a powerful tool that translates [ComfyUI](https://github.com/comfyanonymous/ComfyUI) workflows into executable Python code. Designed to bridge the gap between ComfyUI's visual interface and Python's programming environment, this script facilitates the seamless transition from design to code execution. Whether you're a data scientist, a software developer, or an AI enthusiast, this tool streamlines the process of implementing ComfyUI workflows in Python.
+7 -7
View File
@@ -11,7 +11,7 @@ from typing import Dict, List, Any, Callable, Tuple, TextIO
import black
from comfyui_to_python_utils import import_custom_nodes, find_path, add_comfyui_directory_to_sys_path, add_extra_model_paths, get_value_at_index
from comfyui_to_python_utils import import_custom_nodes, find_path, add_comfyui_directory_to_sys_path, add_extra_model_paths, get_value_at_index, parse_arg
add_comfyui_directory_to_sys_path()
from nodes import NODE_CLASS_MAPPINGS
@@ -202,7 +202,7 @@ class CodeGenerator:
arg_inputs.append((input_var, f"Argument {i}, input `{input}` for node \\\"{data['_meta'].get('title', class_type)}\\\" id {idx}"))
print("WARNING: Missing required input", input, "for", class_type)
print("That will be CLI arg " + str(len(arg_inputs)))
missing.append((input_var, len(arg_inputs)))
missing.append((input, input_var, len(arg_inputs)))
class_def = self.node_class_mappings[class_type]()
@@ -225,8 +225,8 @@ class CodeGenerator:
# Remove any keyword arguments from **inputs if they are not in class_def_params
inputs = {key: value for key, value in inputs.items() if key in class_def_params}
for input, arg in missing:
inputs[input] = {"variable_name": f"argv." + input}
for input, input_var, arg in missing:
inputs[input] = {"variable_name": f"parse_arg(args." + input_var + ")"}
# Deal with hidden variables
if 'unique_id' in class_def_params:
inputs['unique_id'] = random.randint(1, 2**64)
@@ -303,18 +303,18 @@ class CodeGenerator:
"""
# Get the source code of the utils functions as a string
func_strings = []
for func in [get_value_at_index, find_path, add_comfyui_directory_to_sys_path, add_extra_model_paths, import_custom_nodes]:
for func in [get_value_at_index, find_path, add_comfyui_directory_to_sys_path, add_extra_model_paths, import_custom_nodes, parse_arg]:
func_strings.append(f'\n{inspect.getsource(func)}')
argparse_code = ""
if arg_inputs:
argparse_code = f'argv = sys.argv[:]\n\nparser = argparse.ArgumentParser(description="A converted ComfyUI workflow. Required inputs listed below. Values passed should be in JSON")\n'
argparse_code = f'\nparser = argparse.ArgumentParser(description="A converted ComfyUI workflow. Required inputs listed below. Values passed should be in JSON")\n'
for i, (input_name, arg_desc) in enumerate(arg_inputs):
argparse_code += f'parser.add_argument("{input_name}", help="{arg_desc} (autogenerated)")\n'
argparse_code += 'args = parser.parse_args()\nsys.argv = [sys.argv[0]]\n'
# Define static import statements required for the script
static_imports = ['import os', 'import random', 'import sys', 'import argparse', 'from typing import Sequence, Mapping, Any, Union',
static_imports = ['import os', 'import random', 'import sys', 'import json', 'import argparse', 'from typing import Sequence, Mapping, Any, Union',
'import torch'] + func_strings + [argparse_code]
# Check if custom nodes should be included
if custom_nodes:
+7
View File
@@ -101,3 +101,10 @@ def get_value_at_index(obj: Union[Sequence, Mapping], index: int) -> Any:
return obj[index]
except KeyError:
return obj['result'][index]
def parse_arg(s: str):
""" Parses a JSON string, returning it unchanged if the parsing fails. """
try:
return json.loads(s)
except json.JSONDecodeError:
return s
Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB