优化Seedream4的代码结构和相关文档
This commit is contained in:
@@ -32,7 +32,7 @@
|
||||
- **智能统一节点**:
|
||||
- **图像生成**:
|
||||
- `即梦 Seedream 3` 节点会根据是否连接图像输入,**自动在后端智能切换**文生图 (`doubao-seedream-3-0-t2i-250415`) 和图生图编辑 (`doubao-seededit-3-0-i2i-250628`) 模型,无需用户手动配置。
|
||||
- `即梦 Seedream 4` 节点支持更高级的图生图(最多 10 张输入图像)和组图生成模式。
|
||||
- `即梦 Seedream 4` 节点支持更高级的图生图(最多 14 张输入图像)和组图生成模式。
|
||||
- **视频生成**: `即梦视频生成` 节点统一了**文生视频**、**图生视频(首帧)** 和 **首尾帧生视频** 三种核心模式,极大简化了工作流。
|
||||
- **优秀的用户体验**:
|
||||
- **流式进度条**: 支持视频生成等耗时任务的**流式进度条**,可在 ComfyUI 界面实时反馈任务状态。
|
||||
@@ -87,23 +87,25 @@
|
||||
- `response (STRING)`: API 的 JSON 响应。
|
||||
|
||||
### `即梦 Seedream 4 (Jimeng Seedream 4)`
|
||||
支持最新的即梦 Seedream 4.0 及 4.5 模型,提供更高质量的图像生成能力,并支持多图参考和组图生成功能。
|
||||
|
||||
高级图像生成节点,支持组图生成和多图输入。
|
||||
* **Model Version (模型版本)**:
|
||||
* `doubao-seedream-4.5`: 最新模型,效果更佳。
|
||||
* `doubao-seedream-4.0`: 标准模型。
|
||||
* **Enable Group Generation (启用组图生成)**:
|
||||
* **`True` (开启/Auto)**: 激活**组图模式**。生成一组内容关联的图片。
|
||||
* **支持场景**: 文生组图、单图生组图、多图生组图。
|
||||
* **数量限制**: `输入参考图数量` + `生成图片数 (max_images)` ≤ **15**。
|
||||
* **`False` (关闭/Single)**: 激活**单图模式**。
|
||||
* **支持场景**: 文生图、单图生图、多图生图。
|
||||
* **注意**: 此模式下无论输入多少张参考图,最终仅生成 **1** 张图片。
|
||||
* **Prompt**: 文本提示词。
|
||||
* **Max Images**: (仅在组图模式下生效) 设置生成的图片数量。
|
||||
* **Images (Optional)**: 输入参考图像,支持单张或多张(最多 14 张)。
|
||||
* 连接 1 张图片 -> 单图参考。
|
||||
* 连接多张图片 (Batch) -> 多图参考。
|
||||
|
||||
- **输入**:
|
||||
- `client (JIMENG_CLIENT)`: 客户端。
|
||||
- `prompt (STRING)`: 提示词。
|
||||
- `generation_mode (STRING)`: 生成模式 (单图或组图)。
|
||||
- `max_images (INT)`: 最大图片数 (用于组图模式)。
|
||||
- `size (STRING)`: 尺寸。
|
||||
- `width (INT)`: 宽度。
|
||||
- `height (INT)`: 高度。
|
||||
- `seed (INT)`: 种子。
|
||||
- `watermark (BOOLEAN)`: 水印。
|
||||
- `images (IMAGE)`: (可选, 用于图生图, 最多 10 张)。
|
||||
- **输出**:
|
||||
- `images (IMAGE)`: 生成的图像(批处理)。
|
||||
- `response (STRING)`: API 的 JSON 响应。
|
||||
> **注意**: 在组图模式下,请务必确保 `输入图片数 + 生成图片数` 不超过 15,否则会报错。
|
||||
|
||||
### `即梦视频生成 (Jimeng Video Generation)`
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"id":"9cdfd6e3-7426-4a3a-88b1-b5866725d7e0","revision":0,"last_node_id":48,"last_link_id":51,"nodes":[{"id":47,"type":"JimengAPIClient","pos":[659.3174882443304,464.525306048046],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"key_name","name":"key_name","type":"COMBO","widget":{"name":"key_name"},"link":null}],"outputs":[{"localized_name":"client","name":"client","type":"JIMENG_CLIENT","links":[50]}],"properties":{"cnr_id":"ComfyUI-Jimeng-API","ver":"bc7215f572cf093ccf7e4ce142267352a60fb428","Node name for S&R":"JimengAPIClient"},"widgets_values":["未找到密钥 (请配置 api_keys.json)"]},{"id":48,"type":"JimengSeedream4","pos":[949.1629520176931,463.793203747457],"size":[400,300],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"client","name":"client","type":"JIMENG_CLIENT","link":50},{"localized_name":"images","name":"images","shape":7,"type":"IMAGE","link":null},{"localized_name":"model_version","name":"model_version","type":"COMBO","widget":{"name":"model_version"},"link":null},{"localized_name":"prompt","name":"prompt","type":"STRING","widget":{"name":"prompt"},"link":null},{"localized_name":"generation_mode","name":"generation_mode","type":"COMBO","widget":{"name":"generation_mode"},"link":null},{"localized_name":"max_images","name":"max_images","type":"INT","widget":{"name":"max_images"},"link":null},{"localized_name":"size","name":"size","type":"COMBO","widget":{"name":"size"},"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":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"watermark","name":"watermark","type":"BOOLEAN","widget":{"name":"watermark"},"link":null}],"outputs":[{"localized_name":"images","name":"images","type":"IMAGE","links":[51]},{"localized_name":"response","name":"response","type":"STRING","links":null}],"properties":{"cnr_id":"ComfyUI-Jimeng-API","ver":"c07c6b2ff122fcb0ebf9f345ef04b697d6e19b66","Node name for S&R":"JimengSeedream4"},"widgets_values":["doubao-seedream-4.0","","Single Image (disabled)",1,"Custom",2048,2048,-1,"randomize",false]},{"id":45,"type":"SaveImage","pos":[1366.2473373272921,464.2190469588465],"size":[270,58],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"图片","name":"images","type":"IMAGE","link":51},{"localized_name":"文件名前缀","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.65","Node name for S&R":"SaveImage"},"widgets_values":["Jimeng/Image/Seedream4"]}],"links":[[50,47,0,48,0,"JIMENG_CLIENT"],[51,48,0,45,0,"IMAGE"]],"groups":[],"config":{},"extra":{"ds":{"scale":2.11537812904981,"offset":[-565.3072584119454,-279.58656869694266]},"frontendVersion":"1.18.9","VHS_latentpreview":false,"VHS_latentpreviewrate":0,"VHS_MetadataImage":true,"VHS_KeepIntermediate":true,"workflowRendererVersion":"LG"},"version":0.4}
|
||||
{"id":"9cdfd6e3-7426-4a3a-88b1-b5866725d7e0","revision":0,"last_node_id":49,"last_link_id":53,"nodes":[{"id":45,"type":"SaveImage","pos":[1366.2473373272921,464.2190469588465],"size":[270,58],"flags":{},"order":1,"mode":0,"inputs":[{"localized_name":"图片","name":"images","type":"IMAGE","link":53},{"localized_name":"文件名前缀","name":"filename_prefix","type":"STRING","widget":{"name":"filename_prefix"},"link":null}],"outputs":[],"properties":{"cnr_id":"comfy-core","ver":"0.3.65","Node name for S&R":"SaveImage"},"widgets_values":["Jimeng/Image/Seedream4"]},{"id":47,"type":"JimengAPIClient","pos":[659.3174882443304,464.2190469588465],"size":[270,58],"flags":{},"order":0,"mode":0,"inputs":[{"localized_name":"key_name","name":"key_name","type":"COMBO","widget":{"name":"key_name"},"link":null}],"outputs":[{"localized_name":"client","name":"client","type":"JIMENG_CLIENT","links":[52]}],"properties":{"cnr_id":"ComfyUI-Jimeng-API","ver":"bc7215f572cf093ccf7e4ce142267352a60fb428","Node name for S&R":"JimengAPIClient"},"widgets_values":["未找到密钥 (请配置 api_keys.json)"]},{"id":49,"type":"JimengSeedream4","pos":[947.7824127858113,464.2190469588465],"size":[400,300],"flags":{},"order":2,"mode":0,"inputs":[{"localized_name":"client","name":"client","type":"JIMENG_CLIENT","link":52},{"localized_name":"images","name":"images","shape":7,"type":"IMAGE","link":null},{"localized_name":"model_version","name":"model_version","type":"COMBO","widget":{"name":"model_version"},"link":null},{"localized_name":"prompt","name":"prompt","type":"STRING","widget":{"name":"prompt"},"link":null},{"localized_name":"enable_group_generation","name":"enable_group_generation","type":"BOOLEAN","widget":{"name":"enable_group_generation"},"link":null},{"localized_name":"max_images","name":"max_images","type":"INT","widget":{"name":"max_images"},"link":null},{"localized_name":"size","name":"size","type":"COMBO","widget":{"name":"size"},"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":"seed","name":"seed","type":"INT","widget":{"name":"seed"},"link":null},{"localized_name":"watermark","name":"watermark","type":"BOOLEAN","widget":{"name":"watermark"},"link":null}],"outputs":[{"localized_name":"images","name":"images","type":"IMAGE","links":[53]},{"localized_name":"response","name":"response","type":"STRING","links":null}],"properties":{"cnr_id":"ComfyUI-Jimeng-API","ver":"0033eded3f183df3a3ff16d097602da3c8e985fc","Node name for S&R":"JimengSeedream4"},"widgets_values":["doubao-seedream-4.5","",false,1,"Custom",2048,2048,-1,"randomize",false]}],"links":[[52,47,0,49,0,"JIMENG_CLIENT"],[53,49,0,45,0,"IMAGE"]],"groups":[],"config":{},"extra":{"ds":{"scale":1.3134833866600077,"offset":[-330.0922977518734,-207.13823911048317]},"frontendVersion":"1.18.9","VHS_latentpreview":false,"VHS_latentpreviewrate":0,"VHS_MetadataImage":true,"VHS_KeepIntermediate":true,"workflowRendererVersion":"LG"},"version":0.4}
|
||||
@@ -87,13 +87,9 @@
|
||||
"name": "提示词",
|
||||
"tooltip": "用于图像生成的文本提示词"
|
||||
},
|
||||
"generation_mode": {
|
||||
"name": "生成模式",
|
||||
"tooltip": "选择单图或组图生成",
|
||||
"options": {
|
||||
"Single Image (disabled)": "单图模式 (禁用组图)",
|
||||
"Image Group (auto)": "组图模式 (自动)"
|
||||
}
|
||||
"enable_group_generation": {
|
||||
"name": "启用组图生成",
|
||||
"tooltip": "开启 (True) 则生成一组内容关联的图片;关闭 (False) 则生成单张图片。"
|
||||
},
|
||||
"max_images": {
|
||||
"name": "最大图片数",
|
||||
|
||||
+32
-18
@@ -120,9 +120,9 @@ class JimengSeedream4:
|
||||
return {
|
||||
"required": {
|
||||
"client": ("JIMENG_CLIENT",),
|
||||
"model_version": (["doubao-seedream-4.0", "doubao-seedream-4.5"],),
|
||||
"model_version": (["doubao-seedream-4.5", "doubao-seedream-4.0"],),
|
||||
"prompt": ("STRING", {"multiline": True, "default": ""}),
|
||||
"generation_mode": (["Single Image (disabled)", "Image Group (auto)"],),
|
||||
"enable_group_generation": ("BOOLEAN", {"default": False, "label_on": "On (Group)", "label_off": "Off (Single)"}),
|
||||
"max_images": ("INT", {"default": 1, "min": 1, "max": 15, "step": 1}),
|
||||
"size": (s.RECOMMENDED_SIZES,),
|
||||
"width": ("INT", {"default": 2048, "min": 1, "max": 8192, "step": 1}),
|
||||
@@ -139,25 +139,32 @@ class JimengSeedream4:
|
||||
FUNCTION = "generate"
|
||||
CATEGORY = GLOBAL_CATEGORY
|
||||
|
||||
async def generate(self, client, model_version, prompt, generation_mode, max_images, size, width, height, seed, watermark, images=None):
|
||||
async def generate(self, client, model_version, prompt, enable_group_generation, max_images, size, width, height, seed, watermark, images=None):
|
||||
# 节点的主要异步执行函数
|
||||
sequential_image_generation = "disabled" if "disabled" in generation_mode else "auto"
|
||||
n_input_images = 0
|
||||
if images is not None: n_input_images = images.shape[0]
|
||||
if n_input_images > 10:
|
||||
raise ValueError(get_text("err_img_limit_10"))
|
||||
if sequential_image_generation == "auto" and n_input_images + max_images > 15:
|
||||
raise ValueError(get_text("err_img_limit_15").format(n=n_input_images, max=max_images))
|
||||
|
||||
actual_seed = random.randint(0, 2147483647) if seed == -1 else seed
|
||||
|
||||
# 映射模型版本到后端 ID
|
||||
model_id_map = {
|
||||
"doubao-seedream-4.0": "doubao-seedream-4-0-250828",
|
||||
"doubao-seedream-4.5": "doubao-seedream-4-5-251128"
|
||||
}
|
||||
model_id = model_id_map.get(model_version, "doubao-seedream-4-0-250828")
|
||||
|
||||
# 根据 enable_group_generation 布尔值设置 API 参数
|
||||
sequential_param = "auto" if enable_group_generation else "disabled"
|
||||
|
||||
n_input_images = 0
|
||||
if images is not None:
|
||||
n_input_images = images.shape[0]
|
||||
|
||||
# 校验逻辑
|
||||
if sequential_param == "auto":
|
||||
total_count = n_input_images + max_images
|
||||
if total_count > 15:
|
||||
raise ValueError(get_text("err_img_limit_group_15").format(n=n_input_images, max=max_images, total=total_count))
|
||||
else:
|
||||
pass
|
||||
|
||||
actual_seed = random.randint(0, 2147483647) if seed == -1 else seed
|
||||
|
||||
# 处理分辨率
|
||||
if size == "Custom":
|
||||
total_pixels = width * height
|
||||
@@ -174,7 +181,7 @@ class JimengSeedream4:
|
||||
else:
|
||||
size_str = size.split(" ")[0]
|
||||
|
||||
# 处理输入的图像(可能为多个)
|
||||
# 处理输入的图像
|
||||
image_param = None
|
||||
if images is not None:
|
||||
image_b64_list = [_image_to_base64(images[i:i+1]) for i in range(n_input_images)]
|
||||
@@ -182,11 +189,18 @@ class JimengSeedream4:
|
||||
else: image_param = [f"data:image/jpeg;base64,{b64}" for b64 in image_b64_list]
|
||||
|
||||
# 准备 API 请求体
|
||||
extra_body = {"seed": actual_seed, "watermark": watermark, "sequential_image_generation": sequential_image_generation}
|
||||
if image_param: extra_body["image"] = image_param
|
||||
if sequential_image_generation == "auto":
|
||||
extra_body['sequential_image_generation_options'] = {"max_images": max_images}
|
||||
extra_body = {
|
||||
"seed": actual_seed,
|
||||
"watermark": watermark,
|
||||
"sequential_image_generation": sequential_param
|
||||
}
|
||||
|
||||
if image_param:
|
||||
extra_body["image"] = image_param
|
||||
|
||||
if sequential_param == "auto":
|
||||
extra_body['sequential_image_generation_options'] = {"max_images": max_images}
|
||||
|
||||
openai_client = client.openai
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
|
||||
@@ -70,6 +70,7 @@ LOG_TRANSLATIONS = {
|
||||
"err_gen_model": "[JimengAI] 模型 {model} 生成失败: {e}",
|
||||
"err_img_limit_10": "[JimengAI] 参数错误: 输入图像数量不能超过 10 张。",
|
||||
"err_img_limit_15": "[JimengAI] 参数错误: 输入图像数 ({n}) 与最大生成数 ({max}) 之和不能超过 15。",
|
||||
"err_img_limit_group_15": "[JimengAI] 参数错误: 在组图模式下,输入参考图数量 ({n}) 加 生成图片数量 ({max}) 的总和 ({total}) 不能超过 15 张。",
|
||||
|
||||
# API Key 相关
|
||||
"combo_no_keys": "未找到密钥 (请配置 api_keys.json)",
|
||||
@@ -122,6 +123,7 @@ LOG_TRANSLATIONS = {
|
||||
"err_gen_model": "[JimengAI] Failed to generate image with model {model}: {e}",
|
||||
"err_img_limit_10": "[JimengAI] Parameter Error: The number of input images cannot exceed 10.",
|
||||
"err_img_limit_15": "[JimengAI] Parameter Error: The sum of input images ({n}) and max generated images ({max}) cannot exceed 15.",
|
||||
"err_img_limit_group_15": "[JimengAI] Parameter Error: The sum of input images ({n}) and max generated images ({max}) cannot exceed 15 in group mode (Total: {total}).",
|
||||
|
||||
# API Key
|
||||
"combo_no_keys": "No Keys Found (Check api_keys.json)",
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "ComfyUI-Jimeng-API"
|
||||
description = "ComfyUI nodes for Volcano Ark (Jimeng) API"
|
||||
version = "1.9.8"
|
||||
version = "1.9.9"
|
||||
license = {file = "LICENSE"}
|
||||
dependencies = ["volcengine-python-sdk[ark]", "openai"]
|
||||
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
# 即梦 Seedream 4
|
||||
# Jimeng Seedream 4 节点使用说明
|
||||
|
||||
使用即梦 Seedream 4 模型生成图像,支持单图或组图(自动)模式。
|
||||
该节点使用即梦最新的 Seedream 4.0/4.5 模型生成图像。支持灵活的单图或组图生成策略。
|
||||
|
||||
## 输入 (Inputs)
|
||||
## 参数说明
|
||||
|
||||
- **client (客户端)**: 即梦 API 客户端
|
||||
- **prompt (提示词)**: 用于图像生成的文本提示词
|
||||
- **generation_mode (生成模式)**: 选择单图或组图生成
|
||||
- `单图模式 (禁用组图)`
|
||||
- `组图模式 (自动)`
|
||||
- **max_images (最大图片数)**: 在组图模式下生成的最大图像数量
|
||||
- **size (尺寸)**: 预设的图像尺寸。如果选择 'Custom',将使用 '宽度' 和 '高度'。
|
||||
- **width (宽度)**: 自定义宽度(仅当尺寸为 'Custom' 时生效)
|
||||
- **height (高度)**: 自定义高度(仅当尺寸为 'Custom' 时生效)
|
||||
- **seed (种子)**: 随机种子,-1 表示随机
|
||||
- **watermark (水印)**: 是否在生成的图像上添加水印
|
||||
- **images (输入图像)**: 用于图生图的输入图像(最多 10 张)
|
||||
### 核心参数
|
||||
- **client**: 连接 `JimengAPIClient` 节点。
|
||||
- **model_version**: 选择模型版本,推荐使用 `doubao-seedream-4.5`。
|
||||
- **enable_group_generation**: **关键开关**。
|
||||
- **开启 (True)**: 进入组图模式,根据提示词和参考图生成一组连贯的图片。
|
||||
- **关闭 (False)**: 进入单图模式,生成单张高质量图片。
|
||||
- **max_images**: 生成数量设置。仅在 `enable_group_generation` 开启时可见并生效。
|
||||
|
||||
## 输出 (Outputs)
|
||||
### 规则详解
|
||||
|
||||
- **图像**: 生成的图像(批处理)
|
||||
- **响应**: API 的 JSON 格式响应
|
||||
| 模式 | 开关状态 | 输入 | 输出数量 | 限制条件 |
|
||||
| :--- | :--- | :--- | :--- | :--- |
|
||||
| **文生图** | False | 仅提示词 | 1 张 | 无 |
|
||||
| **图生图** | False | 提示词 + 参考图 (1-14张) | 1 张 | 无论输入几张参考图,均融合生成 1 张结果 |
|
||||
| **文生组图** | True | 仅提示词 | N 张 | N ≤ 15 |
|
||||
| **图生组图** | True | 提示词 + 参考图 (M张) | N 张 | M + N ≤ 15 |
|
||||
@@ -34,7 +34,7 @@ function updateNodeHeight(node) {
|
||||
app.graph.setDirtyCanvas(true, true);
|
||||
}
|
||||
|
||||
const TARGET_WIDGETS = ['size', 'generation_mode', 'generation_count'];
|
||||
const TARGET_WIDGETS = ['size', 'enable_group_generation', 'generation_count'];
|
||||
|
||||
function widgetLogic(node, widget) {
|
||||
if (node.comfyClass === "JimengSeedream3" || node.comfyClass === "JimengSeedream4") {
|
||||
@@ -49,8 +49,8 @@ function widgetLogic(node, widget) {
|
||||
}
|
||||
|
||||
if (node.comfyClass === "JimengSeedream4") {
|
||||
if (widget.name === 'generation_mode') {
|
||||
const isGroupMode = widget.value === "Image Group (auto)";
|
||||
if (widget.name === 'enable_group_generation') {
|
||||
const isGroupMode = widget.value === true;
|
||||
const maxImagesWidget = findWidgetByName(node, 'max_images');
|
||||
|
||||
if (maxImagesWidget) toggleWidget(node, maxImagesWidget, isGroupMode);
|
||||
|
||||
Reference in New Issue
Block a user