mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-05-23 23:47:25 +08:00
Merge branch 'master' into fix/sqlalchemy-version-format
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Build package / Build Test (3.10) (push) Has been cancelled
Build package / Build Test (3.11) (push) Has been cancelled
Build package / Build Test (3.12) (push) Has been cancelled
Build package / Build Test (3.13) (push) Has been cancelled
Build package / Build Test (3.14) (push) Has been cancelled
Some checks failed
Python Linting / Run Ruff (push) Has been cancelled
Python Linting / Run Pylint (push) Has been cancelled
Build package / Build Test (3.10) (push) Has been cancelled
Build package / Build Test (3.11) (push) Has been cancelled
Build package / Build Test (3.12) (push) Has been cancelled
Build package / Build Test (3.13) (push) Has been cancelled
Build package / Build Test (3.14) (push) Has been cancelled
This commit is contained in:
commit
7d3498287c
45
.github/workflows/tag-dispatch-cloud.yml
vendored
Normal file
45
.github/workflows/tag-dispatch-cloud.yml
vendored
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
name: Tag Dispatch to Cloud
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dispatch-cloud:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Send repository dispatch to cloud
|
||||||
|
env:
|
||||||
|
DISPATCH_TOKEN: ${{ secrets.CLOUD_REPO_DISPATCH_TOKEN }}
|
||||||
|
RELEASE_TAG: ${{ github.ref_name }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
if [ -z "${DISPATCH_TOKEN:-}" ]; then
|
||||||
|
echo "::error::CLOUD_REPO_DISPATCH_TOKEN is required but not set."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
RELEASE_URL="https://github.com/${{ github.repository }}/releases/tag/${RELEASE_TAG}"
|
||||||
|
|
||||||
|
PAYLOAD="$(jq -n \
|
||||||
|
--arg release_tag "$RELEASE_TAG" \
|
||||||
|
--arg release_url "$RELEASE_URL" \
|
||||||
|
'{
|
||||||
|
event_type: "comfyui_tag_pushed",
|
||||||
|
client_payload: {
|
||||||
|
release_tag: $release_tag,
|
||||||
|
release_url: $release_url
|
||||||
|
}
|
||||||
|
}')"
|
||||||
|
|
||||||
|
curl -fsSL \
|
||||||
|
-X POST \
|
||||||
|
-H "Accept: application/vnd.github+json" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer ${DISPATCH_TOKEN}" \
|
||||||
|
https://api.github.com/repos/Comfy-Org/cloud/dispatches \
|
||||||
|
-d "$PAYLOAD"
|
||||||
|
|
||||||
|
echo "✅ Dispatched ComfyUI tag ${RELEASE_TAG} to Comfy-Org/cloud"
|
||||||
1620
blueprints/Crop Images 2x2.json
Normal file
1620
blueprints/Crop Images 2x2.json
Normal file
File diff suppressed because it is too large
Load Diff
2957
blueprints/Crop Images 3x3.json
Normal file
2957
blueprints/Crop Images 3x3.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -160,7 +160,7 @@
|
|||||||
},
|
},
|
||||||
"revision": 0,
|
"revision": 0,
|
||||||
"config": {},
|
"config": {},
|
||||||
"name": "local-Depth to Image (Z-Image-Turbo)",
|
"name": "Depth to Image (Z-Image-Turbo)",
|
||||||
"inputNode": {
|
"inputNode": {
|
||||||
"id": -10,
|
"id": -10,
|
||||||
"bounding": [
|
"bounding": [
|
||||||
@ -2482,4 +2482,4 @@
|
|||||||
"VHS_KeepIntermediate": true
|
"VHS_KeepIntermediate": true
|
||||||
},
|
},
|
||||||
"version": 0.4
|
"version": 0.4
|
||||||
}
|
}
|
||||||
@ -261,7 +261,7 @@
|
|||||||
},
|
},
|
||||||
"revision": 0,
|
"revision": 0,
|
||||||
"config": {},
|
"config": {},
|
||||||
"name": "local-Depth to Video (LTX 2.0)",
|
"name": "Depth to Video (LTX 2.0)",
|
||||||
"inputNode": {
|
"inputNode": {
|
||||||
"id": -10,
|
"id": -10,
|
||||||
"bounding": [
|
"bounding": [
|
||||||
@ -5208,4 +5208,4 @@
|
|||||||
"workflowRendererVersion": "LG"
|
"workflowRendererVersion": "LG"
|
||||||
},
|
},
|
||||||
"version": 0.4
|
"version": 0.4
|
||||||
}
|
}
|
||||||
3360
blueprints/First-Last-Frame to Video (LTX-2.3).json
Normal file
3360
blueprints/First-Last-Frame to Video (LTX-2.3).json
Normal file
File diff suppressed because it is too large
Load Diff
2148
blueprints/Image Edit (FireRed Image Edit 1.1).json
Normal file
2148
blueprints/Image Edit (FireRed Image Edit 1.1).json
Normal file
File diff suppressed because it is too large
Load Diff
@ -128,7 +128,7 @@
|
|||||||
},
|
},
|
||||||
"revision": 0,
|
"revision": 0,
|
||||||
"config": {},
|
"config": {},
|
||||||
"name": "local-Image Edit (Flux.2 Klein 4B)",
|
"name": "Image Edit (Flux.2 Klein 4B)",
|
||||||
"inputNode": {
|
"inputNode": {
|
||||||
"id": -10,
|
"id": -10,
|
||||||
"bounding": [
|
"bounding": [
|
||||||
@ -1837,4 +1837,4 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"version": 0.4
|
"version": 0.4
|
||||||
}
|
}
|
||||||
1427
blueprints/Image Edit (LongCat Image Edit).json
Normal file
1427
blueprints/Image Edit (LongCat Image Edit).json
Normal file
File diff suppressed because it is too large
Load Diff
1205
blueprints/Image Inpainting (Flux.1 Fill Dev).json
Normal file
1205
blueprints/Image Inpainting (Flux.1 Fill Dev).json
Normal file
File diff suppressed because it is too large
Load Diff
@ -124,7 +124,7 @@
|
|||||||
},
|
},
|
||||||
"revision": 0,
|
"revision": 0,
|
||||||
"config": {},
|
"config": {},
|
||||||
"name": "local-Image Inpainting (Qwen-image)",
|
"name": "Image Inpainting (Qwen-image)",
|
||||||
"inputNode": {
|
"inputNode": {
|
||||||
"id": -10,
|
"id": -10,
|
||||||
"bounding": [
|
"bounding": [
|
||||||
@ -1923,4 +1923,4 @@
|
|||||||
"workflowRendererVersion": "LG"
|
"workflowRendererVersion": "LG"
|
||||||
},
|
},
|
||||||
"version": 0.4
|
"version": 0.4
|
||||||
}
|
}
|
||||||
@ -204,7 +204,7 @@
|
|||||||
},
|
},
|
||||||
"revision": 0,
|
"revision": 0,
|
||||||
"config": {},
|
"config": {},
|
||||||
"name": "local-Image Outpainting (Qwen-Image)",
|
"name": "Image Outpainting (Qwen-Image)",
|
||||||
"inputNode": {
|
"inputNode": {
|
||||||
"id": -10,
|
"id": -10,
|
||||||
"bounding": [
|
"bounding": [
|
||||||
@ -2749,4 +2749,4 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"version": 0.4
|
"version": 0.4
|
||||||
}
|
}
|
||||||
@ -1,15 +1,14 @@
|
|||||||
{
|
{
|
||||||
"id": "1a761372-7c82-4016-b9bf-fa285967e1e9",
|
|
||||||
"revision": 0,
|
"revision": 0,
|
||||||
"last_node_id": 83,
|
"last_node_id": 176,
|
||||||
"last_link_id": 0,
|
"last_link_id": 0,
|
||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
"id": 83,
|
"id": 176,
|
||||||
"type": "f754a936-daaf-4b6e-9658-41fdc54d301d",
|
"type": "2d2e3c8e-53b3-4618-be52-6d1d99382f0e",
|
||||||
"pos": [
|
"pos": [
|
||||||
61.999827823554256,
|
-1150,
|
||||||
153.3332507624185
|
200
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
400,
|
400,
|
||||||
@ -56,6 +55,38 @@
|
|||||||
"name": "layers"
|
"name": "layers"
|
||||||
},
|
},
|
||||||
"link": null
|
"link": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "seed",
|
||||||
|
"type": "INT",
|
||||||
|
"widget": {
|
||||||
|
"name": "seed"
|
||||||
|
},
|
||||||
|
"link": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unet_name",
|
||||||
|
"type": "COMBO",
|
||||||
|
"widget": {
|
||||||
|
"name": "unet_name"
|
||||||
|
},
|
||||||
|
"link": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "clip_name",
|
||||||
|
"type": "COMBO",
|
||||||
|
"widget": {
|
||||||
|
"name": "clip_name"
|
||||||
|
},
|
||||||
|
"link": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "vae_name",
|
||||||
|
"type": "COMBO",
|
||||||
|
"widget": {
|
||||||
|
"name": "vae_name"
|
||||||
|
},
|
||||||
|
"link": null
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@ -66,28 +97,41 @@
|
|||||||
"links": []
|
"links": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"title": "Image to Layers (Qwen-Image-Layered)",
|
||||||
"properties": {
|
"properties": {
|
||||||
"proxyWidgets": [
|
"proxyWidgets": [
|
||||||
[
|
[
|
||||||
"-1",
|
"6",
|
||||||
"text"
|
"text"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"-1",
|
"3",
|
||||||
"steps"
|
"steps"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"-1",
|
"3",
|
||||||
"cfg"
|
"cfg"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"-1",
|
"83",
|
||||||
"layers"
|
"layers"
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"3",
|
"3",
|
||||||
"seed"
|
"seed"
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
"37",
|
||||||
|
"unet_name"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"38",
|
||||||
|
"clip_name"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"39",
|
||||||
|
"vae_name"
|
||||||
|
],
|
||||||
[
|
[
|
||||||
"3",
|
"3",
|
||||||
"control_after_generate"
|
"control_after_generate"
|
||||||
@ -95,6 +139,11 @@
|
|||||||
],
|
],
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -103,25 +152,20 @@
|
|||||||
"secondTabOffset": 80,
|
"secondTabOffset": 80,
|
||||||
"secondTabWidth": 65
|
"secondTabWidth": 65
|
||||||
},
|
},
|
||||||
"widgets_values": [
|
"widgets_values": []
|
||||||
"",
|
|
||||||
20,
|
|
||||||
2.5,
|
|
||||||
2
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"links": [],
|
"links": [],
|
||||||
"groups": [],
|
"version": 0.4,
|
||||||
"definitions": {
|
"definitions": {
|
||||||
"subgraphs": [
|
"subgraphs": [
|
||||||
{
|
{
|
||||||
"id": "f754a936-daaf-4b6e-9658-41fdc54d301d",
|
"id": "2d2e3c8e-53b3-4618-be52-6d1d99382f0e",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"state": {
|
"state": {
|
||||||
"lastGroupId": 3,
|
"lastGroupId": 8,
|
||||||
"lastNodeId": 83,
|
"lastNodeId": 176,
|
||||||
"lastLinkId": 159,
|
"lastLinkId": 380,
|
||||||
"lastRerouteId": 0
|
"lastRerouteId": 0
|
||||||
},
|
},
|
||||||
"revision": 0,
|
"revision": 0,
|
||||||
@ -130,10 +174,10 @@
|
|||||||
"inputNode": {
|
"inputNode": {
|
||||||
"id": -10,
|
"id": -10,
|
||||||
"bounding": [
|
"bounding": [
|
||||||
-510,
|
-720,
|
||||||
523,
|
720,
|
||||||
120,
|
120,
|
||||||
140
|
220
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"outputNode": {
|
"outputNode": {
|
||||||
@ -156,8 +200,8 @@
|
|||||||
],
|
],
|
||||||
"localized_name": "image",
|
"localized_name": "image",
|
||||||
"pos": [
|
"pos": [
|
||||||
-410,
|
-620,
|
||||||
543
|
740
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -168,8 +212,8 @@
|
|||||||
150
|
150
|
||||||
],
|
],
|
||||||
"pos": [
|
"pos": [
|
||||||
-410,
|
-620,
|
||||||
563
|
760
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -180,8 +224,8 @@
|
|||||||
153
|
153
|
||||||
],
|
],
|
||||||
"pos": [
|
"pos": [
|
||||||
-410,
|
-620,
|
||||||
583
|
780
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -192,8 +236,8 @@
|
|||||||
154
|
154
|
||||||
],
|
],
|
||||||
"pos": [
|
"pos": [
|
||||||
-410,
|
-620,
|
||||||
603
|
800
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -204,8 +248,56 @@
|
|||||||
159
|
159
|
||||||
],
|
],
|
||||||
"pos": [
|
"pos": [
|
||||||
-410,
|
-620,
|
||||||
623
|
820
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "9f76338b-f4ca-4bb3-b61a-57b3f233061e",
|
||||||
|
"name": "seed",
|
||||||
|
"type": "INT",
|
||||||
|
"linkIds": [
|
||||||
|
377
|
||||||
|
],
|
||||||
|
"pos": [
|
||||||
|
-620,
|
||||||
|
840
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "8d0422d5-5eee-4f7e-9817-dc613cc62eca",
|
||||||
|
"name": "unet_name",
|
||||||
|
"type": "COMBO",
|
||||||
|
"linkIds": [
|
||||||
|
378
|
||||||
|
],
|
||||||
|
"pos": [
|
||||||
|
-620,
|
||||||
|
860
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "552eece2-a735-4d00-ae78-ded454622bc1",
|
||||||
|
"name": "clip_name",
|
||||||
|
"type": "COMBO",
|
||||||
|
"linkIds": [
|
||||||
|
379
|
||||||
|
],
|
||||||
|
"pos": [
|
||||||
|
-620,
|
||||||
|
880
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1e6d141c-d0f9-4a2b-895c-b6780e57cfa0",
|
||||||
|
"name": "vae_name",
|
||||||
|
"type": "COMBO",
|
||||||
|
"linkIds": [
|
||||||
|
380
|
||||||
|
],
|
||||||
|
"pos": [
|
||||||
|
-620,
|
||||||
|
900
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -231,14 +323,14 @@
|
|||||||
"type": "CLIPLoader",
|
"type": "CLIPLoader",
|
||||||
"pos": [
|
"pos": [
|
||||||
-320,
|
-320,
|
||||||
310
|
360
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
346.7470703125,
|
350,
|
||||||
106
|
150
|
||||||
],
|
],
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 0,
|
"order": 5,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@ -248,7 +340,7 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"name": "clip_name"
|
"name": "clip_name"
|
||||||
},
|
},
|
||||||
"link": null
|
"link": 379
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"localized_name": "type",
|
"localized_name": "type",
|
||||||
@ -283,9 +375,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "CLIPLoader",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "CLIPLoader",
|
||||||
"models": [
|
"models": [
|
||||||
{
|
{
|
||||||
"name": "qwen_2.5_vl_7b_fp8_scaled.safetensors",
|
"name": "qwen_2.5_vl_7b_fp8_scaled.safetensors",
|
||||||
@ -312,14 +409,14 @@
|
|||||||
"type": "VAELoader",
|
"type": "VAELoader",
|
||||||
"pos": [
|
"pos": [
|
||||||
-320,
|
-320,
|
||||||
460
|
580
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
346.7470703125,
|
350,
|
||||||
58
|
110
|
||||||
],
|
],
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 1,
|
"order": 6,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@ -329,7 +426,7 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"name": "vae_name"
|
"name": "vae_name"
|
||||||
},
|
},
|
||||||
"link": null
|
"link": 380
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"outputs": [
|
"outputs": [
|
||||||
@ -345,9 +442,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "VAELoader",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "VAELoader",
|
||||||
"models": [
|
"models": [
|
||||||
{
|
{
|
||||||
"name": "qwen_image_layered_vae.safetensors",
|
"name": "qwen_image_layered_vae.safetensors",
|
||||||
@ -375,11 +477,11 @@
|
|||||||
420
|
420
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
425.27801513671875,
|
430,
|
||||||
180.6060791015625
|
190
|
||||||
],
|
],
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 3,
|
"order": 2,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@ -411,9 +513,14 @@
|
|||||||
],
|
],
|
||||||
"title": "CLIP Text Encode (Negative Prompt)",
|
"title": "CLIP Text Encode (Negative Prompt)",
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "CLIPTextEncode",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "CLIPTextEncode",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -432,12 +539,12 @@
|
|||||||
"id": 70,
|
"id": 70,
|
||||||
"type": "ReferenceLatent",
|
"type": "ReferenceLatent",
|
||||||
"pos": [
|
"pos": [
|
||||||
330,
|
140,
|
||||||
670
|
700
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
204.1666717529297,
|
210,
|
||||||
46
|
50
|
||||||
],
|
],
|
||||||
"flags": {
|
"flags": {
|
||||||
"collapsed": true
|
"collapsed": true
|
||||||
@ -470,9 +577,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "ReferenceLatent",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "ReferenceLatent",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -480,19 +592,18 @@
|
|||||||
"secondTabText": "Send Back",
|
"secondTabText": "Send Back",
|
||||||
"secondTabOffset": 80,
|
"secondTabOffset": 80,
|
||||||
"secondTabWidth": 65
|
"secondTabWidth": 65
|
||||||
},
|
}
|
||||||
"widgets_values": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 69,
|
"id": 69,
|
||||||
"type": "ReferenceLatent",
|
"type": "ReferenceLatent",
|
||||||
"pos": [
|
"pos": [
|
||||||
330,
|
160,
|
||||||
710
|
820
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
204.1666717529297,
|
210,
|
||||||
46
|
50
|
||||||
],
|
],
|
||||||
"flags": {
|
"flags": {
|
||||||
"collapsed": true
|
"collapsed": true
|
||||||
@ -525,9 +636,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "ReferenceLatent",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "ReferenceLatent",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -535,8 +651,7 @@
|
|||||||
"secondTabText": "Send Back",
|
"secondTabText": "Send Back",
|
||||||
"secondTabOffset": 80,
|
"secondTabOffset": 80,
|
||||||
"secondTabWidth": 65
|
"secondTabWidth": 65
|
||||||
},
|
}
|
||||||
"widgets_values": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 66,
|
"id": 66,
|
||||||
@ -547,10 +662,10 @@
|
|||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
270,
|
270,
|
||||||
58
|
110
|
||||||
],
|
],
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 4,
|
"order": 7,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@ -580,9 +695,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "ModelSamplingAuraFlow",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "ModelSamplingAuraFlow",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -600,11 +720,11 @@
|
|||||||
"type": "LatentCutToBatch",
|
"type": "LatentCutToBatch",
|
||||||
"pos": [
|
"pos": [
|
||||||
830,
|
830,
|
||||||
160
|
140
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
270,
|
270,
|
||||||
82
|
140
|
||||||
],
|
],
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 11,
|
"order": 11,
|
||||||
@ -646,9 +766,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "LatentCutToBatch",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "LatentCutToBatch",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -666,12 +791,12 @@
|
|||||||
"id": 71,
|
"id": 71,
|
||||||
"type": "VAEEncode",
|
"type": "VAEEncode",
|
||||||
"pos": [
|
"pos": [
|
||||||
100,
|
-280,
|
||||||
690
|
780
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
140,
|
230,
|
||||||
46
|
100
|
||||||
],
|
],
|
||||||
"flags": {
|
"flags": {
|
||||||
"collapsed": false
|
"collapsed": false
|
||||||
@ -704,9 +829,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "VAEEncode",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "VAEEncode",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -714,24 +844,23 @@
|
|||||||
"secondTabText": "Send Back",
|
"secondTabText": "Send Back",
|
||||||
"secondTabOffset": 80,
|
"secondTabOffset": 80,
|
||||||
"secondTabWidth": 65
|
"secondTabWidth": 65
|
||||||
},
|
}
|
||||||
"widgets_values": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 8,
|
"id": 8,
|
||||||
"type": "VAEDecode",
|
"type": "VAEDecode",
|
||||||
"pos": [
|
"pos": [
|
||||||
850,
|
850,
|
||||||
310
|
370
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
210,
|
210,
|
||||||
46
|
50
|
||||||
],
|
],
|
||||||
"flags": {
|
"flags": {
|
||||||
"collapsed": true
|
"collapsed": true
|
||||||
},
|
},
|
||||||
"order": 7,
|
"order": 3,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@ -759,9 +888,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "VAEDecode",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "VAEDecode",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -769,8 +903,7 @@
|
|||||||
"secondTabText": "Send Back",
|
"secondTabText": "Send Back",
|
||||||
"secondTabOffset": 80,
|
"secondTabOffset": 80,
|
||||||
"secondTabWidth": 65
|
"secondTabWidth": 65
|
||||||
},
|
}
|
||||||
"widgets_values": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 6,
|
"id": 6,
|
||||||
@ -780,11 +913,11 @@
|
|||||||
180
|
180
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
422.84503173828125,
|
430,
|
||||||
164.31304931640625
|
170
|
||||||
],
|
],
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 6,
|
"order": 1,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@ -816,9 +949,14 @@
|
|||||||
],
|
],
|
||||||
"title": "CLIP Text Encode (Positive Prompt)",
|
"title": "CLIP Text Encode (Positive Prompt)",
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "CLIPTextEncode",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "CLIPTextEncode",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -838,14 +976,14 @@
|
|||||||
"type": "KSampler",
|
"type": "KSampler",
|
||||||
"pos": [
|
"pos": [
|
||||||
530,
|
530,
|
||||||
280
|
340
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
270,
|
270,
|
||||||
400
|
400
|
||||||
],
|
],
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 5,
|
"order": 0,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@ -879,7 +1017,7 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"name": "seed"
|
"name": "seed"
|
||||||
},
|
},
|
||||||
"link": null
|
"link": 377
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"localized_name": "steps",
|
"localized_name": "steps",
|
||||||
@ -939,9 +1077,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "KSampler",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "KSampler",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -964,12 +1107,12 @@
|
|||||||
"id": 78,
|
"id": 78,
|
||||||
"type": "GetImageSize",
|
"type": "GetImageSize",
|
||||||
"pos": [
|
"pos": [
|
||||||
80,
|
-280,
|
||||||
790
|
930
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
210,
|
230,
|
||||||
136
|
140
|
||||||
],
|
],
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 12,
|
"order": 12,
|
||||||
@ -1007,9 +1150,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "GetImageSize",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "GetImageSize",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -1017,23 +1165,23 @@
|
|||||||
"secondTabText": "Send Back",
|
"secondTabText": "Send Back",
|
||||||
"secondTabOffset": 80,
|
"secondTabOffset": 80,
|
||||||
"secondTabWidth": 65
|
"secondTabWidth": 65
|
||||||
},
|
}
|
||||||
"widgets_values": []
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 83,
|
"id": 83,
|
||||||
"type": "EmptyQwenImageLayeredLatentImage",
|
"type": "EmptyQwenImageLayeredLatentImage",
|
||||||
"pos": [
|
"pos": [
|
||||||
320,
|
-280,
|
||||||
790
|
1120
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
330.9341796875,
|
340,
|
||||||
130
|
200
|
||||||
],
|
],
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 13,
|
"order": 13,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
|
"showAdvanced": true,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"localized_name": "width",
|
"localized_name": "width",
|
||||||
@ -1083,9 +1231,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "EmptyQwenImageLayeredLatentImage",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "EmptyQwenImageLayeredLatentImage",
|
||||||
"enableTabs": false,
|
"enableTabs": false,
|
||||||
"tabWidth": 65,
|
"tabWidth": 65,
|
||||||
"tabXOffset": 10,
|
"tabXOffset": 10,
|
||||||
@ -1109,11 +1262,11 @@
|
|||||||
180
|
180
|
||||||
],
|
],
|
||||||
"size": [
|
"size": [
|
||||||
346.7470703125,
|
350,
|
||||||
82
|
110
|
||||||
],
|
],
|
||||||
"flags": {},
|
"flags": {},
|
||||||
"order": 2,
|
"order": 4,
|
||||||
"mode": 0,
|
"mode": 0,
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
@ -1123,7 +1276,7 @@
|
|||||||
"widget": {
|
"widget": {
|
||||||
"name": "unet_name"
|
"name": "unet_name"
|
||||||
},
|
},
|
||||||
"link": null
|
"link": 378
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"localized_name": "weight_dtype",
|
"localized_name": "weight_dtype",
|
||||||
@ -1147,9 +1300,14 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"Node name for S&R": "UNETLoader",
|
|
||||||
"cnr_id": "comfy-core",
|
"cnr_id": "comfy-core",
|
||||||
"ver": "0.5.1",
|
"ver": "0.5.1",
|
||||||
|
"ue_properties": {
|
||||||
|
"widget_ue_connectable": {},
|
||||||
|
"input_ue_unconnectable": {},
|
||||||
|
"version": "7.7"
|
||||||
|
},
|
||||||
|
"Node name for S&R": "UNETLoader",
|
||||||
"models": [
|
"models": [
|
||||||
{
|
{
|
||||||
"name": "qwen_image_layered_bf16.safetensors",
|
"name": "qwen_image_layered_bf16.safetensors",
|
||||||
@ -1191,8 +1349,8 @@
|
|||||||
"bounding": [
|
"bounding": [
|
||||||
-330,
|
-330,
|
||||||
110,
|
110,
|
||||||
366.7470703125,
|
370,
|
||||||
421.6
|
610
|
||||||
],
|
],
|
||||||
"color": "#3f789e",
|
"color": "#3f789e",
|
||||||
"font_size": 24,
|
"font_size": 24,
|
||||||
@ -1391,6 +1549,38 @@
|
|||||||
"target_id": 83,
|
"target_id": 83,
|
||||||
"target_slot": 2,
|
"target_slot": 2,
|
||||||
"type": "INT"
|
"type": "INT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 377,
|
||||||
|
"origin_id": -10,
|
||||||
|
"origin_slot": 5,
|
||||||
|
"target_id": 3,
|
||||||
|
"target_slot": 4,
|
||||||
|
"type": "INT"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 378,
|
||||||
|
"origin_id": -10,
|
||||||
|
"origin_slot": 6,
|
||||||
|
"target_id": 37,
|
||||||
|
"target_slot": 0,
|
||||||
|
"type": "COMBO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 379,
|
||||||
|
"origin_id": -10,
|
||||||
|
"origin_slot": 7,
|
||||||
|
"target_id": 38,
|
||||||
|
"target_slot": 0,
|
||||||
|
"type": "COMBO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 380,
|
||||||
|
"origin_id": -10,
|
||||||
|
"origin_slot": 8,
|
||||||
|
"target_id": 39,
|
||||||
|
"target_slot": 0,
|
||||||
|
"type": "COMBO"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"extra": {
|
"extra": {
|
||||||
@ -1400,7 +1590,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"config": {},
|
|
||||||
"extra": {
|
"extra": {
|
||||||
"ds": {
|
"ds": {
|
||||||
"scale": 1.14,
|
"scale": 1.14,
|
||||||
@ -1409,7 +1598,6 @@
|
|||||||
6.855893974423647
|
6.855893974423647
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"workflowRendererVersion": "LG"
|
"ue_links": []
|
||||||
},
|
}
|
||||||
"version": 0.4
|
}
|
||||||
}
|
|
||||||
4233
blueprints/Image to Video (LTX-2.3).json
Normal file
4233
blueprints/Image to Video (LTX-2.3).json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1046
blueprints/Text to Image (Flux.1 Dev).json
Normal file
1046
blueprints/Text to Image (Flux.1 Dev).json
Normal file
File diff suppressed because it is too large
Load Diff
1040
blueprints/Text to Image (Flux.1 Krea Dev).json
Normal file
1040
blueprints/Text to Image (Flux.1 Krea Dev).json
Normal file
File diff suppressed because it is too large
Load Diff
1468
blueprints/Text to Image (NetaYume Lumina).json
Normal file
1468
blueprints/Text to Image (NetaYume Lumina).json
Normal file
File diff suppressed because it is too large
Load Diff
1951
blueprints/Text to Image (Qwen-Image 2512).json
Normal file
1951
blueprints/Text to Image (Qwen-Image 2512).json
Normal file
File diff suppressed because it is too large
Load Diff
1881
blueprints/Text to Image (Qwen-Image).json
Normal file
1881
blueprints/Text to Image (Qwen-Image).json
Normal file
File diff suppressed because it is too large
Load Diff
4296
blueprints/Text to Video (LTX-2.3).json
Normal file
4296
blueprints/Text to Video (LTX-2.3).json
Normal file
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,7 @@ import comfy.float
|
|||||||
import comfy.hooks
|
import comfy.hooks
|
||||||
import comfy.lora
|
import comfy.lora
|
||||||
import comfy.model_management
|
import comfy.model_management
|
||||||
|
import comfy.ops
|
||||||
import comfy.patcher_extension
|
import comfy.patcher_extension
|
||||||
import comfy.utils
|
import comfy.utils
|
||||||
from comfy.comfy_types import UnetWrapperFunction
|
from comfy.comfy_types import UnetWrapperFunction
|
||||||
@ -856,7 +857,9 @@ class ModelPatcher:
|
|||||||
if m.comfy_patched_weights == True:
|
if m.comfy_patched_weights == True:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for param in params:
|
for param, param_value in params.items():
|
||||||
|
if hasattr(m, "comfy_cast_weights") and getattr(param_value, "is_meta", False):
|
||||||
|
comfy.ops.disable_weight_init._zero_init_parameter(m, param)
|
||||||
key = key_param_name_to_key(n, param)
|
key = key_param_name_to_key(n, param)
|
||||||
self.unpin_weight(key)
|
self.unpin_weight(key)
|
||||||
self.patch_weight_to_device(key, device_to=device_to)
|
self.patch_weight_to_device(key, device_to=device_to)
|
||||||
|
|||||||
16
comfy/ops.py
16
comfy/ops.py
@ -79,14 +79,21 @@ def cast_to_input(weight, input, non_blocking=False, copy=True):
|
|||||||
return comfy.model_management.cast_to(weight, input.dtype, input.device, non_blocking=non_blocking, copy=copy)
|
return comfy.model_management.cast_to(weight, input.dtype, input.device, non_blocking=non_blocking, copy=copy)
|
||||||
|
|
||||||
|
|
||||||
def cast_bias_weight_with_vbar(s, dtype, device, bias_dtype, non_blocking, compute_dtype, want_requant):
|
def materialize_meta_param(s, param_keys):
|
||||||
|
for param_key in param_keys:
|
||||||
|
param = getattr(s, param_key, None)
|
||||||
|
if param is not None and getattr(param, "is_meta", False):
|
||||||
|
setattr(s, param_key, torch.nn.Parameter(torch.zeros(param.shape, dtype=param.dtype), requires_grad=param.requires_grad))
|
||||||
|
|
||||||
|
|
||||||
|
def cast_bias_weight_with_vbar(s, dtype, device, bias_dtype, non_blocking, compute_dtype, want_requant):
|
||||||
#vbar doesn't support CPU weights, but some custom nodes have weird paths
|
#vbar doesn't support CPU weights, but some custom nodes have weird paths
|
||||||
#that might switch the layer to the CPU and expect it to work. We have to take
|
#that might switch the layer to the CPU and expect it to work. We have to take
|
||||||
#a clone conservatively as we are mmapped and some SFT files are packed misaligned
|
#a clone conservatively as we are mmapped and some SFT files are packed misaligned
|
||||||
#If you are a custom node author reading this, please move your layer to the GPU
|
#If you are a custom node author reading this, please move your layer to the GPU
|
||||||
#or declare your ModelPatcher as CPU in the first place.
|
#or declare your ModelPatcher as CPU in the first place.
|
||||||
if comfy.model_management.is_device_cpu(device):
|
if comfy.model_management.is_device_cpu(device):
|
||||||
|
materialize_meta_param(s, ["weight", "bias"])
|
||||||
weight = s.weight.to(dtype=dtype, copy=True)
|
weight = s.weight.to(dtype=dtype, copy=True)
|
||||||
if isinstance(weight, QuantizedTensor):
|
if isinstance(weight, QuantizedTensor):
|
||||||
weight = weight.dequantize()
|
weight = weight.dequantize()
|
||||||
@ -108,6 +115,7 @@ def cast_bias_weight_with_vbar(s, dtype, device, bias_dtype, non_blocking, compu
|
|||||||
xfer_dest = comfy_aimdo.torch.aimdo_to_tensor(s._v, device)
|
xfer_dest = comfy_aimdo.torch.aimdo_to_tensor(s._v, device)
|
||||||
|
|
||||||
if not resident:
|
if not resident:
|
||||||
|
materialize_meta_param(s, ["weight", "bias"])
|
||||||
cast_geometry = comfy.memory_management.tensors_to_geometries([ s.weight, s.bias ])
|
cast_geometry = comfy.memory_management.tensors_to_geometries([ s.weight, s.bias ])
|
||||||
cast_dest = None
|
cast_dest = None
|
||||||
|
|
||||||
@ -306,6 +314,12 @@ class CastWeightBiasOp:
|
|||||||
bias_function = []
|
bias_function = []
|
||||||
|
|
||||||
class disable_weight_init:
|
class disable_weight_init:
|
||||||
|
@staticmethod
|
||||||
|
def _zero_init_parameter(module, name):
|
||||||
|
param = getattr(module, name)
|
||||||
|
device = None if getattr(param, "is_meta", False) else param.device
|
||||||
|
setattr(module, name, torch.nn.Parameter(torch.zeros(param.shape, device=device, dtype=param.dtype), requires_grad=False))
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _lazy_load_from_state_dict(module, state_dict, prefix, local_metadata,
|
def _lazy_load_from_state_dict(module, state_dict, prefix, local_metadata,
|
||||||
missing_keys, unexpected_keys, weight_shape,
|
missing_keys, unexpected_keys, weight_shape,
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import numpy as np
|
|||||||
import math
|
import math
|
||||||
import torch
|
import torch
|
||||||
from .._util import VideoContainer, VideoCodec, VideoComponents
|
from .._util import VideoContainer, VideoCodec, VideoComponents
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
def container_to_output_format(container_format: str | None) -> str | None:
|
def container_to_output_format(container_format: str | None) -> str | None:
|
||||||
@ -238,64 +239,107 @@ class VideoFromFile(VideoInput):
|
|||||||
start_time = max(self._get_raw_duration() + self.__start_time, 0)
|
start_time = max(self._get_raw_duration() + self.__start_time, 0)
|
||||||
else:
|
else:
|
||||||
start_time = self.__start_time
|
start_time = self.__start_time
|
||||||
|
|
||||||
# Get video frames
|
# Get video frames
|
||||||
frames = []
|
frames = []
|
||||||
|
audio_frames = []
|
||||||
|
alphas = None
|
||||||
start_pts = int(start_time / video_stream.time_base)
|
start_pts = int(start_time / video_stream.time_base)
|
||||||
end_pts = int((start_time + self.__duration) / video_stream.time_base)
|
end_pts = int((start_time + self.__duration) / video_stream.time_base)
|
||||||
container.seek(start_pts, stream=video_stream)
|
|
||||||
for frame in container.decode(video_stream):
|
|
||||||
if frame.pts < start_pts:
|
|
||||||
continue
|
|
||||||
if self.__duration and frame.pts >= end_pts:
|
|
||||||
break
|
|
||||||
img = frame.to_ndarray(format='gbrpf32le') # shape: (H, W, 3)
|
|
||||||
img = torch.from_numpy(img)
|
|
||||||
frames.append(img)
|
|
||||||
|
|
||||||
images = torch.stack(frames) if len(frames) > 0 else torch.zeros(0, 3, 0, 0)
|
if start_pts != 0:
|
||||||
|
container.seek(start_pts, stream=video_stream)
|
||||||
|
|
||||||
|
image_format = 'gbrpf32le'
|
||||||
|
audio = None
|
||||||
|
|
||||||
|
streams = [video_stream]
|
||||||
|
has_first_audio_frame = False
|
||||||
|
checked_alpha = False
|
||||||
|
|
||||||
|
# Default to False so we decode until EOF if duration is 0
|
||||||
|
video_done = False
|
||||||
|
audio_done = True
|
||||||
|
|
||||||
|
if len(container.streams.audio):
|
||||||
|
audio_stream = container.streams.audio[-1]
|
||||||
|
streams += [audio_stream]
|
||||||
|
resampler = av.audio.resampler.AudioResampler(format='fltp')
|
||||||
|
audio_done = False
|
||||||
|
|
||||||
|
for packet in container.demux(*streams):
|
||||||
|
if video_done and audio_done:
|
||||||
|
break
|
||||||
|
|
||||||
|
if packet.stream.type == "video":
|
||||||
|
if video_done:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
for frame in packet.decode():
|
||||||
|
if frame.pts < start_pts:
|
||||||
|
continue
|
||||||
|
if self.__duration and frame.pts >= end_pts:
|
||||||
|
video_done = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not checked_alpha:
|
||||||
|
for comp in frame.format.components:
|
||||||
|
if comp.is_alpha:
|
||||||
|
alphas = []
|
||||||
|
image_format = 'gbrapf32le'
|
||||||
|
break
|
||||||
|
checked_alpha = True
|
||||||
|
|
||||||
|
img = frame.to_ndarray(format=image_format) # shape: (H, W, 4)
|
||||||
|
if alphas is None:
|
||||||
|
frames.append(torch.from_numpy(img))
|
||||||
|
else:
|
||||||
|
frames.append(torch.from_numpy(img[..., :-1]))
|
||||||
|
alphas.append(torch.from_numpy(img[..., -1:]))
|
||||||
|
except av.error.InvalidDataError:
|
||||||
|
logging.info("pyav decode error")
|
||||||
|
|
||||||
|
elif packet.stream.type == "audio":
|
||||||
|
if audio_done:
|
||||||
|
continue
|
||||||
|
|
||||||
|
aframes = itertools.chain.from_iterable(
|
||||||
|
map(resampler.resample, packet.decode())
|
||||||
|
)
|
||||||
|
for frame in aframes:
|
||||||
|
if self.__duration and frame.time > start_time + self.__duration:
|
||||||
|
audio_done = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not has_first_audio_frame:
|
||||||
|
offset_seconds = start_time - frame.pts * audio_stream.time_base
|
||||||
|
to_skip = max(0, int(offset_seconds * audio_stream.sample_rate))
|
||||||
|
if to_skip < frame.samples:
|
||||||
|
has_first_audio_frame = True
|
||||||
|
audio_frames.append(frame.to_ndarray()[..., to_skip:])
|
||||||
|
else:
|
||||||
|
audio_frames.append(frame.to_ndarray())
|
||||||
|
|
||||||
|
images = torch.stack(frames) if len(frames) > 0 else torch.zeros(0, 0, 0, 3)
|
||||||
|
if alphas is not None:
|
||||||
|
alphas = torch.stack(alphas) if len(alphas) > 0 else torch.zeros(0, 0, 0, 1)
|
||||||
|
|
||||||
# Get frame rate
|
# Get frame rate
|
||||||
frame_rate = Fraction(video_stream.average_rate) if video_stream.average_rate else Fraction(1)
|
frame_rate = Fraction(video_stream.average_rate) if video_stream.average_rate else Fraction(1)
|
||||||
|
|
||||||
# Get audio if available
|
if len(audio_frames) > 0:
|
||||||
audio = None
|
audio_data = np.concatenate(audio_frames, axis=1) # shape: (channels, total_samples)
|
||||||
container.seek(start_pts, stream=video_stream)
|
if self.__duration:
|
||||||
# Use last stream for consistency
|
audio_data = audio_data[..., :int(self.__duration * audio_stream.sample_rate)]
|
||||||
if len(container.streams.audio):
|
|
||||||
audio_stream = container.streams.audio[-1]
|
|
||||||
audio_frames = []
|
|
||||||
resample = av.audio.resampler.AudioResampler(format='fltp').resample
|
|
||||||
frames = itertools.chain.from_iterable(
|
|
||||||
map(resample, container.decode(audio_stream))
|
|
||||||
)
|
|
||||||
|
|
||||||
has_first_frame = False
|
audio_tensor = torch.from_numpy(audio_data).unsqueeze(0) # shape: (1, channels, total_samples)
|
||||||
for frame in frames:
|
audio = AudioInput({
|
||||||
offset_seconds = start_time - frame.pts * audio_stream.time_base
|
"waveform": audio_tensor,
|
||||||
to_skip = max(0, int(offset_seconds * audio_stream.sample_rate))
|
"sample_rate": int(audio_stream.sample_rate) if audio_stream.sample_rate else 1,
|
||||||
if to_skip < frame.samples:
|
})
|
||||||
has_first_frame = True
|
|
||||||
break
|
|
||||||
if has_first_frame:
|
|
||||||
audio_frames.append(frame.to_ndarray()[..., to_skip:])
|
|
||||||
|
|
||||||
for frame in frames:
|
|
||||||
if self.__duration and frame.time > start_time + self.__duration:
|
|
||||||
break
|
|
||||||
audio_frames.append(frame.to_ndarray()) # shape: (channels, samples)
|
|
||||||
if len(audio_frames) > 0:
|
|
||||||
audio_data = np.concatenate(audio_frames, axis=1) # shape: (channels, total_samples)
|
|
||||||
if self.__duration:
|
|
||||||
audio_data = audio_data[..., :int(self.__duration * audio_stream.sample_rate)]
|
|
||||||
|
|
||||||
audio_tensor = torch.from_numpy(audio_data).unsqueeze(0) # shape: (1, channels, total_samples)
|
|
||||||
audio = AudioInput({
|
|
||||||
"waveform": audio_tensor,
|
|
||||||
"sample_rate": int(audio_stream.sample_rate) if audio_stream.sample_rate else 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
metadata = container.metadata
|
metadata = container.metadata
|
||||||
return VideoComponents(images=images, audio=audio, frame_rate=frame_rate, metadata=metadata)
|
return VideoComponents(images=images, alpha=alphas, audio=audio, frame_rate=frame_rate, metadata=metadata)
|
||||||
|
|
||||||
def get_components(self) -> VideoComponents:
|
def get_components(self) -> VideoComponents:
|
||||||
if isinstance(self.__file, io.BytesIO):
|
if isinstance(self.__file, io.BytesIO):
|
||||||
|
|||||||
@ -3,7 +3,7 @@ from dataclasses import dataclass
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from fractions import Fraction
|
from fractions import Fraction
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from .._input import ImageInput, AudioInput
|
from .._input import ImageInput, AudioInput, MaskInput
|
||||||
|
|
||||||
class VideoCodec(str, Enum):
|
class VideoCodec(str, Enum):
|
||||||
AUTO = "auto"
|
AUTO = "auto"
|
||||||
@ -48,5 +48,4 @@ class VideoComponents:
|
|||||||
frame_rate: Fraction
|
frame_rate: Fraction
|
||||||
audio: Optional[AudioInput] = None
|
audio: Optional[AudioInput] = None
|
||||||
metadata: Optional[dict] = None
|
metadata: Optional[dict] = None
|
||||||
|
alpha: Optional[MaskInput] = None
|
||||||
|
|
||||||
|
|||||||
@ -118,7 +118,7 @@ class Wan27ReferenceVideoInputField(BaseModel):
|
|||||||
class Wan27ReferenceVideoParametersField(BaseModel):
|
class Wan27ReferenceVideoParametersField(BaseModel):
|
||||||
resolution: str = Field(...)
|
resolution: str = Field(...)
|
||||||
ratio: str | None = Field(None)
|
ratio: str | None = Field(None)
|
||||||
duration: int = Field(5, ge=2, le=10)
|
duration: int = Field(5, ge=2, le=15)
|
||||||
watermark: bool = Field(False)
|
watermark: bool = Field(False)
|
||||||
seed: int = Field(..., ge=0, le=2147483647)
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
|
||||||
@ -157,7 +157,7 @@ class Wan27VideoEditInputField(BaseModel):
|
|||||||
class Wan27VideoEditParametersField(BaseModel):
|
class Wan27VideoEditParametersField(BaseModel):
|
||||||
resolution: str = Field(...)
|
resolution: str = Field(...)
|
||||||
ratio: str | None = Field(None)
|
ratio: str | None = Field(None)
|
||||||
duration: int = Field(0)
|
duration: int | None = Field(0)
|
||||||
audio_setting: str = Field("auto")
|
audio_setting: str = Field("auto")
|
||||||
watermark: bool = Field(False)
|
watermark: bool = Field(False)
|
||||||
seed: int = Field(..., ge=0, le=2147483647)
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
|||||||
@ -1646,6 +1646,557 @@ class Wan2ReferenceVideoApi(IO.ComfyNode):
|
|||||||
return IO.NodeOutput(await download_url_to_video_output(response.output.video_url))
|
return IO.NodeOutput(await download_url_to_video_output(response.output.video_url))
|
||||||
|
|
||||||
|
|
||||||
|
class HappyHorseTextToVideoApi(IO.ComfyNode):
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return IO.Schema(
|
||||||
|
node_id="HappyHorseTextToVideoApi",
|
||||||
|
display_name="HappyHorse Text to Video",
|
||||||
|
category="api node/video/Wan",
|
||||||
|
description="Generates a video based on a text prompt using the HappyHorse model.",
|
||||||
|
inputs=[
|
||||||
|
IO.DynamicCombo.Input(
|
||||||
|
"model",
|
||||||
|
options=[
|
||||||
|
IO.DynamicCombo.Option(
|
||||||
|
"happyhorse-1.0-t2v",
|
||||||
|
[
|
||||||
|
IO.String.Input(
|
||||||
|
"prompt",
|
||||||
|
multiline=True,
|
||||||
|
default="",
|
||||||
|
tooltip="Prompt describing the elements and visual features. "
|
||||||
|
"Supports English and Chinese.",
|
||||||
|
),
|
||||||
|
IO.Combo.Input(
|
||||||
|
"resolution",
|
||||||
|
options=["720P", "1080P"],
|
||||||
|
),
|
||||||
|
IO.Combo.Input(
|
||||||
|
"ratio",
|
||||||
|
options=["16:9", "9:16", "1:1", "4:3", "3:4"],
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"duration",
|
||||||
|
default=5,
|
||||||
|
min=3,
|
||||||
|
max=15,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.number,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"seed",
|
||||||
|
default=0,
|
||||||
|
min=0,
|
||||||
|
max=2147483647,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.number,
|
||||||
|
control_after_generate=True,
|
||||||
|
tooltip="Seed to use for generation.",
|
||||||
|
),
|
||||||
|
IO.Boolean.Input(
|
||||||
|
"watermark",
|
||||||
|
default=False,
|
||||||
|
tooltip="Whether to add an AI-generated watermark to the result.",
|
||||||
|
advanced=True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[
|
||||||
|
IO.Video.Output(),
|
||||||
|
],
|
||||||
|
hidden=[
|
||||||
|
IO.Hidden.auth_token_comfy_org,
|
||||||
|
IO.Hidden.api_key_comfy_org,
|
||||||
|
IO.Hidden.unique_id,
|
||||||
|
],
|
||||||
|
is_api_node=True,
|
||||||
|
price_badge=IO.PriceBadge(
|
||||||
|
depends_on=IO.PriceBadgeDepends(widgets=["model", "model.resolution", "model.duration"]),
|
||||||
|
expr="""
|
||||||
|
(
|
||||||
|
$res := $lookup(widgets, "model.resolution");
|
||||||
|
$dur := $lookup(widgets, "model.duration");
|
||||||
|
$ppsTable := { "720p": 0.14, "1080p": 0.24 };
|
||||||
|
$pps := $lookup($ppsTable, $res);
|
||||||
|
{ "type": "usd", "usd": $pps * $dur }
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def execute(
|
||||||
|
cls,
|
||||||
|
model: dict,
|
||||||
|
seed: int,
|
||||||
|
watermark: bool,
|
||||||
|
):
|
||||||
|
validate_string(model["prompt"], strip_whitespace=False, min_length=1)
|
||||||
|
initial_response = await sync_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(
|
||||||
|
path="/proxy/wan/api/v1/services/aigc/video-generation/video-synthesis",
|
||||||
|
method="POST",
|
||||||
|
),
|
||||||
|
response_model=TaskCreationResponse,
|
||||||
|
data=Wan27Text2VideoTaskCreationRequest(
|
||||||
|
model=model["model"],
|
||||||
|
input=Text2VideoInputField(
|
||||||
|
prompt=model["prompt"],
|
||||||
|
negative_prompt=None,
|
||||||
|
),
|
||||||
|
parameters=Wan27Text2VideoParametersField(
|
||||||
|
resolution=model["resolution"],
|
||||||
|
ratio=model["ratio"],
|
||||||
|
duration=model["duration"],
|
||||||
|
seed=seed,
|
||||||
|
watermark=watermark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if not initial_response.output:
|
||||||
|
raise Exception(f"An unknown error occurred: {initial_response.code} - {initial_response.message}")
|
||||||
|
response = await poll_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(path=f"/proxy/wan/api/v1/tasks/{initial_response.output.task_id}"),
|
||||||
|
response_model=VideoTaskStatusResponse,
|
||||||
|
status_extractor=lambda x: x.output.task_status,
|
||||||
|
poll_interval=7,
|
||||||
|
)
|
||||||
|
return IO.NodeOutput(await download_url_to_video_output(response.output.video_url))
|
||||||
|
|
||||||
|
|
||||||
|
class HappyHorseImageToVideoApi(IO.ComfyNode):
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return IO.Schema(
|
||||||
|
node_id="HappyHorseImageToVideoApi",
|
||||||
|
display_name="HappyHorse Image to Video",
|
||||||
|
category="api node/video/Wan",
|
||||||
|
description="Generate a video from a first-frame image using the HappyHorse model.",
|
||||||
|
inputs=[
|
||||||
|
IO.DynamicCombo.Input(
|
||||||
|
"model",
|
||||||
|
options=[
|
||||||
|
IO.DynamicCombo.Option(
|
||||||
|
"happyhorse-1.0-i2v",
|
||||||
|
[
|
||||||
|
IO.String.Input(
|
||||||
|
"prompt",
|
||||||
|
multiline=True,
|
||||||
|
default="",
|
||||||
|
tooltip="Prompt describing the elements and visual features. "
|
||||||
|
"Supports English and Chinese.",
|
||||||
|
),
|
||||||
|
IO.Combo.Input(
|
||||||
|
"resolution",
|
||||||
|
options=["720P", "1080P"],
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"duration",
|
||||||
|
default=5,
|
||||||
|
min=3,
|
||||||
|
max=15,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.number,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
IO.Image.Input(
|
||||||
|
"first_frame",
|
||||||
|
tooltip="First frame image. The output aspect ratio is derived from this image.",
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"seed",
|
||||||
|
default=0,
|
||||||
|
min=0,
|
||||||
|
max=2147483647,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.number,
|
||||||
|
control_after_generate=True,
|
||||||
|
tooltip="Seed to use for generation.",
|
||||||
|
),
|
||||||
|
IO.Boolean.Input(
|
||||||
|
"watermark",
|
||||||
|
default=False,
|
||||||
|
tooltip="Whether to add an AI-generated watermark to the result.",
|
||||||
|
advanced=True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[
|
||||||
|
IO.Video.Output(),
|
||||||
|
],
|
||||||
|
hidden=[
|
||||||
|
IO.Hidden.auth_token_comfy_org,
|
||||||
|
IO.Hidden.api_key_comfy_org,
|
||||||
|
IO.Hidden.unique_id,
|
||||||
|
],
|
||||||
|
is_api_node=True,
|
||||||
|
price_badge=IO.PriceBadge(
|
||||||
|
depends_on=IO.PriceBadgeDepends(widgets=["model", "model.resolution", "model.duration"]),
|
||||||
|
expr="""
|
||||||
|
(
|
||||||
|
$res := $lookup(widgets, "model.resolution");
|
||||||
|
$dur := $lookup(widgets, "model.duration");
|
||||||
|
$ppsTable := { "720p": 0.14, "1080p": 0.24 };
|
||||||
|
$pps := $lookup($ppsTable, $res);
|
||||||
|
{ "type": "usd", "usd": $pps * $dur }
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def execute(
|
||||||
|
cls,
|
||||||
|
model: dict,
|
||||||
|
first_frame: Input.Image,
|
||||||
|
seed: int,
|
||||||
|
watermark: bool,
|
||||||
|
):
|
||||||
|
media = [
|
||||||
|
Wan27MediaItem(
|
||||||
|
type="first_frame",
|
||||||
|
url=await upload_image_to_comfyapi(cls, image=first_frame),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
initial_response = await sync_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(
|
||||||
|
path="/proxy/wan/api/v1/services/aigc/video-generation/video-synthesis",
|
||||||
|
method="POST",
|
||||||
|
),
|
||||||
|
response_model=TaskCreationResponse,
|
||||||
|
data=Wan27ImageToVideoTaskCreationRequest(
|
||||||
|
model=model["model"],
|
||||||
|
input=Wan27ImageToVideoInputField(
|
||||||
|
prompt=model["prompt"] or None,
|
||||||
|
negative_prompt=None,
|
||||||
|
media=media,
|
||||||
|
),
|
||||||
|
parameters=Wan27ImageToVideoParametersField(
|
||||||
|
resolution=model["resolution"],
|
||||||
|
duration=model["duration"],
|
||||||
|
seed=seed,
|
||||||
|
watermark=watermark,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if not initial_response.output:
|
||||||
|
raise Exception(f"An unknown error occurred: {initial_response.code} - {initial_response.message}")
|
||||||
|
response = await poll_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(path=f"/proxy/wan/api/v1/tasks/{initial_response.output.task_id}"),
|
||||||
|
response_model=VideoTaskStatusResponse,
|
||||||
|
status_extractor=lambda x: x.output.task_status,
|
||||||
|
poll_interval=7,
|
||||||
|
)
|
||||||
|
return IO.NodeOutput(await download_url_to_video_output(response.output.video_url))
|
||||||
|
|
||||||
|
|
||||||
|
class HappyHorseVideoEditApi(IO.ComfyNode):
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return IO.Schema(
|
||||||
|
node_id="HappyHorseVideoEditApi",
|
||||||
|
display_name="HappyHorse Video Edit",
|
||||||
|
category="api node/video/Wan",
|
||||||
|
description="Edit a video using text instructions or reference images with the HappyHorse model. "
|
||||||
|
"Output duration is 3-15s and matches the input video; inputs longer than 15s are truncated.",
|
||||||
|
inputs=[
|
||||||
|
IO.DynamicCombo.Input(
|
||||||
|
"model",
|
||||||
|
options=[
|
||||||
|
IO.DynamicCombo.Option(
|
||||||
|
"happyhorse-1.0-video-edit",
|
||||||
|
[
|
||||||
|
IO.String.Input(
|
||||||
|
"prompt",
|
||||||
|
multiline=True,
|
||||||
|
default="",
|
||||||
|
tooltip="Editing instructions or style transfer requirements.",
|
||||||
|
),
|
||||||
|
IO.Combo.Input(
|
||||||
|
"resolution",
|
||||||
|
options=["720P", "1080P"],
|
||||||
|
),
|
||||||
|
IO.Combo.Input(
|
||||||
|
"ratio",
|
||||||
|
options=["16:9", "9:16", "1:1", "4:3", "3:4"],
|
||||||
|
tooltip="Aspect ratio. If not changed, approximates the input video ratio.",
|
||||||
|
),
|
||||||
|
IO.Autogrow.Input(
|
||||||
|
"reference_images",
|
||||||
|
template=IO.Autogrow.TemplateNames(
|
||||||
|
IO.Image.Input("reference_image"),
|
||||||
|
names=[
|
||||||
|
"image1",
|
||||||
|
"image2",
|
||||||
|
"image3",
|
||||||
|
"image4",
|
||||||
|
"image5",
|
||||||
|
],
|
||||||
|
min=0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
IO.Video.Input(
|
||||||
|
"video",
|
||||||
|
tooltip="The video to edit.",
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"seed",
|
||||||
|
default=0,
|
||||||
|
min=0,
|
||||||
|
max=2147483647,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.number,
|
||||||
|
control_after_generate=True,
|
||||||
|
tooltip="Seed to use for generation.",
|
||||||
|
),
|
||||||
|
IO.Boolean.Input(
|
||||||
|
"watermark",
|
||||||
|
default=False,
|
||||||
|
tooltip="Whether to add an AI-generated watermark to the result.",
|
||||||
|
advanced=True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[
|
||||||
|
IO.Video.Output(),
|
||||||
|
],
|
||||||
|
hidden=[
|
||||||
|
IO.Hidden.auth_token_comfy_org,
|
||||||
|
IO.Hidden.api_key_comfy_org,
|
||||||
|
IO.Hidden.unique_id,
|
||||||
|
],
|
||||||
|
is_api_node=True,
|
||||||
|
price_badge=IO.PriceBadge(
|
||||||
|
depends_on=IO.PriceBadgeDepends(widgets=["model", "model.resolution"]),
|
||||||
|
expr="""
|
||||||
|
(
|
||||||
|
$res := $lookup(widgets, "model.resolution");
|
||||||
|
$ppsTable := { "720p": 0.14, "1080p": 0.24 };
|
||||||
|
$pps := $lookup($ppsTable, $res);
|
||||||
|
{ "type": "usd", "usd": $pps, "format": { "suffix": "/second" } }
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def execute(
|
||||||
|
cls,
|
||||||
|
model: dict,
|
||||||
|
video: Input.Video,
|
||||||
|
seed: int,
|
||||||
|
watermark: bool,
|
||||||
|
):
|
||||||
|
validate_string(model["prompt"], strip_whitespace=False, min_length=1)
|
||||||
|
validate_video_duration(video, min_duration=3, max_duration=60)
|
||||||
|
media = [Wan27MediaItem(type="video", url=await upload_video_to_comfyapi(cls, video))]
|
||||||
|
reference_images = model.get("reference_images", {})
|
||||||
|
for key in reference_images:
|
||||||
|
media.append(
|
||||||
|
Wan27MediaItem(
|
||||||
|
type="reference_image", url=await upload_image_to_comfyapi(cls, image=reference_images[key])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
initial_response = await sync_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(
|
||||||
|
path="/proxy/wan/api/v1/services/aigc/video-generation/video-synthesis",
|
||||||
|
method="POST",
|
||||||
|
),
|
||||||
|
response_model=TaskCreationResponse,
|
||||||
|
data=Wan27VideoEditTaskCreationRequest(
|
||||||
|
model=model["model"],
|
||||||
|
input=Wan27VideoEditInputField(prompt=model["prompt"], media=media),
|
||||||
|
parameters=Wan27VideoEditParametersField(
|
||||||
|
resolution=model["resolution"],
|
||||||
|
ratio=model["ratio"],
|
||||||
|
duration=None,
|
||||||
|
watermark=watermark,
|
||||||
|
seed=seed,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if not initial_response.output:
|
||||||
|
raise Exception(f"An unknown error occurred: {initial_response.code} - {initial_response.message}")
|
||||||
|
response = await poll_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(path=f"/proxy/wan/api/v1/tasks/{initial_response.output.task_id}"),
|
||||||
|
response_model=VideoTaskStatusResponse,
|
||||||
|
status_extractor=lambda x: x.output.task_status,
|
||||||
|
poll_interval=7,
|
||||||
|
)
|
||||||
|
return IO.NodeOutput(await download_url_to_video_output(response.output.video_url))
|
||||||
|
|
||||||
|
|
||||||
|
class HappyHorseReferenceVideoApi(IO.ComfyNode):
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return IO.Schema(
|
||||||
|
node_id="HappyHorseReferenceVideoApi",
|
||||||
|
display_name="HappyHorse Reference to Video",
|
||||||
|
category="api node/video/Wan",
|
||||||
|
description="Generate a video featuring a person or object from reference materials with the HappyHorse "
|
||||||
|
"model. Supports single-character performances and multi-character interactions.",
|
||||||
|
inputs=[
|
||||||
|
IO.DynamicCombo.Input(
|
||||||
|
"model",
|
||||||
|
options=[
|
||||||
|
IO.DynamicCombo.Option(
|
||||||
|
"happyhorse-1.0-r2v",
|
||||||
|
[
|
||||||
|
IO.String.Input(
|
||||||
|
"prompt",
|
||||||
|
multiline=True,
|
||||||
|
default="",
|
||||||
|
tooltip="Prompt describing the video. Use identifiers such as 'character1' and "
|
||||||
|
"'character2' to refer to the reference characters.",
|
||||||
|
),
|
||||||
|
IO.Combo.Input(
|
||||||
|
"resolution",
|
||||||
|
options=["720P", "1080P"],
|
||||||
|
),
|
||||||
|
IO.Combo.Input(
|
||||||
|
"ratio",
|
||||||
|
options=["16:9", "9:16", "1:1", "4:3", "3:4"],
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"duration",
|
||||||
|
default=5,
|
||||||
|
min=3,
|
||||||
|
max=15,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.number,
|
||||||
|
),
|
||||||
|
IO.Autogrow.Input(
|
||||||
|
"reference_images",
|
||||||
|
template=IO.Autogrow.TemplateNames(
|
||||||
|
IO.Image.Input("reference_image"),
|
||||||
|
names=[
|
||||||
|
"image1",
|
||||||
|
"image2",
|
||||||
|
"image3",
|
||||||
|
"image4",
|
||||||
|
"image5",
|
||||||
|
"image6",
|
||||||
|
"image7",
|
||||||
|
"image8",
|
||||||
|
"image9",
|
||||||
|
],
|
||||||
|
min=1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
IO.Int.Input(
|
||||||
|
"seed",
|
||||||
|
default=0,
|
||||||
|
min=0,
|
||||||
|
max=2147483647,
|
||||||
|
step=1,
|
||||||
|
display_mode=IO.NumberDisplay.number,
|
||||||
|
control_after_generate=True,
|
||||||
|
tooltip="Seed to use for generation.",
|
||||||
|
),
|
||||||
|
IO.Boolean.Input(
|
||||||
|
"watermark",
|
||||||
|
default=False,
|
||||||
|
tooltip="Whether to add an AI-generated watermark to the result.",
|
||||||
|
advanced=True,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
outputs=[
|
||||||
|
IO.Video.Output(),
|
||||||
|
],
|
||||||
|
hidden=[
|
||||||
|
IO.Hidden.auth_token_comfy_org,
|
||||||
|
IO.Hidden.api_key_comfy_org,
|
||||||
|
IO.Hidden.unique_id,
|
||||||
|
],
|
||||||
|
is_api_node=True,
|
||||||
|
price_badge=IO.PriceBadge(
|
||||||
|
depends_on=IO.PriceBadgeDepends(widgets=["model", "model.resolution", "model.duration"]),
|
||||||
|
expr="""
|
||||||
|
(
|
||||||
|
$res := $lookup(widgets, "model.resolution");
|
||||||
|
$dur := $lookup(widgets, "model.duration");
|
||||||
|
$ppsTable := { "720p": 0.14, "1080p": 0.24 };
|
||||||
|
$pps := $lookup($ppsTable, $res);
|
||||||
|
{ "type": "usd", "usd": $pps * $dur }
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
async def execute(
|
||||||
|
cls,
|
||||||
|
model: dict,
|
||||||
|
seed: int,
|
||||||
|
watermark: bool,
|
||||||
|
):
|
||||||
|
validate_string(model["prompt"], strip_whitespace=False, min_length=1)
|
||||||
|
media = []
|
||||||
|
reference_images = model.get("reference_images", {})
|
||||||
|
for key in reference_images:
|
||||||
|
media.append(
|
||||||
|
Wan27MediaItem(
|
||||||
|
type="reference_image",
|
||||||
|
url=await upload_image_to_comfyapi(cls, image=reference_images[key]),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if not media:
|
||||||
|
raise ValueError("At least one reference reference image must be provided.")
|
||||||
|
|
||||||
|
initial_response = await sync_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(
|
||||||
|
path="/proxy/wan/api/v1/services/aigc/video-generation/video-synthesis",
|
||||||
|
method="POST",
|
||||||
|
),
|
||||||
|
response_model=TaskCreationResponse,
|
||||||
|
data=Wan27ReferenceVideoTaskCreationRequest(
|
||||||
|
model=model["model"],
|
||||||
|
input=Wan27ReferenceVideoInputField(
|
||||||
|
prompt=model["prompt"],
|
||||||
|
negative_prompt=None,
|
||||||
|
media=media,
|
||||||
|
),
|
||||||
|
parameters=Wan27ReferenceVideoParametersField(
|
||||||
|
resolution=model["resolution"],
|
||||||
|
ratio=model["ratio"],
|
||||||
|
duration=model["duration"],
|
||||||
|
watermark=watermark,
|
||||||
|
seed=seed,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if not initial_response.output:
|
||||||
|
raise Exception(f"An unknown error occurred: {initial_response.code} - {initial_response.message}")
|
||||||
|
response = await poll_op(
|
||||||
|
cls,
|
||||||
|
ApiEndpoint(path=f"/proxy/wan/api/v1/tasks/{initial_response.output.task_id}"),
|
||||||
|
response_model=VideoTaskStatusResponse,
|
||||||
|
status_extractor=lambda x: x.output.task_status,
|
||||||
|
poll_interval=7,
|
||||||
|
)
|
||||||
|
return IO.NodeOutput(await download_url_to_video_output(response.output.video_url))
|
||||||
|
|
||||||
|
|
||||||
class WanApiExtension(ComfyExtension):
|
class WanApiExtension(ComfyExtension):
|
||||||
@override
|
@override
|
||||||
async def get_node_list(self) -> list[type[IO.ComfyNode]]:
|
async def get_node_list(self) -> list[type[IO.ComfyNode]]:
|
||||||
@ -1660,6 +2211,10 @@ class WanApiExtension(ComfyExtension):
|
|||||||
Wan2VideoContinuationApi,
|
Wan2VideoContinuationApi,
|
||||||
Wan2VideoEditApi,
|
Wan2VideoEditApi,
|
||||||
Wan2ReferenceVideoApi,
|
Wan2ReferenceVideoApi,
|
||||||
|
HappyHorseTextToVideoApi,
|
||||||
|
HappyHorseImageToVideoApi,
|
||||||
|
HappyHorseVideoEditApi,
|
||||||
|
HappyHorseReferenceVideoApi,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -637,7 +637,7 @@ class SaveGLB(IO.ComfyNode):
|
|||||||
],
|
],
|
||||||
tooltip="Mesh or 3D file to save",
|
tooltip="Mesh or 3D file to save",
|
||||||
),
|
),
|
||||||
IO.String.Input("filename_prefix", default="mesh/ComfyUI"),
|
IO.String.Input("filename_prefix", default="3d/ComfyUI"),
|
||||||
],
|
],
|
||||||
hidden=[IO.Hidden.prompt, IO.Hidden.extra_pnginfo]
|
hidden=[IO.Hidden.prompt, IO.Hidden.extra_pnginfo]
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import numpy as np
|
|||||||
import scipy.ndimage
|
import scipy.ndimage
|
||||||
import torch
|
import torch
|
||||||
import comfy.utils
|
import comfy.utils
|
||||||
|
import comfy.model_management
|
||||||
import node_helpers
|
import node_helpers
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
from comfy_api.latest import ComfyExtension, IO, UI
|
from comfy_api.latest import ComfyExtension, IO, UI
|
||||||
@ -188,7 +189,7 @@ class SolidMask(IO.ComfyNode):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def execute(cls, value, width, height) -> IO.NodeOutput:
|
def execute(cls, value, width, height) -> IO.NodeOutput:
|
||||||
out = torch.full((1, height, width), value, dtype=torch.float32, device="cpu")
|
out = torch.full((1, height, width), value, dtype=torch.float32, device=comfy.model_management.intermediate_device())
|
||||||
return IO.NodeOutput(out)
|
return IO.NodeOutput(out)
|
||||||
|
|
||||||
solid = execute # TODO: remove
|
solid = execute # TODO: remove
|
||||||
@ -262,6 +263,7 @@ class MaskComposite(IO.ComfyNode):
|
|||||||
def execute(cls, destination, source, x, y, operation) -> IO.NodeOutput:
|
def execute(cls, destination, source, x, y, operation) -> IO.NodeOutput:
|
||||||
output = destination.reshape((-1, destination.shape[-2], destination.shape[-1])).clone()
|
output = destination.reshape((-1, destination.shape[-2], destination.shape[-1])).clone()
|
||||||
source = source.reshape((-1, source.shape[-2], source.shape[-1]))
|
source = source.reshape((-1, source.shape[-2], source.shape[-1]))
|
||||||
|
source = source.to(output.device)
|
||||||
|
|
||||||
left, top = (x, y,)
|
left, top = (x, y,)
|
||||||
right, bottom = (min(left + source.shape[-1], destination.shape[-1]), min(top + source.shape[-2], destination.shape[-2]))
|
right, bottom = (min(left + source.shape[-1], destination.shape[-1]), min(top + source.shape[-2], destination.shape[-2]))
|
||||||
|
|||||||
@ -54,7 +54,7 @@ class EmptySD3LatentImage(io.ComfyNode):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def execute(cls, width, height, batch_size=1) -> io.NodeOutput:
|
def execute(cls, width, height, batch_size=1) -> io.NodeOutput:
|
||||||
latent = torch.zeros([batch_size, 16, height // 8, width // 8], device=comfy.model_management.intermediate_device())
|
latent = torch.zeros([batch_size, 16, height // 8, width // 8], device=comfy.model_management.intermediate_device(), dtype=comfy.model_management.intermediate_dtype())
|
||||||
return io.NodeOutput({"samples": latent, "downscale_ratio_spacial": 8})
|
return io.NodeOutput({"samples": latent, "downscale_ratio_spacial": 8})
|
||||||
|
|
||||||
generate = execute # TODO: remove
|
generate = execute # TODO: remove
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
# This file is automatically generated by the build process when version is
|
# This file is automatically generated by the build process when version is
|
||||||
# updated in pyproject.toml.
|
# updated in pyproject.toml.
|
||||||
__version__ = "0.19.3"
|
__version__ = "0.20.1"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "ComfyUI"
|
name = "ComfyUI"
|
||||||
version = "0.19.3"
|
version = "0.20.1"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
license = { file = "LICENSE" }
|
license = { file = "LICENSE" }
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
comfyui-frontend-package==1.42.15
|
comfyui-frontend-package==1.42.15
|
||||||
comfyui-workflow-templates==0.9.62
|
comfyui-workflow-templates==0.9.63
|
||||||
comfyui-embedded-docs==0.4.4
|
comfyui-embedded-docs==0.4.4
|
||||||
torch
|
torch
|
||||||
torchsde
|
torchsde
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user