# youcam-cli

`youcam` 是 [YouCam AI API](https://yce.perfectcorp.com/ai-api) 的命令行工具。它的每一项 AI 功能——人脸与身体编辑、发型、测肤、美妆、虚拟试穿、背景与照片编辑、图像与 AI 视频生成器等等——都能在终端里跑，用的模型和参数与 API 完全一致。此外还能查任务状态、浏览预置模板、查看点数和各功能的花费。

不管是评估功能、做集成开发，还是自动化流水线，这个 CLI 都使得上：

- **评估 YouCam API 的 AI 功能**：拿自己的照片跑功能、看结果，比如比较风格、验证功能合不合产品。一行代码都不用写。
- **集成 API**：写代码之前，先在终端里把任意接口试一遍。命令行选项与请求字段一一对应，每个功能都链到它的 [API 参考文档](#available-ai-features)。
- **AI 智能体**：Claude Code、Cursor、Codex 等智能体可以把任何 YouCam 功能当成普通 shell 命令来用。所有命令都输出 JSON，失败时以退出码 1 退出；每个功能和选项在 `--help` 里都有自说明；非法取值在发出请求之前就会被拦下。
- **自动化与批处理**：在 shell 脚本、CI 流水线、容器里，对整文件夹的商品图、人像批量跑功能。本地文件由 CLI 代为上传，脚本里不用写上传这一步。


## 环境要求

- **[Node.js](https://nodejs.org/) 18 或以上**（以及 npm）。
- 一个 [YouCam API 密钥](https://yce.perfectcorp.com/api-console/en/api-keys/)。


## 安装

```bash
npm install -g @youcam_cli/youcam-cli

# Verify the installation
youcam --help

# Version of the YouCam CLI
youcam --version
```

卸载请执行 `npm uninstall -g @youcam_cli/youcam-cli`。

## 鉴权

用 `youcam auth login <apiKey>` 存一次 API 密钥，密钥就保存在本地，之后每条命令都会自动沿用。

```bash
youcam auth login <apiKey>

# or explicitly with a flag
youcam auth login --api-key <apiKey>

# Remove the saved API key (logout CLI tool)
youcam auth logout

# List the available authentication options
youcam auth --help
```

`auth login` 会把密钥写进一个明文 JSON 文件，`~/.youcam-cli/credentials.json`：

```json
{
  "apiKey": "<your-api-key>"
}
```

- 每条 `run`、`status`、`template`、`client` 命令都会自动读这个文件。
- 设置了 `YOUCAM_CLI_API_KEY` 环境变量时，它的优先级高于已保存的密钥。


## 快速上手

从查点数到下载结果，跑通您的第一个 AI 任务。这会真实跑一个任务，因此会消耗点数（见[查询功能花费](#checking-feature-cost)）。

YouCam 的每个功能都以后台任务的方式运行：启动任务，拿到一个 `task_id`，然后查这个 `task_id`，直到结果就绪。

**1. 安装并登录**（细节见[安装](#installation)与[鉴权](#authentication)）

```bash
npm install -g @youcam_cli/youcam-cli
youcam auth login <apiKey>
```

**2. 查看点数**

```bash
youcam client credit
```

响应：

```json
{
  "status": 200,
  "results": [
 {
 "id": 0,
 "type": "ApiPaygToken",
 "amount": 8193,
 "amount_dec": 8193,
 "expiry": 1801958399000
 }
  ]
}
```

`amount` 是每一项里剩余的点数，`expiry` 是它们的到期时间（自 Unix 纪元起的毫秒数）。这条命令之所以叫 `credit`，是因为 API 把「点」称为 "credit"（见[点数与功能花费](#units-and-feature-cost)）。

**3. 启动任务**

下面这条命令用 [AI 照片优化](/reference/ai_photo_enhance/v1.0/paths/~1s2s~1v2.0~1task~1enhance/post) 把一张示例照片放大到 2 倍分辨率：

```bash
youcam run enhance --src_file "https://plugins-media.makeupar.com/strapi/assets/hair_color_03_81c0c8a3c8.jpg" --scale 2
```

响应：

```json
{
  "status": 200,
  "data": {
 "task_id": "32tu4jQvRbI9NfnKlw13cls8tyT1zA2ZoOtKq-RkiTL_FrIEOLYHJX1HxYVrnWz"
  }
}
```

CLI 还会顺手打印下一步要用的命令。它输出到 stderr，这样 stdout 保持纯净的 JSON，方便脚本处理：

```
Run `youcam status enhance 32tu4jQvRbI9NfnKlw13cls8tyT1zA2ZoOtKq-RkiTL_FrIEOLYHJX1HxYVrnWz` to check the result.
```

想用自己的照片，传本地路径即可，例如 `--src_file ./photo.jpg`。

**4. 查看并下载结果**

```bash
youcam status enhance <task_id>
```

任务还在处理时，`task_status` 是 `running`；过几秒再跑一次这条命令。任务完成后：

```json
{
  "status": 200,
  "data": {
 "error": null,
 "results": {
 "url": "https://yce-us.s3-accelerate.amazonaws.com/ttl30/.../509f8acd-8d41-4459-aa31-1d4738d7a922.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&...&X-Amz-Expires=7200&..."
 },
 "task_status": "success"
  }
}
```

`results.url` 就是增强后的图片。它是一个签名链接，2 小时后失效（`X-Amz-Expires=7200`），请尽快下载。

**下一步**

- 浏览[可用的 AI 功能](#available-ai-features)，并用 `youcam run <feature> --help` 查看某个功能有哪些选项。
- 在[运行 AI 任务](#running-an-ai-task)里了解选项、文件与 JSON 参数怎么用。
- 有些功能要先做人脸或人体检测，见[预处理](#pre-process-face-and-body-detection)。


## 点数与功能花费

点数是用 YouCam API 的花费单位，每个 AI 功能消耗的点数各不相同。API（因而 CLI 也是）把点数称为 "credit"，所以命令叫 `client credit` 和 `client credit-history`。详见官方 FAQ 里的[「点数（Unit）是什么意思，怎么用？」](/develop/faq)。

### 查看点数

```bash
youcam client credit  # remaining units
youcam client credit-history  # unit usage history
```

### 查询功能花费

在大批量跑之前，先查清某个功能要吃多少点数。

```bash
youcam client feature-cost
```

这两条命令都支持用 `--page_size` 和 `--starting_token <token>` 翻页：

- `credit-history`：`--page_size <1-30>`，默认 20。
- `feature-cost`：`--page_size <1-20>`，默认 20。


> 说明：[预处理](#pre-process-face-and-body-detection)检测任务与[列出预置模板](#listing-predefined-templates)不消耗点数。


## 命令一览

```
youcam <command> [options]

Commands:
  auth Manage authentication credentials
  run  Run an AI task
  status  Check the status of an AI task
  template   List predefined templates
  client  Get account/credit info
  help Display help for a command
```

每条命令和子命令都支持 `-h, --help`，用来查看自己的用法和选项：

```bash
youcam run --help
youcam run face-swap --help
```

结果以 JSON 输出。请求失败时，命令以退出码 1 退出。

## API 与 CLI 命令对照

API 参考文档里的每个接口，都能有规律地换算成一条CLI命令:

| REST 接口 | CLI 命令 |
|  --- | --- |
| `POST /s2s/v{ver}/task/{feature}` | `youcam run <feature> [options]` |
| `GET /s2s/v{ver}/task/{feature}/{task_id}` | `youcam status <feature> <task_id>` |
| `POST /s2s/v{ver}/task/{feature}/pre-process` | `youcam run pre-process <feature> [options]` |
| `GET /s2s/v{ver}/task/{feature}/pre-process/{task_id}` | `youcam status pre-process <feature> <task_id>` |
| `GET /s2s/v{ver}/task/template/{feature}` | `youcam template <feature> [--page_size] [--starting_token]` |
| 公开的 makeup-vto 图案目录 | `youcam template makeup-vto <categories...>` |
| `GET /s2s/v1.0/client/credit` | `youcam client credit` |
| `GET /s2s/v1.0/client/credit/history` | `youcam client credit-history [--page_size] [--starting_token]` |
| `GET /s2s/v2.0/credit/feature-cost` | `youcam client feature-cost [--page_size] [--starting_token]` |
| `POST /s2s/v2.0/file` + 预签名 `PUT` 上传 | 文件选项是本地路径时自动完成（见[上传文件](#uploading-files)） |


从 API 参考文档推导 `<feature>` 的几条经验：

- CLI 的功能名就是 `{task_id}` 前面那一段路径，例如 `/s2s/v2.0/task/abs-shape/{task_id}` → `abs-shape`。
- API 版本前缀（`v2.0`、`v2.1` 等）不用您操心：每条命令都会调用API 参考文档里的最新 API 版本，例如 `skin-analysis` 和 `hair-transfer` 走的是 `/s2s/v2.1/...`。某功能有多个引擎版本时，只给最新的，例如提供 `cloth-v4`，不提供 `cloth-v3`。
- 少数接口多一段路径，去掉那一段就是 CLI 名：
| API 路径 | CLI 命令 |
|  --- | --- |
| `/s2s/v2.0/task/2d-vto/earring`（`necklace`、`ring`、`bracelet`、`watch` 同理） | `youcam run earring` |
| `/s2s/v2.0/task/image-to-image/youcam`、`/text-to-image/youcam`、`/image-to-video/youcam`、`/text-to-video/youcam` | `youcam run image-to-image`、`run text-to-image`、`run image-to-video`、`run text-to-video` |
| `/s2s/v2.0/task/colorize/color-correct` | `youcam run color-correct` |
- 请求体的属性，会变成对应 `run` 命令上的 `--<property_name>` 选项（见[上传文件](#uploading-files)与[传 JSON 参数](#passing-json-parameters)）。`page_size`、`starting_token` 这类查询参数同样变成 `--<param_name>` 选项。


以 [AI 发色虚拟试染](/reference/ai_hair_color/v1.0/paths/~1s2s~1v2.0~1task~1hair-color/post) 为例，它的两个接口是：

```
POST /s2s/v2.0/task/hair-color   { src_file_url | src_file_id, preset?, pattern?, palettes? }
GET  /s2s/v2.0/task/hair-color/{task_id}
```

对应到这两条 CLI 命令：

```bash
youcam run hair-color --src_file <url-or-path> [--preset <value> | --pattern <json> --palettes <json>]
youcam status hair-color <task_id>
```

套用预设发色：

```bash
youcam run hair-color --src_file "https://plugins-media.makeupar.com/strapi/assets/hair_color_09_76a7a1081e.jpg" --preset "Honey Blonde"
youcam status hair-color <task_id>
```

`run` 命令发出的请求体是：

```json
{
  "src_file_url": "https://plugins-media.makeupar.com/strapi/assets/hair_color_09_76a7a1081e.jpg",
  "preset": "Honey Blonde"
}
```

想改用自定义颜色，就传 `pattern` 和 `palettes` 两个对象：

```bash
youcam run hair-color --src_file "https://plugins-media.makeupar.com/strapi/assets/hair_color_09_76a7a1081e.jpg" \
  --pattern '{"name": "full"}' \
  --palettes '[{"color": "#8B4513", "color_intensity": 80, "shine_intensity": 50}]'
youcam status hair-color <task_id>
```

等价的 JSON 请求体是：

```json
{
  "src_file_url": "https://plugins-media.makeupar.com/strapi/assets/hair_color_09_76a7a1081e.jpg",
  "pattern": { "name": "full" },
  "palettes": [{ "color": "#8B4513", "color_intensity": 80, "shine_intensity": 50 }]
}
```

`youcam run` 会打印新的 `task_id`；把它交给 `youcam status`，反复查询，直到 `task_status` 变成 `success`。

## 运行 AI 任务

每个 AI 功能都是 `run` 的一个子命令。选项因功能而异，用 `--help` 看这个功能接受哪些输入。

```bash
youcam run <feature> [options]
```

例如跑 [AI 腹肌滤镜](/reference/ai_abs_filter/v1.0/paths/~1s2s~1v2.0~1task~1abs-shape/post)：

```bash
youcam run abs-shape --src_file "https://example.com/photo.jpg" --mode "Six-pack" --intensity 2
```

任务启动后会返回一个 `task_id`，用它[查询状态](#checking-task-status)。

- **预处理：** 少数功能会先检测照片里的人脸或人体，好让您选定要处理哪一个人。见[预处理](#pre-process-face-and-body-detection)。
- **模板：** 一些功能支持用 `--template_id` 直接套用现成的风格预设。见[列出预置模板](#listing-predefined-templates)。
- **校验：** 选项取值会在发出请求之前对照 API 结构校验。取值范围固定的选项会在 `--help` 里把可选值列出来；给了非法值会被拦下，并告诉您允许哪些取值。


## 上传文件

凡是接收图片或视频的功能，都把它收敛成一个 `--src_file` 选项，尽管 API 端是两个互斥字段：`src_file_url`（一个公开 URL）或 `src_file_id`（已上传文件的 ID）。CLI 会根据您传的内容自动选对的那个：

- **可公开访问的 URL** 作为 `src_file_url` 送出，不做任何上传。

```bash
youcam run enhance --src_file "https://example.com/photo.jpg" --scale 2
```
- **本地文件路径** 由 CLI 代为上传，任务用 `src_file_id` 送出：
  1. `POST /s2s/v2.0/file` 登记文件（名称、内容类型、大小），返回一个预签名上传地址和一个 `file_id`。
  2. 把文件内容 `PUT` 到那个预签名地址。
  3. 调用 `run <feature>` 时，把 `src_file_id` 设为这个 `file_id`。

```bash
youcam run enhance --src_file ./photo.jpg --scale 2
```
在 PowerShell 或 cmd 里，Windows 路径一样能用：

```powershell
youcam run enhance --src_file .\photo.jpg --scale 2
```


补充说明：

- 本地文件必须是 `.jpg`、`.jpeg`、`.png` 或 `.mp4`。
- 大小、分辨率、时长上限因功能而异；文件超限会让任务失败，`status` 里给出 `exceed_max_filesize`。
- 没有单独的上传命令，上传只通过文件选项发生。


### 其他文件选项

除了 `--src_file`，有些功能还要额外的图片（蒙版、参考照、商品图）。规则一样：传公开 URL 或本地路径，本地路径由 CLI 代为上传。

| 选项 | 是什么 | 取值数量 | 哪些功能在用 |
|  --- | --- | --- | --- |
| `--src_file <input>` | 主要的源图片或视频 | 单个 | 多数功能 |
| `--src_files <inputs...>` | 多张源图片 | 多个 | `hair-frizziness-detection`、`hair-type-detection`、`image-to-image` |
| `--ref_file <input>` | 要参照的图片（例如某个妆容、一套衣服、一件商品） | 单个 | `bag`、`cloth-v4`、`eye-color-vto`、`hair-transfer`、`hat`、`mu-transfer`、`ai-nail`、`scarf`、`shoes-transfer`、`bg-replace-vid`、`face-swap-vid` |
| `--ref_files <inputs...>` | 多张参考图（例如每个目标各一张脸、商品图） | 多个 | `bracelet`、`earring`、`face-swap`、`nail-vto`、`necklace`、`ring`、`watch` |
| `--msk_file <input>` | 源图上的蒙版：白色是要改的区域，黑色保持原样 | 单个 | `generative-fill`、`obj-replace`、`obj-rem-vid` |
| `--srcmsk_file <input>` | 在源图中框出相关部位的蒙版（例如耳朵、颈部、手腕） | 单个 | `bracelet`、`earring`、`necklace`、`ring`、`watch` |
| `--refmsk_files <inputs...>` | 与每个 `--ref_files` 逐项对应的蒙版，顺序一致 | 多个 | `bracelet`、`earring`、`ring`、`watch` |


带 `...` 的选项，是在一个选项名后面跟多个值，用空格分隔（不是逗号）：

```bash
youcam run face-swap \
  --src_file group-photo.jpg \
  --ref_files person-a.jpg person-b.jpg \
  --face_mapping '[{"index":0,"position":0},{"index":1,"position":1}]'
```

如果一个多值选项里混着公开 URL 和本地路径，例如 `--ref_files https://example.com/a.jpg ./b.jpg`，那么里面每个文件都会被上传，URL 也一样：CLI 会先把每个 URL 下载下来，当作本地文件上传，最后全部以文件 ID（例如 `ref_file_ids`）送出。这些 URL 指向的必须是 JPG、PNG 或 MP4。想让 URL 以 URL 的形式送出，那个选项里就只传 URL。

运行 `youcam run <feature> --help`，可以看到这个功能具体接受上面哪几项。

## 选项写法

下面这几种写法等价，随您喜欢哪种：

```bash
youcam run skin-simulation --src_file https://example.com/face.png --acne 1
youcam run skin-simulation --src_file=https://example.com/face.png --acne=1
youcam run skin-simulation --src_file="https://example.com/face.png" --acne="1"
```

- 只有当值里有空格，或包含 shell 要特殊处理的字符时（例如 URL 里的 `&`，或 JSON），才需要加引号。
- 接收多个值的选项，可以在一个选项名后空格分隔地跟上，也可以重复写这个选项名：
  - `--src_files a.jpg b.jpg`
  - `--src_files=a.jpg --src_files=b.jpg`
  - 不能写 `--src_files=a.jpg b.jpg`，这样会被拒绝。


## 传 JSON 参数

在 `--help` 里标成 `<json>`（而不是 `<value>`）的选项，对应 API 请求体里一个 `object` 或 `array` 字段。请把整个结构作为一个 JSON 值传进来：

- 直接写 JSON，例如 `--pattern '{"name":"full"}'`
- 给一个 `.json` 文件的路径，例如 `--effects ./effects.json`
- 用 `-` 从标准输入读 JSON，例如 `cat effects.json | youcam run makeup-vto --src_file photo.jpg --effects -`


**行内 JSON 的引号：**

```bash
# bash / zsh / macOS / Linux / Git Bash: single quotes protect the double quotes
youcam run hair-color --src_file photo.jpg --pattern '{"name":"full"}' --palettes '[{"color":"#8B4513","color_intensity":80,"shine_intensity":50}]'

# Windows PowerShell: escape the inner double quotes
youcam run hair-color --src_file photo.jpg --pattern '{\"name\":\"full\"}' --palettes '[{\"color\":\"#8B4513\",\"color_intensity\":80,\"shine_intensity\":50}]'
```

**嵌套对象与数组：** `hair-color` 的 `--pattern` 是一个 `object`，`--palettes` 是一个由 `{color, color_intensity, shine_intensity}` 对象组成的 `array`（全头模式 1 个，渐层模式 2 个）：

```bash
youcam run hair-color \
  --src_file photo.jpg \
  --pattern '{"name":"full"}' \
  --palettes '[{"color":"#FF5733","color_intensity":80,"shine_intensity":50}]'
```

`photo.jpg` 上传完成、解析成 `src_file_id` 之后，CLI 会向 `POST /s2s/v2.0/task/hair-color` 发出这个请求体：

```json
{
  "src_file_id": "<file_id from the upload>",
  "pattern": {
 "name": "full"
  },
  "palettes": [
 {
 "color": "#FF5733",
 "color_intensity": 80,
 "shine_intensity": 50
 }
  ]
}
```

每个 `--<option> <json>` 的值都原样作为该属性的值使用：`--pattern` 就是 `pattern` 对象，`--palettes` 就是 `palettes` 数组。不改名、不重排，也不给您没传的选项补默认值。

**深层嵌套数组：** `makeup-vto` 的 `--effects` 是一个特效对象数组，其中一些对象自带 `pattern` 和 `palettes`。多行 JSON 完全没问题：

```bash
youcam run makeup-vto --src_file photo.jpg --effects '[
  {"category":"skin_smooth","skinSmoothStrength":55,"skinSmoothColorIntensity":45},
  {"category":"blush","pattern":{"name":"1color1"},"palettes":[
 {"color":"#e19f9f","texture":"matte","colorIntensity":60}
  ]}
]'
```

`1color1` 这类图案名来自 `youcam template makeup-vto`（见[列出 makeup-vto 图案名](#listing-makeup-vto-pattern-names)）。

JSON 不合法，或者值的类型不对，请求发出前就会被拦下，并点名出问题的字段，例如 `Invalid value for --palettes: [{"color":123}] (0.color: Invalid input: expected string, received number)`。

## 查询任务状态

```bash
youcam status <feature> <task_id>
# or
youcam status <feature> --task_id <task_id>
```

例如：

```bash
youcam status abs-shape 1234567890abcdef
```

请轮询到 `task_status` 为 `success`（或 `error`）为止；届时响应里就带上结果，例如输出文件的 URL。预处理任务请用 `youcam status pre-process <feature> <task_id>`。

## 预处理（人脸与人体检测）

> 预处理任务不消耗点数，只有主任务消耗。


下面这些功能，一张照片里可能有多个人，需要您选定处理哪一个。`youcam run pre-process <feature>` 会检测照片里的人脸或人体，并以列表返回。列表里每一项按位置编号：第 1 个是 `0`，第 2 个是 `1`，依此类推。

1. 检测：`youcam run pre-process <feature> --src_file <photo>` 返回一个 `task_id`。
2. 读检测结果：`youcam status pre-process <feature> <task_id>` 会列出检测到的脸或人体。列表的形态因功能而异：`body-reshape` 返回 `results.result[]`，框以图片尺寸为基准（`0`–`1`）；`face-swap` 返回 `results.faces[].bbox`，是像素坐标的 `[x1, y1, x2, y2]`（左上角与右下角）。
3. 在同一张照片上运行该功能，用下表里的选项把选中的编号传进去：


| 功能 | 接收人脸/人体编号的选项 |
|  --- | --- |
| `body-reshape` | `--index <number>` |
| `face-lift` | `--index <number>` |
| `face-reshape` | `--index <number>` |
| `fitzpatrick-scale-analyzer` | `--index <number>` |
| `teeth-whiten` | `--index <number>` |
| `face-swap` | 每个 `--face_mapping` 条目里的 `"position"`；同一件事条目里的 `"index"` 指定用哪一张 `--ref_files` 图片 |


举例：`youcam run face-lift --src_file <photo> --index 1 ...` 就是对检测到的第 2 张脸做提升。完整流程与真实输出见[示例流程](#example-workflow)。

## 列出预置模板

一些功能自带现成模板（风格或妆效预设），用 `--template_id` 引用即可，不用自己拼参数。

```bash
youcam template <feature> [--page_size <1-20>] [--starting_token <token>]
```

`<feature>` 取以下之一：

| 类别 | 功能 |
|  --- | --- |
| 头发与胡子 | `hair-bang`、`hair-curl`、`hair-ext`、`hair-transfer`、`hair-vol`、`beard-style` |
| 美妆与试穿 | `look-vto`、`fabric` |
| 图像 | `ai-avatar`、`ai-studio`、`headshot`、`bg-replace` |
| 视频 | `video-trans` |


`makeup-vto` 的图案细节，见[列出 makeup-vto 图案名](#listing-makeup-vto-pattern-names)。

示例：

```bash
youcam template ai-avatar --page_size 10
youcam run ai-avatar --src_file ./photo.jpg --template_id <id> --output_count 1
```

把响应里的 `next_token` 作为 `--starting_token` 传入，即可取下一页。

`ai-avatar` 任务成功后，`youcam status ai-avatar <task_id>` 会在 `results.output[].url` 里列出生成的图片，一个输出对应一条。

### 列出 makeup-vto 图案名

`makeup-vto` 的特效按名称挑选形状，例如腮红用 `"pattern":{"name":"1color1"}`，唇色用 `"shape":{"name":"plump"}`。下面列出每种特效类别的可用名称：

```bash
youcam template makeup-vto <categories...>
```

传入 `blush`、`bronzer`、`contour`、`eyebrows`、`eyeliner`、`eyeshadow`、`eyelashes`、`lipshape`、`lipliner`、`highlighter` 中的一个或多个（也可以写成 `--category` 后跟同样的名称）。至少要传一个。这些目录是公开的，列出不消耗点数。

```bash
youcam template makeup-vto blush lipshape
```

结果按类别归组。用条目的 `label` 作为图案名；`colorNum`（仅腮红、眼线、眼影有）表示这个图案需要几组 `palettes`：

```json
{
  "blush": [
 {
 "category": "1 color",
 "label": "1color1",
 "thumbnail": "https://app-cdn-01.makeupar.com/.../a53cd4f4-43b6-4e19-b85a-ec7a95c6a47f.jpg",
 "tags": [
  { "id": 100, "name": "Blush 3D" },
  { "id": 103, "name": "Oblong" }
 ],
 "colorNum": 1
 }
  ],
  "lipshape": [
 {
 "category": "general",
 "label": "original",
 "thumbnail": "https://plugins-media.makeupar.com/wcm-saas/images/lipshapes/original.png",
 "tags": []
 }
  ]
}
```

某个类别取不到时，会给出 `{ "error": "..." }`，命令以退出码 1 退出。

## 可用的 AI 功能

下面这些名称都可以作为 `<feature>` 传给 `run` 和 `status`。每一项都链到它的 API 参考页面。带检测步骤的功能见[预处理](#pre-process-face-and-body-detection)；配合 `youcam template` 使用的功能见[列出预置模板](#listing-predefined-templates)。

### 美妆

- [makeup-vto](/reference/makeup_vto/v1.0/paths/~1s2s~1v2.0~1task~1makeup-vto/post)
  - [图案名](#listing-makeup-vto-pattern-names)
- [mu-transfer](/reference/ai_makeup_transfer/v1.0/paths/~1s2s~1v2.0~1task~1mu-transfer/post)
- [look-vto](/reference/ai_look_vto/v1.0/paths/~1s2s~1v2.0~1task~1look-vto/post)
- [eye-color-vto](/reference/ai_eye_color_lens/v1.0/paths/~1s2s~1v2.0~1task~1eye-color-vto/post)
- [nail-vto](/reference/ai_nail_vto/v1.0/paths/~1s2s~1v2.0~1task~1nail-vto/post)
- [ai-nail](/reference/ai_nail_transfer/v1.0/paths/~1s2s~1v2.0~1task~1ai-nail/post)


### 肤质、面部与身体

- [face-attr-analysis](/reference/ai_face_analyzer/v1.0/paths/~1s2s~1v2.0~1task~1face-attr-analysis/post)
- [skin-analysis](/reference/ai_skin_analysis/)
- [skin-tone-analysis](/reference/ai_skin_tone_analysis/v1.0/paths/~1s2s~1v2.0~1task~1skin-tone-analysis/post)
- [fitzpatrick-scale-analyzer](/reference/ai_fitzpatrick_skin_type/v1.0/paths/~1s2s~1v2.0~1task~1fitzpatrick-scale-analyzer/post)
- [skin-simulation](/reference/ai_skin_simulation/v1.0/paths/~1s2s~1v2.0~1task~1skin-simulation/post)
- [abs-shape](/reference/ai_abs_filter/v1.0/paths/~1s2s~1v2.0~1task~1abs-shape/post)
- [aging](/reference/ai_aging_simulation/v1.0/paths/~1s2s~1v2.0~1task~1aging/post)
- [body-reshape](/reference/ai_body_reshape/v1.0/paths/~1s2s~1v2.0~1task~1body-reshape/post)
- [breast-shape](/reference/ai_breast_augmentation/v1.0/paths/~1s2s~1v2.0~1task~1breast-shape/post)
- [face-lift](/reference/ai_face_lift/v1.0/paths/~1s2s~1v2.0~1task~1face-lift/post)
- [face-reshape](/reference/ai_face_reshape/v1.0/paths/~1s2s~1v2.0~1task~1face-reshape/post)
- [ai-smile](/reference/ai_smile/v1.0/paths/~1s2s~1v2.0~1task~1ai-smile/post)
- [teeth-whiten](/reference/ai_teeth_whitening/v1.0/paths/~1s2s~1v2.0~1task~1teeth-whiten/post)


### 头发与胡子

- [hair-density-detection](/reference/ai_hair_density_detection/v1.0/paths/~1s2s~1v2.0~1task~1hair-density-detection/post)
- [hair-frizziness-detection](/reference/ai_hair_frizziness_detection/v1.0/paths/~1s2s~1v2.0~1task~1hair-frizziness-detection/post)
- [hair-length-detection](/reference/ai_hair_length_detection/v1.0/paths/~1s2s~1v2.0~1task~1hair-length-detection/post)
- [hair-type-detection](/reference/ai_hair_type_detection/v1.0/paths/~1s2s~1v2.0~1task~1hair-type-detection/post)
- [hair-bang](/reference/ai_bangs/v1.0/paths/~1s2s~1v2.0~1task~1hair-bang/post)
- [hair-color](/reference/ai_hair_color/v1.0/paths/~1s2s~1v2.0~1task~1hair-color/post)
- [hair-curl](/reference/ai_wavy_hair/v1.0/paths/~1s2s~1v2.0~1task~1hair-curl/post)
- [hair-ext](/reference/ai_hair_extension/v1.0/paths/~1s2s~1v2.0~1task~1hair-ext/post)
- [hair-transfer](/reference/ai_hairstyle/v2.1/paths/~1s2s~1v2.1~1task~1hair-transfer/post)
- [hair-vol](/reference/ai_hair_volume/v1.0/paths/~1s2s~1v2.0~1task~1hair-vol/post)
- [beard-style](/reference/ai_beard_style/v1.0/paths/~1s2s~1v2.0~1task~1beard-style/post)


### 虚拟试穿与试戴

- [earring](/reference/ai_earrings/v1.0/paths/~1s2s~1v2.0~1task~12d-vto~1earring/post)
- [necklace](/reference/ai_necklace/v1.0/paths/~1s2s~1v2.0~1task~12d-vto~1necklace/post)
- [ring](/reference/ring_vto/v1.0/paths/~1s2s~1v2.0~1task~12d-vto~1ring/post)
- [bracelet](/reference/ai_bracelet/v1.0/paths/~1s2s~1v2.0~1task~12d-vto~1bracelet/post)
- [watch](/reference/ai_watch/v1.0/paths/~1s2s~1v2.0~1task~12d-vto~1watch/post)
- [bag](/reference/ai_bag/v2.0/paths/~1s2s~1v2.0~1task~1bag/post)
- [hat](/reference/ai_hat/v2.0/paths/~1s2s~1v2.0~1task~1hat/post)
- [scarf](/reference/ai_scarf/v2.0/paths/~1s2s~1v2.0~1task~1scarf/post)
- [cloth-v4](/reference/ai_clothes/v4.0/paths/~1s2s~1v2.0~1task~1cloth-v4/post)
- [fabric](/reference/ai_fabric/v1.0/paths/~1s2s~1v2.0~1task~1fabric/post)
- [shoes-transfer](/reference/ai_shoes/v3.0/paths/~1s2s~1v2.0~1task~1shoes-transfer/post)


### 图像

- [enhance](/reference/ai_photo_enhance/v1.0/paths/~1s2s~1v2.0~1task~1enhance/post)
- [lighting](/reference/ai_photo_lighting/v2.0/paths/~1s2s~1v2.0~1task~1lighting/post)
- [colorize](/reference/ai_photo_colorize/v1.0/paths/~1s2s~1v2.0~1task~1colorize/post)
- [color-correct](/reference/ai_color_correction/v1.0/paths/~1s2s~1v2.0~1task~1colorize~1color-correct/post)
- [sod](/reference/ai_background_removal/v1.0/paths/~1s2s~1v2.0~1task~1sod/post)
- [bg-blur](/reference/ai_photo_background_blur/v2.0/paths/~1s2s~1v2.0~1task~1bg-blur/post)
- [bg-replace](/reference/ai_photo_background_change/v2.0/paths/~1s2s~1v2.0~1task~1bg-replace/post)
- [generative-fill](/reference/ai_object_removal_pro/v4.0/paths/~1s2s~1v2.0~1task~1generative-fill/post)
- [obj-replace](/reference/ai_replace/v1.0/paths/~1s2s~1v2.0~1task~1obj-replace/post)
- [out-paint](/reference/ai_image_extender/v2.0/paths/~1s2s~1v2.0~1task~1out-paint/post)
- [image-to-image](/reference/ai_image_generator/v2.0/paths/~1s2s~1v2.0~1task~1image-to-image~1youcam/post)
- [text-to-image](/reference/ai_image_generator/v2.0/paths/~1s2s~1v2.0~1task~1text-to-image~1youcam/post)
- [ai-avatar](/reference/ai_avatar_generator/v3.0/paths/~1s2s~1v2.0~1task~1ai-avatar/post)
- [ai-studio](/reference/ai_studio_generator/v3.0/paths/~1s2s~1v2.0~1task~1ai-studio/post)
- [headshot](/reference/ai_headshot_generator/v1.0/paths/~1s2s~1v2.0~1task~1headshot/post)
- [wmk-removal](/reference/ai_watermark_removal/v1.0/paths/~1s2s~1v2.0~1task~1wmk-removal/post)
- [face-swap](/reference/ai_face_swap/v1.0/paths/~1s2s~1v2.0~1task~1face-swap/post)


### 视频

- [bg-replace-vid](/reference/ai_video_background_replace/v1.0/paths/~1s2s~1v2.0~1task~1bg-replace-vid/post)
- [face-swap-vid](/reference/ai_video_face_swap/v1.0/paths/~1s2s~1v2.0~1task~1face-swap-vid/post)
- [image-to-video](/reference/ai_video_generator/v2.0/paths/~1s2s~1v2.0~1task~1image-to-video~1youcam/post)
- [text-to-video](/reference/ai_video_generator/v2.0/paths/~1s2s~1v2.0~1task~1text-to-video~1youcam/post)
- [obj-rem-vid](/reference/ai_video_object_removal/v2.1/paths/~1s2s~1v2.0~1task~1obj-rem-vid/post)
- [video-sr](/reference/ai_video_enhancer/v1.0/paths/~1s2s~1v2.0~1task~1video-sr/post)
- [video-trans](/reference/ai_video_style_transfer/v1.0/paths/~1s2s~1v2.0~1task~1video-trans/post)


各功能的确切入参，请用 `youcam run <feature> --help` 查看。

## 示例流程

这里以 [AI 身形塑形](/reference/ai_body_reshape/v1.0/paths/~1s2s~1v2.0~1task~1body-reshape/post) 走一遍完整流程——先检测照片里的人体，挑一个，做塑形，再取结果。下面的请求体与响应体都取自用这张示例照片的真实运行：

**1. 启动检测（预处理）任务**

```bash
youcam run pre-process body-reshape \
  --src_file "https://plugins-media.makeupar.com/strapi/assets/body_reshape_01_d10c50c97d.jpg"
```

响应：

```json
{
  "status": 200,
  "data": {
 "task_id": "CKPWaMO-olxd1ECr_3tTDXW5Gu_tQw0EKgN0-dU27zSyXhV8cJR2TzYLMhDqD"
  }
}
```

**2. 取回检测到的人体**

```bash
youcam status pre-process body-reshape CKPWaMO-olxd1ECr_3tTDXW5Gu_tQw0EKgN0-dU27zSyXhV8cJR2TzYLMhDqD
```

响应：

```json
{
  "status": 200,
  "data": {
 "error": null,
 "results": {
 "result": [
  {
  "left": 0.35347824096679686,
  "top": 0.022326231002807617,
  "width": 0.3041056156158447,
  "height": 0.951037073135376
  }
 ],
 "timed": 4565
 },
 "task_status": "success"
  }
}
```

`results.result` 里每一项就是一个被检测到的人，用相对于图片尺寸的包围框表示（`0`–`1`）。它在数组中的位置，就是接下来要传的 `--index`；这张照片只有一个人，所以编号是 `0`。

**3. 对选中的人运行主任务**

```bash
youcam run body-reshape \
  --src_file "https://plugins-media.makeupar.com/strapi/assets/body_reshape_01_d10c50c97d.jpg" \
  --version 1.0 \
  --index 0 \
  --features '{"slim": 20}'
```

响应：

```json
{
  "status": 200,
  "data": {
 "task_id": "ZV3WIzcB1rk7I5o8hMxKP5VdgIEpnHf7VOpsk1YC76tZy2Wur0lg4Bunb3KY-7Qa"
  }
}
```

**4. 轮询主任务直到完成**

```bash
youcam status body-reshape ZV3WIzcB1rk7I5o8hMxKP5VdgIEpnHf7VOpsk1YC76tZy2Wur0lg4Bunb3KY-7Qa
```

任务在跑时 `task_status` 是 `running`；每隔几秒重复执行这条命令。任务成功后（`GET /s2s/v2.0/task/body-reshape/{task_id}`）：

```json
{
  "status": 200,
  "data": {
 "error": null,
 "results": {
 "url": "https://yce-us.s3-accelerate.amazonaws.com/ttl30/.../0b333891-60be-4cd1-81cd-7d8cae35b3eb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&...&X-Amz-Expires=7200&...",
 "timed": 12131,
 "slim": true
 },
 "task_status": "success"
  }
}
```

`results.url` 就是塑形后的图片。它是一个签名链接，会过期（`X-Amz-Expires=7200`，也就是 2 小时），所以任务成功后请尽快下载。

## 调试指南

CLI 发出的就是标准的 YouCam API 请求，所以 API 文档里的一切规定原样适用：相同的[速率限制](/develop/rate_limit)、[错误码](/develop/error_codes)与[文件保留期限](/develop/file_retention_period)。另见 API 自身的[调试指南](/develop/debugging_guide)。

### 错误出现在哪儿

问题可能在三个环节暴露：

| 失败位置 | 退出码 | stdout | stderr | 参见 |
|  --- | --- | --- | --- | --- |
| CLI 在发出请求前就把命令拒绝 | `1` | 空 | 错误信息 | [CLI 错误](#cli-errors) |
| API 拒绝了请求 | `1` | 带 `status`、`error` 与 `error_code` 的 JSON | 空 | [API 请求错误](#api-request-errors) |
| 任务跑起来了但失败 | `0` | 带 `"task_status": "error"` 的 JSON，`data.error` 里是错误码，`data.error_message` 里是说明 | 空 | [任务错误](#task-errors) |


任务失败时退出码仍是 `0`，因为 `status` 这个请求本身是成功的。脚本必须检查 `data.task_status`，不能只看退出码。

### 速率限制

[API 速率限制](/develop/rate_limit)对每条 `youcam` 命令都生效：

- **按 IP 地址：** 300 秒内最多 250 次请求。
- **按访问令牌（API 密钥）：** 300 秒内最多 250 次请求。
- 两条上限都要满足。任何一条被突破，请求会得到 `429 Too Many Requests`，CLI 以退出码 `1` 退出。
- 建议节奏约为每秒 5 次请求。


多数命令只发 1 次 API 请求。`run` 带本地文件时，在任务请求之前，每个文件还会多发 1 次 `POST /s2s/v2.0/file`。轮询也算数——每秒查好几个任务，额度很快就见底。请每隔几秒轮询一次；收到 `429` 时，等一等，再用递增的间隔重试，别立刻重打。

### CLI 错误

这些都在任务请求发出之前被拦下，因此不消耗点数。

| CLI 错误信息 | 可能的原因 | 解决办法 |
|  --- | --- | --- |
| `Not authenticated. Run: youcam auth login <apiKey>, or set YOUCAM_CLI_API_KEY` | 没有已保存的 API 密钥，且 `YOUCAM_CLI_API_KEY` 未设置或为空 | 执行 `youcam auth login <apiKey>`，或设置 `YOUCAM_CLI_API_KEY` |
| `Invalid credentials file at <path>. Re-run: youcam auth login <apiKey>` | `credentials.json` 不是合法 JSON，或 `apiKey` 为空、不是字符串 | 执行 `youcam auth login <apiKey>`，它会覆盖该文件 |
| `Can't log out: credentials file at <path> is invalid. Fix or delete it by hand` | `youcam auth logout` 发现了同样损坏的 `credentials.json`，并保持原样未动 | 把文件改成 `{ "apiKey": "<your-api-key>" }`，然后重新登出；或者删掉该文件 |
| `error: required option '--scale <value>' not specified` | 缺少必填选项 | 补上。`youcam run <feature> --help` 会列出所有选项 |
| `error: option '--scale <value>' argument '9' is invalid. Allowed choices are 1, 2, 4.` | 取值不在允许的范围里 | 用列出的取值之一 |
| `Invalid value for --page_size: 99 (Too big: expected number to be <=20)` | 取值类型不对或超出范围。JSON 选项会点名具体字段 | 修正取值。JSON 的引号写法见[传 JSON 参数](#passing-json-parameters) |
| `error: unknown option '--bogus'` | 这个功能没有该选项，或拼写有误 | 到 `--help` 里核对拼写。选项用 snake_case，例如 `--src_file`，不是 `--src-file` |
| `ENOENT: no such file or directory, open '...'` | 本地文件路径不对 | 检查路径。相对路径以当前目录为起点。含空格的路径请加引号 |
| `Unsupported file type "unknown" for ./notes.txt. Supported types: image/jpeg, image/png, video/mp4` | 本地文件不是 JPG、PNG 或 MP4 | 转换文件格式，或者改传公开 URL |
| `Missing task ID. Usage: status <feature> <task_id> (or --task_id <value>)` | 执行 `status` 时没给任务 ID | 传入 `run` 打印出来的 `task_id` |


### API 请求错误

API 拒绝了请求。CLI 会把 API 的响应打印到 stdout，例如：

```json
{
  "status": 400,
  "error": "This task ID doesn't exist, or the task has expired.",
  "error_code": "InvalidTaskId"
}
```

| 状态码 | `error_code` | 可能的原因 | 解决办法 |
|  --- | --- | --- | --- |
| `400` | `InvalidTaskId` | 任务 ID 打错了；或它属于另一个功能（例如 `run enhance` 的任务却用 `status hair-color` 去查）；或已超过 30 天——`task_id` 的有效期是 30 天 | `status` 里用的功能名请与 `run` 里的一致。预处理任务请用 `youcam status pre-process <feature> <task_id>`。任务启动后请在 30 天内查询 |
| `401` | `InvalidAccessToken` | 保存的 API 密钥不对，或已失效 | 到 [API 控制台](https://yce.perfectcorp.com/api-console/en/api-keys/)复制密钥，重新执行 `youcam auth login`。密钥里不要带用法行中的 `<` `>` |
| `429` | — | 您的 IP 地址或 API 密钥请求过多 | 放慢速度，用递增的间隔重试。见[速率限制](#rate-limits) |


### 任务错误

任务已被受理，但 AI 引擎处理不了。`youcam status` 返回 `"task_status": "error"`，错误码在 `data.error`，说明在 `data.error_message`。请到 API 的[错误码](/develop/error_codes)页面查这个码。部分功能另有专属错误码，列在该功能的 API 参考页面「文件规格与错误」一节里，同一节还写明尺寸、分辨率与姿态的限制。

### 结果链接过期

结果 URL（例如 `results.url`，`ai-avatar` 则是 `results.output[].url`）在任务成功后 2 小时内有效。若已过期，重新执行 `youcam status <feature> <task_id>` 就能拿到新链接；任务创建后 30 天内都可以这样取。结果在 30 天后会被删除，所以要留的东西请务必在此之前下载。

## 获取帮助

```bash
youcam help
youcam help <command>
youcam <command> <subcommand> --help # e.g., youcam run pre-process --help
```