# baidu-service · 文心助手图片编辑 API

> 把 `wenxin.baidu.com` / `chat.baidu.com`（文心助手「图片编辑工具」）包成 **OpenAI 风格**的同步图片接口：**一条 POST、进图出图**。
> 对外模型名 `wenxin:*`；本服务注册 **19 项能力**，本部署当前可调用 **16 项**（口径见「兜底与降级」）。

## 怎么调

```bash
curl -sS https://<host>/v1/images/generations \
  -H "Authorization: Bearer $BAIDU_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"model": "wenxin:clarity", "image": "https://example.com/a.jpg"}'
```

- `image` 支持 **http(s) URL** 或 **data URI**（`data:image/png;base64,...`）；裸 base64 亦可（按 PNG 处理）。
- **想零成本试跑**：任何请求体加 `"dry_run": true`（或请求头 `X-Avm-Dry-Run: 1`）——只回**将要发出的上游请求计划**（凭据已打码），不触网、不消耗额度。
- 结果：`response_format=b64_json`（默认）在 `data[0].b64_json`；`url` 则由本服务落盘并给链接。

## 鉴权

- 免鉴权：`GET /healthz`、`GET /readyz`、`GET /v1/models`、`GET /llms.txt`；
- 其余端点（含 `POST /v1/images/generations`、`GET /capabilities`、`GET /stats`）需 `Authorization: Bearer <key>`；未配 key 的部署会拒绝挂载受保护面。

## 能力清单（19 项，`model` 取值即 `wenxin:*`）

| model | 名称 | 必填输入 | 上游通路 | 本部署 |
|---|---|---|---|---|
| `wenxin:beauty` | 美颜 | `image` | 主链 toolType=24 | ✅ 可调用 |
| `wenxin:bgreplace` | 背景替换 | `mask` + `prompt` | 老接口 type=12（主链形态不可用） | ✅ 可调用 |
| `wenxin:clarity` | 变清晰 | `image` | 主链 toolType=3 + 老接口 type=3 | ✅ 可调用 |
| `wenxin:dewatermark` | 去水印 | `image` | 老接口 type=1（主链形态不可用） | ✅ 可调用 |
| `wenxin:erase` | 消除 | `mask` | 老接口 type=8（主链形态不可用） | ✅ 可调用 |
| `wenxin:expand` | 扩图 | `size` | 主链 toolType=4 + 老接口 type=4 | ✅ 可调用 |
| `wenxin:filter` | 滤镜 | `image` | 主链 toolType=23 | ✅ 可调用 |
| `wenxin:matting` | 抠图 | `image` | 主链 toolType=9 + 老接口 type=9 | ✅ 可调用 |
| `wenxin:matting-pro` | 背景抠图 | `image` | 主链 toolType=10 | ⛔ wenxin:matting-pro 未端到端取证（§3 枚举期出图 ✅（与 9 同能力、不同模型入口）；**2026-09-24 复验不可用**：8 类输入（含人像/旅拍/extinfo 官方示例）18 次调用全部只回「编辑器链接」，无结果图。待复验再开）；要放开请设 BAIDU_ALLOW_UNVERIFIED=1（自担，背景抠图（toolType 10）。与 wenxin:matting 同能力域；当前主链只回编辑器链接；老接口只有 type=9（同域），未单独登记映射） |
| `wenxin:ps` | P图 | `image` | 主链 toolType=27 | ⛔ wenxin:ps 未端到端取证（§3 枚举期出图 ✅；**2026-09-24 复验不可用**：8 类输入（合成图 / 54×54 占位图 / 官方人像样图 / 旅拍样图 / extinfo 官方示例 ×6）**18 次调用全部只回「交互式编辑链接（picEditBaseUrl）」，无结果图**（对照：同批人像输入下 `wenxin:beauty` 出图 25.6s ⇒ 排除「输入语义」这一解释）。⇒ 疑似该 toolType 已转编辑器形态；**待上游恢复或找到适配输入后复验再开**）；要放开请设 BAIDU_ALLOW_UNVERIFIED=1（自担，P图（toolType 27）。当前主链只回编辑器链接；本服务不含无参透传的老接口映射） |
| `wenxin:redraw` | AI重绘 | `image` | 老接口 type=6 | ✅ 可调用 |
| `wenxin:removeperson` | 去路人 | `image` | 主链 toolType=21 | ⛔ wenxin:removeperson 未端到端取证（§3 枚举期出图 ✅；**2026-09-24 复验不可用**：8 类输入 18 次调用全部只回「编辑器链接」，无结果图（同批人像输入下 beauty 出图 ⇒ 非输入语义问题）。待复验再开）；要放开请设 BAIDU_ALLOW_UNVERIFIED=1（自担，去路人（toolType 21）。当前主链只回编辑器链接） |
| `wenxin:removetext` | 去文字 | `image` | 主链 toolType=22 | ✅ 可调用 |
| `wenxin:replace` | 局部替换 | `mask` + `prompt` | 老接口 type=5（主链形态不可用） | ✅ 可调用 |
| `wenxin:restore` | 图片修复 | `image` | 主链 toolType=20 | ✅ 可调用 |
| `wenxin:restyle` | 换风格 | `style` | 主链 toolType=14 | ✅ 可调用 |
| `wenxin:similar` | 相似图 | `image` | 老接口 type=7 | ✅ 可调用 |
| `wenxin:sketch` | 提线稿 | `image` | 主链 toolType=15 + 老接口 type=15 | ✅ 可调用 |
| `wenxin:textreplace` | 文字替换 | `image` | 主链 toolType=17 | ✅ 可调用 |

