Update Seedream 5 sizing behavior
This commit is contained in:
@@ -21,6 +21,7 @@ A Custom Node that integrates [Fal.ai's](https://fal.ai) powerful image editing
|
||||
| **Grok Imagine Edit** | `grok_imagine_edit` | xAI image edit model, up to 3 input images. |
|
||||
| **Seedream 4.5** | `seedream_4.5` | ByteDance's model. Optimized for high-res editing. |
|
||||
| **Seedream 5 Pro Edit** | `seedream_5` | ByteDance Seedream 5.0 Pro region-precise editing. |
|
||||
| **Seedream 5 Lite Edit** | `seedream_5_lite` | ByteDance Seedream 5.0 Lite editing. |
|
||||
| **Qwen Edit Plus** | `qwen_edit_plus` | Powerful instruction-based editing with guidance control. |
|
||||
| **Flux 2 (Standard, Pro, Flex)** | `flux_2_edit` | (BFL) High-fidelity editing capabilities. |
|
||||
| **Flux 2 Klein 9B Edit** | `flux_2_klein_9b_edit` | Fast FLUX.2 Klein 9B image editing model. |
|
||||
@@ -85,15 +86,21 @@ Different models have different requirements implemented in the node:
|
||||
|
||||
4. **Seedream 5 Pro Edit (`seedream_5`)**:
|
||||
* Supports up to **10 input images**.
|
||||
* Uses `auto_2K` sizing unless custom width and height are provided.
|
||||
* Custom total pixels must be between **1024x1024** and **2048x2048**.
|
||||
* If `aspect_ratio` is not `auto`, the selected aspect ratio is prioritized and converted to Seedream's `image_size`.
|
||||
* If `aspect_ratio` is `auto`, the selected `resolution` is mapped to Seedream's automatic size presets.
|
||||
* Pro supports `auto_1K` and `auto_2K`; `4K` falls back to Pro's highest automatic preset.
|
||||
|
||||
5. **Nano Banana / Pro / 2**:
|
||||
5. **Seedream 5 Lite Edit (`seedream_5_lite`)**:
|
||||
* Supports up to **10 input images**.
|
||||
* Uses the same aspect-ratio-first behavior as Seedream 5 Pro.
|
||||
* Supports Lite automatic presets up to `auto_4K`.
|
||||
|
||||
6. **Nano Banana / Pro / 2**:
|
||||
* These models rely on `aspect_ratio` and `resolution` settings rather than custom width/height integers.
|
||||
* `nano_banana_2` supports `0.5K`, `1K`, `2K`, and `4K` resolution presets.
|
||||
* `nano_banana_2` also supports extended aspect ratios: `4:1`, `1:4`, `8:1`, and `1:8`.
|
||||
|
||||
6. **Grok Imagine Edit (`grok_imagine_edit`)**:
|
||||
7. **Grok Imagine Edit (`grok_imagine_edit`)**:
|
||||
* Supports up to **3 input images**.
|
||||
* Uses up to **4 output images**.
|
||||
|
||||
|
||||
+101
-21
@@ -1,12 +1,95 @@
|
||||
import torch
|
||||
import requests
|
||||
import base64
|
||||
import numpy as np
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
|
||||
# Helper function to convert ComfyUI tensor (B=1, H, W, C) to PIL Image (RGB)
|
||||
def tensor2pil(image_tensor):
|
||||
import numpy as np
|
||||
from io import BytesIO
|
||||
from PIL import Image
|
||||
|
||||
SEEDREAM_5_AUTO_IMAGE_SIZE_BY_RESOLUTION = {
|
||||
"seedream_5": {
|
||||
"0.5K": "auto_1K",
|
||||
"1K": "auto_1K",
|
||||
"2K": "auto_2K",
|
||||
"4K": "auto_2K",
|
||||
},
|
||||
"seedream_5_pro": {
|
||||
"0.5K": "auto_1K",
|
||||
"1K": "auto_1K",
|
||||
"2K": "auto_2K",
|
||||
"4K": "auto_2K",
|
||||
},
|
||||
"seedream_5_lite": {
|
||||
"0.5K": "auto_2K",
|
||||
"1K": "auto_2K",
|
||||
"2K": "auto_2K",
|
||||
"4K": "auto_4K",
|
||||
},
|
||||
}
|
||||
|
||||
SEEDREAM_5_RESOLUTION_PIXELS = {
|
||||
"seedream_5": {
|
||||
"0.5K": 1024 * 1024,
|
||||
"1K": 1024 * 1024,
|
||||
"2K": 2048 * 2048,
|
||||
"4K": 2048 * 2048,
|
||||
},
|
||||
"seedream_5_pro": {
|
||||
"0.5K": 1024 * 1024,
|
||||
"1K": 1024 * 1024,
|
||||
"2K": 2048 * 2048,
|
||||
"4K": 2048 * 2048,
|
||||
},
|
||||
"seedream_5_lite": {
|
||||
"0.5K": 2560 * 1440,
|
||||
"1K": 2560 * 1440,
|
||||
"2K": 2048 * 2048,
|
||||
"4K": 4096 * 4096,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _round_to_multiple(value, multiple=8):
|
||||
return max(multiple, int(round(value / multiple)) * multiple)
|
||||
|
||||
|
||||
def seedream_5_image_size(aspect_ratio, resolution, model="seedream_5"):
|
||||
auto_sizes = SEEDREAM_5_AUTO_IMAGE_SIZE_BY_RESOLUTION.get(
|
||||
model,
|
||||
SEEDREAM_5_AUTO_IMAGE_SIZE_BY_RESOLUTION["seedream_5"],
|
||||
)
|
||||
resolution_pixels = SEEDREAM_5_RESOLUTION_PIXELS.get(
|
||||
model,
|
||||
SEEDREAM_5_RESOLUTION_PIXELS["seedream_5"],
|
||||
)
|
||||
|
||||
if aspect_ratio == "auto":
|
||||
return auto_sizes.get(resolution, auto_sizes["2K"])
|
||||
|
||||
width_ratio, height_ratio = [int(part) for part in aspect_ratio.split(":", 1)]
|
||||
ratio = width_ratio / height_ratio
|
||||
target_pixels = resolution_pixels.get(resolution, resolution_pixels["2K"])
|
||||
|
||||
width = (target_pixels * ratio) ** 0.5
|
||||
height = target_pixels / width
|
||||
|
||||
max_dimension = 4096
|
||||
if width > max_dimension:
|
||||
scale = max_dimension / width
|
||||
width *= scale
|
||||
height *= scale
|
||||
if height > max_dimension:
|
||||
scale = max_dimension / height
|
||||
width *= scale
|
||||
height *= scale
|
||||
|
||||
return {
|
||||
"width": _round_to_multiple(width),
|
||||
"height": _round_to_multiple(height),
|
||||
}
|
||||
|
||||
|
||||
# Helper function to convert ComfyUI tensor (B=1, H, W, C) to PIL Image (RGB)
|
||||
def tensor2pil(image_tensor):
|
||||
if image_tensor is None or image_tensor.shape[0] == 0:
|
||||
return None
|
||||
i = 255. * image_tensor[0].cpu().numpy() # (H, W, C)
|
||||
@@ -52,7 +135,7 @@ class NanoSeedEdit:
|
||||
return {
|
||||
"required": {
|
||||
"prompt": ("STRING", {"default": "Edit the image according to this prompt.", "multiline": True}),
|
||||
"model": (["nano_banana", "nano_banana_pro", "nano_banana_2", "gpt_image_2_edit", "grok_imagine_edit", "seedream_4.5", "seedream_5", "qwen_edit_plus", "flux_2_edit", "flux_2_pro", "flux_2_flex", "flux_2_klein_9b_edit"],),
|
||||
"model": (["nano_banana", "nano_banana_pro", "nano_banana_2", "gpt_image_2_edit", "grok_imagine_edit", "seedream_4.5", "seedream_5", "seedream_5_lite", "qwen_edit_plus", "flux_2_edit", "flux_2_pro", "flux_2_flex", "flux_2_klein_9b_edit"],),
|
||||
"fal_key": ("STRING", {"default": "your_fal_key_here"}),
|
||||
},
|
||||
"optional": {
|
||||
@@ -123,8 +206,8 @@ class NanoSeedEdit:
|
||||
img_data_uris.append(img_data_uri)
|
||||
|
||||
# Enforce limits (Updated: Removed Flux 2 single image limit)
|
||||
if model == "seedream_4.5" and len(img_data_uris) + num_images > 15:
|
||||
raise ValueError("Seedream 4.5: Total inputs + outputs must <=15.")
|
||||
if model in ["seedream_4.5", "seedream_5", "seedream_5_pro", "seedream_5_lite"] and len(img_data_uris) + num_images > 15:
|
||||
raise ValueError("Seedream: Total inputs + outputs must <=15.")
|
||||
|
||||
# Model-specific payloads
|
||||
if model == "nano_banana":
|
||||
@@ -207,26 +290,23 @@ class NanoSeedEdit:
|
||||
if not (3686400 <= area <= 16777216):
|
||||
raise ValueError(f"Seedream 4.5: Image area must be 3,686,400-16,777,216px. Got {area}.")
|
||||
payload["image_size"] = {"width": width, "height": height}
|
||||
elif model == "seedream_5":
|
||||
url = "https://fal.run/bytedance/seedream/v5/pro/edit"
|
||||
elif model in ["seedream_5", "seedream_5_pro", "seedream_5_lite"]:
|
||||
if model in ["seedream_5", "seedream_5_pro"]:
|
||||
url = "https://fal.run/bytedance/seedream/v5/pro/edit"
|
||||
else:
|
||||
url = "https://fal.run/fal-ai/bytedance/seedream/v5/lite/edit"
|
||||
payload = {
|
||||
"prompt": prompt,
|
||||
"image_urls": img_data_uris[:10],
|
||||
"image_size": seedream_5_image_size(aspect_ratio, resolution, model),
|
||||
"num_images": min(num_images, 6),
|
||||
"output_format": "png",
|
||||
"enable_safety_checker": False,
|
||||
"sync_mode": True,
|
||||
}
|
||||
if custom_size:
|
||||
area = width * height
|
||||
aspect = width / height
|
||||
if not (1048576 <= area <= 4194304):
|
||||
raise ValueError(f"Seedream 5: Image area must be 1,048,576-4,194,304px. Got {area}.")
|
||||
if not (1 / 16 <= aspect <= 16):
|
||||
raise ValueError(f"Seedream 5: Aspect ratio must be between 1:16 and 16:1. Got {width}:{height}.")
|
||||
payload["image_size"] = {"width": width, "height": height}
|
||||
if model in ["seedream_5", "seedream_5_pro"]:
|
||||
payload["output_format"] = "png"
|
||||
else:
|
||||
payload["image_size"] = "auto_2K"
|
||||
payload["max_images"] = 1
|
||||
elif model == "qwen_edit_plus":
|
||||
url = "https://fal.run/fal-ai/qwen-image-edit-plus"
|
||||
payload = {
|
||||
|
||||
Reference in New Issue
Block a user