fix: skip aspect_ratio for kling-o1 models and detect image MIME via Pillow
kling-o1-pro and kling-o1-std silently fail when aspect_ratio is included in the payload — they derive it from the input image. Added VIDEO_ASPECT_RATIO_MODELS whitelist so only kling-elements and minimax-hailuo receive the parameter. Also switched image_to_base64 to use Pillow for format detection instead of trusting the file extension, which correctly handles files saved with the wrong extension. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -107,7 +107,14 @@ VIDEO_IMAGE_FIELDS: dict[VideoModel, str] = {
|
|||||||
VideoModel.MINIMAX_HAILUO: "image",
|
VideoModel.MINIMAX_HAILUO: "image",
|
||||||
}
|
}
|
||||||
|
|
||||||
# Kling Elements requires named aspect ratio slugs
|
# Models that support an aspect_ratio parameter at all
|
||||||
|
VIDEO_ASPECT_RATIO_MODELS: set[VideoModel] = {
|
||||||
|
VideoModel.KLING_ELEMENTS_PRO,
|
||||||
|
VideoModel.KLING_ELEMENTS_STD,
|
||||||
|
VideoModel.MINIMAX_HAILUO,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Of those, these require named slug aspect ratios instead of "W:H" strings
|
||||||
VIDEO_SLUG_ASPECT_RATIO_MODELS: set[VideoModel] = {
|
VIDEO_SLUG_ASPECT_RATIO_MODELS: set[VideoModel] = {
|
||||||
VideoModel.KLING_ELEMENTS_PRO,
|
VideoModel.KLING_ELEMENTS_PRO,
|
||||||
VideoModel.KLING_ELEMENTS_STD,
|
VideoModel.KLING_ELEMENTS_STD,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from freepik_cli.api.models import (
|
|||||||
VIDEO_POST_ENDPOINTS,
|
VIDEO_POST_ENDPOINTS,
|
||||||
VIDEO_STATUS_ENDPOINTS,
|
VIDEO_STATUS_ENDPOINTS,
|
||||||
VIDEO_IMAGE_FIELDS,
|
VIDEO_IMAGE_FIELDS,
|
||||||
VIDEO_SLUG_ASPECT_RATIO_MODELS,
|
VIDEO_ASPECT_RATIO_MODELS,
|
||||||
VideoModel,
|
VideoModel,
|
||||||
get_output_urls,
|
get_output_urls,
|
||||||
get_status,
|
get_status,
|
||||||
@@ -49,7 +49,7 @@ class VideoAPI:
|
|||||||
effective_duration = 6
|
effective_duration = 6
|
||||||
payload["duration"] = str(effective_duration)
|
payload["duration"] = str(effective_duration)
|
||||||
|
|
||||||
if aspect_ratio:
|
if aspect_ratio and model in VIDEO_ASPECT_RATIO_MODELS:
|
||||||
payload["aspect_ratio"] = normalize_aspect_ratio_video(aspect_ratio, model)
|
payload["aspect_ratio"] = normalize_aspect_ratio_video(aspect_ratio, model)
|
||||||
|
|
||||||
if seed is not None:
|
if seed is not None:
|
||||||
|
|||||||
@@ -20,16 +20,24 @@ from rich.progress import (
|
|||||||
|
|
||||||
|
|
||||||
def image_to_base64(path: Path) -> str:
|
def image_to_base64(path: Path) -> str:
|
||||||
"""Read an image file and return a base64-encoded string."""
|
"""Read an image file and return a base64-encoded string.
|
||||||
suffix = path.suffix.lower().lstrip(".")
|
|
||||||
mime_map = {
|
Uses Pillow to detect the actual format rather than trusting the file
|
||||||
"jpg": "image/jpeg",
|
extension — mismatched extensions (e.g. a JPEG saved as .png) would
|
||||||
"jpeg": "image/jpeg",
|
produce an incorrect MIME type that causes silent failures with some models.
|
||||||
"png": "image/png",
|
"""
|
||||||
"gif": "image/gif",
|
from PIL import Image
|
||||||
"webp": "image/webp",
|
|
||||||
|
_pillow_to_mime = {
|
||||||
|
"JPEG": "image/jpeg",
|
||||||
|
"PNG": "image/png",
|
||||||
|
"GIF": "image/gif",
|
||||||
|
"WEBP": "image/webp",
|
||||||
}
|
}
|
||||||
mime = mime_map.get(suffix, "image/jpeg")
|
with Image.open(path) as img:
|
||||||
|
fmt = img.format or "JPEG"
|
||||||
|
mime = _pillow_to_mime.get(fmt, "image/jpeg")
|
||||||
|
|
||||||
with open(path, "rb") as f:
|
with open(path, "rb") as f:
|
||||||
encoded = base64.b64encode(f.read()).decode()
|
encoded = base64.b64encode(f.read()).decode()
|
||||||
return f"data:{mime};base64,{encoded}"
|
return f"data:{mime};base64,{encoded}"
|
||||||
|
|||||||
Reference in New Issue
Block a user