Bugfixes for args, updated the README
This commit is contained in:
@@ -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:
|
||||
|
||||

|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 |
Reference in New Issue
Block a user