---
name: yoooclaw-media-generate
description: >-
  AI 图片生成与视频生成：根据用户的文字描述、创意或提示词，直接生成可查看和下载的图片或视频。
  当用户想画图、生图、生成图片、创作插画、制作海报配图、头像、壁纸、封面或产品概念图时使用，
  例如“帮我画一只小猫”“生成一张日落海边的图片”“做一张咖啡店宣传海报”“给这篇文章配张图”“我想要一个卡通头像”。
  当用户想生成视频、文生视频、图片加文字生视频、指定视频首尾帧、做一段短视频或动态场景时使用，
  例如“生成一个小猫喝水的视频”“帮我做一段 5 秒的海浪视频”“把这段文字生成视频”“做一个镜头缓慢推进森林的短片”。
  也适用于询问生成所需积分、查询已提交视频任务的进度或获取结果，
  例如“生成这个视频要多少积分”“刚才的视频生成好了吗”。用户只描述目标画面并明确要求出图或出视频时，也应使用，无需提及 skill 名称。
  支持 text-to-image、图生图/图片编辑、text-to-video、参考图加文字及首尾帧视频请求、积分估算和视频任务查询；仅搜索现有素材、仅编写提示词或脚本、剪辑已有视频不属于当前能力。
hooks:
  Stop:
    - hooks:
        - type: command
          command: "python3 __YOOOCLAW_SKILL_DIR__/scripts/link_guard.py"
---

# 图片与视频生成

通过自有服务生成媒体，脚本仅依赖 Python 3 标准库。根据用户需求执行下方图片或视频分支；查询已有视频任务时直接使用任务 ID 查询。

## 共同流程

1. 每次新的生成请求都必须先询问并等待用户选择本次规格：图片询问标准版/专业版；视频询问 480P/720P/1080P 和 2–30 秒的时长。支持多张生成时还要确认本次张数，图生图/首尾帧请求还要确认本次素材及顺序。不能根据上文、历史偏好、上一次生成或“再来一张/一段”自动沿用规格。即使新请求中已写明规格，也先复述并请用户确认本次选择；收到回复前不估价、不生成。可以一次集中询问所需选项，面向用户用档位和规格描述，隐藏内部模型名称、供应商及路由。
2. 使用对应脚本的 `estimate` 获取报价。返回 `estimate_response.credits` 后，告知本次规格和预计总积分；估算失败或金额不明时停止生成。
3. 展示本次规格和本次估算的总积分，等待用户明确授权本次生成。历史报价或历史生成授权不能用于新的请求。只有本次已获授权才传 `--confirmed`，生成规格必须与本次确认和估算一致；规格或报价变化时重新询问确认。
4. 取得有效结果后，脚本已自动保存到工作空间并给出 `reply_markdown`，按“结果交付”回复。预计积分与实际扣费分开表述，当前生成响应不提供实际扣费金额。

本次请求中的规格回复、估价确认、生成、轮询和结果交付属于同一次流程，不因每次调用脚本而重复询问已经确认的本次规格。查询或续查已有任务时直接使用原任务 ID，不重新询问规格，也不创建新任务；用户另提生成、重做或再生成请求时，必须重新开始上述选择和授权流程。

### 提交数量与防重复

