Update: Added support for first and last frames

This commit is contained in:
jueming
2025-08-29 10:01:16 +08:00
parent 3c208445a9
commit 4396d8e805
3 changed files with 57 additions and 25 deletions
Binary file not shown.
Binary file not shown.
+57 -25
View File
@@ -29,16 +29,19 @@ class MiniMaxVideoGeneration:
"prompt_optimizer": ("BOOLEAN", {"default": True}),
},
"optional": {
"image": ("IMAGE", {
"tooltip": "Required for I2V models (I2V-01-Director, I2V-01, I2V-01-live). Optional for MiniMax-Hailuo-02 and other models."
"first_frame_image": ("IMAGE", {
"tooltip": "Required for I2V models (I2V-01-Director, I2V-01, I2V-01-live) and MiniMax-Hailuo-02 with 512P resolution. Optional for other cases."
}),
"last_frame_image": ("IMAGE", {
"tooltip": "Only supported by MiniMax-Hailuo-02 model. Model will generate video ending with this frame. Not supported with 512P resolution."
}),
"duration": (["6", "10"], {
"default": "6",
"tooltip": "Video duration in seconds. 01 series: only 6s. MiniMax-Hailuo-02: 6s or 10s (10s only available for 768P resolution)."
"tooltip": "Video duration in seconds. 01 series: only 6s. MiniMax-Hailuo-02: 6s or 10s (10s only available for 512P and 768P resolution)."
}),
"resolution": (["768P", "1080P"], {
"resolution": (["512P", "768P", "1080P"], {
"default": "768P",
"tooltip": "Video resolution. Only applicable to MiniMax-Hailuo-02 model. 01 series uses fixed resolution."
"tooltip": "Video resolution. Only applicable to MiniMax-Hailuo-02 model. 01 series uses fixed 720P resolution."
}),
"callback_url": ("STRING", {
"multiline": False,
@@ -53,7 +56,7 @@ class MiniMaxVideoGeneration:
FUNCTION = "generate_video"
CATEGORY = "JM-MiniMax-API/Video"
def generate_video(self, api_key, model, prompt, prompt_optimizer, image=None, duration="6", resolution="768P", callback_url=""):
def generate_video(self, api_key, model, prompt, prompt_optimizer, first_frame_image=None, last_frame_image=None, duration="6", resolution="768P", callback_url=""):
if not api_key:
raise ValueError("API Key must be provided")
@@ -64,21 +67,39 @@ class MiniMaxVideoGeneration:
hailuo_models = ["MiniMax-Hailuo-02"]
# Validate model-specific requirements
if model in i2v_models and image is None:
raise ValueError(f"Model {model} requires an image input. Please connect an image to the 'image' input.")
if model in i2v_models and first_frame_image is None:
raise ValueError(f"Model {model} requires a first frame image input. Please connect an image to the 'first_frame_image' input.")
if model in t2v_models and not prompt.strip():
raise ValueError(f"Model {model} requires a text prompt. Please provide a description in the 'prompt' field.")
# Validate duration and resolution combinations for MiniMax-Hailuo-02
# Validate MiniMax-Hailuo-02 specific requirements
if model in hailuo_models:
duration_int = int(duration)
# Check duration and resolution combinations
if duration_int == 10 and resolution == "1080P":
raise ValueError("MiniMax-Hailuo-02 model does not support 10s duration with 1080P resolution. Please use 768P for 10s duration or 6s for 1080P.")
raise ValueError("MiniMax-Hailuo-02 model does not support 10s duration with 1080P resolution. Please use 512P or 768P for 10s duration or 6s for 1080P.")
# Check 512P resolution requirements
if resolution == "512P" and first_frame_image is None:
raise ValueError("MiniMax-Hailuo-02 model with 512P resolution requires a first frame image. Please connect an image to the 'first_frame_image' input.")
# Check last_frame_image with 512P
if resolution == "512P" and last_frame_image is not None:
raise ValueError("MiniMax-Hailuo-02 model does not support last_frame_image with 512P resolution. Please use 768P or 1080P resolution.")
# Validate last_frame_image is only used with MiniMax-Hailuo-02
if last_frame_image is not None and model not in hailuo_models:
raise ValueError(f"last_frame_image is only supported by MiniMax-Hailuo-02 model, but current model is {model}.")
# Validate duration for 01 series models
if model not in hailuo_models and duration != "6":
print(f"Warning: Duration parameter is not applicable to {model}. Using default 6s duration.")
# Validate resolution for 01 series models
if model not in hailuo_models and resolution != "768P":
print(f"Warning: Resolution parameter is not applicable to {model}. 01 series models use fixed 720P resolution.")
try:
# Prepare API request
@@ -99,24 +120,24 @@ class MiniMaxVideoGeneration:
payload["duration"] = int(duration)
payload["resolution"] = resolution
# Handle image input for I2V models and MiniMax-Hailuo-02
if (model in i2v_models and image is not None) or (model in hailuo_models and image is not None):
# Helper function to convert ComfyUI image to base64
def convert_image_to_base64(image_tensor, image_name):
# Convert ComfyUI image tensor to PIL Image
if len(image.shape) == 4: # Batch dimension
if len(image_tensor.shape) == 4: # Batch dimension
# Take the first image from batch
image_tensor = image[0]
tensor = image_tensor[0]
else:
image_tensor = image
tensor = image_tensor
# Convert from tensor format (H, W, C) with values 0-1 to PIL Image
import torch
import numpy as np
# Convert tensor to numpy array and scale to 0-255
if isinstance(image_tensor, torch.Tensor):
image_np = image_tensor.cpu().numpy()
if isinstance(tensor, torch.Tensor):
image_np = tensor.cpu().numpy()
else:
image_np = image_tensor
image_np = tensor
# Ensure values are in range 0-1, then scale to 0-255
image_np = np.clip(image_np, 0, 1)
@@ -130,11 +151,11 @@ class MiniMaxVideoGeneration:
aspect_ratio = width / height
if aspect_ratio <= 2/5 or aspect_ratio >= 5/2:
raise ValueError(f"Image aspect ratio ({aspect_ratio:.2f}) must be between 2:5 and 5:2")
raise ValueError(f"{image_name} aspect ratio ({aspect_ratio:.2f}) must be between 2:5 and 5:2")
min_dimension = min(width, height)
if min_dimension < 300:
raise ValueError(f"Image short side ({min_dimension}px) must be at least 300px")
raise ValueError(f"{image_name} short side ({min_dimension}px) must be at least 300px")
# Convert PIL Image to base64
import io
@@ -151,16 +172,23 @@ class MiniMaxVideoGeneration:
# Check file size (should be < 20MB)
file_size = buffer.getbuffer().nbytes
if file_size > 20 * 1024 * 1024: # 20MB
raise ValueError(f"Image file size ({file_size/1024/1024:.1f}MB) exceeds 20MB limit")
raise ValueError(f"{image_name} file size ({file_size/1024/1024:.1f}MB) exceeds 20MB limit")
# Convert to base64
image_base64 = base64.b64encode(buffer.getvalue()).decode('utf-8')
# Add image to payload
payload["first_frame_image"] = f"data:image/jpeg;base64,{image_base64}"
print(f"{image_name} converted to base64, size: {len(image_base64)} characters")
print(f"{image_name} dimensions: {width}x{height}, aspect ratio: {aspect_ratio:.2f}")
print(f"Image converted to base64, size: {len(image_base64)} characters")
print(f"Image dimensions: {width}x{height}, aspect ratio: {aspect_ratio:.2f}")
return f"data:image/jpeg;base64,{image_base64}"
# Handle first frame image
if first_frame_image is not None:
payload["first_frame_image"] = convert_image_to_base64(first_frame_image, "First frame image")
# Handle last frame image (only for MiniMax-Hailuo-02)
if last_frame_image is not None:
payload["last_frame_image"] = convert_image_to_base64(last_frame_image, "Last frame image")
# Add optional callback URL if provided
if callback_url.strip():
@@ -173,6 +201,10 @@ class MiniMaxVideoGeneration:
if model in hailuo_models:
print(f"Duration: {duration}s")
print(f"Resolution: {resolution}")
if first_frame_image is not None:
print(f"First frame image: provided")
if last_frame_image is not None:
print(f"Last frame image: provided")
if callback_url:
print(f"Callback URL: {callback_url}")