From 0de3f7d6bc2fafd5a67b16f0260ed54c1b959123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Kr=C3=BCger?= Date: Fri, 10 Apr 2026 18:15:59 +0200 Subject: [PATCH] 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 --- freepik_cli/api/models.py | 34 ++++++++++++++++++++++++++------ freepik_cli/api/videos.py | 26 ++++++++++++++++++------ freepik_cli/commands/generate.py | 9 +++++++-- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/freepik_cli/api/models.py b/freepik_cli/api/models.py index 4e03f89..0b73b36 100644 --- a/freepik_cli/api/models.py +++ b/freepik_cli/api/models.py @@ -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", diff --git a/freepik_cli/api/videos.py b/freepik_cli/api/videos.py index 3bd4d6d..9bd637b 100644 --- a/freepik_cli/api/videos.py +++ b/freepik_cli/api/videos.py @@ -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 diff --git a/freepik_cli/commands/generate.py b/freepik_cli/commands/generate.py index 27ad5a9..57b2bb2 100644 --- a/freepik_cli/commands/generate.py +++ b/freepik_cli/commands/generate.py @@ -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)