- 每次调用 `generate` 前，核对用户本次已确认的图片张数/视频条数、计划提交次数，以及本次已经提交和仍在执行的请求。数量不明确时先询问，不自行增加任务、备选版本或重复生成。同一请求的规格确认中一并确认数量，无需另开一轮重复询问。
- 图片 `generate --n` 只用于同一需求、同一提示词出多张图，一次 `--n 3` 已请求三张，不能再重复提交三次。不同需求分别提交，每个需求仅提交一次（超过单次上限时按确认的张数拆分批次）。视频每次 `generate` 只创建一个任务。多任务的数量和预计总积分须在提交前一并告知并获得授权。
- 提交后立即保留执行进程/会话标识、已提交数量、返回的任务 ID 和对应需求；异步命令仍在运行时先查看原进程结果，不另起命令重复提交。同一需求只能由一个执行者提交，禁止主助手与子助手或多个并发调用重复执行。
- 用户催进度、重复确认、要求重发链接，以及任务处于 PENDING/RUNNING/QUEUED 时，都只查询或交付原结果。图片预览与下载链接对应同一个结果，不各生成一次。
- 超时、503、响应丢失或进程状态不明，不能当作“未提交”而自动补交；先核实原请求。失败或结果数量不足时也不自动补生成，说明情况后由用户明确授权新的提交。

### 对话上传图片的准备

用户请求生成图片或视频，并在本次对话上传图片而非提供 URL 时，在调用生成脚本前按以下步骤准备素材（适用于图生图、视频参考图及首尾帧）：

1. 在运行环境的 `wuying-agent-workspace/.wuying-agent-runner/attachments/` 目录寻找本次上传的对应图片。根据对话附件信息、文件名及图片内容匹配；不要仅凭文件最新就选用，也不要沿用上次请求的附件。路径按实际运行环境定位，不假定它位于用户主目录。找不到或无法确定对应图片时，询问用户确认附件或实际路径。
2. 将匹配的图片复制到用户当前工作目录的 `media-inputs/` 下；如果该目录不存在，先创建目录，再复制图片。保留原附件，使用唯一文件名避免覆盖已有文件。先确定用户实际工作目录，不把附件目录或 skill 安装目录当作工作目录；复制后确认文件存在、可读且与源文件一致。
3. 使用复制后图片的绝对路径调用脚本：图生图传 `image_generate.py --image`；视频参考图传 `video_generate.py --image`；视频首尾帧传 `--first-frame` / `--last-frame`。这些参数用于各脚本的 `generate` 子命令，其他规格和授权参数仍按对应流程提供。多张图片逐一复制并保持用户确认的素材顺序。脚本自动将本地图片转为 Base64 data URL。

### 结果交付

生成成功后，脚本自行把结果下载到 `--save-dir`（默认当前工作目录下的 `media-results/`），并输出可直接粘贴的 `reply_markdown`。用户指定了保存目录时传 `--save-dir`；先确认实际工作目录，不把 skill 安装目录当作工作目录。不需要也不要再自行下载或拼接链接。

- 最终回复中**原样粘贴 `reply_markdown`**：不改写其中的链接，不放进代码块，不转义方括号或圆括号，不用 `![...](...)` 预览语法替代。可以在其前后补充说明，也可以只改方括号内的描述文字。
- `files` 非空时说明已保存到工作空间并列出文件路径；有 `download_failed` 时说明对应数量本地保存失败，下载链接仍可用。
- 用户要求重发结果时，从原脚本输出中取 `reply_markdown` 原样重发；视频可用原任务 ID `query` 重新获取。不重新提交付费生成。
- 本 skill 带有回复校验：最终回复中的媒体链接与脚本输出不一致时，会被要求按给出的正确链接重写。收到该提示时逐字替换后重新输出完整回复。
- 脚本报错、缺少有效结果或输出被截断时，报告结果暂不可用并核实原任务，不猜测或补全链接。

## 图片

支持文生图和图生图/图像编辑，同一需求每次生成 1–4 张，`--n` 默认 1；不同需求分别提交。让用户在下列两档中选择，仅说明已知价格，不捏造画质或速度差异。

| 用户选项 | 每张参考积分 | 脚本档位 |
| --- | --- | --- |
| 标准版 | 10.10 | `standard` |
| 专业版 | 25.25 | `professional` |

用本 skill 的绝对路径替换 `{baseDir}`：

```bash
python3 {baseDir}/scripts/image_generate.py estimate --tier standard
python3 {baseDir}/scripts/image_generate.py generate --tier standard --prompt '一只戴着墨镜的奶牛猫，坐在日落海边' --confirmed
```

