@dsh-gis/dsh-video-studio-skill 0.7.2 → 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.
Files changed (45) hide show
  1. package/CHANGELOG.md +1109 -0
  2. package/README.md +76 -10
  3. package/THIRD_PARTY_NOTICES.md +1 -0
  4. package/docs/styles/sheet-8-styles.png +0 -0
  5. package/docs/styles/sheet-before-after.png +0 -0
  6. package/index.js +4 -1
  7. package/package.json +7 -3
  8. package/schemas/film.schema.json +329 -2
  9. package/skills/video-studio/SKILL.md +270 -13
  10. package/skills/video-studio/assets/golden_frames.json +65 -0
  11. package/skills/video-studio/assets/scenes.py +2162 -1190
  12. package/skills/video-studio/assets/web/engine.js +63 -2
  13. package/skills/video-studio/assets/web/film.js +224 -101
  14. package/skills/video-studio/assets/web/index.html +4 -2
  15. package/skills/video-studio/assets/web/qa_text.js +36 -8
  16. package/skills/video-studio/references/audio-variation.md +4 -3
  17. package/skills/video-studio/references/audio.md +2 -2
  18. package/skills/video-studio/references/change-impact.md +1 -1
  19. package/skills/video-studio/references/quality-gates.md +25 -3
  20. package/skills/video-studio/references/scene-grammar.md +306 -0
  21. package/skills/video-studio/references/style-packs.md +108 -3
  22. package/skills/video-studio/references/v08-quality.md +256 -0
  23. package/skills/video-studio/references/web-engine.md +19 -2
  24. package/skills/video-studio/references/word-timeline.md +147 -0
  25. package/skills/video-studio/requirements.txt +14 -0
  26. package/skills/video-studio/scripts/filmcheck.py +218 -0
  27. package/skills/video-studio/scripts/filmkit.py +521 -38
  28. package/skills/video-studio/scripts/gates.py +88 -4
  29. package/skills/video-studio/scripts/grammar.py +559 -0
  30. package/skills/video-studio/scripts/preflight.py +774 -0
  31. package/skills/video-studio/scripts/qa_frames.py +49 -8
  32. package/skills/video-studio/scripts/qaasr.py +1563 -0
  33. package/skills/video-studio/scripts/qavmaf.py +1442 -0
  34. package/skills/video-studio/scripts/render.py +764 -32
  35. package/skills/video-studio/scripts/scorekit.py +16 -30
  36. package/skills/video-studio/scripts/selfcheck.py +483 -0
  37. package/skills/video-studio/scripts/sfxkit.py +130 -14
  38. package/skills/video-studio/scripts/stagewatch.py +19 -6
  39. package/skills/video-studio/scripts/stylekit.py +242 -12
  40. package/skills/video-studio/scripts/voicekit.py +15 -7
  41. package/skills/video-studio/scripts/webengine.py +1119 -72
  42. package/tools/ci_check.py +173 -31
  43. package/tools/estimate.py +130 -19
  44. package/tools/golden_frames.py +664 -0
  45. package/tools/silhouette_qa.py +910 -0
package/README.md CHANGED
@@ -1,11 +1,12 @@
1
1
  # @dsh-gis/dsh-video-studio-skill
2
2
 
