fix: correct per-model video API field names and remove non-existent models
Each video model uses a different image input field: - kling-o1-pro/std: first_frame (not image) - kling-elements-pro/std: images (array) - minimax-hailuo: image, duration fixed at "6" Also: - kling-elements requires slug aspect ratios (square_1_1, etc.) - Remove wan-2.5 and runway-gen4 which return 404 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,8 +27,6 @@ class VideoModel(str, Enum):
|
|||||||
KLING_ELEMENTS_PRO = "kling-elements-pro"
|
KLING_ELEMENTS_PRO = "kling-elements-pro"
|
||||||
KLING_ELEMENTS_STD = "kling-elements-std"
|
KLING_ELEMENTS_STD = "kling-elements-std"
|
||||||
MINIMAX_HAILUO = "minimax-hailuo"
|
MINIMAX_HAILUO = "minimax-hailuo"
|
||||||
WAN_2_5 = "wan-2.5"
|
|
||||||
RUNWAY_GEN4 = "runway-gen4"
|
|
||||||
|
|
||||||
|
|
||||||
class UpscaleMode(str, Enum):
|
class UpscaleMode(str, Enum):
|
||||||
@@ -90,8 +88,6 @@ VIDEO_POST_ENDPOINTS: dict[VideoModel, str] = {
|
|||||||
VideoModel.KLING_ELEMENTS_PRO: "/v1/ai/image-to-video/kling-elements-pro",
|
VideoModel.KLING_ELEMENTS_PRO: "/v1/ai/image-to-video/kling-elements-pro",
|
||||||
VideoModel.KLING_ELEMENTS_STD: "/v1/ai/image-to-video/kling-elements-std",
|
VideoModel.KLING_ELEMENTS_STD: "/v1/ai/image-to-video/kling-elements-std",
|
||||||
VideoModel.MINIMAX_HAILUO: "/v1/ai/image-to-video/minimax-hailuo-02-1080p",
|
VideoModel.MINIMAX_HAILUO: "/v1/ai/image-to-video/minimax-hailuo-02-1080p",
|
||||||
VideoModel.WAN_2_5: "/v1/ai/image-to-video/wan-2-5",
|
|
||||||
VideoModel.RUNWAY_GEN4: "/v1/ai/image-to-video/runway-gen4",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VIDEO_STATUS_ENDPOINTS: dict[VideoModel, str] = {
|
VIDEO_STATUS_ENDPOINTS: dict[VideoModel, str] = {
|
||||||
@@ -100,10 +96,36 @@ VIDEO_STATUS_ENDPOINTS: dict[VideoModel, str] = {
|
|||||||
VideoModel.KLING_ELEMENTS_PRO: "/v1/ai/image-to-video/kling-elements-pro/{task_id}",
|
VideoModel.KLING_ELEMENTS_PRO: "/v1/ai/image-to-video/kling-elements-pro/{task_id}",
|
||||||
VideoModel.KLING_ELEMENTS_STD: "/v1/ai/image-to-video/kling-elements-std/{task_id}",
|
VideoModel.KLING_ELEMENTS_STD: "/v1/ai/image-to-video/kling-elements-std/{task_id}",
|
||||||
VideoModel.MINIMAX_HAILUO: "/v1/ai/image-to-video/minimax-hailuo-02-1080p/{task_id}",
|
VideoModel.MINIMAX_HAILUO: "/v1/ai/image-to-video/minimax-hailuo-02-1080p/{task_id}",
|
||||||
VideoModel.WAN_2_5: "/v1/ai/image-to-video/wan-2-5/{task_id}",
|
|
||||||
VideoModel.RUNWAY_GEN4: "/v1/ai/image-to-video/runway-gen4/{task_id}",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Per-model image input field name
|
||||||
|
VIDEO_IMAGE_FIELDS: dict[VideoModel, str] = {
|
||||||
|
VideoModel.KLING_O1_PRO: "first_frame",
|
||||||
|
VideoModel.KLING_O1_STD: "first_frame",
|
||||||
|
VideoModel.KLING_ELEMENTS_PRO: "images", # expects an array
|
||||||
|
VideoModel.KLING_ELEMENTS_STD: "images", # expects an array
|
||||||
|
VideoModel.MINIMAX_HAILUO: "image",
|
||||||
|
}
|
||||||
|
|
||||||
|
# Kling Elements requires named aspect ratio slugs
|
||||||
|
VIDEO_SLUG_ASPECT_RATIO_MODELS: set[VideoModel] = {
|
||||||
|
VideoModel.KLING_ELEMENTS_PRO,
|
||||||
|
VideoModel.KLING_ELEMENTS_STD,
|
||||||
|
}
|
||||||
|
|
||||||
|
_VIDEO_RATIO_TO_SLUG: dict[str, str] = {
|
||||||
|
"1:1": "square_1_1",
|
||||||
|
"16:9": "widescreen_16_9",
|
||||||
|
"9:16": "social_story_9_16",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_aspect_ratio_video(ratio: str, model: VideoModel) -> str:
|
||||||
|
"""Convert a user-facing aspect ratio to the format required by the video model."""
|
||||||
|
if model not in VIDEO_SLUG_ASPECT_RATIO_MODELS:
|
||||||
|
return ratio
|
||||||
|
return _VIDEO_RATIO_TO_SLUG.get(ratio, ratio)
|
||||||
|
|
||||||
UPSCALE_POST_ENDPOINTS: dict[UpscaleMode, str] = {
|
UPSCALE_POST_ENDPOINTS: dict[UpscaleMode, str] = {
|
||||||
UpscaleMode.CREATIVE: "/v1/ai/image-upscaler",
|
UpscaleMode.CREATIVE: "/v1/ai/image-upscaler",
|
||||||
UpscaleMode.PRECISION: "/v1/ai/image-upscaler-precision",
|
UpscaleMode.PRECISION: "/v1/ai/image-upscaler-precision",
|
||||||
|
|||||||
@@ -8,10 +8,13 @@ from freepik_cli.api.client import FreepikClient
|
|||||||
from freepik_cli.api.models import (
|
from freepik_cli.api.models import (
|
||||||
VIDEO_POST_ENDPOINTS,
|
VIDEO_POST_ENDPOINTS,
|
||||||
VIDEO_STATUS_ENDPOINTS,
|
VIDEO_STATUS_ENDPOINTS,
|
||||||
|
VIDEO_IMAGE_FIELDS,
|
||||||
|
VIDEO_SLUG_ASPECT_RATIO_MODELS,
|
||||||
VideoModel,
|
VideoModel,
|
||||||
get_output_urls,
|
get_output_urls,
|
||||||
get_status,
|
get_status,
|
||||||
get_task_id,
|
get_task_id,
|
||||||
|
normalize_aspect_ratio_video,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -29,15 +32,26 @@ class VideoAPI:
|
|||||||
seed: Optional[int] = None,
|
seed: Optional[int] = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Submit an image-to-video task. Returns task_id."""
|
"""Submit an image-to-video task. Returns task_id."""
|
||||||
payload: dict[str, Any] = {
|
image_field = VIDEO_IMAGE_FIELDS[model]
|
||||||
"image": image_b64,
|
|
||||||
}
|
# kling-elements uses an array; all others use a scalar
|
||||||
|
if image_field == "images":
|
||||||
|
payload: dict[str, Any] = {"images": [image_b64]}
|
||||||
|
else:
|
||||||
|
payload = {image_field: image_b64}
|
||||||
|
|
||||||
if prompt:
|
if prompt:
|
||||||
payload["prompt"] = prompt
|
payload["prompt"] = prompt
|
||||||
if duration:
|
|
||||||
payload["duration"] = str(duration)
|
# minimax only supports duration=6; clamp silently
|
||||||
|
effective_duration = duration
|
||||||
|
if model == VideoModel.MINIMAX_HAILUO:
|
||||||
|
effective_duration = 6
|
||||||
|
payload["duration"] = str(effective_duration)
|
||||||
|
|
||||||
if aspect_ratio:
|
if aspect_ratio:
|
||||||
payload["aspect_ratio"] = aspect_ratio
|
payload["aspect_ratio"] = normalize_aspect_ratio_video(aspect_ratio, model)
|
||||||
|
|
||||||
if seed is not None:
|
if seed is not None:
|
||||||
payload["seed"] = seed
|
payload["seed"] = seed
|
||||||
|
|
||||||
|
|||||||
@@ -161,7 +161,11 @@ def generate_video(
|
|||||||
] = None,
|
] = None,
|
||||||
duration: Annotated[
|
duration: Annotated[
|
||||||
int,
|
int,
|
||||||
typer.Option("--duration", "-d", help="Video duration in seconds: [cyan]5[/cyan] or [cyan]10[/cyan]", min=5, max=10),
|
typer.Option(
|
||||||
|
"--duration", "-d",
|
||||||
|
help="Duration in seconds: [cyan]5[/cyan] or [cyan]10[/cyan] (minimax-hailuo is fixed at 6s)",
|
||||||
|
min=5, max=10,
|
||||||
|
),
|
||||||
] = 5,
|
] = 5,
|
||||||
aspect_ratio: Annotated[
|
aspect_ratio: Annotated[
|
||||||
str,
|
str,
|
||||||
@@ -189,7 +193,8 @@ def generate_video(
|
|||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik generate-video photo.jpg --prompt "gentle ocean waves" --model kling-o1-pro
|
freepik generate-video photo.jpg --prompt "gentle ocean waves" --model kling-o1-pro
|
||||||
freepik generate-video portrait.png --model minimax-hailuo --duration 10 --aspect-ratio 9:16
|
freepik generate-video portrait.png --model kling-elements-pro --aspect-ratio 9:16
|
||||||
|
freepik generate-video photo.jpg --model minimax-hailuo --aspect-ratio 16:9
|
||||||
"""
|
"""
|
||||||
config = FreepikConfig.load()
|
config = FreepikConfig.load()
|
||||||
key = _get_api_key(api_key, config)
|
key = _get_api_key(api_key, config)
|
||||||
|
|||||||
Reference in New Issue
Block a user