fix: align Freepik API paths with OpenAPI spec
Some checks failed
Build and Push Docker Image / build (push) Failing after 9s

The original implementation used guessed endpoint paths that don't match
the actual Freepik API. Key fixes based on their OpenAPI spec:

- Task polling is per-endpoint (e.g. GET /v1/ai/text-to-image/flux-dev/{task-id})
  not a generic /v1/ai/tasks/{id}. freepik_client now returns TaskResult
  with status_path, and task_tracker polls using that path.
- Fixed endpoint paths: flux-pro -> flux-pro-v1-1, upscale -> image-upscaler,
  relight -> image-relight, style-transfer -> image-style-transfer,
  expand -> image-expand/flux-pro, inpaint -> ideogram-image-edit,
  remove-background -> beta/remove-background, classifier -> classifier/image,
  audio-isolate -> audio-isolation, icon -> text-to-icon
- Fixed video paths: kling -> kling-o1-pro with kling-o1 status path,
  minimax -> minimax-hailuo-02-1080p, seedance -> seedance-pro-1080p
- Fixed request schemas to match actual API params (e.g. scale_factor
  not scale, reference_image not style_reference, image_url for bg removal)
- Fixed response parsing: status is uppercase (COMPLETED not completed),
  results in data.generated[] array, classifier returns [{class_name, probability}]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-16 16:26:42 +01:00
parent 99c24adfe8
commit 1a5c686dfc
10 changed files with 333 additions and 269 deletions

View File

@@ -6,36 +6,43 @@ from pydantic import BaseModel, Field
class UpscaleCreativeRequest(BaseModel):
image: str = Field(..., description='Base64-encoded image')
prompt: Optional[str] = None
scale: Optional[int] = Field(None, ge=2, le=4)
creativity: Optional[float] = Field(None, ge=0.0, le=1.0)
resemblance: Optional[float] = Field(None, ge=0.0, le=1.0)
scale_factor: Optional[str] = Field(None, description='2x, 4x, 8x, or 16x')
creativity: Optional[int] = Field(None, ge=-10, le=10)
resemblance: Optional[int] = Field(None, ge=-10, le=10)
optimized_for: Optional[str] = Field(
None,
description='standard, soft_portraits, hard_portraits, art_n_illustration, etc.',
)
class UpscalePrecisionRequest(BaseModel):
image: str = Field(..., description='Base64-encoded image')
scale: Optional[int] = Field(None, ge=2, le=4)
scale_factor: Optional[str] = Field(None, description='2x or 4x')
class RelightRequest(BaseModel):
image: str = Field(..., description='Base64-encoded image')
image: str = Field(..., description='Base64 or URL of image')
prompt: Optional[str] = None
light_source: Optional[str] = None
intensity: Optional[float] = Field(None, ge=0.0, le=1.0)
transfer_light_from_reference_image: Optional[str] = Field(
None, description='Base64 or URL of reference image for light transfer',
)
light_transfer_strength: Optional[int] = Field(None, ge=0, le=100)
class StyleTransferRequest(BaseModel):
image: str = Field(..., description='Base64-encoded image')
style_reference: str = Field(..., description='Base64-encoded style reference image')
strength: Optional[float] = Field(None, ge=0.0, le=1.0)
image: str = Field(..., description='Base64 or URL of image')
reference_image: str = Field(..., description='Base64 or URL of style reference image')
prompt: Optional[str] = None
style_strength: Optional[int] = Field(None, ge=0, le=100)
structure_strength: Optional[int] = Field(None, ge=0, le=100)
class ExpandRequest(BaseModel):
image: str = Field(..., description='Base64-encoded image')
image: str = Field(..., description='Base64 or URL of image')
prompt: Optional[str] = None
direction: Optional[str] = Field(None, description='Expansion direction')
class InpaintRequest(BaseModel):
image: str = Field(..., description='Base64-encoded image')
mask: str = Field(..., description='Base64-encoded mask image')
image: str = Field(..., description='Base64 or URL of image')
mask: str = Field(..., description='Base64 or URL of mask image')
prompt: str = Field(..., min_length=1)

View File

