Design & media

Phosor AI

Try it

Generate AI video, image, and speech outputs, or run e-commerce photo studios, from one CLI against the Phosor AI API.

What it does

Covers text-to-video, image-to-video, reference-to-video, speech-to-video, animate, text-to-image, image-to-image, multi-reference image edit, FLUX.2-dev edit, and Qwen3-TTS. Upload your own LoRA (one .safetensors for image, two for video) and pass --lora-id in submit. Image Studio endpoints handle AI product, model, and clothing photography for e-commerce. Image-based jobs follow a two-step flow: upload-image (or import-image) to get an s3_key, then submit with that key. All commands print JSON to stdout.

When to use it

  • Generate short videos from text prompts, first-frame images, or reference images/videos/audio
  • Animate a still character image from a reference dance video, or lip-sync a face image to speech audio
  • Generate or edit images in the style of a LoRA you uploaded yourself
  • Produce AI product photos, model shots, or clothing shots for e-commerce listings

The skill document

Phosor AI

Generate AI videos and images (text-to-video, image-to-video, speech-to-video, animate, text-to-image, image-to-image), bring your own LoRA models, and generate AI product/model photography for e-commerce (Image Studio) via the Phosor AI platform.

For detailed API endpoints, parameters, pricing, and limits, see references/api.md.

Setup

Set your API key:

export PHOSOR_API_KEY="your-api-key-here"

Get an API key at phosor.ai → Settings → API Keys.

The CLI script is at scripts/phosor_client.py. All commands output JSON to stdout.

Environments (dev vs prod — same API, only the base URL differs)

It is one API. Endpoints, parameters and payloads are identical across environments — only the base URL (host:port) and scheme change. Do not fork the client or the skill per environment; just point the same client at a different base URL.

