From 63af6fc33469ea1d01b834f60d79eea337696b16 Mon Sep 17 00:00:00 2001 From: malkuthro <166633396+malkuthro@users.noreply.github.com> Date: Tue, 25 Nov 2025 21:08:50 +0100 Subject: [PATCH] Pipeline - outDir fix --- .github/copilot-instructions.md | 61 +++++++++++++++++++++++++++++++++ k_ai_pipeline.py | 17 +++++++-- 2 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..939c296 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,61 @@ +## Purpose +Give an AI coding agent the minimal, high-value context to be productive in this repo (ComfyUI-Koolook). + +## Quick orientation +- Repo provides custom ComfyUI nodes focused on VFX / video/image prompt generation and resizing. +- Key Python nodes live at the repo root: `k_easy_version.py`, `k_easy_wan22_prompt.py`, `k_easy_resize.py`, `k_ai_pipeline.py`. +- `config.json` drives dynamic UI/inputs for the Wan 2.2 prompt node. +- `web/ai_pipeline.js` contains ComfyUI front-end tweaks (preview buttons, read-only instruction widget). + +## High-level architecture and runtime behavior +- Each node is implemented as a Python class exposing the ComfyUI node contract: `INPUT_TYPES`, `RETURN_TYPES`, `RETURN_NAMES`, `FUNCTION`, and `CATEGORY`. +- `__init__.py` imports these classes and exposes `NODE_CLASS_MAPPINGS` / `NODE_DISPLAY_NAME_MAPPINGS` so ComfyUI can register nodes. +- Nodes are imported at ComfyUI startup. `k_easy_wan22_prompt.py` reads `config.json` at import time to build inputs dynamically—editing `config.json` requires a ComfyUI restart to take effect. +- Front-end behaviour is extended via `web/ai_pipeline.js` which hooks `beforeRegisterNodeDef` and `nodeCreated` to add widgets and preview buttons for `EasyAIPipeline` and to dynamically update resize widgets for `EasyResize`. + +## Important patterns & conventions (concrete) +- Dynamic inputs: `config.json` defines fields as `{ name, type, options, default }`. The node code iterates this to create combo/string widgets. See `config.json` and `k_easy_wan22_prompt.py`. +- Node signature pattern: + - `INPUT_TYPES()` returns a dict with `required` inputs where each entry is a tuple like `("INT", {"default": 1, ...})`. + - `RETURN_TYPES` and `RETURN_NAMES` describe outputs. `FUNCTION` is the callable to run. + - Example: `k_ai_pipeline.py` exposes `generate_pipeline` via `FUNCTION = "generate_pipeline"` and returns `(file_path, name, version_str, output_directory, ...)`. +- File-path handling: nodes use `os.path.join(...)` then normalize separators with `.replace('\\','/')` and remove duplicate slashes. Versioning uses `f"v{version:03d}"` when not disabled. +- Overwrite protection: `k_ai_pipeline.generate_pipeline` raises a `ValueError` when the output directory exists and `enable_overwrite` is False. Agents should follow this behavior when changing save semantics. + +## UI integration specifics +- `web/ai_pipeline.js` provides two preview buttons for `EasyAIPipeline`: + - "Get output directory path" — builds the path from widget/widget-values and upstream simple widget values. If an input is connected to a complex node, it shows "Cannot preview..." because it can't resolve runtime values. + - "Get output file path" — same but includes constructed filename using the `extension` widget and padded version string. +- The JS helper `getEffectiveValue(node, name)` tries to resolve widget value or simple upstream widget values. When adding or editing similar front-end helpers, mirror this approach. + +## Developer workflows (how to run / debug) +- Install via ComfyUI Manager (recommended) or clone into `ComfyUI/custom_nodes/` and restart ComfyUI (see `README.md`). +- To see runtime exceptions / startup logs, run ComfyUI from a terminal and watch stdout/stderr (on Windows PowerShell): + - `python main.py` (run from the ComfyUI root) +- To apply `config.json` changes: edit `config.json` and restart ComfyUI. + +## Integration points & external references +- Prompt builders: designed to plug into nodes such as `PromptJSON` (see README). The Wan 2.2 prompt outputs comma-separated strings. +- Inspired by / interoperable with ComfyUI-KJNodes (Resize Image V2) — see README links. + +## What to keep in mind when editing code +- Preserve the node contract fields (`INPUT_TYPES`, `RETURN_TYPES`, `FUNCTION`, `CATEGORY`) to avoid breaking ComfyUI registration. +- When changing `config.json` fields, ensure defaults are valid and keep `output_type` consistent (current value: `"STRING"`). +- If adding front-end widgets, make changes in `web/ai_pipeline.js` to keep the UI in sync with node behavior (preview helpers, dynamic widget insertion/removal patterns). + +## Useful examples to cite in edits +- Construct version string: `version_str = f"v{version:03d}"` in `k_ai_pipeline.py`. +- Normalize path: `os.path.join(*parts).replace('\\', '/')` followed by removing duplicate slashes. +- UI preview button logic: `web/ai_pipeline.js` uses `parts.filter(...).join('/')` and `.replace(/\\/g, "/").replace(/\/+/g, '/')` for browser-side cleaning. + +## Where to look next (key files) +- `README.md` — repo purpose and installation instructions. +- `config.json` — dynamic prompt definitions. +- `k_ai_pipeline.py`, `k_easy_wan22_prompt.py`, `k_easy_resize.py`, `k_easy_version.py` — node implementations. +- `web/ai_pipeline.js` — front-end customizations. + +## Quick ask for the maintainer +- Tell me if there are any hidden developer scripts or a preferred local dev command for running ComfyUI in dev mode (otherwise I will use `python main.py`). + +--- +If you'd like, I can iterate and trim or expand any section, or add short examples of small edits (e.g., add a new field to `config.json` and show the minimal Python changes needed). diff --git a/k_ai_pipeline.py b/k_ai_pipeline.py index 4b8b587..51bd1dc 100644 --- a/k_ai_pipeline.py +++ b/k_ai_pipeline.py @@ -79,9 +79,14 @@ class EasyAIPipeline: while '//' in output_directory: output_directory = output_directory.replace('//', '/') - # Check for overwrite protection - if not enable_overwrite and os.path.exists(output_directory): - raise ValueError(f"Output directory already exists and overwrite is disabled. Enable 'enable_overwrite' or adjust parameters: {output_directory}") + # Ensure output directory exists (create if missing) but don't treat an existing directory + # as a reason to error — only an existing file with the same final path should block writing. + if not os.path.exists(output_directory): + try: + os.makedirs(output_directory, exist_ok=True) + except Exception: + # If directory creation fails, leave the original path and let downstream handle it. + pass # Construct full name: shot_name_ai_method[_version_str].extension name = f"{shot_name}_{ai_method}_{version_str}{extension}" if not disable_versioning else f"{shot_name}_{ai_method}{extension}" @@ -91,6 +96,12 @@ class EasyAIPipeline: while '//' in file_path: file_path = file_path.replace('//', '/') + # Check for overwrite protection on the final file path only. This avoids raising an error + # simply because the directory exists (useful when this node's output is connected to a loader), + # but still prevents accidentally overwriting an existing file unless enable_overwrite is True. + if not enable_overwrite and os.path.exists(file_path): + raise ValueError(f"Output file already exists and overwrite is disabled. Enable 'enable_overwrite' or adjust parameters: {file_path}") + # Return all for chaining in workflows (e.g., connect to savers or prompts) return (file_path, name, version_str, output_directory, shot_duration, seed_value, shot_name)