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:
2026-04-10 18:15:59 +02:00
parent 209a4840db
commit 0de3f7d6bc
3 changed files with 55 additions and 14 deletions
+28 -6
View File
@@ -27,8 +27,6 @@ class VideoModel(str, Enum):
KLING_ELEMENTS_PRO = "kling-elements-pro"
KLING_ELEMENTS_STD = "kling-elements-std"
MINIMAX_HAILUO = "minimax-hailuo"
WAN_2_5 = "wan-2.5"
RUNWAY_GEN4 = "runway-gen4"
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_STD: "/v1/ai/image-to-video/kling-elements-std",
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] = {
@@ -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_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.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] = {
UpscaleMode.CREATIVE: "/v1/ai/image-upscaler",
UpscaleMode.PRECISION: "/v1/ai/image-upscaler-precision",
+20 -6
View File
@@ -8,10 +8,13 @@ from freepik_cli.api.client import FreepikClient
from freepik_cli.api.models import (
VIDEO_POST_ENDPOINTS,
VIDEO_STATUS_ENDPOINTS,
VIDEO_IMAGE_FIELDS,
VIDEO_SLUG_ASPECT_RATIO_MODELS,
VideoModel,
get_output_urls,
get_status,
get_task_id,
normalize_aspect_ratio_video,
)
@@ -29,15 +32,26 @@ class VideoAPI:
seed: Optional[int] = None,
) -> str:
"""Submit an image-to-video task. Returns task_id."""
payload: dict[str, Any] = {
"image": image_b64,
}
image_field = VIDEO_IMAGE_FIELDS[model]
# 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:
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:
payload["aspect_ratio"] = aspect_ratio
payload["aspect_ratio"] = normalize_aspect_ratio_video(aspect_ratio, model)
if seed is not None:
payload["seed"] = seed
+7 -2
View File
@@ -161,7 +161,11 @@ def generate_video(
] = None,
duration: Annotated[
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,
aspect_ratio: Annotated[
str,
@@ -189,7 +193,8 @@ def generate_video(
[dim]Examples:[/dim]
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()
key = _get_api_key(api_key, config)