生成接口同步等待，图片生成请求的网络超时为 300 秒。成功时脚本输出：

```json
{"status":"success","images":["https://..."],"files":["/abs/path/media-results/....png"],"reply_markdown":"[...（点击下载）](https://...)"}
```

**完成条件：取得有效图片结果，并按“结果交付”原样交付 `reply_markdown`；本地保存失败须明确说明。** 超时或响应格式异常时先核实结果，避免重复生成扣费。目前只解析 URL 图片结果。估算用 `--count` 指定该档位待估价的图片总张数（不是提交次数），返回的是总积分，不要再乘张数；估价传 `--n` 会报错并引导改用 `--count`。生成仍用 `--n` 指定同一提示词本次生成的 1–4 张图片。多个需求档位相同时可合计张数估价，档位不同则分别估价后求和；各次生成张数之和必须与已确认并估价的总张数一致。

### 输出尺寸

`--size` 可用于文生图和图生图；未指定时使用后端默认值。

| 场景 | 可选尺寸 |
| --- | --- |
| 标准版文生图 | `1K`、`2K` |
| 专业版纯文生图（无参考图、非组图） | `1K`、`2K`、`4K` |
| 任一档位图生图 | `1K`、`2K` |

当前脚本不开放组图模式；`--n` 表示独立输出图片张数。每次向用户确认本次尺寸，不能因用户要求 4K 就擅自切换专业版或移除参考图。自定义像素尺寸当前不接受；不支持的规格需用户重新选择并确认。专业版 4K 已接入参数校验，尚未完成线上生成验证。

```bash
python3 {baseDir}/scripts/image_generate.py estimate --tier professional --count 1
python3 {baseDir}/scripts/image_generate.py generate --tier professional --n 1 --size 4K --prompt '雪山日落，光线自然，细节丰富' --confirmed
```

示例中的 `--confirmed` 仅在本次规格和报价已获用户确认后使用。

### 图生图 / 图片编辑

向用户确认编辑目标、参考图片顺序、档位和生成张数；多张参考图按传入顺序编号。确认素材后先估价、告知总积分并获得授权，再生成。参考图与输出数量是两个概念：`--image` 可重复最多 9 次，`--n` 是生成张数（1–4）。

```bash
python3 {baseDir}/scripts/image_generate.py estimate --tier professional --count 2
python3 {baseDir}/scripts/image_generate.py generate --tier professional --n 2 --prompt '保持图1主体不变，参考图2风格，将背景换成雪山日落' --image '/absolute/path/source.webp' --image 'https://example.com/style.webp' --size 1K --negative-prompt '模糊，畸变，文字' --seed 123456 --prompt-extend false --watermark false --confirmed
```

已实测成功的标准版单张图生图扩展参数组合：`--size 1K --negative-prompt '模糊，畸变，文字' --seed 123456 --prompt-extend false --watermark false`。这是调用示例，不替代用户本次的参数选择，也不保证精确输出尺寸。

替换示例图片路径/链接后再调用；`--confirmed` 仅用于已获授权的生成。脚本向同一 `/images/generations` 接口传顶层 `image` 数组和 `prompt`，不传百炼原生 `input.messages`。不带 `--image` 时仍为文生图。

