自动驾驶 - 当用户输入 /short-form-video-editor 时的操作流程
用户上传视频(以及可选的Logo图片)并输入命令。完整执行整个任务,无需提问;仅在遇到真正阻塞的问题时停止(未找到视频、没有ffmpeg)。命令后的额外文本视为风格/品牌说明,请加以应用。
- 查找输入:会话上传中最新的视频文件(
ls -t /root/.claude/uploads/*/*.{mp4,mov,webm}或消息中给出的路径);Logo = 附件中的图片(如有)(无Logo则跳过水印/片头/片尾Logo,使用干净的无文本片尾)。语言 = 使用asr_chunks.py ... auto自动检测。 - 定位工具包:本技能文件夹(包含此SKILL.md的目录)下有
template/。在新的项目文件夹中工作:当该仓库在会话中时,在Video-editing仓库克隆内创建为projects/<slug>-<YYYYMMDD>/,否则在暂存区中。执行cp -r template/. <project>/。 - 检查/安装依赖(一次性操作):
ffmpeg、Node + Playwright Chromium(位于/opt/pw-browsers,切勿运行playwright install)、pip install numpy pillow sherpa-onnx、scripts/fetch_asr_model.sh。HuggingFace无网络连接;GitHub releases、npm、PyPI可正常工作。 - 端到端运行下面的工作流,自行做出设计决策(品牌色从Logo提取;否则使用珊瑚/青绿科技调色板;场景从
reference/scene-patterns.md中选择,以匹配实际说的内容)。 - 交付:使用
SendUserFile发送mp4(展示渲染结果),然后提供简短摘要:规格、添加了哪些图形、需要人工听校的低置信度转录片段、原始分辨率说明、“音频未经验听”。将项目目录(不含work/)和最终mp4保存到仓库中,并推送到会话指定的分支(若无则推送到main)。除非被要求,切勿创建PR。 - 预计60秒视频耗时约15-25分钟(转录约3分钟,渲染约4分钟,编码约2分钟)。开始时用一句话告知用户,然后静默工作直到完成。
配音模式 - 翻译 + 新语音 + 唇形同步(在Glow片段上测试过一次:阿拉伯语 -> 英语)
当用户希望视频以另一种语言出现“并且嘴唇跟台词同步”时使用。
- 脚本:像编辑模式一样转录并验证原文,然后自行撰写翻译并保存为
data/phrases.<lang>.json=[[win_start, win_end, "text with *key words and DISPLAY|spoken overrides (NBSP inside multi-word tokens)"], ...]。保留原始短语窗口,以便摄像机/图形节拍保持不变;可以合并相邻窗口。每个窗口大约设定2.5-3个词/秒(英语)——浓缩而非赶时间;保留原意,不添加新主张。口语覆盖示例:*COSRX|Cosrex、Axis-Y|Axis\u00a0Y。 - 模型:运行
scripts/fetch_dub_models.sh(以及用于验证的fetch_asr_model.sh)。 - 语音(默认 = 克隆说话人的声音):构建
work/ref.wav= 4-5个干净的无音停顿片段(共约15秒)的说话人原始语音(16k单声道,拼接而成)。执行python3 -I scripts/tts_clone.py data/phrases.en.json work/ref.wav 8 <total_seconds>-> 生成work/voice_en.wav+ 包含实际语音片段的data/transcript.source.json。YourTTS(coqui,由fetch_dub_models.sh下载)进行零样本音色克隆;该脚本每行生成N个候选,保留Whisper回读与脚本最匹配的候选,然后进行时间拉伸(0.72-1.25倍,保持音高)以填充约90%的原始窗口时长。在Glow片段上的验证数据:中位音高144 Hz vs 说话人154 Hz(Kokoro基础语音123 Hz),长期频谱相似度0.96 vs 0.90,每行回读正确。通过DISPLAY|spoken按音标拼写品牌名称(并自动将其排除在评分之外)。后备方案tts_phrases.py= 使用Kokoro基础语音(清晰但不匹配说话人)。口音:模型传递的是音色/音高,不是母语口音——不要承诺埃及口音的英语;要说明实际达到的效果。 - 在原始分辨率帧上进行唇形同步:
ffmpeg -t <end> -i src -vf fps=30 work/raw/%05d.png;ffmpeg -i work/voice_en.wav -ac 1 -ar 16000 work/en16k.wav;MODELS=work/models python3 -I scripts/lipsync2.py work/raw work/en16k.wav work/ls --model wav2lip_gan_96.onnx --enhance 0.7(先用--range a b测试;1700帧在4个CPU上完整运行约25分钟:Haar框、每帧的2dfan4地标、然后Wav2Lip + GFPGAN逐帧处理)。lipsync2 = 基于地标的FFHQ-512裁剪、平滑地标、在地标面部框上的Wav2Lip、0.7混合的GFPGAN修复、嘴部形状遮罩(绝不触及鼻子)、粘贴回去。然后运行scripts/01b_upscale_lipsynced.sh。不要使用旧的lipsync.py(粗糙的Haar裁剪:嘴唇模糊、舌头状伪影——用户称之为“非常差”)。EDTalk-256也曾试用过,效果更差(嘴部鬼影)。模型:来自facefusion-assets GitHub release的2dfan4、gfpgan_1.4、wav2lip_gan_96。 - 视觉同步验证:制作嘴部裁剪图的联系表,每帧下方显示音频包络线——嘴部在静音间隙必须闭合,在音频条上升时张开并有变化。像素相关性指标在此过于嘈杂,不要依赖它们。
- 图形:执行
python3 -I scripts/build_transcript.py work/en16k.wav(在源json中将max_chars设置为约22(英语)),重新生成composition/transcript.js,然后重写scene.js复制和触发词(使用新语言:LTR方向下.row/.chunk方向为ltr,使用Inter字体,起点居左,流向箭头从左到右)。多词标记在转录中作为单独的词处理:查找单个词(ts('skin',0,43.5)),切勿使用ts('your skin')。 - 像往常一样渲染(
LAST_SRC_FRAME=<n> scripts/02_render_all.sh、提示、音效)并与VOICE=work/voice_en.wav OUT=out/name-en.mp4 scripts/03_mix_and_encode.sh混合。 - 在摘要中诚实说明:Wav2Lip在大约100像素的面部上会产生柔软、略微平滑的嘴部(近看可见),头部和手部动作仍然是原说话人的,语音是合成的,说话人应批准其形象的配音版本,建议标记为AI配音。注明任何源转录置信度较低的翻译短语。
短视频编辑器(字幕 + 动态图形 + 音效)
两种模式:编辑(保持语言,添加字幕/图形/音效)和配音(翻译成另一种语言,新语音,嘴唇随新音频重新动画化——当用户提到英语/翻译/配音/唇形同步时触发)。流水线已在57秒的埃及阿拉伯语药店宣传片(Glow Cosmetics)上验证。输出:1080x1920 @30fps、H.264/AAC、-14 LUFS。
已完成的示例项目:projects/glow-kbeauty-reel/ 在 https://github.com/MuhammadToffaha/Video-editing
定义“专业,而非模板”的规则
- 保持说话人、语音和原意不变。绝不虚构声明(数字、“100%”、价格)。如果图形需要文本而原语音中并未说出,则保持通用(类别名称、标签文字)。
- 每个视觉元素支持一句口语,并在该词上触发(
ts('word')),而非短语开头。卡片在下一个进入前退出;无重叠残影。 - 单一视觉语言:品牌色(从Logo采样) + 白色 + 深墨色玻璃面板,拉丁标签用Inter字体,标题/字幕用Cairo字体(阿拉伯语)。仅薄荷色用于成功状态。
- 布局区域(1080x1920,说话人面部约y 790-1110):卡片y 235-735(绝不覆盖面部,即使1.15倍缩放后),字幕y约1545,保持底部220像素和顶部130像素无关键内容(平台UI)。需为每个源重新检查面部位置。
- 留存手段,适度使用:句子开始时1.12-1.15倍缩放快切,其间缓慢漂移,每2-4秒一个图形,活动单词高亮字幕,划线/勾选/计数微动画,品牌名称出现时的片头Logo时刻,品牌片尾卡片。
- 音效:卡片进入时的嗖声,元素上的噼啪/滴答声,成功时的铃声,Logo上的重击声。音量低(比语音低约-10 dB)。除非用户提供,否则不使用音乐。
工作流
- 检查:
ffprobe,联系表(ffmpeg -vf "fps=1/6,scale=239:-1,tile=5x2"),查找片尾卡片(WhatsApp/CapCut黑帧)并记录说话人位置。原始源通常分辨率较低(手机/WhatsApp):使用lanczos升采样,告知用户画面会偏软而图形保持清晰。 - 项目:
cp -r <skill>/template/. my-project/ && cd my-project;cp <logo> assets/;python3 -I scripts/extract_logo.py assets/logo_original.png assets/logo_white.png(打印品牌十六进制颜色)。在composition/style.css和#wm/#outro中更新--coral/--brand。 - 准备:
END=<trim_seconds> scripts/01_prepare.sh input.mp4(帧、16k wav、语音)。 - 转录(沙箱中无HF访问;GitHub releases可工作):运行
scripts/fetch_asr_model.sh;然后- 运行
python3 -I scripts/asr_chunks.py work/asr16k.wav <lang|auto> 3.2 a,重复使用2.4和4.5。Whisper会截断片段尾部;自己合并3个假设并利用自己的语言知识修正。 - 不确定的词/品牌名:运行
python3 -I scripts/asr_probe.py work/asr16k.wav ar,en 14.0-16.8 14.5-16.6 ...(en通道拼写拉丁品牌名称)。只信任跨重叠窗口一致的内容;其余的在最终消息和README中列为低置信度。绝不要基于猜测的名称构建图形。
- 运行
- 时间点:运行
python3 -I scripts/pauses.py work/asr16k.wav-> 停顿是可靠的短语边界。将data/transcript.source.json写为[start, end, "text"]短语(参见data/transcript.source.example.json;*word= 重点标注;多词拉丁名称内使用NBSP;RTL文本中的拉丁品牌:避免阿拉伯语و前缀粘附到它们上,写成و Brand)。然后运行python3 -I scripts/build_transcript.py work/asr16k.wav和echo "window.TRANSCRIPT=$(cat data/transcript.json);" > composition/transcript.js。该脚本通过音节权重在每个短语内分配词的时间并匹配能量谷点,然后生成2-4个词的平衡字幕块。合理性检查:无声间隙内无词起点。 - 在
composition/scene.js中设计场景(参见reference/scene-patterns.md)。使用card(t0,t1,{y,h,html})、pop、fade、draw、cue、ts。将示例场景作为模式使用:钩子卡片、品牌芯片(说出名称时填充的骨骼槽)、类别磁贴、A->B匹配图(带移动圆点和勾选)、划掉芯片、流程节点、星级评分、清单行、路线图、条形图、信任环、片头Logo揭示、品牌片尾。设置finish(<seconds>)= 语音结束 + 约1.7秒片尾。 - 渲染与质量保证:首先渲染几个测试帧(
node scripts/render.mjs <f> <f+1> work/test),使用Pillow制作联系表,查看它们。然后运行scripts/02_render_all.sh(4个worker,总计约8 fps)、node scripts/render.mjs cues work/cues.json && python3 -I scripts/sfx.py work/cues.json work/sfx.wav、OUT=out/name.mp4 scripts/03_mix_and_encode.sh。如果源视频以片尾卡片结束,传递LAST_SRC_FRAME=<n>以冻结最后一帧干净的画面。 - 交付:发送mp4(SendUserFile),注明规格、低置信度转录片段、原始分辨率限制,以及音频未经人耳听校(你无法听到)——仅通过响度计和起点vs能量测试检查。
已解决的陷阱(无需重新学习)
- Python的
str.split()会在NBSP上分割——使用split(' ')(已在 build_transcript.py 中修正)。 - 使用CSS
scaleY动画化SVG<rect>在无头Chromium中会导致翻转/偏移问题——改为补间attr:{y,height}。路径描边动画:使用draw(path,t,d)。 - 初始隐藏的元素需要CSS
opacity:0(类hid)和设置immediateRender:false的补间;每个补间必须可寻址(worker直接跳转到其起始帧)。 - 使用
backdrop-filter的卡片仅在视频帧位于同一页面(#bgimg)时才能模糊——这就是为什么帧会在页面内合成。 - 空的模糊卡片看起来有问题:要么在触发词上开始卡片,要么显示暗淡的占位行/插槽,在讲到时点亮。
- 阿拉伯语需要真实字形整形:Chromium + Cairo woff2(按unicode范围分割阿拉伯语/拉丁语)可行;Pillow/ffmpeg drawtext不行。
- sherpa-onnx中的Whisper没有词时间戳且会截断尾部;因此使用短窗口+停顿锚定。
- opencv 5.x没有
CascadeClassifier(请锁定4.10.0.84版本);Haar人脸框会在手/衬衫上产生误报并遗漏约30%的帧 -> 中值框离群值剔除 + ROI二次检测 + 插值(已在 lipsync.py 中实现)。 - Kokoro/Whisper风格的TTS会把
COSRX作为字母逐个读出:使用DISPLAY|spoken覆盖。 - GitHub MCP的
create_repository可能返回403——请让用户创建仓库,然后使用add_repo+ 克隆(如果路径已存在则克隆到新目录)。