Skip to content

Commit 6c14f3a

Browse files
authored
use new API client in Luma and Minimax nodes (#10528)
1 parent e525673 commit 6c14f3a

File tree

7 files changed

+286
-519
lines changed

7 files changed

+286
-519
lines changed

comfy_api_nodes/apinode_utils.py

Lines changed: 0 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,6 @@
33
import mimetypes
44
from typing import Optional, Union
55
from comfy.utils import common_upscale
6-
from comfy_api_nodes.apis.client import (
7-
ApiClient,
8-
ApiEndpoint,
9-
HttpMethod,
10-
SynchronousOperation,
11-
UploadRequest,
12-
UploadResponse,
13-
)
146
from server import PromptServer
157
from comfy.cli_args import args
168

@@ -19,7 +11,6 @@
1911
import torch
2012
import math
2113
import base64
22-
from .util import tensor_to_bytesio, bytesio_to_image_tensor
2314
from io import BytesIO
2415

2516

@@ -148,11 +139,6 @@ async def download_url_to_bytesio(
148139
return BytesIO(await resp.read())
149140

150141

151-
def process_image_response(response_content: bytes | str) -> torch.Tensor:
152-
"""Uses content from a Response object and converts it to a torch.Tensor"""
153-
return bytesio_to_image_tensor(BytesIO(response_content))
154-
155-
156142
def text_filepath_to_base64_string(filepath: str) -> str:
157143
"""Converts a text file to a base64 string."""
158144
with open(filepath, "rb") as f:
@@ -169,73 +155,6 @@ def text_filepath_to_data_uri(filepath: str) -> str:
169155
return f"data:{mime_type};base64,{base64_string}"
170156

171157

172-
async def upload_file_to_comfyapi(
173-
file_bytes_io: BytesIO,
174-
filename: str,
175-
upload_mime_type: Optional[str],
176-
auth_kwargs: Optional[dict[str, str]] = None,
177-
) -> str:
178-
"""
179-
Uploads a single file to ComfyUI API and returns its download URL.
180-
181-
Args:
182-
file_bytes_io: BytesIO object containing the file data.
183-
filename: The filename of the file.
184-
upload_mime_type: MIME type of the file.
185-
auth_kwargs: Optional authentication token(s).
186-
187-
Returns:
188-
The download URL for the uploaded file.
189-
"""
190-
if upload_mime_type is None:
191-
request_object = UploadRequest(file_name=filename)
192-
else:
193-
request_object = UploadRequest(file_name=filename, content_type=upload_mime_type)
194-
operation = SynchronousOperation(
195-
endpoint=ApiEndpoint(
196-
path="/customers/storage",
197-
method=HttpMethod.POST,
198-
request_model=UploadRequest,
199-
response_model=UploadResponse,
200-
),
201-
request=request_object,
202-
auth_kwargs=auth_kwargs,
203-
)
204-
205-
response: UploadResponse = await operation.execute()
206-
await ApiClient.upload_file(response.upload_url, file_bytes_io, content_type=upload_mime_type)
207-
return response.download_url
208-
209-
210-
async def upload_images_to_comfyapi(
211-
image: torch.Tensor,
212-
max_images=8,
213-
auth_kwargs: Optional[dict[str, str]] = None,
214-
mime_type: Optional[str] = None,
215-
) -> list[str]:
216-
"""
217-
Uploads images to ComfyUI API and returns download URLs.
218-
To upload multiple images, stack them in the batch dimension first.
219-
220-
Args:
221-
image: Input torch.Tensor image.
222-
max_images: Maximum number of images to upload.
223-
auth_kwargs: Optional authentication token(s).
224-
mime_type: Optional MIME type for the image.
225-
"""
226-
# if batch, try to upload each file if max_images is greater than 0
227-
download_urls: list[str] = []
228-
is_batch = len(image.shape) > 3
229-
batch_len = image.shape[0] if is_batch else 1
230-
231-
for idx in range(min(batch_len, max_images)):
232-
tensor = image[idx] if is_batch else image
233-
img_io = tensor_to_bytesio(tensor, mime_type=mime_type)
234-
url = await upload_file_to_comfyapi(img_io, img_io.name, mime_type, auth_kwargs)
235-
download_urls.append(url)
236-
return download_urls
237-
238-
239158
def resize_mask_to_image(
240159
mask: torch.Tensor,
241160
image: torch.Tensor,
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
from enum import Enum
2+
from typing import Optional
3+
4+
from pydantic import BaseModel, Field
5+
6+
7+
class MinimaxBaseResponse(BaseModel):
8+
status_code: int = Field(
9+
...,
10+
description='Status code. 0 indicates success, other values indicate errors.',
11+
)
12+
status_msg: str = Field(
13+
..., description='Specific error details or success message.'
14+
)
15+
16+
17+
class File(BaseModel):
18+
bytes: Optional[int] = Field(None, description='File size in bytes')
19+
created_at: Optional[int] = Field(
20+
None, description='Unix timestamp when the file was created, in seconds'
21+
)
22+
download_url: Optional[str] = Field(
23+
None, description='The URL to download the video'
24+
)
25+
backup_download_url: Optional[str] = Field(
26+
None, description='The backup URL to download the video'
27+
)
28+
29+
file_id: Optional[int] = Field(None, description='Unique identifier for the file')
30+
filename: Optional[str] = Field(None, description='The name of the file')
31+
purpose: Optional[str] = Field(None, description='The purpose of using the file')
32+
33+
34+
class MinimaxFileRetrieveResponse(BaseModel):
35+
base_resp: MinimaxBaseResponse
36+
file: File
37+
38+
39+
class MiniMaxModel(str, Enum):
40+
T2V_01_Director = 'T2V-01-Director'
41+
I2V_01_Director = 'I2V-01-Director'
42+
S2V_01 = 'S2V-01'
43+
I2V_01 = 'I2V-01'
44+
I2V_01_live = 'I2V-01-live'
45+
T2V_01 = 'T2V-01'
46+
Hailuo_02 = 'MiniMax-Hailuo-02'
47+
48+
49+
class Status6(str, Enum):
50+
Queueing = 'Queueing'
51+
Preparing = 'Preparing'
52+
Processing = 'Processing'
53+
Success = 'Success'
54+
Fail = 'Fail'
55+
56+
57+
class MinimaxTaskResultResponse(BaseModel):
58+
base_resp: MinimaxBaseResponse
59+
file_id: Optional[str] = Field(
60+
None,
61+
description='After the task status changes to Success, this field returns the file ID corresponding to the generated video.',
62+
)
63+
status: Status6 = Field(
64+
...,
65+
description="Task status: 'Queueing' (in queue), 'Preparing' (task is preparing), 'Processing' (generating), 'Success' (task completed successfully), or 'Fail' (task failed).",
66+
)
67+
task_id: str = Field(..., description='The task ID being queried.')
68+
69+
70+
class SubjectReferenceItem(BaseModel):
71+
image: Optional[str] = Field(
72+
None, description='URL or base64 encoding of the subject reference image.'
73+
)
74+
mask: Optional[str] = Field(
75+
None,
76+
description='URL or base64 encoding of the mask for the subject reference image.',
77+
)
78+
79+
80+
class MinimaxVideoGenerationRequest(BaseModel):
81+
callback_url: Optional[str] = Field(
82+
None,
83+
description='Optional. URL to receive real-time status updates about the video generation task.',
84+
)
85+
first_frame_image: Optional[str] = Field(
86+
None,
87+
description='URL or base64 encoding of the first frame image. Required when model is I2V-01, I2V-01-Director, or I2V-01-live.',
88+
)
89+
model: MiniMaxModel = Field(
90+
...,
91+
description='Required. ID of model. Options: T2V-01-Director, I2V-01-Director, S2V-01, I2V-01, I2V-01-live, T2V-01',
92+
)
93+
prompt: Optional[str] = Field(
94+
None,
95+
description='Description of the video. Should be less than 2000 characters. Supports camera movement instructions in [brackets].',
96+
max_length=2000,
97+
)
98+
prompt_optimizer: Optional[bool] = Field(
99+
True,
100+
description='If true (default), the model will automatically optimize the prompt. Set to false for more precise control.',
101+
)
102+
subject_reference: Optional[list[SubjectReferenceItem]] = Field(
103+
None,
104+
description='Only available when model is S2V-01. The model will generate a video based on the subject uploaded through this parameter.',
105+
)
106+
duration: Optional[int] = Field(
107+
None,
108+
description="The length of the output video in seconds."
109+
)
110+
resolution: Optional[str] = Field(
111+
None,
112+
description="The dimensions of the video display. 1080p corresponds to 1920 x 1080 pixels, 768p corresponds to 1366 x 768 pixels."
113+
)
114+
115+
116+
class MinimaxVideoGenerationResponse(BaseModel):
117+
base_resp: MinimaxBaseResponse
118+
task_id: str = Field(
119+
..., description='The task ID for the asynchronous video generation task.'
120+
)

comfy_api_nodes/nodes_ideogram.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020

2121
from comfy_api_nodes.apinode_utils import (
2222
download_url_to_bytesio,
23-
bytesio_to_image_tensor,
2423
resize_mask_to_image,
2524
)
25+
from comfy_api_nodes.util import bytesio_to_image_tensor
2626
from server import PromptServer
2727

2828
V1_V1_RES_MAP = {

0 commit comments

Comments
 (0)