- `--image` 接受公网 HTTP(S) URL、Base64 data URL 或本地文件路径。本地文件由脚本编码为 data URL，无需另行公开上传。不要在回复或日志中输出 Base64 图片内容。
- 输入格式：JPEG/JPG、PNG（无透明通道）、BMP、WEBP；每张不超过 20 MB，单边 240–8000 像素，宽高比 1:8–8:1。脚本检查本地/Base64 大小和格式签名；完整解码、尺寸、透明通道及远程 URL 图片限制由服务端校验。
- URL 必须可被供应商公网访问。平台媒体中转链接只有确认供应商支持跟随其 302 时才作为输入；本地图片可直接用路径传入。完整保留链接签名。
- 编辑指令最多 5000 字符。图生图的 `--size` 仅接受 `1K`、`2K`，未指定时由后端默认使用 `2K`；不接受自定义尺寸或 `4K`。用户要求这些尺寸时先解释当前脚本限制，请其重新选择并确认，不自动换算或提交。
- 可选 `--negative-prompt`（非空）、`--seed`（0–2147483647）、`--prompt-extend true|false`、`--watermark true|false`。未指定时不传入，使用服务端默认；同一个 seed 不保证完全相同结果。这些扩展参数当前仅开放给带 `--image` 的请求。
- 两个档位均按图生图契约接入，但后端需配置支持图像编辑的路由。服务拒绝时报告问题，不移除参考图退化为文生图，不自动更换档位或重新提交。生成网络超时仍为 300 秒。

## 视频

每次新的视频生成请求都重新询问本次分辨率和时长，并等待用户回复，不沿用上文选择。视频时长必须为 2–30 的整数秒，最长 30 秒；估算和生成均受此限制。用户要求低于 2 秒、高于 30 秒或非整数秒时，明确告知该时长不支持，并询问用户在 2–30 的整数秒中重新选择；收到回复前不估价、不生成。可以建议可用时长，但不得自行接受建议、取整、补到 2 秒或截到 30 秒。用户重新选定后，按新规格重新估价、展示总积分并再次询问是否生成；只有用户明确确认后才能提交。

| 分辨率 | 每秒参考积分 |
| --- | --- |
| 480P | 22.73 |
| 720P | 45.45 |
| 1080P | 90.9 |

总积分以估算结果为准。估算与生成均显式传相同的 `--seconds`；脚本分别映射为估算的 `seconds` 和生成的 `parameters.duration`。

```bash
python3 {baseDir}/scripts/video_generate.py estimate --resolution 720P --seconds 5
python3 {baseDir}/scripts/video_generate.py generate --resolution 720P --seconds 5 --prompt '生成一个小猫的视频' --confirmed
python3 {baseDir}/scripts/video_generate.py query '<task_id>'
```

### 参考图与首尾帧

- 纯文字：只传 `--prompt`。
- 图片＋文字：传 `--image` 和 `--prompt`，图片作为内容参考，不强制作为首帧。
- 首帧＋文字：传 `--first-frame` 和 `--prompt`，指定视频起始画面。
- 首尾帧＋文字：同时传 `--first-frame`、`--last-frame` 和 `--prompt`。向用户确认两张图的顺序；不能只有尾帧。
- 三个图片参数均接受公网 HTTP(S) URL、Base64 data URL 或本地文件路径；兼容旧名称 `--image-url`、`--first-frame-url`、`--last-frame-url`。本地文件由脚本编码，无需公开上传；不要在回复或日志中输出 Base64 内容。URL 完整保留签名参数。
- 图片支持 JPEG/JPG、PNG（无透明通道）、BMP、WEBP，每张不超过 20 MB，单边 240–8000 像素，宽高比 1:8–8:1。脚本校验本地/Base64 大小、格式签名和 MIME；完整解码、像素、透明通道与远程图片限制由服务端校验。
- 参考图模式与首尾帧模式互斥。脚本按 Wan 3.0 的 `input.media` 结构提交，使用接口契约允许的扩展字段透传。尚未完成线上生成验证；服务拒绝时报告原任务问题，不删除图片后降级为文生视频，也不自动更换模型或输入方式重试。
- 先按同样的分辨率、时长估价并取得生成授权，再提交一次。轮询与交付流程不变。

