| name | content-generation-workflow |
| description | 统一内容生成工作流,编排图片、视频、音乐等多种内容的生成与交付。当用户提到"工作流""流水线""编排"时引用(无论是否同时指定供应商);当用户表达内容生成需求但未指定供应商时引用;当工作流选择供应商后调用对应原子能力 skill。 |
| metadata | {"openclaw":{"requires":{"bins":["uv"],"anyBins":["python","python3","py"],"env":["OUTPUT_ROOT"]}}} |
内容生成工作流
统一的内容生成协调入口,支持图片、视频、音乐等多种内容类型,不绑定具体 AI 供应商或对象存储供应商。适用于用户表达内容生成需求(生成图片、视频、音乐、歌曲、歌词等)且需要编排生成、轮询、交付等多个步骤的场景。
工作流程
总体流程
1. 解析意图 → 确定内容类型、子类型、参数
2. 查供应商注册表 → 获取该内容类型的供应商列表
3. 选择供应商(用户指定 > 优先级排序)
4. 同步供应商?→ 直接调用,一步拿到结果
异步供应商?→ 创建任务 → 定时轮询 → 下载
5. 失败?→ 降级到下一个供应商重试
6. 交付:用户要求只要本地?→ 返回本地路径 / 否则上传七牛返回链接
同步流程(doubao 图片)
直接调用脚本,同步返回结果,无需轮询:
调用 text_to_image.py / image_to_image.py
→ 拿到 local_path
→ 交付
异步流程(tianpuyue)
通过一次性定时任务实现轮询,不使用脚本内部 sleep 循环,也不使用周期性定时任务。每次轮询是一个独立的一次性定时任务,由上一次轮询的结果触发创建:当前轮询发现任务仍在进行中时,计算下一次斐波那契间隔,创建一个新的一次性定时任务。触发后查询状态,根据结果决定下一步继续创建一次性定时任务还是结束。
Step 1: 创建任务
调用 create 脚本 → 拿到 task_id
告知用户:「任务已创建,{间隔}秒后查询进度(第1/6次)」
设置一次性定时任务,{间隔}秒后触发下一次查询
Step 2: 定时任务触发 → 查询状态
调用 query 脚本 → 解析状态
├─ 完成 → 下载文件 → 交付
├─ 进行中 → 计算下一次斐波那契间隔 → 设置下一个定时任务 → 告知用户下次查询时间
├─ 失败 → 降级或告知用户
└─ 第 7 次(超时)→ 告知用户超时
Step 3: 下载
从 query 结果提取 URL → 调用 download 脚本保存本地
每次定时任务触发时,需要携带完整上下文(供应商、task_id、当前轮询次数、用户原始请求、交付偏好等),以便独立执行查询和后续决策。
轮询策略
斐波那契间隔
间隔 = 斐波那契数列 × 基准系数(秒),最多轮询 6 次,第 7 次仍未完成则超时。
| 轮询次数 | Fib | 图片 (×3) | 视频 (×20) | 音乐 (×12) |
|---|
| 1 | 1 | 3s | 20s | 12s |
| 2 | 1 | 3s | 20s | 12s |
| 3 | 2 | 6s | 40s | 24s |
| 4 | 3 | 9s | 60s | 36s |
| 5 | 5 | 15s | 100s | 60s |
| 6 | 8 | 24s | 160s | 96s |
| 累计 | — | 60s | 400s (~6.7min) | 240s (4min) |
图片基准系数=3,视频=20,音乐=12。音乐涵盖纯音乐和歌曲,歌词参照图片(系数=3)。
完成判定
Tianpuyue(音乐、歌曲、歌词):
- 状态字段:
item.status
- 成功:
"succeeded" / "main_succeeded" / "part_failed"
- 失败:
"failed"
- 结果提取:
- 音乐/歌曲 URL:
item.audio_url
- 歌词文本:
item.lyric(同时保存 .md 到 outputs/tianpuyue/lyrics/)
用户通知
每次轮询后告知用户当前状态和下一次查询时间:
- 任务创建时:「任务已创建,{间隔}秒后查询进度(第1/6次)」
- 进行中时:「仍在处理中,{间隔}秒后再次查询(第{n}/6次)」
- 完成时:直接进入下载和交付
供应商注册表
模式分同步(一次调用返回结果)和异步(create → poll → download 三步)。
图片 (image)
| 优先级 | 供应商 | 模式 | 子类型 | create | query | download |
|---|
| 1 | doubao | 同步 | text_to_image | ✓ | — | — |
| 1 | doubao | 同步 | image_to_image | ✓ | — | — |
视频 (video)
| 优先级 | 供应商 | 模式 | 子类型 | create | query | download |
|---|
| 1 | doubao | 异步 | text_to_video | ✓ | ✓ | ✓ |
| 1 | doubao | 异步 | image_to_video | ✓ | ✓ | ✓ |
Doubao 视频(Seedance)完成判定:
- 状态字段:
status
- 成功:
"succeeded"
- 失败:
"failed"
- 结果提取:
content.video_url
音乐 (music)
| 优先级 | 供应商 | 模式 | 子类型 | create | query | download |
|---|
| 1 | tianpuyue | 异步 | instrumental | ✓ | ✓ | ✓ |
| 1 | tianpuyue | 异步 | song | ✓ | ✓ | ✓ |
| 1 | tianpuyue | 异步 | lyrics | ✓ | ✓ | ✓ |
对象存储
降级策略
- 模型级降级优先:同一供应商内,先尝试该供应商的其他模型(如 doubao 5.0 → 4.5 → 4.0),再考虑跨供应商降级
- 跨供应商降级:同一内容类型内,同一供应商所有模型都失败后,按优先级从高到低尝试下一个供应商
- 当前供应商脚本报错(非零退出码)或任务失败,触发降级
- 用户指定了供应商时不降级,直接报告该供应商的失败结果
- 所有供应商都失败,汇总各供应商的错误信息告知用户
交付策略
- 默认:上传到七牛对象存储,返回交付链接
- 用户要求"只要本地"/"不要上传":跳过上传,返回本地文件路径
- 用户指定链接类型:使用
--private-url(签名链接)或 --public-url(公网链接)
文件命名
调用生成脚本时,必须通过 --name 参数传入一个不超过 10 个中文字的简短标题,用于输出文件命名(格式:{标题}_{yyyyMMddhhmm}.{ext})。如果不传 --name,文件名将只有时间戳,缺少语义。 标题在解析意图、优化提示词阶段一并生成,概括内容核心,如"雪中小猫玩耍""忧伤钢琴曲""海边日落漫步"。
用户覆盖
以下情况应覆盖默认行为:
- 用户明确指定供应商(如"用豆包生成"、"用天谱乐")
- 用户明确要求"只保存本地"或"不要上传"
- 用户指定了特定模型、尺寸、比例等参数
- 用户提供了参考图片(走 image_to_image 子类型)
- 用户提供了自定义歌词或指定了人声(走 song 子类型)
意图识别规则
| 用户说法 | 内容类型 | 子类型 |
|---|
| 生成图片、画一张图 | image | text_to_image |
| 根据这张图生成、图生图 | image | image_to_image |
| 生成视频 | video | text_to_video |
| 根据图片生成视频、首帧生视频 | video | image_to_video |
| 生成音乐、BGM、背景音乐 | music | instrumental |
| 生成歌曲、带人声的 | music | song |
| 写歌词、生成歌词 | music | lyrics |