@remixmate/cli 0.1.1 → 0.9.1
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 +46 -0
- package/README.zh-CN.md +22 -0
- package/dist/auth/auth-lock.d.ts +26 -0
- package/dist/auth/auth-lock.js +100 -0
- package/dist/auth/auto-login.d.ts +20 -0
- package/dist/auth/auto-login.js +66 -0
- package/dist/auth/commands.d.ts +8 -0
- package/dist/auth/commands.js +130 -0
- package/dist/auth/credential-store.d.ts +44 -0
- package/dist/auth/credential-store.js +126 -0
- package/dist/auth/device-flow-runner.d.ts +43 -0
- package/dist/auth/device-flow-runner.js +62 -0
- package/dist/auth/device-flow.d.ts +52 -0
- package/dist/auth/device-flow.js +115 -0
- package/dist/auth/environment.d.ts +25 -0
- package/dist/auth/environment.js +48 -0
- package/dist/auth/resolve.d.ts +30 -0
- package/dist/auth/resolve.js +44 -0
- package/dist/cli.js +11 -0
- package/dist/handlers/gen-digital-human.js +1 -1
- package/dist/handlers/gen-image.js +1 -1
- package/dist/handlers/gen-video.js +1 -1
- package/dist/handlers/gen-voice.js +2 -2
- package/dist/http.d.ts +9 -5
- package/dist/http.js +24 -10
- package/dist/manifest.json +14 -3
- package/dist/runner.d.ts +1 -1
- package/dist/skill-schema.d.ts +18 -0
- package/dist/skill-schema.js +4 -0
- package/package.json +1 -1
- package/skills/export-jianying/skill.json +1 -0
- package/skills/gen-digital-human/SKILL.md +11 -11
- package/skills/gen-digital-human/skill.json +1 -0
- package/skills/gen-digital-human/version.json +1 -1
- package/skills/gen-image/SKILL.md +6 -6
- package/skills/gen-image/skill.json +1 -0
- package/skills/gen-image/version.json +1 -1
- package/skills/gen-script/scripts/gen_script.py +105 -31
- package/skills/gen-script/skill.json +3 -1
- package/skills/gen-script/version.json +1 -1
- package/skills/gen-video/SKILL.md +6 -6
- package/skills/gen-video/skill.json +1 -0
- package/skills/gen-video/version.json +1 -1
- package/skills/gen-voice/SKILL.md +6 -6
- package/skills/gen-voice/skill.json +1 -0
- package/skills/gen-voice/version.json +1 -1
- package/skills/prepare-video-assets/skill.json +1 -0
- package/skills/render-video/scripts/remote_renderer_client.py +9 -7
- package/skills/render-video/scripts/render_video.py +72 -15
- package/skills/render-video/skill.json +1 -0
- package/skills/render-video/version.json +1 -1
- package/skills/template-registry/README.md +12 -13
- package/skills/template-registry/SKILL.md +11 -12
- package/skills/template-registry/scripts/list_templates.py +87 -2
- package/skills/template-registry/scripts/registry_loader.py +117 -96
- package/skills/template-registry/scripts/render_job_client.py +12 -0
- package/skills/template-registry/skill.json +4 -2
- package/skills/template-registry/version.json +1 -1
- package/skills/template-registry/video_dsl/runtime/dsl_validator.py +2 -2
- package/skills/video-parser/skill.json +1 -0
- package/skills/web-capture/skill.json +1 -1
- package/skills/web-capture/version.json +1 -1
package/dist/runner.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { ParsedArgs } from './argv.js';
|
|
9
9
|
export interface RunOptions {
|
|
10
|
-
/** Override the skills directory (defaults to
|
|
10
|
+
/** Override the skills directory (defaults to the package's bundled skills/). */
|
|
11
11
|
baseDir?: string;
|
|
12
12
|
/** Raw argv slice after the skill name (passed verbatim for python; parsed for handlers). */
|
|
13
13
|
rawArgs: string[];
|
package/dist/skill-schema.d.ts
CHANGED
|
@@ -21,12 +21,30 @@ export type SkillEntry = {
|
|
|
21
21
|
type: 'builtin';
|
|
22
22
|
handler: string;
|
|
23
23
|
};
|
|
24
|
+
/**
|
|
25
|
+
* Skill 类别 — 区分"创作期 / 消费期 / 元数据型" skill。
|
|
26
|
+
*
|
|
27
|
+
* - "authoring": 创建 / 编辑模板期间使用,例如 template-registry / gen-script /
|
|
28
|
+
* render-video(用于 try_render) / prepare-video-assets。
|
|
29
|
+
* - "consuming": 消费已有模板生成媒体,例如 export-jianying / video-parser /
|
|
30
|
+
* web-capture(与"创建模板"无关,是消费侧场景)。
|
|
31
|
+
* - "asset": 生成单一类型素材的原子 skill:gen-image / gen-voice /
|
|
32
|
+
* gen-video / gen-digital-human。authoring 也会用,但通过 stub
|
|
33
|
+
* 方式占位;consuming 场景下是真调用。
|
|
34
|
+
* - "meta": 元 skill(如未来加入 doc-only 的 template-creator)。
|
|
35
|
+
*
|
|
36
|
+
* 下游消费方(如 ab-template-studio)按 category 自动挑选白名单,避免每加一个
|
|
37
|
+
* skill 就要改两侧 hardcode。
|
|
38
|
+
*/
|
|
39
|
+
export type SkillCategory = 'authoring' | 'consuming' | 'asset' | 'meta';
|
|
40
|
+
export declare const CATEGORY_VALUES: readonly ["authoring", "consuming", "asset", "meta"];
|
|
24
41
|
export interface RawSkillJson {
|
|
25
42
|
name: string;
|
|
26
43
|
toolName: string;
|
|
27
44
|
description: string;
|
|
28
45
|
title?: string;
|
|
29
46
|
tier?: string;
|
|
47
|
+
category?: SkillCategory;
|
|
30
48
|
parameters?: Record<string, unknown>;
|
|
31
49
|
scriptPath?: string;
|
|
32
50
|
entry?: SkillEntry;
|
package/dist/skill-schema.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* human-readable problems (empty = OK). The runtime loader skips + warns;
|
|
12
12
|
* the build treats them as fatal.
|
|
13
13
|
*/
|
|
14
|
+
export const CATEGORY_VALUES = ['authoring', 'consuming', 'asset', 'meta'];
|
|
14
15
|
export const TIER_VALUES = ['atomic', 'orchestration', 'tool'];
|
|
15
16
|
export const REQUIRED_SKILL_JSON_FIELDS = ['name', 'tier', 'title', 'description'];
|
|
16
17
|
/**
|
|
@@ -39,6 +40,9 @@ export function validateSkillJson(raw, skillId) {
|
|
|
39
40
|
if (raw.tier != null && !TIER_VALUES.includes(raw.tier)) {
|
|
40
41
|
errors.push(`skill.json.tier must be one of ${TIER_VALUES.join(' | ')}, got '${raw.tier}'`);
|
|
41
42
|
}
|
|
43
|
+
if (raw.category != null && !CATEGORY_VALUES.includes(raw.category)) {
|
|
44
|
+
errors.push(`skill.json.category must be one of ${CATEGORY_VALUES.join(' | ')}, got '${raw.category}'`);
|
|
45
|
+
}
|
|
42
46
|
if (raw.name && raw.name !== skillId) {
|
|
43
47
|
errors.push(`skill.json.name='${raw.name}' does not match directory name '${skillId}'`);
|
|
44
48
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remixmate/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "AI media generation skills for Claude Code / Codex — 11 skills covering image, video, voice, digital human, web capture, script, template registry, rendering, Jianying export, and video deconstruction.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"name": "export-jianying",
|
|
3
3
|
"toolName": "export_jianying",
|
|
4
4
|
"tier": "orchestration",
|
|
5
|
+
"category": "consuming",
|
|
5
6
|
"title": "Jianying (CapCut) Draft Export",
|
|
6
7
|
"description": "Jianying (CapCut) draft export: package asset URLs into a draft ZIP that Jianying can import. Supports automatic conversion from a RenderPlan.",
|
|
7
8
|
"envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "AGENT_NAME"],
|
|
@@ -21,7 +21,7 @@ triggers:
|
|
|
21
21
|
|
|
22
22
|
Wraps ab-api's digital-human endpoints (the same ones the web studio uses), authenticated with the **Tianyan privateToken**. Two providers: **Jimeng** (image-driven) and **HiFly** (video-driven). Generation is async — the handler submits the task and polls `/digital-human/video/status` until completion.
|
|
23
23
|
|
|
24
|
-
> This skill was migrated from a Python script to an
|
|
24
|
+
> 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_digital_human`, same params as in `skill.json`); local repro goes through `remixmate gen-digital-human ...`.
|
|
25
25
|
|
|
26
26
|
## Capabilities
|
|
27
27
|
|
|
@@ -54,24 +54,24 @@ By default only the URL is printed; generation is async and the handler polls un
|
|
|
54
54
|
### 1. List avatars
|
|
55
55
|
|
|
56
56
|
```bash
|
|
57
|
-
|
|
57
|
+
remixmate gen-digital-human --list-avatars
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
Optional filters:
|
|
61
61
|
|
|
62
62
|
```bash
|
|
63
63
|
# Filter by source (jimeng = image-driven, hifly = video-driven)
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
remixmate gen-digital-human --list-avatars --source jimeng
|
|
65
|
+
remixmate gen-digital-human --list-avatars --source hifly
|
|
66
66
|
|
|
67
67
|
# Filter by gender
|
|
68
|
-
|
|
68
|
+
remixmate gen-digital-human --list-avatars --gender female
|
|
69
69
|
|
|
70
70
|
# Show your custom avatars
|
|
71
|
-
|
|
71
|
+
remixmate gen-digital-human --list-avatars --mine
|
|
72
72
|
|
|
73
73
|
# Filter by name
|
|
74
|
-
|
|
74
|
+
remixmate gen-digital-human --list-avatars --name "alice"
|
|
75
75
|
```
|
|
76
76
|
|
|
77
77
|
> Custom avatars require `--mine`. When generating a video the handler auto-falls back from the public list to `mine: true` if needed.
|
|
@@ -81,7 +81,7 @@ ab-skill gen-digital-human --list-avatars --name "alice"
|
|
|
81
81
|
#### TTS mode
|
|
82
82
|
|
|
83
83
|
```bash
|
|
84
|
-
|
|
84
|
+
remixmate gen-digital-human \
|
|
85
85
|
--avatar-id 7 \
|
|
86
86
|
--text "Hi everyone, welcome to the live stream — today I'll introduce a new product." \
|
|
87
87
|
--voice-id "male-qn-qingse"
|
|
@@ -90,7 +90,7 @@ ab-skill gen-digital-human \
|
|
|
90
90
|
#### TTS + custom voice + aspect ratio
|
|
91
91
|
|
|
92
92
|
```bash
|
|
93
|
-
|
|
93
|
+
remixmate gen-digital-human \
|
|
94
94
|
--avatar-id 7 \
|
|
95
95
|
--text "Hi class, here's our brand-new course." \
|
|
96
96
|
--voice-id "female-shaonv" \
|
|
@@ -100,7 +100,7 @@ ab-skill gen-digital-human \
|
|
|
100
100
|
#### Audio-driven mode
|
|
101
101
|
|
|
102
102
|
```bash
|
|
103
|
-
|
|
103
|
+
remixmate gen-digital-human \
|
|
104
104
|
--avatar-id 39 \
|
|
105
105
|
--source hifly \
|
|
106
106
|
--audio-url "https://example.com/voice.mp3" \
|
|
@@ -110,7 +110,7 @@ ab-skill gen-digital-human \
|
|
|
110
110
|
### 3. Check job status
|
|
111
111
|
|
|
112
112
|
```bash
|
|
113
|
-
|
|
113
|
+
remixmate gen-digital-human --check-status --generation-id 123
|
|
114
114
|
```
|
|
115
115
|
|
|
116
116
|
## Common CLI flags
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"name": "gen-digital-human",
|
|
3
3
|
"toolName": "gen_digital_human",
|
|
4
4
|
"tier": "atomic",
|
|
5
|
+
"category": "asset",
|
|
5
6
|
"title": "Digital-Human Talking-Head",
|
|
6
7
|
"description": "Digital-human video: list available avatars; produce a talking-head video from text via TTS, or drive an avatar from an existing audio URL.",
|
|
7
8
|
"envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "AGENT_NAME"],
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"skillName": "gen-digital-human",
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "336",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "V8",
|
|
6
6
|
"skillDescription": "数字人口播视频技能,支持查询形象、TTS 口播、音频驱动口播和查询生成状态(调用 ab-api 数字人接口,即梦 / 飞影)。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- 数字人、数字人视频、数字人口播、生成数字人视频\n- 用户提供已有音频 URL(MP3 等)、用外链音频驱动数字人口型\n- AI 主播、虚拟主播、虚拟人物视频、口播视频\n- 让数字人说话、让虚拟人说一段话、让 AI 人物播报\n- 查看/列出数字人形象、有哪些数字人可以用\n- 使用即梦/飞影数字人\n\n即使用户没有明确说「使用 AI」,只要他们想要让一个虚拟人物朗读/播报一段文字并生成视频,也要使用本 skill。"
|
|
7
7
|
}
|
|
@@ -51,7 +51,7 @@ No skill-local env file — the executing process inherits the system environmen
|
|
|
51
51
|
|
|
52
52
|
## Operations
|
|
53
53
|
|
|
54
|
-
> This skill was migrated from a Python script to an
|
|
54
|
+
> 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_image`, same params as in `skill.json`); local repro goes through `remixmate gen-image ...`.
|
|
55
55
|
|
|
56
56
|
1. **Prompt**: be specific about subject, style, lighting, composition. Either English or Chinese works.
|
|
57
57
|
2. By default only the URL is printed (good for showing to the user); the legacy local-download flag has been dropped — image URLs are persisted in the cloud.
|
|
@@ -59,13 +59,13 @@ No skill-local env file — the executing process inherits the system environmen
|
|
|
59
59
|
### Text-to-image
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
|
|
62
|
+
remixmate gen-image \
|
|
63
63
|
--prompt "<image description>" \
|
|
64
64
|
--size "9:16"
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
```bash
|
|
68
|
-
|
|
68
|
+
remixmate gen-image \
|
|
69
69
|
--prompt "<image description>" \
|
|
70
70
|
--model gemini-3-pro-image \
|
|
71
71
|
--size "16:9" \
|
|
@@ -81,14 +81,14 @@ Reference images accept local file paths, HTTPS URLs, or data URIs. Pass `--refe
|
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
83
|
# URL reference
|
|
84
|
-
|
|
84
|
+
remixmate gen-image \
|
|
85
85
|
--prompt "Convert this photo to an oil-painting style" \
|
|
86
86
|
--reference "https://example.com/photo.jpg"
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
```bash
|
|
90
90
|
# Local-file reference + reference strength
|
|
91
|
-
|
|
91
|
+
remixmate gen-image \
|
|
92
92
|
--prompt "Match the style of this reference" \
|
|
93
93
|
--reference ./ref.png \
|
|
94
94
|
--image-strength 0.6
|
|
@@ -96,7 +96,7 @@ ab-skill gen-image \
|
|
|
96
96
|
|
|
97
97
|
```bash
|
|
98
98
|
# Multiple references
|
|
99
|
-
|
|
99
|
+
remixmate gen-image \
|
|
100
100
|
--prompt "Blend these styles" \
|
|
101
101
|
--reference ./a.png \
|
|
102
102
|
--reference ./b.png
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"name": "gen-image",
|
|
3
3
|
"toolName": "gen_image",
|
|
4
4
|
"tier": "atomic",
|
|
5
|
+
"category": "asset",
|
|
5
6
|
"title": "AI Image Generation",
|
|
6
7
|
"description": "AI image generation: produce an image from a text prompt. Supports Seedream and Gemini models, plus image-to-image with reference images.",
|
|
7
8
|
"envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "AGENT_NAME", "MM_IMAGE_MODEL"],
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"skillName": "gen-image",
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "337",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "V9",
|
|
6
6
|
"skillDescription": "AI 生图技能,根据文字描述生成图片,也支持参考图进行图生图(调用 ab-api /model/genImg,支持 Seedream 与 Gemini)。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- AI 生图、AI 画图、文生图、文字生成图片、生成图像、帮我画、生成一张图\n- 图生图、以图生图、参考图、风格迁移、图片变体\n- 使用 doubao / 豆包 / seedream、Gemini 等生成图片\n- 用户提供图片提示词并希望生成图片\n\n即使用户没有明确说「使用 AI」,只要他们想要根据描述生成图片,也要使用本 skill。"
|
|
7
7
|
}
|
|
@@ -322,9 +322,9 @@ def generate_image_prompt(
|
|
|
322
322
|
def _load_template_config(template_id: str) -> dict | None:
|
|
323
323
|
"""Load template definition for the given template ID.
|
|
324
324
|
|
|
325
|
-
|
|
326
|
-
1. 通过 registry_loader 从
|
|
327
|
-
|
|
325
|
+
解析顺序:
|
|
326
|
+
1. 通过 registry_loader 从 ab-api(单一数据源,URL 取
|
|
327
|
+
VIDEO_TEMPLATE_REGISTRY_URL 或按 MM_API_BASE_URL 推导)加载,按 templateId 匹配。
|
|
328
328
|
2. 兜底:旧路径 template-registry/video_dsl/templates/<id>/template.json
|
|
329
329
|
(仅在仓库还残留旧目录时使用)。
|
|
330
330
|
返回完整 template dict(含 supportedAspectRatios / assetRequirements / slotMapping 等),
|
|
@@ -384,6 +384,29 @@ def _template_primary_visual_type(template_config: dict | None) -> str:
|
|
|
384
384
|
return "none"
|
|
385
385
|
|
|
386
386
|
|
|
387
|
+
def _template_needs_narration(template_config: dict | None) -> bool:
|
|
388
|
+
"""模板是否需要旁白(TTS)。
|
|
389
|
+
|
|
390
|
+
默认 True —— 保持历史行为:每个场景挂一个 gen-voice 素材 + 写入
|
|
391
|
+
``audio.narration`` 骨架,由 agent 后续填真实文案。
|
|
392
|
+
|
|
393
|
+
模板可通过 ``capabilities.needsNarration=false`` 声明"纯视觉 / 无旁白"
|
|
394
|
+
(如单图 Ken Burns、BGM-only 展示)。此时 gen_script:
|
|
395
|
+
- 不生成 gen-voice 素材;
|
|
396
|
+
- 场景不写 ``audio.narration``。
|
|
397
|
+
于是骨架的 narrationSceneCount=0,ab-agent 的 prepare_video_assets 预校验
|
|
398
|
+
会直接放行,不再强制用户为每个场景填旁白(与 spotlight-card 等无配音模板
|
|
399
|
+
走的是同一条 pass-through 路径)。
|
|
400
|
+
|
|
401
|
+
兼容历史脏数据:部分模板的 ``capabilities`` 是空列表 ``[]``(而非 dict),
|
|
402
|
+
统一按"未声明"处理 → 返回 True。仅当显式为 JSON ``false`` 时才关闭旁白。
|
|
403
|
+
"""
|
|
404
|
+
caps = (template_config or {}).get("capabilities")
|
|
405
|
+
if not isinstance(caps, dict):
|
|
406
|
+
return True
|
|
407
|
+
return caps.get("needsNarration", True) is not False
|
|
408
|
+
|
|
409
|
+
|
|
387
410
|
def _template_needs_image(template_config: dict | None) -> bool:
|
|
388
411
|
"""Check if a template requires image assets.
|
|
389
412
|
|
|
@@ -786,6 +809,9 @@ def build_dsl(
|
|
|
786
809
|
)
|
|
787
810
|
primary_visual_type = _template_primary_visual_type(template_config)
|
|
788
811
|
has_visual = primary_visual_type in ("image", "video")
|
|
812
|
+
# 旁白是模板能力(capabilities.needsNarration)。声明为 false 的模板(纯视觉 /
|
|
813
|
+
# BGM-only,如单图 Ken Burns)不分配 gen-voice 素材、场景不写 audio.narration。
|
|
814
|
+
needs_narration = _template_needs_narration(template_config)
|
|
789
815
|
|
|
790
816
|
# ── Resolve template-driven output language + voice ────────────────────
|
|
791
817
|
# outputLanguage is owned by the template (template.json). Missing/invalid
|
|
@@ -815,8 +841,11 @@ def build_dsl(
|
|
|
815
841
|
visual_asset_id = f"video-{scene_id}"
|
|
816
842
|
else:
|
|
817
843
|
visual_asset_id = f"img-{scene_id}"
|
|
818
|
-
narration_asset_id = f"narration-{scene_id}"
|
|
819
|
-
narration_text =
|
|
844
|
+
narration_asset_id = f"narration-{scene_id}" if needs_narration else None
|
|
845
|
+
narration_text = (
|
|
846
|
+
estimate_narration_text(plan["label"], plan["purpose"], plan["duration"], topic, language=output_language)
|
|
847
|
+
if needs_narration else ""
|
|
848
|
+
)
|
|
820
849
|
|
|
821
850
|
# 根据模板 assetRequirements 生成对应类型的视觉素材
|
|
822
851
|
if primary_visual_type == "image":
|
|
@@ -881,15 +910,17 @@ def build_dsl(
|
|
|
881
910
|
# narration text 不再在 audio asset 的 payload 里冗余存放——
|
|
882
911
|
# 唯一来源是下游 scenes[].audio.narration.text,render_video 在
|
|
883
912
|
# 调用 TTS skill 前会按 assetRef 回查 scene 文本注入。
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
"
|
|
891
|
-
|
|
892
|
-
|
|
913
|
+
# 模板声明 needsNarration=false 时,完全不生成 gen-voice 素材。
|
|
914
|
+
if needs_narration:
|
|
915
|
+
assets.append({
|
|
916
|
+
"assetId": narration_asset_id,
|
|
917
|
+
"type": "audio",
|
|
918
|
+
"source": "gen-voice",
|
|
919
|
+
"status": "planned",
|
|
920
|
+
"payload": {
|
|
921
|
+
"voiceId": resolved_voice_id,
|
|
922
|
+
},
|
|
923
|
+
})
|
|
893
924
|
|
|
894
925
|
if has_visual:
|
|
895
926
|
layout = "text-overlay" if plan["purpose"] in ("opening", "cta") else "full-visual"
|
|
@@ -916,33 +947,35 @@ def build_dsl(
|
|
|
916
947
|
if effective_subheadline:
|
|
917
948
|
text_layers.append({"role": "subheadline", "content": effective_subheadline, "animation": "fade-in"})
|
|
918
949
|
|
|
919
|
-
|
|
950
|
+
scene = {
|
|
920
951
|
"id": scene_id,
|
|
921
952
|
"purpose": plan["purpose"],
|
|
922
953
|
"duration": plan["duration"],
|
|
923
954
|
"layout": layout,
|
|
924
955
|
"visuals": {"background": {"assetRef": visual_asset_id}},
|
|
925
|
-
"
|
|
956
|
+
"textLayers": text_layers,
|
|
957
|
+
"animationHints": {
|
|
958
|
+
"entrance": "fade",
|
|
959
|
+
"motion": "kenburns-in" if idx % 2 == 0 else "kenburns-out",
|
|
960
|
+
},
|
|
961
|
+
}
|
|
962
|
+
if needs_narration:
|
|
963
|
+
scene["audio"] = {
|
|
926
964
|
"narration": {
|
|
927
965
|
"text": narration_text,
|
|
928
966
|
"assetRef": narration_asset_id,
|
|
929
967
|
# 骨架标记:scenes[].audio.narration.text 同样需要被真实旁白替换
|
|
930
968
|
"needsFill": True,
|
|
931
969
|
},
|
|
932
|
-
}
|
|
933
|
-
|
|
934
|
-
"animationHints": {
|
|
935
|
-
"entrance": "fade",
|
|
936
|
-
"motion": "kenburns-in" if idx % 2 == 0 else "kenburns-out",
|
|
937
|
-
},
|
|
938
|
-
})
|
|
970
|
+
}
|
|
971
|
+
scenes.append(scene)
|
|
939
972
|
else:
|
|
940
973
|
# The "no-visual" branch labels each scene with a layout hint.
|
|
941
974
|
# Historical fallback was hardcoded "html-slide" — when no template
|
|
942
975
|
# was specified, every audio-only scene defaulted to html-slide
|
|
943
976
|
# styling. We replace the hardcoded fallback chain with:
|
|
944
977
|
# 1. template.capabilities.defaultLayout ⇐ the template tells
|
|
945
|
-
#
|
|
978
|
+
# remixmate what layout name it wants on its no-visual scenes
|
|
946
979
|
# 2. template_id ⇐ legacy: pass id as
|
|
947
980
|
# layout name (existing behavior when no capability declared)
|
|
948
981
|
# 3. "html-slide" ⇐ absolute fallback
|
|
@@ -966,22 +999,24 @@ def build_dsl(
|
|
|
966
999
|
|
|
967
1000
|
custom_payload = _build_custom_payload(plan["purpose"], topic, plan["label"], idx, len(scene_plans), language=output_language)
|
|
968
1001
|
|
|
969
|
-
|
|
1002
|
+
scene = {
|
|
970
1003
|
"id": scene_id,
|
|
971
1004
|
"purpose": plan["purpose"],
|
|
972
1005
|
"duration": plan["duration"],
|
|
973
1006
|
"layout": layout,
|
|
974
|
-
"
|
|
1007
|
+
"textLayers": text_layers,
|
|
1008
|
+
"customPayload": custom_payload,
|
|
1009
|
+
}
|
|
1010
|
+
if needs_narration:
|
|
1011
|
+
scene["audio"] = {
|
|
975
1012
|
"narration": {
|
|
976
1013
|
"text": narration_text,
|
|
977
1014
|
"assetRef": narration_asset_id,
|
|
978
1015
|
# 骨架标记:scenes[].audio.narration.text 同样需要被真实旁白替换
|
|
979
1016
|
"needsFill": True,
|
|
980
1017
|
},
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
"customPayload": custom_payload,
|
|
984
|
-
})
|
|
1018
|
+
}
|
|
1019
|
+
scenes.append(scene)
|
|
985
1020
|
|
|
986
1021
|
dsl = {
|
|
987
1022
|
"version": "v1alpha1",
|
|
@@ -1001,7 +1036,7 @@ def build_dsl(
|
|
|
1001
1036
|
"aspectRatio": ratio,
|
|
1002
1037
|
"resolution": resolution,
|
|
1003
1038
|
"fps": 30,
|
|
1004
|
-
"subtitle": {"enabled":
|
|
1039
|
+
"subtitle": {"enabled": needs_narration, "style": "bottom"},
|
|
1005
1040
|
"narration": {"voiceId": resolved_voice_id, "speed": 1.0},
|
|
1006
1041
|
"bgm": {"enabled": True, "volume": 0.12},
|
|
1007
1042
|
},
|
|
@@ -1054,6 +1089,11 @@ Examples:
|
|
|
1054
1089
|
default=None,
|
|
1055
1090
|
help="On-screen subheadline / project name (e.g. 'Pixelle-Video'). Stored at meta.subheadline and pushed into textLayers[role=subheadline]. Independent from CC subtitles (global.subtitle).",
|
|
1056
1091
|
)
|
|
1092
|
+
parser.add_argument(
|
|
1093
|
+
"--skip-asset-generation",
|
|
1094
|
+
action="store_true",
|
|
1095
|
+
help="Skill-creator / template-creator helper: when set, every produced AssetRef is marked as already generated with a stub URL — no gen-image / gen-voice / gen-video calls are needed. Implies --stub-image-url + --stub-video-url with default sentinels (https://placeholder.local/stub.png|.mp4) when those flags are absent, and additionally rewrites every gen-voice asset to source=existing + status=generated + a placeholder audio URL. Useful when a downstream agent only wants the DSL shape (e.g. to feed into try_render with all assets pre-stubbed).",
|
|
1096
|
+
)
|
|
1057
1097
|
parser.add_argument(
|
|
1058
1098
|
"--stub-image-url",
|
|
1059
1099
|
default=None,
|
|
@@ -1157,6 +1197,22 @@ Examples:
|
|
|
1157
1197
|
print(f"⚠️ STUB_VIDEO_URL env var detected ({env_v}); using it as the video stub. Prefer passing --stub-video-url explicitly, or unset the env var.", file=sys.stderr)
|
|
1158
1198
|
stub_video_url = env_v
|
|
1159
1199
|
|
|
1200
|
+
# --skip-asset-generation 是为下游"只想要 DSL shape"的 agent 设计的
|
|
1201
|
+
# 一键开关:等价于 --stub-image-url + --stub-video-url + 把 gen-voice 资产
|
|
1202
|
+
# 也写成 source=existing + status=generated。当用户没显式提供 stub URL 时
|
|
1203
|
+
# 用一组 sentinel 占位(https://placeholder.local/...),模板创作 / 调试场景
|
|
1204
|
+
# 不会真的去 fetch 这些 URL。
|
|
1205
|
+
if args.skip_asset_generation:
|
|
1206
|
+
if not stub_image_url:
|
|
1207
|
+
stub_image_url = "https://placeholder.local/stub.png"
|
|
1208
|
+
if not stub_video_url:
|
|
1209
|
+
stub_video_url = "https://placeholder.local/stub.mp4"
|
|
1210
|
+
print(
|
|
1211
|
+
"ℹ️ --skip-asset-generation: forcing all assets to source=existing/status=generated "
|
|
1212
|
+
f"(image={stub_image_url}, video={stub_video_url}, audio=https://placeholder.local/stub.mp3)",
|
|
1213
|
+
file=sys.stderr,
|
|
1214
|
+
)
|
|
1215
|
+
|
|
1160
1216
|
dsl = build_dsl(
|
|
1161
1217
|
topic=args.topic,
|
|
1162
1218
|
platform=args.platform,
|
|
@@ -1177,6 +1233,24 @@ Examples:
|
|
|
1177
1233
|
caption_lines=args.caption_lines,
|
|
1178
1234
|
)
|
|
1179
1235
|
|
|
1236
|
+
# Post-process for --skip-asset-generation: rewrite all gen-voice / gen-digital-human
|
|
1237
|
+
# assets to be already-generated stubs. Image / video are already covered by the
|
|
1238
|
+
# stub_image_url / stub_video_url params threaded through build_dsl above.
|
|
1239
|
+
if args.skip_asset_generation:
|
|
1240
|
+
_AUDIO_STUB = "https://placeholder.local/stub.mp3"
|
|
1241
|
+
_VIDEO_STUB = stub_video_url # same sentinel for digital-human placeholder
|
|
1242
|
+
for asset in dsl.get("assets", []):
|
|
1243
|
+
src = asset.get("source")
|
|
1244
|
+
if src in ("gen-voice",):
|
|
1245
|
+
asset["source"] = "existing"
|
|
1246
|
+
asset["status"] = "generated"
|
|
1247
|
+
asset["url"] = _AUDIO_STUB
|
|
1248
|
+
# payload 留作 reference(renderer 不会再读它,因为 status=generated)
|
|
1249
|
+
elif src in ("gen-digital-human",):
|
|
1250
|
+
asset["source"] = "existing"
|
|
1251
|
+
asset["status"] = "generated"
|
|
1252
|
+
asset["url"] = _VIDEO_STUB
|
|
1253
|
+
|
|
1180
1254
|
errors = validate_dsl(dsl)
|
|
1181
1255
|
if errors:
|
|
1182
1256
|
print("❌ generated DSL failed validation:", file=sys.stderr)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"name": "gen-script",
|
|
3
3
|
"toolName": "gen_script",
|
|
4
4
|
"tier": "orchestration",
|
|
5
|
+
"category": "authoring",
|
|
5
6
|
"title": "Video Script Generation",
|
|
6
7
|
"description": "Video script generation: turn a topic into a structured Video DSL (JSON) that describes the full video — scene structure, asset requirements, and narrative flow.",
|
|
7
8
|
"envVars": ["DEFAULT_IMAGE_MODEL", "DEFAULT_VIDEO_MODEL", "STUB_IMAGE_URL", "STUB_VIDEO_URL"],
|
|
@@ -34,7 +35,8 @@
|
|
|
34
35
|
"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 for the video."
|
|
35
36
|
},
|
|
36
37
|
"stub_image_url": { "type": "string", "description": "Test-mode image stub URL. Only pass when the user explicitly says things like 'just testing / don't actually generate / use a placeholder image / stub URL / save credits' AND provides a concrete URL. With this set, every image AssetRef in the produced DSL is written as source=existing, status=generated, url=<this URL> — no gen-image call. Do not pass otherwise; if the user expressed the intent without a URL, ask for one — do not invent one." },
|
|
37
|
-
"stub_video_url": { "type": "string", "description": "Test-mode video stub URL. Only pass when the user explicitly says things like 'just testing / don't actually generate the video / placeholder clip / save credits' AND provides a concrete URL. With this set, every video AssetRef in the produced DSL is written as source=existing, status=generated, url=<this URL> — no gen-video call. Do not pass otherwise; if the user expressed the intent without a URL, ask for one — do not invent one." }
|
|
38
|
+
"stub_video_url": { "type": "string", "description": "Test-mode video stub URL. Only pass when the user explicitly says things like 'just testing / don't actually generate the video / placeholder clip / save credits' AND provides a concrete URL. With this set, every video AssetRef in the produced DSL is written as source=existing, status=generated, url=<this URL> — no gen-video call. Do not pass otherwise; if the user expressed the intent without a URL, ask for one — do not invent one." },
|
|
39
|
+
"skip_asset_generation": { "type": "boolean", "description": "All-in-one switch for downstream agents (e.g. template-creator) that only want the DSL shape: every produced AssetRef is marked as already generated with placeholder URLs (image: https://placeholder.local/stub.png, video: stub.mp4, audio: stub.mp3). Implies the equivalent of --stub-image-url + --stub-video-url with sentinel defaults plus the same rewrite for gen-voice / gen-digital-human assets. Useful when the agent only needs to inspect DSL structure or feed it into try_render_local with all assets pre-stubbed." }
|
|
38
40
|
},
|
|
39
41
|
"required": ["topic"]
|
|
40
42
|
}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"skillName": "gen-script",
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "474",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "V10",
|
|
6
6
|
"skillDescription": "视频脚本生成技能,将用户主题转化为结构化 Video DSL(JSON),描述视频的完整结构、素材需求与叙事逻辑。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- 帮我写视频脚本、生成视频脚本、视频策划、写分镜脚本\n- 做一个短视频、帮我规划视频内容、生成视频 DSL\n- 把主题转成视频结构、视频内容规划\n\n即使用户没有明确说「生成 DSL」,只要他们想要把一个主题变成视频内容结构,也要使用本 skill。"
|
|
7
7
|
}
|
|
@@ -19,7 +19,7 @@ triggers:
|
|
|
19
19
|
|
|
20
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** or **Veo**. Generation is async — the handler submits the task and polls `/model/getVideoStatus` until completion.
|
|
21
21
|
|
|
22
|
-
> This skill was migrated from a Python script to an
|
|
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
|
|
|
24
24
|
## Models
|
|
25
25
|
|
|
@@ -72,7 +72,7 @@ No skill-local env file — the executing process inherits the system environmen
|
|
|
72
72
|
### Seedance text-to-video (default model)
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
|
-
|
|
75
|
+
remixmate gen-video \
|
|
76
76
|
--prompt "<video description>" \
|
|
77
77
|
--duration 5 \
|
|
78
78
|
--ratio "16:9"
|
|
@@ -83,7 +83,7 @@ ab-skill gen-video \
|
|
|
83
83
|
Frame images accept local file paths, HTTPS URLs, or data URIs (local files are base64-encoded into a data URI).
|
|
84
84
|
|
|
85
85
|
```bash
|
|
86
|
-
|
|
86
|
+
remixmate gen-video \
|
|
87
87
|
--prompt "<transition description>" \
|
|
88
88
|
--first-frame ./start.png \
|
|
89
89
|
--last-frame ./end.png \
|
|
@@ -94,7 +94,7 @@ ab-skill gen-video \
|
|
|
94
94
|
### Veo 3.1 high-resolution
|
|
95
95
|
|
|
96
96
|
```bash
|
|
97
|
-
|
|
97
|
+
remixmate gen-video \
|
|
98
98
|
--model veo \
|
|
99
99
|
--prompt "<video description>" \
|
|
100
100
|
--duration 8 \
|
|
@@ -105,7 +105,7 @@ ab-skill gen-video \
|
|
|
105
105
|
### Veo 3.1 Fast for rapid iteration
|
|
106
106
|
|
|
107
107
|
```bash
|
|
108
|
-
|
|
108
|
+
remixmate gen-video \
|
|
109
109
|
--model veo-fast \
|
|
110
110
|
--prompt "<video description>" \
|
|
111
111
|
--duration 6
|
|
@@ -116,7 +116,7 @@ ab-skill gen-video \
|
|
|
116
116
|
Pass `--reference` multiple times (Veo only, up to 3).
|
|
117
117
|
|
|
118
118
|
```bash
|
|
119
|
-
|
|
119
|
+
remixmate gen-video \
|
|
120
120
|
--model veo \
|
|
121
121
|
--prompt "<video description>" \
|
|
122
122
|
--reference ./ref1.png \
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"name": "gen-video",
|
|
3
3
|
"toolName": "gen_video",
|
|
4
4
|
"tier": "atomic",
|
|
5
|
+
"category": "asset",
|
|
5
6
|
"title": "AI Video Generation",
|
|
6
7
|
"description": "AI video generation: produce a short video clip from a text prompt. Supports Seedance and Veo models, plus first/last frame and reference images.",
|
|
7
8
|
"envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "AGENT_NAME", "MM_VIDEO_MODEL"],
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
"skillName": "gen-video",
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "339",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "V8",
|
|
6
6
|
"skillDescription": "AI 生视频技能,根据文字描述生成素材视频(调用 ab-api /model/genVideo,支持 Seedance 与 Veo)。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- AI 生视频、文生视频、文字生成视频、生成一段视频、AI 制作视频\n- 使用 doubao / 豆包 / seedance、Veo、Google 等生成视频\n- 用户提供视频提示词并希望生成视频\n- 图生视频、首帧生成视频、参考图生成视频\n\n即使用户没有明确说「使用 AI」,只要他们想要根据描述生成视频,也要使用本 skill。"
|
|
7
7
|
}
|
|
@@ -34,7 +34,7 @@ There is no skill-local env file — the executing process inherits the system e
|
|
|
34
34
|
|
|
35
35
|
## Operations
|
|
36
36
|
|
|
37
|
-
> This skill was migrated from a Python script to an
|
|
37
|
+
> 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_voice`, same params as in `skill.json`); local repro goes through `remixmate gen-voice ...`. The legacy `--download` flag has been removed — audio URLs are persisted in the cloud and play directly.
|
|
38
38
|
|
|
39
39
|
1. **Text**: confirm what to synthesize. Punctuation drives pauses (commas short, periods long).
|
|
40
40
|
2. **Voice**: if the user prefers a specific voice, run `--list-voices` first and pick a matching id.
|
|
@@ -43,13 +43,13 @@ There is no skill-local env file — the executing process inherits the system e
|
|
|
43
43
|
### List available voices
|
|
44
44
|
|
|
45
45
|
```bash
|
|
46
|
-
|
|
46
|
+
remixmate gen-voice --list-voices
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
To inspect the local language-tagged fallback catalog used by the voice resolver (no remote API call), add `--local`:
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
|
-
|
|
52
|
+
remixmate gen-voice --list-voices --local
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
The local catalog prints one voice per line as `<voice-id>\t<lang>\t<display-name>`.
|
|
@@ -57,13 +57,13 @@ The local catalog prints one voice per line as `<voice-id>\t<lang>\t<display-nam
|
|
|
57
57
|
### Default synthesis (URL output)
|
|
58
58
|
|
|
59
59
|
```bash
|
|
60
|
-
|
|
60
|
+
remixmate gen-voice --text "<text-to-synthesize>"
|
|
61
61
|
```
|
|
62
62
|
|
|
63
63
|
### With voice + speed
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
|
-
|
|
66
|
+
remixmate gen-voice \
|
|
67
67
|
--text "<text-to-synthesize>" \
|
|
68
68
|
--voice-id "female-shaonv" \
|
|
69
69
|
--speed 1.2
|
|
@@ -72,7 +72,7 @@ ab-skill gen-voice \
|
|
|
72
72
|
### JSON output (with subtitle timestamps)
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
|
-
|
|
75
|
+
remixmate gen-voice --text "<text-to-synthesize>" --json-output
|
|
76
76
|
```
|
|
77
77
|
|
|
78
78
|
## Common CLI flags
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"name": "gen-voice",
|
|
3
3
|
"toolName": "gen_voice",
|
|
4
4
|
"tier": "atomic",
|
|
5
|
+
"category": "asset",
|
|
5
6
|
"title": "Text-to-Speech (Minimax)",
|
|
6
7
|
"description": "Text-to-speech (TTS): synthesize narration audio from text via the Minimax TTS model. Returns the persisted audio URL — no download needed.",
|
|
7
8
|
"envVars": ["PRIV_TOKEN", "MM_API_BASE_URL", "AGENT_NAME"],
|