给视频烧录短视频特效字幕。SRT → ASS → ffmpeg。 Agent 决定风格,模板提供骨架,自然语言做微调。 一个 skill 服务所有需要加字幕的 workflow。
用户在 task form 填 3 个字段。Skill 按优先级合并:模板默认值最弱,自然语言中等, 显式 overrides 最强。最终用了哪个值、值来自哪一层,都写进 result.json,可追溯。
# 三种典型 payload # A. 只选模板,什么都不调 — 直接用默认 { "subtitle_template": "pop_kara" } # B. 自然语言微调 { "subtitle_template": "pop_kara", "instruction": "改蓝色高亮,弹得更强,字大一号" } # C. instruction 不够精确 — 加 overrides 锁死关键值 { "subtitle_template": "glow", "instruction": "低调点,别太炫", "style_overrides": { "base_outline_color": "#4A0099" } }
每个模板是一段确定性的 ASS 标签生成规则 + 一份参数表。Agent 选哪个,看用户填的 subtitle_template;若选了 "auto",Agent 自己读 instruction + 视频内容决定。
| 模板 | 核心 ASS 标签 | 关键可调参数 | SRT 要求 |
|---|---|---|---|
| clean | \fad(120,150) + 整句换行 | fontsize · primary_color · outline_color | 句级或词级 |
| karaoke | \kf<cs> 逐词 | primary_color · secondary_color | 仅词级 |
| pop | \alpha\fscx\fscy + \t() 三段 | pop_peak · pop_up_ms · pop_settle_ms | 仅词级 |
| pop_kara | pop + \1c 色切 | primary_color · settle_color · pop_peak · fontsize_scale | 仅词级 |
| glow | \3c\bord + \t() 脉冲 | base_outline · flash_outline · flash_bord_boost | 仅词级 |
用户不需要选这些。Skill 探测视频和 SRT,自动决定字号、留白、行宽、字体。 所有数值假设短边 1080 基线;不同分辨率按比例缩放。
"字大一点"也能改,"我就要 80px"也能改。最终值 = template_default × fontsize_scale × resolution_scale,除非用 absolute 锁死。
| 用户说什么 | fontsize_scale | portrait 上实际像素 |
|---|---|---|
| (什么都没说) | 1.00 | 64 |
| "字大一点" / "字大一号" | 1.15 | 74 |
| "字大很多" / "再大点" | 1.30 | 83 |
| "字超大" / "字最大" | 1.45 | 93 |
| "字小一点" | 0.85 | 54 |
| "更紧凑" / "字小点" | 0.75 | 48 |
| (精确值) style_overrides.fontsize: 80 | (绕过) | 80 |
v106 模式 — 不在任务运行时 pip install 或 curl 字体。所有 binary/包都在 worker host 准备好,workflow 的 hooks.after_create 跑 fail-fast 检查,缺则不让任务启动。
| 依赖类型 | 位置 | 暴露 | after_create 检查 |
|---|---|---|---|
| 系统二进制 | /usr/bin/ffmpeg · ffprobe | PATH | command -v ffmpeg |
| Python + pysubs2 | /opt/tobatsu/venvs/subtitle-effect-renderer/bin/python | $SUBTITLE_RENDERER_PYTHON | "$PY" -c "import pysubs2" |
| 字体集 | /opt/tobatsu/assets/subtitle-fonts | $SUBTITLE_FONT_DIR | fc-match "Noto Sans Arabic" |
* 字体不入 skill_revisions 表(管理 skill 仅 UTF-8 文本),companion 文件只放 .md/.py。
Agent 收到 payload,读 .tobatsu/skills/subtitle-effect-renderer/SKILL.md, 跑 companion 脚本,上传产物。整条流水线 7 步。
# Agent 实际跑的命令 $SUBTITLE_RENDERER_PYTHON \ .tobatsu/skills/subtitle-effect-renderer/scripts/render_subtitles.py \ --video=$workspace/inputs/source.mp4 \ --srt=$workspace/inputs/source.srt \ --template=pop_kara \ --params='{"primary_color":"#00BFFF","fontsize_scale":1.15}' \ --fontsdir=$SUBTITLE_FONT_DIR \ --out=$workspace/outputs/video/sample_sub.mp4 \ --result=$workspace/outputs/result.json tobatsu-agent output upload $workspace/outputs/video/sample_sub.mp4 \ --label "subtitled-video" --content-type video/mp4 tobatsu-agent complete --summary "pop_kara · 33 chunks · 59s"
每个最终参数都标注来自哪一层。出问题倒查 5 秒能定位是 instruction 解读偏了、 overrides 写错了,还是 template 默认值不合理。
{
"template_resolved": "pop_kara",
"template_source": "explicit", // "explicit" | "auto-from-instruction"
"params_used": {
"primary_color": "#00BFFF",
"settle_color": "#FFFFFF",
"pop_peak": 145,
"fontsize": 74,
"fontsize_scale": 1.15
},
"params_source": {
"primary_color": "instruction", // "蓝色高亮"
"settle_color": "default",
"pop_peak": "instruction", // "弹得更强"
"fontsize_scale": "instruction", // "字大一号"
"fontsize": "computed" // = default × scale × res
},
"video": {
"url": "https://cdn-asia.../sample_sub.mp4",
"width": 1080,
"height": 1920,
"duration_ms": 59200,
"size_bytes": 19450427
},
"ass_file": "outputs/subtitles/final.ass",
"chunks": 33,
"script_detected": "latin",
"aspect": "portrait"
}
覆盖语种 × 画幅 × 分辨率 × 模板的关键组合。每个用例都要看到字幕位置、字号、语种渲染都对。
* 阿拉伯是硬要求,要测 RTL 方向 + 字形重塑 + 卡拉OK 方向 + 组合符号上下行间距,缺一项不算 done。