clipwise: 长视频 → 竖屏短视频 是做什么的?
所有操作在本地运行(CPU 即可;如果存在 CUDA,则用于转录加速)。
SKILL_DIR 指本文件所在的文件夹。所有命令都是
python3 SKILL_DIR/scripts/run.py ...;脚本会自动切换到 clipwise 虚拟环境。
任务输出写入 ~/clipwise-work/<job>/(或 $CLIPWISE_WORK),或使用 --workdir DIR。
0. 环境检查(每次会话,仅一次)
python3 SKILL_DIR/scripts/run.py check
必须以 ready 结束。如果不是,告知用户 clipwise 需要一次性设置(约 2 GB:Python 包加 whisper 模型),请他们阅读 SKILL_DIR/setup.sh,并在同意后运行 bash SKILL_DIR/setup.sh。如果缺少 ffmpeg 或 Python 3.10+,setup.sh 会打印对应操作系统的安装命令;未经询问不要安装系统包。
工作流程
- 准备(获取 + 转录,一条命令):
输出在任务文件夹中:python3 SKILL_DIR/scripts/run.py prep "<路径或链接>" --job <名称> [--start 秒数 --max-seconds N] [--cookies cookies.txt] [--model large-v3-turbo] [--language xx]source.mp4(第一个视频 + 音频流,SDR,CFR 30(如果重新编码)),probe.json,transcript.txt(每行一个[起始-结束] (wN) 文本段,单位:来源秒数),transcript.json,words.tsv。对于长视频,使用--start/--max-seconds限定值得剪辑的部分;CPU 上转录约 0.6-1 倍实时速度。 - 自行挑选片段。 阅读
transcript.txt(以及顶部的任何# WARNING行),配合SKILL_DIR/references/viral-rubric.md。编写<job>/picks.json:每个片段 10-50 秒,开头先放钩子,结尾干净利落。数量参考下方规则。 - 渲染前获取用户批准。 显示每个片段一行:时间戳、钩子、标题、一句话理由。在小型 CPU 上渲染每个片段约需 1-2 分钟。如果您手动编写了字幕文本(非英语或混杂语言),也显示这些行。
- 渲染:
每个片段在python3 SKILL_DIR/scripts/run.py render --job <名称> [--fast] [--only 2] [--music bed.mp3]<job>/out/下输出:clip_<id>.mp4,clip_<id>.txt(标题、描述、置顶评论、话题标签、理由),clip_<id>.json(探测数据、布局、人脸覆盖率、音效、时间信息),clip_<id>_cutmap.json,clip_<id>_sheet.png。--fast= 预览质量。 - 查看每一张
clip_<id>_sheet.png使用您的图像/视觉工具(10 帧;红线 = y 1620,下方为平台 UI)。检查:脸在画面内、字幕可读、字幕不在脸上、红线下无重要内容、颜色未失真。修复(调整片段、字幕覆盖、--layout、--font-size)并用--only <id>重新渲染。 - 交付 MP4 路径和
.txt内容。提供run.py clean --job <名称>(删除source.mp4和临时目录,保留out/)。
每个视频生成多少 Shorts
-
用户指定了数量(如“从 <链接> 制作 5 个 Shorts”):精确制作该数量。如果视频中没有那么多的有力片段,在渲染前告知用户并提出实际数量(“我找到 3 个通过检查清单的片段;另外 2 个会较弱”)。
-
未指定数量: 根据来源长度(或转录窗口长度)缩放:
来源长度 Shorts 数量 5 分钟以下 1-2 5-15 分钟 3-5 15-45 分钟 5-8 45 分钟以上(播客、演讲) 8-15 -
只有通过评分规范检查清单的片段才计入。绝不要为了凑数而加入弱片段。
picks.json(最小化示例)
[{"id": "1", "start": 65.5, "end": 110.3, "title": "每场洪水都是气候变化引起的吗?",
"hook_start": 74.85, "hook_end": 80.1, "payoff_start": 102.0,
"why": "先抛出意外观点,结尾解决。", "comment_bait": "你知道吗?",
"description": "...", "hashtags": ["#shorts", "#气候"],
"caption_overrides": [{"w": 219, "text": ""}, {"start": 90.1, "end": 92.4, "text": "此处确切的词语"}]}]
必需项:id、start、end(来源秒数)。hook_start/hook_end 将 2-3 秒的行移到开头("hook_mode": "repeat" 也保留在正文中)。payoff_start 放置低音收束。caption_overrides:{"w": N, "text": ""} 编辑/删除单词 N(transcript.txt 中的 (wN),words.tsv 中的 i);{"start", "end", "text"} 替换该区间所有单词。完整模式与评分:references/viral-rubric.md。
渲染标志
| 标志 | 效果 |
|---|---|
--fast | x264 ultrafast CRF 24,4 fps 人脸采样(预览)。默认:preset faster,CRF 20 |
--only ID | 仅渲染一个片段(可重复) |
--layout auto|crop|pad | pad = 完整 16:9 画面置于模糊背景上(用于宽幅多人镜头)。当宽幅来源人脸覆盖率低于 40% 时自动选择 pad |
--music FILE | 用户提供的音乐背景,约比语音低 17 LU,通过侧链压缩闪避。--music-db 20 = 更安静 |
--sfx-dir DIR | 使用您自己的 whoosh_fast、whoosh_soft、thud_low、pop、tick(.wav/.mp3/.flac/.ogg)替代合成音效 |
--no-sfx、--no-silence-cut | 关闭这些功能 |
--font "Lato Black"、--font-size 84、--highlight yellow|green、--no-upper | 字幕样式 |
--preset、--crf、--keep-tmp | 编码器覆盖;保留语音/混音 wav 和 captions.ass 用于调试 |
环境变量:CLIPWISE_HOME(默认 ~/.clipwise)、CLIPWISE_VENV、CLIPWISE_WORK、
CLIPWISE_MODEL(默认 large-v3-turbo)、CLIPWISE_DEVICE(auto|cpu|cuda)。
渲染每个片段的具体操作
将钩子移到开头,剪切静音 > 0.35 秒(阈值来自片段自身的语音/噪音水平),保留的片段对齐到 30 fps 网格,使音频样本等于帧数。使用 YuNet 对剪切后保留的帧进行人脸跟踪:主导人脸,粘性(新人脸必须比当前大 1.6 倍且持续 1.2 秒才切换),带死区的平滑摄像头,仅在剪切处快切。每 2-4 秒推近 1.0/1.12 倍。逐字 ASS 字幕(最多 4 个单词,当前单词高亮)放置在下巴下方且 y 坐标 1620 以上。语音清洁、合成音效、可选闪避音乐、两段 loudnorm 到 -14 LUFS / -1.5 dBTP。H.264 + AAC 48 kHz、1080×1920、30 fps。最终音视频流时长需一致。
实测时间(2 核 CPU,无 GPU)
| 步骤 | 实测 |
|---|---|
| 获取:85 MB 1080p VP9 网络下载 + 3 分钟窗口重新编码为 H.264 | 总共 7.7 分钟(下载占主导,约 5 分钟) |
| 获取:20 秒 10-bit HDR iPhone 片段(色调映射 + CFR) | 45 秒(HDR 耗时约为时长的 2.3 倍) |
| large-v3-turbo 转录 3 分钟英语 | ASR 110 秒(0.61 倍实时)+ 模型加载 19 秒 |
| 默认渲染,40.6 秒片段 | 85 秒 |
--fast 渲染,26.4 秒片段 / 17.1 秒 pad 片段 | 32 秒 / 30 秒 |
常见陷阱
- YouTube 机器人验证墙(“Sign in to confirm you're not a bot”):间歇性出现,依赖 IP。
fetch 返回退出码 3。请用户提供
--cookies cookies.txt(从浏览器导出)或文件本身 / Drive 或 Dropbox 链接。不要循环尝试 yt-dlp 播放器客户端或代理。 私有 Drive 链接返回退出码 2:请用户在链接共享中设置为“拥有链接的任何人都可访问”,或提供本地文件。 - 音视频同步是硬规则。 每个输出的音频和视频流时长必须匹配,误差不超过 0.1 秒(渲染会断言)。绝不要使用非零起始的流拷贝进行修剪,也绝不要使用
aselect裁剪音频;请使用脚本。 - ASR 方案固定: 先对音频进行归一化,自动检测语言,无 VAD,无
initial_prompt(它会泄漏到转录文本中)。保持使用 large-v3-turbo;small模型在有口音或混杂语言的语音上会循环和产生幻觉(转录时会发出循环警告)。 - 非英语语音可能返回翻译结果。 对于许多使用非拉丁文字的语言(以及混杂语言语音),whisper 会返回英语。此时转录文本仅作为时间对齐和含义参考:请使用
caption_overrides中的{"start", "end", "text"}区间,以说话者自己的语言和文字编写字幕行,并在渲染前展示给用户。标题和话题标签也应遵循说话者的语言。 - 字幕: 绝不要放在脸上,且应高于底部约 300 像素(平台 UI)。如果检查帧显示冲突,缩短片段、使用
--layout pad或降低--font-size。 - 跟踪器跟随最大的脸,而不是说话者。 对于两个人在同一宽幅镜头中交谈的情况,请使用
--layout pad,或选择一个只有一个人说话的窗口。 - 上采样: 1080p 16:9 来源裁剪为 608×1080 后放大 1.8 倍;720p 来源放大 2.7 倍,看起来较模糊。优先使用 1080p 以上的下载。
- 小型 CPU: 不要同时运行两个编码任务,也不要同时运行转录和编码;渲染会逐个处理片段(run.py 已经实现)。