Add multi-image support for Seedream45 Edit
This commit is contained in:
@@ -42,7 +42,7 @@ This node pack currently includes the following nodes:
|
||||
- Image generation node using the Googles Nano Banana Pro model
|
||||
- **Seedream Text-to-Image / Edit**
|
||||
- Text-to-image and image-editing node for Seedream models.
|
||||
- Supports prompt-based generation and edits.
|
||||
- Supports prompt-based generation and edits (edit node accepts up to 14 input images).
|
||||
- **Flux 2 Image-to-Image (Pro/Flex)**
|
||||
- Image-to-image node with a model dropdown for Pro or Flex.
|
||||
- Accepts 1–8 input images via ComfyUI batch.
|
||||
|
||||
+2
-1
@@ -1,6 +1,6 @@
|
||||
# Internal Status
|
||||
|
||||
Last updated: 2026-01-31
|
||||
Last updated: 2026-02-02
|
||||
|
||||
## Active Tasks
|
||||
- [x] Consolidate Gemini LLM nodes into one with model dropdown (2.5/3 Pro/Flash)
|
||||
@@ -9,3 +9,4 @@ Last updated: 2026-01-31
|
||||
|
||||
## Notes
|
||||
- 2026-01-31: Gemini LLM node now selects model via dropdown and logs selected model.
|
||||
- 2026-02-02: Seedream 4.5 Edit updated to accept up to 14 input images.
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
Seedream 4.5 is Bytedance’s refined image model for 4K generation, precise editing, and consistent multi-image output.
|
||||
|
||||
POST
|
||||
/api/v1/jobs/createTask
|
||||
Create Task
|
||||
Create a new generation task
|
||||
|
||||
Request Parameters
|
||||
The API accepts a JSON payload with the following structure:
|
||||
|
||||
Request Body Structure
|
||||
{
|
||||
"model": "string",
|
||||
"callBackUrl": "string (optional)",
|
||||
"input": {
|
||||
// Input parameters based on form configuration
|
||||
}
|
||||
}
|
||||
Root Level Parameters
|
||||
model
|
||||
Required
|
||||
string
|
||||
The model name to use for generation
|
||||
|
||||
Example:
|
||||
|
||||
"seedream/4.5-edit"
|
||||
callBackUrl
|
||||
Optional
|
||||
string
|
||||
Callback URL for task completion notifications. Optional parameter. If provided, the system will send POST requests to this URL when the task completes (success or failure). If not provided, no callback notifications will be sent.
|
||||
|
||||
Example:
|
||||
|
||||
"https://your-domain.com/api/callback"
|
||||
Input Object Parameters
|
||||
The input object contains the following parameters based on the form configuration:
|
||||
|
||||
input.prompt
|
||||
Required
|
||||
string
|
||||
A text description of the image you want to generate
|
||||
|
||||
Max length: 3000 characters
|
||||
Example:
|
||||
|
||||
"Keep the model's pose and the flowing shape of the liquid dress unchanged. Change the clothing material from silver metal to completely transparent clear water (or glass). Through the liquid water, the model's skin details are visible. Lighting changes from reflection to refraction."
|
||||
input.image_urls
|
||||
Required
|
||||
array(URL)
|
||||
Upload an image file to use as input for the API
|
||||
|
||||
File URL after upload, not file content; Accepted types: image/jpeg, image/png, image/webp; Max size: 10.0MB
|
||||
Max count: 14 images
|
||||
Example:
|
||||
|
||||
["https://static.aiquickdraw.com/tools/example/1764851484363_ScV1s2aq.webp"]
|
||||
input.aspect_ratio
|
||||
Required
|
||||
string
|
||||
Width-height ratio of the image, determining its visual form.
|
||||
|
||||
Available options:
|
||||
|
||||
1:1
|
||||
-
|
||||
1:1
|
||||
4:3
|
||||
-
|
||||
4:3
|
||||
3:4
|
||||
-
|
||||
3:4
|
||||
16:9
|
||||
-
|
||||
16:9
|
||||
9:16
|
||||
-
|
||||
9:16
|
||||
2:3
|
||||
-
|
||||
2:3
|
||||
3:2
|
||||
-
|
||||
3:2
|
||||
21:9
|
||||
-
|
||||
21:9
|
||||
Example:
|
||||
|
||||
"1:1"
|
||||
input.quality
|
||||
Required
|
||||
string
|
||||
Basic outputs 2K images, while High outputs 4K images.
|
||||
|
||||
Available options:
|
||||
|
||||
basic
|
||||
-
|
||||
Basic
|
||||
high
|
||||
-
|
||||
High
|
||||
Example:
|
||||
|
||||
"basic"
|
||||
Request Example
|
||||
|
||||
cURL
|
||||
|
||||
JavaScript
|
||||
|
||||
Python
|
||||
import requests
|
||||
import json
|
||||
|
||||
url = "https://api.kie.ai/api/v1/jobs/createTask"
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer YOUR_API_KEY"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"model": "seedream/4.5-edit",
|
||||
"callBackUrl": "https://your-domain.com/api/callback",
|
||||
"input": {
|
||||
"prompt": "Keep the model's pose and the flowing shape of the liquid dress unchanged. Change the clothing material from silver metal to completely transparent clear water (or glass). Through the liquid water, the model's skin details are visible. Lighting changes from reflection to refraction.",
|
||||
"image_urls": [
|
||||
"https://static.aiquickdraw.com/tools/example/1764851484363_ScV1s2aq.webp"
|
||||
],
|
||||
"aspect_ratio": "1:1",
|
||||
"quality": "basic"
|
||||
}
|
||||
}
|
||||
|
||||
response = requests.post(url, headers=headers, data=json.dumps(payload))
|
||||
result = response.json()
|
||||
print(result)
|
||||
Response Example
|
||||
{
|
||||
"code": 200,
|
||||
"message": "success",
|
||||
"data": {
|
||||
"taskId": "task_12345678"
|
||||
}
|
||||
}
|
||||
Response Fields
|
||||
code
|
||||
Status code, 200 for success, others for failure
|
||||
message
|
||||
Response message, error description when failed
|
||||
data.taskId
|
||||
Task ID for querying task status
|
||||
Callback Notifications
|
||||
When you provide the callBackUrl parameter when creating a task, the system will send POST requests to the specified URL upon task completion (success or failure).
|
||||
|
||||
Success Callback Example
|
||||
{
|
||||
"code": 200,
|
||||
"data": {
|
||||
"completeTime": 1755599644000,
|
||||
"consumeCredits": 100,
|
||||
"costTime": 8,
|
||||
"createTime": 1755599634000,
|
||||
"model": "seedream/4.5-edit",
|
||||
"param": "{\"callBackUrl\":\"https://your-domain.com/api/callback\",\"model\":\"seedream/4.5-edit\",\"input\":{\"prompt\":\"Keep the model's pose and the flowing shape of the liquid dress unchanged. Change the clothing material from silver metal to completely transparent clear water (or glass). Through the liquid water, the model's skin details are visible. Lighting changes from reflection to refraction.\",\"image_urls\":[\"https://static.aiquickdraw.com/tools/example/1764851484363_ScV1s2aq.webp\"],\"aspect_ratio\":\"1:1\",\"quality\":\"basic\"}}",
|
||||
"remainedCredits": 2510330,
|
||||
"resultJson": "{\"resultUrls\":[\"https://example.com/generated-image.jpg\"]}",
|
||||
"state": "success",
|
||||
"taskId": "e989621f54392584b05867f87b160672",
|
||||
"updateTime": 1755599644000
|
||||
},
|
||||
"msg": "Playground task completed successfully."
|
||||
}
|
||||
Failure Callback Example
|
||||
{
|
||||
"code": 501,
|
||||
"data": {
|
||||
"completeTime": 1755597081000,
|
||||
"consumeCredits": 0,
|
||||
"costTime": 0,
|
||||
"createTime": 1755596341000,
|
||||
"failCode": "500",
|
||||
"failMsg": "Internal server error",
|
||||
"model": "seedream/4.5-edit",
|
||||
"param": "{\"callBackUrl\":\"https://your-domain.com/api/callback\",\"model\":\"seedream/4.5-edit\",\"input\":{\"prompt\":\"Keep the model's pose and the flowing shape of the liquid dress unchanged. Change the clothing material from silver metal to completely transparent clear water (or glass). Through the liquid water, the model's skin details are visible. Lighting changes from reflection to refraction.\",\"image_urls\":[\"https://static.aiquickdraw.com/tools/example/1764851484363_ScV1s2aq.webp\"],\"aspect_ratio\":\"1:1\",\"quality\":\"basic\"}}",
|
||||
"remainedCredits": 2510430,
|
||||
"state": "fail",
|
||||
"taskId": "bd3a37c523149e4adf45a3ddb5faf1a8",
|
||||
"updateTime": 1755597097000
|
||||
},
|
||||
"msg": "Playground task failed."
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# KIE Seedream 4.5 Edit — Multi-Image Support Task List
|
||||
|
||||
Goal: allow the Seedream45_Edit node/helper to accept and upload up to 14 input images, then pass all uploaded URLs to `input.image_urls`.
|
||||
|
||||
## Context (current behavior)
|
||||
- Helper: `kie_api/seedream45_edit.py` uploads only the first image in the batch.
|
||||
- Node: `nodes.py` HELP text explicitly says "first image used".
|
||||
- Spec: `_internal/docs/KIE_API_SEEDREAM_45_EDIT_SPEC.md` lists `input.image_urls` but does not specify a max count.
|
||||
- Multi-image patterns to mirror: `kie_api/flux2_i2i.py` and `kie_api/nanobanana.py`.
|
||||
|
||||
## Open question (must confirm before coding)
|
||||
- Confirm the server-side max image count for Seedream 4.5 Edit (user believes 14). If confirmed, update the spec doc to include the max.
|
||||
|
||||
## Phase 1 — Spec/requirements alignment
|
||||
- [ ] Confirm max image count with KIE docs or internal source.
|
||||
- [ ] Update `_internal/docs/KIE_API_SEEDREAM_45_EDIT_SPEC.md` to include max count (1..14) once confirmed.
|
||||
|
||||
## Phase 2 — Helper changes (seedream45_edit.py)
|
||||
- [ ] Add `MAX_IMAGE_COUNT = 14` (or confirmed value).
|
||||
- [ ] Update `_validate_image_input()` to keep shape checks; do not fail on batch size > 1.
|
||||
- [ ] Upload up to `MAX_IMAGE_COUNT` images using the pattern in `flux2_i2i.py`:
|
||||
- log when more than max provided
|
||||
- iterate through `min(total_images, MAX_IMAGE_COUNT)`
|
||||
- build `image_urls` list from uploads
|
||||
- [ ] Update payload to use `image_urls` list (instead of a single URL).
|
||||
- [ ] Log how many URLs are sent to `createTask` for traceability.
|
||||
|
||||
## Phase 3 — Node wrapper and docs
|
||||
- [ ] Update `nodes.py` HELP text for `KIE_Seedream45_Edit` to reflect up to 14 images and that all provided images are uploaded (up to the cap).
|
||||
- [ ] Update `web/docs/KIE_Seedream45_Edit.md` with correct inputs/outputs and helper behavior (upload cap, truncation behavior).
|
||||
|
||||
## Phase 4 — Validation
|
||||
- [ ] Run `python3 -m py_compile nodes.py kie_api/seedream45_edit.py`.
|
||||
- [ ] Minimal manual test: pass a batch of 2+ images and confirm multiple uploads + task creation includes multiple URLs.
|
||||
|
||||
## Acceptance criteria
|
||||
- Helper uploads up to 14 images and sends all URLs in `input.image_urls`.
|
||||
- If more than 14 images are supplied, the helper logs a truncation message and uses only the first 14.
|
||||
- Node HELP and web docs clearly describe the multi-image behavior.
|
||||
@@ -33,6 +33,7 @@ MODEL_NAME = "seedream/4.5-edit"
|
||||
ASPECT_RATIO_OPTIONS = ["1:1", "4:3", "3:4", "16:9", "9:16", "2:3", "3:2", "21:9"]
|
||||
QUALITY_OPTIONS = ["basic", "high"]
|
||||
PROMPT_MAX_LENGTH = 3000
|
||||
MAX_IMAGE_COUNT = 14
|
||||
|
||||
|
||||
def _validate_options(aspect_ratio: str, quality: str) -> None:
|
||||
@@ -119,24 +120,32 @@ def run_seedream45_edit(
|
||||
|
||||
api_key = _load_api_key()
|
||||
|
||||
if images.shape[0] > 1:
|
||||
_log(log, f"More than 1 image provided ({images.shape[0]}); only the first will be used.")
|
||||
total_images = images.shape[0]
|
||||
if total_images > MAX_IMAGE_COUNT:
|
||||
_log(log, f"More than {MAX_IMAGE_COUNT} images provided ({total_images}); only first {MAX_IMAGE_COUNT} used.")
|
||||
|
||||
_log(log, "Uploading edit input image...")
|
||||
png_bytes = _image_tensor_to_png_bytes(images[0])
|
||||
image_url = _upload_image(api_key, png_bytes)
|
||||
_log(log, f"Input image upload success: {_truncate_url(image_url)}")
|
||||
upload_count = min(total_images, MAX_IMAGE_COUNT)
|
||||
image_urls: list[str] = []
|
||||
if upload_count > 0:
|
||||
_log(log, f"Uploading {upload_count} edit image(s)...")
|
||||
|
||||
for idx in range(upload_count):
|
||||
png_bytes = _image_tensor_to_png_bytes(images[idx])
|
||||
image_url = _upload_image(api_key, png_bytes)
|
||||
image_urls.append(image_url)
|
||||
_log(log, f"Image {idx + 1} upload success: {_truncate_url(image_url)}")
|
||||
|
||||
payload = {
|
||||
"model": MODEL_NAME,
|
||||
"input": {
|
||||
"prompt": prompt,
|
||||
"image_urls": [image_url],
|
||||
"image_urls": image_urls,
|
||||
"aspect_ratio": aspect_ratio,
|
||||
"quality": quality,
|
||||
},
|
||||
}
|
||||
|
||||
_log(log, f"Sending {len(image_urls)} image URL(s) to createTask")
|
||||
_log(log, "Creating Seedream 4.5 edit task...")
|
||||
start_time = time.time()
|
||||
task_id, create_response_text = _create_seedream45_edit_task(api_key, payload)
|
||||
|
||||
@@ -219,7 +219,7 @@ Edit an input image using Seedream 4.5.
|
||||
|
||||
Inputs:
|
||||
- prompt: Edit prompt (required)
|
||||
- images: Source image batch (first image used)
|
||||
- images: Source image batch (up to 14 images; all uploaded)
|
||||
- aspect_ratio / quality
|
||||
- poll_interval_s / timeout_s / log
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
## KIE Seedream 4.5 Edit
|
||||
|
||||
Edit an input image (or batch of images) using Seedream 4.5.
|
||||
|
||||
### Inputs
|
||||
- **prompt** (STRING, required): Edit prompt text (max 3000 chars).
|
||||
- **images** (IMAGE, required): Source image batch. Up to 14 images are uploaded; extra images are ignored.
|
||||
- **aspect_ratio** (COMBO, optional): `1:1`, `4:3`, `3:4`, `16:9`, `9:16`, `2:3`, `3:2`, `21:9` (default: `1:1`).
|
||||
- **quality** (COMBO, optional): `basic`, `high` (default: `basic`).
|
||||
- **log** (BOOLEAN, optional): Enable helper logging (default: `true`).
|
||||
|
||||
### Outputs
|
||||
- **IMAGE**: ComfyUI image tensor (BHWC float32, 0..1).
|
||||
|
||||
### Helper behavior
|
||||
- Uploads up to 14 images and sends all uploaded URLs in `input.image_urls`.
|
||||
- If more than 14 images are provided, only the first 14 are used and a log message is emitted.
|
||||
|
||||
Reference in New Issue
Block a user