fix: normalize aspect ratio per model, surface invalid_params in errors

Models like mystic, flux-pro-1.1, and seedream-v4/v4-5 require named
aspect ratio slugs (e.g. "square_1_1", "widescreen_16_9") while other
models accept the "W:H" format directly.

- Add normalize_aspect_ratio() mapping W:H strings to slugs for affected models
- Apply normalization in generate-image before building the request payload
- Improve FreepikAPIError to surface invalid_params field details from the API
  response, so "Validation error" now also shows which field failed and why

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 18:06:40 +02:00
parent e6bf85ca8a
commit d0f454df29
3 changed files with 49 additions and 3 deletions
+8 -1
View File
@@ -34,10 +34,17 @@ class FreepikAPIError(Exception):
or f"HTTP {response.status_code}"
)
# Append individual field validation errors when present
invalid = body.get("invalid_params", [])
if invalid:
details = "\n".join(
f"{p.get('field', '?')}: {p.get('reason', '')}" for p in invalid
)
message = f"{message}\n\n{details}"
hints = {
401: "Check your API key — set FREEPIK_API_KEY or use --api-key.",
403: "Your plan may not support this feature. Check your Freepik subscription.",
422: "Invalid request parameters. Check the options you provided.",
429: "Rate limit exceeded. Please wait before retrying.",
}
hint = hints.get(response.status_code)
+39
View File
@@ -124,6 +124,45 @@ VIDEO_UPSCALE_POST_ENDPOINTS: dict[VideoUpscaleMode, str] = {
VIDEO_UPSCALE_STATUS_ENDPOINT = "/v1/ai/video-upscaler/{task_id}"
# ---------------------------------------------------------------------------
# Aspect ratio normalization
# ---------------------------------------------------------------------------
# Models that require named slug aspect ratios instead of "W:H" strings
SLUG_ASPECT_RATIO_MODELS: set[ImageModel] = {
ImageModel.MYSTIC,
ImageModel.FLUX_PRO_1_1,
ImageModel.SEEDREAM_V4,
ImageModel.SEEDREAM_V4_5,
}
# User-friendly "W:H" → API slug mapping
_RATIO_TO_SLUG: dict[str, str] = {
"1:1": "square_1_1",
"16:9": "widescreen_16_9",
"9:16": "social_story_9_16",
"4:3": "classic_4_3",
"3:4": "traditional_3_4",
"3:2": "standard_3_2",
"2:3": "portrait_2_3",
"2:1": "horizontal_2_1",
"1:2": "vertical_1_2",
"4:5": "social_post_4_5",
"21:9": "widescreen_16_9", # closest match
}
def normalize_aspect_ratio(ratio: str, model: ImageModel) -> str:
"""Convert a user-facing aspect ratio to the format required by the model."""
if model not in SLUG_ASPECT_RATIO_MODELS:
return ratio # free-form models accept "1:1" directly
slug = _RATIO_TO_SLUG.get(ratio)
if slug:
return slug
# Already a slug (user passed "square_1_1" directly) — pass through
return ratio
# ---------------------------------------------------------------------------
# Response normalization helpers
# ---------------------------------------------------------------------------