fix: 修复香蕉2画草图导致生成2张图片问题
- gemini_client: 解析响应时跳过 thought:true 的草稿图,从源头过滤 - 两个香蕉节点的 _images_to_tensor_safe 改为保留最大尺寸图片 Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
b4e82fecf7
commit
dafc4cf0f4
@@ -6,6 +6,13 @@
|
||||
|
||||
---
|
||||
|
||||
## [1.10.4] - 2026-04-13
|
||||
|
||||
### 修复
|
||||
- 修复香蕉2画草图导致生成2张图片问题
|
||||
|
||||
---
|
||||
|
||||
## [1.10.3] - 2026-04-13
|
||||
|
||||
### 修复
|
||||
|
||||
@@ -318,6 +318,10 @@ class GeminiAPIClient(BaseAPIClient):
|
||||
inline_data_key = "inlineData"
|
||||
|
||||
if inline_data_key:
|
||||
# 跳过思考链草稿图(thought:true 标记的 inlineData 为模型自检用途,非最终输出)
|
||||
if part.get("thought") is True:
|
||||
continue
|
||||
|
||||
inline_data = part[inline_data_key]
|
||||
# 同样兼容 data/mimeType 的命名
|
||||
img_data = inline_data.get("data") or inline_data.get("data", "")
|
||||
|
||||
@@ -74,32 +74,26 @@ def _images_to_tensor_safe(images: List[Image.Image], node_label: str) -> torch.
|
||||
"""
|
||||
将 PIL Image 列表转换为 ComfyUI tensor,安全处理多张不同尺寸的情况。
|
||||
|
||||
ComfyUI 的 IMAGE tensor 格式为 [B, H, W, C],要求 batch 内所有图尺寸相同。
|
||||
当 API 返回多张不同分辨率的图时(主图 + 附图),直接 stack 会崩溃。
|
||||
|
||||
策略:
|
||||
- 所有图均已按原始分辨率保存到磁盘(调用此函数前已完成)
|
||||
- 以第一张图的尺寸为基准,只将尺寸相同的图纳入 tensor 输出
|
||||
- 尺寸不同的图跳过(不 resize、不丢弃磁盘文件),并打印日志提示
|
||||
- 若没有任何图与第一张尺寸相同(极罕见),则只输出第一张
|
||||
- 以像素数最大的图尺寸为基准
|
||||
- 只输出与最大尺寸相同的图,其余较小的图丢弃
|
||||
"""
|
||||
if not images:
|
||||
placeholder = Image.new('RGB', (512, 512), color=(128, 128, 128))
|
||||
return pil_to_tensor([placeholder])
|
||||
|
||||
base_size = images[0].size # PIL size = (W, H)
|
||||
base_size = max(images, key=lambda img: img.size[0] * img.size[1]).size
|
||||
matched = [img for img in images if img.size == base_size]
|
||||
skipped = [img for img in images if img.size != base_size]
|
||||
|
||||
if skipped:
|
||||
sizes_str = ", ".join(f"{img.size[0]}×{img.size[1]}" for img in skipped)
|
||||
print(
|
||||
f"{node_label}: API 额外返回了 {len(skipped)} 张不同尺寸的图 ({sizes_str}),"
|
||||
f"已按原始分辨率保存到磁盘,tensor 输出仅包含与主图尺寸相同的 {len(matched)} 张 "
|
||||
f"({base_size[0]}×{base_size[1]})"
|
||||
f"{node_label}: 丢弃 {len(skipped)} 张较小尺寸的图 ({sizes_str}),"
|
||||
f"仅输出最大尺寸 {base_size[0]}×{base_size[1]} 的 {len(matched)} 张"
|
||||
)
|
||||
|
||||
return pil_to_tensor(matched if matched else [images[0]])
|
||||
return pil_to_tensor(matched)
|
||||
|
||||
|
||||
class BatchNanoBananaPro:
|
||||
|
||||
@@ -65,32 +65,26 @@ def _images_to_tensor_safe(images: List[Image.Image], node_label: str) -> torch.
|
||||
"""
|
||||
将 PIL Image 列表转换为 ComfyUI tensor,安全处理多张不同尺寸的情况。
|
||||
|
||||
ComfyUI 的 IMAGE tensor 格式为 [B, H, W, C],要求 batch 内所有图尺寸相同。
|
||||
当 API 返回多张不同分辨率的图时(主图 + 附图),直接 stack 会崩溃。
|
||||
|
||||
策略:
|
||||
- 所有图均已按原始分辨率保存到磁盘(调用此函数前已完成)
|
||||
- 以第一张图的尺寸为基准,只将尺寸相同的图纳入 tensor 输出
|
||||
- 尺寸不同的图跳过(不 resize、不丢弃磁盘文件),并打印日志提示
|
||||
- 若没有任何图与第一张尺寸相同(极罕见),则只输出第一张
|
||||
- 以像素数最大的图尺寸为基准
|
||||
- 只输出与最大尺寸相同的图,其余较小的图丢弃
|
||||
"""
|
||||
if not images:
|
||||
placeholder = Image.new('RGB', (512, 512), color=(128, 128, 128))
|
||||
return pil_to_tensor([placeholder])
|
||||
|
||||
base_size = images[0].size # PIL size = (W, H)
|
||||
base_size = max(images, key=lambda img: img.size[0] * img.size[1]).size
|
||||
matched = [img for img in images if img.size == base_size]
|
||||
skipped = [img for img in images if img.size != base_size]
|
||||
|
||||
if skipped:
|
||||
sizes_str = ", ".join(f"{img.size[0]}×{img.size[1]}" for img in skipped)
|
||||
print(
|
||||
f"{node_label}: API 额外返回了 {len(skipped)} 张不同尺寸的图 ({sizes_str}),"
|
||||
f"已按原始分辨率保存到磁盘,tensor 输出仅包含与主图尺寸相同的 {len(matched)} 张 "
|
||||
f"({base_size[0]}×{base_size[1]})"
|
||||
f"{node_label}: 丢弃 {len(skipped)} 张较小尺寸的图 ({sizes_str}),"
|
||||
f"仅输出最大尺寸 {base_size[0]}×{base_size[1]} 的 {len(matched)} 张"
|
||||
)
|
||||
|
||||
return pil_to_tensor(matched if matched else [images[0]])
|
||||
return pil_to_tensor(matched)
|
||||
|
||||
|
||||
class NanoBananaPro:
|
||||
|
||||
Reference in New Issue
Block a user