@remixmate/cli 0.1.2 → 0.9.2
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 +3 -3
- package/dist/runner.d.ts +1 -1
- package/package.json +1 -1
- package/skills/export-jianying/SKILL.md +9 -3
- package/skills/export-jianying/version.json +1 -1
- package/skills/gen-digital-human/SKILL.md +11 -11
- package/skills/gen-digital-human/version.json +1 -1
- package/skills/gen-image/SKILL.md +6 -6
- package/skills/gen-image/version.json +1 -1
- package/skills/gen-script/scripts/gen_script.py +66 -31
- package/skills/gen-script/version.json +1 -1
- package/skills/gen-video/SKILL.md +6 -6
- package/skills/gen-video/version.json +1 -1
- package/skills/gen-voice/SKILL.md +6 -6
- package/skills/gen-voice/version.json +1 -1
- package/skills/render-video/SKILL.md +20 -1
- package/skills/render-video/scripts/remote_renderer_client.py +9 -7
- package/skills/render-video/scripts/render_video.py +119 -15
- 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/registry_loader.py +117 -96
- package/skills/template-registry/scripts/render_job_client.py +12 -0
- package/skills/template-registry/skill.json +1 -1
- package/skills/template-registry/version.json +1 -1
- package/skills/template-registry/video_dsl/runtime/dsl_validator.py +2 -2
- package/skills/web-capture/skill.json +0 -1
- package/skills/web-capture/version.json +1 -1
|
@@ -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,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,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
|
},
|
|
@@ -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,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,6 @@
|
|
|
2
2
|
"skillName": "gen-voice",
|
|
3
3
|
"repoName": "agent-skill-media-maker",
|
|
4
4
|
"skillId": "338",
|
|
5
|
-
"version": "
|
|
5
|
+
"version": "V7",
|
|
6
6
|
"skillDescription": "语音合成(TTS)技能,将文字转为语音音频(调用 ab-api /tool/minimaxT2aV2,基于 Minimax TTS)。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- AI 配音、语音合成、文字转语音、TTS、文本转音频、生成语音\n- 使用 minimax 语音合成\n- 用户想要将一段文字朗读出来、生成音频\n\n即使用户没有明确说「使用 AI」,只要他们想要将文字转为语音,也要使用本 skill。"
|
|
7
7
|
}
|
|
@@ -73,9 +73,28 @@ python3 <SkillDir>/scripts/render_video.py --job-id <jobId>
|
|
|
73
73
|
When the DB is unavailable, the script accepts a pre-generated RenderPlan file:
|
|
74
74
|
|
|
75
75
|
```bash
|
|
76
|
-
python3 <SkillDir>/scripts/render_video.py --render-plan
|
|
76
|
+
python3 <SkillDir>/scripts/render_video.py --render-plan <path>.render-plan.json
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
+
> ⚠️ **Do NOT blindly point `--render-plan` at a shared `output/render-plan.json`.**
|
|
80
|
+
> Under the default token-present path, `prepare_video_assets` / `render_video`
|
|
81
|
+
> persist the plan to the **database (jobId)** only — they do **not** write
|
|
82
|
+
> `output/render-plan.json`. Any file sitting there is likely a leftover from a
|
|
83
|
+
> previous, unrelated run (the `output/` dir is gitignored scratch), and rendering
|
|
84
|
+
> it silently produces the wrong video.
|
|
85
|
+
>
|
|
86
|
+
> To get a RenderPlan file on disk, generate it explicitly:
|
|
87
|
+
> ```bash
|
|
88
|
+
> python3 <SkillDir>/scripts/render_video.py --dsl video.dsl.json --template-id <id> \
|
|
89
|
+
> --resolve-only --save-render-plan --render-plan-output video.render-plan.json
|
|
90
|
+
> ```
|
|
91
|
+
> Or skip the file entirely and render in one shot:
|
|
92
|
+
> `render_video.py --dsl video.dsl.json --template-id <id>`.
|
|
93
|
+
>
|
|
94
|
+
> On load, the script now prints a `↳ plan: templateId=… composition=… duration=… title=…`
|
|
95
|
+
> summary, and warns if the plan file is older than a `--dsl` you also passed —
|
|
96
|
+
> check that line matches what you intend before the render proceeds.
|
|
97
|
+
|
|
79
98
|
### Render and upload to Alibaba Cloud OSS (default behavior)
|
|
80
99
|
|
|
81
100
|
```bash
|
|
@@ -121,11 +121,12 @@ def start_render(
|
|
|
121
121
|
base_url: Optional[str] = None,
|
|
122
122
|
timeout: float = 120.0,
|
|
123
123
|
conversation_id: Optional[str] = None,
|
|
124
|
+
path: str = "/render",
|
|
124
125
|
) -> str:
|
|
125
|
-
"""POST /render
|
|
126
|
+
"""POST <path>(默认 /render,私有模板动态渲染传 /renderDraft);返回 taskId。"""
|
|
126
127
|
result = _request(
|
|
127
128
|
"POST",
|
|
128
|
-
|
|
129
|
+
path,
|
|
129
130
|
private_token=private_token,
|
|
130
131
|
payload=payload,
|
|
131
132
|
base_url=base_url,
|
|
@@ -135,7 +136,7 @@ def start_render(
|
|
|
135
136
|
data = _check_code(result)
|
|
136
137
|
task_id = data.get("taskId")
|
|
137
138
|
if not task_id:
|
|
138
|
-
raise RemoteRenderError(f"
|
|
139
|
+
raise RemoteRenderError(f"{path} did not return a taskId: {result}")
|
|
139
140
|
return str(task_id)
|
|
140
141
|
|
|
141
142
|
|
|
@@ -150,8 +151,9 @@ def poll_render(
|
|
|
150
151
|
max_consecutive_errors: int = 5,
|
|
151
152
|
on_progress: Optional[Callable[[dict], None]] = None,
|
|
152
153
|
adaptive_interval: bool = False,
|
|
154
|
+
status_path: str = "/renderStatus",
|
|
153
155
|
) -> dict:
|
|
154
|
-
"""POST /renderStatus
|
|
156
|
+
"""POST <status_path>(默认 /renderStatus,私有模板传 /renderDraftStatus)轮询直到完成/失败/超时。
|
|
155
157
|
|
|
156
158
|
成功时返回 data dict(至少包含 fileUrl),否则抛 RemoteRenderError。
|
|
157
159
|
on_progress 回调在每次成功请求后触发,参数为完整 data dict。
|
|
@@ -170,13 +172,13 @@ def poll_render(
|
|
|
170
172
|
if elapsed > timeout:
|
|
171
173
|
raise RemoteRenderError(
|
|
172
174
|
f"remote render polling timed out (waited {elapsed:.0f}s, taskId={task_id}); "
|
|
173
|
-
f"the job may still be running on the backend — query
|
|
175
|
+
f"the job may still be running on the backend — query {status_path} later"
|
|
174
176
|
)
|
|
175
177
|
|
|
176
178
|
try:
|
|
177
179
|
result = _request(
|
|
178
180
|
"POST",
|
|
179
|
-
|
|
181
|
+
status_path,
|
|
180
182
|
private_token=private_token,
|
|
181
183
|
payload={"taskId": task_id},
|
|
182
184
|
base_url=base_url,
|
|
@@ -201,7 +203,7 @@ def poll_render(
|
|
|
201
203
|
body = exc.read().decode("utf-8")
|
|
202
204
|
except Exception:
|
|
203
205
|
pass
|
|
204
|
-
raise RemoteRenderError(f"HTTP {exc.code}
|
|
206
|
+
raise RemoteRenderError(f"HTTP {exc.code} {status_path}: {body[:200]}") from exc
|
|
205
207
|
|
|
206
208
|
consecutive_errors = 0
|
|
207
209
|
|