@remixmate/cli 0.9.19 → 0.9.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/README.zh-CN.md +6 -6
- package/dist/handlers/gen-image.d.ts +2 -1
- package/dist/handlers/gen-image.js +4 -5
- package/dist/manifest.json +17 -17
- package/package.json +1 -1
- package/skills/gen-image/SKILL.md +9 -20
- package/skills/gen-image/skill.json +6 -6
- package/skills/gen-image/version.json +2 -2
- package/skills/gen-script/SKILL.md +25 -6
- package/skills/gen-script/scripts/gen_script.py +103 -5
- package/skills/gen-script/skill.json +1 -1
- package/skills/gen-video/SKILL.md +47 -50
- package/skills/gen-video/skill.json +6 -6
- package/skills/gen-video/version.json +2 -2
- package/skills/template-registry/scripts/match_template.py +14 -0
- package/skills/template-registry/video_dsl/schema/video-dsl-v1alpha1.json +11 -0
package/README.md
CHANGED
|
@@ -165,8 +165,8 @@ This project contains 11 AI media generation skills covering the full pipeline f
|
|
|
165
165
|
│ export-jianying Assets → Jianying draft ZIP │
|
|
166
166
|
├─────────────────────────────────────────────────────────────┤
|
|
167
167
|
│ Atomic Skills │
|
|
168
|
-
│ gen-image Text/Image-to-image (Seedream
|
|
169
|
-
│ gen-video Text-to-video (Seedance
|
|
168
|
+
│ gen-image Text/Image-to-image (Seedream 5.0) │
|
|
169
|
+
│ gen-video Text-to-video (Seedance 2.0) │
|
|
170
170
|
│ gen-voice Text-to-speech (Minimax TTS) │
|
|
171
171
|
│ gen-digital-human Talking-head (Jimeng / Feiying) │
|
|
172
172
|
├─────────────────────────────────────────────────────────────┤
|
|
@@ -203,8 +203,8 @@ This project contains 11 AI media generation skills covering the full pipeline f
|
|
|
203
203
|
|
|
204
204
|
| Skill | Type | Description | Runtime / entry |
|
|
205
205
|
|-------|------|-------------|-----------------|
|
|
206
|
-
| gen-image | atomic | Text/Image-to-image (Seedream
|
|
207
|
-
| gen-video | atomic | Text-to-video (Seedance,
|
|
206
|
+
| gen-image | atomic | Text/Image-to-image (Seedream 5.0 Lite / Pro) | http handler |
|
|
207
|
+
| gen-video | atomic | Text-to-video (Seedance 2.0, three tiers) | http handler |
|
|
208
208
|
| gen-voice | atomic | Text-to-speech (Minimax TTS) | http handler |
|
|
209
209
|
| gen-digital-human | atomic | Talking-head (Jimeng / Feiying) | http handler |
|
|
210
210
|
| gen-script | orchestration | Topic → Video DSL JSON | python `scripts/gen_script.py` |
|
|
@@ -296,8 +296,8 @@ remixmate template-registry --list-templates
|
|
|
296
296
|
### Quick start
|
|
297
297
|
|
|
298
298
|
```
|
|
299
|
-
@skills/gen-image/SKILL.md Generate an image of a panda, 9:16, using
|
|
300
|
-
@skills/gen-video/SKILL.md Generate a video of a panda running in a bamboo forest, 9:16, 6 seconds, using
|
|
299
|
+
@skills/gen-image/SKILL.md Generate an image of a panda, 9:16, using seedream-pro, Chinese-painting style + follow this doc strictly
|
|
300
|
+
@skills/gen-video/SKILL.md Generate a video of a panda running in a bamboo forest, 9:16, 6 seconds, using seedance-mini + follow this doc strictly
|
|
301
301
|
@skills/gen-voice/SKILL.md Generate a voiceover introducing panda habits, around 100 words + follow this doc strictly
|
|
302
302
|
@skills/gen-digital-human/SKILL.md Get the digital human list + follow this doc strictly
|
|
303
303
|
@skills/template-registry/SKILL.md Get the template list + follow this doc strictly
|
package/README.zh-CN.md
CHANGED
|
@@ -124,8 +124,8 @@ Python 技能(12 个中的 8 个)需要 `python3 >= 3.10`。`web-screenshot`
|
|
|
124
124
|
│ export-jianying 素材 → 剪映草稿 ZIP │
|
|
125
125
|
├─────────────────────────────────────────────────────────────┤
|
|
126
126
|
│ 原子层 Skills │
|
|
127
|
-
│ gen-image 文生图 / 图生图(Seedream
|
|
128
|
-
│ gen-video 文生视频(Seedance
|
|
127
|
+
│ gen-image 文生图 / 图生图(Seedream 5.0) │
|
|
128
|
+
│ gen-video 文生视频(Seedance 2.0) │
|
|
129
129
|
│ gen-voice 语音合成(Minimax TTS) │
|
|
130
130
|
│ gen-digital-human 数字人口播(即梦 / 飞影) │
|
|
131
131
|
├─────────────────────────────────────────────────────────────┤
|
|
@@ -162,8 +162,8 @@ Python 技能(12 个中的 8 个)需要 `python3 >= 3.10`。`web-screenshot`
|
|
|
162
162
|
|
|
163
163
|
| 技能 | 类型 | 说明 | 运行方式 / entry |
|
|
164
164
|
|------|------|------|------------------|
|
|
165
|
-
| gen-image | 原子 | 文生图 / 图生图(Seedream
|
|
166
|
-
| gen-video | 原子 | 文生视频(Seedance
|
|
165
|
+
| gen-image | 原子 | 文生图 / 图生图(Seedream 5.0 Lite / Pro) | http handler |
|
|
166
|
+
| gen-video | 原子 | 文生视频(Seedance 2.0 三档) | http handler |
|
|
167
167
|
| gen-voice | 原子 | 语音合成(Minimax TTS) | http handler |
|
|
168
168
|
| gen-digital-human | 原子 | 数字人口播(即梦 / 飞影) | http handler |
|
|
169
169
|
| gen-script | 编排 | 主题 → Video DSL JSON | python `scripts/gen_script.py` |
|
|
@@ -232,8 +232,8 @@ remixmate template-registry --list-templates
|
|
|
232
232
|
### 快速体验
|
|
233
233
|
|
|
234
234
|
```
|
|
235
|
-
@skills/gen-image/SKILL.md 生成一张熊猫的图片,9:16,调用
|
|
236
|
-
@skills/gen-video/SKILL.md 生成一段熊猫在竹林奔跑的视频,9:16,长度6
|
|
235
|
+
@skills/gen-image/SKILL.md 生成一张熊猫的图片,9:16,调用 seedream-pro,国画风 + 严格按该文档执行
|
|
236
|
+
@skills/gen-video/SKILL.md 生成一段熊猫在竹林奔跑的视频,9:16,长度6秒,用 seedance-mini + 严格按该文档执行
|
|
237
237
|
@skills/gen-voice/SKILL.md 生成一段语音,介绍熊猫的习性,大概100字左右 + 严格按该文档执行
|
|
238
238
|
@skills/gen-digital-human/SKILL.md 获取数字人列表 + 严格按该文档执行
|
|
239
239
|
@skills/template-registry/SKILL.md 获取模版列表 + 严格按该文档执行
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* through and is validated by the backend).
|
|
10
10
|
* - --size accepts a WxH string (→ width/height) or an aspect-ratio preset key
|
|
11
11
|
* (→ aspectRatio; for Seedream models ab-api maps the preset to pixels).
|
|
12
|
-
* - --resolution
|
|
12
|
+
* - --resolution is accepted but inert: it only ever fed the Gemini `size` tier,
|
|
13
|
+
* and Gemini is not wired up on the gateway, so we no longer send it.
|
|
13
14
|
* - Reference images: HTTPS URLs and data: URIs pass through; local paths are
|
|
14
15
|
* read and base64-encoded into a data: URI.
|
|
15
16
|
* - Async response (generationId + status:'generating'/'pending') is polled
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
* through and is validated by the backend).
|
|
10
10
|
* - --size accepts a WxH string (→ width/height) or an aspect-ratio preset key
|
|
11
11
|
* (→ aspectRatio; for Seedream models ab-api maps the preset to pixels).
|
|
12
|
-
* - --resolution
|
|
12
|
+
* - --resolution is accepted but inert: it only ever fed the Gemini `size` tier,
|
|
13
|
+
* and Gemini is not wired up on the gateway, so we no longer send it.
|
|
13
14
|
* - Reference images: HTTPS URLs and data: URIs pass through; local paths are
|
|
14
15
|
* read and base64-encoded into a data: URI.
|
|
15
16
|
* - Async response (generationId + status:'generating'/'pending') is polled
|
|
@@ -48,7 +49,6 @@ export async function genImage(input, ctxIn) {
|
|
|
48
49
|
const model = descriptor?.id ?? requested ?? defaultModel(caps.image)?.id ?? '';
|
|
49
50
|
const size = input.size ?? '1:1';
|
|
50
51
|
const n = toNumber(input.n, 'n') ?? 1;
|
|
51
|
-
const resolution = input.resolution ?? '1K';
|
|
52
52
|
const seed = toNumber(input.seed, 'seed');
|
|
53
53
|
const imageStrength = toNumber(input.image_strength, 'image_strength');
|
|
54
54
|
const guidanceScale = toNumber(input.guidance_scale, 'guidance_scale');
|
|
@@ -76,8 +76,8 @@ export async function genImage(input, ctxIn) {
|
|
|
76
76
|
if (watermark !== undefined)
|
|
77
77
|
payload.watermark = watermark;
|
|
78
78
|
// --size as WxH → explicit pixels; otherwise treat as an aspect-ratio preset.
|
|
79
|
-
// ab-api maps an aspect-ratio preset to
|
|
80
|
-
//
|
|
79
|
+
// ab-api maps an aspect-ratio preset to that model's pixel table, so the CLI
|
|
80
|
+
// carries no per-model size table.
|
|
81
81
|
if (/^\d+x\d+$/i.test(size)) {
|
|
82
82
|
const [w, h] = size.toLowerCase().split('x').map((v) => parseInt(v, 10));
|
|
83
83
|
payload.width = w;
|
|
@@ -86,7 +86,6 @@ export async function genImage(input, ctxIn) {
|
|
|
86
86
|
else {
|
|
87
87
|
payload.aspectRatio = size;
|
|
88
88
|
}
|
|
89
|
-
payload.size = resolution;
|
|
90
89
|
const ctx = await resolveHttpContext(ctxIn.skillName, {
|
|
91
90
|
apiBaseUrl,
|
|
92
91
|
privateToken: input.priv_token,
|
package/dist/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "0.9.
|
|
4
|
-
"generatedAt": "2026-09-
|
|
3
|
+
"version": "0.9.20",
|
|
4
|
+
"generatedAt": "2026-09-05T03:37:29.567Z",
|
|
5
5
|
"skills": [
|
|
6
6
|
{
|
|
7
7
|
"id": "export-jianying",
|
|
@@ -217,11 +217,11 @@
|
|
|
217
217
|
"tier": "atomic",
|
|
218
218
|
"category": "asset",
|
|
219
219
|
"title": "AI Image Generation",
|
|
220
|
-
"summary": "AI image generation: produce an image from a text prompt. Supports the Seedream family (
|
|
220
|
+
"summary": "AI image generation: produce an image from a text prompt. Supports the Seedream 5.0 family (Lite and a high-fidelity 'pro' variant), plus image-to-image with reference images.",
|
|
221
221
|
"triggers": [
|
|
222
222
|
"AI image generation, text-to-image, \"draw me ...\", \"generate an image of ...\"",
|
|
223
223
|
"Image-to-image, reference image, style transfer, image variation",
|
|
224
|
-
"Generate an image with Doubao / Seedream
|
|
224
|
+
"Generate an image with Doubao / Seedream",
|
|
225
225
|
"Provide a prompt and ask for an image"
|
|
226
226
|
],
|
|
227
227
|
"entry": {
|
|
@@ -244,7 +244,7 @@
|
|
|
244
244
|
},
|
|
245
245
|
"model": {
|
|
246
246
|
"type": "string",
|
|
247
|
-
"description": "Model: 'seedream' (default
|
|
247
|
+
"description": "Model: 'seedream' (default, Seedream 5.0 Lite) or 'seedream-pro' (high fidelity, precise placement and on-image text; costs more per image)"
|
|
248
248
|
},
|
|
249
249
|
"size": {
|
|
250
250
|
"type": "string",
|
|
@@ -257,7 +257,7 @@
|
|
|
257
257
|
"2K",
|
|
258
258
|
"4K"
|
|
259
259
|
],
|
|
260
|
-
"description": "Output resolution (Gemini
|
|
260
|
+
"description": "Output resolution tier. Currently inert: the only backend model that read it (Gemini) is not wired up, so this is ignored — use `size` for image dimensions."
|
|
261
261
|
},
|
|
262
262
|
"n": {
|
|
263
263
|
"type": "number",
|
|
@@ -268,7 +268,7 @@
|
|
|
268
268
|
"items": {
|
|
269
269
|
"type": "string"
|
|
270
270
|
},
|
|
271
|
-
"description": "Reference images for image-to-image: local file path, https URL, or data URI. Pass multiple to blend several references (seedream: max 14, seedream-pro: max 10
|
|
271
|
+
"description": "Reference images for image-to-image: local file path, https URL, or data URI. Pass multiple to blend several references (seedream: max 14, seedream-pro: max 10 — over the limit fails before spending credits)."
|
|
272
272
|
},
|
|
273
273
|
"image_strength": {
|
|
274
274
|
"type": "number",
|
|
@@ -309,14 +309,14 @@
|
|
|
309
309
|
"n",
|
|
310
310
|
"reference",
|
|
311
311
|
"negative_prompt",
|
|
312
|
-
"resolution",
|
|
313
312
|
"image_strength"
|
|
314
313
|
],
|
|
315
314
|
"hidden": [
|
|
316
315
|
"json_output",
|
|
317
316
|
"seed",
|
|
318
317
|
"guidance_scale",
|
|
319
|
-
"watermark"
|
|
318
|
+
"watermark",
|
|
319
|
+
"resolution"
|
|
320
320
|
]
|
|
321
321
|
}
|
|
322
322
|
},
|
|
@@ -406,7 +406,7 @@
|
|
|
406
406
|
"items": {
|
|
407
407
|
"type": "string"
|
|
408
408
|
},
|
|
409
|
-
"description": "Bottom typewriter text lines for templates that support a caption/typewriter area (e.g. spotlight-card). Each element is one line of text. Supports **emphasis** syntax (rendered with accent color). **Must** pass when the user explicitly provides bullet-point text / bottom copy
|
|
409
|
+
"description": "Bottom typewriter text lines for templates that support a caption/typewriter area (e.g. spotlight-card). Each element is one line of text, max 10 lines. Supports **emphasis** syntax (rendered with accent color). **Must** pass when the user explicitly provides bullet-point text / bottom copy. **Also must pass — written by you — when the user did NOT provide any copy but the template is typewriter-driven** (capabilities.durationStrategy=fit-caption, e.g. spotlight-card): such templates have no narration, so these lines are both the video's content and the thing that decides its duration. Draft them from the material you researched (repo README, page screenshots, the topic). Leaving this empty for a fit-caption template is rejected: nothing auto-generates caption text, and an empty caption renders a titled carousel with no words at all."
|
|
410
410
|
},
|
|
411
411
|
"stub_image_url": {
|
|
412
412
|
"type": "string",
|
|
@@ -455,10 +455,10 @@
|
|
|
455
455
|
"tier": "atomic",
|
|
456
456
|
"category": "asset",
|
|
457
457
|
"title": "AI Video Generation",
|
|
458
|
-
"summary": "AI video generation: produce a short video clip from a text prompt.
|
|
458
|
+
"summary": "AI video generation: produce a short video clip from a text prompt. Three Seedance 2.0 tiers (mini / fast / standard), plus first/last frame and reference images.",
|
|
459
459
|
"triggers": [
|
|
460
460
|
"Text-to-video, AI-generated clip, \"make a short video of ...\"",
|
|
461
|
-
"Generate video with Doubao / Seedance
|
|
461
|
+
"Generate video with Doubao / Seedance",
|
|
462
462
|
"Image-to-video, first-frame / last-frame, reference-image-to-video"
|
|
463
463
|
],
|
|
464
464
|
"entry": {
|
|
@@ -481,7 +481,7 @@
|
|
|
481
481
|
},
|
|
482
482
|
"model": {
|
|
483
483
|
"type": "string",
|
|
484
|
-
"description": "Model: 'seedance' (default;
|
|
484
|
+
"description": "Model: 'seedance-mini' (default; cheapest, 480p/720p), 'seedance-fast' (480p/720p), or 'seedance' (Seedance 2.0, adds 1080p). All are 4-15s and share the same features"
|
|
485
485
|
},
|
|
486
486
|
"duration": {
|
|
487
487
|
"type": "number",
|
|
@@ -508,7 +508,7 @@
|
|
|
508
508
|
"items": {
|
|
509
509
|
"type": "string"
|
|
510
510
|
},
|
|
511
|
-
"description": "Reference images: local file path, https URL, or data URI.
|
|
511
|
+
"description": "Reference images: local file path, https URL, or data URI. Up to 9; combinable with first_frame / last_frame."
|
|
512
512
|
},
|
|
513
513
|
"generate_audio": {
|
|
514
514
|
"type": "boolean",
|
|
@@ -520,7 +520,7 @@
|
|
|
520
520
|
},
|
|
521
521
|
"negative_prompt": {
|
|
522
522
|
"type": "string",
|
|
523
|
-
"description": "Content to steer away from (Veo)"
|
|
523
|
+
"description": "Content to steer away from. Veo only — Seedance ignores it (kept for when a Veo channel is available again)"
|
|
524
524
|
},
|
|
525
525
|
"seed": {
|
|
526
526
|
"type": "number",
|
|
@@ -556,12 +556,12 @@
|
|
|
556
556
|
"last_frame",
|
|
557
557
|
"reference",
|
|
558
558
|
"generate_audio",
|
|
559
|
-
"camera_fixed"
|
|
560
|
-
"negative_prompt"
|
|
559
|
+
"camera_fixed"
|
|
561
560
|
],
|
|
562
561
|
"hidden": [
|
|
563
562
|
"json_output",
|
|
564
563
|
"seed",
|
|
564
|
+
"negative_prompt",
|
|
565
565
|
"person_generation"
|
|
566
566
|
]
|
|
567
567
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remixmate/cli",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.20",
|
|
4
4
|
"description": "AI media generation skills for Claude Code / Codex — 12 skills covering image, video, voice, digital human, web screenshot, web recording, script, template registry, rendering, Jianying export, and video deconstruction.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gen-image
|
|
3
3
|
description: |
|
|
4
|
-
AI image generation skill: produce an image from a text prompt, or do image-to-image with reference images. Backed by ab-api's `/model/genImg` (Seedream
|
|
4
|
+
AI image generation skill: produce an image from a text prompt, or do image-to-image with reference images. Backed by ab-api's `/model/genImg` (the Seedream 5.0 family).
|
|
5
5
|
|
|
6
6
|
Use this skill immediately whenever the user asks for any of:
|
|
7
7
|
- AI image generation, text-to-image, "draw me ...", "generate an image of ..."
|
|
8
8
|
- Image-to-image, reference image, style transfer, image variation
|
|
9
|
-
- Generate an image with Doubao / Seedream
|
|
9
|
+
- Generate an image with Doubao / Seedream
|
|
10
10
|
- Provide a prompt and ask for an image
|
|
11
11
|
|
|
12
12
|
Even without an explicit "use AI", any request that turns a description into an image should route here.
|
|
13
13
|
triggers:
|
|
14
14
|
- AI image generation, text-to-image, "draw me ...", "generate an image of ..."
|
|
15
15
|
- Image-to-image, reference image, style transfer, image variation
|
|
16
|
-
- Generate an image with Doubao / Seedream
|
|
16
|
+
- Generate an image with Doubao / Seedream
|
|
17
17
|
- Provide a prompt and ask for an image
|
|
18
18
|
---
|
|
19
19
|
|
|
20
20
|
# AI Image Generation Skill
|
|
21
21
|
|
|
22
|
-
Wraps ab-api's `POST /model/genImg` (the same endpoint the web studio uses), authenticated with the **Tianyan privateToken**, routed through LiteLLM to **Seedream**
|
|
22
|
+
Wraps ab-api's `POST /model/genImg` (the same endpoint the web studio uses), authenticated with the **Tianyan privateToken**, routed through LiteLLM to the **Seedream 5.0** family.
|
|
23
23
|
|
|
24
24
|
## Models and sizes
|
|
25
25
|
|
|
@@ -31,7 +31,6 @@ the names below are the stable aliases to use.
|
|
|
31
31
|
|-----------|------------|------------------|
|
|
32
32
|
| `seedream` | Default. General-purpose, highest output resolution. | up to 14 |
|
|
33
33
|
| `seedream-pro` | High-fidelity variant: better placement/element control, more faithful text rendering. Costs more per image. | up to 10 |
|
|
34
|
-
| `gemini` | Gemini 3 Pro. | up to 4 |
|
|
35
34
|
|
|
36
35
|
- **Seedream**: `--size` is an aspect ratio (e.g. `1:1`, `9:16`) or `WxH`. The backend maps the
|
|
37
36
|
ratio to that model's own pixel preset and rescales out-of-range sizes, so prefer a ratio
|
|
@@ -39,8 +38,8 @@ the names below are the stable aliases to use.
|
|
|
39
38
|
- **`seedream-pro`** additionally supports `3:2` / `2:3` / `21:9`, and caps output at ~2K
|
|
40
39
|
(about 4.6 MP). Asking it for 4K pixels gets scaled down, not rejected — use `seedream`
|
|
41
40
|
when you need a genuinely larger image.
|
|
42
|
-
-
|
|
43
|
-
|
|
41
|
+
- **`--resolution`** is inert today: it only ever applied to Gemini, which is not wired up on
|
|
42
|
+
the gateway. Control image dimensions with `--size`.
|
|
44
43
|
|
|
45
44
|
## Auth & environment
|
|
46
45
|
|
|
@@ -71,14 +70,6 @@ remixmate gen-image \
|
|
|
71
70
|
--size "9:16"
|
|
72
71
|
```
|
|
73
72
|
|
|
74
|
-
```bash
|
|
75
|
-
remixmate gen-image \
|
|
76
|
-
--prompt "<image description>" \
|
|
77
|
-
--model gemini \
|
|
78
|
-
--size "16:9" \
|
|
79
|
-
--resolution "2K"
|
|
80
|
-
```
|
|
81
|
-
|
|
82
73
|
```bash
|
|
83
74
|
# High-fidelity: precise placement, legible on-image text
|
|
84
75
|
remixmate gen-image \
|
|
@@ -95,7 +86,6 @@ Reference images accept local file paths, HTTPS URLs, or data URIs. Pass `--refe
|
|
|
95
86
|
- **`seedream-pro`**: up to **10** reference images. Best choice when the edit has to land in a
|
|
96
87
|
specific spot — describe the target region in the prompt (e.g. "in the marked area at the
|
|
97
88
|
bottom left") and it holds position far better than `seedream`.
|
|
98
|
-
- **`gemini`**: up to **4** reference images.
|
|
99
89
|
|
|
100
90
|
Over-the-limit runs fail fast in the CLI, before spending credits.
|
|
101
91
|
|
|
@@ -129,13 +119,12 @@ remixmate gen-image \
|
|
|
129
119
|
| Flag | Description | Default |
|
|
130
120
|
|------|-------------|---------|
|
|
131
121
|
| `-p` / `--prompt` | Description (required) | — |
|
|
132
|
-
| `-m` / `--model` | `seedream` / `seedream-pro`
|
|
133
|
-
| `-s` / `--size` |
|
|
134
|
-
| `--resolution` | Gemini only: `1K` / `2K` / `4K` | `1K` |
|
|
122
|
+
| `-m` / `--model` | `seedream` / `seedream-pro` | see `MM_IMAGE_MODEL` |
|
|
123
|
+
| `-s` / `--size` | Aspect ratio or WxH | `1:1` |
|
|
135
124
|
| `-n` | Number of images, 1–4 | `1` |
|
|
136
125
|
| `-g` / `--guidance-scale` | Guidance scale (when supported) | backend default |
|
|
137
126
|
| `--reference` | Reference image (repeatable; local path / URL / data URI) | none |
|
|
138
|
-
| `--image-strength` | Reference strength 0–1
|
|
127
|
+
| `--image-strength` | Reference strength 0–1 | backend default |
|
|
139
128
|
| `--negative-prompt` | Things to avoid | none |
|
|
140
129
|
| `--seed` | Random seed (reproducibility) | none |
|
|
141
130
|
| `--watermark` | Add a watermark (no `--no-watermark` opt-out) | backend default |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"tier": "atomic",
|
|
5
5
|
"category": "asset",
|
|
6
6
|
"title": "AI Image Generation",
|
|
7
|
-
"description": "AI image generation: produce an image from a text prompt. Supports the Seedream family (
|
|
7
|
+
"description": "AI image generation: produce an image from a text prompt. Supports the Seedream 5.0 family (Lite and a high-fidelity 'pro' variant), plus image-to-image with reference images.",
|
|
8
8
|
"auth": "required",
|
|
9
9
|
"joinsTake": true,
|
|
10
10
|
"envVars": [
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"model": {
|
|
28
28
|
"type": "string",
|
|
29
|
-
"description": "Model: 'seedream' (default
|
|
29
|
+
"description": "Model: 'seedream' (default, Seedream 5.0 Lite) or 'seedream-pro' (high fidelity, precise placement and on-image text; costs more per image)"
|
|
30
30
|
},
|
|
31
31
|
"size": {
|
|
32
32
|
"type": "string",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"2K",
|
|
40
40
|
"4K"
|
|
41
41
|
],
|
|
42
|
-
"description": "Output resolution (Gemini
|
|
42
|
+
"description": "Output resolution tier. Currently inert: the only backend model that read it (Gemini) is not wired up, so this is ignored — use `size` for image dimensions."
|
|
43
43
|
},
|
|
44
44
|
"n": {
|
|
45
45
|
"type": "number",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"items": {
|
|
51
51
|
"type": "string"
|
|
52
52
|
},
|
|
53
|
-
"description": "Reference images for image-to-image: local file path, https URL, or data URI. Pass multiple to blend several references (seedream: max 14, seedream-pro: max 10
|
|
53
|
+
"description": "Reference images for image-to-image: local file path, https URL, or data URI. Pass multiple to blend several references (seedream: max 14, seedream-pro: max 10 — over the limit fails before spending credits)."
|
|
54
54
|
},
|
|
55
55
|
"image_strength": {
|
|
56
56
|
"type": "number",
|
|
@@ -91,14 +91,14 @@
|
|
|
91
91
|
"n",
|
|
92
92
|
"reference",
|
|
93
93
|
"negative_prompt",
|
|
94
|
-
"resolution",
|
|
95
94
|
"image_strength"
|
|
96
95
|
],
|
|
97
96
|
"hidden": [
|
|
98
97
|
"json_output",
|
|
99
98
|
"seed",
|
|
100
99
|
"guidance_scale",
|
|
101
|
-
"watermark"
|
|
100
|
+
"watermark",
|
|
101
|
+
"resolution"
|
|
102
102
|
]
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"skillName": "gen-image",
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "337",
|
|
5
|
-
"version": "
|
|
6
|
-
"skillDescription": "AI image generation skill: produce an image from a text prompt, or do image-to-image with reference images. Backed by ab-api's `/model/genImg` (Seedream
|
|
5
|
+
"version": "V10",
|
|
6
|
+
"skillDescription": "AI image generation skill: produce an image from a text prompt, or do image-to-image with reference images. Backed by ab-api's `/model/genImg` (the Seedream 5.0 family).\n\nUse this skill immediately whenever the user asks for any of:\n- AI image generation, text-to-image, \"draw me ...\", \"generate an image of ...\"\n- Image-to-image, reference image, style transfer, image variation\n- Generate an image with Doubao / Seedream\n- Provide a prompt and ask for an image\n\nEven without an explicit \"use AI\", any request that turns a description into an image should route here."
|
|
7
7
|
}
|
|
@@ -106,6 +106,18 @@ This skill does not hit any external API; no token required. The script only doe
|
|
|
106
106
|
Show **every scene in full** — do not collapse them with phrases like "scenes 2–6 same as above".
|
|
107
107
|
The user is reviewing the narration word by word; a summary they cannot proofread defeats the gate.
|
|
108
108
|
|
|
109
|
+
> ⚠️ **Read every value back from the returned DSL, never from what you meant to pass.**
|
|
110
|
+
> The summary exists so the user can catch a wrong tool call; a summary written from intent hides
|
|
111
|
+
> exactly the bug it should surface.
|
|
112
|
+
> - Durations ← `scenes[].duration`, **not** your `--duration` argument (`fit-caption` / `fit-narration`
|
|
113
|
+
> templates recompute it and ignore the target you passed).
|
|
114
|
+
> - On-screen text ← `textLayers[]`, `customPayload.caption.lines`, `customPayload.carousel.items` —
|
|
115
|
+
> quoted verbatim, with the counts you actually see.
|
|
116
|
+
> - If something you intended to set is missing or empty in the returned DSL, that is a failed call:
|
|
117
|
+
> say so and re-run `gen_script.py` with the right flags. Listing caption lines that are not in
|
|
118
|
+
> `customPayload.caption.lines` means the user confirms a script that does not exist and pays to
|
|
119
|
+
> render something else.
|
|
120
|
+
|
|
109
121
|
### Summary content
|
|
110
122
|
|
|
111
123
|
The agent should show the following in clear Markdown:
|
|
@@ -156,9 +168,12 @@ For these templates the picture comes from `customPayload.carousel.items`, which
|
|
|
156
168
|
When the user selects a `carousel-caption` template (or any template whose `assetRequirements` is image/video-only and whose `payloadStyle` is `carousel-caption`):
|
|
157
169
|
|
|
158
170
|
1. **Extract every media URL the user provided** (image or video links in the prompt) and pass each one as a separate `--carousel-items <url>` flag — preserve the user's order, and pass the URLs **verbatim** (do not rewrite host/path/query).
|
|
159
|
-
2.
|
|
171
|
+
2. Pass each on-screen caption line as `--caption-lines '<text>'`. Whether this is optional depends on the template's `capabilities.durationStrategy`, **not** on `needsNarration` (every `carousel-caption` template has `needsNarration: false`):
|
|
172
|
+
- `durationStrategy: fit-caption` (e.g. `spotlight-card`) → **caption lines are mandatory.** The template has no narration and the typewriter copy is both the content and the clock: it is what the video says *and* what decides how long it runs. **If the user did not supply the copy, write it yourself** from the material you researched (repo README, page screenshots, the topic) and pass it. `gen_script.py` hard-fails on an empty caption for these templates.
|
|
173
|
+
- `durationStrategy: fit-images` (e.g. `adaptive-image-video` / `image-to-video`) → purely visual, captions genuinely optional; duration comes from the image count.
|
|
160
174
|
3. **Never call gen_script for a `carousel-caption` template without `--carousel-items`.** If the user picked such a template but provided no media, ask them for the image/video URLs first — do not generate an empty carousel.
|
|
161
175
|
4. Do **not** route these user-provided images through `gen-image`; they are existing assets and go straight into the carousel.
|
|
176
|
+
5. Nothing downstream fills these in for you. `gen_script.py` routes on `capabilities.payloadStyle` alone — omitting the flags does **not** fall back to a generic path that generates images or writes copy; it assembles an empty carousel / empty caption. There is no auto-generation of caption text anywhere in the pipeline.
|
|
162
177
|
|
|
163
178
|
### Command example
|
|
164
179
|
|
|
@@ -266,7 +281,9 @@ python3 <SkillDir>/scripts/gen_script.py \
|
|
|
266
281
|
|------|-------------|---------|
|
|
267
282
|
| `--topic` | Video topic (required unless `--validate`). | — |
|
|
268
283
|
| `--platform` | Target platform: `douyin` / `xiaohongshu` / `bilibili` / `wechat` / `youtube` / `generic`. | `generic` |
|
|
269
|
-
| `--
|
|
284
|
+
| `--headline` | On-screen main title (4–12 chars / ~3 words). Written to `meta.headline` + `textLayers[role=headline]`. **Pass it whenever the user gave a title** — otherwise headline falls back to the long-form topic and overflows the top text layer. | falls back to `--topic` |
|
|
285
|
+
| `--subheadline` | On-screen subtitle / project name / slogan. Written to `meta.subheadline` + `textLayers[role=subheadline]`. Not the same thing as CC subtitles (`global.subtitle`). | `""` |
|
|
286
|
+
| `--duration` | Target duration (seconds). Templates whose `durationStrategy` is `fit-caption` / `fit-narration` recompute the real duration and ignore this value. | `30` |
|
|
270
287
|
| `--style` | Style tag. | — |
|
|
271
288
|
| `--ratio` | Aspect ratio. | `16:9` |
|
|
272
289
|
| `--scenes` | Scene count. | auto-planned |
|
|
@@ -279,7 +296,7 @@ python3 <SkillDir>/scripts/gen_script.py \
|
|
|
279
296
|
| `--stub-image-url` | Test mode: every image AssetRef is written as existing + generated + this URL, no prompt (env: `STUB_IMAGE_URL`). | — |
|
|
280
297
|
| `--stub-video-url` | Test mode: every video AssetRef is written as existing + generated + this URL, no prompt (env: `STUB_VIDEO_URL`). | — |
|
|
281
298
|
| `--carousel-items` | Repeatable. Media URL placed directly into `customPayload.carousel.items` for `carousel-caption` templates (e.g. `adaptive-image-video`, `spotlight-card`). Bypasses gen-image. **Required** for `carousel-caption` templates when the user supplies images. | — |
|
|
282
|
-
| `--caption-lines` | Repeatable. On-screen typewriter caption line for `carousel-caption` templates → `customPayload.caption.lines
|
|
299
|
+
| `--caption-lines` | Repeatable. On-screen typewriter caption line for `carousel-caption` templates → `customPayload.caption.lines` (max 10 lines). Supports `**emphasis**`. **Required** for `durationStrategy: fit-caption` templates (`spotlight-card`) — write the lines yourself if the user did not supply them. Optional only for `fit-images` templates. | — |
|
|
283
300
|
|
|
284
301
|
## DSL generation principles
|
|
285
302
|
|
|
@@ -295,7 +312,7 @@ Apply the following principles when producing the DSL:
|
|
|
295
312
|
instead of one continuous paragraph.
|
|
296
313
|
5. **Moderate scene count**: 30-second videos work well with 4–6 scenes, 60-second videos with 6–10.
|
|
297
314
|
6. **Leave room for templates**: pick generic layouts; do not assume a specific template implementation.
|
|
298
|
-
7. **Image model allowlist**: every `type: image` + `source: gen-image` `AssetRef`'s `payload.model` **must** be one of the values in the table below. **Never** use display names, short forms, or made-up ids (e.g. `seedream`, `
|
|
315
|
+
7. **Image model allowlist**: every `type: image` + `source: gen-image` `AssetRef`'s `payload.model` **must** be one of the values in the table below. **Never** use display names, short forms, or made-up ids (e.g. `seedream`, `seedream-5`, etc.).
|
|
299
316
|
|
|
300
317
|
### Allowlist `model` values aligned with gen-image
|
|
301
318
|
|
|
@@ -307,12 +324,11 @@ prefix and version — not a short alias:
|
|
|
307
324
|
|-----------------|--------------|----------|-------|
|
|
308
325
|
| `doubao/doubao-seedream-5-0-260128` | Seedream 5.0 Lite | Volcano | Default. Highest output resolution, up to 14 reference images. |
|
|
309
326
|
| `doubao/doubao-seedream-5-0-pro-260628` | Seedream 5.0 Pro | Volcano | High fidelity: precise element placement, faithful on-image text. Up to 10 reference images, caps out around 2K. Costs noticeably more per image. |
|
|
310
|
-
| `gemini-3-pro` | Gemini 3 Pro | Google | Up to 4 reference images. |
|
|
311
327
|
|
|
312
328
|
**Agent behavior (avoid accidentally rewriting `model`)**:
|
|
313
329
|
|
|
314
330
|
- `gen_script.py` already writes a valid `payload.model` (`doubao/doubao-seedream-5-0-260128` unless `DEFAULT_IMAGE_MODEL` overrides it). When the user only asks to refine narration, change `payload.prompt`, add or remove scenes, etc. and does **not** ask to change the image model, the agent **must keep** each image asset's original `payload.model` — do not replace it under the guise of "polishing the script".
|
|
315
|
-
- **Only when the user explicitly asks to change the image model** (e.g. switches to the Pro variant
|
|
331
|
+
- **Only when the user explicitly asks to change the image model** (e.g. switches to the Pro variant), update the corresponding image `AssetRef`'s `payload.model` to the matching row id from the table. Writing a display name or an alias into JSON is wrong.
|
|
316
332
|
- When creating a new image `AssetRef`, pick one of the values above for `payload.model`; default to `doubao/doubao-seedream-5-0-260128` to match the script, or to whichever value the user specified.
|
|
317
333
|
- If a run fails with an unknown-model error, the catalog has moved on from this table — check `/model/capabilities` rather than guessing a version string.
|
|
318
334
|
|
|
@@ -321,6 +337,9 @@ prefix and version — not a short alias:
|
|
|
321
337
|
- **Schema validation failed**: check the DSL JSON shape and required fields against the schema.
|
|
322
338
|
- **Scene duration mismatch**: adjust the narration length or the scene duration.
|
|
323
339
|
- **Invalid platform**: look at the supported-platform list.
|
|
340
|
+
- **`carousel-caption template ... needs visual or text content`**: you passed neither `--carousel-items` nor `--caption-lines`. Pass the user's media URLs (and caption lines where the template requires them).
|
|
341
|
+
- **`template ... is typewriter-driven ... but --caption-lines is empty`**: a `fit-caption` template (e.g. `spotlight-card`) got no caption. Write the copy yourself if the user did not supply it, then pass one `--caption-lines` per line.
|
|
342
|
+
- **`duration Ns is below/above template ... supportedDurations`**: the assembled DSL falls outside the range the template declares it was designed for. Below the minimum usually means the content is too thin (add caption lines / narration / scenes); above the maximum means trimming content or lowering `--duration`. This is enforced at generation time on purpose — a degenerate video still costs full render credits.
|
|
324
343
|
|
|
325
344
|
## scripts/ contents
|
|
326
345
|
|
|
@@ -475,6 +475,51 @@ def _resolve_contract(template_config: dict | None) -> dict:
|
|
|
475
475
|
}
|
|
476
476
|
|
|
477
477
|
|
|
478
|
+
def _enforce_supported_duration(
|
|
479
|
+
dsl: dict, template_config: dict | None, template_id: str | None
|
|
480
|
+
) -> None:
|
|
481
|
+
"""校验成片总时长落在模板自己声明的 ``supportedDurations`` 区间内。
|
|
482
|
+
|
|
483
|
+
这条约束此前只在 template-library 的 CI(``check-dsl-examples.mjs``)对仓库里的
|
|
484
|
+
示例 DSL 生效,运行时链路(gen_script → prepare_video_assets → render_video)没有
|
|
485
|
+
任何一环校验它。于是 spotlight-card(``min: 10``)可以静默产出 5s 成片——模板自己
|
|
486
|
+
声明"我不是为 5s 设计的",却没人拦。这里在 DSL 出厂前补上同一道栅栏。
|
|
487
|
+
|
|
488
|
+
越界即报错退出,而不是静默出片:时长不足通常意味着内容(打字机文案 / 旁白 / 场景)
|
|
489
|
+
根本没填够,继续往下走只会烧掉渲染积分换一条废片。
|
|
490
|
+
"""
|
|
491
|
+
sd = (template_config or {}).get("supportedDurations")
|
|
492
|
+
if not isinstance(sd, dict):
|
|
493
|
+
return
|
|
494
|
+
|
|
495
|
+
total = sum(s.get("duration", 0) for s in dsl.get("scenes", []))
|
|
496
|
+
lo = sd.get("min")
|
|
497
|
+
hi = sd.get("max")
|
|
498
|
+
|
|
499
|
+
if isinstance(lo, (int, float)) and total < lo:
|
|
500
|
+
print(
|
|
501
|
+
f"❌ duration {total}s is below template '{template_id}' declared minimum {lo}s "
|
|
502
|
+
f"(supportedDurations: [{lo}, {hi}]).\n"
|
|
503
|
+
" The template declares it is not designed for clips this short; rendering "
|
|
504
|
+
"anyway burns credits on a degenerate video.\n"
|
|
505
|
+
" Fix: add content until the estimated duration reaches the minimum — more "
|
|
506
|
+
"--caption-lines for typewriter-driven templates, longer narration / more scenes "
|
|
507
|
+
"for narration-driven ones.",
|
|
508
|
+
file=sys.stderr,
|
|
509
|
+
)
|
|
510
|
+
sys.exit(1)
|
|
511
|
+
|
|
512
|
+
if isinstance(hi, (int, float)) and total > hi:
|
|
513
|
+
print(
|
|
514
|
+
f"❌ duration {total}s exceeds template '{template_id}' declared maximum {hi}s "
|
|
515
|
+
f"(supportedDurations: [{lo}, {hi}]).\n"
|
|
516
|
+
" Fix: shorten the content (fewer --caption-lines / scenes) or lower --duration, "
|
|
517
|
+
"or pick a template that supports longer videos.",
|
|
518
|
+
file=sys.stderr,
|
|
519
|
+
)
|
|
520
|
+
sys.exit(1)
|
|
521
|
+
|
|
522
|
+
|
|
478
523
|
def _plan_contract_scenes(
|
|
479
524
|
contract: dict, topic: str, duration: int, scene_count: int | None, language: str
|
|
480
525
|
) -> list:
|
|
@@ -586,6 +631,8 @@ def _build_carousel_caption_dsl(
|
|
|
586
631
|
resolution: str,
|
|
587
632
|
output_language: str,
|
|
588
633
|
resolved_voice_id: str,
|
|
634
|
+
font_id: str | None,
|
|
635
|
+
font_name: str | None,
|
|
589
636
|
narration_enabled: bool,
|
|
590
637
|
payload_defaults: dict,
|
|
591
638
|
duration_strategy: str | None,
|
|
@@ -732,6 +779,7 @@ def _build_carousel_caption_dsl(
|
|
|
732
779
|
# 并省略 global.narration,避免下游误判存在旁白。
|
|
733
780
|
"subtitle": {"enabled": narration_enabled, "style": "bottom"},
|
|
734
781
|
**({"narration": {"voiceId": resolved_voice_id, "speed": 1.0}} if narration_enabled else {}),
|
|
782
|
+
**({"font": {"fontId": font_id, **({"fontName": font_name} if font_name else {})}} if font_id else {}),
|
|
735
783
|
"bgm": {"enabled": True, "volume": 0.12},
|
|
736
784
|
},
|
|
737
785
|
"assets": assets,
|
|
@@ -779,6 +827,8 @@ def build_dsl(
|
|
|
779
827
|
ratio: str,
|
|
780
828
|
resolution: str,
|
|
781
829
|
voice_id: str,
|
|
830
|
+
font_id: str | None,
|
|
831
|
+
font_name: str | None,
|
|
782
832
|
scene_count: int | None,
|
|
783
833
|
allow_digital_human: bool,
|
|
784
834
|
allow_ai_video: bool,
|
|
@@ -861,7 +911,32 @@ def build_dsl(
|
|
|
861
911
|
file=sys.stderr,
|
|
862
912
|
)
|
|
863
913
|
sys.exit(1)
|
|
864
|
-
|
|
914
|
+
# 兜底校验 ②:durationStrategy=fit-caption 的模板(spotlight-card 类)由打字机
|
|
915
|
+
# 文案驱动节奏 —— caption 就是内容本体,不是可选装饰。caption_lines 为空时上面的
|
|
916
|
+
# "两者皆空" 检查放行,产出的却是「顶部标题 + 轮播、底部一个字都没有」的退化片:
|
|
917
|
+
# 估时掉到轮播地板值(2 张图 ≈ 5s),而调用方往往还在确认摘要里描述了一段
|
|
918
|
+
# 根本没进 DSL 的文案,用户在确认环节也看不出来。所以这里必须硬失败。
|
|
919
|
+
# 注意:只卡 fit-caption。carousel-caption 里 durationStrategy=fit-images 的
|
|
920
|
+
# 纯视觉模板(image-to-video 等)本来就允许无文案,不受影响。
|
|
921
|
+
if contract["duration_strategy"] == "fit-caption" and not (caption_lines or []):
|
|
922
|
+
print(
|
|
923
|
+
"❌ template "
|
|
924
|
+
f"'{template_id}' is typewriter-driven (capabilities.durationStrategy="
|
|
925
|
+
"fit-caption), but --caption-lines is empty.\n"
|
|
926
|
+
" For this template the bottom typewriter copy IS the content: it carries "
|
|
927
|
+
"the message and it decides the video length. With no lines the render "
|
|
928
|
+
"collapses to the carousel floor (~5s for 2 images) and shows no text at all.\n"
|
|
929
|
+
" Fix: pass one --caption-lines '<text>' per line. If the user did not "
|
|
930
|
+
"supply the copy, WRITE IT YOURSELF from the material you researched "
|
|
931
|
+
"(repo README, page screenshots, the user's topic) and pass it — do not leave "
|
|
932
|
+
"it empty, and do not describe lines you never passed.\n"
|
|
933
|
+
" gen_script.py --topic <topic> --template-id "
|
|
934
|
+
f"{template_id} --carousel-items <url> "
|
|
935
|
+
"--caption-lines '<line 1>' --caption-lines '<line 2>' ...",
|
|
936
|
+
file=sys.stderr,
|
|
937
|
+
)
|
|
938
|
+
sys.exit(1)
|
|
939
|
+
carousel_dsl = _build_carousel_caption_dsl(
|
|
865
940
|
template_id=template_id,
|
|
866
941
|
topic=topic,
|
|
867
942
|
headline=effective_headline,
|
|
@@ -875,10 +950,14 @@ def build_dsl(
|
|
|
875
950
|
resolution=resolution,
|
|
876
951
|
output_language=output_language,
|
|
877
952
|
resolved_voice_id=resolved_voice_id,
|
|
953
|
+
font_id=font_id,
|
|
954
|
+
font_name=font_name,
|
|
878
955
|
narration_enabled=needs_narration,
|
|
879
956
|
payload_defaults=contract["payload_defaults"],
|
|
880
957
|
duration_strategy=contract["duration_strategy"],
|
|
881
958
|
)
|
|
959
|
+
_enforce_supported_duration(carousel_dsl, template_config, template_id)
|
|
960
|
+
return carousel_dsl
|
|
882
961
|
|
|
883
962
|
# ── 其余模板:统一场景规划(arc 叙事弧 / single / fixed)+ 统一装配循环 ──────
|
|
884
963
|
scene_plans = _plan_contract_scenes(contract, topic, duration, scene_count, output_language)
|
|
@@ -940,14 +1019,16 @@ def build_dsl(
|
|
|
940
1019
|
})
|
|
941
1020
|
else:
|
|
942
1021
|
# 视频素材:复用 image prompt 生成器作为兜底,再追加 "视频/动态" 关键词
|
|
943
|
-
# 模型 / 时长 / 比例都遵循 gen-video 校验规则(Seedance 4-
|
|
1022
|
+
# 模型 / 时长 / 比例都遵循 gen-video 校验规则(Seedance 2.0:4-15s)
|
|
944
1023
|
image_result = generate_image_prompt(plan["purpose"], topic, style, narration_text=narration_text)
|
|
945
1024
|
video_prompt = image_result["prompt"]
|
|
946
|
-
#
|
|
947
|
-
video_duration = max(4, min(int(plan["duration"]),
|
|
1025
|
+
# 视频时长按 gen-video 的 4-15s 区间截断
|
|
1026
|
+
video_duration = max(4, min(int(plan["duration"]), 15))
|
|
948
1027
|
vid_payload = {
|
|
949
1028
|
"prompt": video_prompt,
|
|
950
|
-
|
|
1029
|
+
# 写别名而不是带日期的模型 ID:真源是 ab-api 的能力目录,
|
|
1030
|
+
# 版本号换代时这里不该跟着改(seedance → 当前的 Seedance 2.0)
|
|
1031
|
+
"model": os.environ.get("DEFAULT_VIDEO_MODEL", "seedance"),
|
|
951
1032
|
"ratio": ratio,
|
|
952
1033
|
"duration": video_duration,
|
|
953
1034
|
}
|
|
@@ -1092,6 +1173,7 @@ def build_dsl(
|
|
|
1092
1173
|
# global.narration,避免下游误判存在旁白。
|
|
1093
1174
|
"subtitle": {"enabled": needs_narration, "style": "bottom"},
|
|
1094
1175
|
**({"narration": {"voiceId": resolved_voice_id, "speed": 1.0}} if needs_narration else {}),
|
|
1176
|
+
**({"font": {"fontId": font_id, **({"fontName": font_name} if font_name else {})}} if font_id else {}),
|
|
1095
1177
|
"bgm": {"enabled": True, "volume": 0.12},
|
|
1096
1178
|
},
|
|
1097
1179
|
"assets": assets,
|
|
@@ -1102,6 +1184,8 @@ def build_dsl(
|
|
|
1102
1184
|
if template_id:
|
|
1103
1185
|
dsl["meta"]["templateId"] = template_id
|
|
1104
1186
|
|
|
1187
|
+
_enforce_supported_duration(dsl, template_config, template_id)
|
|
1188
|
+
|
|
1105
1189
|
return dsl
|
|
1106
1190
|
|
|
1107
1191
|
|
|
@@ -1128,6 +1212,18 @@ Examples:
|
|
|
1128
1212
|
parser.add_argument("--resolution", default="1080p", help="Resolution (default: 1080p)")
|
|
1129
1213
|
parser.add_argument("--scenes", type=int, default=None, help="Scene count (default: auto-planned)")
|
|
1130
1214
|
parser.add_argument("--voice-id", default=None, help="Narration voice id. When omitted, the resolver picks template.defaultVoiceId, then the language-keyed fallback (zh→Chinese (Mandarin)_Male_Announcer, en→TBD English voice). gen_voice --list-voices --local prints the language-tagged catalog.")
|
|
1215
|
+
parser.add_argument(
|
|
1216
|
+
"--font-id",
|
|
1217
|
+
default=None,
|
|
1218
|
+
help=(
|
|
1219
|
+
"Font family key from the font library (font.uniq_id, e.g. zzgf-xi-mai). "
|
|
1220
|
+
"Omit to follow the template's own font pairing. "
|
|
1221
|
+
"Pass the opaque key, NOT a CSS family name: the family name is a rendering "
|
|
1222
|
+
"detail resolved by ab-render; a mistyped family name silently falls back to "
|
|
1223
|
+
"the default font with no error."
|
|
1224
|
+
),
|
|
1225
|
+
)
|
|
1226
|
+
parser.add_argument("--font-name", default=None, help="Human-readable font name. Logged and stored for display only; never used for rendering.")
|
|
1131
1227
|
parser.add_argument("--allow-digital-human", action="store_true", help="Allow digital-human assets")
|
|
1132
1228
|
parser.add_argument("--allow-ai-video", action="store_true", help="Allow AI-generated video assets")
|
|
1133
1229
|
parser.add_argument("--template-id", default=None, help="Template id. The template owns outputLanguage and may declare a defaultVoiceId.")
|
|
@@ -1276,6 +1372,8 @@ Examples:
|
|
|
1276
1372
|
ratio=args.ratio,
|
|
1277
1373
|
resolution=args.resolution,
|
|
1278
1374
|
voice_id=args.voice_id,
|
|
1375
|
+
font_id=args.font_id,
|
|
1376
|
+
font_name=args.font_name,
|
|
1279
1377
|
scene_count=args.scenes,
|
|
1280
1378
|
allow_digital_human=args.allow_digital_human,
|
|
1281
1379
|
allow_ai_video=args.allow_ai_video,
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"items": {
|
|
77
77
|
"type": "string"
|
|
78
78
|
},
|
|
79
|
-
"description": "Bottom typewriter text lines for templates that support a caption/typewriter area (e.g. spotlight-card). Each element is one line of text. Supports **emphasis** syntax (rendered with accent color). **Must** pass when the user explicitly provides bullet-point text / bottom copy
|
|
79
|
+
"description": "Bottom typewriter text lines for templates that support a caption/typewriter area (e.g. spotlight-card). Each element is one line of text, max 10 lines. Supports **emphasis** syntax (rendered with accent color). **Must** pass when the user explicitly provides bullet-point text / bottom copy. **Also must pass — written by you — when the user did NOT provide any copy but the template is typewriter-driven** (capabilities.durationStrategy=fit-caption, e.g. spotlight-card): such templates have no narration, so these lines are both the video's content and the thing that decides its duration. Draft them from the material you researched (repo README, page screenshots, the topic). Leaving this empty for a fit-caption template is rejected: nothing auto-generates caption text, and an empty caption renders a titled carousel with no words at all."
|
|
80
80
|
},
|
|
81
81
|
"stub_image_url": {
|
|
82
82
|
"type": "string",
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gen-video
|
|
3
3
|
description: |
|
|
4
|
-
AI video generation skill: produce a short clip from a text prompt. Backed by ab-api's `/model/genVideo` (Seedance
|
|
4
|
+
AI video generation skill: produce a short clip from a text prompt. Backed by ab-api's `/model/genVideo` (Seedance 2.0 family).
|
|
5
5
|
|
|
6
6
|
Use this skill immediately whenever the user asks for any of:
|
|
7
7
|
- Text-to-video, AI-generated clip, "make a short video of ..."
|
|
8
|
-
- Generate video with Doubao / Seedance
|
|
8
|
+
- Generate video with Doubao / Seedance
|
|
9
9
|
- Image-to-video, first-frame / last-frame, reference-image-to-video
|
|
10
10
|
|
|
11
11
|
Even without an explicit "use AI", any request that turns a description into a moving clip should route here.
|
|
12
12
|
triggers:
|
|
13
13
|
- Text-to-video, AI-generated clip, "make a short video of ..."
|
|
14
|
-
- Generate video with Doubao / Seedance
|
|
14
|
+
- Generate video with Doubao / Seedance
|
|
15
15
|
- Image-to-video, first-frame / last-frame, reference-image-to-video
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
# AI Video Generation Skill
|
|
19
19
|
|
|
20
|
-
Wraps ab-api's `POST /model/genVideo` (the same endpoint the web "Lingchuang AI Video" tool uses), authenticated with the **Tianyan privateToken**, routed through LiteLLM to **Seedance
|
|
20
|
+
Wraps ab-api's `POST /model/genVideo` (the same endpoint the web "Lingchuang AI Video" tool uses), authenticated with the **Tianyan privateToken**, routed through LiteLLM to **Seedance 2.0**. Generation is async — the handler submits the task and polls `/model/getVideoStatus` until completion.
|
|
21
21
|
|
|
22
22
|
> This skill was migrated from a Python script to an remixmate CLI HTTP handler (`entry.type: http`). The agent invocation is unchanged (same tool name `gen_video`, same params as in `skill.json`); local repro goes through `remixmate gen-video ...`.
|
|
23
23
|
|
|
@@ -27,29 +27,34 @@ The authoritative roster — ids, aliases and per-model limits — lives in the
|
|
|
27
27
|
(`/model/capabilities`), which the CLI fetches at runtime. The table below mirrors it; when the
|
|
28
28
|
two disagree, the catalog wins.
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
| `
|
|
33
|
-
|
|
34
|
-
| `
|
|
30
|
+
All three are Seedance 2.0; they differ only in price tier and top resolution.
|
|
31
|
+
|
|
32
|
+
| LiteLLM `model` | Display name | Provider | Resolution | Notes |
|
|
33
|
+
|-----------------|--------------|----------|------------|-------|
|
|
34
|
+
| `doubao-seedance-2-0-mini-260615` | Seedance-2.0-mini | Volcano | `480p` `720p` | Default. Cheapest tier (~half the standard rate) |
|
|
35
|
+
| `doubao-seedance-2-0-fast-260128` | Seedance-2.0-fast | Volcano | `480p` `720p` | Mid tier |
|
|
36
|
+
| `doubao-seedance-2-0-260128` | Seedance-2.0 | Volcano | `480p` `720p` `1080p` | Highest quality; the only tier with 1080p |
|
|
35
37
|
|
|
36
38
|
**Model shortcuts** (`--model` / `-m` accepts these directly):
|
|
37
|
-
- `seedance
|
|
38
|
-
- `
|
|
39
|
-
- `
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
|
47
|
-
|
|
48
|
-
| **
|
|
49
|
-
| **
|
|
50
|
-
| **
|
|
51
|
-
| **
|
|
52
|
-
| **
|
|
39
|
+
- `seedance-mini` / `seedance-2.0-mini` → Seedance-2.0-mini
|
|
40
|
+
- `seedance-fast` / `seedance-2.0-fast` → Seedance-2.0-fast
|
|
41
|
+
- `seedance` / `seedance-2.0` → Seedance-2.0
|
|
42
|
+
|
|
43
|
+
Veo 3.1 / Veo 3.1 Fast are **not available** — there is no working Veo channel on the gateway,
|
|
44
|
+
so they are absent from the catalog and `--model veo` will fail.
|
|
45
|
+
|
|
46
|
+
### Parameter ranges (identical across the three tiers, except resolution)
|
|
47
|
+
|
|
48
|
+
| | Seedance 2.0 mini / fast / standard |
|
|
49
|
+
|--|--|
|
|
50
|
+
| **Aspect ratio** | `adaptive` `16:9` `4:3` `1:1` `3:4` `9:16` `21:9` |
|
|
51
|
+
| **Resolution** | `480p` `720p` (`1080p` on `seedance` only) |
|
|
52
|
+
| **Duration** | 4–15 seconds (continuous integers) |
|
|
53
|
+
| **First / last frame** | yes |
|
|
54
|
+
| **Reference images** | yes, up to 9 |
|
|
55
|
+
| **Generated audio** | yes |
|
|
56
|
+
| **Fixed camera** | yes |
|
|
57
|
+
| **Negative prompt** | ignored (Veo-only parameter) |
|
|
53
58
|
|
|
54
59
|
## Auth & environment
|
|
55
60
|
|
|
@@ -61,7 +66,7 @@ No skill-local env file — the executing process inherits the system environmen
|
|
|
61
66
|
| Env var | Description | Default |
|
|
62
67
|
|---------|-------------|---------|
|
|
63
68
|
| `PRIV_TOKEN` | Tianyan token; `--priv-token` overrides | none |
|
|
64
|
-
| `MM_VIDEO_MODEL` | Default model id | `
|
|
69
|
+
| `MM_VIDEO_MODEL` | Default model id or shortcut | catalog default (`seedance-mini`) |
|
|
65
70
|
| `MM_API_BASE_URL` | API root; `--api-base-url` overrides | `https://api.remixmate.com/api` |
|
|
66
71
|
| `AGENT_NAME` | Optional `x-invoke-agent` header | none |
|
|
67
72
|
|
|
@@ -71,7 +76,7 @@ No skill-local env file — the executing process inherits the system environmen
|
|
|
71
76
|
2. **Async job**: video generation is async; the handler polls until completion (typically 1–3 minutes) and emits `__progress__` lines.
|
|
72
77
|
3. **Surface results**: stdout prints the video URL on its own line; show it directly to the user (no download needed — the URL is cloud-persisted).
|
|
73
78
|
|
|
74
|
-
###
|
|
79
|
+
### Text-to-video (default model: Seedance-2.0-mini)
|
|
75
80
|
|
|
76
81
|
```bash
|
|
77
82
|
remixmate gen-video \
|
|
@@ -80,7 +85,7 @@ remixmate gen-video \
|
|
|
80
85
|
--ratio "16:9"
|
|
81
86
|
```
|
|
82
87
|
|
|
83
|
-
###
|
|
88
|
+
### First/last frame + audio
|
|
84
89
|
|
|
85
90
|
Frame images accept local file paths, HTTPS URLs, or data URIs (local files are base64-encoded into a data URI).
|
|
86
91
|
|
|
@@ -93,33 +98,25 @@ remixmate gen-video \
|
|
|
93
98
|
--generate-audio
|
|
94
99
|
```
|
|
95
100
|
|
|
96
|
-
###
|
|
101
|
+
### 1080p final cut
|
|
102
|
+
|
|
103
|
+
Only `seedance` (the standard tier) offers 1080p; it also costs roughly twice mini per second.
|
|
97
104
|
|
|
98
105
|
```bash
|
|
99
106
|
remixmate gen-video \
|
|
100
|
-
--model
|
|
107
|
+
--model seedance \
|
|
101
108
|
--prompt "<video description>" \
|
|
102
109
|
--duration 8 \
|
|
103
110
|
--ratio "16:9" \
|
|
104
|
-
--resolution
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Veo 3.1 Fast for rapid iteration
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
remixmate gen-video \
|
|
111
|
-
--model veo-fast \
|
|
112
|
-
--prompt "<video description>" \
|
|
113
|
-
--duration 6
|
|
111
|
+
--resolution 1080p
|
|
114
112
|
```
|
|
115
113
|
|
|
116
|
-
###
|
|
114
|
+
### With reference images
|
|
117
115
|
|
|
118
|
-
Pass `--reference` multiple times (
|
|
116
|
+
Pass `--reference` multiple times (up to 9).
|
|
119
117
|
|
|
120
118
|
```bash
|
|
121
119
|
remixmate gen-video \
|
|
122
|
-
--model veo \
|
|
123
120
|
--prompt "<video description>" \
|
|
124
121
|
--reference ./ref1.png \
|
|
125
122
|
--reference ./ref2.png \
|
|
@@ -131,16 +128,16 @@ remixmate gen-video \
|
|
|
131
128
|
| Flag | Description | Default |
|
|
132
129
|
|------|-------------|---------|
|
|
133
130
|
| `-p` / `--prompt` | Video description (combinable with first/last frame or references) | — |
|
|
134
|
-
| `-m` / `--model` | Model id or shortcut (`seedance` / `
|
|
135
|
-
| `-d` / `--duration` | Duration in seconds
|
|
136
|
-
| `-r` / `--ratio` | Aspect ratio
|
|
137
|
-
| `--resolution` | Resolution.
|
|
131
|
+
| `-m` / `--model` | Model id or shortcut (`seedance-mini` / `seedance-fast` / `seedance`) | see `MM_VIDEO_MODEL` |
|
|
132
|
+
| `-d` / `--duration` | Duration in seconds (4–15) | 5 |
|
|
133
|
+
| `-r` / `--ratio` | Aspect ratio; `adaptive` also accepted | `16:9` |
|
|
134
|
+
| `--resolution` | Resolution. `1080p` only on `seedance` | `720p` |
|
|
138
135
|
| `--first-frame` | First-frame image: local path, https URL, or data URI | none |
|
|
139
136
|
| `--last-frame` | Last-frame image | none |
|
|
140
|
-
| `--reference` | Reference image (repeatable
|
|
137
|
+
| `--reference` | Reference image (repeatable, max 9) | none |
|
|
141
138
|
| `--generate-audio` | Generate native audio | off |
|
|
142
|
-
| `--camera-fixed` | Fixed camera
|
|
143
|
-
| `--negative-prompt` | Negative prompt (
|
|
139
|
+
| `--camera-fixed` | Fixed camera | off |
|
|
140
|
+
| `--negative-prompt` | Negative prompt (Veo only; ignored by Seedance) | none |
|
|
144
141
|
| `--seed` | Random seed | none |
|
|
145
142
|
| `--person-generation` | Person policy: `allow_all` / `dont_allow` (Veo) | none |
|
|
146
143
|
| `--api-base-url` | Override API root | see above |
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"tier": "atomic",
|
|
5
5
|
"category": "asset",
|
|
6
6
|
"title": "AI Video Generation",
|
|
7
|
-
"description": "AI video generation: produce a short video clip from a text prompt.
|
|
7
|
+
"description": "AI video generation: produce a short video clip from a text prompt. Three Seedance 2.0 tiers (mini / fast / standard), plus first/last frame and reference images.",
|
|
8
8
|
"auth": "required",
|
|
9
9
|
"joinsTake": true,
|
|
10
10
|
"envVars": [
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"model": {
|
|
28
28
|
"type": "string",
|
|
29
|
-
"description": "Model: 'seedance' (default;
|
|
29
|
+
"description": "Model: 'seedance-mini' (default; cheapest, 480p/720p), 'seedance-fast' (480p/720p), or 'seedance' (Seedance 2.0, adds 1080p). All are 4-15s and share the same features"
|
|
30
30
|
},
|
|
31
31
|
"duration": {
|
|
32
32
|
"type": "number",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"items": {
|
|
54
54
|
"type": "string"
|
|
55
55
|
},
|
|
56
|
-
"description": "Reference images: local file path, https URL, or data URI.
|
|
56
|
+
"description": "Reference images: local file path, https URL, or data URI. Up to 9; combinable with first_frame / last_frame."
|
|
57
57
|
},
|
|
58
58
|
"generate_audio": {
|
|
59
59
|
"type": "boolean",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
},
|
|
66
66
|
"negative_prompt": {
|
|
67
67
|
"type": "string",
|
|
68
|
-
"description": "Content to steer away from (Veo)"
|
|
68
|
+
"description": "Content to steer away from. Veo only — Seedance ignores it (kept for when a Veo channel is available again)"
|
|
69
69
|
},
|
|
70
70
|
"seed": {
|
|
71
71
|
"type": "number",
|
|
@@ -101,12 +101,12 @@
|
|
|
101
101
|
"last_frame",
|
|
102
102
|
"reference",
|
|
103
103
|
"generate_audio",
|
|
104
|
-
"camera_fixed"
|
|
105
|
-
"negative_prompt"
|
|
104
|
+
"camera_fixed"
|
|
106
105
|
],
|
|
107
106
|
"hidden": [
|
|
108
107
|
"json_output",
|
|
109
108
|
"seed",
|
|
109
|
+
"negative_prompt",
|
|
110
110
|
"person_generation"
|
|
111
111
|
]
|
|
112
112
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"skillName": "gen-video",
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "339",
|
|
5
|
-
"version": "
|
|
6
|
-
"skillDescription": "AI video generation skill: produce a short clip from a text prompt. Backed by ab-api's `/model/genVideo` (Seedance
|
|
5
|
+
"version": "V9",
|
|
6
|
+
"skillDescription": "AI video generation skill: produce a short clip from a text prompt. Backed by ab-api's `/model/genVideo` (Seedance 2.0 family).\n\nUse this skill immediately whenever the user asks for any of:\n- Text-to-video, AI-generated clip, \"make a short video of ...\"\n- Generate video with Doubao / Seedance\n- Image-to-video, first-frame / last-frame, reference-image-to-video\n\nEven without an explicit \"use AI\", any request that turns a description into a moving clip should route here."
|
|
7
7
|
}
|
|
@@ -183,6 +183,16 @@ def build_binding(template: dict, dsl: dict) -> dict:
|
|
|
183
183
|
motion = template.get("defaultMotionPreset", "smooth")
|
|
184
184
|
colors = template.get("defaultColorScheme", [])
|
|
185
185
|
|
|
186
|
+
# 用户选中的字体(DSL 的 global.font)。这里只是把不透明 key 折进 typography,
|
|
187
|
+
# 真正的解析(uniqId → 排印家族名 + 字重文件)在 ab-render 侧完成。
|
|
188
|
+
#
|
|
189
|
+
# 优先级见 ab-platform/docs/font-selection-design.md §13.3:
|
|
190
|
+
# 用户选择 > variant.defaultFontId(预留档位,当前恒为空)
|
|
191
|
+
# > template.defaultTypography.bodyFont(现状裸 family 名)> 模板 theme 字栈
|
|
192
|
+
# 下面的 variant 合并在此之后执行,所以 fontId 单独在合并后再写回,
|
|
193
|
+
# 避免被 variant 的 defaultTypography 覆盖掉。
|
|
194
|
+
user_font_id = ((dsl.get("global", {}) or {}).get("font", {}) or {}).get("fontId")
|
|
195
|
+
|
|
186
196
|
# --- variant selection(确定性)---
|
|
187
197
|
# 优先级:
|
|
188
198
|
# 1) DSL 显式声明 — meta.templateVariant / meta.variant / renderHints.templateVariant
|
|
@@ -268,6 +278,10 @@ def build_binding(template: dict, dsl: dict) -> dict:
|
|
|
268
278
|
if vcolors:
|
|
269
279
|
colors = vcolors
|
|
270
280
|
|
|
281
|
+
# 用户的字体选择压过 variant 默认值(§13.3 的优先级第一档),所以写在合并之后。
|
|
282
|
+
if isinstance(user_font_id, str) and user_font_id.strip():
|
|
283
|
+
typography = {**typography, "fontId": user_font_id.strip()}
|
|
284
|
+
|
|
271
285
|
result = {
|
|
272
286
|
"version": "v1alpha1",
|
|
273
287
|
"templateId": template.get("templateId", ""),
|
|
@@ -105,6 +105,17 @@
|
|
|
105
105
|
"url": { "type": "string" },
|
|
106
106
|
"volume": { "type": "number", "default": 0.15, "minimum": 0, "maximum": 1 }
|
|
107
107
|
}
|
|
108
|
+
},
|
|
109
|
+
"font": {
|
|
110
|
+
"type": "object",
|
|
111
|
+
"description": "全局字体选择。省略 = 跟随模板自带的字体搭配。match_template 会把它折进 binding 的 globalOverrides.typography。",
|
|
112
|
+
"properties": {
|
|
113
|
+
"fontId": {
|
|
114
|
+
"type": "string",
|
|
115
|
+
"description": "字体库的不透明 key(font.uniq_id)。**不要在这里写 CSS family 名**:family 名是渲染细节,由 ab-render 调 /font/resolve 解析;写成 family 名一旦拼错就静默退回默认字体,没有任何报错。见 ab-platform/docs/font-selection-design.md §8.1。"
|
|
116
|
+
},
|
|
117
|
+
"fontName": { "type": "string", "description": "展示名,仅供人读与日志,渲染不使用" }
|
|
118
|
+
}
|
|
108
119
|
}
|
|
109
120
|
}
|
|
110
121
|
},
|