refactor: rename project from Freepik to Magnific
Rename all identifiers, strings, file names, env vars, CLI entry point, ASCII banner, and API endpoint to reflect the company rebrand. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+9
-9
@@ -1,11 +1,11 @@
|
|||||||
# Freepik API Configuration
|
# Magnific API Configuration
|
||||||
# Get your API key at https://www.freepik.com/api
|
# Get your API key at https://magnific.ai
|
||||||
FREEPIK_API_KEY=your_api_key_here
|
MAGNIFIC_API_KEY=your_api_key_here
|
||||||
|
|
||||||
# Optional overrides
|
# Optional overrides
|
||||||
# FREEPIK_BASE_URL=https://api.freepik.com
|
# MAGNIFIC_BASE_URL=https://api.magnific.ai
|
||||||
# FREEPIK_POLL_TIMEOUT=600
|
# MAGNIFIC_POLL_TIMEOUT=600
|
||||||
# FREEPIK_DEFAULT_IMAGE_MODEL=flux-2-pro
|
# MAGNIFIC_DEFAULT_IMAGE_MODEL=flux-2-pro
|
||||||
# FREEPIK_DEFAULT_VIDEO_MODEL=kling-o1-pro
|
# MAGNIFIC_DEFAULT_VIDEO_MODEL=kling-o1-pro
|
||||||
# FREEPIK_DEFAULT_OUTPUT_DIR=./output
|
# MAGNIFIC_DEFAULT_OUTPUT_DIR=./output
|
||||||
# FREEPIK_SHOW_BANNER=true
|
# MAGNIFIC_SHOW_BANNER=true
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
# Freepik AI CLI
|
# Magnific AI CLI
|
||||||
|
|
||||||
A sophisticated, beautiful command-line interface for the [Freepik AI API](https://docs.freepik.com/introduction) — generate images, animate videos, upscale media, and more, all from your terminal.
|
A sophisticated, beautiful command-line interface for the [Magnific AI API](https://magnific.ai) — generate images, animate videos, upscale media, and more, all from your terminal.
|
||||||
|
|
||||||
```
|
```
|
||||||
███████╗██████╗ ███████╗███████╗██████╗ ██╗██╗ ██╗
|
███╗ ███╗ █████╗ ██████╗ ███╗ ██╗██╗███████╗██╗ ██████╗
|
||||||
██╔════╝██╔══██╗██╔════╝██╔════╝██╔══██╗██║██║ ██╔╝
|
████╗ ████║██╔══██╗██╔════╝ ████╗ ██║██║██╔════╝██║██╔════╝
|
||||||
█████╗ ██████╔╝█████╗ █████╗ ██████╔╝██║█████╔╝
|
██╔████╔██║███████║██║ ███╗██╔██╗ ██║██║█████╗ ██║██║
|
||||||
██╔══╝ ██╔══██╗██╔══╝ ██╔══╝ ██╔═══╝ ██║██╔═██╗
|
██║╚██╔╝██║██╔══██║██║ ██║██║╚██╗██║██║██╔══╝ ██║██║
|
||||||
██║ ██║ ██║███████╗███████╗██║ ██║██║ ██╗
|
██║ ╚═╝ ██║██║ ██║╚██████╔╝██║ ╚████║██║██║ ██║╚██████╗
|
||||||
╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝
|
╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝╚═╝ ╚═╝ ╚═════╝
|
||||||
AI Media Generation CLI • v0.1.0
|
AI Media Generation CLI • v0.1.0
|
||||||
```
|
```
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
@@ -18,20 +18,20 @@ A sophisticated, beautiful command-line interface for the [Freepik AI API](https
|
|||||||
- **Beautiful terminal UI** — live polling panels, progress bars, color-coded status, Rich-themed output
|
- **Beautiful terminal UI** — live polling panels, progress bars, color-coded status, Rich-themed output
|
||||||
- **15+ AI models** — Flux, Mystic, Seedream, Kling, Minimax, Runway, and more
|
- **15+ AI models** — Flux, Mystic, Seedream, Kling, Minimax, Runway, and more
|
||||||
- **Async-first** — all long-running tasks poll with exponential backoff; use `--no-wait` for fire-and-forget
|
- **Async-first** — all long-running tasks poll with exponential backoff; use `--no-wait` for fire-and-forget
|
||||||
- **Zero config required** — just set `FREEPIK_API_KEY` and go
|
- **Zero config required** — just set `MAGNIFIC_API_KEY` and go
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Prerequisites
|
### Prerequisites
|
||||||
|
|
||||||
- Python 3.11+
|
- Python 3.11+
|
||||||
- A [Freepik API key](https://www.freepik.com/api) (free tier includes $5 credit)
|
- A [Magnific API key](https://magnific.ai) (free tier includes $5 credit)
|
||||||
|
|
||||||
### Setup
|
### Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone <repo>
|
git clone <repo>
|
||||||
cd freepik
|
cd magnific
|
||||||
|
|
||||||
python3 -m venv .venv
|
python3 -m venv .venv
|
||||||
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
||||||
@@ -42,7 +42,7 @@ pip install -e .
|
|||||||
### API Key
|
### API Key
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export FREEPIK_API_KEY=your_api_key_here
|
export MAGNIFIC_API_KEY=your_api_key_here
|
||||||
```
|
```
|
||||||
|
|
||||||
Or add it to a `.env` file in the project root (see `.env.example`).
|
Or add it to a `.env` file in the project root (see `.env.example`).
|
||||||
@@ -51,19 +51,19 @@ Or add it to a `.env` file in the project root (see `.env.example`).
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Generate an image
|
# Generate an image
|
||||||
freepik generate-image "a misty forest at dawn, cinematic lighting"
|
magnific generate-image "a misty forest at dawn, cinematic lighting"
|
||||||
|
|
||||||
# Animate an image into a video
|
# Animate an image into a video
|
||||||
freepik generate-video photo.jpg --prompt "gentle camera drift" --duration 5
|
magnific generate-video photo.jpg --prompt "gentle camera drift" --duration 5
|
||||||
|
|
||||||
# Upscale an image 4x
|
# Upscale an image 4x
|
||||||
freepik upscale-image photo.jpg --mode precision-v2 --scale 4x
|
magnific upscale-image photo.jpg --mode precision-v2 --scale 4x
|
||||||
|
|
||||||
# Upscale a video
|
# Upscale a video
|
||||||
freepik upscale-video clip.mp4 --mode turbo
|
magnific upscale-video clip.mp4 --mode turbo
|
||||||
|
|
||||||
# Describe an image (reverse-engineer its prompt)
|
# Describe an image (reverse-engineer its prompt)
|
||||||
freepik describe-image painting.jpg
|
magnific describe-image painting.jpg
|
||||||
```
|
```
|
||||||
|
|
||||||
## Commands
|
## Commands
|
||||||
@@ -73,7 +73,7 @@ freepik describe-image painting.jpg
|
|||||||
Generate an image from a text prompt.
|
Generate an image from a text prompt.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik generate-image <prompt> [OPTIONS]
|
magnific generate-image <prompt> [OPTIONS]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Short | Default | Description |
|
| Option | Short | Default | Description |
|
||||||
@@ -85,14 +85,14 @@ freepik generate-image <prompt> [OPTIONS]
|
|||||||
| `--input-image` | `-i` | — | Reference image for img2img (flux-kontext-pro) |
|
| `--input-image` | `-i` | — | Reference image for img2img (flux-kontext-pro) |
|
||||||
| `--output` | `-o` | auto | Output file path |
|
| `--output` | `-o` | auto | Output file path |
|
||||||
| `--wait / --no-wait` | | `--wait` | Wait for completion or return task ID |
|
| `--wait / --no-wait` | | `--wait` | Wait for completion or return task ID |
|
||||||
| `--api-key` | | `$FREEPIK_API_KEY` | API key override |
|
| `--api-key` | | `$MAGNIFIC_API_KEY` | API key override |
|
||||||
|
|
||||||
**Available models:**
|
**Available models:**
|
||||||
|
|
||||||
| Model | Description |
|
| Model | Description |
|
||||||
|-------|-------------|
|
|-------|-------------|
|
||||||
| `flux-2-pro` | High-quality, versatile (default) |
|
| `flux-2-pro` | High-quality, versatile (default) |
|
||||||
| `mystic` | Freepik's exclusive photorealistic workflow |
|
| `mystic` | Magnific's exclusive photorealistic workflow |
|
||||||
| `flux-kontext-pro` | Instruction-based image editing (img2img) |
|
| `flux-kontext-pro` | Instruction-based image editing (img2img) |
|
||||||
| `flux-2-turbo` | Fast generation |
|
| `flux-2-turbo` | Fast generation |
|
||||||
| `flux-pro-1.1` | Flux Pro v1.1 |
|
| `flux-pro-1.1` | Flux Pro v1.1 |
|
||||||
@@ -103,11 +103,11 @@ freepik generate-image <prompt> [OPTIONS]
|
|||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik generate-image "a cat on the moon, oil painting style"
|
magnific generate-image "a cat on the moon, oil painting style"
|
||||||
freepik generate-image "cyberpunk city at night" --model mystic --aspect-ratio 16:9
|
magnific generate-image "cyberpunk city at night" --model mystic --aspect-ratio 16:9
|
||||||
freepik generate-image "make the sky orange at sunset" --model flux-kontext-pro --input-image photo.jpg
|
magnific generate-image "make the sky orange at sunset" --model flux-kontext-pro --input-image photo.jpg
|
||||||
freepik generate-image "portrait of a wizard" --seed 42 --output wizard.jpg
|
magnific generate-image "portrait of a wizard" --seed 42 --output wizard.jpg
|
||||||
freepik generate-image "vast ocean panorama" --model flux-2-pro --no-wait
|
magnific generate-image "vast ocean panorama" --model flux-2-pro --no-wait
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -117,7 +117,7 @@ freepik generate-image "vast ocean panorama" --model flux-2-pro --no-wait
|
|||||||
Animate a source image into a short video clip.
|
Animate a source image into a short video clip.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik generate-video <image> [OPTIONS]
|
magnific generate-video <image> [OPTIONS]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Short | Default | Description |
|
| Option | Short | Default | Description |
|
||||||
@@ -129,7 +129,7 @@ freepik generate-video <image> [OPTIONS]
|
|||||||
| `--seed` | | — | Seed for reproducibility |
|
| `--seed` | | — | Seed for reproducibility |
|
||||||
| `--output` | `-o` | auto | Output `.mp4` path |
|
| `--output` | `-o` | auto | Output `.mp4` path |
|
||||||
| `--wait / --no-wait` | | `--wait` | |
|
| `--wait / --no-wait` | | `--wait` | |
|
||||||
| `--api-key` | | `$FREEPIK_API_KEY` | |
|
| `--api-key` | | `$MAGNIFIC_API_KEY` | |
|
||||||
|
|
||||||
**Available models:**
|
**Available models:**
|
||||||
|
|
||||||
@@ -146,9 +146,9 @@ freepik generate-video <image> [OPTIONS]
|
|||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik generate-video photo.jpg --prompt "gentle ocean waves lapping at the shore"
|
magnific generate-video photo.jpg --prompt "gentle ocean waves lapping at the shore"
|
||||||
freepik generate-video portrait.png --model minimax-hailuo --duration 10 --aspect-ratio 9:16
|
magnific generate-video portrait.png --model minimax-hailuo --duration 10 --aspect-ratio 9:16
|
||||||
freepik generate-video landscape.jpg --model kling-o1-pro --output timelapse.mp4
|
magnific generate-video landscape.jpg --model kling-o1-pro --output timelapse.mp4
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -158,7 +158,7 @@ freepik generate-video landscape.jpg --model kling-o1-pro --output timelapse.mp4
|
|||||||
Upscale and enhance an image using AI.
|
Upscale and enhance an image using AI.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik upscale-image <image> [OPTIONS]
|
magnific upscale-image <image> [OPTIONS]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Short | Default | Description |
|
| Option | Short | Default | Description |
|
||||||
@@ -170,7 +170,7 @@ freepik upscale-image <image> [OPTIONS]
|
|||||||
| `--seed` | | — | Seed for reproducibility |
|
| `--seed` | | — | Seed for reproducibility |
|
||||||
| `--output` | `-o` | auto | Output file path |
|
| `--output` | `-o` | auto | Output file path |
|
||||||
| `--wait / --no-wait` | | `--wait` | |
|
| `--wait / --no-wait` | | `--wait` | |
|
||||||
| `--api-key` | | `$FREEPIK_API_KEY` | |
|
| `--api-key` | | `$MAGNIFIC_API_KEY` | |
|
||||||
|
|
||||||
**Modes:**
|
**Modes:**
|
||||||
|
|
||||||
@@ -183,9 +183,9 @@ freepik upscale-image <image> [OPTIONS]
|
|||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik upscale-image photo.jpg --scale 4x
|
magnific upscale-image photo.jpg --scale 4x
|
||||||
freepik upscale-image photo.jpg --mode precision-v2 --scale 2x --output photo_hd.jpg
|
magnific upscale-image photo.jpg --mode precision-v2 --scale 2x --output photo_hd.jpg
|
||||||
freepik upscale-image portrait.jpg --mode creative --creativity 6 --prompt "sharp cinematic texture"
|
magnific upscale-image portrait.jpg --mode creative --creativity 6 --prompt "sharp cinematic texture"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -195,7 +195,7 @@ freepik upscale-image portrait.jpg --mode creative --creativity 6 --prompt "shar
|
|||||||
Upscale a video to higher resolution using AI.
|
Upscale a video to higher resolution using AI.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik upscale-video <video> [OPTIONS]
|
magnific upscale-video <video> [OPTIONS]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Short | Default | Description |
|
| Option | Short | Default | Description |
|
||||||
@@ -203,13 +203,13 @@ freepik upscale-video <video> [OPTIONS]
|
|||||||
| `--mode` | | `standard` | `standard` \| `turbo` (faster) |
|
| `--mode` | | `standard` | `standard` \| `turbo` (faster) |
|
||||||
| `--output` | `-o` | auto | Output `.mp4` path |
|
| `--output` | `-o` | auto | Output `.mp4` path |
|
||||||
| `--wait / --no-wait` | | `--wait` | |
|
| `--wait / --no-wait` | | `--wait` | |
|
||||||
| `--api-key` | | `$FREEPIK_API_KEY` | |
|
| `--api-key` | | `$MAGNIFIC_API_KEY` | |
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik upscale-video clip.mp4
|
magnific upscale-video clip.mp4
|
||||||
freepik upscale-video clip.mp4 --mode turbo --output clip_4k.mp4
|
magnific upscale-video clip.mp4 --mode turbo --output clip_4k.mp4
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -219,7 +219,7 @@ freepik upscale-video clip.mp4 --mode turbo --output clip_4k.mp4
|
|||||||
Generate an icon from a text prompt in various styles.
|
Generate an icon from a text prompt in various styles.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik generate-icon <prompt> [OPTIONS]
|
magnific generate-icon <prompt> [OPTIONS]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Short | Default | Description |
|
| Option | Short | Default | Description |
|
||||||
@@ -234,9 +234,9 @@ freepik generate-icon <prompt> [OPTIONS]
|
|||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik generate-icon "shopping cart" --style solid --format svg
|
magnific generate-icon "shopping cart" --style solid --format svg
|
||||||
freepik generate-icon "rocket ship" --style color --format png
|
magnific generate-icon "rocket ship" --style color --format png
|
||||||
freepik generate-icon "leaf" --style outline --format svg --output leaf.svg
|
magnific generate-icon "leaf" --style outline --format svg --output leaf.svg
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -246,7 +246,7 @@ freepik generate-icon "leaf" --style outline --format svg --output leaf.svg
|
|||||||
Expand an image by generating new content around its edges (outpainting).
|
Expand an image by generating new content around its edges (outpainting).
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik expand-image <image> [OPTIONS]
|
magnific expand-image <image> [OPTIONS]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Default | Description |
|
| Option | Default | Description |
|
||||||
@@ -263,9 +263,9 @@ freepik expand-image <image> [OPTIONS]
|
|||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik expand-image photo.jpg --left 512 --right 512 --prompt "lush green forest"
|
magnific expand-image photo.jpg --left 512 --right 512 --prompt "lush green forest"
|
||||||
freepik expand-image banner.png --bottom 256 --model seedream-v4-5
|
magnific expand-image banner.png --bottom 256 --model seedream-v4-5
|
||||||
freepik expand-image portrait.jpg --top 300 --bottom 300 --prompt "studio backdrop"
|
magnific expand-image portrait.jpg --top 300 --bottom 300 --prompt "studio backdrop"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -275,7 +275,7 @@ freepik expand-image portrait.jpg --top 300 --bottom 300 --prompt "studio backdr
|
|||||||
Analyze an image and generate a descriptive text prompt for it — useful for reverse-engineering AI images or building prompt libraries.
|
Analyze an image and generate a descriptive text prompt for it — useful for reverse-engineering AI images or building prompt libraries.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik describe-image <image> [OPTIONS]
|
magnific describe-image <image> [OPTIONS]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Short | Description |
|
| Option | Short | Description |
|
||||||
@@ -287,8 +287,8 @@ freepik describe-image <image> [OPTIONS]
|
|||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik describe-image painting.jpg
|
magnific describe-image painting.jpg
|
||||||
freepik describe-image scene.png --output scene_prompt.txt
|
magnific describe-image scene.png --output scene_prompt.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -298,7 +298,7 @@ freepik describe-image scene.png --output scene_prompt.txt
|
|||||||
Relight an image using AI-controlled lighting.
|
Relight an image using AI-controlled lighting.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik relight <image> [OPTIONS]
|
magnific relight <image> [OPTIONS]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Short | Description |
|
| Option | Short | Description |
|
||||||
@@ -310,8 +310,8 @@ freepik relight <image> [OPTIONS]
|
|||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik relight portrait.jpg --prompt "warm golden hour sunlight from the left"
|
magnific relight portrait.jpg --prompt "warm golden hour sunlight from the left"
|
||||||
freepik relight product.png --prompt "soft studio lighting, white background"
|
magnific relight product.png --prompt "soft studio lighting, white background"
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -321,7 +321,7 @@ freepik relight product.png --prompt "soft studio lighting, white background"
|
|||||||
Apply the artistic style from one image onto the content of another.
|
Apply the artistic style from one image onto the content of another.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik style-transfer <content-image> <style-image> [OPTIONS]
|
magnific style-transfer <content-image> <style-image> [OPTIONS]
|
||||||
```
|
```
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
@@ -332,23 +332,23 @@ freepik style-transfer <content-image> <style-image> [OPTIONS]
|
|||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik style-transfer photo.jpg van_gogh.jpg
|
magnific style-transfer photo.jpg van_gogh.jpg
|
||||||
freepik style-transfer portrait.png impressionist.jpg --strength 0.75 --output styled.jpg
|
magnific style-transfer portrait.png impressionist.jpg --strength 0.75 --output styled.jpg
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `config`
|
### `config`
|
||||||
|
|
||||||
Manage CLI configuration stored at `~/.config/freepik-cli/config.toml`.
|
Manage CLI configuration stored at `~/.config/magnific-cli/config.toml`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik config show # Display all settings (as a table)
|
magnific config show # Display all settings (as a table)
|
||||||
freepik config show --toml # Display as highlighted TOML
|
magnific config show --toml # Display as highlighted TOML
|
||||||
freepik config get <key> # Print a single value
|
magnific config get <key> # Print a single value
|
||||||
freepik config set <key> <value> # Update a setting
|
magnific config set <key> <value> # Update a setting
|
||||||
freepik config reset # Reset to defaults
|
magnific config reset # Reset to defaults
|
||||||
freepik config path # Print the config file path
|
magnific config path # Print the config file path
|
||||||
```
|
```
|
||||||
|
|
||||||
**Configurable keys:**
|
**Configurable keys:**
|
||||||
@@ -359,20 +359,20 @@ freepik config path # Print the config file path
|
|||||||
| `default_video_model` | `kling-o1-pro` | Default model for `generate-video` |
|
| `default_video_model` | `kling-o1-pro` | Default model for `generate-video` |
|
||||||
| `default_upscale_mode` | `precision-v2` | Default mode for `upscale-image` |
|
| `default_upscale_mode` | `precision-v2` | Default mode for `upscale-image` |
|
||||||
| `default_output_dir` | `.` | Directory for auto-generated output files |
|
| `default_output_dir` | `.` | Directory for auto-generated output files |
|
||||||
| `base_url` | `https://api.freepik.com` | API base URL |
|
| `base_url` | `https://api.magnific.ai` | API base URL |
|
||||||
| `poll_timeout` | `600` | Max seconds to wait for task completion |
|
| `poll_timeout` | `600` | Max seconds to wait for task completion |
|
||||||
| `poll_max_interval` | `15` | Max seconds between polling attempts |
|
| `poll_max_interval` | `15` | Max seconds between polling attempts |
|
||||||
| `show_banner` | `true` | Show the ASCII art banner |
|
| `show_banner` | `true` | Show the ASCII art banner |
|
||||||
|
|
||||||
> **Note:** The API key is never saved to the config file. Use `FREEPIK_API_KEY` or `--api-key`.
|
> **Note:** The API key is never saved to the config file. Use `MAGNIFIC_API_KEY` or `--api-key`.
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik config set default_image_model mystic
|
magnific config set default_image_model mystic
|
||||||
freepik config set default_output_dir ~/Pictures/freepik
|
magnific config set default_output_dir ~/Pictures/magnific
|
||||||
freepik config set show_banner false
|
magnific config set show_banner false
|
||||||
freepik config set poll_timeout 300
|
magnific config set poll_timeout 300
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
@@ -380,36 +380,36 @@ freepik config set poll_timeout 300
|
|||||||
Settings are resolved in this priority order (highest wins):
|
Settings are resolved in this priority order (highest wins):
|
||||||
|
|
||||||
1. `--api-key` / `--model` / etc. command-line flags
|
1. `--api-key` / `--model` / etc. command-line flags
|
||||||
2. `FREEPIK_*` environment variables (e.g. `FREEPIK_API_KEY`)
|
2. `MAGNIFIC_*` environment variables (e.g. `MAGNIFIC_API_KEY`)
|
||||||
3. `~/.config/freepik-cli/config.toml`
|
3. `~/.config/magnific-cli/config.toml`
|
||||||
4. Built-in defaults
|
4. Built-in defaults
|
||||||
|
|
||||||
### Environment Variables
|
### Environment Variables
|
||||||
|
|
||||||
| Variable | Description |
|
| Variable | Description |
|
||||||
|----------|-------------|
|
|----------|-------------|
|
||||||
| `FREEPIK_API_KEY` | Your Freepik API key **(required)** |
|
| `MAGNIFIC_API_KEY` | Your Magnific API key **(required)** |
|
||||||
| `FREEPIK_BASE_URL` | API base URL override |
|
| `MAGNIFIC_BASE_URL` | API base URL override |
|
||||||
| `FREEPIK_DEFAULT_IMAGE_MODEL` | Default image model |
|
| `MAGNIFIC_DEFAULT_IMAGE_MODEL` | Default image model |
|
||||||
| `FREEPIK_DEFAULT_VIDEO_MODEL` | Default video model |
|
| `MAGNIFIC_DEFAULT_VIDEO_MODEL` | Default video model |
|
||||||
| `FREEPIK_DEFAULT_OUTPUT_DIR` | Default output directory |
|
| `MAGNIFIC_DEFAULT_OUTPUT_DIR` | Default output directory |
|
||||||
| `FREEPIK_POLL_TIMEOUT` | Task polling timeout in seconds |
|
| `MAGNIFIC_POLL_TIMEOUT` | Task polling timeout in seconds |
|
||||||
| `FREEPIK_SHOW_BANNER` | Show/hide the ASCII banner (`true`/`false`) |
|
| `MAGNIFIC_SHOW_BANNER` | Show/hide the ASCII banner (`true`/`false`) |
|
||||||
|
|
||||||
## Output Files
|
## Output Files
|
||||||
|
|
||||||
When no `--output` path is provided, files are saved with an auto-generated name:
|
When no `--output` path is provided, files are saved with an auto-generated name:
|
||||||
|
|
||||||
```
|
```
|
||||||
freepik_image_flux-2-pro_20260408_143022.jpg
|
magnific_image_flux-2-pro_20260408_143022.jpg
|
||||||
freepik_video_kling-o1-pro_20260408_143512.mp4
|
magnific_video_kling-o1-pro_20260408_143512.mp4
|
||||||
freepik_upscaled_precision-v2_20260408_144001.jpg
|
magnific_upscaled_precision-v2_20260408_144001.jpg
|
||||||
```
|
```
|
||||||
|
|
||||||
The default output directory is the current working directory. Change it with:
|
The default output directory is the current working directory. Change it with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik config set default_output_dir ~/Pictures/freepik
|
magnific config set default_output_dir ~/Pictures/magnific
|
||||||
```
|
```
|
||||||
|
|
||||||
## Async Workflows (`--no-wait`)
|
## Async Workflows (`--no-wait`)
|
||||||
@@ -418,7 +418,7 @@ Every command supports `--no-wait` to submit a task and return immediately witho
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Submit and get task ID instantly
|
# Submit and get task ID instantly
|
||||||
freepik generate-image "a nebula" --model mystic --no-wait
|
magnific generate-image "a nebula" --model mystic --no-wait
|
||||||
|
|
||||||
# Task Queued
|
# Task Queued
|
||||||
# Task ID: c3f2a1b8-...
|
# Task ID: c3f2a1b8-...
|
||||||
@@ -433,7 +433,7 @@ This is useful for batching multiple requests or integrating with scripts.
|
|||||||
Install tab-completion for your shell:
|
Install tab-completion for your shell:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
freepik --install-completion # auto-detects your shell
|
magnific --install-completion # auto-detects your shell
|
||||||
```
|
```
|
||||||
|
|
||||||
Supports bash, zsh, fish, and PowerShell.
|
Supports bash, zsh, fish, and PowerShell.
|
||||||
@@ -441,10 +441,10 @@ Supports bash, zsh, fish, and PowerShell.
|
|||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
freepik/
|
magnific/
|
||||||
├── pyproject.toml
|
├── pyproject.toml
|
||||||
├── .env.example
|
├── .env.example
|
||||||
├── freepik_cli/
|
├── magnific_cli/
|
||||||
│ ├── main.py # CLI entry point
|
│ ├── main.py # CLI entry point
|
||||||
│ ├── api/
|
│ ├── api/
|
||||||
│ │ ├── client.py # HTTP client (httpx)
|
│ │ ├── client.py # HTTP client (httpx)
|
||||||
@@ -461,7 +461,7 @@ freepik/
|
|||||||
│ │ └── config.py # config management
|
│ │ └── config.py # config management
|
||||||
│ └── utils/
|
│ └── utils/
|
||||||
│ ├── console.py # Rich console, theme, display helpers
|
│ ├── console.py # Rich console, theme, display helpers
|
||||||
│ ├── config.py # FreepikConfig (pydantic-settings)
|
│ ├── config.py # MagnificConfig (pydantic-settings)
|
||||||
│ ├── polling.py # Live polling with Rich
|
│ ├── polling.py # Live polling with Rich
|
||||||
│ └── files.py # Base64 encoding, download, path utils
|
│ └── files.py # Base64 encoding, download, path utils
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
"""Freepik AI CLI — generate images, videos, and more."""
|
|
||||||
|
|
||||||
__version__ = "0.1.0"
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""Magnific AI CLI — generate images, videos, and more."""
|
||||||
|
|
||||||
|
__version__ = "0.1.0"
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
"""Freepik HTTP client with authentication, error handling, and download support."""
|
"""Magnific HTTP client with authentication, error handling, and download support."""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
@@ -6,14 +6,14 @@ from typing import Any, Optional
|
|||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
from freepik_cli import __version__
|
from magnific_cli import __version__
|
||||||
|
|
||||||
BASE_URL = "https://api.freepik.com"
|
BASE_URL = "https://api.magnific.ai"
|
||||||
DEFAULT_TIMEOUT = 60.0
|
DEFAULT_TIMEOUT = 60.0
|
||||||
|
|
||||||
|
|
||||||
class FreepikAPIError(Exception):
|
class MagnificAPIError(Exception):
|
||||||
"""Raised when the Freepik API returns an error response."""
|
"""Raised when the Magnific API returns an error response."""
|
||||||
|
|
||||||
def __init__(self, message: str, status_code: Optional[int] = None, raw: Optional[dict] = None):
|
def __init__(self, message: str, status_code: Optional[int] = None, raw: Optional[dict] = None):
|
||||||
super().__init__(message)
|
super().__init__(message)
|
||||||
@@ -21,7 +21,7 @@ class FreepikAPIError(Exception):
|
|||||||
self.raw = raw or {}
|
self.raw = raw or {}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_response(cls, response: httpx.Response) -> "FreepikAPIError":
|
def from_response(cls, response: httpx.Response) -> "MagnificAPIError":
|
||||||
try:
|
try:
|
||||||
body = response.json()
|
body = response.json()
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -43,8 +43,8 @@ class FreepikAPIError(Exception):
|
|||||||
message = f"{message}\n\n{details}"
|
message = f"{message}\n\n{details}"
|
||||||
|
|
||||||
hints = {
|
hints = {
|
||||||
401: "Check your API key — set FREEPIK_API_KEY or use --api-key.",
|
401: "Check your API key — set MAGNIFIC_API_KEY or use --api-key.",
|
||||||
403: "Your plan may not support this feature. Check your Freepik subscription.",
|
403: "Your plan may not support this feature. Check your Magnific subscription.",
|
||||||
429: "Rate limit exceeded. Please wait before retrying.",
|
429: "Rate limit exceeded. Please wait before retrying.",
|
||||||
}
|
}
|
||||||
hint = hints.get(response.status_code)
|
hint = hints.get(response.status_code)
|
||||||
@@ -54,8 +54,8 @@ class FreepikAPIError(Exception):
|
|||||||
return cls(message, status_code=response.status_code, raw=body)
|
return cls(message, status_code=response.status_code, raw=body)
|
||||||
|
|
||||||
|
|
||||||
class FreepikClient:
|
class MagnificClient:
|
||||||
"""Thin synchronous HTTP wrapper around the Freepik API."""
|
"""Thin synchronous HTTP wrapper around the Magnific API."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -66,10 +66,10 @@ class FreepikClient:
|
|||||||
self._client = httpx.Client(
|
self._client = httpx.Client(
|
||||||
base_url=base_url,
|
base_url=base_url,
|
||||||
headers={
|
headers={
|
||||||
"x-freepik-api-key": api_key,
|
"x-magnific-api-key": api_key,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"Accept": "application/json",
|
"Accept": "application/json",
|
||||||
"User-Agent": f"freepik-cli/{__version__}",
|
"User-Agent": f"magnific-cli/{__version__}",
|
||||||
},
|
},
|
||||||
timeout=httpx.Timeout(timeout),
|
timeout=httpx.Timeout(timeout),
|
||||||
)
|
)
|
||||||
@@ -80,9 +80,9 @@ class FreepikClient:
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json()
|
return response.json()
|
||||||
except httpx.HTTPStatusError as exc:
|
except httpx.HTTPStatusError as exc:
|
||||||
raise FreepikAPIError.from_response(exc.response) from exc
|
raise MagnificAPIError.from_response(exc.response) from exc
|
||||||
except httpx.RequestError as exc:
|
except httpx.RequestError as exc:
|
||||||
raise FreepikAPIError(f"Network error: {exc}") from exc
|
raise MagnificAPIError(f"Network error: {exc}") from exc
|
||||||
|
|
||||||
def post_multipart(self, path: str, data: dict[str, Any], files: dict[str, Any]) -> dict[str, Any]:
|
def post_multipart(self, path: str, data: dict[str, Any], files: dict[str, Any]) -> dict[str, Any]:
|
||||||
"""POST with multipart/form-data (for file uploads)."""
|
"""POST with multipart/form-data (for file uploads)."""
|
||||||
@@ -92,9 +92,9 @@ class FreepikClient:
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json()
|
return response.json()
|
||||||
except httpx.HTTPStatusError as exc:
|
except httpx.HTTPStatusError as exc:
|
||||||
raise FreepikAPIError.from_response(exc.response) from exc
|
raise MagnificAPIError.from_response(exc.response) from exc
|
||||||
except httpx.RequestError as exc:
|
except httpx.RequestError as exc:
|
||||||
raise FreepikAPIError(f"Network error: {exc}") from exc
|
raise MagnificAPIError(f"Network error: {exc}") from exc
|
||||||
|
|
||||||
def get(self, path: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
|
def get(self, path: str, params: dict[str, Any] | None = None) -> dict[str, Any]:
|
||||||
try:
|
try:
|
||||||
@@ -102,11 +102,11 @@ class FreepikClient:
|
|||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json()
|
return response.json()
|
||||||
except httpx.HTTPStatusError as exc:
|
except httpx.HTTPStatusError as exc:
|
||||||
raise FreepikAPIError.from_response(exc.response) from exc
|
raise MagnificAPIError.from_response(exc.response) from exc
|
||||||
except httpx.RequestError as exc:
|
except httpx.RequestError as exc:
|
||||||
raise FreepikAPIError(f"Network error: {exc}") from exc
|
raise MagnificAPIError(f"Network error: {exc}") from exc
|
||||||
|
|
||||||
def __enter__(self) -> "FreepikClient":
|
def __enter__(self) -> "MagnificClient":
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __exit__(self, *args: Any) -> None:
|
def __exit__(self, *args: Any) -> None:
|
||||||
@@ -4,12 +4,12 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Any, Optional, Tuple
|
from typing import Any, Optional, Tuple
|
||||||
|
|
||||||
from freepik_cli.api.client import FreepikClient
|
from magnific_cli.api.client import MagnificClient
|
||||||
from freepik_cli.api.models import IconStyle, get_output_urls, get_status, get_task_id
|
from magnific_cli.api.models import IconStyle, get_output_urls, get_status, get_task_id
|
||||||
|
|
||||||
|
|
||||||
class EditAPI:
|
class EditAPI:
|
||||||
def __init__(self, client: FreepikClient) -> None:
|
def __init__(self, client: MagnificClient) -> None:
|
||||||
self._client = client
|
self._client = client
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -4,8 +4,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Any, Optional, Tuple
|
from typing import Any, Optional, Tuple
|
||||||
|
|
||||||
from freepik_cli.api.client import FreepikClient
|
from magnific_cli.api.client import MagnificClient
|
||||||
from freepik_cli.api.models import (
|
from magnific_cli.api.models import (
|
||||||
IMAGE_POST_ENDPOINTS,
|
IMAGE_POST_ENDPOINTS,
|
||||||
IMAGE_STATUS_ENDPOINTS,
|
IMAGE_STATUS_ENDPOINTS,
|
||||||
ImageModel,
|
ImageModel,
|
||||||
@@ -16,7 +16,7 @@ from freepik_cli.api.models import (
|
|||||||
|
|
||||||
|
|
||||||
class ImageAPI:
|
class ImageAPI:
|
||||||
def __init__(self, client: FreepikClient) -> None:
|
def __init__(self, client: MagnificClient) -> None:
|
||||||
self._client = client
|
self._client = client
|
||||||
|
|
||||||
def generate(self, model: ImageModel, payload: dict[str, Any]) -> str:
|
def generate(self, model: ImageModel, payload: dict[str, Any]) -> str:
|
||||||
@@ -4,8 +4,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Any, Optional, Tuple
|
from typing import Any, Optional, Tuple
|
||||||
|
|
||||||
from freepik_cli.api.client import FreepikClient
|
from magnific_cli.api.client import MagnificClient
|
||||||
from freepik_cli.api.models import (
|
from magnific_cli.api.models import (
|
||||||
UPSCALE_POST_ENDPOINTS,
|
UPSCALE_POST_ENDPOINTS,
|
||||||
UPSCALE_STATUS_ENDPOINTS,
|
UPSCALE_STATUS_ENDPOINTS,
|
||||||
VIDEO_UPSCALE_POST_ENDPOINTS,
|
VIDEO_UPSCALE_POST_ENDPOINTS,
|
||||||
@@ -19,7 +19,7 @@ from freepik_cli.api.models import (
|
|||||||
|
|
||||||
|
|
||||||
class UpscaleAPI:
|
class UpscaleAPI:
|
||||||
def __init__(self, client: FreepikClient) -> None:
|
def __init__(self, client: MagnificClient) -> None:
|
||||||
self._client = client
|
self._client = client
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -4,8 +4,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from typing import Any, Optional, Tuple
|
from typing import Any, Optional, Tuple
|
||||||
|
|
||||||
from freepik_cli.api.client import FreepikClient
|
from magnific_cli.api.client import MagnificClient
|
||||||
from freepik_cli.api.models import (
|
from magnific_cli.api.models import (
|
||||||
VIDEO_POST_ENDPOINTS,
|
VIDEO_POST_ENDPOINTS,
|
||||||
VIDEO_STATUS_ENDPOINTS,
|
VIDEO_STATUS_ENDPOINTS,
|
||||||
VIDEO_IMAGE_FIELDS,
|
VIDEO_IMAGE_FIELDS,
|
||||||
@@ -19,7 +19,7 @@ from freepik_cli.api.models import (
|
|||||||
|
|
||||||
|
|
||||||
class VideoAPI:
|
class VideoAPI:
|
||||||
def __init__(self, client: FreepikClient) -> None:
|
def __init__(self, client: MagnificClient) -> None:
|
||||||
self._client = client
|
self._client = client
|
||||||
|
|
||||||
def generate(
|
def generate(
|
||||||
@@ -7,18 +7,18 @@ from typing import Annotated, Optional
|
|||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
from freepik_cli.api.client import FreepikAPIError, FreepikClient
|
from magnific_cli.api.client import MagnificAPIError, MagnificClient
|
||||||
from freepik_cli.api.images import ImageAPI
|
from magnific_cli.api.images import ImageAPI
|
||||||
from freepik_cli.utils.config import FreepikConfig
|
from magnific_cli.utils.config import MagnificConfig
|
||||||
from freepik_cli.utils.console import console, print_describe_result, print_error, print_no_wait
|
from magnific_cli.utils.console import console, print_describe_result, print_error, print_no_wait
|
||||||
from freepik_cli.utils.files import image_to_base64
|
from magnific_cli.utils.files import image_to_base64
|
||||||
from freepik_cli.utils.polling import FreepikTaskError, FreepikTimeoutError, PollConfig, poll_task
|
from magnific_cli.utils.polling import MagnificTaskError, MagnificTimeoutError, PollConfig, poll_task
|
||||||
|
|
||||||
|
|
||||||
def _get_api_key(api_key: Optional[str], config: FreepikConfig) -> str:
|
def _get_api_key(api_key: Optional[str], config: MagnificConfig) -> str:
|
||||||
key = api_key or config.api_key
|
key = api_key or config.api_key
|
||||||
if not key:
|
if not key:
|
||||||
print_error("No API key found.", hint="Set [cyan]FREEPIK_API_KEY[/cyan] or pass [cyan]--api-key[/cyan].")
|
print_error("No API key found.", hint="Set [cyan]MAGNIFIC_API_KEY[/cyan] or pass [cyan]--api-key[/cyan].")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
return key
|
return key
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ def describe_image(
|
|||||||
] = True,
|
] = True,
|
||||||
api_key: Annotated[
|
api_key: Annotated[
|
||||||
Optional[str],
|
Optional[str],
|
||||||
typer.Option("--api-key", envvar="FREEPIK_API_KEY"),
|
typer.Option("--api-key", envvar="MAGNIFIC_API_KEY"),
|
||||||
] = None,
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -51,20 +51,20 @@ def describe_image(
|
|||||||
[cyan]generate-image[/cyan].
|
[cyan]generate-image[/cyan].
|
||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik describe-image photo.jpg
|
magnific describe-image photo.jpg
|
||||||
freepik describe-image scene.png --output prompt.txt
|
magnific describe-image scene.png --output prompt.txt
|
||||||
"""
|
"""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
key = _get_api_key(api_key, config)
|
key = _get_api_key(api_key, config)
|
||||||
image_b64 = image_to_base64(image)
|
image_b64 = image_to_base64(image)
|
||||||
|
|
||||||
with FreepikClient(key, base_url=config.base_url) as client:
|
with MagnificClient(key, base_url=config.base_url) as client:
|
||||||
api = ImageAPI(client)
|
api = ImageAPI(client)
|
||||||
|
|
||||||
with console.status("[info]Submitting image analysis…[/info]"):
|
with console.status("[info]Submitting image analysis…[/info]"):
|
||||||
try:
|
try:
|
||||||
task_id = api.describe_submit(image_b64)
|
task_id = api.describe_submit(image_b64)
|
||||||
except FreepikAPIError as exc:
|
except MagnificAPIError as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ def describe_image(
|
|||||||
config=poll_config,
|
config=poll_config,
|
||||||
console=console,
|
console=console,
|
||||||
)
|
)
|
||||||
except (FreepikTaskError, FreepikTimeoutError) as exc:
|
except (MagnificTaskError, MagnificTimeoutError) as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -7,12 +7,12 @@ from typing import Annotated, Optional
|
|||||||
import typer
|
import typer
|
||||||
from rich.prompt import Confirm
|
from rich.prompt import Confirm
|
||||||
|
|
||||||
from freepik_cli.utils.config import CONFIG_FILE, FreepikConfig
|
from magnific_cli.utils.config import CONFIG_FILE, MagnificConfig
|
||||||
from freepik_cli.utils.console import console, print_config_table, print_config_toml, print_error, print_warning
|
from magnific_cli.utils.console import console, print_config_table, print_config_toml, print_error, print_warning
|
||||||
|
|
||||||
app = typer.Typer(
|
app = typer.Typer(
|
||||||
name="config",
|
name="config",
|
||||||
help="[bold]Manage[/bold] Freepik CLI configuration.",
|
help="[bold]Manage[/bold] Magnific CLI configuration.",
|
||||||
rich_markup_mode="rich",
|
rich_markup_mode="rich",
|
||||||
no_args_is_help=True,
|
no_args_is_help=True,
|
||||||
)
|
)
|
||||||
@@ -26,7 +26,7 @@ def config_show(
|
|||||||
] = False,
|
] = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""[bold]Show[/bold] all current configuration values."""
|
"""[bold]Show[/bold] all current configuration values."""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
d = config.to_display_dict()
|
d = config.to_display_dict()
|
||||||
if toml:
|
if toml:
|
||||||
print_config_toml(d)
|
print_config_toml(d)
|
||||||
@@ -40,12 +40,12 @@ def config_get(
|
|||||||
key: Annotated[str, typer.Argument(help="Config key to retrieve")],
|
key: Annotated[str, typer.Argument(help="Config key to retrieve")],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""[bold]Get[/bold] the value of a single configuration key."""
|
"""[bold]Get[/bold] the value of a single configuration key."""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
d = config.to_display_dict()
|
d = config.to_display_dict()
|
||||||
if key not in d:
|
if key not in d:
|
||||||
print_error(
|
print_error(
|
||||||
f"Unknown config key: '{key}'",
|
f"Unknown config key: '{key}'",
|
||||||
hint=f"Run [cyan]freepik config show[/cyan] to see all available keys.",
|
hint=f"Run [cyan]magnific config show[/cyan] to see all available keys.",
|
||||||
)
|
)
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -68,14 +68,14 @@ def config_set(
|
|||||||
[bold]Set[/bold] a configuration value.
|
[bold]Set[/bold] a configuration value.
|
||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik config set default_image_model mystic
|
magnific config set default_image_model mystic
|
||||||
freepik config set default_output_dir ~/images
|
magnific config set default_output_dir ~/images
|
||||||
freepik config set poll_timeout 300
|
magnific config set poll_timeout 300
|
||||||
|
|
||||||
[dim]Note:[/dim] The API key is never saved to disk. Use the
|
[dim]Note:[/dim] The API key is never saved to disk. Use the
|
||||||
[cyan]FREEPIK_API_KEY[/cyan] environment variable instead.
|
[cyan]MAGNIFIC_API_KEY[/cyan] environment variable instead.
|
||||||
"""
|
"""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
try:
|
try:
|
||||||
config.set_value(key, value)
|
config.set_value(key, value)
|
||||||
console.print(f"[success]✓[/success] Set [cyan]{key}[/cyan] = [bold]{value}[/bold]")
|
console.print(f"[success]✓[/success] Set [cyan]{key}[/cyan] = [bold]{value}[/bold]")
|
||||||
@@ -7,20 +7,20 @@ from typing import Annotated, Optional
|
|||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
from freepik_cli.api.client import FreepikAPIError, FreepikClient
|
from magnific_cli.api.client import MagnificAPIError, MagnificClient
|
||||||
from freepik_cli.api.edit import EditAPI
|
from magnific_cli.api.edit import EditAPI
|
||||||
from freepik_cli.utils.config import FreepikConfig
|
from magnific_cli.utils.config import MagnificConfig
|
||||||
from freepik_cli.utils.console import GenerationResult, console, print_error, print_no_wait, print_result
|
from magnific_cli.utils.console import GenerationResult, console, print_error, print_no_wait, print_result
|
||||||
from freepik_cli.utils.files import auto_output_path, get_image_dimensions, image_to_base64, save_from_url
|
from magnific_cli.utils.files import auto_output_path, get_image_dimensions, image_to_base64, save_from_url
|
||||||
from freepik_cli.utils.polling import FreepikTaskError, FreepikTimeoutError, PollConfig, poll_task
|
from magnific_cli.utils.polling import MagnificTaskError, MagnificTimeoutError, PollConfig, poll_task
|
||||||
|
|
||||||
_EXPAND_MODELS = ["flux-pro", "ideogram", "seedream-v4-5"]
|
_EXPAND_MODELS = ["flux-pro", "ideogram", "seedream-v4-5"]
|
||||||
|
|
||||||
|
|
||||||
def _get_api_key(api_key: Optional[str], config: FreepikConfig) -> str:
|
def _get_api_key(api_key: Optional[str], config: MagnificConfig) -> str:
|
||||||
key = api_key or config.api_key
|
key = api_key or config.api_key
|
||||||
if not key:
|
if not key:
|
||||||
print_error("No API key found.", hint="Set [cyan]FREEPIK_API_KEY[/cyan] or pass [cyan]--api-key[/cyan].")
|
print_error("No API key found.", hint="Set [cyan]MAGNIFIC_API_KEY[/cyan] or pass [cyan]--api-key[/cyan].")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
return key
|
return key
|
||||||
|
|
||||||
@@ -39,14 +39,14 @@ def expand_image(
|
|||||||
seed: Annotated[Optional[int], typer.Option("--seed")] = None,
|
seed: Annotated[Optional[int], typer.Option("--seed")] = None,
|
||||||
output: Annotated[Optional[Path], typer.Option("--output", "-o")] = None,
|
output: Annotated[Optional[Path], typer.Option("--output", "-o")] = None,
|
||||||
wait: Annotated[bool, typer.Option("--wait/--no-wait")] = True,
|
wait: Annotated[bool, typer.Option("--wait/--no-wait")] = True,
|
||||||
api_key: Annotated[Optional[str], typer.Option("--api-key", envvar="FREEPIK_API_KEY")] = None,
|
api_key: Annotated[Optional[str], typer.Option("--api-key", envvar="MAGNIFIC_API_KEY")] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
[bold]Expand an image[/bold] by adding new content around its edges (outpainting).
|
[bold]Expand an image[/bold] by adding new content around its edges (outpainting).
|
||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik expand-image photo.jpg --left 512 --right 512 --prompt "lush forest"
|
magnific expand-image photo.jpg --left 512 --right 512 --prompt "lush forest"
|
||||||
freepik expand-image banner.png --bottom 256 --model seedream-v4-5
|
magnific expand-image banner.png --bottom 256 --model seedream-v4-5
|
||||||
"""
|
"""
|
||||||
if not any([left, right, top, bottom]):
|
if not any([left, right, top, bottom]):
|
||||||
print_error("At least one of --left, --right, --top, --bottom must be > 0.")
|
print_error("At least one of --left, --right, --top, --bottom must be > 0.")
|
||||||
@@ -56,17 +56,17 @@ def expand_image(
|
|||||||
print_error(f"Unknown model '{model}'.", hint=f"Choose from: {', '.join(_EXPAND_MODELS)}")
|
print_error(f"Unknown model '{model}'.", hint=f"Choose from: {', '.join(_EXPAND_MODELS)}")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
key = _get_api_key(api_key, config)
|
key = _get_api_key(api_key, config)
|
||||||
image_b64 = image_to_base64(image)
|
image_b64 = image_to_base64(image)
|
||||||
|
|
||||||
with FreepikClient(key, base_url=config.base_url) as client:
|
with MagnificClient(key, base_url=config.base_url) as client:
|
||||||
api = EditAPI(client)
|
api = EditAPI(client)
|
||||||
|
|
||||||
with console.status("[info]Submitting image expansion…[/info]"):
|
with console.status("[info]Submitting image expansion…[/info]"):
|
||||||
try:
|
try:
|
||||||
task_id = api.expand_submit(model, image_b64, left, right, top, bottom, prompt, seed)
|
task_id = api.expand_submit(model, image_b64, left, right, top, bottom, prompt, seed)
|
||||||
except FreepikAPIError as exc:
|
except MagnificAPIError as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ def expand_image(
|
|||||||
return
|
return
|
||||||
|
|
||||||
poll_config = PollConfig(task_type="expand", max_wait=config.poll_timeout)
|
poll_config = PollConfig(task_type="expand", max_wait=config.poll_timeout)
|
||||||
from freepik_cli.api.images import ImageAPI
|
from magnific_cli.api.images import ImageAPI
|
||||||
img_api = ImageAPI(client)
|
img_api = ImageAPI(client)
|
||||||
try:
|
try:
|
||||||
result = poll_task(
|
result = poll_task(
|
||||||
@@ -85,11 +85,11 @@ def expand_image(
|
|||||||
console=console,
|
console=console,
|
||||||
extra_info={"Model": model, "Expand": f"L{left} R{right} T{top} B{bottom}"},
|
extra_info={"Model": model, "Expand": f"L{left} R{right} T{top} B{bottom}"},
|
||||||
)
|
)
|
||||||
except (FreepikTaskError, FreepikTimeoutError) as exc:
|
except (MagnificTaskError, MagnificTimeoutError) as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
from freepik_cli.api.models import get_output_urls
|
from magnific_cli.api.models import get_output_urls
|
||||||
urls = get_output_urls(result)
|
urls = get_output_urls(result)
|
||||||
if not urls:
|
if not urls:
|
||||||
print_error("Expansion completed but no output URL found.")
|
print_error("Expansion completed but no output URL found.")
|
||||||
@@ -107,26 +107,26 @@ def relight_image(
|
|||||||
style: Annotated[Optional[str], typer.Option("--style", "-s", help="Lighting style preset")] = None,
|
style: Annotated[Optional[str], typer.Option("--style", "-s", help="Lighting style preset")] = None,
|
||||||
output: Annotated[Optional[Path], typer.Option("--output", "-o")] = None,
|
output: Annotated[Optional[Path], typer.Option("--output", "-o")] = None,
|
||||||
wait: Annotated[bool, typer.Option("--wait/--no-wait")] = True,
|
wait: Annotated[bool, typer.Option("--wait/--no-wait")] = True,
|
||||||
api_key: Annotated[Optional[str], typer.Option("--api-key", envvar="FREEPIK_API_KEY")] = None,
|
api_key: Annotated[Optional[str], typer.Option("--api-key", envvar="MAGNIFIC_API_KEY")] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
[bold]Relight an image[/bold] using AI-controlled lighting. [dim](Premium feature)[/dim]
|
[bold]Relight an image[/bold] using AI-controlled lighting. [dim](Premium feature)[/dim]
|
||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik relight portrait.jpg --prompt "dramatic studio lighting"
|
magnific relight portrait.jpg --prompt "dramatic studio lighting"
|
||||||
freepik relight scene.png --prompt "warm golden hour" --output relit.jpg
|
magnific relight scene.png --prompt "warm golden hour" --output relit.jpg
|
||||||
"""
|
"""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
key = _get_api_key(api_key, config)
|
key = _get_api_key(api_key, config)
|
||||||
image_b64 = image_to_base64(image)
|
image_b64 = image_to_base64(image)
|
||||||
|
|
||||||
with FreepikClient(key, base_url=config.base_url) as client:
|
with MagnificClient(key, base_url=config.base_url) as client:
|
||||||
api = EditAPI(client)
|
api = EditAPI(client)
|
||||||
|
|
||||||
with console.status("[info]Submitting image relight…[/info]"):
|
with console.status("[info]Submitting image relight…[/info]"):
|
||||||
try:
|
try:
|
||||||
task_id = api.relight_submit(image_b64, prompt, style)
|
task_id = api.relight_submit(image_b64, prompt, style)
|
||||||
except FreepikAPIError as exc:
|
except MagnificAPIError as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -142,7 +142,7 @@ def relight_image(
|
|||||||
config=poll_config,
|
config=poll_config,
|
||||||
console=console,
|
console=console,
|
||||||
)
|
)
|
||||||
except (FreepikTaskError, FreepikTimeoutError) as exc:
|
except (MagnificTaskError, MagnificTimeoutError) as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -163,28 +163,28 @@ def style_transfer(
|
|||||||
strength: Annotated[Optional[float], typer.Option("--strength", help="Style strength 0.0–1.0", min=0.0, max=1.0)] = None,
|
strength: Annotated[Optional[float], typer.Option("--strength", help="Style strength 0.0–1.0", min=0.0, max=1.0)] = None,
|
||||||
output: Annotated[Optional[Path], typer.Option("--output", "-o")] = None,
|
output: Annotated[Optional[Path], typer.Option("--output", "-o")] = None,
|
||||||
wait: Annotated[bool, typer.Option("--wait/--no-wait")] = True,
|
wait: Annotated[bool, typer.Option("--wait/--no-wait")] = True,
|
||||||
api_key: Annotated[Optional[str], typer.Option("--api-key", envvar="FREEPIK_API_KEY")] = None,
|
api_key: Annotated[Optional[str], typer.Option("--api-key", envvar="MAGNIFIC_API_KEY")] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
[bold]Apply an artistic style[/bold] from one image onto another. [dim](Premium feature)[/dim]
|
[bold]Apply an artistic style[/bold] from one image onto another. [dim](Premium feature)[/dim]
|
||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik style-transfer photo.jpg painting.jpg --strength 0.8
|
magnific style-transfer photo.jpg painting.jpg --strength 0.8
|
||||||
freepik style-transfer portrait.png van_gogh.jpg --output styled.jpg
|
magnific style-transfer portrait.png van_gogh.jpg --output styled.jpg
|
||||||
"""
|
"""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
key = _get_api_key(api_key, config)
|
key = _get_api_key(api_key, config)
|
||||||
|
|
||||||
content_b64 = image_to_base64(content)
|
content_b64 = image_to_base64(content)
|
||||||
style_b64 = image_to_base64(style_image)
|
style_b64 = image_to_base64(style_image)
|
||||||
|
|
||||||
with FreepikClient(key, base_url=config.base_url) as client:
|
with MagnificClient(key, base_url=config.base_url) as client:
|
||||||
api = EditAPI(client)
|
api = EditAPI(client)
|
||||||
|
|
||||||
with console.status("[info]Submitting style transfer…[/info]"):
|
with console.status("[info]Submitting style transfer…[/info]"):
|
||||||
try:
|
try:
|
||||||
task_id = api.style_transfer_submit(content_b64, style_b64, strength)
|
task_id = api.style_transfer_submit(content_b64, style_b64, strength)
|
||||||
except FreepikAPIError as exc:
|
except MagnificAPIError as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -200,7 +200,7 @@ def style_transfer(
|
|||||||
config=poll_config,
|
config=poll_config,
|
||||||
console=console,
|
console=console,
|
||||||
)
|
)
|
||||||
except (FreepikTaskError, FreepikTimeoutError) as exc:
|
except (MagnificTaskError, MagnificTimeoutError) as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -7,23 +7,23 @@ from typing import Annotated, Optional
|
|||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
from freepik_cli.api.client import FreepikAPIError, FreepikClient
|
from magnific_cli.api.client import MagnificAPIError, MagnificClient
|
||||||
from freepik_cli.api.edit import EditAPI
|
from magnific_cli.api.edit import EditAPI
|
||||||
from freepik_cli.api.images import ImageAPI
|
from magnific_cli.api.images import ImageAPI
|
||||||
from freepik_cli.api.models import IconStyle, ImageModel, VideoModel, normalize_aspect_ratio
|
from magnific_cli.api.models import IconStyle, ImageModel, VideoModel, normalize_aspect_ratio
|
||||||
from freepik_cli.api.videos import VideoAPI
|
from magnific_cli.api.videos import VideoAPI
|
||||||
from freepik_cli.utils.config import FreepikConfig
|
from magnific_cli.utils.config import MagnificConfig
|
||||||
from freepik_cli.utils.console import GenerationResult, console, print_error, print_no_wait, print_result
|
from magnific_cli.utils.console import GenerationResult, console, print_error, print_no_wait, print_result
|
||||||
from freepik_cli.utils.files import auto_output_path, get_image_dimensions, image_to_base64, save_from_url
|
from magnific_cli.utils.files import auto_output_path, get_image_dimensions, image_to_base64, save_from_url
|
||||||
from freepik_cli.utils.polling import FreepikTaskError, FreepikTimeoutError, PollConfig, poll_task
|
from magnific_cli.utils.polling import MagnificTaskError, MagnificTimeoutError, PollConfig, poll_task
|
||||||
|
|
||||||
|
|
||||||
def _get_api_key(api_key: Optional[str], config: FreepikConfig) -> str:
|
def _get_api_key(api_key: Optional[str], config: MagnificConfig) -> str:
|
||||||
key = api_key or config.api_key
|
key = api_key or config.api_key
|
||||||
if not key:
|
if not key:
|
||||||
print_error(
|
print_error(
|
||||||
"No API key found.",
|
"No API key found.",
|
||||||
hint="Set the [cyan]FREEPIK_API_KEY[/cyan] environment variable, "
|
hint="Set the [cyan]MAGNIFIC_API_KEY[/cyan] environment variable, "
|
||||||
"or pass [cyan]--api-key YOUR_KEY[/cyan].",
|
"or pass [cyan]--api-key YOUR_KEY[/cyan].",
|
||||||
)
|
)
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
@@ -69,18 +69,18 @@ def generate_image(
|
|||||||
] = True,
|
] = True,
|
||||||
api_key: Annotated[
|
api_key: Annotated[
|
||||||
Optional[str],
|
Optional[str],
|
||||||
typer.Option("--api-key", envvar="FREEPIK_API_KEY", help="Freepik API key"),
|
typer.Option("--api-key", envvar="MAGNIFIC_API_KEY", help="Magnific API key"),
|
||||||
] = None,
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
[bold]Generate an image[/bold] using Freepik AI models.
|
[bold]Generate an image[/bold] using Magnific AI models.
|
||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik generate-image "a cat on the moon" --model flux-2-pro
|
magnific generate-image "a cat on the moon" --model flux-2-pro
|
||||||
freepik generate-image "cyberpunk city at night" --model mystic --aspect-ratio 16:9
|
magnific generate-image "cyberpunk city at night" --model mystic --aspect-ratio 16:9
|
||||||
freepik generate-image "make the sky orange" --model flux-kontext-pro --input-image photo.jpg
|
magnific generate-image "make the sky orange" --model flux-kontext-pro --input-image photo.jpg
|
||||||
"""
|
"""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
key = _get_api_key(api_key, config)
|
key = _get_api_key(api_key, config)
|
||||||
|
|
||||||
# Build request payload
|
# Build request payload
|
||||||
@@ -94,13 +94,13 @@ def generate_image(
|
|||||||
if input_image:
|
if input_image:
|
||||||
payload["image"] = image_to_base64(input_image)
|
payload["image"] = image_to_base64(input_image)
|
||||||
|
|
||||||
with FreepikClient(key, base_url=config.base_url) as client:
|
with MagnificClient(key, base_url=config.base_url) as client:
|
||||||
api = ImageAPI(client)
|
api = ImageAPI(client)
|
||||||
|
|
||||||
with console.status(f"[info]Submitting {model.value} generation…[/info]"):
|
with console.status(f"[info]Submitting {model.value} generation…[/info]"):
|
||||||
try:
|
try:
|
||||||
task_id = api.generate(model, payload)
|
task_id = api.generate(model, payload)
|
||||||
except FreepikAPIError as exc:
|
except MagnificAPIError as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -117,13 +117,13 @@ def generate_image(
|
|||||||
console=console,
|
console=console,
|
||||||
extra_info={"Model": f"[magenta]{model.value}[/magenta]"},
|
extra_info={"Model": f"[magenta]{model.value}[/magenta]"},
|
||||||
)
|
)
|
||||||
except (FreepikTaskError, FreepikTimeoutError) as exc:
|
except (MagnificTaskError, MagnificTimeoutError) as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
urls = api.get_output_urls(result)
|
urls = api.get_output_urls(result)
|
||||||
if not urls:
|
if not urls:
|
||||||
print_error("Generation completed but no output URLs found.", hint="Check the Freepik dashboard.")
|
print_error("Generation completed but no output URLs found.", hint="Check the Magnific dashboard.")
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
out = output or auto_output_path("image", model.value, "jpg", config.default_output_dir)
|
out = output or auto_output_path("image", model.value, "jpg", config.default_output_dir)
|
||||||
@@ -185,23 +185,23 @@ def generate_video(
|
|||||||
] = True,
|
] = True,
|
||||||
api_key: Annotated[
|
api_key: Annotated[
|
||||||
Optional[str],
|
Optional[str],
|
||||||
typer.Option("--api-key", envvar="FREEPIK_API_KEY", help="Freepik API key"),
|
typer.Option("--api-key", envvar="MAGNIFIC_API_KEY", help="Magnific API key"),
|
||||||
] = None,
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
[bold]Generate a video[/bold] from a source image using AI.
|
[bold]Generate a video[/bold] from a source image using AI.
|
||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik generate-video photo.jpg --prompt "gentle ocean waves" --model kling-o1-pro
|
magnific generate-video photo.jpg --prompt "gentle ocean waves" --model kling-o1-pro
|
||||||
freepik generate-video portrait.png --model kling-elements-pro --aspect-ratio 9:16
|
magnific generate-video portrait.png --model kling-elements-pro --aspect-ratio 9:16
|
||||||
freepik generate-video photo.jpg --model minimax-hailuo --aspect-ratio 16:9
|
magnific generate-video photo.jpg --model minimax-hailuo --aspect-ratio 16:9
|
||||||
"""
|
"""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
key = _get_api_key(api_key, config)
|
key = _get_api_key(api_key, config)
|
||||||
|
|
||||||
image_b64 = image_to_base64(image)
|
image_b64 = image_to_base64(image)
|
||||||
|
|
||||||
with FreepikClient(key, base_url=config.base_url) as client:
|
with MagnificClient(key, base_url=config.base_url) as client:
|
||||||
api = VideoAPI(client)
|
api = VideoAPI(client)
|
||||||
|
|
||||||
with console.status(f"[info]Submitting {model.value} video generation…[/info]"):
|
with console.status(f"[info]Submitting {model.value} video generation…[/info]"):
|
||||||
@@ -214,7 +214,7 @@ def generate_video(
|
|||||||
aspect_ratio=aspect_ratio,
|
aspect_ratio=aspect_ratio,
|
||||||
seed=seed,
|
seed=seed,
|
||||||
)
|
)
|
||||||
except FreepikAPIError as exc:
|
except MagnificAPIError as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ def generate_video(
|
|||||||
"Ratio": aspect_ratio,
|
"Ratio": aspect_ratio,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
except (FreepikTaskError, FreepikTimeoutError) as exc:
|
except (MagnificTaskError, MagnificTimeoutError) as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -294,26 +294,26 @@ def generate_icon(
|
|||||||
] = True,
|
] = True,
|
||||||
api_key: Annotated[
|
api_key: Annotated[
|
||||||
Optional[str],
|
Optional[str],
|
||||||
typer.Option("--api-key", envvar="FREEPIK_API_KEY"),
|
typer.Option("--api-key", envvar="MAGNIFIC_API_KEY"),
|
||||||
] = None,
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
[bold]Generate an icon[/bold] from a text prompt.
|
[bold]Generate an icon[/bold] from a text prompt.
|
||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik generate-icon "shopping cart" --style solid --format svg
|
magnific generate-icon "shopping cart" --style solid --format svg
|
||||||
freepik generate-icon "rocket ship" --style color --format png
|
magnific generate-icon "rocket ship" --style color --format png
|
||||||
"""
|
"""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
key = _get_api_key(api_key, config)
|
key = _get_api_key(api_key, config)
|
||||||
|
|
||||||
with FreepikClient(key, base_url=config.base_url) as client:
|
with MagnificClient(key, base_url=config.base_url) as client:
|
||||||
api = EditAPI(client)
|
api = EditAPI(client)
|
||||||
|
|
||||||
with console.status("[info]Submitting icon generation…[/info]"):
|
with console.status("[info]Submitting icon generation…[/info]"):
|
||||||
try:
|
try:
|
||||||
task_id = api.generate_icon(prompt, style, steps, guidance, seed)
|
task_id = api.generate_icon(prompt, style, steps, guidance, seed)
|
||||||
except FreepikAPIError as exc:
|
except MagnificAPIError as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -330,7 +330,7 @@ def generate_icon(
|
|||||||
console=console,
|
console=console,
|
||||||
extra_info={"Style": style.value, "Format": fmt},
|
extra_info={"Style": style.value, "Format": fmt},
|
||||||
)
|
)
|
||||||
except (FreepikTaskError, FreepikTimeoutError) as exc:
|
except (MagnificTaskError, MagnificTimeoutError) as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -338,7 +338,7 @@ def generate_icon(
|
|||||||
with console.status(f"[info]Rendering icon as {fmt.upper()}…[/info]"):
|
with console.status(f"[info]Rendering icon as {fmt.upper()}…[/info]"):
|
||||||
try:
|
try:
|
||||||
url = api.render_icon(task_id, fmt)
|
url = api.render_icon(task_id, fmt)
|
||||||
except FreepikAPIError as exc:
|
except MagnificAPIError as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -7,21 +7,21 @@ from typing import Annotated, Optional
|
|||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
from freepik_cli.api.client import FreepikAPIError, FreepikClient
|
from magnific_cli.api.client import MagnificAPIError, MagnificClient
|
||||||
from freepik_cli.api.models import UpscaleMode, VideoUpscaleMode
|
from magnific_cli.api.models import UpscaleMode, VideoUpscaleMode
|
||||||
from freepik_cli.api.upscale import UpscaleAPI
|
from magnific_cli.api.upscale import UpscaleAPI
|
||||||
from freepik_cli.utils.config import FreepikConfig
|
from magnific_cli.utils.config import MagnificConfig
|
||||||
from freepik_cli.utils.console import GenerationResult, console, print_error, print_no_wait, print_result
|
from magnific_cli.utils.console import GenerationResult, console, print_error, print_no_wait, print_result
|
||||||
from freepik_cli.utils.files import auto_output_path, get_image_dimensions, image_to_base64, save_from_url, video_to_base64
|
from magnific_cli.utils.files import auto_output_path, get_image_dimensions, image_to_base64, save_from_url, video_to_base64
|
||||||
from freepik_cli.utils.polling import FreepikTaskError, FreepikTimeoutError, PollConfig, poll_task
|
from magnific_cli.utils.polling import MagnificTaskError, MagnificTimeoutError, PollConfig, poll_task
|
||||||
|
|
||||||
|
|
||||||
def _get_api_key(api_key: Optional[str], config: FreepikConfig) -> str:
|
def _get_api_key(api_key: Optional[str], config: MagnificConfig) -> str:
|
||||||
key = api_key or config.api_key
|
key = api_key or config.api_key
|
||||||
if not key:
|
if not key:
|
||||||
print_error(
|
print_error(
|
||||||
"No API key found.",
|
"No API key found.",
|
||||||
hint="Set [cyan]FREEPIK_API_KEY[/cyan] or pass [cyan]--api-key YOUR_KEY[/cyan].",
|
hint="Set [cyan]MAGNIFIC_API_KEY[/cyan] or pass [cyan]--api-key YOUR_KEY[/cyan].",
|
||||||
)
|
)
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
return key
|
return key
|
||||||
@@ -76,17 +76,17 @@ def upscale_image(
|
|||||||
] = True,
|
] = True,
|
||||||
api_key: Annotated[
|
api_key: Annotated[
|
||||||
Optional[str],
|
Optional[str],
|
||||||
typer.Option("--api-key", envvar="FREEPIK_API_KEY", help="Freepik API key"),
|
typer.Option("--api-key", envvar="MAGNIFIC_API_KEY", help="Magnific API key"),
|
||||||
] = None,
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
[bold]Upscale and enhance an image[/bold] using AI.
|
[bold]Upscale and enhance an image[/bold] using AI.
|
||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik upscale-image photo.jpg --mode precision-v2 --scale 4x
|
magnific upscale-image photo.jpg --mode precision-v2 --scale 4x
|
||||||
freepik upscale-image portrait.png --mode creative --creativity 7 --prompt "sharp cinematic"
|
magnific upscale-image portrait.png --mode creative --creativity 7 --prompt "sharp cinematic"
|
||||||
"""
|
"""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
key = _get_api_key(api_key, config)
|
key = _get_api_key(api_key, config)
|
||||||
|
|
||||||
if mode != UpscaleMode.CREATIVE and (creativity is not None or prompt):
|
if mode != UpscaleMode.CREATIVE and (creativity is not None or prompt):
|
||||||
@@ -98,7 +98,7 @@ def upscale_image(
|
|||||||
|
|
||||||
image_b64 = image_to_base64(image)
|
image_b64 = image_to_base64(image)
|
||||||
|
|
||||||
with FreepikClient(key, base_url=config.base_url) as client:
|
with MagnificClient(key, base_url=config.base_url) as client:
|
||||||
api = UpscaleAPI(client)
|
api = UpscaleAPI(client)
|
||||||
|
|
||||||
with console.status(f"[info]Submitting {mode.value} upscale ({scale})…[/info]"):
|
with console.status(f"[info]Submitting {mode.value} upscale ({scale})…[/info]"):
|
||||||
@@ -111,7 +111,7 @@ def upscale_image(
|
|||||||
prompt=prompt,
|
prompt=prompt,
|
||||||
seed=seed,
|
seed=seed,
|
||||||
)
|
)
|
||||||
except FreepikAPIError as exc:
|
except MagnificAPIError as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ def upscale_image(
|
|||||||
console=console,
|
console=console,
|
||||||
extra_info={"Mode": mode.value, "Scale": scale},
|
extra_info={"Mode": mode.value, "Scale": scale},
|
||||||
)
|
)
|
||||||
except (FreepikTaskError, FreepikTimeoutError) as exc:
|
except (MagnificTaskError, MagnificTimeoutError) as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -179,28 +179,28 @@ def upscale_video(
|
|||||||
] = True,
|
] = True,
|
||||||
api_key: Annotated[
|
api_key: Annotated[
|
||||||
Optional[str],
|
Optional[str],
|
||||||
typer.Option("--api-key", envvar="FREEPIK_API_KEY"),
|
typer.Option("--api-key", envvar="MAGNIFIC_API_KEY"),
|
||||||
] = None,
|
] = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
[bold]Upscale a video[/bold] to higher resolution using AI.
|
[bold]Upscale a video[/bold] to higher resolution using AI.
|
||||||
|
|
||||||
[dim]Examples:[/dim]
|
[dim]Examples:[/dim]
|
||||||
freepik upscale-video clip.mp4 --mode standard
|
magnific upscale-video clip.mp4 --mode standard
|
||||||
freepik upscale-video clip.mp4 --mode turbo --output clip_4k.mp4
|
magnific upscale-video clip.mp4 --mode turbo --output clip_4k.mp4
|
||||||
"""
|
"""
|
||||||
config = FreepikConfig.load()
|
config = MagnificConfig.load()
|
||||||
key = _get_api_key(api_key, config)
|
key = _get_api_key(api_key, config)
|
||||||
|
|
||||||
video_b64 = video_to_base64(video)
|
video_b64 = video_to_base64(video)
|
||||||
|
|
||||||
with FreepikClient(key, base_url=config.base_url) as client:
|
with MagnificClient(key, base_url=config.base_url) as client:
|
||||||
api = UpscaleAPI(client)
|
api = UpscaleAPI(client)
|
||||||
|
|
||||||
with console.status(f"[info]Submitting video upscale ({mode.value})…[/info]"):
|
with console.status(f"[info]Submitting video upscale ({mode.value})…[/info]"):
|
||||||
try:
|
try:
|
||||||
task_id = api.upscale_video(mode=mode, video_b64=video_b64)
|
task_id = api.upscale_video(mode=mode, video_b64=video_b64)
|
||||||
except FreepikAPIError as exc:
|
except MagnificAPIError as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ def upscale_video(
|
|||||||
console=console,
|
console=console,
|
||||||
extra_info={"Mode": mode.value},
|
extra_info={"Mode": mode.value},
|
||||||
)
|
)
|
||||||
except (FreepikTaskError, FreepikTimeoutError) as exc:
|
except (MagnificTaskError, MagnificTimeoutError) as exc:
|
||||||
print_error(str(exc))
|
print_error(str(exc))
|
||||||
raise typer.Exit(1)
|
raise typer.Exit(1)
|
||||||
|
|
||||||
@@ -6,22 +6,22 @@ from typing import Annotated, Optional
|
|||||||
|
|
||||||
import typer
|
import typer
|
||||||
|
|
||||||
from freepik_cli import __version__
|
from magnific_cli import __version__
|
||||||
from freepik_cli.commands import config as config_cmd
|
from magnific_cli.commands import config as config_cmd
|
||||||
from freepik_cli.commands.analyze import describe_image
|
from magnific_cli.commands.analyze import describe_image
|
||||||
from freepik_cli.commands.edit import expand_image, relight_image, style_transfer
|
from magnific_cli.commands.edit import expand_image, relight_image, style_transfer
|
||||||
from freepik_cli.commands.generate import generate_icon, generate_image, generate_video
|
from magnific_cli.commands.generate import generate_icon, generate_image, generate_video
|
||||||
from freepik_cli.commands.upscale import upscale_image, upscale_video
|
from magnific_cli.commands.upscale import upscale_image, upscale_video
|
||||||
from freepik_cli.utils.console import console, print_banner
|
from magnific_cli.utils.console import console, print_banner
|
||||||
from freepik_cli.utils.config import FreepikConfig
|
from magnific_cli.utils.config import MagnificConfig
|
||||||
|
|
||||||
app = typer.Typer(
|
app = typer.Typer(
|
||||||
name="freepik",
|
name="magnific",
|
||||||
help=(
|
help=(
|
||||||
"[bold magenta]Freepik AI[/bold magenta] — generate images, videos, and more "
|
"[bold magenta]Magnific AI[/bold magenta] — generate images, videos, and more "
|
||||||
"from the command line.\n\n"
|
"from the command line.\n\n"
|
||||||
"[dim]Set your API key:[/dim] [cyan]export FREEPIK_API_KEY=your_key[/cyan]\n"
|
"[dim]Set your API key:[/dim] [cyan]export MAGNIFIC_API_KEY=your_key[/cyan]\n"
|
||||||
"[dim]Get an API key:[/dim] https://www.freepik.com/api"
|
"[dim]Get an API key:[/dim] https://magnific.ai"
|
||||||
),
|
),
|
||||||
rich_markup_mode="rich",
|
rich_markup_mode="rich",
|
||||||
no_args_is_help=True,
|
no_args_is_help=True,
|
||||||
@@ -106,9 +106,9 @@ def main(
|
|||||||
] = False,
|
] = False,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
[bold magenta]Freepik AI[/bold magenta] — generate images, videos, icons, and more.
|
[bold magenta]Magnific AI[/bold magenta] — generate images, videos, icons, and more.
|
||||||
"""
|
"""
|
||||||
cfg = FreepikConfig.load()
|
cfg = MagnificConfig.load()
|
||||||
|
|
||||||
if version:
|
if version:
|
||||||
print_banner()
|
print_banner()
|
||||||
@@ -10,28 +10,28 @@ from platformdirs import user_config_dir
|
|||||||
from pydantic import field_validator
|
from pydantic import field_validator
|
||||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
|
||||||
CONFIG_DIR = Path(user_config_dir("freepik-cli"))
|
CONFIG_DIR = Path(user_config_dir("magnific-cli"))
|
||||||
CONFIG_FILE = CONFIG_DIR / "config.toml"
|
CONFIG_FILE = CONFIG_DIR / "config.toml"
|
||||||
|
|
||||||
|
|
||||||
class FreepikConfig(BaseSettings):
|
class MagnificConfig(BaseSettings):
|
||||||
"""
|
"""
|
||||||
Configuration with priority (highest to lowest):
|
Configuration with priority (highest to lowest):
|
||||||
1. CLI --api-key flag (handled in commands directly)
|
1. CLI --api-key flag (handled in commands directly)
|
||||||
2. FREEPIK_* environment variables
|
2. MAGNIFIC_* environment variables
|
||||||
3. ~/.config/freepik-cli/config.toml
|
3. ~/.config/magnific-cli/config.toml
|
||||||
4. Defaults below
|
4. Defaults below
|
||||||
"""
|
"""
|
||||||
|
|
||||||
model_config = SettingsConfigDict(
|
model_config = SettingsConfigDict(
|
||||||
env_prefix="FREEPIK_",
|
env_prefix="MAGNIFIC_",
|
||||||
env_file=".env",
|
env_file=".env",
|
||||||
env_file_encoding="utf-8",
|
env_file_encoding="utf-8",
|
||||||
extra="ignore",
|
extra="ignore",
|
||||||
)
|
)
|
||||||
|
|
||||||
api_key: Optional[str] = None
|
api_key: Optional[str] = None
|
||||||
base_url: str = "https://api.freepik.com"
|
base_url: str = "https://api.magnific.ai"
|
||||||
default_output_dir: str = "."
|
default_output_dir: str = "."
|
||||||
default_image_model: str = "flux-2-pro"
|
default_image_model: str = "flux-2-pro"
|
||||||
default_video_model: str = "kling-o1-pro"
|
default_video_model: str = "kling-o1-pro"
|
||||||
@@ -46,7 +46,7 @@ class FreepikConfig(BaseSettings):
|
|||||||
return v.strip() if isinstance(v, str) else v
|
return v.strip() if isinstance(v, str) else v
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls) -> "FreepikConfig":
|
def load(cls) -> "MagnificConfig":
|
||||||
"""Load from config file, then overlay environment variables."""
|
"""Load from config file, then overlay environment variables."""
|
||||||
file_data: dict = {}
|
file_data: dict = {}
|
||||||
if CONFIG_FILE.exists():
|
if CONFIG_FILE.exists():
|
||||||
@@ -83,7 +83,7 @@ class FreepikConfig(BaseSettings):
|
|||||||
if key not in allowed:
|
if key not in allowed:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Key '{key}' is not configurable via this command. "
|
f"Key '{key}' is not configurable via this command. "
|
||||||
f"Use the FREEPIK_API_KEY environment variable to set the API key."
|
f"Use the MAGNIFIC_API_KEY environment variable to set the API key."
|
||||||
)
|
)
|
||||||
current = self.model_dump()
|
current = self.model_dump()
|
||||||
if key in ("poll_timeout", "poll_max_interval"):
|
if key in ("poll_timeout", "poll_max_interval"):
|
||||||
@@ -92,5 +92,5 @@ class FreepikConfig(BaseSettings):
|
|||||||
current[key] = value.lower() in ("true", "1", "yes")
|
current[key] = value.lower() in ("true", "1", "yes")
|
||||||
else:
|
else:
|
||||||
current[key] = value
|
current[key] = value
|
||||||
updated = FreepikConfig(**{k: v for k, v in current.items() if v is not None})
|
updated = MagnificConfig(**{k: v for k, v in current.items() if v is not None})
|
||||||
updated.save()
|
updated.save()
|
||||||
@@ -17,7 +17,7 @@ from rich.table import Table
|
|||||||
from rich.text import Text
|
from rich.text import Text
|
||||||
from rich.theme import Theme
|
from rich.theme import Theme
|
||||||
|
|
||||||
FREEPIK_THEME = Theme(
|
MAGNIFIC_THEME = Theme(
|
||||||
{
|
{
|
||||||
"info": "bold cyan",
|
"info": "bold cyan",
|
||||||
"success": "bold green",
|
"success": "bold green",
|
||||||
@@ -32,17 +32,17 @@ FREEPIK_THEME = Theme(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
console = Console(theme=FREEPIK_THEME, highlight=True)
|
console = Console(theme=MAGNIFIC_THEME, highlight=True)
|
||||||
err_console = Console(stderr=True, theme=FREEPIK_THEME)
|
err_console = Console(stderr=True, theme=MAGNIFIC_THEME)
|
||||||
|
|
||||||
BANNER = """\
|
BANNER = """\
|
||||||
[bold magenta] ███████╗██████╗ ███████╗███████╗██████╗ ██╗██╗ ██╗[/bold magenta]
|
[bold magenta]███╗ ███╗ █████╗ ██████╗ ███╗ ██╗██╗███████╗██╗ ██████╗ [/bold magenta]
|
||||||
[bold magenta] ██╔════╝██╔══██╗██╔════╝██╔════╝██╔══██╗██║██║ ██╔╝[/bold magenta]
|
[bold magenta]████╗ ████║██╔══██╗██╔════╝ ████╗ ██║██║██╔════╝██║██╔════╝ [/bold magenta]
|
||||||
[bold magenta] █████╗ ██████╔╝█████╗ █████╗ ██████╔╝██║█████╔╝ [/bold magenta]
|
[bold magenta]██╔████╔██║███████║██║ ███╗██╔██╗ ██║██║█████╗ ██║██║ [/bold magenta]
|
||||||
[bold magenta] ██╔══╝ ██╔══██╗██╔══╝ ██╔══╝ ██╔═══╝ ██║██╔═██╗ [/bold magenta]
|
[bold magenta]██║╚██╔╝██║██╔══██║██║ ██║██║╚██╗██║██║██╔══╝ ██║██║ [/bold magenta]
|
||||||
[bold magenta] ██║ ██║ ██║███████╗███████╗██║ ██║██║ ██╗[/bold magenta]
|
[bold magenta]██║ ╚═╝ ██║██║ ██║╚██████╔╝██║ ╚████║██║██║ ██║╚██████╗ [/bold magenta]
|
||||||
[bold magenta] ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝[/bold magenta]
|
[bold magenta]╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚═╝╚═╝ ╚═╝ ╚═════╝[/bold magenta]
|
||||||
[dim] AI Media Generation CLI • v0.1.0[/dim]"""
|
[dim] AI Media Generation CLI • v0.1.0[/dim]"""
|
||||||
|
|
||||||
|
|
||||||
def print_banner() -> None:
|
def print_banner() -> None:
|
||||||
@@ -128,7 +128,7 @@ def print_no_wait(task_id: str, task_type: str, model: str) -> None:
|
|||||||
f"[dim.label]Type:[/dim.label] {task_type}\n"
|
f"[dim.label]Type:[/dim.label] {task_type}\n"
|
||||||
f"[dim.label]Model:[/dim.label] [model]{model}[/model]\n\n"
|
f"[dim.label]Model:[/dim.label] [model]{model}[/model]\n\n"
|
||||||
f"[dim]The task is processing asynchronously. Results will be available\n"
|
f"[dim]The task is processing asynchronously. Results will be available\n"
|
||||||
f"on the Freepik dashboard when complete.[/dim]"
|
f"on the Magnific dashboard when complete.[/dim]"
|
||||||
),
|
),
|
||||||
title="⏳ Task Queued",
|
title="⏳ Task Queued",
|
||||||
border_style="cyan",
|
border_style="cyan",
|
||||||
@@ -165,7 +165,7 @@ def print_warning(message: str) -> None:
|
|||||||
def print_config_table(config_dict: dict, masked_keys: set[str] | None = None) -> None:
|
def print_config_table(config_dict: dict, masked_keys: set[str] | None = None) -> None:
|
||||||
masked_keys = masked_keys or {"api_key"}
|
masked_keys = masked_keys or {"api_key"}
|
||||||
table = Table(
|
table = Table(
|
||||||
title="[brand]Freepik CLI Configuration[/brand]",
|
title="[brand]Magnific CLI Configuration[/brand]",
|
||||||
show_header=True,
|
show_header=True,
|
||||||
header_style="bold magenta",
|
header_style="bold magenta",
|
||||||
border_style="magenta",
|
border_style="magenta",
|
||||||
@@ -206,7 +206,7 @@ def print_config_toml(config_dict: dict, masked_keys: set[str] | None = None) ->
|
|||||||
console.print(
|
console.print(
|
||||||
Panel(
|
Panel(
|
||||||
Syntax(toml_str, "toml", theme="monokai", background_color="default"),
|
Syntax(toml_str, "toml", theme="monokai", background_color="default"),
|
||||||
title="[brand]~/.config/freepik-cli/config.toml[/brand]",
|
title="[brand]~/.config/magnific-cli/config.toml[/brand]",
|
||||||
border_style="magenta",
|
border_style="magenta",
|
||||||
padding=(1, 2),
|
padding=(1, 2),
|
||||||
)
|
)
|
||||||
@@ -62,7 +62,7 @@ def auto_output_path(task_type: str, model: str, ext: str = "jpg", output_dir: s
|
|||||||
"""Generate a timestamped output filename."""
|
"""Generate a timestamped output filename."""
|
||||||
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
safe_model = model.replace("/", "-").replace(" ", "-")
|
safe_model = model.replace("/", "-").replace(" ", "-")
|
||||||
filename = f"freepik_{task_type}_{safe_model}_{ts}.{ext}"
|
filename = f"magnific_{task_type}_{safe_model}_{ts}.{ext}"
|
||||||
return Path(output_dir) / filename
|
return Path(output_dir) / filename
|
||||||
|
|
||||||
|
|
||||||
@@ -46,11 +46,11 @@ TASK_TYPE_LABELS: dict[str, str] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class FreepikTaskError(Exception):
|
class MagnificTaskError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FreepikTimeoutError(Exception):
|
class MagnificTimeoutError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ def _render_panel(
|
|||||||
|
|
||||||
return Panel(
|
return Panel(
|
||||||
grid,
|
grid,
|
||||||
title="[bold magenta]~ Freepik AI ~[/bold magenta]",
|
title="[bold magenta]~ Magnific AI ~[/bold magenta]",
|
||||||
border_style="magenta",
|
border_style="magenta",
|
||||||
padding=(1, 2),
|
padding=(1, 2),
|
||||||
width=52,
|
width=52,
|
||||||
@@ -149,7 +149,7 @@ def poll_task(
|
|||||||
|
|
||||||
if elapsed > config.max_wait:
|
if elapsed > config.max_wait:
|
||||||
live.stop()
|
live.stop()
|
||||||
raise FreepikTimeoutError(
|
raise MagnificTimeoutError(
|
||||||
f"Task {task_id} timed out after {config.max_wait:.0f}s"
|
f"Task {task_id} timed out after {config.max_wait:.0f}s"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ def poll_task(
|
|||||||
or data.get("message")
|
or data.get("message")
|
||||||
or f"Task ended with status {upper}"
|
or f"Task ended with status {upper}"
|
||||||
)
|
)
|
||||||
raise FreepikTaskError(f"{upper}: {error_msg}")
|
raise MagnificTaskError(f"{upper}: {error_msg}")
|
||||||
|
|
||||||
time.sleep(interval)
|
time.sleep(interval)
|
||||||
interval = min(interval * config.backoff_factor, config.max_interval)
|
interval = min(interval * config.backoff_factor, config.max_interval)
|
||||||
+4
-4
@@ -3,9 +3,9 @@ requires = ["hatchling"]
|
|||||||
build-backend = "hatchling.build"
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "freepik-cli"
|
name = "magnific-cli"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "A beautiful CLI for the Freepik AI API — generate images, videos, and more"
|
description = "A beautiful CLI for the Magnific AI API — generate images, videos, and more"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
license = { text = "MIT" }
|
license = { text = "MIT" }
|
||||||
@@ -30,10 +30,10 @@ dev = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
freepik = "freepik_cli.main:app"
|
magnific = "magnific_cli.main:app"
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
packages = ["freepik_cli"]
|
packages = ["magnific_cli"]
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
line-length = 100
|
line-length = 100
|
||||||
|
|||||||
Reference in New Issue
Block a user