ElevenLabs 画外音生成
使用 ElevenLabs API 为 Remotion 视频生成专业的 AI 画外音。
前置要求
.env.local文件中包含ELEVENLABS_API_KEY
快速开始
# 从文本生成画外音
node .claude/skills/elevenlabs-remotion-skill/generate.js --text "你的文本在此" --output public/audio/voiceover.mp3
# 使用叙事者风格(更自然)
node .claude/skills/elevenlabs-remotion-skill/generate.js --text "你的文本" --character narrator --output voiceover.mp3
# 生成带有请求拼接的场景
node .claude/skills/elevenlabs-remotion-skill/generate.js --scenes remotion/scenes.json --output-dir public/audio/project/
# 重新生成单个场景
node .claude/skills/elevenlabs-remotion-skill/generate.js --scenes scenes.json --scene scene2 --new-text "更新后的文本"
# 列出可用声音和角色预设
node .claude/skills/elevenlabs-remotion-skill/generate.js --list-voices
node .claude/skills/elevenlabs-remotion-skill/generate.js --list-characters
角色预设
使用角色预设可以获得更自然的画外音,而不是照本宣科地朗读屏幕文本:
| 角色 | 描述 | 最佳用途 |
|---|---|---|
literal | 完全按文本原样朗读 | 屏幕文本、引言 |
narrator | 专业讲述者,流畅吸引人 | 解说、纪录片 |
salesperson | 热情、有说服力、充满活力 | 营销、广告 |
expert | 权威、自信、知识渊博 | 法律内容、教程 |
conversational | 随意、友好、自然 | 社交媒体、休闲内容 |
dramatic | 强烈、富有情感、有冲击力 | 开场吸引力、问题陈述 |
calm | 舒缓、安心、温和 | 建立信任、结尾 |
# 全局使用叙事者风格
node .claude/skills/elevenlabs-remotion-skill/generate.js --scenes scenes.json --character narrator --output-dir public/audio/
# 或在 scenes.json 中按场景设置
{
"scenes": [
{ "id": "scene1", "text": "问题陈述", "character": "dramatic" },
{ "id": "scene2", "text": "解决方案", "character": "calm" }
]
}
基于场景的生成与请求拼接
使用 ElevenLabs 请求拼接功能,为多个场景生成一致的韵律:
scenes.json 格式
{
"name": "product-demo",
"voice": "George",
"character": "narrator",
"scenes": [
{
"id": "scene1",
"text": "通用的文本转语音听起来很机械。你的品牌值得更好的。",
"duration": 4.5,
"character": "dramatic"
},
{
"id": "scene2",
"text": "通过语音克隆,你可以用自己的声音制作无限的内容。",
"duration": 5.5
},
{
"id": "scene3",
"text": "录制一个简短的样本。克隆它。在几分钟内创建专业的画外音。",
"duration": 6,
"delay": 0.3
}
]
}
生成所有场景
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/product-demo-scenes.json \
--output-dir public/audio/product-demo/
这将创建:
product-demo-scene1.mp3到sceneN.mp3product-demo-combined.mp3(所有场景拼接)product-demo-info.json(包含时长信息的元数据)
单场景重新生成
如果某个场景开始过早、时序错误或需要不同的文本:
# 使用新文本重新生成 scene2
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/scenes.json \
--scene scene2 \
--new-text "更新后的场景2文本" \
--output-dir public/audio/project/
# 使用不同角色重新生成 scene3
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/scenes.json \
--scene scene3 \
--character salesperson \
--output-dir public/audio/project/
# 仅重新生成(相同文本,相同角色)
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/scenes.json \
--scene scene1 \
--output-dir public/audio/project/
# 将缩略图嵌入 MP4 视频
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--embed-thumbnail public/videos/my-video.mp4 \
--thumbnail public/videos/my-thumbnail.png \
--output public/videos/my-video-with-thumb.mp4
该工具会自动:
- 使用前一个场景的请求拼接,确保一致的韵律
- 使用新的元数据更新 info.json 文件
- 如果提供了
--new-text,则更新 scenes.json
缩略图嵌入
将缩略图图像嵌入 MP4 视频,以便 Twitter、YouTube 和视频播放器等平台显示你自定义的缩略图,而不是视频的第一帧。
将缩略图嵌入视频
# 基本用法 - 输出到 video-thumb.mp4
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--embed-thumbnail public/videos/promo.mp4 \
--thumbnail public/videos/thumbnail.png
# 自定义输出路径
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--embed-thumbnail public/videos/promo.mp4 \
--thumbnail public/videos/thumbnail.png \
--output public/videos/promo-final.mp4
与 Remotion 配合使用的工作流
# 1. 渲染你的视频
npx remotion render MyVideo public/videos/my-video.mp4
# 2. 渲染你的缩略图(使用 Still composition)
npx remotion still MyVideoThumbnail public/videos/my-thumbnail.png
# 3. 嵌入缩略图
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--embed-thumbnail public/videos/my-video.mp4 \
--thumbnail public/videos/my-thumbnail.png \
--output public/videos/my-video-final.mp4
支持的格式
- 视频:MP4(H.264/H.265)
- 缩略图:PNG、JPG、JPEG
嵌入功能使用 ffmpeg 的 -disposition:v:1 attached_pic 标志将缩略图设置为附加图片,大多数视频播放器和平台都会识别。
定时验证
此技能在生成后会自动使用 ffprobe 验证定时:
检查内容
| 检查项 | 阈值 | 描述 |
|---|---|---|
| 时长不匹配 | >15% | 如果实际时长与预期不同则发出警告 |
| 开头静音 | >200ms | 音频开始延迟(画外音延迟) |
| 结尾静音 | >500ms | 末尾不必要的静音 |
| 语速 | 2-4.5 wps | 最佳约 3 字/秒 |
验证现有音频
# 验证项目中的所有场景
node .claude/skills/elevenlabs-remotion-skill/generate.js --validate public/audio/product-demo/
输出示例:
🔍 正在验证 product-demo(6 个场景)
❌ scene1:3.00秒(预期:4.5秒)
❌ 音频比预期短 1.50秒
👍 8 个单词 @ 3.1 字/秒
⚠️ scene2:6.35秒(预期:5.5秒)
⚠️ 开头静音:235 毫秒(可能开始延迟)
🐢 10 个单词 @ 1.8 字/秒
✅ scene4:4.36秒(预期:4秒)
👍 9 个单词 @ 2.3 字/秒
📊 总时长:30.80秒(预期:30.00秒)
更新后的 info.json
验证后,info.json 包含实际测量结果:
{
"scenes": [
{
"id": "scene1",
"duration": 4.5,
"actualDuration": 3.0,
"leadingSilence": 0.05,
"wordsPerSecond": 3.1
}
]
}
在你的 Remotion composition 中使用 actualDuration 实现精确同步。
选项
| 选项 | 描述 | 默认值 |
|---|---|---|
--text, -t | 要转换为语音的文本 | 必需(或 --file/--scenes) |
--file, -f | 从文件读取文本 | - |
--output, -o | 输出文件路径 | output.mp3 |
--output-dir | 场景的输出目录 | public/audio |
--voice, -v | 声音名称或 ID | George |
--model, -m | 模型 ID | eleven_multilingual_v2 |
--character, -c | 角色预设 | literal |
--scenes | 包含场景的 JSON 文件 | - |
--scene | 重新生成单个场景的 ID | - |
--new-text | 场景重新生成的新文本 | - |
--validate | 验证现有的音频目录 | - |
--skip-validation | 跳过自动验证 | false |
--embed-thumbnail | 要嵌入缩略图的视频文件 | - |
--thumbnail | 缩略图图像文件(PNG/JPG) | - |
--stability | 语音稳定性(0-1) | 因角色而异 |
--similarity | 语音相似度(0-1) | 因角色而异 |
--style | 风格夸张程度(0-1) | 因角色而异 |
--no-combined | 跳过组合文件 | false |
推荐声音
| 声音 | 风格 | 最佳用途 |
|---|---|---|
George | 温暖、迷人的英式 | 叙事、解说 |
Antoni | 专业、温暖 | 法律内容、教程 |
Arnold | 权威、深沉 | 企业、严肃话题 |
Josh | 友好、对话式 | 营销、休闲内容 |
与 Remotion 集成
生成场景画外音后,在 composition 中使用它们:
import { Audio, Sequence, staticFile } from "remotion";
// 使用单独的场景音频文件实现精确同步
const SCENE_DURATIONS = {
scene1: 4.5, // 来自 info.json
scene2: 5.5,
scene3: 8.0,
};
export const VideoWithVoiceover: React.FC = () => {
const { fps } = useVideoConfig();
const scene1Frames = Math.round(SCENE_DURATIONS.scene1 * fps);
const scene2Frames = Math.round(SCENE_DURATIONS.scene2 * fps);
return (
<>
<Sequence from={0} durationInFrames={scene1Frames}>
<Audio src={staticFile("audio/project/project-scene1.mp3")} />
<Scene1Visual />
</Sequence>
<Sequence from={scene1Frames} durationInFrames={scene2Frames}>
<Audio src={staticFile("audio/project/project-scene2.mp3")} />
<Scene2Visual />
</Sequence>
</>
);
};
获取最佳效果的技巧
- 使用角色预设:不要逐字朗读屏幕文本 - 使用
narrator或expert实现自然流畅 - 标点符号很重要:使用句号表示停顿,逗号表示短暂停顿
- 数字:为了自然发音,拼写出数字("五百" 而非 "500")
- 缩写:写出完整的单词("二十四小时" 而非 "24h")
- 逐个场景:不同的场景可以使用不同的角色(戏剧性的开场、平静的呼吁行动)
- 精细调整:使用
--scene重新生成单个场景,无需重做所有内容 - 请求拼接:确保所有场景的语音保持一致
工作流示例
# 1. 使用你的脚本创建 scenes.json
# 2. 使用叙事者风格生成所有场景
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/my-video-scenes.json \
--character narrator \
--output-dir public/audio/my-video/
# 3. 在 Remotion 中预览,发现 scene2 开始过早
# 4. 仅重新生成 scene2,并使用更新后的文本
node .claude/skills/elevenlabs-remotion-skill/generate.js \
--scenes remotion/my-video-scenes.json \
--scene scene2 \
--new-text "稍长一点的文本以填充视觉时序" \
--output-dir public/audio/my-video/
# 5. 使用 info.json 中的新时长更新视频 composition
# 6. 重复直到时序完美