"""describe-image command.""" from __future__ import annotations from pathlib import Path from typing import Annotated, Optional import typer from freepik_cli.api.client import FreepikAPIError, FreepikClient from freepik_cli.api.images import ImageAPI from freepik_cli.utils.config import FreepikConfig from freepik_cli.utils.console import console, print_describe_result, print_error, print_no_wait from freepik_cli.utils.files import image_to_base64 from freepik_cli.utils.polling import FreepikTaskError, FreepikTimeoutError, PollConfig, poll_task def _get_api_key(api_key: Optional[str], config: FreepikConfig) -> str: key = api_key or config.api_key if not key: print_error("No API key found.", hint="Set [cyan]FREEPIK_API_KEY[/cyan] or pass [cyan]--api-key[/cyan].") raise typer.Exit(1) return key def describe_image( image: Annotated[ Path, typer.Argument( help="Image to analyze and describe", exists=True, file_okay=True, dir_okay=False, ), ], output: Annotated[ Optional[Path], typer.Option("--output", "-o", help="Save the generated prompt to a text file"), ] = None, wait: Annotated[ bool, typer.Option("--wait/--no-wait"), ] = True, api_key: Annotated[ Optional[str], typer.Option("--api-key", envvar="FREEPIK_API_KEY"), ] = None, ) -> None: """ [bold]Describe an image[/bold] and generate a text prompt for it. Reverse-engineers the image into an AI-ready prompt you can use with [cyan]generate-image[/cyan]. [dim]Examples:[/dim] freepik describe-image photo.jpg freepik describe-image scene.png --output prompt.txt """ config = FreepikConfig.load() key = _get_api_key(api_key, config) image_b64 = image_to_base64(image) with FreepikClient(key, base_url=config.base_url) as client: api = ImageAPI(client) with console.status("[info]Submitting image analysis…[/info]"): try: task_id = api.describe_submit(image_b64) except FreepikAPIError as exc: print_error(str(exc)) raise typer.Exit(1) if not wait: print_no_wait(task_id, "describe-image", "image-to-prompt") return poll_config = PollConfig(task_type="describe", max_wait=config.poll_timeout) try: result = poll_task( check_fn=lambda tid: api.describe_status(tid), task_id=task_id, config=poll_config, console=console, ) except (FreepikTaskError, FreepikTimeoutError) as exc: print_error(str(exc)) raise typer.Exit(1) prompt_text = api.get_prompt_text(result) if not prompt_text: print_error("Analysis completed but no prompt text found.") raise typer.Exit(1) saved_path: Optional[Path] = None if output: output.write_text(prompt_text, encoding="utf-8") saved_path = output print_describe_result(task_id, prompt_text, saved_path)