@remixmate/cli 0.1.0 → 0.1.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 +100 -83
- package/README.zh-CN.md +183 -0
- package/dist/handlers/gen-digital-human.d.ts +12 -0
- package/dist/handlers/gen-digital-human.js +157 -0
- package/dist/handlers/gen-image.js +5 -41
- package/dist/handlers/gen-video.d.ts +18 -0
- package/dist/handlers/gen-video.js +153 -0
- package/dist/handlers/gen-voice.js +2 -12
- package/dist/handlers/index.js +4 -2
- package/dist/handlers/shared.d.ts +26 -0
- package/dist/handlers/shared.js +66 -0
- package/dist/http.d.ts +4 -2
- package/dist/http.js +5 -3
- package/dist/manifest.json +38 -24
- package/dist/registry.d.ts +5 -16
- package/dist/registry.js +11 -17
- package/dist/skill-schema.d.ts +65 -0
- package/dist/skill-schema.js +53 -0
- package/package.json +5 -4
- package/skills/export-jianying/scripts/gen_jianying_draft.py +4 -4
- package/skills/export-jianying/skill.json +1 -0
- package/skills/gen-digital-human/SKILL.md +23 -46
- package/skills/gen-digital-human/skill.json +4 -2
- package/skills/gen-digital-human/version.json +1 -1
- package/skills/gen-image/SKILL.md +2 -2
- package/skills/gen-image/skill.json +3 -1
- package/skills/gen-image/version.json +1 -1
- package/skills/gen-script/SKILL.md +13 -13
- package/skills/gen-script/scripts/gen_script.py +50 -12
- package/skills/gen-script/skill.json +3 -1
- package/skills/gen-video/SKILL.md +22 -33
- package/skills/gen-video/skill.json +4 -2
- package/skills/gen-video/version.json +1 -1
- package/skills/gen-voice/SKILL.md +1 -1
- package/skills/gen-voice/skill.json +1 -0
- package/skills/gen-voice/version.json +1 -1
- package/skills/prepare-video-assets/SKILL.md +2 -2
- package/skills/prepare-video-assets/skill.json +2 -1
- package/skills/render-video/scripts/render_video.py +8 -8
- package/skills/render-video/skill.json +1 -0
- package/skills/{template-bind → template-registry}/README.md +4 -4
- package/skills/{template-bind → template-registry}/SKILL.md +14 -12
- package/skills/template-registry/scripts/list_templates.py +214 -0
- package/skills/{template-bind → template-registry}/scripts/match_template.py +4 -3
- package/skills/{template-bind → template-registry}/scripts/registry_loader.py +1 -1
- package/skills/{template-bind → template-registry}/scripts/template_paths.py +7 -7
- package/skills/{template-bind → template-registry}/skill.json +8 -5
- package/skills/template-registry/version.json +7 -0
- package/skills/{template-bind → template-registry}/video_dsl/README.md +2 -2
- package/skills/{template-bind → template-registry}/video_dsl/runtime/__init__.py +1 -1
- package/skills/video-parser/SKILL.md +47 -160
- package/skills/video-parser/skill.json +4 -4
- package/skills/video-parser/version.json +1 -1
- package/skills/web-capture/SKILL.md +407 -116
- package/skills/web-capture/scripts/_media_screenshot/__init__.py +21 -0
- package/skills/web-capture/scripts/_media_screenshot/bootstrap.py +34 -0
- package/skills/web-capture/scripts/_media_screenshot/browser.py +86 -0
- package/skills/web-capture/scripts/_media_screenshot/cli_args.py +111 -0
- package/skills/web-capture/scripts/_media_screenshot/js/arrow.js +86 -0
- package/skills/web-capture/scripts/_media_screenshot/js/caption.js +27 -0
- package/skills/web-capture/scripts/_media_screenshot/js/clear_overlay.js +5 -0
- package/skills/web-capture/scripts/_media_screenshot/js/cursor_bootstrap.js +26 -0
- package/skills/web-capture/scripts/_media_screenshot/js/cursor_hide.js +6 -0
- package/skills/web-capture/scripts/_media_screenshot/js/cursor_move.js +12 -0
- package/skills/web-capture/scripts/_media_screenshot/js/cursor_ripple.js +25 -0
- package/skills/web-capture/scripts/_media_screenshot/js/element_zoom.js +72 -0
- package/skills/web-capture/scripts/_media_screenshot/js/element_zoom_restore.js +21 -0
- package/skills/web-capture/scripts/_media_screenshot/js/fade_out_overlays.js +10 -0
- package/skills/web-capture/scripts/_media_screenshot/js/focus.js +38 -0
- package/skills/web-capture/scripts/_media_screenshot/js/highlight.js +97 -0
- package/skills/web-capture/scripts/_media_screenshot/js/overlay_bootstrap.js +19 -0
- package/skills/web-capture/scripts/_media_screenshot/js/page_zoom_in.js +54 -0
- package/skills/web-capture/scripts/_media_screenshot/js/page_zoom_out.js +11 -0
- package/skills/web-capture/scripts/_media_screenshot/js/page_zoom_restore.js +13 -0
- package/skills/web-capture/scripts/_media_screenshot/js/redact.js +33 -0
- package/skills/web-capture/scripts/_media_screenshot/js/scroll.js +26 -0
- package/skills/web-capture/scripts/_media_screenshot/js/scroll_through.js +18 -0
- package/skills/web-capture/scripts/_media_screenshot/js/sequence.js +76 -0
- package/skills/web-capture/scripts/_media_screenshot/js/settled_check.js +15 -0
- package/skills/web-capture/scripts/_media_screenshot/js/title_card.js +71 -0
- package/skills/web-capture/scripts/_media_screenshot/js_loader.py +14 -0
- package/skills/web-capture/scripts/_media_screenshot/overlay.py +17 -0
- package/skills/web-capture/scripts/_media_screenshot/recording.py +100 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/__init__.py +39 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/arrow.py +50 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/caption.py +20 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/click.py +35 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/code_lines.py +54 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/focus.py +24 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/highlight.py +54 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/hover.py +28 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/redact.py +32 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/scroll.py +32 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/sequence.py +43 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/title_card.py +20 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/type.py +42 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/wait.py +9 -0
- package/skills/web-capture/scripts/_media_screenshot/scenes/zoom.py +72 -0
- package/skills/web-capture/scripts/_media_screenshot/screenshot.py +166 -0
- package/skills/web-capture/scripts/_media_screenshot/storyboard.py +88 -0
- package/skills/web-capture/scripts/_media_screenshot/template.py +119 -0
- package/skills/web-capture/scripts/_media_screenshot/trim.py +82 -0
- package/skills/web-capture/scripts/record.py +186 -0
- package/skills/web-capture/scripts/screenshot.py +94 -0
- package/skills/web-capture/skill.json +15 -14
- package/skills/web-capture/templates/github-code-tour.json +59 -0
- package/skills/web-capture/templates/github-readme-tour.json +77 -0
- package/skills/web-capture/templates/github-repo-intro.json +74 -0
- package/skills/web-capture/version.json +2 -2
- package/dist/handlers/template-bind.d.ts +0 -15
- package/dist/handlers/template-bind.js +0 -149
- package/skills/gen-digital-human/scripts/gen_digital_human_video.py +0 -574
- package/skills/gen-video/scripts/gen_video.py +0 -591
- package/skills/template-bind/version.json +0 -7
- package/skills/web-capture/scripts/web_capture.py +0 -461
- /package/skills/{template-bind → template-registry}/scripts/check_contracts.py +0 -0
- /package/skills/{template-bind → template-registry}/scripts/render_job_client.py +0 -0
- /package/skills/{template-bind → template-registry}/scripts/sync_registry.py +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/runtime/dsl_validator.py +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/runtime/prompt_enhancer.py +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/runtime/template_binder.py +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/runtime/timeline_compiler.py +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/schema/render-plan-v1alpha1.json +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/schema/template-binding-v1alpha1.json +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/schema/template-definition-v1alpha1.json +0 -0
- /package/skills/{template-bind → template-registry}/video_dsl/schema/video-dsl-v1alpha1.json +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
template-registry CLI — list available video templates.
|
|
4
|
+
|
|
5
|
+
Single source of truth: registry loading, caching and stable/beta status
|
|
6
|
+
gating all live in ``registry_loader.py`` (the same module ``render-video``
|
|
7
|
+
and ``gen-script`` import in-process). This entry point only adds the CLI
|
|
8
|
+
surface — flag parsing, tag/aspect/language filtering, and table/JSON
|
|
9
|
+
rendering — that used to be re-implemented in TypeScript
|
|
10
|
+
(``src/handlers/template-bind.ts``). Deleting that handler removes the
|
|
11
|
+
TS↔Python duplication; this is now the only place the list verb is realized.
|
|
12
|
+
|
|
13
|
+
The DSL → TemplateBinding logic stays in ``match_template.py`` and is invoked
|
|
14
|
+
in-process by ``render-video``; it is intentionally NOT exposed as a CLI verb.
|
|
15
|
+
|
|
16
|
+
Flags:
|
|
17
|
+
--list-templates (accepted; listing is the only verb)
|
|
18
|
+
--list-examples list *.dsl.json / *.binding.json reference
|
|
19
|
+
examples grouped by templateId (consumed
|
|
20
|
+
by downstream agents that want to read a
|
|
21
|
+
template's reference shape before producing
|
|
22
|
+
new DSL)
|
|
23
|
+
--filter-tag <substr> keep templates whose styleTags match
|
|
24
|
+
--filter-aspect <ratio> keep templates supporting this aspect ratio
|
|
25
|
+
--filter-language <zh|en|...> keep templates tagged with this content lang
|
|
26
|
+
(templates with no contentLanguage are kept)
|
|
27
|
+
--include-beta also show beta templates (else stable-only)
|
|
28
|
+
--json-output emit {"templates": [...]} or {"examples": [...]}
|
|
29
|
+
instead of a table
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import argparse
|
|
35
|
+
import json
|
|
36
|
+
import os
|
|
37
|
+
import sys
|
|
38
|
+
from pathlib import Path
|
|
39
|
+
|
|
40
|
+
# When run as `python3 <skillDir>/scripts/list_templates.py`, this script's own
|
|
41
|
+
# directory is sys.path[0], so the sibling shared modules import directly.
|
|
42
|
+
from registry_loader import list_templates as load_visible_templates # noqa: E402
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _matches(tpl: dict, tag: str | None, aspect: str | None, language: str | None) -> bool:
|
|
46
|
+
if tag:
|
|
47
|
+
needle = tag.lower()
|
|
48
|
+
tags = [str(t).lower() for t in (tpl.get("styleTags") or [])]
|
|
49
|
+
if not any(needle in t or t in needle for t in tags):
|
|
50
|
+
return False
|
|
51
|
+
if aspect:
|
|
52
|
+
want = aspect.lower()
|
|
53
|
+
ratios = [str(r).lower() for r in (tpl.get("supportedAspectRatios") or [])]
|
|
54
|
+
if want not in ratios:
|
|
55
|
+
return False
|
|
56
|
+
if language:
|
|
57
|
+
# Unknown language (absent/empty) is never excluded by a language filter.
|
|
58
|
+
langs = [str(l).lower() for l in (tpl.get("contentLanguage") or [])]
|
|
59
|
+
if langs and language.lower() not in langs:
|
|
60
|
+
return False
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _status_of(tpl: dict) -> str:
|
|
65
|
+
raw = tpl.get("status")
|
|
66
|
+
if isinstance(raw, str) and raw.strip():
|
|
67
|
+
return raw.strip().lower()
|
|
68
|
+
return "stable"
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ----- Examples discovery (--list-examples) ---------------------------------
|
|
72
|
+
#
|
|
73
|
+
# Examples live under <SkillDir>/video_dsl/schema/examples/ as `*.dsl.json` and
|
|
74
|
+
# `*.binding.json` files. Naming convention (per gen-script SKILL.md) is
|
|
75
|
+
# `<templateId>.dsl.json` / `<templateId>.binding.json`, occasionally with
|
|
76
|
+
# variant suffixes (`<templateId>.<variant>.dsl.json`).
|
|
77
|
+
#
|
|
78
|
+
# We do not parse the JSON content here (downstream agents read the raw files
|
|
79
|
+
# they care about); we just enumerate paths so the agent doesn't have to guess
|
|
80
|
+
# the directory layout. When the directory does not exist (e.g. inside a slim
|
|
81
|
+
# package distribution), we return an empty list — non-fatal.
|
|
82
|
+
|
|
83
|
+
# Resolve the examples directory relative to this script.
|
|
84
|
+
# <skill>/scripts/list_templates.py → <skill>/video_dsl/schema/examples/
|
|
85
|
+
_EXAMPLES_DIR = Path(__file__).resolve().parent.parent / "video_dsl" / "schema" / "examples"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _collect_examples() -> list[dict]:
|
|
89
|
+
if not _EXAMPLES_DIR.is_dir():
|
|
90
|
+
return []
|
|
91
|
+
by_template: dict[str, dict] = {}
|
|
92
|
+
for entry in sorted(_EXAMPLES_DIR.iterdir()):
|
|
93
|
+
if not entry.is_file():
|
|
94
|
+
continue
|
|
95
|
+
name = entry.name
|
|
96
|
+
# Recognise *.dsl.json / *.binding.json
|
|
97
|
+
if name.endswith(".dsl.json"):
|
|
98
|
+
kind = "dsl"
|
|
99
|
+
base = name[: -len(".dsl.json")]
|
|
100
|
+
elif name.endswith(".binding.json"):
|
|
101
|
+
kind = "binding"
|
|
102
|
+
base = name[: -len(".binding.json")]
|
|
103
|
+
else:
|
|
104
|
+
continue
|
|
105
|
+
# Variant: 'foo.bar.dsl.json' → templateId='foo', variant='bar'
|
|
106
|
+
if "." in base:
|
|
107
|
+
template_id, variant = base.split(".", 1)
|
|
108
|
+
else:
|
|
109
|
+
template_id, variant = base, None
|
|
110
|
+
bucket = by_template.setdefault(template_id, {"templateId": template_id, "files": []})
|
|
111
|
+
bucket["files"].append({
|
|
112
|
+
"kind": kind,
|
|
113
|
+
"variant": variant,
|
|
114
|
+
"path": str(entry.relative_to(_EXAMPLES_DIR.parent.parent.parent)), # relative to skill dir
|
|
115
|
+
"absolutePath": str(entry),
|
|
116
|
+
"sizeBytes": entry.stat().st_size,
|
|
117
|
+
})
|
|
118
|
+
return list(by_template.values())
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def main() -> None:
|
|
122
|
+
ap = argparse.ArgumentParser(
|
|
123
|
+
description="List available video templates from the registry.",
|
|
124
|
+
)
|
|
125
|
+
ap.add_argument("--list-templates", action="store_true",
|
|
126
|
+
help="List every available template (the only CLI verb).")
|
|
127
|
+
ap.add_argument("--list-examples", action="store_true",
|
|
128
|
+
help="List reference examples (*.dsl.json / *.binding.json) grouped by templateId.")
|
|
129
|
+
ap.add_argument("--filter-tag", help="Keep templates whose styleTags match this substring.")
|
|
130
|
+
ap.add_argument("--filter-aspect", help="Keep templates supporting this aspect ratio (e.g. 9:16).")
|
|
131
|
+
ap.add_argument("--filter-language", help="Keep templates tagged with this content language (zh|en|...).")
|
|
132
|
+
ap.add_argument("--include-beta", action="store_true", help="Also show beta templates (default: stable only).")
|
|
133
|
+
ap.add_argument("--json-output", action="store_true", help='Emit JSON ({"templates":[...]} or {"examples":[...]}) instead of a table.')
|
|
134
|
+
args = ap.parse_args()
|
|
135
|
+
|
|
136
|
+
# --include-beta flips registry_loader's documented status gate via env, so
|
|
137
|
+
# the CLI and in-process callers share one gating implementation.
|
|
138
|
+
if args.include_beta:
|
|
139
|
+
os.environ["ENABLE_BETA_TEMPLATES"] = "1"
|
|
140
|
+
|
|
141
|
+
# ----- examples mode -----------------------------------------------------
|
|
142
|
+
if args.list_examples:
|
|
143
|
+
examples = _collect_examples()
|
|
144
|
+
if args.json_output:
|
|
145
|
+
print(json.dumps({"examples": examples}, ensure_ascii=False))
|
|
146
|
+
return
|
|
147
|
+
if not examples:
|
|
148
|
+
print(
|
|
149
|
+
f"⚠️ No examples found under {_EXAMPLES_DIR}.\n"
|
|
150
|
+
" This package may have shipped without reference examples; "
|
|
151
|
+
"check the cli source repo or upgrade @remixmate/cli.",
|
|
152
|
+
)
|
|
153
|
+
return
|
|
154
|
+
print(f"\n{'Template ID':<28} Files")
|
|
155
|
+
print(f"{'-' * 28} {'-' * 60}")
|
|
156
|
+
for bucket in examples:
|
|
157
|
+
tid = str(bucket["templateId"])[:28].ljust(28)
|
|
158
|
+
files = bucket["files"]
|
|
159
|
+
for i, f in enumerate(files):
|
|
160
|
+
marker = tid if i == 0 else " " * 28
|
|
161
|
+
kind = f["kind"]
|
|
162
|
+
variant = f"@{f['variant']}" if f.get("variant") else ""
|
|
163
|
+
print(f"{marker} [{kind}{variant}] {f['path']} ({f['sizeBytes']}B)")
|
|
164
|
+
print(f"\n{sum(len(b['files']) for b in examples)} example file(s) across {len(examples)} template(s)")
|
|
165
|
+
return
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
templates = load_visible_templates()
|
|
169
|
+
except RuntimeError as exc:
|
|
170
|
+
print(f"❌ {exc}", file=sys.stderr)
|
|
171
|
+
sys.exit(1)
|
|
172
|
+
|
|
173
|
+
visible = [
|
|
174
|
+
t for t in templates
|
|
175
|
+
if _matches(t, args.filter_tag, args.filter_aspect, args.filter_language)
|
|
176
|
+
]
|
|
177
|
+
|
|
178
|
+
if args.json_output:
|
|
179
|
+
print(json.dumps({"templates": visible}, ensure_ascii=False))
|
|
180
|
+
return
|
|
181
|
+
|
|
182
|
+
if not visible:
|
|
183
|
+
print(
|
|
184
|
+
"⚠️ No templates match the current filters "
|
|
185
|
+
"(check --include-beta or relax --filter-*).",
|
|
186
|
+
)
|
|
187
|
+
return
|
|
188
|
+
|
|
189
|
+
header = (
|
|
190
|
+
f"\n{'Template ID':<22} {'Name':<18} {'Aspect':<12} "
|
|
191
|
+
f"{'Lang':<8} {'Status':<8} Tags / LLM hint"
|
|
192
|
+
)
|
|
193
|
+
print(header)
|
|
194
|
+
print(
|
|
195
|
+
f"{'-' * 22} {'-' * 18} {'-' * 12} {'-' * 8} {'-' * 8} {'-' * 60}"
|
|
196
|
+
)
|
|
197
|
+
for tpl in visible:
|
|
198
|
+
tid = str(tpl.get("templateId", ""))[:22].ljust(22)
|
|
199
|
+
name = str(tpl.get("name", ""))[:18].ljust(18)
|
|
200
|
+
ratios = ",".join(tpl.get("supportedAspectRatios") or [])[:12].ljust(12)
|
|
201
|
+
lang = (",".join(tpl.get("contentLanguage") or []) or "-")[:8].ljust(8)
|
|
202
|
+
status = _status_of(tpl).ljust(8)
|
|
203
|
+
tags = ", ".join((tpl.get("styleTags") or [])[:5])
|
|
204
|
+
print(f"{tid} {name} {ratios} {lang} {status} {tags}")
|
|
205
|
+
hint = tpl.get("llmHint")
|
|
206
|
+
if hint:
|
|
207
|
+
hint = hint if len(hint) <= 200 else hint[:197] + "..."
|
|
208
|
+
print(f"{' ' * 22} ↳ {hint}")
|
|
209
|
+
|
|
210
|
+
print(f"\n{len(visible)} template(s) shown")
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
if __name__ == "__main__":
|
|
214
|
+
main()
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"""
|
|
2
|
-
template-
|
|
2
|
+
template-registry 库模块 — DSL → TemplateBinding 的纯函数实现。
|
|
3
3
|
|
|
4
4
|
仅作为 Python library 被 render-video 的 render_video.py / gen-script 的
|
|
5
5
|
gen_script.py 通过 `sys.path.insert` 后 `import match_template` 引入;
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
对外不暴露 binding CLI。template-registry skill 的 `--list-templates` 入口由
|
|
7
|
+
sibling 的 `list_templates.py` 实现(它复用 registry_loader 的统一加载 +
|
|
8
|
+
状态门控),两者共享同一份 registry 读取逻辑,无 TS 侧重复实现。
|
|
8
9
|
|
|
9
10
|
提供的公共接口:
|
|
10
11
|
load_registry() → list[dict] 模板列表
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
模板 registry 加载器 - 统一抽象本地文件 / HTTP API 两种数据源。
|
|
4
4
|
|
|
5
5
|
为什么独立成一个模块:
|
|
6
|
-
template-
|
|
6
|
+
template-registry、render-video 等多个 skill 都要读 registry,集中在一处便于:
|
|
7
7
|
- 缓存策略一致(HTTP 拉取 5 分钟 TTL + ETag 复用)
|
|
8
8
|
- 解析顺序一致(环境变量 → 本地文件 → monorepo 回退)
|
|
9
9
|
- 错误降级一致(HTTP 故障时复用上一次缓存)
|
|
@@ -6,9 +6,9 @@ Before this file landed, every caller that needed to reach into the
|
|
|
6
6
|
monorepo's ``template-library/`` from inside ``apps/ab-skill/`` had to count
|
|
7
7
|
``..`` segments by hand. The depth differs per call site:
|
|
8
8
|
|
|
9
|
-
skills/template-
|
|
10
|
-
skills/template-
|
|
11
|
-
skills/template-
|
|
9
|
+
skills/template-registry/scripts/registry_loader.py → 5 × ".."
|
|
10
|
+
skills/template-registry/scripts/check_contracts.py → 3 × ".."
|
|
11
|
+
skills/template-registry/video_dsl/runtime/template_binder → 6 × ".."
|
|
12
12
|
skills/gen-script/scripts/gen_script.py → 5 × ".."
|
|
13
13
|
skills/render-video/scripts/render_video.py → 4 × ".."
|
|
14
14
|
|
|
@@ -17,9 +17,9 @@ move silently breaks one site without touching the others. This module
|
|
|
17
17
|
computes the monorepo root **once** from its own location and exposes
|
|
18
18
|
helpers so callers no longer count.
|
|
19
19
|
|
|
20
|
-
All sibling skills
|
|
21
|
-
``
|
|
22
|
-
|
|
20
|
+
All sibling skills (including the ``list_templates.py`` CLI entry, via
|
|
21
|
+
``registry_loader``) go through these helpers, so the monorepo-root
|
|
22
|
+
computation lives in exactly one place.
|
|
23
23
|
"""
|
|
24
24
|
from __future__ import annotations
|
|
25
25
|
|
|
@@ -29,7 +29,7 @@ from typing import Optional
|
|
|
29
29
|
__all__ = ["monorepo_root", "monorepo_registry_path", "monorepo_template_src_dir"]
|
|
30
30
|
|
|
31
31
|
# This file lives at:
|
|
32
|
-
# <repo>/apps/ab-skill/skills/template-
|
|
32
|
+
# <repo>/apps/ab-skill/skills/template-registry/scripts/template_paths.py
|
|
33
33
|
# So the monorepo root is 5 levels up.
|
|
34
34
|
_HERE = os.path.dirname(os.path.abspath(__file__))
|
|
35
35
|
_REPO_ROOT = os.path.normpath(os.path.join(_HERE, "..", "..", "..", "..", ".."))
|
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "template-
|
|
3
|
-
"toolName": "
|
|
2
|
+
"name": "template-registry",
|
|
3
|
+
"toolName": "template_registry",
|
|
4
4
|
"tier": "orchestration",
|
|
5
|
-
"
|
|
5
|
+
"category": "authoring",
|
|
6
|
+
"title": "Video Template Registry",
|
|
6
7
|
"description": "List all available video templates (templateId / name / aspect ratio / style tags). Template-to-DSL binding is no longer exposed as a separate step — once prepare_video_assets receives a template_id it runs the full DSL→RenderPlan pipeline internally.",
|
|
7
8
|
"envVars": ["PRIV_TOKEN", "VIDEO_TEMPLATE_REGISTRY", "VIDEO_TEMPLATE_REGISTRY_URL", "VIDEO_TEMPLATE_REGISTRY_HTTP_METHOD"],
|
|
8
|
-
"entry": { "type": "
|
|
9
|
+
"entry": { "type": "python", "scriptPath": "scripts/list_templates.py" },
|
|
9
10
|
"parameters": {
|
|
10
11
|
"type": "object",
|
|
11
12
|
"properties": {
|
|
12
13
|
"list_templates": { "type": "boolean", "description": "List available templates (default behavior; also implied when other flags are passed)." },
|
|
14
|
+
"list_examples": { "type": "boolean", "description": "List the *.dsl.json / *.binding.json reference examples shipped under template-registry/video_dsl/schema/examples/, grouped by templateId. Useful for downstream agents (e.g. a creation agent) that want to read a template's reference shape before producing new DSL." },
|
|
13
15
|
"filter_tag": { "type": "string", "description": "Show only templates whose styleTags contain (or are contained in) this string. Case-insensitive. E.g. 'tech' / '科普' / 'walkthrough'." },
|
|
14
16
|
"filter_aspect": { "type": "string", "description": "Show only templates that declare this aspect ratio. E.g. '9:16' / '16:9' / '1:1'." },
|
|
15
17
|
"filter_language": { "type": "string", "description": "Show only templates whose contentLanguage includes this code ('zh' or 'en'). Templates with no declared language are always shown (treated as language-agnostic)." },
|
|
16
|
-
"include_beta": { "type": "boolean", "description": "Also list templates with status='beta'. Default off (only 'stable' shows). The ENABLE_BETA_TEMPLATES env var has the same effect process-wide." }
|
|
18
|
+
"include_beta": { "type": "boolean", "description": "Also list templates with status='beta'. Default off (only 'stable' shows). The ENABLE_BETA_TEMPLATES env var has the same effect process-wide." },
|
|
19
|
+
"json_output": { "type": "boolean", "description": "Emit a JSON result ({ templates: [...] } or { examples: [...] }) instead of the human-readable table." }
|
|
17
20
|
},
|
|
18
21
|
"required": []
|
|
19
22
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"skillName": "template-registry",
|
|
3
|
+
"repoName": "agent-skill-media-maker",
|
|
4
|
+
"skillId": "475",
|
|
5
|
+
"version": "V12",
|
|
6
|
+
"skillDescription": "视频模板仓库(列表查询)。存储所有视频模板定义,对外只暴露「列出可用模板」一个能力;DSL→TemplateBinding 的绑定逻辑已内嵌进 prepare-video-assets,不再作为独立步骤暴露。同时是跨 skill 共享 Python 库(registry_loader / match_template / template_paths / video_dsl 等)的存放位置。\n\n当用户提到以下任何需求时,立即使用本 skill:\n- 查看可用模板、列出所有模板"
|
|
7
|
+
}
|
|
@@ -47,7 +47,7 @@ video_dsl/
|
|
|
47
47
|
```
|
|
48
48
|
主题 → [gen-script] → Video DSL
|
|
49
49
|
↓
|
|
50
|
-
[template-
|
|
50
|
+
[template-registry] → TemplateBinding
|
|
51
51
|
↓
|
|
52
52
|
[render-video] → RenderPlan → MP4 / 剪映草稿
|
|
53
53
|
```
|
|
@@ -67,7 +67,7 @@ video_dsl/
|
|
|
67
67
|
| 模块 | 职责 | 被谁调用 |
|
|
68
68
|
|------|------|----------|
|
|
69
69
|
| `dsl_validator.py` | DSL JSON Schema 校验与参数标准化 | gen-script、render-video |
|
|
70
|
-
| `template_binder.py` | 将 DSL scene 映射到模板 slot,生成 TemplateBinding(从 @ab-templates/metadata 读取模板定义) | template-
|
|
70
|
+
| `template_binder.py` | 将 DSL scene 映射到模板 slot,生成 TemplateBinding(从 @ab-templates/metadata 读取模板定义) | template-registry |
|
|
71
71
|
| `timeline_compiler.py` | 帧号计算、字幕切片(`split_subtitle`)、旁白分段(`segment_narration`) | render-video(跨 skill import) |
|
|
72
72
|
| `asset_adapter.py` | 素材格式适配 | render-video |
|
|
73
73
|
| `prompt_enhancer.py` | 图片 prompt 增强 | render-video |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Package marker for ``video_dsl.runtime`` — kept intentionally empty.
|
|
2
2
|
|
|
3
3
|
This file exists so ``from video_dsl.runtime.<mod> import …`` resolves when
|
|
4
|
-
``skills/template-
|
|
4
|
+
``skills/template-registry/`` is on sys.path (the pattern used by render-video
|
|
5
5
|
and gen-script). Public modules:
|
|
6
6
|
|
|
7
7
|
- timeline_compiler : DSL → Remotion frame-axis timeline + subtitle splits
|
|
@@ -17,222 +17,109 @@ triggers:
|
|
|
17
17
|
|
|
18
18
|
# Video Deconstruction Skill
|
|
19
19
|
|
|
20
|
-
Splits a video into reusable content assets — audio, ASR transcript (with per-word timestamps), scene cuts, keyframe images
|
|
20
|
+
Splits a video into reusable content assets — audio, ASR transcript (with per-word timestamps), scene cuts, keyframe images — and returns a structured asset-manifest JSON.
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- **ffmpeg**: must be installed locally (`brew install ffmpeg`) — used for audio extraction, scene-change detection, and keyframe capture.
|
|
25
|
-
- **Python 3**: standard library only, no third-party dependencies.
|
|
22
|
+
The skill entry (`scripts/parse_via_render.py`) runs the deconstruction **through the ab-render HTTP service** (`POST /parse` → poll `POST /parseStatus`). It needs **no local ffmpeg** — the heavy lifting happens server-side and the manifest (with cloud-hosted asset URLs) comes back as JSON on stdout.
|
|
26
23
|
|
|
27
24
|
## Authentication & environment
|
|
28
25
|
|
|
29
|
-
|
|
26
|
+
No skill-local env file — the executing process inherits the system environment.
|
|
30
27
|
|
|
31
|
-
- **Enterprise OpenClaw**: auth
|
|
32
|
-
- **Other environments**:
|
|
28
|
+
- **Enterprise OpenClaw**: auth + service address are injected; nothing to configure.
|
|
29
|
+
- **Other environments**: set `RENDER_API_URL` (the ab-render service) and `PRIV_TOKEN`. Without them the run fails fast with an actionable message.
|
|
33
30
|
|
|
34
31
|
| Env var | Description | Default |
|
|
35
32
|
|---------|-------------|---------|
|
|
36
|
-
| `
|
|
37
|
-
| `
|
|
38
|
-
| `
|
|
33
|
+
| `RENDER_API_URL` | ab-render service base URL (e.g. `http://localhost:3000`). Required. | (none) |
|
|
34
|
+
| `PRIV_TOKEN` | Tianyan token, sent as `X-Priv-Token`. | (none) |
|
|
35
|
+
| `CONVERSATION_ID` | Optional, sent as `x-conversation-id` for file association. | (none) |
|
|
39
36
|
|
|
40
37
|
## Steps
|
|
41
38
|
|
|
42
|
-
1. **Script path**: read the system-injected `Base directory for this skill: <path>` as `<SkillDir>`.
|
|
43
|
-
2. **
|
|
44
|
-
3. **
|
|
45
|
-
4. **
|
|
46
|
-
5. **Inspect the result**: check `deconstruction.json`, `audio.mp3`, and the `keyframes/` directory in the output folder.
|
|
39
|
+
1. **Script path**: read the system-injected `Base directory for this skill: <path>` as `<SkillDir>`. The entry is always `<SkillDir>/scripts/parse_via_render.py`; never hard-code paths.
|
|
40
|
+
2. **Provide a direct video URL** (`--url`). Page links (Douyin / Xiaohongshu share pages) are not supported — pass a direct video file URL.
|
|
41
|
+
3. **Run and wait**: the script submits the task and polls until it finishes (up to ~10 minutes), printing progress lines.
|
|
42
|
+
4. **Consume the result**: a JSON asset-manifest is printed to stdout (audio / ASR / scenes / keyframes, with cloud URLs). Save or pipe it as needed.
|
|
47
43
|
|
|
48
|
-
### Deconstruct
|
|
44
|
+
### Deconstruct a video
|
|
49
45
|
|
|
50
46
|
```bash
|
|
51
|
-
python3 <SkillDir>/scripts/
|
|
52
|
-
--url "https://example.com/video.mp4"
|
|
53
|
-
--output-dir ./output_deconstructed
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### Deconstruct from a local file
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
python3 <SkillDir>/scripts/deconstruct_video.py \
|
|
60
|
-
--local /path/to/video.mp4 \
|
|
61
|
-
--output-dir ./output_deconstructed
|
|
47
|
+
python3 <SkillDir>/scripts/parse_via_render.py \
|
|
48
|
+
--url "https://example.com/video.mp4"
|
|
62
49
|
```
|
|
63
50
|
|
|
64
51
|
### Custom scene-change threshold
|
|
65
52
|
|
|
66
53
|
```bash
|
|
67
|
-
python3 <SkillDir>/scripts/
|
|
54
|
+
python3 <SkillDir>/scripts/parse_via_render.py \
|
|
68
55
|
--url "https://example.com/video.mp4" \
|
|
69
56
|
--scene-threshold 0.4
|
|
70
57
|
```
|
|
71
58
|
|
|
72
|
-
Lower values are more sensitive (more cuts), higher values
|
|
59
|
+
Lower values are more sensitive (more cuts), higher values looser (fewer cuts). Default `0.3`.
|
|
73
60
|
|
|
74
|
-
###
|
|
61
|
+
### Skip ASR or keyframes
|
|
75
62
|
|
|
76
63
|
```bash
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
--skip-keyframes
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Keyframes only (skip ASR)
|
|
64
|
+
# audio + scenes only (skip keyframes)
|
|
65
|
+
python3 <SkillDir>/scripts/parse_via_render.py --url "https://example.com/video.mp4" --skip-keyframes
|
|
83
66
|
|
|
84
|
-
|
|
85
|
-
python3 <SkillDir>/scripts/
|
|
86
|
-
--url "https://example.com/video.mp4" \
|
|
87
|
-
--skip-asr
|
|
67
|
+
# keyframes + scenes only (skip ASR)
|
|
68
|
+
python3 <SkillDir>/scripts/parse_via_render.py --url "https://example.com/video.mp4" --skip-asr
|
|
88
69
|
```
|
|
89
70
|
|
|
90
71
|
### JSON pipeline mode
|
|
91
72
|
|
|
92
73
|
```bash
|
|
93
|
-
python3 <SkillDir>/scripts/
|
|
74
|
+
python3 <SkillDir>/scripts/parse_via_render.py \
|
|
94
75
|
--url "https://example.com/video.mp4" \
|
|
95
76
|
--json-output
|
|
96
77
|
```
|
|
97
78
|
|
|
98
|
-
Prints only the final
|
|
99
|
-
|
|
100
|
-
See every option: `python3 <SkillDir>/scripts/deconstruct_video.py --help`.
|
|
79
|
+
Prints only the final manifest JSON to stdout — no progress lines — suitable for piping into downstream tools.
|
|
101
80
|
|
|
102
81
|
## Common CLI flags
|
|
103
82
|
|
|
104
83
|
| Flag | Description | Default |
|
|
105
84
|
|------|-------------|---------|
|
|
106
|
-
| `--url` |
|
|
107
|
-
| `--
|
|
108
|
-
| `-o` / `--output-dir` | Output directory. | `./deconstructed_<timestamp>` |
|
|
109
|
-
| `--scene-threshold` | Scene-change threshold 0.0–1.0. | `0.3` |
|
|
110
|
-
| `--private-token` | Override `privateToken`. | env var |
|
|
111
|
-
| `--json-output` | Pipeline mode — JSON-only stdout. | off |
|
|
85
|
+
| `--url` | Direct remote video URL (required). | — |
|
|
86
|
+
| `--scene-threshold` | Scene-change sensitivity 0.0–1.0. | `0.3` |
|
|
112
87
|
| `--skip-asr` | Skip the ASR step. | off |
|
|
113
88
|
| `--skip-keyframes` | Skip the keyframe-extraction step. | off |
|
|
89
|
+
| `--json-output` | Pipeline mode — JSON-only stdout. | off |
|
|
114
90
|
|
|
115
|
-
##
|
|
116
|
-
|
|
117
|
-
The script writes the following under `--output-dir`:
|
|
118
|
-
|
|
119
|
-
```
|
|
120
|
-
<output-dir>/
|
|
121
|
-
├── audio.mp3 # Extracted audio file
|
|
122
|
-
├── deconstruction.json # Asset-manifest JSON
|
|
123
|
-
└── keyframes/ # Keyframe images
|
|
124
|
-
├── frame_001.jpg
|
|
125
|
-
├── frame_002.jpg
|
|
126
|
-
└── ...
|
|
127
|
-
```
|
|
91
|
+
## Result manifest shape
|
|
128
92
|
|
|
129
|
-
|
|
93
|
+
`parse_via_render.py` prints the service's `result` payload — a structured manifest whose top-level fields are:
|
|
130
94
|
|
|
131
95
|
```json
|
|
132
96
|
{
|
|
133
|
-
"source":
|
|
134
|
-
"url": "
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
138
|
-
"audio": {
|
|
139
|
-
"localPath": "output_dir/audio.mp3",
|
|
140
|
-
"url": "uploaded OSS URL"
|
|
141
|
-
},
|
|
142
|
-
"asr": {
|
|
143
|
-
"text": "full recognized transcript",
|
|
144
|
-
"duration": 3816,
|
|
145
|
-
"utterances": [
|
|
146
|
-
{
|
|
147
|
-
"text": "per-utterance text",
|
|
148
|
-
"startTime": 0,
|
|
149
|
-
"endTime": 1000,
|
|
150
|
-
"words": [...]
|
|
151
|
-
}
|
|
152
|
-
]
|
|
153
|
-
},
|
|
154
|
-
"scenes": [
|
|
155
|
-
{
|
|
156
|
-
"index": 0,
|
|
157
|
-
"startTimeSec": 0.0,
|
|
158
|
-
"endTimeSec": 3.5,
|
|
159
|
-
"keyframe": "keyframes/frame_001.jpg"
|
|
160
|
-
}
|
|
161
|
-
],
|
|
162
|
-
"keyframes": [
|
|
163
|
-
{
|
|
164
|
-
"index": 0,
|
|
165
|
-
"timestampSec": 0.0,
|
|
166
|
-
"localPath": "keyframes/frame_001.jpg"
|
|
167
|
-
}
|
|
168
|
-
]
|
|
97
|
+
"source": { "url": "original URL", "durationMs": 12345 },
|
|
98
|
+
"audio": { "url": "cloud audio URL" },
|
|
99
|
+
"asr": { "text": "full transcript", "utterances": [ { "text": "...", "startTime": 0, "endTime": 1000, "words": [] } ] },
|
|
100
|
+
"scenes": [ { "index": 0, "startTimeSec": 0.0, "endTimeSec": 3.5, "keyframe": "cloud keyframe URL" } ],
|
|
101
|
+
"keyframes":[ { "index": 0, "timestampSec": 0.0, "url": "cloud keyframe URL" } ]
|
|
169
102
|
}
|
|
170
103
|
```
|
|
171
104
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
Reads the deconstruction artifacts and extracts hook, narrative structure, copy pacing, scene composition, etc., emitting a structured analysis report. Script path: `<SkillDir>/scripts/analyze_video.py`.
|
|
175
|
-
|
|
176
|
-
The analysis report can be used to:
|
|
177
|
-
- Feed an AI to write a new script with the same structure.
|
|
178
|
-
- Guide a human re-creator to replicate the video's rhythm.
|
|
179
|
-
- Inform downstream template development.
|
|
105
|
+
(Exact fields are defined by the ab-render service; treat the above as representative.)
|
|
180
106
|
|
|
181
|
-
|
|
107
|
+
## Optional local tools (not the skill entry)
|
|
182
108
|
|
|
183
|
-
|
|
184
|
-
python3 <SkillDir>/scripts/analyze_video.py \
|
|
185
|
-
-i ./output/deconstructed_xxx/deconstruction.json
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
### Specify the output directory
|
|
189
|
-
|
|
190
|
-
```bash
|
|
191
|
-
python3 <SkillDir>/scripts/analyze_video.py \
|
|
192
|
-
-i ./output/deconstructed_xxx/ \
|
|
193
|
-
-o ./reports/
|
|
194
|
-
```
|
|
109
|
+
Two extra scripts ship alongside the entry for local / offline use. They are **not** invoked by the `video_parser` tool and are **not** the skill entry — call them directly with `python3` only when you specifically need local processing:
|
|
195
110
|
|
|
196
|
-
|
|
111
|
+
- **`scripts/deconstruct_video.py`** — a fully local deconstruction alternative that **requires ffmpeg** (`brew install ffmpeg`) and writes `audio.mp3` + `keyframes/` + `deconstruction.json` to an `--output-dir`. Use when there is no ab-render service available. Flags: `--url` / `--local`, `-o/--output-dir`, `--scene-threshold`, `--skip-asr`, `--skip-keyframes`, `--json-output`.
|
|
112
|
+
- **`scripts/analyze_video.py`** — a second stage that reads a `deconstruction.json` (or the manifest above saved to disk) and emits a structural-analysis report (hook, narrative structure, pacing, CTA, …). Flags: `-i/--input`, `-o/--output-dir`, `--json-output`.
|
|
197
113
|
|
|
198
|
-
```bash
|
|
199
|
-
python3 <SkillDir>/scripts/analyze_video.py
|
|
200
|
-
|
|
201
|
-
--json-output
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
Prints only the `analysis.json` payload to stdout, no progress text, suitable for piping.
|
|
205
|
-
|
|
206
|
-
### analyze_video.py flags
|
|
207
|
-
|
|
208
|
-
| Flag | Description | Default |
|
|
209
|
-
|------|-------------|---------|
|
|
210
|
-
| `-i` / `--input` | Path to `deconstruction.json` or its parent directory. | required |
|
|
211
|
-
| `-o` / `--output-dir` | Output directory. | same as input |
|
|
212
|
-
| `--json-output` | Pipeline mode (JSON-only stdout). | off |
|
|
213
|
-
|
|
214
|
-
### Output files
|
|
215
|
-
|
|
216
|
-
`analysis.json`: the structured analysis report. Covers the following dimensions:
|
|
217
|
-
|
|
218
|
-
| Field | Description |
|
|
219
|
-
|-------|-------------|
|
|
220
|
-
| `source` | Original video information (URL, duration). |
|
|
221
|
-
| `overview` | Language, scene count, copy length, asset types. |
|
|
222
|
-
| `hook` | Opening-hook text, duration, strategy classification. |
|
|
223
|
-
| `narrativeStructure` | Per-scene narrative structure (role, duration share, text density). |
|
|
224
|
-
| `pacing` | Pacing analysis (scene-duration distribution, rhythm type). |
|
|
225
|
-
| `textStructure` | Copy structure (speaking rate, silent gaps, keywords). |
|
|
226
|
-
| `audioPattern` | Audio pattern (speech vs. silence ratio). |
|
|
227
|
-
| `cta` | CTA detection (closing copy, whether an explicit CTA exists). |
|
|
228
|
-
| `assets` | Asset manifest (audio, keyframes). |
|
|
114
|
+
```bash
|
|
115
|
+
python3 <SkillDir>/scripts/analyze_video.py -i ./deconstruction.json
|
|
116
|
+
```
|
|
229
117
|
|
|
230
118
|
## Error handling
|
|
231
119
|
|
|
232
|
-
-
|
|
233
|
-
- **401 / token missing** (non-OpenClaw):
|
|
120
|
+
- **`RENDER_API_URL` not configured**: the script exits with a clear message; set the ab-render service URL.
|
|
121
|
+
- **401 / token missing** (non-OpenClaw): set `PRIV_TOKEN`.
|
|
234
122
|
- **Business `code != 0`**: read the `msg` printed on stderr.
|
|
235
|
-
- **Video download failed**: confirm the URL is a direct video link (page links
|
|
236
|
-
- **
|
|
237
|
-
- **No scene change detected**: too-high threshold
|
|
238
|
-
- **Network**: check connectivity and `MM_API_BASE_URL`.
|
|
123
|
+
- **Video download failed**: confirm the URL is a direct video link (share/page links are not supported).
|
|
124
|
+
- **Timeout**: very long videos may exceed the ~10-minute poll window; retry or pre-trim.
|
|
125
|
+
- **No scene change detected**: a too-high threshold yields zero cuts — lower `--scene-threshold`.
|
|
@@ -2,20 +2,20 @@
|
|
|
2
2
|
"name": "video-parser",
|
|
3
3
|
"toolName": "video_parser",
|
|
4
4
|
"tier": "tool",
|
|
5
|
+
"category": "consuming",
|
|
5
6
|
"title": "Video Deconstruction",
|
|
6
7
|
"description": "Video deconstruction: split a video into reusable assets (audio extraction, ASR transcript, keyframe extraction, scene segmentation).",
|
|
7
|
-
"envVars": ["
|
|
8
|
+
"envVars": ["RENDER_API_URL", "PRIV_TOKEN", "CONVERSATION_ID"],
|
|
8
9
|
"scriptPath": "scripts/parse_via_render.py",
|
|
9
10
|
"parameters": {
|
|
10
11
|
"type": "object",
|
|
11
12
|
"properties": {
|
|
12
|
-
"url": { "type": "string", "description": "
|
|
13
|
-
"local": { "type": "string", "description": "Local video path (or use url)" },
|
|
13
|
+
"url": { "type": "string", "description": "Direct remote video URL (required). Share/page links are not supported." },
|
|
14
14
|
"scene_threshold": { "type": "number", "description": "Scene-cut detection threshold 0.0-1.0 (default 0.3)" },
|
|
15
15
|
"skip_asr": { "type": "boolean", "description": "Skip the ASR step" },
|
|
16
16
|
"skip_keyframes": { "type": "boolean", "description": "Skip the keyframe-extraction step" },
|
|
17
17
|
"json_output": { "type": "boolean", "description": "Pipeline mode — emit JSON only on stdout" }
|
|
18
18
|
},
|
|
19
|
-
"required": []
|
|
19
|
+
"required": ["url"]
|
|
20
20
|
}
|
|
21
21
|
}
|