Files
freepik/freepik_cli/api/images.py
T
valknar f24d138ab4 feat: initial Freepik AI CLI
Sophisticated Python CLI for generating and manipulating images and
video via the Freepik API, built with typer + rich.

Commands:
- generate-image: text-to-image with 8 models (flux-2-pro, mystic, seedream, etc.)
- generate-video: image-to-video with 7 models (kling, minimax, runway, etc.)
- generate-icon: text-to-icon in solid/outline/color/flat/sticker styles
- upscale-image: 3 modes (precision-v2, precision, creative) + 2x/4x scale
- upscale-video: standard/turbo modes
- expand-image: outpainting with per-side pixel offsets
- relight: AI-controlled relighting (Premium)
- style-transfer: artistic style application (Premium)
- describe-image: reverse-engineer an image into a prompt
- config set/get/show/reset: configuration management

Features: Rich Live polling panel, exponential backoff, --wait/--no-wait,
auto-timestamped output filenames, streaming download with progress bar,
FREEPIK_API_KEY env var support, venv-based setup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-08 10:56:45 +02:00

106 lines
3.6 KiB
Python

"""Image generation and analysis API methods."""
from __future__ import annotations
from typing import Any, Optional, Tuple
from freepik_cli.api.client import FreepikClient
from freepik_cli.api.models import (
IMAGE_POST_ENDPOINTS,
IMAGE_STATUS_ENDPOINTS,
ImageModel,
get_output_urls,
get_status,
get_task_id,
)
class ImageAPI:
def __init__(self, client: FreepikClient) -> None:
self._client = client
def generate(self, model: ImageModel, payload: dict[str, Any]) -> str:
"""Submit a generation task. Returns task_id."""
endpoint = IMAGE_POST_ENDPOINTS[model]
raw = self._client.post(endpoint, json=payload)
return get_task_id(raw)
def get_status(self, model: ImageModel, task_id: str) -> Tuple[str, dict[str, Any]]:
"""Poll status. Returns (status_str, raw_response)."""
endpoint = IMAGE_STATUS_ENDPOINTS[model].format(task_id=task_id)
raw = self._client.get(endpoint)
return get_status(raw), raw
def get_output_urls(self, raw: dict[str, Any]) -> list[str]:
return get_output_urls(raw)
# ------------------------------------------------------------------
# Image-to-prompt (describe)
# ------------------------------------------------------------------
def describe_submit(self, image_b64: str) -> str:
"""Submit image-to-prompt task. Returns task_id."""
raw = self._client.post("/v1/ai/image-to-prompt", json={"image": image_b64})
return get_task_id(raw)
def describe_status(self, task_id: str) -> Tuple[str, dict[str, Any]]:
raw = self._client.get(f"/v1/ai/image-to-prompt/{task_id}")
return get_status(raw), raw
def get_prompt_text(self, raw: dict[str, Any]) -> str:
"""Extract generated prompt text from a completed describe response."""
data = raw.get("data", raw)
return (
data.get("prompt")
or data.get("description")
or data.get("text")
or data.get("result", {}).get("prompt", "")
or ""
)
# ------------------------------------------------------------------
# Image expansion (outpainting)
# ------------------------------------------------------------------
def expand_submit(
self,
model: str,
image_b64: str,
left: int = 0,
right: int = 0,
top: int = 0,
bottom: int = 0,
prompt: Optional[str] = None,
seed: Optional[int] = None,
) -> str:
payload: dict[str, Any] = {
"image": image_b64,
"left": left,
"right": right,
"top": top,
"bottom": bottom,
}
if prompt:
payload["prompt"] = prompt
if seed is not None:
payload["seed"] = seed
endpoint_map = {
"flux-pro": "/v1/ai/image-expand/flux-pro",
"ideogram": "/v1/ai/image-expand/ideogram",
"seedream-v4-5": "/v1/ai/image-expand/seedream-v4-5",
}
endpoint = endpoint_map.get(model, "/v1/ai/image-expand/flux-pro")
raw = self._client.post(endpoint, json=payload)
return get_task_id(raw)
def expand_status(self, model: str, task_id: str) -> Tuple[str, dict[str, Any]]:
endpoint_map = {
"flux-pro": "/v1/ai/image-expand/flux-pro",
"ideogram": "/v1/ai/image-expand/ideogram",
"seedream-v4-5": "/v1/ai/image-expand/seedream-v4-5",
}
base = endpoint_map.get(model, "/v1/ai/image-expand/flux-pro")
raw = self._client.get(f"{base}/{task_id}")
return get_status(raw), raw