涌现视频自动化:WebReel 网页录屏、PPT 转化与 AI 剧本生成
面向产品演示和学术教程的自动化视频制作流水线。使用 WebReel 进行浏览器录制,使用 DashScope/Edge-TTS 进行配音,并使用 FFmpeg 进行后期组装。
安装
文档
Technical Manifest
技能:涌现视频制作器 (Emergence Video Producer) 🎬
本技能可将 Markdown 格式的“视频脚本”转化为专业的产品演示或教学视频。它专为云端 VM 的无头 (Headless) 环境设计,使智能体能够自主生成视觉文档。
1. 前置要求
请确保以下工具已安装在系统路径中:
webreel或puppeteer(用于录制/截图)ffmpeg(用于后期组装)edge-tts或dashscope凭据 (用于语音合成)Pillow(如果需要从 WebP 提取帧)
2. 交互模型:访谈模式
与僵化的 CLI 工具不同,本技能从 “人工参与的访谈” (Human-in-the-Loop Interview) 开始。
探索阶段
智能体必须主动询问以下问题:
- 目标: “这个视频的主要目标是什么?(例如:功能发布、学术总结、新手引导)”
- 模式: “应该使用 浏览器演示 (WebReel/Puppeteer) 还是 PPT 风格展示 (Slidev)?”
- 基调: “期望的人设是什么?(例如:专业、激情、严谨)”
- 目标 URL/内容: “我们需要录制哪个网站,或者有哪些关键幻灯片?”
3. 工作流程
阶段 1:构思与分镜 (Ideation & Storyboarding)
根据访谈内容,智能体起草 storyboard.md。这是一个协商产生的文件。
- 不要 要求人类编写 Markdown。
- 要 要求人类“审查并批准”草案。
阶段 2:配置与资源准备
获得批准后,智能体将自动生成:
- 浏览器模式: 包含精确选择器和时间点的
webreel.config.json或capture.js。 - 幻灯片模式: 用于 Slidev 渲染的
slides.md。 - 音频: 将旁白文本合成为高质量的 TTS 语音。
阶段 3:浏览器捕获 (Browser Capture)
您可以选择以下两种方法之一:
方案 A:Puppeteer 截图捕获 (推荐)
编写一个 capture.js 脚本,每秒抓取 1 张截图:
const puppeteer = require('puppeteer');
const fs = require('fs');
const path = require('path');
const TOTAL_SECONDS = 68; // 与音频时长匹配
const OUTPUT_DIR = '/tmp/video-frames';
const VIEWPORT = { width: 1920, height: 1080 };
// 在给定的秒数触发动作
const steps = [
{ at: 0, action: 'navigate', url: 'https://example.com' },
{ at: 3, action: 'wait' },
{ at: 8, action: 'scroll', y: 500 },
{ at: 14, action: 'scroll', y: 1000 },
{ at: 22, action: 'click', selector: 'a[href="/target"]' },
{ at: 35, action: 'scroll', y: 600 },
];
(async () => {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu'],
defaultViewport: VIEWPORT,
});
const page = await browser.newPage();
for (let second = 0; second < TOTAL_SECONDS; second++) {
for (const s of steps.filter(s => s.at === second)) {
if (s.action === 'navigate') {
await page.goto(s.url, { waitUntil: 'networkidle2', timeout: 15000 }).catch(() => {});
} else if (s.action === 'scroll') {
await page.evaluate(y => window.scrollTo({ top: y, behavior: 'instant' }), s.y).catch(() => {});
} else if (s.action === 'click') {
await Promise.all([
page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 15000 }).catch(() => {}),
page.click(s.selector).catch(() => {})
]);
}
}
await page.screenshot({
path: path.join(OUTPUT_DIR, `frame_${String(second).padStart(4, '0')}.png`),
}).catch(e => console.error('截图错误:', e.message));
}
await browser.close();
console.log('已捕获 ' + TOTAL_SECONDS + ' 帧至 ' + OUTPUT_DIR);
})();
运行脚本:
NODE_PATH=$(npm root -g) node /tmp/capture.js
注意:必须使用 NODE_PATH=$(npm root -g) 前缀来加载全局安装的 puppeteer。
方案 B:WebReel 配置 (如果您的版本可用)
webreel init --name my-video --url https://example.com
# 修改 webreel.config.json 定义步骤,然后运行:
webreel record -c webreel.config.json
如果遇到 ENOENT: no such file or directory, rename 错误,请退回到方案 A。
阶段 4:视频组装 (Video Assembly)
将图像帧与配音组合成最终的 MP4 文件:
# 统计帧数
FRAME_COUNT=$(ls /tmp/video-frames/frame_*.png | wc -l)
# 获取音频时长
AUDIO_DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 narration.mp3)
# 计算输入帧率,使所有帧填满音频时长
FPS=$(echo "$FRAME_COUNT / $AUDIO_DURATION" | bc -l)
ffmpeg -y \
-framerate $FPS \
-i /tmp/video-frames/frame_%04d.png \
-i narration.mp3 \
-c:v libx264 -pix_fmt yuv420p -preset medium -crf 23 \
-c:a aac -b:a 192k \
-shortest -r 30 \
output.mp4
FFmpeg 备注:
-framerate $FPS: 输入帧率(例如:65 帧 / 68s 音频 = ~0.956)。-r 30: 输出帧率(30fps 确保播放流畅)。-shortest: 在最短的流结束时停止。-crf 23: 质量(越低越好,18-28 为正常范围)。
阶段 5:品控与分发 (Taste Gate and Distribution)
将生成的视频提交给用户进行审查。提供以下信息:
- MP4 文件路径
- 时长、分辨率、文件大小
- 各章节涵盖内容的简要总结
审查通过后,发布至 ClawHub、社交平台,或通过聊天附件交付。
4. 完整工作流示例
# 设置
mkdir -p /tmp/my-video && cd /tmp/my-video
# 生成配音
cat > narration.txt << 'EOF'
欢迎来到涌现科学 (Emergence Science)...
EOF
edge-tts --voice zh-CN-XiaoxiaoNeural --text "$(cat narration.txt)" --write-media narration.mp3
# 捕获截图 (根据音频时长每秒 1 帧)
AUDIO_DURATION=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 narration.mp3)
echo "音频时长: $AUDIO_DURATION 秒"
NODE_PATH=$(npm root -g) node capture.js
# 组装视频
FRAME_COUNT=$(ls frames/frame_*.png | wc -l)
FPS=$(echo "$FRAME_COUNT / $AUDIO_DURATION" | bc -l)
ffmpeg -y -framerate $FPS -i frames/frame_%04d.png -i narration.mp3 \
-c:v libx264 -pix_fmt yuv420p -c:a aac -shortest -r 30 output.mp4
# 验证
ffprobe -v error -show_entries format=duration,size \
-of default=noprint_wrappers=1:nokey=1 output.mp4
ls -lh output.mp4
5. 常见问题与解决方案
WebReel 报错 ENOENT rename
不要尝试调试 WebReel。请切换到 Puppeteer (方案 A),它在无头环境中更可靠。
Puppeteer 报错: Cannot find module
puppeteer 是全局安装的,而非本地。请使用 NODE_PATH=$(npm root -g) 前缀。
Chrome 启动时崩溃
确保在 Puppeteer 启动参数中包含以下内容:
args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu']
视频时长异常(例如应为 60s 却只有 2s)
可能是您对 65 帧使用了 -framerate 30。请确保使用 FPS = 帧数 / 音频时长 作为输入帧率,并单独指定 -r 30 作为输出帧率。
视频没有声音
验证 TTS 文件:ffprobe -v error -show_entries format=duration narration.mp3
WebReel 无法点击文本
在导航元素中请使用 selector (CSS 选择器) 而非 text:
{ "action": "click", "selector": "a[href='/zh/bounties']" }
6. 模板
本技能提供两个模板:
templates/webreel.config.json— 标准 WebReel 配置支架templates/slides.md— PPT 风格模式的 Slidev 幻灯片模板
7. 脚本
scripts/assemble_video.py— FFmpeg CLI 的 Python 替代方案(支持 WebP 帧提取)scripts/generate_audio.py— 支持 dotenv 的 edge-tts Python 封装
可验证性证明
该技能已通过涌现科学结算中心的分析和验证。它遵循通用惊奇协议(Surprisal Protocol),确保确定性的智能体执行和安全的数据处理。