3
- ![version](https://img.shields.io/badge/version-0.7.2-blue) ![license](https://img.shields.io/badge/license-MIT-green)
3
+ ![version](https://img.shields.io/badge/version-0.9.1-blue) ![license](https://img.shields.io/badge/license-MIT-green)
4
4
 
5
5
  **DeepSeek Harness 技能插件:用代码从零生成中文视频。**
6
6
 
7
7
  写剧本 → edge-tts 旁白 → **实测时长**排时间轴 → **提示点**驱动配乐与音效 → PIL 或浏览器逐帧渲染 →
8
- ffmpeg 编码 → 采样级混音 → **四层质检**(容器 / 信号 / 时间 / 页面)。
8
+ ffmpeg 编码 → 采样级混音 → **四层质检**(容器 / 信号 / 时间 / 页面)+ **v0.8 的四个新闸**
9
+ (渲前资源预检 `G0` / 词级时间戳 `G10` / 全片 VMAF `G11` / ASR 回读 `G12`)。
9
10
  零素材、可复现、可断点续跑、可脚本化验收;装成插件后,整片生产流程随技能一起进入每个会话。
10
11
 
11
12
  > 源自 `dsh-v` 资产包的 `02-技能包-video-studio`(817 个 DSH 会话的考古分析 + 5 套现存工程逆向 + 本机实测)。
@@ -36,6 +37,43 @@ ffmpeg 编码 → 采样级混音 → **四层质检**(容器 / 信号 / 时
36
37
  > 实测(真实素材):旧混音 -4.2 dB → 新混音 12.0 dB,`audio_similarity --strict` D 组 12.9 dB;
37
38
  > selfcheck 34 → 38 条,其中第 35–38 条专盯这条链路。
38
39
  > 详见 [CHANGELOG.md](CHANGELOG.md) 与 SKILL.md §5.6 / §5.7、references/audio-variation.md。
40
+ > **v0.8.0(把"看得见"变成"抓得住")**:四个方向——① **词级时间轴**:edge-tts 的 WordBoundary 事件落
41
+ > `work/words.json`(4 句 / 64 词 / 末词偏差 0.09 s),字幕改按词折行,cue 可写词锚点 `"l03:w2+0.1"`;
42
+ > ② **四道新门禁**:渲前资源预检 `G0`(缺字形/坏音频在渲第一帧前 fail,< 1 s)、词级时间戳 `G10`、
43
+ > 全片 VMAF/SSIM `G11`(参考帧由场景函数**实时重渲**,不是成片抽帧;29 s 片 VMAF 97.22 / 14.2 s)、ASR 回读 `G12`
44
+ > (成片音轨转文字对账,0.72 以下才 fail,8.7 s/片);③ **画幅/帧率参数化**(只做 16:9 横屏,
45
+ > 内部恒 1080p、编码时下采样,720p 已实测全门通过)、**批量** `--batch`(≤100 条、开跑前全量预检、
46
+ > 单条失败不阻断)、**预览** `--preview N`(前 N 秒出 mp4+gif)、**运行版本化** `--run-id`(`work/runs/<runId>/`);
47
+ > ④ web 引擎跟随风格包(`window.__STYLE__` 注入,`style=None` 时逐字节等于 v0.7)+ 金帧像素回归
48
+ > `tools/golden_frames.py`。**代价要说清**:29 s 模板片全链从约 28 s 涨到 **47.3 s**,其中 `qa` **23.9 s**
49
+ > 已经**超过渲染本身**(`frames` 12.5 s);`estimate` 预演也从 28.4 s 变成 **58.8–108.2 s**(vmaf 31–50 s 是瓶颈)。
50
+ > v0.8 之后"出片时间"不再只是渲染时间。selfcheck 43 → **51 条**。
51
+ > 详见 [CHANGELOG.md](CHANGELOG.md) 与 SKILL.md §6.1 / §7.5、references/word-timeline.md、references/v08-quality.md。
52
+ > **v0.8.1(全项目深审,无新功能)**:把 14 个模块 / 5 个前端文件 / 12 篇 references / 仓库工具链
53
+ > 全部过一遍,修掉 **60+ 处**「看着没问题、其实没在查」。举几个真会伤到交付的:
54
+ > ① **VMAF 参考帧与成片的字幕折行口径不一致**(渲染传 `words`、参考帧没传)——近静态画面
55
+ > 从 **99.95 掉到 8.55**,同源好片被判 fail;② `--stage style/stills/frames/mux` 的门禁 fail
56
+ > **没进退出码**(stdout 打 [FAIL]、进程仍 exit 0);③ `webengine` 在 `style=None` + 720p 时
57
+ > **静默输出 1080p 原画的左上角裁切**(逐像素相同、标题/HUD 全丢、exit 0);
58
+ > ④ `visual.layout` 与 `qa.vmaf.sample_step` 写了**完全没人读**;⑤ `selfcheck` 第 51 条把金帧
59
+ > 的 skipped 当 PASS(**这条门禁从没真的比过一帧**);⑥ `ci_check` 把"跳过(没装 node)"记成 PASS。
60
+ > 详见 [CHANGELOG.md](CHANGELOG.md) 的 0.8.1 段(含行为变化表与升级须知)。
61
+ > **v0.9.0(换风格不再只是换色)**:v0.5 的风格包只覆盖"皮肤"(配色/字体/纹理/字距/缓动),
62
+ > 8 套风格共用同样的构图骨架,用户反馈"每个视频都差不多,只是主题和颜色不同"。
63
+ > v0.9 把这条链路拆成三层:**场景语法**(按内容选 10 类构图:hero / statement / list / stat /
64
+ > compare / process / quote / chapter / chart / outro,落 `work/storyboard.json` 可审计)、
65
+ > **视觉语言包**(每套风格补五组结构签名:motion / motif / transition / typography / bias,
66
+ > 母题预烘焙并合成进背景底版,逐帧只 copy/EXTENT)、**片内编排**(版式变体 / 装饰密度 / 相位偏移,防"复印")。
67
+ > 新门禁 **G13 剪影可区分**(`tools/silhouette_qa.py`):8 套风格两两 **28 对全部通过**,
68
+ > 改造前同明暗族 12 对只过 8 对。**代价如实说**:模板片 frames 约 **19 ms/帧(54–61 fps)**,
69
+ > 仍在 25 ms 预算内,但比 v0.8.1 的约 13 ms/帧(约 75 fps)慢——慢在 10 类构图各自多了装饰与几何。
70
+ > 0.9.1 已经把装饰母题从"逐帧 paste(实测 5.6 ms)"改成"烘焙进背景底版(1.3–2.0 ms)",
71
+ > 这也是它比 0.9.0 首版快回来一截的原因。web 引擎本次不跟随场景语法;
72
+ > legacy(不写 `style`)仍逐字节不变。selfcheck 51 → **55 条**。
73
+ > **v0.9.1** 把"逐帧全屏贴装饰"(实测 5.6 ms/帧)改成"装饰烘焙进背景底版"(1.3–2.0 ms),
74
+ > 顺带让装饰跟着镜头缓推一起动(cinema / epic 的强 push 下不再穿帮)。
75
+ > 详见 [CHANGELOG.md](CHANGELOG.md) 的 0.9.0 / 0.9.1 段与
76
+ > [references/scene-grammar.md](skills/video-studio/references/scene-grammar.md)。
39
77
 
40
78
  ## 安装
41
79
 
@@ -79,12 +117,19 @@ TTS 实测时长、AAC 编码都会让真峰/响度/锐度浮动,**别 chasing
79
117
  29.00 s / -16.5 LUFS / -1.4 dBTP / 锐度比 1.01(2026-11-10 另一台 Windows 机器复测)——
80
118
  **不同机器、不同 TTS 结果,两组都对,别混着引用**。
81
119
 
82
- ## 效果:同一个模板,八种气质(v0.5)
120
+ ## 效果:同一个模板,八种气质(v0.5 → v0.9)
83
121
 
84
- 同一份文字,只改 `"style"`(画风 / 配乐 / 旁白 / 节奏一起变):
122
+ 同一份文字、同一个场景类型(`list`),只改 `"style"`。**v0.9 起不只是换色**:
123
+ 每套风格有自己的装饰母题(括角 / 手绘框 / letterbox / 信号条 / 放射线…)、
124
+ 字距与编号写法、段界转场、整体重心偏移,所以同一屏的骨架与留白也不同:
85
125
 
86
126
  <p align="center"><img src="docs/styles/sheet-8-styles.png" width="100%" alt="8 套风格对比:科技深蓝 / 杂志暖白 / 手绘纸感 / 活力撞色 / 极简黑白 / 电影青橙 / 暖灰薄荷 / 深黑鎏金"></p>
87
127
 
128
+ > 这张图是 v0.9 用新代码重渲的(8 套风格 × 同一段内容),**换图不是换滤镜**:
129
+ > 标题锚点、装饰语言、编号写法、重心都在变。要看"这一段为什么画成这样",
130
+ > 跑 `--stage style` 会打印视觉语言(母题/转场/字距/编号/重心),
131
+ > 跑 `--stage layout` 会打印分镜(每段选哪类构图、为什么)并落 `work/storyboard.json`。
132
+
88
133
  三份**不同题材**的短片(全流程真跑:TTS → 排轴 → 配乐 → 音效 → 混音 → 逐帧 → 编码 → 质检;数据见
89
134
  `docs/styles/demo-results.json`,是 v0.5 时期的实测快照,片源脚本未随仓库分发,**不可直接复现**;
90
135
  **别把这张表当成"现在跑出来就是这样"**——BPM/调性由内容指纹从风格梯度里选(v0.7 起指纹还参与配乐结构),
@@ -112,11 +157,14 @@ mkdir -p myfilm && cd myfilm
112
157
  cp <SKILL_DIR>/assets/film.json . # 剧本模板("style": "auto")
113
158
  cp <SKILL_DIR>/assets/scenes.py . # 场景模板
114
159
  cp <SKILL_DIR>/scripts/*.py . # filmkit/stylekit/voicekit/render/selfcheck + sfxkit/scorekit/qa_frames/webengine
160
+ # v0.8 还含 preflight/qaasr/qavmaf(可选:缺了对应门禁记 skipped)
115
161
  cp -r <SKILL_DIR>/assets/web ./web # 只在走浏览器引擎时需要
116
162
 
117
- python selfcheck.py # 43 条环境/回归断言(20 秒内,不联网)
163
+ python selfcheck.py # 55 条环境/回归断言(20 秒内,不联网)
118
164
  python <REPO>/tools/estimate.py --script film.json # v0.6:开渲前先算耗时/磁盘/分块(仓库/包里的工具,
119
165
  # 不在 skills/video-studio/ 内,quickstart 拷出来的目录没有它)
166
+ # v0.8:已含 preflight/vmaf/asr 三段;29 s 模板片
167
+ # 预演 total 28.4 s -> 37.5-83.0 s(区间上界,实测 47.3 s)
120
168
  python render.py --stage stills --stills "l01:3,l02:5" # 母版预览(缺 tts/layout 会自动补跑)
121
169
  python render.py --script film.json --scenes scenes.py --out out/film.mp4 --work work
122
170
  cat out/QC-REPORT.md # v0.6:机器可读交付结论(pass/fail/skipped)
@@ -157,6 +205,15 @@ tts → layout → cues → score → sfx → audio → frames → mux → qa
157
205
  | 改完东西不知道要重跑什么 | `--stage explain`(机器判断过时阶段 + 给最小重跑命令),表见 [references/change-impact.md](skills/video-studio/references/change-impact.md) |
158
206
  | 规整 `film.json` 避免静默失效 | `python skills/video-studio/scripts/filmcheck.py film.json`(`holds`→提示写成 `hold`) |
159
207
 
208
+ **v0.8 的四个新开关**(前三个会改变门禁结果,第四个只是看片更快):
209
+
210
+ | 想要 | 怎么做 |
211
+ |---|---|
212
+ | 交付 720p / 换帧率 | `film.json` 写 `"video": {"width":1280,"height":720,"fps":24}`(只做 16:9 横屏、只能下采样;720p 已实测全门通过) |
213
+ | 批量出片 | `python render.py --batch films.json`(≤100 条、开跑前全量预检、单条失败不阻断、末尾 `batch-report.json`) |
214
+ | 只渲前 N 秒给人看 | `--preview 15`(出 `out/preview/*.mp4` + `.gif`,不写交付账本) |
215
+ | 让 QA 快一点 | `--vmaf sample`(每 5 帧取 1,实测 8.0 s vs 全片 14.2 s,VMAF 只差 0.34)或 `--vmaf off`(G11 记 skipped) |
216
+
160
217
  长片:`--stage frames --jobs 4`(按绝对帧号分块并行)+ `--resume`(中断只补缺块)。
161
218
 
162
219
  ## 这个技能解决什么
@@ -186,12 +243,17 @@ skills/video-studio/
186
243
  SKILL.md 主线:上手 / 八阶段 / 引擎选型 / 画质 / 声音 / 提示点 / 停留窗口 / 质检 / 故障速查
187
244
  references/ pipeline · scene-authoring · audio · audio-variation · sfx-design · web-engine
188
245
  frame-qa · quality-gates · change-impact · style-packs · pitfalls
246
+ word-timeline(v0.8)· v08-quality(v0.8)
189
247
  scripts/filmkit.py 生产内核(字体/排版/字幕/音频总线/CueBus/TTS/时间轴/编码/质检)
190
248
  scripts/gates.py v0.6 门禁账本 / QC 报告渲染 / 人工签核(绑内容指纹)
191
249
  scripts/stagewatch.py v0.6 阶段新鲜度(work/manifest.json + --stage explain)
192
250
  scripts/filmcheck.py v0.6 film.json 契约校验(未知键/枚举/跨字段)
193
- scripts/render.py 编排器(13 个 stage、pil|web 双引擎、分块并行、断点续跑、母版预览、门禁账本)
194
- scripts/selfcheck.py 回归自检(43 条"曾真的坏过"的断言)
251
+ scripts/render.py 编排器(13 个 stage、pil|web 双引擎、分块并行、断点续跑、母版预览、门禁账本;
252
+ v0.8 增 --batch / --preview / --run-id / --vmaf / --no-preflight)
253
+ scripts/preflight.py v0.8 渲染前资源预检(字形 / TTS 音频 / 字体 / web 入口页,门禁 G0)
254
+ scripts/qavmaf.py v0.8 全片 VMAF/SSIM(参考帧由场景函数实时重渲,门禁 G11)
255
+ scripts/qaasr.py v0.8 ASR 回读(成片音轨转文字对账,门禁 G12)
256
+ scripts/selfcheck.py 回归自检(55 条"曾真的坏过"的断言)
195
257
  scripts/sfxkit.py 物理建模音效库(24 配方,scipy 可选)
196
258
  scripts/scorekit.py 程序化配乐(和弦表 / 分段能量 / 吸气)
197
259
  scripts/webengine.py 浏览器逐帧渲染(CDP 截图、分块并行、崩溃重开、cue 导出、文字质检)
@@ -199,9 +261,11 @@ skills/video-studio/
199
261
  requirements.txt Python 依赖(必需 / 强烈建议 / 可选三档,带注释)
200
262
  assets/film.json 剧本模板(含 bpm / music / sfx.cues / 逐句 hold;顶层 hold 可选,缺省用风格 pacing)
201
263
  assets/scenes.py 场景模板(开场 / 正文卡片 / 收尾 + cues() 钩子)
202
- assets/web/ 浏览器页面模板(原生 Canvas2D 确定性时间轴)
264
+ assets/golden_frames.json v0.8 金帧基线(3 帧 sha256 + 字体/环境指纹,改绘制代码后重录)
265
+ assets/web/ 浏览器页面模板(原生 Canvas2D 确定性时间轴;v0.8 读 window.__STYLE__)
203
266
  tools/ci_check.py 仓库级体检(12 项;语法/JSON/依赖白名单/打包卫生/文档引用/film 契约,不需 ffmpeg)
204
- tools/estimate.py 开渲前成本预演(帧数/耗时/磁盘/分块建议,--json 可机读)
267
+ tools/estimate.py 开渲前成本预演(帧数/耗时/磁盘/分块建议,--json 可机读;v0.8 含 preflight/vmaf/asr)
268
+ tools/golden_frames.py v0.8 金帧像素回归(--write 重录 / --check 校验;同环境像素变了 = fail)
205
269
  tools/audio_similarity.py 音频差异/相似度验收(--strict 阈值判定,改音频代码后必跑)
206
270
  tools/selftest_noscipy.py 无 scipy 兜底路径自检(CI 用;屏蔽 scipy 后跑 sfxkit/scorekit 自检)
207
271
  schemas/film.schema.json film.json 的契约(draft-07 子集)
@@ -213,7 +277,9 @@ schemas/film.schema.json film.json 的契约(draft-07 子集)
213
277
  **插件运行**:Node.js ≥ 20(`package.json` 的 `engines`;这是 DSH 加载插件用的运行时,不必另装)。
214
278
  **必需**:ffmpeg + Python 的 numpy / Pillow / edge-tts。
215
279
  **可选**:cv2(编码锐度比)、scipy(音效滤波加速,缺了走 FFT 卷积)、
216
- playwright + Chromium/Edge(只在 `--engine web` 时需要)。
280
+ playwright + Chromium/Edge(只在 `--engine web` 时需要)、
281
+ faster-whisper(v0.8 的 ASR 回读门禁 G12;没装会降级到 ffmpeg whisper 滤镜,仍不可用则记 skipped)。
282
+ v0.8 的 G11(全片 VMAF)不需要新依赖,但要求 ffmpeg 构建**带 libvmaf**(9.0.2 full_build 有)。
217
283
  不需要 moviepy / pydub / soundfile / librosa / manim——本技能一行都不 import 它们。
218
284
 
219
285
  依赖清单有机器可读的一份,别再手抄:
@@ -30,6 +30,7 @@
30
30
  | opencv-python(cv2) | 编码锐度比(Laplacian 方差) | Apache-2.0 | 可选(缺了跳过锐度门禁) |
31
31
  | scipy | sfxkit 的时间域滤波加速 | BSD-3-Clause | 可选(缺了走 FFT 卷积兜底) |
32
32
  | playwright | web 引擎驱动 Chromium/Edge | Apache-2.0 | 可选(只在 `--engine web` 时需要) |
33
+ | faster-whisper | ASR 回读门禁(G12)把成片音轨转回文字 | MIT(模型权重另有许可,随模型分发) | 可选(缺了降级到 ffmpeg whisper 滤镜 / skipped) |
33
34
  | Chromium / Microsoft Edge | web 引擎的渲染内核 | BSD-3-Clause / 微软条款 | 可选 |
34
35
 
35
36
  **字体**:PIL 引擎使用系统自带中文字体(Windows 的 `msyh.ttc`/`msyhbd.ttc` 等),
Binary file
package/index.js CHANGED
@@ -68,7 +68,10 @@ export async function apply(ctx) {
68
68
  // 这里必须兜住:插件行的加载失败会让整行从 profile 里消失,而"挂不上技能"本来只是个降级。
69
69
  // (v0.7.1 之前没兜:provider 一抛错 apply 就 reject,而且一行日志都没有——stub 实测复现过。)
70
70
  try {
71
- applyFilesystemProvider(ctx, {
71
+ // 必须 await:provider 的 apply 是 Cordis 插件函数,允许返回 Promise。
72
+ // 不 await 时这里的 try/catch 只能拦住同步 throw,异步 reject 会变成
73
+ // unhandledRejection(Node >=15 默认让进程退出),"挂不上技能只是降级"就变成崩进程。
74
+ await applyFilesystemProvider(ctx, {
72
75
  providerName: "video-studio",
73
76
  includeDefaultRoots: false,
74
77
  bundledSkillDir,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dsh-gis/dsh-video-studio-skill",
3
- "version": "0.7.2",
4
- "description": "Video Studio skill plugin for DeepSeek Harness: style-pack driven code-generated Chinese videos — one style id decides palette/typography/music style/voice persona/pacing, measured TTS timeline, deterministic PIL/browser rendering, programmatic SFX and score, cue-driven sound sync, ffmpeg encoding, sample-level mixing and multi-layer QA gates.",
3
+ "version": "0.9.1",
4
+ "description": "Video Studio skill plugin for DeepSeek Harness: style-pack driven code-generated Chinese videos — one style id decides palette/typography/music style/voice persona/pacing, measured TTS timeline with word-level boundaries, deterministic PIL/browser rendering (16:9 landscape, 720p/1080p), programmatic SFX and score, cue-driven sound sync, ffmpeg encoding, sample-level mixing, batch production and multi-layer QA gates (preflight, full-film VMAF/SSIM, ASR readback).",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "exports": {
@@ -24,10 +24,12 @@
24
24
  "locale/*.json",
25
25
  "docs/demo-pil-sheet.png",
26
26
  "THIRD_PARTY_NOTICES.md",
27
+ "CHANGELOG.md",
27
28
  "skills",
28
29
  "!skills/**/__pycache__",
29
30
  "!skills/**/*.pyc",
30
31
  "docs/styles/sheet-8-styles.png",
32
+ "docs/styles/sheet-before-after.png",
31
33
  "docs/styles/sheet-ai.png",
32
34
  "docs/styles/sheet-craft.png",
33
35
  "docs/styles/sheet-night.png",
@@ -36,7 +38,9 @@
36
38
  "tools/estimate.py",
37
39
  "tools/ci_check.py",
38
40
  "tools/audio_similarity.py",
39
- "tools/selftest_noscipy.py"
41
+ "tools/selftest_noscipy.py",
42
+ "tools/golden_frames.py",
43
+ "tools/silhouette_qa.py"
40
44
  ],
41
45
  "publishConfig": {
42
46
  "access": "public"
@@ -76,12 +76,16 @@
76
76
  "rate_range": {
77
77
  "type": "array",
78
78
  "description": "语速夹取区间(百分数,例如 [-15, 12])",
79
- "items": { "type": "number" }
79
+ "items": {
80
+ "type": "number"
81
+ }
80
82
  },
81
83
  "cps_band": {
82
84
  "type": "array",
83
85
  "description": "可接受的每秒字数区间(默认 [3.6, 5.6])",
84
- "items": { "type": "number" }
86
+ "items": {
87
+ "type": "number"
88
+ }
85
89
  }
86
90
  }
87
91
  },
@@ -235,6 +239,173 @@
235
239
  "voice": {
236
240
  "type": "string",
237
241
  "description": "显式 edge-tts voice id(覆盖 persona 底子)"
242
+ },
243
+ "type": {
244
+ "type": "string",
245
+ "enum": [
246
+ "hero",
247
+ "statement",
248
+ "list",
249
+ "stat",
250
+ "compare",
251
+ "process",
252
+ "quote",
253
+ "chapter",
254
+ "chart",
255
+ "outro"
256
+ ],
257
+ "description": "视觉场景类型(v0.9,可选):决定这段画面长成什么构图——hero 封面 / statement 金句 / list 要点列表 / stat 数字卡 / compare 左右对比 / process 流程轴 / quote 引语 / chapter 章节卡 / chart 数据条 / outro 收尾。与 kind **正交**:kind 管声线、语气、配乐能量,type 只管构图,所以没有新增 kind 值;不写 = 由 grammar.py 按内容自动推导(写错值 filmcheck.py 会报 error)。枚举真值来自 grammar.SCENE_TYPES 与 assets/scenes.py 的 _DRAWERS 键,改那边要同步这里"
258
+ },
259
+ "quote": {
260
+ "type": "string",
261
+ "description": "引语原文(type=quote 时用):打在屏幕上的引文。它和 text 是两件事——text 是 TTS 念的那句,quote 是画面上那句话本身"
262
+ },
263
+ "by": {
264
+ "type": "string",
265
+ "description": "引语出处/作者(type=quote 时用),如“—— 某本书 · 某作者”;与 quote 配套,缺省不画署名"
266
+ },
267
+ "stats": {
268
+ "type": "array",
269
+ "description": "数字卡原料(type=stat):每项 {value, unit, label, note}。value 必填(数字或字符串,字符串用于“>3x”“1/2”这类写法);unit 是单位后缀,label 是指标名,note 是小字补充",
270
+ "items": {
271
+ "type": "object",
272
+ "required": [
273
+ "value"
274
+ ],
275
+ "additionalProperties": true,
276
+ "properties": {
277
+ "value": {
278
+ "type": [
279
+ "number",
280
+ "string"
281
+ ],
282
+ "description": "数字主体(必填):数字,或“>3x”“1/2”这类字符串写法"
283
+ },
284
+ "unit": {
285
+ "type": "string",
286
+ "description": "单位/后缀,如“秒”“%”“fps”"
287
+ },
288
+ "label": {
289
+ "type": "string",
290
+ "description": "指标名,如“帧率”"
291
+ },
292
+ "note": {
293
+ "type": "string",
294
+ "description": "补充说明(小字),可省略"
295
+ }
296
+ }
297
+ }
298
+ },
299
+ "series": {
300
+ "type": "array",
301
+ "description": "数据条原料(type=chart):每项 {label, value, unit}。label 是条形名(必填),value 是条长(必填,数字或数值字符串)",
302
+ "items": {
303
+ "type": "object",
304
+ "required": [
305
+ "label",
306
+ "value"
307
+ ],
308
+ "additionalProperties": true,
309
+ "properties": {
310
+ "label": {
311
+ "type": "string",
312
+ "description": "条形名(必填)"
313
+ },
314
+ "value": {
315
+ "type": [
316
+ "number",
317
+ "string"
318
+ ],
319
+ "description": "条长(必填):数字或数值字符串(“0.8”“80%”由绘制器解析)"
320
+ },
321
+ "unit": {
322
+ "type": "string",
323
+ "description": "单位/后缀,如“GB”“%”"
324
+ }
325
+ }
326
+ }
327
+ },
328
+ "steps": {
329
+ "type": "array",
330
+ "description": "流程轴原料(type=process):每项 {label, note},数组顺序即节点顺序",
331
+ "items": {
332
+ "type": "object",
333
+ "required": [
334
+ "label"
335
+ ],
336
+ "additionalProperties": true,
337
+ "properties": {
338
+ "label": {
339
+ "type": "string",
340
+ "description": "节点名(必填)"
341
+ },
342
+ "note": {
343
+ "type": "string",
344
+ "description": "节点补充说明(小字),可省略"
345
+ }
346
+ }
347
+ }
348
+ },
349
+ "sides": {
350
+ "type": "object",
351
+ "additionalProperties": true,
352
+ "description": "左右对比原料(type=compare):{left, right},每侧 {head, items[]};items 里每项可写字符串,也可写对象 {text}(两种都认:短条目直接写字符串更省事)",
353
+ "properties": {
354
+ "left": {
355
+ "type": "object",
356
+ "additionalProperties": true,
357
+ "description": "左侧",
358
+ "properties": {
359
+ "head": {
360
+ "type": "string",
361
+ "description": "左侧小标题"
362
+ },
363
+ "items": {
364
+ "type": "array",
365
+ "description": "左侧条目:字符串或对象 {text} 两种写法都行",
366
+ "items": {
367
+ "type": [
368
+ "string",
369
+ "object"
370
+ ],
371
+ "properties": {
372
+ "text": {
373
+ "type": "string",
374
+ "description": "条目文字(写对象时用它;写字符串时字符串本身就是文字)"
375
+ }
376
+ }
377
+ }
378
+ }
379
+ }
380
+ },
381
+ "right": {
382
+ "type": "object",
383
+ "additionalProperties": true,
384
+ "description": "右侧",
385
+ "properties": {
386
+ "head": {
387
+ "type": "string",
388
+ "description": "右侧小标题"
389
+ },
390
+ "items": {
391
+ "type": "array",
392
+ "description": "右侧条目:字符串或对象 {text} 两种写法都行",
393
+ "items": {
394
+ "type": [
395
+ "string",
396
+ "object"
397
+ ],
398
+ "properties": {
399
+ "text": {
400
+ "type": "string",
401
+ "description": "条目文字(写对象时用它;写字符串时字符串本身就是文字)"
402
+ }
403
+ }
404
+ }
405
+ }
406
+ }
407
+ }
408
+ }
238
409
  }
239
410
  }
240
411
  }