@@ -5,31 +5,30 @@ from pydantic import BaseModel, Field
class MysticRequest(BaseModel):
prompt: str = Field(..., min_length=1, max_length=4000)
negative_prompt: Optional[str] = None
resolution: Optional[str] = None
resolution: Optional[str] = Field(None, description='1k, 2k, or 4k')
aspect_ratio: Optional[str] = Field(None, description='e.g. square_1_1, widescreen_16_9')
model: Optional[str] = Field(None, description='realism, fluid, zen, flexible, super_real, editorial_portraits')
seed: Optional[int] = Field(None, ge=1, le=4294967295)
styling: Optional[dict] = None
seed: Optional[int] = None
num_images: Optional[int] = Field(None, ge=1, le=4)
structure_reference: Optional[str] = Field(None, description='Base64 image for structure reference')
style_reference: Optional[str] = Field(None, description='Base64 image for style reference')
class FluxDevRequest(BaseModel):
prompt: str = Field(..., min_length=1, max_length=4000)
image: Optional[str] = Field(None, description='Base64-encoded image for img2img')
guidance_scale: Optional[float] = Field(None, ge=1.0, le=20.0)
num_images: Optional[int] = Field(None, ge=1, le=4)
seed: Optional[int] = None
aspect_ratio: Optional[str] = Field(None, description='e.g. square_1_1, widescreen_16_9')
styling: Optional[dict] = None
seed: Optional[int] = Field(None, ge=1, le=4294967295)
class FluxProRequest(BaseModel):
prompt: str = Field(..., min_length=1, max_length=4000)
image: Optional[str] = Field(None, description='Base64-encoded image for img2img')
guidance_scale: Optional[float] = Field(None, ge=1.0, le=20.0)
seed: Optional[int] = None
aspect_ratio: Optional[str] = Field(None, description='e.g. square_1_1, widescreen_16_9')
styling: Optional[dict] = None
seed: Optional[int] = Field(None, ge=1, le=4294967295)
class SeedreamRequest(BaseModel):
prompt: str = Field(..., min_length=1, max_length=4000)
image: Optional[str] = Field(None, description='Base64-encoded image for img2img')
aspect_ratio: Optional[str] = None
num_images: Optional[int] = Field(None, ge=1, le=4)
seed: Optional[int] = None
aspect_ratio: Optional[str] = Field(None, description='e.g. square_1_1, widescreen_16_9')
seed: Optional[int] = Field(None, ge=1, le=4294967295)

View File

@@ -3,10 +3,24 @@ from typing import Optional
from pydantic import BaseModel, Field
class ClassificationResult(BaseModel):
class_name: str
probability: float
class ClassificationResponse(BaseModel):
is_ai_generated: bool
ai_probability: float
human_probability: float
data: list[ClassificationResult]
class RemoveBackgroundRequest(BaseModel):
image_url: str = Field(..., description='URL of image to remove background from')
class RemoveBackgroundResponse(BaseModel):
original: Optional[str] = None
high_resolution: Optional[str] = None
preview: Optional[str] = None
url: Optional[str] = None
class IconRequest(BaseModel):

View File

@@ -4,20 +4,20 @@ from pydantic import BaseModel, Field
class KlingRequest(BaseModel):
image: str = Field(..., description='Base64-encoded image')
prompt: Optional[str] = None
duration: Optional[str] = Field(None, description='5 or 10 seconds')
aspect_ratio: Optional[str] = None
first_frame: Optional[str] = Field(None, description='Base64 or URL of first frame image')
last_frame: Optional[str] = Field(None, description='Base64 or URL of last frame image')
prompt: Optional[str] = Field(None, max_length=2500)
duration: Optional[int] = Field(None, description='5 or 10 seconds')
aspect_ratio: Optional[str] = Field(None, description='16:9, 9:16, or 1:1')
class MinimaxRequest(BaseModel):
prompt: str = Field(..., min_length=1, max_length=4000)
first_frame_image: Optional[str] = Field(None, description='Base64-encoded image')
subject_reference: Optional[str] = Field(None, description='Base64-encoded reference image')
first_frame_image: Optional[str] = Field(None, description='Base64 or URL of first frame')
last_frame_image: Optional[str] = Field(None, description='Base64 or URL of last frame')
class SeedanceRequest(BaseModel):
prompt: str = Field(..., min_length=1, max_length=4000)
image: Optional[str] = Field(None, description='Base64-encoded image')
duration: Optional[str] = None
resolution: Optional[str] = None
prompt: str = Field(..., min_length=1, max_length=2000)
image: Optional[str] = Field(None, description='Base64 or URL of input image')
duration: Optional[str] = Field(None, description='5 or 10 seconds')