EnvBase URLHow to target it
Production (default)https://phosor.ai (fixed)nothing to set; key from phosor.ai → Settings → API Keys
Devthe current dev machine — not fixed, it moves with the box (e.g. http://54.95.59.4:3000 nginx front, or http://localhost:8010 gateway when you're on the box)--base-url http:// --allow-http (or env PHOSOR_BASE_URL=... PHOSOR_ALLOW_HTTP=1). localhost/127.0.0.1 needs no flag. Dev key from the dev site.
# dev
python3 scripts/phosor_client.py --base-url http://54.95.59.4:3000 --allow-http --api-key  check-key
# prod (default — HTTPS enforced)
python3 scripts/phosor_client.py --api-key  check-key

Dev gotcha: studio-analyze / studio-suite --image-url must be the full https S3 URL returned by upload-image, not the bare S3 key path — a bare key errors with unsupported URL scheme.

Quick Start

MiniMax H3 — Text-to-Video

H3 is duration-based, not frame-based: it ignores --num-frames / --fps (output is always 24fps) and bills per output second. Pick the frame size with --resolution-tier + --aspect instead of --width/--height.

python3 scripts/phosor_client.py submit "A cat walking on a beach at sunset" \
  --model minimax/h3/text-to-video \
  --resolution-tier 768p --aspect 16:9 --duration 5

MiniMax H3 — Image-to-Video

# Upload first (direct URLs are not accepted); then submit with the returned s3_key
python3 scripts/phosor_client.py upload-image /path/to/first-frame.jpg

python3 scripts/phosor_client.py submit "The person starts dancing" \
  --model minimax/h3/image-to-video \
  --image-url "images/img-xxx.jpg" \
  --end-image-url "images/img-yyy.jpg" \
  --resolution-tier 480p --aspect 9:16 --duration 6

--end-image-url is optional and pins the closing frame.

MiniMax H3 — Reference-to-Video (Ref2VA)

Feed reference images, videos, and audio together; refer to them positionally in the prompt as , , … At least one of --reference-image-urls / --reference-video-urls is required.

python3 scripts/phosor_client.py submit \
  "Use  and  as sequential keyframes; slow push-in, cinematic 35mm look." \
  --model minimax/h3/reference-to-video \
  --reference-image-urls "images/a.jpg,images/b.jpg" \
  --reference-audio-urls "audio/voice.mp3" \
  --resolution-tier 768p --aspect 16:9 --duration 5

Reference inputs are billed on top of the output — see Ref2VA Pricing below, and Ref2VA Reference Limits for the per-tier caps (they differ between 480p and 768p).

Text-to-Video (Wan)

Wan is frame-based. Add /turbo to the model id for the fast, ~3x cheaper variant (it ignores --steps / --guidance).

# Submit T2V job (480p, 81 frames, 16fps)
python3 scripts/phosor_client.py submit "A cat walking on a beach at sunset" \
  --width 854 --height 480 --num-frames 81 --fps 16

# Check status
python3 scripts/phosor_client.py status 

# Get result (video URL)
python3 scripts/phosor_client.py result 

Image-to-Video

Two-step flow: upload image first, then submit with the returned S3 key.

# Step 1: Upload image
python3 scripts/phosor_client.py upload-image /path/to/photo.jpg
# Returns: {"file_id": "img-xxx", "s3_key": "images/img-xxx.jpg", ...}

# Step 2: Submit I2V job using the s3_key as image_url
python3 scripts/phosor_client.py submit "The person in the photo starts dancing" \
  --image-url "images/img-xxx.jpg" --width 854 --height 480

Text-to-Image

# Submit T2I job (1024x1024, default settings)
python3 scripts/phosor_client.py submit "A futuristic city skyline at dusk" \
  --model qwen-image/v2512/text-to-image --width 1024 --height 1024

# Generate multiple images at once (1-4)
python3 scripts/phosor_client.py submit "A futuristic city skyline at dusk" \
  --model z-image/turbo/text-to-image --width 1024 --height 768 --num-images 4

# Check status and get result (image URL)
python3 scripts/phosor_client.py status 
python3 scripts/phosor_client.py result 
# Returns: {"data": {"image": {"url": "..."}, "seed": 12345}, ...}

Image-to-Image

Two-step flow: upload source image first, then submit with the returned S3 key.

# Step 1: Upload source image
python3 scripts/phosor_client.py upload-image /path/to/photo.jpg
# Returns: {"file_id": "img-xxx", "s3_key": "images/img-xxx.jpg", ...}

# Step 2: Submit I2I job using the s3_key as image_url
python3 scripts/phosor_client.py submit "Transform into oil painting style" \
  --model z-image/turbo/image-to-image --image-url "images/img-xxx.jpg" \
  --width 1024 --height 1024 --strength 0.7

Image Edit (Multi-image Reference)

Two-step flow: upload reference images first, then submit with S3 keys as image_urls.

# Step 1: Upload reference images (up to 3)
python3 scripts/phosor_client.py upload-image /path/to/ref1.jpg
python3 scripts/phosor_client.py upload-image /path/to/ref2.jpg

# Step 2: Submit image-edit job
python3 scripts/phosor_client.py submit \
  "The girl in image 1 is wearing the outfit from image 2" \
  --model qwen-image/v2511/image-edit \
  --image-urls '["images/img-ref1.jpg","images/img-ref2.jpg"]' \
  --width 1024 --height 1024

# Turbo variant (faster, Lightning LoRA built-in)
python3 scripts/phosor_client.py submit \
  "The girl in image 1 is wearing the outfit from image 2" \
  --model qwen-image/v2511/image-edit \
  --image-urls '["images/img-ref1.jpg","images/img-ref2.jpg"]'

Speech-to-Video (S2V)

Two-step flow: upload both audio and reference image first, then submit with the returned S3 keys.

# Step 1: Upload reference image
python3 scripts/phosor_client.py upload-image /path/to/face.jpg
# Returns: {"file_id": "img-xxx", "s3_key": "images/img-xxx.jpg", ...}

# Step 2: Submit S2V job using the s3_key as image_url and audio URL as audio_url
python3 scripts/phosor_client.py submit "A person speaking naturally" \
  --model wan/v2.2-a14b/speech-to-video \
  --image-url "images/img-xxx.jpg" --audio-url "https://example.com/speech.wav" \
  --width 854 --height 480

Animate

Two-step flow: upload both source video and reference image first, then submit.

# Step 1: Upload reference image
python3 scripts/phosor_client.py upload-image /path/to/character.jpg
# Returns: {"file_id": "img-xxx", "s3_key": "images/img-xxx.jpg", ...}

# Step 2: Submit Animate job using the s3_key as image_url and video URL as video_url
python3 scripts/phosor_client.py submit "The character performs the dance moves" \
  --model wan/v2.2-a14b/animate \
  --image-url "images/img-xxx.jpg" --video-url "https://example.com/dance.mp4" \
  --width 854 --height 480

Text-to-Image (GPT Image 2)

Its own resolution set and always exactly 1 image (--num-images is ignored).

python3 scripts/phosor_client.py submit "A ceramic mug on a linen cloth, soft window light" \
  --model openai/gpt-image-2/text-to-image --width 1024 --height 1024

Allowed sizes: 1024×1024 only. Any other size is rejected with 400 Invalid parameters. It ignores --num-images, --steps and --guidance — the only parameters it accepts are prompt, model, width, height and seed.

Text-to-Image (FLUX.2-dev)

FLUX.2-dev has its own resolution whitelist and is fixed at 1 image per request (--num-images and --steps are ignored).

python3 scripts/phosor_client.py submit "Editorial product photo, soft window light" \
  --model flux2/dev/text-to-image --width 2048 --height 1536

Image Edit (FLUX.2-dev)

python3 scripts/phosor_client.py upload-image /path/to/source.jpg

python3 scripts/phosor_client.py submit "Replace the background with a marble surface" \
  --model flux2/dev/image-edit --image-url "images/img-xxx.jpg" \
  --width 1024 --height 1024

Text-to-Speech

TTS takes text (not a prompt) and is billed per character with a minimum charge.

python3 scripts/phosor_client.py submit-tts "Hello, welcome to Phosor AI." \
  --speaker Sohee --language English

LoRA Upload (Custom Pre-trained)

Video LoRA requires two .safetensors files (high_noise + low_noise). Image LoRA requires a single .safetensors file.

# Video LoRA: upload two .safetensors files
python3 scripts/phosor_client.py upload-lora high_noise.safetensors low_noise.safetensors --name "My Style"

# Image LoRA: import single .safetensors file via URL
python3 scripts/phosor_client.py import-lora \
  "https://example.com/my_lora.safetensors" \
  --name "My Image Style"

# Video LoRA: import two files via URL
python3 scripts/phosor_client.py import-lora \
  "https://example.com/high_noise.safetensors" \
  "https://example.com/low_noise.safetensors" \
  --name "My Video Style"

# Check status, then use
python3 scripts/phosor_client.py lora-status 
python3 scripts/phosor_client.py submit "A person walking" --lora-id 

CLI Commands

CommandDescriptionKey Arguments
check-keyValidate API key
submitSubmit inference job (T2V/I2V/S2V/Animate/T2I/I2I)prompt, --width, --height, --num-frames, --fps, --steps, --guidance, --image-url, --audio-url, --video-url, --lora-id, --lora-scale, --loras, --seed, --negative-prompt, --model, --num-images, --strength, --output-format
statusGet job statusrequest_id
resultGet job result (video or image URL)request_id
pollPoll all pending jobs
listList locally tracked pending jobs
historyGet job history--limit
upload-imageUpload image for I2V or I2Ifile
import-imageImport image from URLurl, --filename
upload-loraUpload LoRA (two .safetensors for video)high_noise_file, low_noise_file, --name
import-loraImport LoRA from URLs (one or two files)high_noise_url, [low_noise_url], --name
lorasList LoRA models--limit, --offset
lora-statusGet LoRA upload/import statuslora_id
save-loraActivate a LoRA (extends expiry to 7 days)lora_id, --name
delete-loraDelete a LoRA modellora_id
submit-ttsSubmit a text-to-speech job (Qwen3-TTS) — keys off text, not a prompttext, --speaker, --language, --seed, --temperature, --top-p, --top-k, --repetition-penalty
modelsList available video/image models (static offline reference)
studio-featuresList Image Studio endpoints, fields, billing (static offline reference)
studio-pricingGet live Image Studio pricing
studio-analyzeAI-analyze a product/garment image or reference URL (freemium)--target agent|product|model|reference, --image-url, --url, --prompt, --language
studio-layoutsList the layout template library (query, then select) — static asset on the web front (prod phosor.ai / dev :3000), not a /api/v1 endpoint; needs no key; dev auto-falls back :8010:3000--module (product|clothing), --type (selling_point|aplus|white_bg|scene|closeup|size_chart)
studio-suiteGenerate a product image suite--image-url, --layout-types, --count-per-type, --custom-suggestions, --template-ids (ids from studio-layouts, auto-expanded to custom_suggestions like the UI's manual pick — use this to get text-callout selling-point / A+ layouts and model templates), --product-info, --aspect-ratio, --gen-language, --model, --same-style-reference
studio-clothing-suiteGenerate a model/garment image suite--image-urls, --main-image-types, --aplus-types, --product-info, --brand-config, --aspect-ratio, --gen-language, --model, --same-style-reference
studio-statusGet Image Studio job status (separate id space, same request_id key)request_id
studio-cancelCancel a running generation — queued images refunded, already-generating ones chargedrequest_id
studio-my-worksList past Image Studio generations--task-type, --limit, --offset
studio-callGeneric call for any other Image Studio endpoint (remove-bg, replace, inpaint, erase, handheld, translate, outpaint, recolor, enhance, upscale, scene-compose, scene-variation, real-model-swap, mannequin-swap, model-scene-swap, ai-outfit, pose-variation, ai-wearable)method, path, --json

Image Studio (Product & Model Photography)

Image Studio is a separate product surface for e-commerce sellers — AI product photography and model/clothing photography — reached through the same gateway and API key as video/LoRA, under the /api/v1/image-studio prefix. It has its own async namespace - the same key name request_id, but a separate id space: an Image Studio request_id is not valid on /api/v1/inference/status/... and vice versa - and its own pricing (flat per-image rate + freemium analyze quota, not per-frame). Full endpoint/parameter reference: references/api.md.

Quick Start: Product Suite

# 1. Upload the product photo
python3 scripts/phosor_client.py upload-image /path/to/product.jpg
# Returns: {"file_id": "img-xxx", "s3_key": "images/img-xxx.jpg", ...}

# 2. (Optional) AI-analyze it first for richer generation context
python3 scripts/phosor_client.py studio-analyze --target product --image-url "images/img-xxx.jpg"

# 3. Generate a product image suite
python3 scripts/phosor_client.py studio-suite --image-url "images/img-xxx.jpg" \
  --layout-types "white_background,lifestyle_scene" --count-per-type 2

# 4. Poll for the result
python3 scripts/phosor_client.py studio-status 

Quick Start: Clothing/Model Suite

python3 scripts/phosor_client.py upload-image /path/to/garment.jpg
python3 scripts/phosor_client.py studio-clothing-suite \
  --image-urls "images/img-xxx.jpg" \
  --main-image-types '{"model_shot":2,"selling_point":1}' \
  --aplus-types '{"standard_aplus":1}'
python3 scripts/phosor_client.py studio-status 

Quick Start: One-off Edits (remove-bg, inpaint, translate, etc.)

The long tail of single-purpose editing endpoints doesn't get a dedicated subcommand — use studio-call with the exact field names from references/api.md:

python3 scripts/phosor_client.py studio-call POST /product/remove-bg \
  --json '{"image_url": "images/img-xxx.jpg", "count": 2}'
python3 scripts/phosor_client.py studio-status 

Key facts

  • Every Image Studio call requires X-API-Key (PHOSOR_API_KEY), including GET /pricing — there is no unauthenticated endpoint under this prefix.
  • All generation/analyze endpoints are async: POST returns {"request_id": "...", "status": "pending"}; poll studio-status until status is "done", "error" or "cancelled". Earlier revisions of this skill said the key was job_id - it is not, and reading it yields undefined. Image Studio ids live in a separate id space from video/LoRA: poll/status/result will not accept an Image Studio request_id.
  • Cancelling: POST /jobs/{request_id}/cancel stops a running generation. Images still queued are refunded; images already generating are charged and cannot be stopped; images already delivered bill once through the normal path. The response reports the split as refunded_queued, charged_running and already_done, and the task then polls as status: "cancelled" - not an error.
  • Pricing is per-image, not per-frame: call studio-pricing for the live rate. Partial success (e.g. 3 of 5 images) bills only the successes.
  • Analyze is freemium: agent/analyze, product/analyze, model/analyze share a daily free quota before per-call billing kicks in.
  • model_attrs matters for model-photography endpoints (real-model-swap, mannequin-swap, ai-outfit, ai-wearable) — pass {gender, age_group, ethnicity, skin_tone, hair_color} explicitly; it is not reliably inferred from the source image alone.
  • Run studio-features for the full offline endpoint/field catalog without leaving the terminal.

Key Constraints

Video Resolutions (exact pairs only)

PresetWidth × HeightMax Frames (turbo)Max Frames (standard)
480p landscape854 × 480161161
480p portrait480 × 854161161
720p landscape1280 × 720161161
720p portrait720 × 1280161161
1080p landscape1920 × 108015381
1080p portrait1080 × 192015381

Standard (non-turbo) mode: 1080p is capped at 81 frames due to generation time limits.

S2V / Animate Video Resolutions (exact pairs only)

PresetWidth x HeightMax Frames
480p landscape854 x 480161
480p portrait480 x 854161
512p square512 x 512161
720p landscape1280 x 720161
720p portrait720 x 1280161

Image Resolutions (exact pairs only)

PresetWidth × Height
Square small512 × 512
Square1024 × 1024
Landscape1024 × 768
Portrait768 × 1024
Wide landscape1280 × 768
Tall portrait768 × 1280

MiniMax H3 Frame Sizes (--resolution-tier + --aspect)

Tier16:94:31:13:49:16
480p832 × 480640 × 480480 × 480480 × 640480 × 832
768p1344 × 7681024 × 768768 × 768768 × 1024768 × 1344

duration is 4–15 seconds (default 5). Output FPS is fixed at 24 and frames_per_second is ignored.

Ref2VA Reference Limits (minimax/h3/reference-to-video)

Caps differ per tier, and the image cap is higher when you send only images:

Limit480p768p
Reference images (with videos/audio present)42
Reference images (images only)94
Reference videos31
Reference audios33
LimitValue
Total reference video length6.5 s (across all reference videos)
Reference video FPS ceiling24
Reference audio length10 s each
Reference image longest edge2048 px
Reference image aspect ratio≤ 4.0

FLUX.2-dev Resolutions (exact pairs only)

Width × Height
2048 × 1536 · 1536 × 2048
2048 × 1152 · 1152 × 2048
2048 × 2048 · 1024 × 1024

FLUX.2-dev does not accept the general image resolution list above, and always returns exactly 1 image.

Frame Alignment (video only)

Frames must follow 1 + 4*k where k >= 1 (e.g. 5, 9, 13, ... 81, 85, ...). Server auto-aligns down.

Video Inference Parameters

ParameterDefaultRange
frames_per_second164–60
num_inference_steps44–40
guidance_scale1.01.0–10.0

Image Inference Parameters

ParameterDefaultRangeNotes
num_images11–4Number of images to generate
num_inference_stepsvaries1–4 (z-image turbo), 1–40 (qwen-image)Model-dependent max
guidance_scalevaries1.0–20.0
strength0.0–1.0Image-to-image only: how much to transform the source
output_formatpngpng, jpegOutput file format

Concurrency

Model API inference jobs run concurrently up to a per-account cap; over it the submit returns 429 and you retry after a job finishes.

TierPlanConcurrent Model API jobs
Free1
1Starter2
2Standard4
3Pro8

Image Studio runs on its own pool and does not consume this quota — a suite and a video generation can run at the same time.

Multiple LoRAs

python3 scripts/phosor_client.py submit "A person dancing" \
  --loras '[{"lora_id": "lora-abc", "lora_scale": 0.8}, {"lora_id": "lora-def", "lora_scale": 0.5}]'

Two-Step Upload Rule

Files must be uploaded before use — direct URLs are NOT supported in submit --image-url:

  1. Imageupload-image / import-image → returns s3_key → use as --image-url
  2. LoRAupload-lora / import-lora → returns lora_id → use as --lora-id

Queue Flow

PENDING → PROCESSING → COMPLETED / FAILED

The poll command checks all locally-tracked pending jobs and removes completed/failed ones.

MiniMax H3 Pricing (per output second)

TierUSD/secCredits/sec
480p$0.020.2
768p$0.040.4

Ref2VA Pricing (minimax/h3/reference-to-video)

Billed in two parts — the output plus the reference inputs:

total = duration x base_rate
      + reference_images x $0.010
      + reference_audios x $0.010
      + reference_video_seconds x base_rate
TierBase USD/secReference imageReference audioReference video USD/sec
480p$0.025$0.010 each$0.010 each$0.025
768p$0.063$0.010 each$0.010 each$0.063

Example — 5s at 768p with 4 reference images: 5 x $0.063 + 4 x $0.010 = $0.355 (3.55 credits).

Ref2VA's base rate is higher than plain H3 T2V/I2V — do not reuse the table above for it.

Wan Video Pricing (per frame)

TierStandard+ LoRATurbo
480p$0.0009375$0.00125$0.0003125
512p$0.0013125$0.001625$0.0004375
720p$0.001875$0.0021875$0.000625
1080p$0.0025$0.003$0.0010938

LoRA multiplier on turbo: 1.2x.

S2V Pricing (per frame)

TierCost
480p$0.0009375
512p$0.0013125
720p$0.001875

Animate Pricing (per frame)

TierCost
480p$0.00125
512p$0.00175
720p$0.0025

Image Pricing (per image)

ModelUSDCredits
GPT Image 2 T2I$0.030.3
FLUX.2-dev T2I$0.0060.06
FLUX.2-dev Image Edit$0.0120.12
qwen-image T2I$0.0150.15
qwen-image T2I + LoRA$0.0180.18
qwen-image-edit$0.0030.03
z-image turbo (T2I / I2I)$0.00250.025
z-image turbo + LoRA$0.0030.03

Flat per image at every resolution. Multiply by num_images (1–4) where the model supports it; FLUX.2-dev is fixed at 1 image per request.

Audio Pricing

ItemCost
Qwen3-TTS$0.00003 per character
Minimum charge$0.003 per request

Exchange rate: 10 credits = $1 USD. Credits pre-deducted, auto-refunded on failure. Live rates: GET /api/v1/pricing/config — always prefer it over any table here.

Questions people ask

Do I need to upload images before submitting I2V, I2I, image-edit, S2V, or animate jobs?
Yes. Run upload-image (or import-image from a URL) and pass the returned s3_key into submit. The doc also notes that studio-analyze / studio-suite --image-url must be the full https S3 URL returned by upload-image, not the bare S3 key, otherwise it errors with unsupported URL scheme.
Can I bring my own LoRA, and how does it differ for image vs video?
Yes. Image LoRA is a single .safetensors file; video LoRA requires two files (high_noise + low_noise). Use upload-lora or import-lora, then pass --lora-id to submit; save-lora extends its expiry to 7 days.
Is the dev environment a different API from production?
No — endpoints, parameters, and payloads are identical. Only the base URL and scheme change; prod is HTTPS at phosor.ai, dev uses HTTP and requires --allow-http or PHOSOR_ALLOW_HTTP=1 (localhost / 127.0.0.1 needs no flag).

Related skills

Turn one product photo into a vertical product video that speaks. This AI product video generator and product video maker builds ecommerce product videos, product ads, and commerce short videos from a single photo — composing a 9:16 opening frame, writing a short script from what the photo shows and the details you supply, voicing it with a selected narrator, and directing one finished clip ready to post. Use it for product launches, listing videos, shoppable social posts, storefront promos, and turning a phone snap of merchandise into a video that sells, with no shoot, no crew, and no editing.

Generate videos using the Volcengine Doubao Seedance 2.0 model series.

3 installs

Generate and edit images from text or references using routed AI models, with character consistency and product photography support.

539 installs10 stars

Generate AI images and videos using top-tier models including Sora 2, Kling 2.6, Seedance 2.0, Nano Banana Pro, Veo 3.1 and more. Supports text-to-image, tex...

31 installs