From 4e30f2611278ebc86a4bfe1d53a103813dc7c577 Mon Sep 17 00:00:00 2001 From: rui40000 Date: Wed, 1 Apr 2026 13:40:05 +0800 Subject: [PATCH] Fix OpenAI multi-image node to process mixed image sizes independently --- README.md | 8 ++++-- __pycache__/openai_node.cpython-312.pyc | Bin 0 -> 5939 bytes openai_node.py | 32 +++++++++++++++--------- 3 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 __pycache__/openai_node.cpython-312.pyc diff --git a/README.md b/README.md index 2f7eef5..8ba7a5e 100644 --- a/README.md +++ b/README.md @@ -381,8 +381,8 @@ Rui-Node🐶 是一个功能丰富的 ComfyUI 节点集合,提供图像处理 - `seed` (INT): 随机种子,用于控制生成的随机性 - `image_1` ~ `image_6` (IMAGE, 可选): 最多 6 张输入图像 - 说明: 用户有几张图就连接几个输入口,无需手动 Batch - - 规则: 节点内部会自动收集所有已连接图像,并使用 `torch.cat(..., dim=0)` 合并后逐张编码发送到 API - - 注意: 多张图像尺寸需一致,否则会返回尺寸不一致错误 + - 规则: 节点内部会自动逐张处理每个输入图像,分别编码后发送到 API + - 优势: 不要求所有图像尺寸一致,512×512 和 511×768 之类的混合输入也可直接使用 - `temperature` (FLOAT, 可选): 采样温度 - 默认值: 0.3 - 范围: 0.0 ~ 2.0 @@ -392,6 +392,10 @@ Rui-Node🐶 是一个功能丰富的 ComfyUI 节点集合,提供图像处理 - `detail` (选择, 可选): 图像分析细节等级 - 选项: low, high, auto - 默认值: auto +- `image_max_size` (INT, 可选): 单张图像最长边缩放上限 + - 默认值: 1024 + - 范围: 256 ~ 4096 + - 说明: 超过该尺寸的图像会在发送前按比例缩小,以减少 token 消耗与请求体积 - `proxy_url` (STRING, 可选): HTTP/HTTPS 代理地址 - 示例: `http://127.0.0.1:7890` diff --git a/__pycache__/openai_node.cpython-312.pyc b/__pycache__/openai_node.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..069c2c1933cca93f7ebc8dfd40afab696e29d616 GIT binary patch literal 5939 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 image_max_size: + ratio = image_max_size / max(width, height) + img_pil = img_pil.resize( + (max(1, int(width * ratio)), max(1, int(height * ratio))), + Image.LANCZOS + ) buffered = io.BytesIO() - img_pil.save(buffered, format="JPEG") + img_pil.save(buffered, format="JPEG", quality=85) return base64.b64encode(buffered.getvalue()).decode('utf-8') def generate_content( @@ -114,6 +126,7 @@ class OpenAINode: temperature=0.3, max_tokens=500, detail="auto", + image_max_size=1024, proxy_url="" ): """ @@ -132,12 +145,7 @@ class OpenAINode: ] if not all_images: - return ("Error: 至少需要连接一张图像到 image_1 ~ image_6。",) - - try: - images = torch.cat(all_images, dim=0) - except Exception as e: - return (f"Error: 无法合并多张图像,请确保所有输入图像尺寸一致。详细信息: {str(e)}",) + return (user_prompt if user_prompt.strip() else "(未提供图片和描述)",) messages = [ {"role": "system", "content": system_prompt} @@ -151,9 +159,9 @@ class OpenAINode: "text": user_prompt }) - for idx in range(images.shape[0]): - img_tensor = images[idx] - img_base64 = self._encode_image_tensor(img_tensor) + for image in all_images: + img_tensor = image[0] + img_base64 = self._encode_image_tensor(img_tensor, image_max_size) user_content.append({ "type": "image_url", "image_url": {