```bash
python3 {baseDir}/scripts/video_generate.py generate --resolution 720P --seconds 5 --prompt '小猫转头看向镜头' --image '/absolute/path/cat.jpg' --confirmed
python3 {baseDir}/scripts/video_generate.py generate --resolution 720P --seconds 5 --prompt '从日出平滑过渡到夕阳' --first-frame '/absolute/path/start.jpg' --last-frame 'https://example.com/end.jpg' --confirmed
```

示例路径和链接为占位地址，调用时替换为用户提供的实际图片；`--confirmed` 仅用于已获授权的生成。

`generate` 只提交一次，立即输出任务 ID 和状态，然后在同一脚本进程内使用完整 ID 自动轮询，默认最多等待 1200 秒（20 分钟，提交成功后开始计时）。Agent 应继续查看原执行进程的输出，不复制任务 ID 另开查询、不因工具调用暂未结束而再次运行 `generate`。执行工具支持时为原进程配置足够的运行时长；任务成功后按“结果交付”交付。

`query` 用于原进程已结束或中断后的续查，默认同样最多等待 1200 秒。两条命令可用 `--wait` 调整轮询时长；`generate --wait 0` 仅提交，`query --wait 0` 仅查询一次。脚本每 10 秒查询一次，单次查询连接/读取超时不超过剩余轮询时间（且不超过 60 秒）。等待上限约束的是轮询窗口，不包含最初提交请求耗时。

提交接口直接返回终态时，脚本立即交付成功结果或报告失败，不再轮询。诊断字段经过脱敏和长度限制。

根据脚本输出处理：

- `PENDING` / `RUNNING` / `QUEUED`：尚未完成，继续等待原进程；可据其输出报告进度，不新建任务。
- `SUCCEEDED` 且有 `video_url`：脚本已保存视频并给出 `reply_markdown`，按“结果交付”原样交付；本地保存失败须明确说明。
- `FAILED` / `CANCELED` / `CANCELLED`：报告任务终止及脚本提供的 `code`、`message`，保留任务 ID 和可用的 `request_id`；未返回具体原因时不要猜测。
- `wait_expired: true`：轮询窗口结束，任务未必失败；保留任务 ID 和最后状态，需要时续查原任务。
- 未知状态、格式异常或查询错误：脚本停止并保留任务 ID，不自动重新提交。

**拿到任务 ID 仅代表提交成功，取得视频链接才代表生成成功。** 支持文字、参考图加文字和首尾帧视频请求；`query` 始终查询原任务，不创建新任务。

## 配置和错误处理

公共实现位于 [scripts/client.py](scripts/client.py)。脚本只读当前用户 `~/.config/yoooclaw/credentials` 中的 `MODEL_PROXY_API_KEY=对应的key`，使用 Bearer 鉴权，不输出或保存 Key 副本。凭证文件使用逐行 `KEY=VALUE` 格式，支持空行、整行 `#` 注释以及值外侧的单引号或双引号；不执行文件内容或展开变量。

固定服务地址为 `https://openclaw-service.yoooclaw.com/model-proxy/v1`，忽略配置里的 `baseUrl`，不使用 Cookie 或其他凭证来源。配置缺失或无效时报错，由用户修正原配置。

积分估算固定使用 GET，参数放在查询字符串中；不提供 `--method` 选项，不尝试 POST。失败时脚本输出 `{"status":"error","message":"..."}` 并以 1 退出；视频失败任务也以 1 退出。等待结束但任务仍在运行不代表生成失败。

生成请求遇到 HTTP 错误、超时或异常结果时不自动重试，避免重复扣费。已有视频任务 ID 就续查，没有 ID 时说明提交结果不确定并核实服务端记录。向用户总结错误，不直接转发可能包含内部信息的原始响应。

视频生成失败或服务拒绝参数时，说明实际错误；不能把鉴权、余额或服务错误推断为时长问题，不能擅自改变秒数、分辨率或模型再生成。即使建议了替代时长，也必须等待用户重新选择、确认新报价并明确授权。超时或结果不确定时先核实原任务，禁止直接创建新任务。