@@ -593,6 +764,162 @@
593
764
  "description": "页面分块秒数(webengine 切块用,默认 30)"
594
765
  }
595
766
  }
767
+ },
768
+ "words": {
769
+ "type": "boolean",
770
+ "description": "v0.8 词级时间戳开关(默认 true)。true 时 --stage tts 会额外收 edge-tts 的 WordBoundary 事件落 work/words.json,字幕按词边界折行、cue 可用词锚点 l03:w2、QA 走 G10 门禁;false = 退回整句字幕(不影响出片)。"
771
+ },
772
+ "tts": {
773
+ "type": "object",
774
+ "additionalProperties": true,
775
+ "description": "v0.8 TTS 后端选择(接口化,默认 edge;其它后端需先 filmkit.register_tts_backend 注册)。",
776
+ "properties": {
777
+ "backend": {
778
+ "type": "string",
779
+ "description": "后端名,缺省 edge"
780
+ },
781
+ "voice": {
782
+ "type": [
783
+ "string",
784
+ "object"
785
+ ],
786
+ "description": "覆盖顶层 voice"
787
+ }
788
+ }
789
+ },
790
+ "video": {
791
+ "type": "object",
792
+ "additionalProperties": true,
793
+ "description": "v0.8 画幅/帧率(**只支持 16:9 横屏**)。内部构图恒为 1920x1080,输出只能更小(编码时 lanczos 下采样);竖屏 / 非 16:9 / 上采样 / 非法 fps 会被 filmkit.video_plan 直接报错。",
794
+ "properties": {
795
+ "width": {
796
+ "type": "integer",
797
+ "enum": [
798
+ 1920,
799
+ 1280,
800
+ 960,
801
+ 2560
802
+ ],
803
+ "description": "输出宽(16:9 横屏)"
804
+ },
805
+ "height": {
806
+ "type": "integer",
807
+ "enum": [
808
+ 1080,
809
+ 720,
810
+ 540,
811
+ 1440
812
+ ],
813
+ "description": "输出高(16:9 横屏)"
814
+ },
815
+ "fps": {
816
+ "type": "integer",
817
+ "enum": [
818
+ 24,
819
+ 25,
820
+ 30,
821
+ 50,
822
+ 60
823
+ ],
824
+ "description": "帧率,缺省 30"
825
+ }
826
+ }
827
+ },
828
+ "qa": {
829
+ "type": "object",
830
+ "additionalProperties": true,
831
+ "description": "v0.8 质检门禁参数:全片 VMAF/SSIM(G11)与 ASR 回读(G12)。",
832
+ "properties": {
833
+ "vmaf": {
834
+ "type": "object",
835
+ "additionalProperties": true,
836
+ "description": "全片 VMAF/SSIM 门禁(参考帧由场景函数实时渲染,不是成片抽帧)。注意:本对象里的 enabled 与 qa.require_vmaf 是**惰性键**(v0.8 起草时留下,代码无读取点),真正生效的开关是 mode=off / --vmaf off;filmcheck.py 对惰性键会报 WARN。",
837
+ "properties": {
838
+ "enabled": {
839
+ "type": "boolean",
840
+ "description": "惰性键:写它不生效(要跳过 G11 请写 mode=\"off\" 或命令行 --vmaf off)"
841
+ },
842
+ "mode": {
843
+ "type": "string",
844
+ "enum": [
845
+ "full",
846
+ "sample",
847
+ "off"
848
+ ],
849
+ "description": "full=逐帧(默认,约 1.2x 实时);sample=每 N 帧取 1;off=不跑"
850
+ },
851
+ "pass": {
852
+ "type": "number",
853
+ "minimum": 0,
854
+ "maximum": 100,
855
+ "description": "VMAF 低于此值 -> fail(默认 92,权威定义在 qavmaf.py 的 VMAF_PASS;标定依据见 references/v08-quality.md)"
856
+ },
857
+ "warn": {
858
+ "type": "number",
859
+ "minimum": 0,
860
+ "maximum": 100,
861
+ "description": "介于 pass 与 warn 之间 -> pass+warning(默认 96,权威定义在 qavmaf.py 的 VMAF_WARN)"
862
+ },
863
+ "sample_step": {
864
+ "type": "integer",
865
+ "minimum": 1,
866
+ "description": "mode=sample 时的抽样步长"
867
+ }
868
+ }
869
+ },
870
+ "ssim": {
871
+ "type": "object",
872
+ "additionalProperties": true,
873
+ "description": "SSIM 阈值(诊断项,不单独阻断;默认 pass=0.95 / warn=0.98,权威定义在 qavmaf.py)",
874
+ "properties": {
875
+ "enabled": {
876
+ "type": "boolean",
877
+ "description": "惰性键:写它不生效(SSIM 本来就只是诊断项,不单独阻断)"
878
+ },
879
+ "pass": {
880
+ "type": "number",
881
+ "minimum": 0,
882
+ "maximum": 1
883
+ },
884
+ "warn": {
885
+ "type": "number",
886
+ "minimum": 0,
887
+ "maximum": 1
888
+ }
889
+ }
890
+ },
891
+ "require_vmaf": {
892
+ "type": "boolean",
893
+ "description": "惰性键:写它不生效(要强制 G11 不许记 skipped,请用 --strict-gates)"
894
+ },
895
+ "asr": {
896
+ "type": "object",
897
+ "additionalProperties": true,
898
+ "description": "ASR 回读门禁(把成片音轨转回文字与剧本对账)",
899
+ "properties": {
900
+ "enabled": {
901
+ "type": "boolean",
902
+ "description": "false = 本次不做回读(记 skipped)"
903
+ },
904
+ "model": {
905
+ "type": "string",
906
+ "description": "faster-whisper 模型名,缺省 small"
907
+ },
908
+ "recall_pass": {
909
+ "type": "number",
910
+ "minimum": 0,
911
+ "maximum": 1,
912
+ "description": "召回率 >= 此值算干净(默认 0.85)"
913
+ },
914
+ "recall_warn": {
915
+ "type": "number",
916
+ "minimum": 0,
917
+ "maximum": 1,
918
+ "description": "低于此值 -> fail(默认 0.72)"
919
+ }
920
+ }
921
+ }
922
+ }
596
923
  }
597
924
  },
598
925
  "additionalProperties": true