## 参数

| 字段 | 适用 | 说明 |
|---|---|---|
| `model` | 必填 | 见上表 |
| `image` | 必填 | 输入图（URL / data URI / base64） |
| `mask` | 消除 / 局部替换 / 背景替换 **必填** | **黑底白框**：白色 = 要处理的区域（黑=保留）；与 `image` **同尺寸**；形态同 `image` |
| `style` | 换风格 **必填** | 风格 **id** 或**中文标签**（下表 17 项）；错误体 `styles[]` 会回候选 |
| `prompt` | 局部替换 / 背景替换 | 替换内容（老接口 `text`）；其余能力忽略并在 `warnings[]` 明示 |
| `size` | 扩图 | 目标比例，见「扩图比例」；其余能力忽略并提示 |
| `response_format` | 可选 | `b64_json`（默认）/ `url` |
| `dry_run` | 可选 | 只回计划不触网 |

## 风格表（`style` 取值；id 与标签等价）

| id | 标签 |
|---|---|
| `miyazaki` | 宫崎骏风 |
| `giboli` | 吉卜力风 |
| `pailide_clay` | 拍立得风 |
| `clay` | 橡皮泥风 |
| `monet` | 油画风 |
| `style_transfer12` | 奇幻卡通 |
| `style_transfer11` | 梵高 |
| `style_transfer4` | 炫彩插画 |
| `style_transfer9` | 浪漫雕塑 |
| `style_transfer3` | 光的气息 |
| `style_transfer1` | 复古胶片 |
| `style_transfer2` | 美式画报 |
| `style_transfer5` | 法式风情 |
| `style_transfer10` | 童话镇 |
| `style_transfer6` | 水神 |
| `style_transfer7` | 野兽派 |
| `style_transfer8` | 白月光 |

## 扩图比例

- `size` 取：`1:1`、`4:3`、`3:4`、`16:9`、`9:16`、`3:2`、`2:3`

## 兜底与降级

- 本服务有**两条上游通路**：主链（`chat.baidu.com`）为主，**老接口**（`image.baidu.com/aigc`）为辅。
- 当前 `BAIDU_LEGACY=fallback`（老接口可用 ⇒ 上表里带「老接口」通路的能力都可调）；
- 未取证闸门 = `False`（开启后会放行未端到端验证的能力，仅供排障，正常调用别开）。
- 版本 `0.0.7`；能力表版本时间（`/v1/models` 的 `created`）=`1790208000`。

## 常见错误

| code | HTTP | 何时出现 |
|---|---|---|
| `unknown_model` | 400 | 模型名不在 `/v1/models` 里（含已撤销的 `wenxin:reimagine`） |
| `missing_model` | 400 | 请求体缺 `model` |
| `invalid_body` | 400 | 请求体不是 JSON 对象 / 键集不合法 |
| `empty_input` | 400 | `image` 为空 |
| `url_input_unsupported` | 400 | 该部署未开 URL 输入（见 `/readyz` 的 `upload_mode`） |
| `missing_mask` | 400 | 该能力**必填 `mask`**（消除 / 局部替换 / 背景替换） |
| `invalid_mask` | 400 | `mask` 形态不合法（支持 http(s) URL / data URI / base64） |
| `missing_style` | 400 | 该能力**必填 `style`**（换风格），错误体里带 17 项候选 |
| `unknown_style` | 400 | `style` 不在风格表里（错误体 `styles[]` 给候选） |
| `invalid_style` | 400 | `style` 不是字符串 |
| `invalid_size` | 400 | `size` 不是字符串 |
| `invalid_prompt` | 400 | `prompt` 不是字符串 |
| `invalid_response_format` | 400 | `response_format` 只支持 `b64_json` / `url` |
| `unauthorized` | 401 | 受保护端点缺 Bearer 或 key 不对 |
| `capability_not_verified` | 503 | 该能力**未取证**且未开 `BAIDU_ALLOW_UNVERIFIED`（`error.how_to_enable` 给开启方式） |
| `media_write_failed` | 503 | `response_format=url` 落盘失败（磁盘/权限） |
| `internal` | 500 | 未预期异常（已脱敏；细节在服务端日志） |

上游类失败在 `error.kind` 归因（词表与源码同源）：

- `auth`（HTTP 503）：上游凭据/会话失效（检查 `/readyz` 的 `cookie_configured` 与 `token_alive`）
- `param`（HTTP 400）：上游认为参数不合法（多半是输入图/遮罩形态问题）
- `risk_control`（HTTP 429）：上游风控（本服务会进冷却窗，响应带 `retry-after`）
- `timeout`（HTTP 504）：上游超时（可安全重试）
- `upstream`（HTTP 502）：上游未出图或返回结构不符（`note` 给上游原话）

## 其他端点

| 端点 | 鉴权 | 说明 |
|---|---|---|
| `GET /healthz` | 免 | 存活 + 版本 |
| `GET /readyz` | 免 | 就绪（凭据/闸门/冷却/能力计数） |
| `GET /v1/models` | 免 | **本部署可调用**的模型（OpenAI 四键形态） |
| `GET /capabilities` | 需 | 全集 + 未取证项的原因与开启方式 + `styles[]` |
| `GET /stats` | 需 | 进程内窗口/闸门/最近 span |

## 更多

- 仓库（公开）：<https://github.com/rsfree/baidu>
- 契约：`docs/INTERFACE.md`（对外）· `docs/UPSTREAM.md`（上游实测与判断依据）
