diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e1bd3ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +__pycache__/ +*.pyc +.venv*/ +.DS_Store +*.log +ComfyUI/models/ +ComfyUI/input/ +ComfyUI/output/ diff --git a/README.md b/README.md index 7543ccd..1bb5db2 100644 --- a/README.md +++ b/README.md @@ -7,20 +7,29 @@ Clone this repo into your comfyui folder. ## Projects Included ### 🧩 Custom Nodes: Comfyui_FSL_Nodes -- **sampler_config_hub.py** - One of two custom nodes to configure sampler and scheduler settings for workflows. Used to feed data to the meta node -- **sampler_scheduler_config.py** - Two of two custom nodes to configure sampler and scheduler settings for workflows. Used to feed data to the meta node - **manual_alpha_mask_painter.py** Custom node to manually convert black mask areas into alpha transparency. Useful with GRIPTAPE when inpainting and creating the mask by right clicking on the loaded image and select load mask editor. Griptape requires an alpha channel mask. - **8WayImgSwitch** Image switch with eight inputs -- **fsl_composite_with_mask_cropped** +- **fsl_composite_with_mask_cropped.py** Designed to remove the Alpha Channel But Keep Transparent Parts as Background Color (not currently used) - **fsl_save_and_strip_alpha** Strips alpha channel from RGBA image. (not currently used) -- **How to use** - place this node folder into the custom_nodes folder - no additional action is necessary. Nodes can be found in the comfyui onscreen nodes folder by searching for FSL +- **FSLGeminiGenerateImageV6.py** + Allows for the use of Gemini API's to create image. This node also provide for whether or not the preceding image is used for iterative generation. +- **fsl_image_memory.py** + Provides 4 nodes. Image Memory Store and Image Memory Recall stores an image to the key entered in the 'key' field. Image memory recall recalls the image for subsequent use. Image Memory Clear is used to delete the stored image based on the entered key. Image Memory Clear All clears all keys that have been entered. +- **fsl_prompt_compose.py** + Node for Positive and Negative prompt as well as 'scene-lock'. When scene-lock is true - + When lock_scene: True, the node prepends a short instruction block before your positive text that tells the model to treat the provided image as fixed “scene layout” and only change what you explicitly ask. The included language (summarized) is: + - use the provided image as base; + - keep composition, subjects, positions, background, lighting, camera angle, clothing, colors unchanged; + - change only what you specify; + - do not crop, do not isolate a single subject, do not change the background. +- **fsl_ensure_nhwc_batch.py** + Node guarantees that any incoming image tensor is converted to the [N, H, W, C] (batch–height–width–channels) layout expected by downstream nodes, automatically re-ordering dimensions and normalizing types so all image data conform to a consistent format for safe processing. +- **FSLImageSaverWithMetadataV5.py** + Node stores metadata with image. Data can be easily read using the LoadImage-w-Metadata.json workflow Located in the [`Comfyui_FSL_Nodes/`](https://github.com/fredlef/comfyui_projects/tree/main/custom_nodes/Comfyui_FSL_Nodes) directory. @@ -28,13 +37,28 @@ Located in the [`Comfyui_FSL_Nodes/`](https://github.com/fredlef/comfyui_project ### 🎨 Workflow: T-shirt Designer - **Tshirt-Designer-ver_2.0.json** + It is recommended not to use this workflow. A replacement workflow that is less complex will be uploaded as 3.0 Workflow designed for generating masked transparent images for T-shirt and object printing. - Many corrections and updates - Full workflow details and notes are available in [`tshirt_designer/`](https://github.com/fredlef/comfyui_projects/tree/main/workflows/tshirt_designer). --- +### 🎨 Workflow: Nano Banana +- **Nano Banana Iterative-Base.json** + Allows the user to create an image using Gemini-2.5 Flash-image-preview or Gemini-2.5 Flash. Once the initial image is created additional iterations of each succeeding image can be created just be entering a new prompt. Setup is included in a Note node in the workflow. +- **Nano Banana Iterative-Load 5 Images.json** + Provides for using up to 5 nodes to create an image with Nano Banana. The images can they be modified as in the Iterative-Base workflow. Basic instructions are provided in Notes nodes in the workflow. +- **Nano Banana w_Griptape w_Upscaler.json** + Uses Griptape Nodes as a front end prompt loader to Nano Banana. An excellent upscaler by Alex at ComfyUiStudio is included. An OpenAPI Key is required. +### Miscellaneous Workflows +- **LoadImage-w-Metadata.json** + Simple workflow to read the metadata created by the FSLImageSaverWithMetadataV5 node + +## Acknowledgements +- **Thanks to Alex and ComfyuiStudio for allowing me to use his excellent upscaler** +- **Mycroft Holmes - AKA ChatGPT for excellent assistance and guidance in the creation of Custom Nodes** ## Author diff --git a/custom_nodes/Comfyui_FSL_Nodes/FSLGeminiGenerateImageV6.py b/custom_nodes/Comfyui_FSL_Nodes/FSLGeminiGenerateImageV6.py new file mode 100644 index 0000000..f870c29 --- /dev/null +++ b/custom_nodes/Comfyui_FSL_Nodes/FSLGeminiGenerateImageV6.py @@ -0,0 +1,294 @@ + +import os +import time +import base64 +import random +from io import BytesIO +from typing import Any, Dict, List, Optional, Tuple + +import numpy as np +import requests + +try: + import torch +except Exception: + torch = None + +try: + from PIL import Image +except Exception: + Image = None + + +# ---------------- Helpers ---------------- + +def _tensor_to_png_b64(t) -> str: + """Convert torch.Tensor or np.ndarray image to base64 PNG.""" + if torch is not None and isinstance(t, torch.Tensor): + x = t.detach().cpu().float() + if x.dim() == 4 and x.shape[0] > 0: + x = x[0] + if x.dim() == 3 and x.shape[0] in (1, 3, 4) and x.shape[-1] not in (3, 4): + x = x.permute(1, 2, 0) + arr = x.numpy() + elif isinstance(t, np.ndarray): + arr = t + else: + raise TypeError(f"Expected image as torch.Tensor or np.ndarray, got {type(t)}") + + if arr.max() <= 1.5: + arr = arr * 255.0 + arr = np.clip(arr, 0, 255).astype(np.uint8) + + if Image is None: + raise RuntimeError("Pillow is required to encode PNG images.") + im = Image.fromarray(arr) + buf = BytesIO() + im.save(buf, format="PNG") + return base64.b64encode(buf.getvalue()).decode("utf-8") + + +def _extract_base64_image(resp_json: Dict[str, Any]) -> Optional[str]: + """Return first inline image payload from Gemini JSON response.""" + def _walk(node): + if isinstance(node, dict): + for k, v in node.items(): + yield k, v + yield from _walk(v) + elif isinstance(node, list): + for item in node: + yield from _walk(item) + + for k, v in _walk(resp_json): + if k in ("inline_data", "inlineData") and isinstance(v, dict): + data = v.get("data") + mime = v.get("mime_type") or v.get("mimeType") or "" + if data and ("image/" in mime or mime == "" or mime is None): + return data + return None + + +def _post_with_backoff(url: str, headers: Dict[str, str], params: Dict[str, Any], payload: Dict[str, Any]): + delay = 1.0 + last = None + for _ in range(4): + r = requests.post(url, headers=headers, params=params, json=payload, timeout=60) + last = r + if r.status_code != 429: + return r + time.sleep(delay) + delay *= 2 + return last + + +MODEL_CHOICES = ( + "gemini-2.5-flash-image", + "gemini-2.5-flash-image-preview", + "gemini-2.5-pro", + "gemini-2.0-flash-exp", + "gemini-2.0-pro-exp", + "gemini-1.5-pro", + "gemini-1.5-flash", + "gemini-1.0-pro-vision", + "gemini-2.5-flash-audio-preview", + "gemini-2.5-vision-preview", +) + + +class FSLGeminiGenerateImageV6: + """Gemini image generator with iterative + external image toggles.""" + + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + return { + "required": { + "prompt": ("STRING", {"multiline": True, "default": ""}), + "model": (MODEL_CHOICES, {"default": "gemini-2.5-flash-image-preview"}), + "width": ("INT", {"default": 1024, "min": 64, "max": 2048, "step": 64}), + "height": ("INT", {"default": 1024, "min": 64, "max": 2048, "step": 64}), + "temperature": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 2.0, "step": 0.1}), + "seed": ("INT", {"default": -1, "min": -1, "max": 0x7FFFFFFF}), + "use_init_image": ("BOOLEAN", {"default": True}), + "use_images": ("BOOLEAN", {"default": False}), + "refresh_models": ("BOOLEAN", {"default": False}), + "output_prompt": ("BOOLEAN", {"default": False}), + }, + "optional": { + "init_image": ("IMAGE",), + "images": ("IMAGE",), + "api_key": ("STRING", {"default": "", "multiline": False, "placeholder": "Leave blank to use GEMINI_API_KEY env var"}), + }, + } + + RETURN_TYPES = ("IMAGE", "STRING", "STRING", "INT", "INT", "FLOAT", "INT", "STRING", "DICT") + RETURN_NAMES = ( + "image", + "prompt", + "model", + "width", + "height", + "temperature", + "seed", + "seed_mode", + "metadata", + ) + FUNCTION = "generate" + CATEGORY = "FSL" + + # ---------- internals ---------- + + def _resolve_api_key(self, key_in: str) -> str: + k = (key_in or "").strip() + if not k: + k = os.environ.get("GEMINI_API_KEY", "").strip() + if not k: + raise RuntimeError("Gemini API key missing. Provide it in the node or set GEMINI_API_KEY env var.") + return k + + def _append_tensor_as_part(self, img_like, out: List[Dict[str, Any]]): + b64 = _tensor_to_png_b64(img_like) + out.append({"inline_data": {"mime_type": "image/png", "data": b64}}) + + def _collect_reference_parts( + self, + use_init_image: bool, + init_image, + use_images: bool, + images, + ) -> List[Dict[str, Any]]: + parts: List[Dict[str, Any]] = [] + + # init first (if enabled) + if use_init_image and init_image is not None: + if isinstance(init_image, (list, tuple)): + if len(init_image) > 0: + self._append_tensor_as_part(init_image[0], parts) + elif torch is not None and isinstance(init_image, torch.Tensor): + if init_image.dim() == 4 and init_image.shape[0] > 0: + self._append_tensor_as_part(init_image[0], parts) + else: + self._append_tensor_as_part(init_image, parts) + elif isinstance(init_image, np.ndarray): + self._append_tensor_as_part(init_image, parts) + + # then all external images (if enabled) + if use_images and images is not None: + if isinstance(images, (list, tuple)): + for t in images: + self._append_tensor_as_part(t, parts) + elif torch is not None and isinstance(images, torch.Tensor): + if images.dim() == 4: + for i in range(images.shape[0]): + self._append_tensor_as_part(images[i], parts) + else: + self._append_tensor_as_part(images, parts) + elif isinstance(images, np.ndarray): + self._append_tensor_as_part(images, parts) + + return parts + + # ---------- main ---------- + + def generate( + self, + prompt: str, + model: str, + width: int, + height: int, + temperature: float, + seed: int, + use_init_image: bool, + refresh_models: bool, + output_prompt: bool, + use_images: bool = False, + init_image: Optional["torch.Tensor"] = None, + images: Optional["torch.Tensor"] = None, + api_key: str = "", + ) -> Tuple["torch.Tensor", str, str, int, int, float, int, str, Dict[str, Any]]: + + seed_mode = "fixed" + if seed == -1: + seed = random.randint(0, 0x7FFFFFFF) + seed_mode = "randomize" + + api_key = self._resolve_api_key(api_key) + endpoint = f"https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent" + headers = {"Content-Type": "application/json"} + + parts: List[Dict[str, Any]] = [{"text": prompt}] + ref_parts = self._collect_reference_parts(use_init_image, init_image, use_images, images) + parts.extend(ref_parts) + + payload: Dict[str, Any] = { + "contents": [{"role": "user", "parts": parts}], + "generationConfig": { + "temperature": float(temperature), + "seed": int(seed), + }, + } + + _ = refresh_models # UI no-op + + resp = _post_with_backoff(endpoint, headers=headers, params={"key": api_key}, payload=payload) + + # Parse response + try: + resp_json = resp.json() + except Exception as e: + raise RuntimeError(f"Gemini response was not JSON: {e}") + + if isinstance(resp_json, dict) and "error" in resp_json: + err = resp_json["error"] + raise RuntimeError(f"Gemini error: {err.get('status')} - {err.get('message')}") + + b64_img = _extract_base64_image(resp_json) + if not b64_img: + raise RuntimeError(f"Failed to find inline image in Gemini response. First 1k of JSON: {str(resp_json)[:1000]}") + + try: + img_bytes = base64.b64decode(b64_img) + if Image is None: + raise RuntimeError("Pillow is required to decode returned image.") + pil = Image.open(BytesIO(img_bytes)).convert("RGBA") + except Exception as e: + raise RuntimeError(f"Failed to decode inline image: {e}") + + np_img = np.array(pil).astype(np.float32) / 255.0 + if torch is None: + raise RuntimeError("torch is required for IMAGE tensor output.") + image_tensor = torch.from_numpy(np_img)[None, ...] + + out_prompt = prompt if output_prompt else "" + + metadata_output = { + "prompt": prompt, + "model": model, + "width": width, + "height": height, + "temperature": temperature, + "seed": seed, + "seed_mode": seed_mode, + "use_init_image": bool(use_init_image and init_image is not None), + "use_images": bool(use_images and images is not None), + "init_image_connected": bool(init_image is not None), + "batch_images": ( + int(images.shape[0]) if (torch is not None and isinstance(images, torch.Tensor) and images.dim() == 4) + else (len(images) if isinstance(images, (list, tuple)) else (1 if images is not None else 0)) + ), + } + + return ( + image_tensor, + out_prompt, + model, + width, + height, + temperature, + seed, + seed_mode, + metadata_output, + ) + + +NODE_CLASS_MAPPINGS = {"FSLGeminiGenerateImageV6": FSLGeminiGenerateImageV6} +NODE_DISPLAY_NAME_MAPPINGS = {"FSLGeminiGenerateImageV6": "FSL Gemini Generate Image V6"} diff --git a/custom_nodes/Comfyui_FSL_Nodes/FSLImageSaverWithMetadataV5.py b/custom_nodes/Comfyui_FSL_Nodes/FSLImageSaverWithMetadataV5.py new file mode 100644 index 0000000..961f4d6 --- /dev/null +++ b/custom_nodes/Comfyui_FSL_Nodes/FSLImageSaverWithMetadataV5.py @@ -0,0 +1,189 @@ + +import os +import json +from typing import Dict, Any, List, Tuple, Optional + +import numpy as np +import torch +from PIL import Image, PngImagePlugin +import folder_paths +from datetime import datetime + +class FSLImageSaverWithMetadataV5: + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + return { + "required": { + "images": ("IMAGE",), + "filename": ("STRING", {"default": "gemini_out"}), + "save_to_subfolder": ("STRING", {"default": ""}), + }, + "optional": { + "append_datetime": ("BOOLEAN", {"default": False}), + "model_string": ("STRING", {"default": ""}), + "modelname": ("STRING", {"default": ""}), + "seed_string": ("STRING", {"default": ""}), + "width_string": ("STRING", {"default": ""}), + "height_string": ("STRING", {"default": ""}), + "temperature_string": ("STRING", {"default": ""}), + "positive_string": ("STRING", {"default": ""}), + "negative_string": ("STRING", {"default": ""}), + "cfg_string": ("STRING", {"default": ""}), + "steps_string": ("STRING", {"default": ""}), + "sampler_string": ("STRING", {"default": ""}), + "scheduler_string": ("STRING", {"default": ""}), + "guidance_scale_string": ("STRING", {"default": ""}), + "watermark_string": ("STRING", {"default": ""}), + "external_metadata": ("DICT", {"default": {}}), + }, + } + + # Keep METADATA_RAW as output #1 for compatibility. + # Add IMAGE as output #2 so you can optionally preview. + RETURN_TYPES = ("METADATA_RAW", "IMAGE",) + RETURN_NAMES = ("metadata_raw", "image",) + FUNCTION = "save_files" + OUTPUT_NODE = True + CATEGORY = "FSL/Save" + + def _to_numpy_image(self, t: torch.Tensor) -> np.ndarray: + """Convert a tensor to HWC uint8, preserving alpha if present.""" + if t.device.type != "cpu": + t = t.cpu() + t = t.detach().float() + # If CHW, convert to HWC + if t.dim() == 3 and t.shape[0] in (1, 3, 4) and t.shape[-1] not in (3, 4): + t = t.permute(1, 2, 0) + arr = (t.numpy() * 255.0).clip(0, 255).astype(np.uint8) + return arr + + def save_files( + self, + images: torch.Tensor, + filename: str, + save_to_subfolder: str, + append_datetime: bool = False, + model_string: str = "", + modelname: str = "", + seed_string: str = "", + width_string: str = "", + height_string: str = "", + temperature_string: str = "", + positive_string: str = "", + negative_string: str = "", + cfg_string: str = "", + steps_string: str = "", + sampler_string: str = "", + scheduler_string: str = "", + guidance_scale_string: str = "", + watermark_string: str = "", + external_metadata: Optional[Dict[str, Any]] = None, + ) -> Tuple[Dict[str, Any], torch.Tensor]: + + base = folder_paths.get_output_directory() + sub = (save_to_subfolder or "").strip() + sub = os.path.normpath(sub).replace("\\", "/").lstrip("/") + outdir = os.path.join(base, sub) if sub else base + os.makedirs(outdir, exist_ok=True) + + # Normalize batch + if images.dim() == 3: + images = images.unsqueeze(0) + + # One canonical, timezone-aware timestamp used everywhere + now_local = datetime.now().astimezone() + ts_file = now_local.strftime("%Y%m%d_%H%M%S") # e.g. 20251014_163733 + iso_human = now_local.isoformat(timespec="seconds") # e.g. 2025-10-14T16:37:33-04:00 + + if append_datetime: + filename = f"{filename}_{ts_file}" + + model_value = (model_string or modelname).strip() + + lines: List[str] = [] + if model_value: + lines.append("model: " + model_value) + if seed_string: + lines.append("seed: " + seed_string) + if width_string or height_string: + lines.append(f"size: {width_string}x{height_string}") + if temperature_string: + lines.append("temperature: " + temperature_string) + if positive_string: + lines.append("positive: " + positive_string) + if negative_string: + lines.append("negative: " + negative_string) + parameters_text = "\n".join(lines) + + pnginfo = PngImagePlugin.PngInfo() + if parameters_text: + pnginfo.add_text("parameters", parameters_text) + if external_metadata: + try: + pnginfo.add_text("fsl_metadata", json.dumps(external_metadata, ensure_ascii=False)) + except Exception: + pnginfo.add_text("fsl_metadata", str(external_metadata)) + + metadata_raw_out: Dict[str, Any] = { + "fileinfo": { + "filename": "", + "resolution": "", + "date": "", + "size_bytes": 0, + "size_human": "", + "size": "", + "format": "PNG", + } + } + + preview_tensor: Optional[torch.Tensor] = None + + for i in range(images.shape[0]): + np_img = self._to_numpy_image(images[i]) + h, w = np_img.shape[0], np_img.shape[1] + + # Explicit mode preserves alpha if present + mode = "RGBA" if np_img.shape[-1] == 4 else ("RGB" if np_img.shape[-1] == 3 else None) + pil = Image.fromarray(np_img, mode=mode) if mode else Image.fromarray(np_img) + + ret = folder_paths.get_save_image_path(filename, outdir, i) + # Known return: (full_output_folder, filename_prefix, counter, subfolder, filename_with_subfolder) + if isinstance(ret, (list, tuple)) and len(ret) >= 3: + full_output_folder, filename_prefix, counter = ret[0], ret[1], ret[2] + path = os.path.join(full_output_folder, f"{filename_prefix}_{counter:05}.png") + else: + path = os.path.join(outdir, f"{filename}_{i:05}.png") + + pil.save(path, format="PNG", pnginfo=pnginfo) + + # Align filesystem mtime with our canonical timestamp so all tools agree + epoch = now_local.timestamp() + os.utime(path, (epoch, epoch)) + + filesize = os.path.getsize(path) + size_human = f"{filesize / (1024*1024):.2f} MB" + + metadata_raw_out["fileinfo"] = { + "filename": path, + "resolution": f"{w}x{h}", + "date": iso_human, # unified local, tz-aware + "size_bytes": filesize, + "size_human": size_human, + "size": size_human, + "format": "PNG", + } + + # Keep first image as preview + if preview_tensor is None: + # Return normalized [1,H,W,C] float tensor + preview_tensor = torch.from_numpy(np_img.astype(np.float32) / 255.0)[None, ...] + + # Safety: if nothing was saved (empty batch), provide a blank preview + if preview_tensor is None: + preview_tensor = torch.zeros((1, 64, 64, 4), dtype=torch.float32) + + # Return METADATA first (compat), IMAGE second (for optional preview wiring) + return (metadata_raw_out, preview_tensor,) + +NODE_CLASS_MAPPINGS = {"FSLImageSaverWithMetadataV5": FSLImageSaverWithMetadataV5} +NODE_DISPLAY_NAME_MAPPINGS = {"FSLImageSaverWithMetadataV5": "FSL Image Saver w/ Metadata V5"} diff --git a/custom_nodes/Comfyui_FSL_Nodes/README.md b/custom_nodes/Comfyui_FSL_Nodes/README.md deleted file mode 100644 index 8b78a58..0000000 --- a/custom_nodes/Comfyui_FSL_Nodes/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# Comfyui_FSL_Nodes - -This folder contains custom nodes designed by Fred LeFevre for use with ComfyUI workflows. They are required for the tshirt_designer workflow. - -Included nodes: -- `sampler_config_hub.py` — Custom sampler and scheduler configuration node -- `sampler_scheduler_config.py` - Custom sampler and scheduler configuration node -- `manual_alpha_mask_painter.py` — Manual alpha mask painter for converting black masks to transparency - -These nodes are licensed under the main [repository LICENSE](../LICENSE). diff --git a/custom_nodes/Comfyui_FSL_Nodes/Tshirt_Workflow_Notes.md b/custom_nodes/Comfyui_FSL_Nodes/Tshirt_Workflow_Notes.md deleted file mode 100644 index 8c407ca..0000000 --- a/custom_nodes/Comfyui_FSL_Nodes/Tshirt_Workflow_Notes.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -title: T-Shirt and Object Masking Workflow Notes -author: Fred LeFevre -created: 2025-04-27 -description: Documentation for the T-Shirt and Object Masking Workflow, including custom node usage, image source control, and metadata settings. ---- - -# T-Shirt and Object Masking Workflow — Testing & Direction Notes - -This workflow was primarily designed to create masked images for T-shirts and other objects. It has grown beyond my initial expectations. - ---- - -## 1. Pending Work -- **Add an upscaler.** - - I currently use **Topaz Photo AI** for upscaling and it does a great job. - ---- - -## 2. Custom Nodes -- There are **three custom nodes** designed for this workflow. -- The **Sampler** and **Scheduler** nodes are included primarily to **feed settings to metadata**. - - Available fields (except for **Denoise** and **Control After Generate**) should be entered in the **custom nodes**, **not** the **KSampler**. - - **Denoise** and **Control After Generate** should still be entered directly inside the **KSampler**. - ---- - -## 3. Image Input Options -- There are **four Griptape image nodes** plus a standard **Load Image** node that can feed images into the workflow. -- The image that is processed depends on the **5-Way Toggle Image Switch** inside the **Toggle Image Source Group**. -- **Griptape nodes** require **both OpenAI** and **Black Forest Labs API keys**. - - These keys **used to** be entered in a `.env` file. - - They are now entered in the **Griptape Settings window** inside ComfyUI. - - Instructions for obtaining the necessary API keys can easily be found **online** or in the **Griptape documentation**. - ---- - -## 4. SDXL or Direct Path Group -- The **SDXL or Direct Path Group switch** determines: - - Whether the image is processed through the full **SDXL workflow**, or - - Whether it **goes directly** to the **Transparent Background Node**, bypassing SDXL processing. - ---- - -## 5. Prompt vs Image Source Priority -- The **Toggle Prompt or Image Src Group** controls **whether the prompt or the image source takes precedence**. -- This works in conjunction with setting **Denoise** inside the **KSampler**: - - **Denoise = 0.1** → **Prompt** takes precedence. - - **Denoise = 0.5** → **Mix** of prompt and image. - - **Denoise = 0.9** → **Image** takes precedence. - -### Choices Table: - -| Toggle Prompt or Image Src | SDXL or Direct Path Group | Denoise Setting | Precedence | Notes | -|:---------------------------|:--------------------------|:----------------|:-----------|:------| -| 0 and 0 | (Doesn't matter) | 0.9 | Manual Prompt (Enter Positive Prompt Here) | | -| 0 and 0 | (Doesn't matter) | 0.1 | No Image | If SDXL or Direct Path Group switch is set to 1, image skips SDXL workflow | -| 1 and 0 | (Doesn't matter) | 0.9 | Griptape Prompt | | -| 1 and 0 | (Doesn't matter) | 0.1 | No Image | | -| 0 and 1 | (Doesn't matter) | 0.9 | Manual Prompt | | -| 0 and 1 | (Doesn't matter) | 0.5 | Mix of Manual Prompt and Image Source | | -| 0 and 1 | (Doesn't matter) | 0.1 | Image Source | | -| 1 and 1 | (Doesn't matter) | 0.9 | Manual Prompt | | -| 1 and 1 | (Doesn't matter) | 0.5 | Mix of Manual Prompt and Image Source | | -| 1 and 1 | (Doesn't matter) | 0.1 | Mix of Manual Prompt and Image Source | | - ---- - -# End of Notes diff --git a/custom_nodes/Comfyui_FSL_Nodes/fsl_ensure_nhwc_batch.py b/custom_nodes/Comfyui_FSL_Nodes/fsl_ensure_nhwc_batch.py new file mode 100644 index 0000000..c747ccd --- /dev/null +++ b/custom_nodes/Comfyui_FSL_Nodes/fsl_ensure_nhwc_batch.py @@ -0,0 +1,55 @@ +# FSL / Ensure NHWC Batch (returns 1xH×W×3 float32) +import torch + +class FSLEnsureNHWCBatch: + @classmethod + def INPUT_TYPES(cls): + return {"required": {"image": ("IMAGE",)}} + + RETURN_TYPES = ("IMAGE",) + RETURN_NAMES = ("image_nhwc",) + FUNCTION = "ensure_nhwc" + CATEGORY = "FSL/Utils" + + def _to_nhwc(self, t: torch.Tensor) -> torch.Tensor: + if not isinstance(t, torch.Tensor): + raise TypeError(f"Expected torch.Tensor, got {type(t)}") + if t.dtype != torch.float32: + t = t.float() + + # 3D cases: HWC / CHW / HCW + if t.ndim == 3: + if t.shape[-1] in (3, 4): # HWC already + a = t + elif t.shape[0] in (3, 4): # CHW -> HWC + a = t.permute(1, 2, 0).contiguous() + elif t.shape[1] in (3, 4): # HCW -> HWC + a = t.permute(0, 2, 1).contiguous() + else: + raise ValueError(f"3D tensor has unexpected shape {tuple(t.shape)}") + return a.unsqueeze(0).clamp(0.0, 1.0) # -> 1 x H x W x C + + # 4D cases: NHWC / NCHW / NHCW + if t.ndim == 4: + if t.shape[-1] in (3, 4): # NHWC already + a = t + elif t.shape[1] in (3, 4): # NCHW -> NHWC + a = t.permute(0, 2, 3, 1).contiguous() + elif t.shape[2] in (3, 4): # NHCW -> NHWC + a = t.permute(0, 1, 3, 2).contiguous() + else: + raise ValueError(f"4D tensor has unexpected shape {tuple(t.shape)}") + return a.clamp(0.0, 1.0) + + raise ValueError(f"Expected 3D/4D tensor, got {t.ndim}D") + + def ensure_nhwc(self, image): + t = image[0] if isinstance(image, list) else image + t = self._to_nhwc(t) + # Drop alpha if present so esrgan-like models stay happy + if t.shape[-1] == 4: + t = t[..., :3] + return (t,) + +NODE_CLASS_MAPPINGS = {"FSLEnsureNHWCBatch": FSLEnsureNHWCBatch} +NODE_DISPLAY_NAME_MAPPINGS = {"FSLEnsureNHWCBatch": "FSL / Ensure NHWC Batch"} diff --git a/custom_nodes/Comfyui_FSL_Nodes/fsl_image_memory.py b/custom_nodes/Comfyui_FSL_Nodes/fsl_image_memory.py new file mode 100644 index 0000000..39aa1ed --- /dev/null +++ b/custom_nodes/Comfyui_FSL_Nodes/fsl_image_memory.py @@ -0,0 +1,130 @@ +# ComfyUI/custom_nodes/comfyui_fsl_nodes/fsl_image_memory.py +# FSL / Image Memory: store & recall IMAGE tensors between runs. + +import torch, time + +# One in-process cache for IMAGEs: key -> list[HWC float tensors] +_MEM = {} + +def _ensure_list_of_hwctensors(x): + """Return a flat list of HWC float32 tensors in [0,1].""" + imgs = x if isinstance(x, list) else [x] + # unwrap single nested list: [[t]] -> [t] + if len(imgs) == 1 and isinstance(imgs[0], list): + imgs = imgs[0] + + out = [] + for t in imgs: + # normalize to torch tensor + if not torch.is_tensor(t): + t = torch.tensor(t) + + # common incoming shapes: + # (H,W,C) OK; (C,H,W) -> (H,W,C); (1,C,H,W) -> (C,H,W) + if t.ndim == 4 and t.shape[0] == 1: + t = t.squeeze(0) # (1,C,H,W) -> (C,H,W) + if t.ndim == 3 and t.shape[0] in (1, 3) and t.shape[-1] not in (1, 3): + # likely CHW -> HWC + t = t.movedim(0, -1) + if t.ndim == 2: + # grayscale H,W -> H,W,1 + t = t.unsqueeze(-1) + + # dtype/range hygiene + if t.dtype != torch.float32: + t = t.float() + t = t.clamp(0, 1).contiguous() + out.append(t) + return out + +def _first_shape(lst): + try: + t = lst[0] + return tuple(t.shape) + except Exception: + return "n/a" + +class FSLImageMemoryStore: + @classmethod + def INPUT_TYPES(cls): + return {"required": {"image": ("IMAGE",), "key": ("STRING", {"default": "last"})}} + + RETURN_TYPES = ("IMAGE",) + RETURN_NAMES = ("image",) + FUNCTION = "store" + CATEGORY = "FSL/Memory" + + def store(self, image, key): + data = _ensure_list_of_hwctensors(image) + _MEM[key] = data + print(f"[FSLImageMemoryStore] stored key='{key}' ({len(data)} img) first={_first_shape(data)} mem_id={id(_MEM)}") + return (data,) # pass-through as IMAGE + +class FSLImageMemoryRecallSafe: + @classmethod + def INPUT_TYPES(cls): + return {"required": {"key": ("STRING", {"default": "last"})}} + + RETURN_TYPES = ("IMAGE",) + RETURN_NAMES = ("image",) + FUNCTION = "recall" + CATEGORY = "FSL/Memory" + + @classmethod + def IS_CHANGED(cls, **kwargs): + return time.time() + + def recall(self, key): + imgs = _MEM.get(key, None) + if imgs: + imgs = _ensure_list_of_hwctensors(imgs) + print(f"[FSLImageMemoryRecallSafe] key='{key}' ({len(imgs)} img) first={_first_shape(imgs)} mem_id={id(_MEM)}") + return (imgs,) + print(f"[FSLImageMemoryRecallSafe] WARNING: key='{key}' missing -> returning 1x1 black mem_id={id(_MEM)}") + t = torch.zeros((1, 1, 3), dtype=torch.float32) # HWC in [0,1] + return ([t],) + +class FSLImageMemoryClear: + @classmethod + def INPUT_TYPES(cls): + return {"required": {"key": ("STRING", {"default": "last"})}} + + RETURN_TYPES = () + FUNCTION = "clear" + OUTPUT_NODE = True + CATEGORY = "FSL/Memory" + + def clear(self, key): + _MEM.pop(key, None) + print(f"[FSLImageMemoryClear] cleared key='{key}' mem_id={id(_MEM)}") + return () + +class FSLImageMemoryClearAll: + @classmethod + def INPUT_TYPES(cls): + return {} + + RETURN_TYPES = () + FUNCTION = "clear_all" + OUTPUT_NODE = True + CATEGORY = "FSL/Memory" + + def clear_all(self): + global _MEM + _MEM.clear() + print(f"[FSLImageMemoryClearAll] cleared all memory, mem_id={id(_MEM)}") + return () + +NODE_CLASS_MAPPINGS = { + "FSLImageMemoryStore": FSLImageMemoryStore, + "FSLImageMemoryRecallSafe": FSLImageMemoryRecallSafe, + "FSLImageMemoryClear": FSLImageMemoryClear, + "FSLImageMemoryClearAll": FSLImageMemoryClearAll, +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "FSLImageMemoryStore": "FSL / Image Memory → Store", + "FSLImageMemoryRecallSafe": "FSL / Image Memory → Recall (Safe)", + "FSLImageMemoryClear": "FSL / Image Memory → Clear", + "FSLImageMemoryClearAll": "FSL / Image Memory → Clear All", +} \ No newline at end of file diff --git a/custom_nodes/Comfyui_FSL_Nodes/sampler_config_hub.py b/custom_nodes/Comfyui_FSL_Nodes/sampler_config_hub.py deleted file mode 100644 index 703d22c..0000000 --- a/custom_nodes/Comfyui_FSL_Nodes/sampler_config_hub.py +++ /dev/null @@ -1,46 +0,0 @@ -class SamplerConfigHub: - """ - Custom node that emits a unified sampler config dictionary. - This allows centralized control over sampler settings when using multiple - KSampler nodes in a workflow (e.g., for SDXL base and refiner). - """ - CATEGORY = "FSL Nodes/Utils" # Changed to match your preferred category - RETURN_TYPES = ("SAMPLER_CONFIG",) - RETURN_NAMES = ("sampler_config",) - FUNCTION = "build_config" - - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "sampler_name": ([ - "euler", "euler_ancestral", "heun", - "dpm_2", "dpm_2_ancestral", "lms", - "dpm_fast", "dpm_adaptive", - "dpmpp_2s_ancestral", "dpmpp_2m", "dpmpp_sde", - "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", - "ddim", "plms" - ],), - "scheduler": (["normal", "karras", "exponential", "sgm_uniform"],), - "steps": ("INT", {"default": 30, "min": 1, "max": 150}), - "cfg": ("FLOAT", {"default": 7.5, "min": 0.0, "max": 20.0}), - "seed": ("INT", {"default": 42}), - } - } - - def build_config(self, sampler_name, scheduler, steps, cfg, seed): - return ({ - "sampler_name": sampler_name, - "scheduler": scheduler, - "steps": steps, - "cfg": cfg, - "seed": seed, - },) - -NODE_CLASS_MAPPINGS = { - "FSL SamplerConfigHub": SamplerConfigHub, # Added prefix and comma -} - -NODE_DISPLAY_NAME_MAPPINGS = { - "FSL SamplerConfigHub": "🎛️ Sampler Config Hub (FSL)", # Added prefix -} diff --git a/custom_nodes/Comfyui_FSL_Nodes/sampler_scheduler_config.py b/custom_nodes/Comfyui_FSL_Nodes/sampler_scheduler_config.py deleted file mode 100644 index 377fd0c..0000000 --- a/custom_nodes/Comfyui_FSL_Nodes/sampler_scheduler_config.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -FSL Sampler & Scheduler Config Node - -Version: 1.0.0 -Author: Fred LeFevre -Date: 2025-04-27 - -Description: Custom Sampler Node to feed settings to metadata. -""" - -__version__ = "1.0.0" - -class FSL_SamplerSchedulerConfig: - CATEGORY = "FSL Nodes/Utils" - RETURN_TYPES = ("SAMPLER", "SCHEDULER") - RETURN_NAMES = ("sampler", "scheduler") - FUNCTION = "bundle" - - @classmethod - def INPUT_TYPES(cls): - return { - "required": { - "sampler_name": ([ - "euler", "euler_cfg_pp", "euler_ancestral", "euler_ancestral_cfg_pp", - "heun", "heunpp2", "dpm_2", "dpm_2_ancestral", "lms", "dpm_fast", - "dpm_adaptive", "dpmpp_2s_ancestral", "dpmpp_2s_ancestral_cfg_pp", - "dpmpp_sde", "dpmpp_sde_gpu", "dpmpp_2m", "dpmpp_2m_cfg_pp", - "dpmpp_2m_sde", "dpmpp_2m_sde_gpu", "dpmpp_3m_sde", - "dpmpp_3m_sde_gpu", "ddpm", "lcm", "ipndm", "ipndm_v", "deis", - "res_multistep", "res_multistep_cfg_pp", "res_multistep_ancestral", - "res_multistep_ancestral_cfg_pp", "gradient_estimation", "er_sde", - "ddim", "uni_pc", "uni_pc_bh2" - ], {"default": "euler"}), - "scheduler_name": ([ - "normal", "karras", "exponential", "sgm_uniform", - "simple", "ddim_uniform", "beta", "linear_quadratic", "kl_optimal" - ], {"default": "karras"}) - } - } - - def bundle(self, sampler_name, scheduler_name): - return (sampler_name, scheduler_name) - -NODE_CLASS_MAPPINGS = { - "FSL Sampler & Scheduler Config": FSL_SamplerSchedulerConfig, -} - -NODE_DISPLAY_NAME_MAPPINGS = { - "FSL Sampler & Scheduler Config": "🛠️ Sampler & Scheduler Config (FSL)", -} diff --git a/workflows/nano_banana/LoadImage-w-Metadata.json b/workflows/nano_banana/LoadImage-w-Metadata.json new file mode 100644 index 0000000..f7d4864 --- /dev/null +++ b/workflows/nano_banana/LoadImage-w-Metadata.json @@ -0,0 +1 @@ +{"id":"c58118a1-db97-4ce0-9bbb-a8a8d39cbdd5","revision":0,"last_node_id":7,"last_link_id":5,"nodes":[{"id":2,"type":"Show any to JSON [Crystools]","pos":[1213.032470703125,-177.2519073486328],"size":[691.7337036132812,430.23626708984375],"flags":{},"order":4,"mode":0,"inputs":[{"localized_name":"any_value","name":"any_value","shape":7,"type":"*","link":1}],"outputs":[{"localized_name":"string","name":"string","type":"STRING","links":[]}],"properties":{"cnr_id":"comfyui-crystools","ver":"1.27.3","Node name for S&R":"Show any to JSON [Crystools]","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":[]},{"id":3,"type":"LocalImageGalleryNode","pos":[610.5911865234375,399.3844909667969],"size":[800,670],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[{"localized_name":"image","name":"image","type":"IMAGE","links":[2]},{"localized_name":"paths","name":"paths","type":"LMM_ALL_PATHS","links":null},{"localized_name":"path","name":"path","type":"STRING","links":[3]},{"localized_name":"info","name":"info","type":"STRING","links":[]}],"properties":{"cnr_id":"comfyui_local_image_gallery","ver":"1.1.1","Node name for S&R":"LocalImageGalleryNode","gallery_unique_id":"gallery-nbrbpsxuy","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"},"selection":"[]"},"widgets_values":["gallery-nbrbpsxuy","[]",""]},{"id":5,"type":"Show any to JSON [Crystools]","pos":[1441.543701171875,535.852783203125],"size":[691.7337036132812,430.23626708984375],"flags":{},"order":5,"mode":0,"inputs":[{"localized_name":"any_value","name":"any_value","shape":7,"type":"*","link":4}],"outputs":[{"localized_name":"string","name":"string","type":"STRING","links":[]}],"properties":{"cnr_id":"comfyui-crystools","ver":"1.27.3","Node name for S&R":"Show any to JSON [Crystools]","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":[]},{"id":4,"type":"FSLMetadataFromImage","pos":[1437.5640869140625,402.2993469238281],"size":[270,82],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"IMAGE","link":2},{"localized_name":"path","name":"path","type":"STRING","widget":{"name":"path"},"link":3},{"localized_name":"strict","name":"strict","shape":7,"type":"BOOLEAN","widget":{"name":"strict"},"link":null}],"outputs":[{"localized_name":"metadata_raw","name":"metadata_raw","type":"METADATA_RAW","links":[4]}],"properties":{"Node name for S&R":"FSLMetadataFromImage","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":["",false]},{"id":1,"type":"Load image with metadata [Crystools]","pos":[606.4518432617188,-214.61428833007812],"size":[570.5427856445312,497.06268310546875],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"image","name":"image","type":"IMAGE","links":null},{"localized_name":"mask","name":"mask","type":"MASK","links":null},{"localized_name":"prompt","name":"prompt","type":"JSON","links":[]},{"localized_name":"Metadata RAW","name":"Metadata RAW","type":"METADATA_RAW","links":[1]}],"properties":{"cnr_id":"comfyui-crystools","ver":"1.27.3","Node name for S&R":"Load image with metadata [Crystools]","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":["fred_lefevre_closeup_of_a_large_metallic_figure_wears_intrica_287bf5be-7120-4403-9da3-cb0f14b6bd1f_0.png","image"]},{"id":6,"type":"Fast Groups Bypasser (rgthree)","pos":[1980.3636474609375,-217.84588623046875],"size":[236.74765014648438,82],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[{"name":"OPT_CONNECTION","type":"*","links":null}],"properties":{"matchColors":"","matchTitle":"","showNav":true,"showAllGraphs":true,"sort":"position","customSortAlphabet":"","toggleRestriction":"default","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}}}],"links":[[1,1,3,2,0,"*"],[2,3,0,4,0,"IMAGE"],[3,3,2,4,1,"STRING"],[4,4,0,5,0,"*"]],"groups":[{"id":1,"title":"Single Image","bounding":[596.4518432617188,-288.21417236328125,1318.3138427734375,580.6626586914062],"color":"#3f789e","font_size":24,"flags":{}},{"id":2,"title":"Batch Loader","bounding":[600.5911865234375,325.78448486328125,1542.685791015625,753.5999755859375],"color":"#3f789e","font_size":24,"flags":{}}],"config":{},"extra":{"ue_links":[],"ds":{"scale":0.5989729227890566,"offset":[427.8159465408812,391.05747207847645]},"links_added_by_ue":[]},"version":0.4} \ No newline at end of file diff --git a/workflows/nano_banana/LoadImage-w-Metadata.png b/workflows/nano_banana/LoadImage-w-Metadata.png new file mode 100644 index 0000000..e20ff32 Binary files /dev/null and b/workflows/nano_banana/LoadImage-w-Metadata.png differ diff --git a/workflows/nano_banana/Nano Banana Iterative-Base.json b/workflows/nano_banana/Nano Banana Iterative-Base.json new file mode 100644 index 0000000..984a019 --- /dev/null +++ b/workflows/nano_banana/Nano Banana Iterative-Base.json @@ -0,0 +1 @@ +{"id":"8308f63e-e1ae-4006-adcf-df07c490ba28","revision":0,"last_node_id":231,"last_link_id":381,"nodes":[{"id":214,"type":"FSLImageMemoryStore","pos":[2613.50146484375,-134.72097778320312],"size":[285.8443298339844,58],"flags":{},"order":10,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"IMAGE","link":381},{"localized_name":"key","name":"key","type":"STRING","widget":{"name":"key"},"link":null}],"outputs":[{"localized_name":"image","name":"image","type":"IMAGE","links":[367,368]}],"properties":{"Node name for S&R":"FSLImageMemoryStore","ue_properties":{"widget_ue_connectable":{"key":true},"version":"7.0.1"}},"widgets_values":["last"]},{"id":222,"type":"FSLImageMemoryRecallSafe","pos":[2595.37353515625,-16.184179306030273],"size":[333.2994079589844,58],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"key","name":"key","type":"STRING","widget":{"name":"key"},"link":null}],"outputs":[{"localized_name":"image","name":"image","type":"IMAGE","links":[372,373,380]}],"properties":{"Node name for S&R":"FSLImageMemoryRecallSafe","ue_properties":{"widget_ue_connectable":{"key":true},"version":"7.0.1"}},"widgets_values":["last"]},{"id":201,"type":"PreviewImage","pos":[1795.44091796875,-649.9224243164062],"size":[663.215576171875,683.7775268554688],"flags":{},"order":7,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":372}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.56","Node name for S&R":"PreviewImage","ue_properties":{"widget_ue_connectable":{},"version":"7.0.1"}},"widgets_values":[]},{"id":110,"type":"PreviewImage","pos":[3018.059814453125,-1052.4462890625],"size":[331.3426208496094,324.6829528808594],"flags":{},"order":12,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":368}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.43","Node name for S&R":"PreviewImage","ue_properties":{"widget_ue_connectable":{},"version":"7.0.1"}},"widgets_values":[],"color":"#223","bgcolor":"#335"},{"id":109,"type":"SaveImage","pos":[3009.668701171875,-659.6617431640625],"size":[781.212646484375,658.311767578125],"flags":{},"order":11,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":367},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.43","Node name for S&R":"SaveImage","ue_properties":{"widget_ue_connectable":{"filename_prefix":true},"version":"7.0.1"}},"widgets_values":["NanoIter\\nanoi"],"color":"#223","bgcolor":"#335"},{"id":229,"type":"Note","pos":[3785.260986328125,-1074.4326171875],"size":[237.19744873046875,88],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[],"properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.2.2","input_ue_unconnectable":{}}},"widgets_values":["It is not necessary to connect this node. Just enter the name of the key to clear and execute the node."],"color":"#432","bgcolor":"#653"},{"id":230,"type":"Note","pos":[3791.572998046875,-909.0707397460938],"size":[240.98435974121094,88],"flags":{},"order":2,"mode":0,"inputs":[],"outputs":[],"properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.2.2","input_ue_unconnectable":{}}},"widgets_values":["This node clears all keys when executed"],"color":"#432","bgcolor":"#653"},{"id":203,"type":"SaveImage","pos":[1722.9217529296875,-998.1715698242188],"size":[405.7691650390625,270],"flags":{"collapsed":false},"order":8,"mode":4,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":373},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.56","Node name for S&R":"SaveImage","ue_properties":{"widget_ue_connectable":{"filename_prefix":true},"version":"7.0.1"}},"widgets_values":["ComfyUI"]},{"id":231,"type":"Note","pos":[2154.365478515625,-992.3828735351562],"size":[326.82110595703125,184.96815490722656],"flags":{},"order":3,"mode":0,"inputs":[],"outputs":[],"properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.2.2","input_ue_unconnectable":{}}},"widgets_values":["Start by clearing key if necessary or enter a new key.\n\nFor the first run set use_init_image to false then enter prompt and run.\n\nFor suubsequent images set use_init_image to true. Enter a new prompt for each iteration."],"color":"#432","bgcolor":"#653"},{"id":200,"type":"FSLPromptCompose","pos":[2537.281494140625,-985.4965209960938],"size":[400,200],"flags":{},"order":4,"mode":0,"inputs":[{"localized_name":"positive","name":"positive","type":"STRING","widget":{"name":"positive"},"link":null},{"localized_name":"negative","name":"negative","type":"STRING","widget":{"name":"negative"},"link":null},{"localized_name":"lock_scene","name":"lock_scene","type":"BOOLEAN","widget":{"name":"lock_scene"},"link":null}],"outputs":[{"localized_name":"prompt","name":"prompt","type":"STRING","links":[379]}],"properties":{"Node name for S&R":"FSLPromptCompose","ue_properties":{"widget_ue_connectable":{"positive":true,"negative":true,"lock_scene":true},"version":"7.0.1"}},"widgets_values":["replace the foundation with a massive log cabin style mansion complete with fountain, and firepit exuding the idea of wealth and power\n","studio backdrop, black background, portrait-only, isolation, cropping",false]},{"id":227,"type":"FSLImageMemoryClear","pos":[3405.308349609375,-1039.0880126953125],"size":[285.8374938964844,58],"flags":{},"order":5,"mode":0,"inputs":[{"localized_name":"key","name":"key","type":"STRING","widget":{"name":"key"},"link":null}],"outputs":[],"properties":{"Node name for S&R":"FSLImageMemoryClear","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":["last"]},{"id":228,"type":"FSLImageMemoryClearAll","pos":[3410.357177734375,-866.1527709960938],"size":[324.8109130859375,56.29530715942383],"flags":{},"order":6,"mode":0,"inputs":[],"outputs":[],"properties":{"Node name for S&R":"FSLImageMemoryClearAll","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":[]},{"id":226,"type":"FSLGeminiGenerateImageV6","pos":[2543.154296875,-712.1513061523438],"size":[400,512],"flags":{},"order":9,"mode":0,"inputs":[{"localized_name":"init_image","name":"init_image","shape":7,"type":"IMAGE","link":380},{"localized_name":"images","name":"images","shape":7,"type":"IMAGE","link":null},{"localized_name":"prompt","name":"prompt","type":"STRING","widget":{"name":"prompt"},"link":379},{"localized_name":"model","name":"model","type":"COMBO","widget":{"name":"model"},"link":null},{"localized_name":"width","name":"width","type":"INT","widget":{"name":"width"},"link":null},{"localized_name":"height","name":"height","type":"INT","widget":{"name":"height"},"link":null},{"localized_name":"temperature","name":"temperature","type":"FLOAT","widget":{"name":"temperature"},"link":null},{"localized_name":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"use_init_image","name":"use_init_image","type":"BOOLEAN","widget":{"name":"use_init_image"},"link":null},{"localized_name":"use_images","name":"use_images","type":"BOOLEAN","widget":{"name":"use_images"},"link":null},{"localized_name":"refresh_models","name":"refresh_models","type":"BOOLEAN","widget":{"name":"refresh_models"},"link":null},{"localized_name":"output_prompt","name":"output_prompt","type":"BOOLEAN","widget":{"name":"output_prompt"},"link":null},{"localized_name":"api_key","name":"api_key","shape":7,"type":"STRING","widget":{"name":"api_key"},"link":null}],"outputs":[{"localized_name":"image","name":"image","type":"IMAGE","links":[381]},{"localized_name":"prompt","name":"prompt","type":"STRING","links":null},{"localized_name":"model","name":"model","type":"STRING","links":null},{"localized_name":"width","name":"width","type":"INT","links":null},{"localized_name":"height","name":"height","type":"INT","links":null},{"localized_name":"temperature","name":"temperature","type":"FLOAT","links":null},{"localized_name":"seed","name":"seed","type":"INT","links":null},{"localized_name":"seed_mode","name":"seed_mode","type":"STRING","links":null},{"localized_name":"metadata","name":"metadata","type":"DICT","links":null}],"properties":{"Node name for S&R":"FSLGeminiGenerateImageV6","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":["","gemini-2.5-flash-image",1024,1024,1,1542538355,"randomize",false,false,false,false,""]}],"links":[[367,214,0,109,0,"IMAGE"],[368,214,0,110,0,"IMAGE"],[372,222,0,201,0,"IMAGE"],[373,222,0,203,0,"IMAGE"],[379,200,0,226,2,"STRING"],[380,222,0,226,0,"IMAGE"],[381,226,0,214,0,"IMAGE"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.8714220715383929,"offset":[-1980.4230494544126,1068.9082954089424]},"frontendVersion":"1.25.10","VHS_MetadataImage":true,"VHS_latentpreview":false,"VHS_KeepIntermediate":true,"VHS_latentpreviewrate":0,"ue_links":[],"links_added_by_ue":[]},"version":0.4} \ No newline at end of file diff --git a/workflows/nano_banana/Nano Banana Iterative-Base.png b/workflows/nano_banana/Nano Banana Iterative-Base.png new file mode 100644 index 0000000..06debbc Binary files /dev/null and b/workflows/nano_banana/Nano Banana Iterative-Base.png differ diff --git a/workflows/nano_banana/Nano Banana Iterative-Load 5 Images.json b/workflows/nano_banana/Nano Banana Iterative-Load 5 Images.json new file mode 100644 index 0000000..f2a9286 --- /dev/null +++ b/workflows/nano_banana/Nano Banana Iterative-Load 5 Images.json @@ -0,0 +1 @@ +{"id":"2288dbf7-786d-489b-a2ed-9e8677912f34","revision":0,"last_node_id":274,"last_link_id":421,"nodes":[{"id":110,"type":"PreviewImage","pos":[2513.16796875,-1120.122314453125],"size":[331.3426208496094,324.6829528808594],"flags":{},"order":20,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":368}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.43","Node name for S&R":"PreviewImage","ue_properties":{"widget_ue_connectable":{},"version":"7.0.1"}},"widgets_values":[],"color":"#223","bgcolor":"#335"},{"id":242,"type":"PreviewImage","pos":[1362.629150390625,-1127.8250732421875],"size":[644.0482177734375,425.1871032714844],"flags":{},"order":15,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":399}],"outputs":[],"title":"Griptape Image","properties":{"cnr_id":"comfy-core","ver":"0.3.65","Node name for S&R":"PreviewImage","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":[]},{"id":245,"type":"FSLGeminiGenerateImageV6","pos":[2060.907958984375,-860.9055786132812],"size":[400,512],"flags":{},"order":16,"mode":0,"inputs":[{"localized_name":"init_image","name":"init_image","shape":7,"type":"IMAGE","link":395},{"localized_name":"images","name":"images","shape":7,"type":"IMAGE","link":null},{"localized_name":"prompt","name":"prompt","type":"STRING","widget":{"name":"prompt"},"link":397},{"localized_name":"model","name":"model","type":"COMBO","widget":{"name":"model"},"link":null},{"localized_name":"width","name":"width","type":"INT","widget":{"name":"width"},"link":null},{"localized_name":"height","name":"height","type":"INT","widget":{"name":"height"},"link":null},{"localized_name":"temperature","name":"temperature","type":"FLOAT","widget":{"name":"temperature"},"link":null},{"localized_name":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"use_init_image","name":"use_init_image","type":"BOOLEAN","widget":{"name":"use_init_image"},"link":null},{"localized_name":"use_images","name":"use_images","type":"BOOLEAN","widget":{"name":"use_images"},"link":null},{"localized_name":"refresh_models","name":"refresh_models","type":"BOOLEAN","widget":{"name":"refresh_models"},"link":null},{"localized_name":"output_prompt","name":"output_prompt","type":"BOOLEAN","widget":{"name":"output_prompt"},"link":null},{"localized_name":"api_key","name":"api_key","shape":7,"type":"STRING","widget":{"name":"api_key"},"link":null}],"outputs":[{"localized_name":"image","name":"image","type":"IMAGE","links":[396]},{"localized_name":"prompt","name":"prompt","type":"STRING","links":null},{"localized_name":"model","name":"model","type":"STRING","links":null},{"localized_name":"width","name":"width","type":"INT","links":null},{"localized_name":"height","name":"height","type":"INT","links":null},{"localized_name":"temperature","name":"temperature","type":"FLOAT","links":null},{"localized_name":"seed","name":"seed","type":"INT","links":null},{"localized_name":"seed_mode","name":"seed_mode","type":"STRING","links":null},{"localized_name":"metadata","name":"metadata","type":"DICT","links":null}],"properties":{"Node name for S&R":"FSLGeminiGenerateImageV6","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":["","gemini-2.5-flash-image-preview",1024,1024,1,1377763067,"randomize",false,true,false,false,""]},{"id":109,"type":"SaveImage","pos":[2511.11083984375,-702.0146484375],"size":[781.212646484375,658.311767578125],"flags":{},"order":19,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":367},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.43","Node name for S&R":"SaveImage","ue_properties":{"widget_ue_connectable":{"filename_prefix":true},"version":"7.0.1"}},"widgets_values":["NanoIter\\nanoi"],"color":"#223","bgcolor":"#335"},{"id":214,"type":"FSLImageMemoryStore","pos":[2064.054443359375,-277.7234802246094],"size":[285.8443298339844,58],"flags":{},"order":18,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"IMAGE","link":396},{"localized_name":"key","name":"key","type":"STRING","widget":{"name":"key"},"link":null}],"outputs":[{"localized_name":"image","name":"image","type":"IMAGE","links":[367,368]}],"properties":{"Node name for S&R":"FSLImageMemoryStore","ue_properties":{"widget_ue_connectable":{"key":true},"version":"7.0.1"}},"widgets_values":["last-2"]},{"id":222,"type":"FSLImageMemoryRecallSafe","pos":[2062.821533203125,-146.02183532714844],"size":[333.2994079589844,58],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"key","name":"key","type":"STRING","widget":{"name":"key"},"link":null}],"outputs":[{"localized_name":"image","name":"image","type":"IMAGE","links":[372,395,399]}],"properties":{"Node name for S&R":"FSLImageMemoryRecallSafe","ue_properties":{"widget_ue_connectable":{"key":true},"version":"7.1","input_ue_unconnectable":{}}},"widgets_values":["last-2"]},{"id":256,"type":"ImageBatchMultiple+","pos":[978.8824462890625,-913.9879150390625],"size":[270,138],"flags":{},"order":17,"mode":0,"inputs":[{"localized_name":"image_1","name":"image_1","type":"IMAGE","link":405},{"localized_name":"image_2","name":"image_2","shape":7,"type":"IMAGE","link":406},{"localized_name":"image_3","name":"image_3","shape":7,"type":"IMAGE","link":407},{"localized_name":"image_4","name":"image_4","shape":7,"type":"IMAGE","link":408},{"localized_name":"image_5","name":"image_5","shape":7,"type":"IMAGE","link":409},{"localized_name":"method","name":"method","type":"COMBO","widget":{"name":"method"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[]}],"properties":{"cnr_id":"comfyui_essentials","ver":"1.1.0","Node name for S&R":"ImageBatchMultiple+","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["lanczos"]},{"id":263,"type":"ImageBatchMultiple+","pos":[978.8824462890625,-913.9879150390625],"size":[270,138],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"image_1","name":"image_1","type":"IMAGE","link":null},{"localized_name":"image_2","name":"image_2","shape":7,"type":"IMAGE","link":null},{"localized_name":"image_3","name":"image_3","shape":7,"type":"IMAGE","link":null},{"localized_name":"image_4","name":"image_4","shape":7,"type":"IMAGE","link":null},{"localized_name":"image_5","name":"image_5","shape":7,"type":"IMAGE","link":null},{"localized_name":"method","name":"method","type":"COMBO","widget":{"name":"method"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[]}],"properties":{"cnr_id":"comfyui_essentials","ver":"1.1.0","Node name for S&R":"ImageBatchMultiple+","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["lanczos"]},{"id":201,"type":"PreviewImage","pos":[1360.77099609375,-645.6987915039062],"size":[663.215576171875,683.7775268554688],"flags":{},"order":14,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":372}],"outputs":[],"title":"Iterative Image","properties":{"cnr_id":"comfy-core","ver":"0.3.56","Node name for S&R":"PreviewImage","ue_properties":{"widget_ue_connectable":{},"version":"7.0.1"}},"widgets_values":[]},{"id":200,"type":"FSLPromptCompose","pos":[2061.289794921875,-1126.2139892578125],"size":[400,200],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"positive","name":"positive","type":"STRING","widget":{"name":"positive"},"link":null},{"localized_name":"negative","name":"negative","type":"STRING","widget":{"name":"negative"},"link":null},{"localized_name":"lock_scene","name":"lock_scene","type":"BOOLEAN","widget":{"name":"lock_scene"},"link":null}],"outputs":[{"localized_name":"prompt","name":"prompt","type":"STRING","links":[397]}],"properties":{"Node name for S&R":"FSLPromptCompose","ue_properties":{"widget_ue_connectable":{"positive":true,"negative":true,"lock_scene":true},"version":"7.0.1"}},"widgets_values":["","studio backdrop, black background, portrait-only, isolation, cropping",false]},{"id":267,"type":"Note","pos":[967.9016723632812,-1112.7979736328125],"size":[260.3798522949219,129.693603515625],"flags":{},"order":3,"mode":0,"inputs":[],"outputs":[],"properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.2.2","input_ue_unconnectable":{}}},"widgets_values":["Image 1 - Scene\nImage 2 - Person\nFor multiple images connect image output f\nrom batch node to 'images' in gemini node\n\nHeight and width in gemini node are for metadata purposes only. they do not effect image."],"color":"#432","bgcolor":"#653"},{"id":249,"type":"Note","pos":[2875.49462890625,-1125.0057373046875],"size":[367.5962219238281,119.58016204833984],"flags":{},"order":4,"mode":0,"inputs":[],"outputs":[],"properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.2.2","input_ue_unconnectable":{}}},"widgets_values":["Node\t Needs wiring?\tEffect\nFSLImageMemoryClearAll\t❌ No\tClears the entire memory dictionary\nFSLImageMemoryClear\t❌ No (✅ optional)\tClears only the key you specify"],"color":"#432","bgcolor":"#653"},{"id":248,"type":"FSLImageMemoryClear","pos":[2886.496337890625,-956.8795166015625],"size":[285.8374938964844,58],"flags":{},"order":5,"mode":0,"inputs":[{"localized_name":"key","name":"key","type":"STRING","widget":{"name":"key"},"link":null}],"outputs":[],"properties":{"Node name for S&R":"FSLImageMemoryClear","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":["last"]},{"id":247,"type":"FSLImageMemoryClearAll","pos":[2889.6025390625,-837.6253051757812],"size":[309.63232421875,46.25725555419922],"flags":{},"order":6,"mode":0,"inputs":[],"outputs":[],"properties":{"Node name for S&R":"FSLImageMemoryClearAll","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":[]},{"id":257,"type":"LoadImage","pos":[973.365966796875,-423.67523193359375],"size":[277.14801025390625,331.3240051269531],"flags":{},"order":7,"mode":4,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[409]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"title":"Load Image 5","properties":{"cnr_id":"comfy-core","ver":"0.3.52","Node name for S&R":"LoadImage","ue_properties":{"widget_ue_connectable":{},"version":"7.0.1"},"widget_ue_connectable":{}},"widgets_values":["00000-998563309.png","image"]},{"id":258,"type":"LoadImage","pos":[668.9918823242188,-423.9723815917969],"size":[277.14801025390625,331.3240051269531],"flags":{},"order":8,"mode":4,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[408]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"title":"Load Image 4","properties":{"cnr_id":"comfy-core","ver":"0.3.52","Node name for S&R":"LoadImage","ue_properties":{"widget_ue_connectable":{},"version":"7.0.1"},"widget_ue_connectable":{}},"widgets_values":["00000-998563309.png","image"]},{"id":259,"type":"LoadImage","pos":[385.9632568359375,-422.0635070800781],"size":[251.13314819335938,328.5221252441406],"flags":{},"order":9,"mode":4,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[407]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"title":"Load Image 3","properties":{"cnr_id":"comfy-core","ver":"0.3.52","Node name for S&R":"LoadImage","ue_properties":{"widget_ue_connectable":{},"version":"7.0.1"},"widget_ue_connectable":{}},"widgets_values":["Screenshot 2025-10-12 185513.png","image"]},{"id":254,"type":"LoadImage","pos":[381.40728759765625,-807.6578369140625],"size":[270,326],"flags":{"collapsed":false},"order":10,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[405]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"title":"Load Image 1","properties":{"cnr_id":"comfy-core","ver":"0.3.52","Node name for S&R":"LoadImage","ue_properties":{"widget_ue_connectable":{},"version":"7.0.1"},"widget_ue_connectable":{}},"widgets_values":["grip_00310_.png","image"]},{"id":255,"type":"LoadImage","pos":[673.3596801757812,-806.506103515625],"size":[276.2181701660156,326],"flags":{},"order":11,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[406]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"title":"Load Image 2","properties":{"cnr_id":"comfy-core","ver":"0.3.52","Node name for S&R":"LoadImage","ue_properties":{"widget_ue_connectable":{},"version":"7.0.1"},"widget_ue_connectable":{}},"widgets_values":["2025-10-02-111049_1975936534.png","image"]},{"id":250,"type":"Note","pos":[387.67437744140625,-1074.2576904296875],"size":[347.63018798828125,198.10414123535156],"flags":{},"order":12,"mode":0,"inputs":[],"outputs":[],"properties":{"ue_properties":{"widget_ue_connectable":{},"version":"7.2.2","input_ue_unconnectable":{}}},"widgets_values":["To start:\n\n1. set use_ini_image = false\n2. set use_images = true\n3. Enter positive prompt \n\nFor subsequent iterations:\n\n4. set use_ini_image = true (leave true for subsequent runs)\n5. set use_images = false\n6. bypass load image group"],"color":"#432","bgcolor":"#653"},{"id":274,"type":"Fast Groups Bypasser (rgthree)","pos":[96.36329650878906,-1114.8670654296875],"size":[236.74765014648438,82],"flags":{},"order":13,"mode":0,"inputs":[],"outputs":[{"name":"OPT_CONNECTION","type":"*","links":null}],"properties":{"matchColors":"","matchTitle":"","showNav":true,"showAllGraphs":true,"sort":"position","customSortAlphabet":"","toggleRestriction":"default","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}}}],"links":[[367,214,0,109,0,"IMAGE"],[368,214,0,110,0,"IMAGE"],[372,222,0,201,0,"IMAGE"],[395,222,0,245,0,"IMAGE"],[396,245,0,214,0,"IMAGE"],[397,200,0,245,2,"STRING"],[399,222,0,242,0,"IMAGE"],[405,254,0,256,0,"IMAGE"],[406,255,0,256,1,"IMAGE"],[407,259,0,256,2,"IMAGE"],[408,258,0,256,3,"IMAGE"],[409,257,0,256,4,"IMAGE"]],"groups":[{"id":2,"title":"Iterative Nano Banana","bounding":[1343.6209716796875,-1209.766357421875,1961.9517822265625,1260.2283935546875],"color":"#3f789e","font_size":24,"flags":{}},{"id":3,"title":"Images","bounding":[355.9539489746094,-1201.8511962890625,936.4111328125,1140.2022705078125],"color":"#3f789e","font_size":24,"flags":{}}],"config":{},"extra":{"ds":{"scale":0.7765255956009504,"offset":[222.8599872846134,1406.5581919024655]},"frontendVersion":"1.25.10","VHS_MetadataImage":true,"VHS_latentpreview":false,"VHS_KeepIntermediate":true,"VHS_latentpreviewrate":0,"ue_links":[],"links_added_by_ue":[]},"version":0.4} \ No newline at end of file diff --git a/workflows/nano_banana/Nano Banana Iterative-Load 5 Images.png b/workflows/nano_banana/Nano Banana Iterative-Load 5 Images.png new file mode 100644 index 0000000..df736e3 Binary files /dev/null and b/workflows/nano_banana/Nano Banana Iterative-Load 5 Images.png differ diff --git a/workflows/nano_banana/Nano Banana w_Griptape w_Upscaler.json b/workflows/nano_banana/Nano Banana w_Griptape w_Upscaler.json new file mode 100644 index 0000000..21ae8a6 --- /dev/null +++ b/workflows/nano_banana/Nano Banana w_Griptape w_Upscaler.json @@ -0,0 +1 @@ +{"id":"d63c542e-7e99-454c-9b48-08f0dd2486b2","revision":0,"last_node_id":237,"last_link_id":392,"nodes":[{"id":190,"type":"Griptape Create: Rules","pos":[1362.9952392578125,-988.393310546875],"size":[380,160],"flags":{"collapsed":true},"order":0,"mode":0,"inputs":[{"localized_name":"name","name":"name","type":"STRING","widget":{"name":"name"},"link":null},{"localized_name":"rules","name":"rules","type":"STRING","widget":{"name":"rules"},"link":null}],"outputs":[{"localized_name":"RULES","name":"RULES","type":"RULESET","links":[308]},{"localized_name":"NAME","name":"NAME","type":"STRING","links":null}],"title":"NSFW Rules","properties":{"cnr_id":"comfyui-griptape","ver":"2a70afd0f3d6118969cd40565e07376105661a21","Node name for S&R":"Griptape Create: Rules","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["NSFW Blocker","Never include nudity, suggestive content, or explicit scenes in any prompts.\nAvoid adult themes, partial nudity, or sexual innuendo. Keep all prompts family friendly.\n"]},{"id":191,"type":"SetNode","pos":[1902.994873046875,-528.393798828125],"size":[210,34],"flags":{"collapsed":true},"order":18,"mode":0,"inputs":[{"name":"IMAGE","type":"IMAGE","link":301}],"outputs":[{"name":"*","type":"*","links":[]}],"title":"Set_GT-IMG-BAS-2","properties":{"previousName":"","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["GT-IMG-BAS-2"],"color":"#2a363b","bgcolor":"#3f5159"},{"id":192,"type":"SetNode","pos":[1902.994873046875,-608.3941040039062],"size":[210,34],"flags":{"collapsed":true},"order":19,"mode":0,"inputs":[{"name":"IMAGE","type":"IMAGE","link":302}],"outputs":[{"name":"*","type":"*","links":null}],"title":"Set_GT-IMG-BAS-1","properties":{"previousName":"","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["GT-IMG-BAS-1"],"color":"#2a363b","bgcolor":"#3f5159"},{"id":193,"type":"SetNode","pos":[1913.88818359375,-478.66455078125],"size":[210,34],"flags":{"collapsed":true},"order":20,"mode":0,"inputs":[{"name":"IMAGE","type":"IMAGE","link":303}],"outputs":[{"name":"*","type":"*","links":null}],"title":"Set_GT-IMG-BAS-3","properties":{"previousName":"","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["GT-IMG-BAS-3"],"color":"#2a363b","bgcolor":"#3f5159"},{"id":194,"type":"Griptape Create: Rules","pos":[1365.3927001953125,-937.1946411132812],"size":[400,200],"flags":{"collapsed":true},"order":1,"mode":0,"inputs":[{"localized_name":"name","name":"name","type":"STRING","widget":{"name":"name"},"link":null},{"localized_name":"rules","name":"rules","type":"STRING","widget":{"name":"rules"},"link":null}],"outputs":[{"localized_name":"RULES","name":"RULES","type":"RULESET","links":[310]},{"localized_name":"NAME","name":"NAME","type":"STRING","links":null}],"title":"General Rules","properties":{"cnr_id":"comfyui-griptape","ver":"2a70afd0f3d6118969cd40565e07376105661a21","Node name for S&R":"Griptape Create: Rules","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["My rules","You are an expert in creating image generation rules that are high quality and very beautiful.\nYou are an expert in creating amazing images of cats.\nAlways include the following information in the prompt: composition, lighting, design, style, camera lens information, camera angle, time of day, detailed description of character and emotion of the image."]},{"id":195,"type":"SetNode","pos":[1589.3367919921875,-186.8256378173828],"size":[210,58],"flags":{},"order":15,"mode":0,"inputs":[{"name":"STRING","type":"STRING","link":304}],"outputs":[{"name":"*","type":"*","links":null}],"title":"Set_GT-Clip-Encode","properties":{"previousName":"","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["GT-Clip-Encode"]},{"id":196,"type":"Griptape Create: Image from Text","pos":[1827.150146484375,-650.7247924804688],"size":[403.1999816894531,200],"flags":{},"order":16,"mode":0,"inputs":[{"localized_name":"input_string","name":"input_string","shape":7,"type":"STRING","link":305},{"localized_name":"agent","name":"agent","shape":7,"type":"AGENT","link":306},{"localized_name":"key_value_replacement","name":"key_value_replacement","shape":7,"type":"DICT","link":null},{"localized_name":"driver","name":"driver","shape":7,"type":"DRIVER","link":307},{"localized_name":"STRING","name":"STRING","type":"STRING","widget":{"name":"STRING"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[301,302,303,313,314]},{"localized_name":"AGENT","name":"AGENT","type":"AGENT","links":null},{"localized_name":"file_path","name":"file_path","type":"STRING","links":null}],"properties":{"cnr_id":"comfyui-griptape","ver":"2a70afd0f3d6118969cd40565e07376105661a21","Node name for S&R":"Griptape Create: Image from Text","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":[""]},{"id":199,"type":"Griptape Create: Rules","pos":[1350.4224853515625,-887.3697509765625],"size":[400,200],"flags":{"collapsed":true},"order":2,"mode":0,"inputs":[{"localized_name":"name","name":"name","type":"STRING","widget":{"name":"name"},"link":null},{"localized_name":"rules","name":"rules","type":"STRING","widget":{"name":"rules"},"link":null}],"outputs":[{"localized_name":"RULES","name":"RULES","type":"RULESET","links":[309]},{"localized_name":"NAME","name":"NAME","type":"STRING","links":null}],"properties":{"cnr_id":"comfyui-griptape","ver":"2a70afd0f3d6118969cd40565e07376105661a21","Node name for S&R":"Griptape Create: Rules","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["My rules","dark background\nthe magic spiral\nthe golden hour"]},{"id":206,"type":"CLIPTextEncode","pos":[3822.333740234375,-583.5554809570312],"size":[300,100],"flags":{},"order":10,"mode":0,"inputs":[{"localized_name":"clip","name":"clip","type":"CLIP","link":316},{"localized_name":"text","name":"text","type":"STRING","widget":{"name":"text"},"link":null}],"outputs":[{"localized_name":"CONDITIONING","name":"CONDITIONING","type":"CONDITIONING","slot_index":0,"links":[318]}],"title":"Positive Prompt","properties":{"cnr_id":"comfy-core","ver":"0.3.29","Node name for S&R":"CLIPTextEncode","ue_properties":{"version":"7.0.1","widget_ue_connectable":{"text":true}}},"widgets_values":["highly detailed, sharp focus, 8k"]},{"id":209,"type":"SaveImage","pos":[5820.3291015625,-545.6284790039062],"size":[869.017333984375,816.9860229492188],"flags":{},"order":30,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":322},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.29","Node name for S&R":"SaveImage","ue_properties":{"version":"7.0.1","widget_ue_connectable":{"filename_prefix":true}}},"widgets_values":["upscaled\\ups0"]},{"id":211,"type":"UnsharpMask","pos":[4544.38427734375,-815.3297729492188],"size":[300,314],"flags":{},"order":28,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":324},{"localized_name":"kernel_size","name":"kernel_size","type":"INT","widget":{"name":"kernel_size"},"link":null},{"localized_name":"sigma","name":"sigma","type":"FLOAT","widget":{"name":"sigma"},"link":null},{"name":"image","type":"IMAGE","link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","slot_index":0,"links":[323,328]}],"properties":{"cnr_id":"comfyui_imageprocessing","ver":"1.0.0","Node name for S&R":"UnsharpMask","ue_properties":{"version":"7.0.1","widget_ue_connectable":{"kernel_size":true,"sigma":true}}},"widgets_values":[3,1.0900000000000003]},{"id":214,"type":"Fast Bypasser (rgthree)","pos":[4539.89453125,-424.6376037597656],"size":[320.79998779296875,211.26718139648438],"flags":{},"order":32,"mode":0,"inputs":[{"dir":3,"name":"Restore Face 🌌 ReActor","type":"*","link":327},{"dir":3,"name":"Unsharp Mask","type":"*","link":328},{"dir":3,"name":"Load LoRA","type":"*","link":329},{"dir":3,"name":"","type":"*","link":null}],"outputs":[{"dir":4,"name":"OPT_CONNECTION","type":"*","links":null}],"properties":{"toggleRestriction":"default","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}}},{"id":215,"type":"CLIPTextEncode","pos":[3824.068115234375,-431.4895935058594],"size":[300,100],"flags":{},"order":11,"mode":0,"inputs":[{"localized_name":"clip","name":"clip","type":"CLIP","link":330},{"localized_name":"text","name":"text","type":"STRING","widget":{"name":"text"},"link":null}],"outputs":[{"localized_name":"CONDITIONING","name":"CONDITIONING","type":"CONDITIONING","slot_index":0,"links":[319]}],"title":"Negative Prompt","properties":{"cnr_id":"comfy-core","ver":"0.3.29","Node name for S&R":"CLIPTextEncode","ue_properties":{"version":"7.0.1","widget_ue_connectable":{"text":true}}},"widgets_values":["blurry, deformed, low quality"]},{"id":217,"type":"UpscaleModelLoader","pos":[3819.691162109375,-284.2436828613281],"size":[315,58],"flags":{},"order":3,"mode":0,"inputs":[{"localized_name":"model_name","name":"model_name","type":"COMBO","widget":{"name":"model_name"},"link":null}],"outputs":[{"localized_name":"UPSCALE_MODEL","name":"UPSCALE_MODEL","type":"UPSCALE_MODEL","links":[321]}],"properties":{"cnr_id":"comfy-core","ver":"0.3.29","Node name for S&R":"UpscaleModelLoader","ue_properties":{"version":"7.0.1","widget_ue_connectable":{"model_name":true}}},"widgets_values":["4x_foolhardy_Remacri.pth"]},{"id":218,"type":"CheckpointLoaderSimple","pos":[3815.888916015625,-177.26158142089844],"size":[315,98],"flags":{},"order":4,"mode":0,"inputs":[{"localized_name":"ckpt_name","name":"ckpt_name","type":"COMBO","widget":{"name":"ckpt_name"},"link":null}],"outputs":[{"localized_name":"MODEL","name":"MODEL","type":"MODEL","links":[332]},{"localized_name":"CLIP","name":"CLIP","type":"CLIP","links":[316,330,333]},{"localized_name":"VAE","name":"VAE","type":"VAE","links":[320]}],"properties":{"cnr_id":"comfy-core","ver":"0.3.29","Node name for S&R":"CheckpointLoaderSimple","ue_properties":{"version":"7.0.1","widget_ue_connectable":{"ckpt_name":true}}},"widgets_values":["realvisxlV40_v40LightningBakedvae.safetensors"]},{"id":219,"type":"LoraLoader","pos":[4558.12890625,-154.80162048339844],"size":[300,126],"flags":{},"order":12,"mode":0,"inputs":[{"localized_name":"model","name":"model","type":"MODEL","link":332},{"localized_name":"clip","name":"clip","type":"CLIP","link":333},{"localized_name":"lora_name","name":"lora_name","type":"COMBO","widget":{"name":"lora_name"},"link":null},{"localized_name":"strength_model","name":"strength_model","type":"FLOAT","widget":{"name":"strength_model"},"link":null},{"localized_name":"strength_clip","name":"strength_clip","type":"FLOAT","widget":{"name":"strength_clip"},"link":null}],"outputs":[{"localized_name":"MODEL","name":"MODEL","type":"MODEL","slot_index":0,"links":[317,329]},{"localized_name":"CLIP","name":"CLIP","type":"CLIP","slot_index":1,"links":[]}],"properties":{"cnr_id":"comfy-core","ver":"0.3.29","Node name for S&R":"LoraLoader","ue_properties":{"version":"7.0.1","widget_ue_connectable":{"lora_name":true,"strength_model":true,"strength_clip":true}}},"widgets_values":["SDXLFaeTastic2400.safetensors",0.4000000000000001,0.4000000000000001]},{"id":197,"type":"Griptape Driver: OpenAI Image Generation","pos":[1702.9951171875,-1028.3931884765625],"size":[504,130],"flags":{},"order":5,"mode":0,"inputs":[{"localized_name":"image_generation_model","name":"image_generation_model","shape":7,"type":"COMBO","widget":{"name":"image_generation_model"},"link":null},{"localized_name":"size","name":"size","shape":7,"type":"COMBO","widget":{"name":"size"},"link":null},{"localized_name":"api_key_env_var","name":"api_key_env_var","shape":7,"type":"STRING","widget":{"name":"api_key_env_var"},"link":null}],"outputs":[{"localized_name":"DRIVER","name":"DRIVER","type":"DRIVER","links":[307]}],"properties":{"cnr_id":"comfyui-griptape","ver":"2a70afd0f3d6118969cd40565e07376105661a21","Node name for S&R":"Griptape Driver: OpenAI Image Generation","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["dall-e-3","1024x1024","OPENAI_API_KEY",null]},{"id":208,"type":"Image Resize","pos":[4183.060546875,-1022.1375732421875],"size":[315,178],"flags":{},"order":6,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"IMAGE","link":null},{"localized_name":"mode","name":"mode","type":"COMBO","widget":{"name":"mode"},"link":null},{"localized_name":"supersample","name":"supersample","type":"COMBO","widget":{"name":"supersample"},"link":null},{"localized_name":"resampling","name":"resampling","type":"COMBO","widget":{"name":"resampling"},"link":null},{"localized_name":"rescale_factor","name":"rescale_factor","type":"FLOAT","widget":{"name":"rescale_factor"},"link":null},{"localized_name":"resize_width","name":"resize_width","type":"INT","widget":{"name":"resize_width"},"link":null},{"localized_name":"resize_height","name":"resize_height","type":"INT","widget":{"name":"resize_height"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[]}],"properties":{"cnr_id":"was-node-suite-comfyui","ver":"1014f8a1477b8ae0144e16ed4fd6476cd109fb23","Node name for S&R":"Image Resize","ue_properties":{"version":"7.0.1","widget_ue_connectable":{"mode":true,"supersample":true,"resampling":true,"rescale_factor":true,"resize_width":true,"resize_height":true}}},"widgets_values":["rescale","true","lanczos",2.0000000000000004,1024,988]},{"id":207,"type":"UltimateSDUpscaleCustomSample","pos":[4159.59716796875,-569.7019653320312],"size":[346,676],"flags":{},"order":27,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"IMAGE","link":360},{"localized_name":"model","name":"model","type":"MODEL","link":317},{"localized_name":"positive","name":"positive","type":"CONDITIONING","link":318},{"localized_name":"negative","name":"negative","type":"CONDITIONING","link":319},{"localized_name":"vae","name":"vae","type":"VAE","link":320},{"localized_name":"upscale_model","name":"upscale_model","shape":7,"type":"UPSCALE_MODEL","link":321},{"localized_name":"custom_sampler","name":"custom_sampler","shape":7,"type":"SAMPLER","link":null},{"localized_name":"custom_sigmas","name":"custom_sigmas","shape":7,"type":"SIGMAS","link":null},{"localized_name":"upscale_by","name":"upscale_by","type":"FLOAT","widget":{"name":"upscale_by"},"link":null},{"localized_name":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"steps","name":"steps","type":"INT","widget":{"name":"steps"},"link":null},{"localized_name":"cfg","name":"cfg","type":"FLOAT","widget":{"name":"cfg"},"link":null},{"localized_name":"sampler_name","name":"sampler_name","type":"COMBO","widget":{"name":"sampler_name"},"link":null},{"localized_name":"scheduler","name":"scheduler","type":"COMBO","widget":{"name":"scheduler"},"link":null},{"localized_name":"denoise","name":"denoise","type":"FLOAT","widget":{"name":"denoise"},"link":null},{"localized_name":"mode_type","name":"mode_type","type":"COMBO","widget":{"name":"mode_type"},"link":null},{"localized_name":"tile_width","name":"tile_width","type":"INT","widget":{"name":"tile_width"},"link":null},{"localized_name":"tile_height","name":"tile_height","type":"INT","widget":{"name":"tile_height"},"link":null},{"localized_name":"mask_blur","name":"mask_blur","type":"INT","widget":{"name":"mask_blur"},"link":null},{"localized_name":"tile_padding","name":"tile_padding","type":"INT","widget":{"name":"tile_padding"},"link":null},{"localized_name":"seam_fix_mode","name":"seam_fix_mode","type":"COMBO","widget":{"name":"seam_fix_mode"},"link":null},{"localized_name":"seam_fix_denoise","name":"seam_fix_denoise","type":"FLOAT","widget":{"name":"seam_fix_denoise"},"link":null},{"localized_name":"seam_fix_width","name":"seam_fix_width","type":"INT","widget":{"name":"seam_fix_width"},"link":null},{"localized_name":"seam_fix_mask_blur","name":"seam_fix_mask_blur","type":"INT","widget":{"name":"seam_fix_mask_blur"},"link":null},{"localized_name":"seam_fix_padding","name":"seam_fix_padding","type":"INT","widget":{"name":"seam_fix_padding"},"link":null},{"localized_name":"force_uniform_tiles","name":"force_uniform_tiles","type":"BOOLEAN","widget":{"name":"force_uniform_tiles"},"link":null},{"localized_name":"tiled_decode","name":"tiled_decode","type":"BOOLEAN","widget":{"name":"tiled_decode"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[324]}],"properties":{"cnr_id":"comfyui_ultimatesdupscale","ver":"778a475dde8116a2066fe07f6c9ca15554e0b5be","Node name for S&R":"UltimateSDUpscaleCustomSample","ue_properties":{"version":"7.0.1","widget_ue_connectable":{"upscale_by":true,"seed":true,"steps":true,"cfg":true,"sampler_name":true,"scheduler":true,"denoise":true,"mode_type":true,"tile_width":true,"tile_height":true,"mask_blur":true,"tile_padding":true,"seam_fix_mode":true,"seam_fix_denoise":true,"seam_fix_width":true,"seam_fix_mask_blur":true,"seam_fix_padding":true,"force_uniform_tiles":true,"tiled_decode":true}}},"widgets_values":[2,469207506418355,"randomize",12,2,"dpm_2","exponential",0.5000000000000001,"Linear",1024,1024,50,104,"None",1,304,64,304,false,false]},{"id":205,"type":"SaveImage","pos":[2275.5517578125,-656.6166381835938],"size":[523.1109619140625,464.4971618652344],"flags":{},"order":22,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":314},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.27","Node name for S&R":"SaveImage","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["griptape\\grip"]},{"id":198,"type":"Griptape Combine: Rules List","pos":[1334.1939697265625,-830.0010986328125],"size":[352.79998779296875,86],"flags":{"collapsed":true},"order":9,"mode":0,"inputs":[{"localized_name":"rules_1","name":"rules_1","shape":7,"type":"RULESET","link":308},{"name":"rules_2","type":"RULESET","link":309},{"name":"rules_3","type":"RULESET","link":310},{"name":"rules_4","type":"RULESET","link":null}],"outputs":[{"localized_name":"RULESET","name":"RULESET","type":"RULESET","links":[311]}],"properties":{"cnr_id":"comfyui-griptape","ver":"2a70afd0f3d6118969cd40565e07376105661a21","Node name for S&R":"Griptape Combine: Rules List","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":[]},{"id":228,"type":"FSLEnsureNHWCBatch","pos":[3846.474853515625,-800.3880615234375],"size":[208.72714233398438,26],"flags":{},"order":24,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"IMAGE","link":389}],"outputs":[{"localized_name":"image_nhwc","name":"image_nhwc","type":"IMAGE","links":[360,361]}],"properties":{"Node name for S&R":"FSLEnsureNHWCBatch","ue_properties":{"widget_ue_connectable":{},"version":"7.1","input_ue_unconnectable":{}}},"widgets_values":[]},{"id":110,"type":"PreviewImage","pos":[3373.929443359375,-1019.1917114257812],"size":[326.4037780761719,290.91656494140625],"flags":{},"order":25,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":390}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.43","Node name for S&R":"PreviewImage","ue_properties":{"widget_ue_connectable":{},"version":"7.0.1"}},"widgets_values":[],"color":"#223","bgcolor":"#335"},{"id":109,"type":"SaveImage","pos":[3359.13525390625,-678.221923828125],"size":[349.9873352050781,391.2630310058594],"flags":{},"order":26,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":391},{"localized_name":"filename_prefix","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.43","Node name for S&R":"SaveImage","ue_properties":{"widget_ue_connectable":{"filename_prefix":true},"version":"7.0.1"}},"widgets_values":["nanob\\nano"],"color":"#223","bgcolor":"#335"},{"id":210,"type":"ReActorRestoreFace","pos":[4535.76513671875,-1011.4796142578125],"size":[315,130],"flags":{},"order":29,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"IMAGE","link":323},{"localized_name":"facedetection","name":"facedetection","type":"COMBO","widget":{"name":"facedetection"},"link":null},{"localized_name":"model","name":"model","type":"COMBO","widget":{"name":"model"},"link":null},{"localized_name":"visibility","name":"visibility","type":"FLOAT","widget":{"name":"visibility"},"link":null},{"localized_name":"codeformer_weight","name":"codeformer_weight","type":"FLOAT","widget":{"name":"codeformer_weight"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[322,325,327,331,382]}],"properties":{"Node name for S&R":"ReActorRestoreFace","cnr_id":"comfyui-reactor","ver":"d901609a1d5d1942a6b069b2f8f3778fee3a7134","ue_properties":{"version":"7.0.1","widget_ue_connectable":{"facedetection":true,"model":true,"visibility":true,"codeformer_weight":true}}},"widgets_values":["retinaface_resnet50","none",1,0.5]},{"id":234,"type":"Preview from metadata [Crystools]","pos":[3497.969970703125,-201.40306091308594],"size":[210.32537841796875,222.50999450683594],"flags":{},"order":35,"mode":0,"inputs":[{"localized_name":"metadata_raw","name":"metadata_raw","shape":7,"type":"METADATA_RAW","link":384}],"outputs":[{"localized_name":"Metadata RAW","name":"Metadata RAW","type":"METADATA_RAW","links":null}],"properties":{"cnr_id":"comfyui-crystools","ver":"1.27.3","Node name for S&R":"Preview from metadata [Crystools]","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":[]},{"id":235,"type":"PreviewImage","pos":[3495.722900390625,70.34211730957031],"size":[228.71023559570312,246],"flags":{},"order":36,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":385}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.63","Node name for S&R":"PreviewImage","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":[]},{"id":212,"type":"PreviewImage","pos":[4953.79248046875,-920.6201171875],"size":[362.68011474609375,296.4696960449219],"flags":{},"order":31,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":325}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.29","Node name for S&R":"PreviewImage","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":[]},{"id":216,"type":"Image Comparer (rgthree)","pos":[4898.138671875,-531.0244140625],"size":[875.252197265625,822.8955688476562],"flags":{},"order":33,"mode":0,"inputs":[{"dir":3,"name":"image_a","type":"IMAGE","link":331},{"dir":3,"name":"image_b","type":"IMAGE","link":361}],"outputs":[],"properties":{"cnr_id":"rgthree-comfy","ver":"5dc53323e07a021038af9f2a4a06ebc071f7218c","comparer_mode":"Slide","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":[[{"name":"A","selected":true,"url":"/api/view?filename=rgthree.compare._temp_xpppg_00003_.png&type=temp&subfolder=&rand=0.805584959104855"},{"name":"B","selected":true,"url":"/api/view?filename=rgthree.compare._temp_xpppg_00004_.png&type=temp&subfolder=&rand=0.24991398835054868"}]],"color":"#322","bgcolor":"#533"},{"id":202,"type":"PreviewImage","pos":[2267.40625,-1057.9176025390625],"size":[509.1957702636719,333.4749755859375],"flags":{},"order":21,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":313}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.27","Node name for S&R":"PreviewImage","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":[]},{"id":200,"type":"Griptape Create: Agent","pos":[1331.383056640625,-757.8782348632812],"size":[456.1457214355469,322.3581848144531],"flags":{},"order":13,"mode":0,"inputs":[{"localized_name":"agent","name":"agent","shape":7,"type":"AGENT","link":null},{"localized_name":"config","name":"config","shape":7,"type":"CONFIG","link":null},{"localized_name":"tools","name":"tools","shape":7,"type":"TOOL_LIST","link":null},{"localized_name":"rulesets","name":"rulesets","shape":7,"type":"RULESET","link":311},{"localized_name":"input_string","name":"input_string","shape":7,"type":"STRING","link":null},{"localized_name":"key_value_replacement","name":"key_value_replacement","shape":7,"type":"DICT","link":null},{"localized_name":"STRING","name":"STRING","shape":7,"type":"STRING","widget":{"name":"STRING"},"link":null},{"localized_name":"max_subtasks","name":"max_subtasks","shape":7,"type":"INT","widget":{"name":"max_subtasks"},"link":null}],"outputs":[{"localized_name":"OUTPUT","name":"OUTPUT","type":"STRING","links":[312]},{"localized_name":"AGENT","name":"AGENT","type":"AGENT","links":[306]}],"properties":{"cnr_id":"comfyui-griptape","ver":"2a70afd0f3d6118969cd40565e07376105661a21","Node name for S&R":"Griptape Create: Agent","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["image of a hat Made of laughter — sound waves forming sculptural ripples. the hat should look as thought it would fit on a womans head",3]},{"id":201,"type":"Griptape Display: Text","pos":[1433.193603515625,-366.17669677734375],"size":[640,480],"flags":{},"order":14,"mode":0,"inputs":[{"localized_name":"INPUT","name":"INPUT","shape":7,"type":"STRING","link":312},{"localized_name":"STRING","name":"STRING","shape":7,"type":"STRING","widget":{"name":"STRING"},"link":null}],"outputs":[{"localized_name":"OUTPUT","name":"OUTPUT","type":"STRING","links":[304,305,315]}],"properties":{"cnr_id":"comfyui-griptape","ver":"2a70afd0f3d6118969cd40565e07376105661a21","Node name for S&R":"Griptape Display: Text","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["Certainly! Here’s a detailed image generation prompt for your request, following all your rules:\n\n**Prompt:** \nA sculptural hat designed to fit elegantly on a woman’s head, crafted from rippling forms that resemble sound waves frozen in motion—each wave representing laughter, creating a dynamic, joyful texture. The hat’s structure is airy and fluid, with soft, undulating curves that spiral upward, evoking the magic spiral. The background is dark, enhancing the luminous, golden-hour lighting that gently highlights the contours and translucency of the hat. The composition is a close-up portrait, shot at a slight angle from above to showcase both the wearer’s serene, joyful expression and the intricate design of the hat. The style is modern and artistic, with a touch of surrealism. Use a 50mm lens for a natural perspective and shallow depth of field, focusing on the hat and the woman’s face, softly blurring the background for emphasis.\n\n**Summary:** \n- Composition: Close-up portrait, slight angle from above \n- Lighting: Golden hour, soft and luminous \n- Design: Sculptural hat of laughter, sound wave ripples, magic spiral \n- Style: Modern, artistic, surreal \n- Camera: 50mm lens, shallow depth of field \n- Time of day: Golden hour \n- Character: Woman, serene and joyful \n- Emotion: Joy, wonder \n- Background: Dark for contrast and elegance"]},{"id":94,"type":"ComfyUIDeployExternalText","pos":[2886.167236328125,-1039.5758056640625],"size":[391.5573425292969,244.14918518066406],"flags":{},"order":17,"mode":0,"inputs":[{"localized_name":"input_id","name":"input_id","type":"STRING","widget":{"name":"input_id"},"link":null},{"localized_name":"default_value","name":"default_value","shape":7,"type":"STRING","widget":{"name":"default_value"},"link":315},{"localized_name":"display_name","name":"display_name","shape":7,"type":"STRING","widget":{"name":"display_name"},"link":null},{"localized_name":"description","name":"description","shape":7,"type":"STRING","widget":{"name":"description"},"link":null}],"outputs":[{"localized_name":"text","name":"text","type":"STRING","links":[388]}],"title":"PROMPT","properties":{"cnr_id":"comfyui-deploy","ver":"b889f79baf9e099d5e54bd20bab4aa1e7c3296c0","Node name for S&R":"ComfyUIDeployExternalText","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}},"widgets_values":["ACTION_MANUAL_PROMPT","a photorealistic orange tabby cat wearing scuba gear, underwater, 1:1","MANUA_PROMPT ","IF there is no OPENAI_API_KEY on the machine secrets. You will need to enter your full prompt and delete the AI_SYSTEM_PROMPT \n\nOtherwise you can use this to add a The Task to be preform by the model for example \"replace the cat from image1 with the dog on image2\" \n\nshe is wearing the same clothes but it has the logo on the swimsuit make sure it looks well integrated and part of the same material with the fabric and not just an overlay the logo should wrap with the swinsuit to the body of the model "],"color":"#232","bgcolor":"#353"},{"id":230,"type":"LoadImage","pos":[2894.280517578125,-53.485755920410156],"size":[274.080078125,314],"flags":{},"order":7,"mode":0,"inputs":[{"localized_name":"image","name":"image","type":"COMBO","widget":{"name":"image"},"link":null},{"localized_name":"choose file to upload","name":"upload","type":"IMAGEUPLOAD","widget":{"name":"upload"},"link":null}],"outputs":[{"localized_name":"IMAGE","name":"IMAGE","type":"IMAGE","links":[387]},{"localized_name":"MASK","name":"MASK","type":"MASK","links":null}],"properties":{"cnr_id":"comfy-core","ver":"0.3.59","Node name for S&R":"LoadImage","ue_properties":{"widget_ue_connectable":{"image":true,"upload":true},"version":"7.1","input_ue_unconnectable":{}}},"widgets_values":["01_FRAME-1024-150.png","image"]},{"id":233,"type":"FSLImageSaverWithMetadataV5","pos":[3203.047607421875,-138.11155700683594],"size":[268.4547119140625,462],"flags":{},"order":34,"mode":0,"inputs":[{"localized_name":"images","name":"images","type":"IMAGE","link":382},{"localized_name":"external_metadata","name":"external_metadata","shape":7,"type":"DICT","link":392},{"localized_name":"filename","name":"filename","type":"STRING","widget":{"name":"filename"},"link":null},{"localized_name":"save_to_subfolder","name":"save_to_subfolder","type":"STRING","widget":{"name":"save_to_subfolder"},"link":null},{"localized_name":"append_datetime","name":"append_datetime","shape":7,"type":"BOOLEAN","widget":{"name":"append_datetime"},"link":null},{"localized_name":"model_string","name":"model_string","shape":7,"type":"STRING","widget":{"name":"model_string"},"link":null},{"localized_name":"modelname","name":"modelname","shape":7,"type":"STRING","widget":{"name":"modelname"},"link":null},{"localized_name":"seed_string","name":"seed_string","shape":7,"type":"STRING","widget":{"name":"seed_string"},"link":null},{"localized_name":"width_string","name":"width_string","shape":7,"type":"STRING","widget":{"name":"width_string"},"link":null},{"localized_name":"height_string","name":"height_string","shape":7,"type":"STRING","widget":{"name":"height_string"},"link":null},{"localized_name":"temperature_string","name":"temperature_string","shape":7,"type":"STRING","widget":{"name":"temperature_string"},"link":null},{"localized_name":"positive_string","name":"positive_string","shape":7,"type":"STRING","widget":{"name":"positive_string"},"link":null},{"localized_name":"negative_string","name":"negative_string","shape":7,"type":"STRING","widget":{"name":"negative_string"},"link":null},{"localized_name":"cfg_string","name":"cfg_string","shape":7,"type":"STRING","widget":{"name":"cfg_string"},"link":null},{"localized_name":"steps_string","name":"steps_string","shape":7,"type":"STRING","widget":{"name":"steps_string"},"link":null},{"localized_name":"sampler_string","name":"sampler_string","shape":7,"type":"STRING","widget":{"name":"sampler_string"},"link":null},{"localized_name":"scheduler_string","name":"scheduler_string","shape":7,"type":"STRING","widget":{"name":"scheduler_string"},"link":null},{"localized_name":"guidance_scale_string","name":"guidance_scale_string","shape":7,"type":"STRING","widget":{"name":"guidance_scale_string"},"link":null},{"localized_name":"watermark_string","name":"watermark_string","shape":7,"type":"STRING","widget":{"name":"watermark_string"},"link":null}],"outputs":[{"localized_name":"metadata_raw","name":"metadata_raw","type":"METADATA_RAW","links":[384]},{"localized_name":"image","name":"image","type":"IMAGE","links":[385]}],"properties":{"Node name for S&R":"FSLImageSaverWithMetadataV5","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":["nanob_ups_%date_%time","metadata",true,"","","","","","","","","","","","","",""]},{"id":237,"type":"FSLGeminiGenerateImageV6","pos":[2887.32373046875,-732.8950805664062],"size":[400,512],"flags":{},"order":23,"mode":0,"inputs":[{"localized_name":"init_image","name":"init_image","shape":7,"type":"IMAGE","link":387},{"localized_name":"images","name":"images","shape":7,"type":"IMAGE","link":null},{"localized_name":"prompt","name":"prompt","type":"STRING","widget":{"name":"prompt"},"link":388},{"localized_name":"model","name":"model","type":"COMBO","widget":{"name":"model"},"link":null},{"localized_name":"width","name":"width","type":"INT","widget":{"name":"width"},"link":null},{"localized_name":"height","name":"height","type":"INT","widget":{"name":"height"},"link":null},{"localized_name":"temperature","name":"temperature","type":"FLOAT","widget":{"name":"temperature"},"link":null},{"localized_name":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"use_init_image","name":"use_init_image","type":"BOOLEAN","widget":{"name":"use_init_image"},"link":null},{"localized_name":"use_images","name":"use_images","type":"BOOLEAN","widget":{"name":"use_images"},"link":null},{"localized_name":"refresh_models","name":"refresh_models","type":"BOOLEAN","widget":{"name":"refresh_models"},"link":null},{"localized_name":"output_prompt","name":"output_prompt","type":"BOOLEAN","widget":{"name":"output_prompt"},"link":null},{"localized_name":"api_key","name":"api_key","shape":7,"type":"STRING","widget":{"name":"api_key"},"link":null}],"outputs":[{"localized_name":"image","name":"image","type":"IMAGE","links":[389,390,391]},{"localized_name":"prompt","name":"prompt","type":"STRING","links":null},{"localized_name":"model","name":"model","type":"STRING","links":null},{"localized_name":"width","name":"width","type":"INT","links":null},{"localized_name":"height","name":"height","type":"INT","links":null},{"localized_name":"temperature","name":"temperature","type":"FLOAT","links":null},{"localized_name":"seed","name":"seed","type":"INT","links":null},{"localized_name":"seed_mode","name":"seed_mode","type":"STRING","links":null},{"localized_name":"metadata","name":"metadata","type":"DICT","links":[392]}],"properties":{"Node name for S&R":"FSLGeminiGenerateImageV6","ue_properties":{"widget_ue_connectable":{},"input_ue_unconnectable":{},"version":"7.2.2"}},"widgets_values":["","gemini-2.5-flash-image",1024,1024,1,29077942,"randomize",true,false,false,false,""]},{"id":220,"type":"Fast Groups Bypasser (rgthree)","pos":[2619.082275390625,-1299.32861328125],"size":[236.74765014648438,130],"flags":{},"order":8,"mode":0,"inputs":[],"outputs":[{"name":"OPT_CONNECTION","type":"*","links":null}],"properties":{"matchColors":"","matchTitle":"","showNav":true,"showAllGraphs":true,"sort":"position","customSortAlphabet":"","toggleRestriction":"default","ue_properties":{"version":"7.0.1","widget_ue_connectable":{}}}}],"links":[[301,196,0,191,0,"*"],[302,196,0,192,0,"*"],[303,196,0,193,0,"*"],[304,201,0,195,0,"*"],[305,201,0,196,0,"STRING"],[306,200,1,196,1,"AGENT"],[307,197,0,196,3,"DRIVER"],[308,190,0,198,0,"RULESET"],[309,199,0,198,1,"RULESET"],[310,194,0,198,2,"RULESET"],[311,198,0,200,3,"RULESET"],[312,200,0,201,0,"STRING"],[313,196,0,202,0,"IMAGE"],[314,196,0,205,0,"IMAGE"],[315,201,0,94,1,"STRING"],[316,218,1,206,0,"CLIP"],[317,219,0,207,1,"MODEL"],[318,206,0,207,2,"CONDITIONING"],[319,215,0,207,3,"CONDITIONING"],[320,218,2,207,4,"VAE"],[321,217,0,207,5,"UPSCALE_MODEL"],[322,210,0,209,0,"IMAGE"],[323,211,0,210,0,"IMAGE"],[324,207,0,211,0,"IMAGE"],[325,210,0,212,0,"IMAGE"],[327,210,0,214,0,"*"],[328,211,0,214,1,"*"],[329,219,0,214,2,"*"],[330,218,1,215,0,"CLIP"],[331,210,0,216,0,"IMAGE"],[332,218,0,219,0,"MODEL"],[333,218,1,219,1,"CLIP"],[360,228,0,207,0,"IMAGE"],[361,228,0,216,1,"IMAGE"],[382,210,0,233,0,"IMAGE"],[384,233,0,234,0,"METADATA_RAW"],[385,233,1,235,0,"IMAGE"],[387,230,0,237,0,"IMAGE"],[388,94,0,237,2,"STRING"],[389,237,0,228,0,"IMAGE"],[390,237,0,110,0,"IMAGE"],[391,237,0,109,0,"IMAGE"],[392,237,8,233,1,"DICT"]],"groups":[{"id":1,"title":"Griptape Loader","bounding":[1304.4677734375,-1127.59130859375,1520,1260],"color":"#3f789e","font_size":24,"flags":{}},{"id":2,"title":"Nano Banana","bounding":[2868.8671875,-1121.8707275390625,869.5833740234375,1488.0997314453125],"color":"#3f789e","font_size":24,"flags":{}},{"id":3,"title":"Upscaler","bounding":[3781.543212890625,-1127.2529296875,3083.047119140625,1485.775146484375],"color":"#3f789e","font_size":24,"flags":{}}],"config":{},"extra":{"ds":{"scale":1.077553310811715,"offset":[-3996.8698992858785,1255.3590723717825]},"frontendVersion":"1.25.10","VHS_MetadataImage":true,"VHS_latentpreview":false,"VHS_KeepIntermediate":true,"VHS_latentpreviewrate":0,"ue_links":[],"links_added_by_ue":[]},"version":0.4} \ No newline at end of file diff --git a/workflows/nano_banana/Nano Banana w_Griptape w_Upscaler.png b/workflows/nano_banana/Nano Banana w_Griptape w_Upscaler.png new file mode 100644 index 0000000..3b74d2b Binary files /dev/null and b/workflows/nano_banana/Nano Banana w_Griptape w_Upscaler.png differ