关于 elevenlabs
通过 ElevenLabs API 生成和处理音频的工具包技能,涵盖语音合成、转录、声音克隆、音效和音乐。还介绍将分场旁白与 Remotion 场景同步的工作流。
主要功能
- 01使用多种模型生成语音
- 02使用 Scribe 转录音频
- 03创建即时声音克隆
- 04生成音效和音乐
- 05为 Remotion 对齐场景音频
适用场景
- 01制作带旁白的视频场景
- 02转录音频并对齐词语时间
- 03根据音频样本克隆声音
- 04生成音效或背景音乐
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ digitalsamba/ claude-code-video-toolkit --skill elevenlabs安装后在 Claude Code 中输入/elevenlabs确认已加载。
附带文件reference.md
详细介绍
ElevenLabs 音频生成
需要在 .env 中设置 ELEVENLABS_API_KEY。
文本转语音
from elevenlabs.client import ElevenLabs
from elevenlabs import save, VoiceSettings
import os
client = ElevenLabs(api_key=os.getenv("ELEVENLABS_API_KEY"))
audio = client.text_to_speech.convert(
text="Welcome to my video!",
voice_id="JBFqnCBsd6RMkjVDRZzb",
model_id="eleven_multilingual_v2",
voice_settings=VoiceSettings(
stability=0.5,
similarity_boost=0.75,
style=0.5,
speed=1.0
)
)
save(audio, "voiceover.mp3")
模型
| 模型 | 质量 | SSML 支持 | 备注 |
|---|---|---|---|
eleven_multilingual_v2 | 一致性最高 | 无 | 稳定,可用于生产环境,支持 29 种语言。Toolkit 默认模型;支持风格和语速 |
eleven_v4 | 表现力最强 | 无(音频标签、IPA) | 最新模型(发布于 2026-09-28),支持 90 多种语言,克隆准确度最高。仅支持稳定性和相似度,不支持风格或语速 |
eleven_flash_v2_5 | 良好 | <break>、<phoneme> | 速度最快、价格最低;支持暂停和发音标签 |
eleven_v3 | 表现力强 | 无 | 上一代模型——优先使用 v4 |
**选择:**追求可靠性以及风格和语速控制时,选择 multilingual_v2;追求最强表现力和克隆语音时,选择 v4(测试几次生成结果);需要 SSML 控制时,选择 flash。
已弃用:eleven_turbo_v2_5 → 使用 eleven_flash_v2_5(质量相同,延迟更低;参见已弃用模型)。Toolkit 仍接受 --model eleven_turbo_v2_5:它会输出一行警告,并改为发送 eleven_flash_v2_5。
Eleven v4
发布于 2026-09-28(更新日志,模型页面)。Toolkit 通过 Text to Dialogue API 调用 v4,并只传入一个输入(旁白语音),这是 ElevenLabs 对内容创作和长篇音频的推荐方式:
from elevenlabs import DialogueInput
audio = client.text_to_dialogue.convert(
inputs=[DialogueInput(text="[warm] Welcome to my video!", voice_id="JBFqnCBsd6RMkjVDRZzb")],
model_id="eleven_v4",
settings={"stability": 0.5, "similarity": 0.75}, # the only two settings v4 takes
)
save(audio, "voiceover.mp3")
uv run tools/voiceover.py --model eleven_v4 ...(以及redub.py --model eleven_v4)会自动执行上述操作,提示一次--style/--speed会被忽略,并在句子边界处分割每个请求中超过约 2,000 个字符的文本(这是可靠的对话长度限制)。请改用--max-wpm控制语速。client.text_to_dialogue.convert_with_timestamps(...)返回的字符对齐信息与 TTSconvert_with_timestamps相同,因此redub.py --sync可用于 v4,并会发送相同的稳定性和相似度设置。- 将
settings作为字典传入:2.69 之前版本的 SDK 会使用仅包含稳定性的模型对其进行类型标注。自 2026-09-28 起,API 会在此处读取similarity(值超出范围时会返回 422 错误)。Text to Dialogue 需要elevenlabs>=2.21。 - 使用音频标签(
[whispering]、[warm]、[sigh])和标点符号直接生成。请使用清楚描述语音的标签,因为 v4 也可能将标签解读为音效。 eleven_v4_turbo是实时版本,仅可通过 Text to Dialogue WebSocket 使用。Toolkit 不使用此版本,因为离线渲染无法从低延迟中受益。
按风格设置语音参数
| 风格 | stability | similarity | style | speed |
|---|---|---|---|---|
| 自然/专业 | 0.75-0.85 | 0.9 | 0.0-0.1 | 1.0 |
| 对话式 | 0.5-0.6 | 0.85 | 0.3-0.4 | 0.9-1.0 |
| 活力/YouTuber | 0.3-0.5 | 0.75 | 0.5-0.7 | 1.0-1.1 |
段落之间的停顿
**使用 flash 模型时:**在文本中内联使用 SSML break 标签:
...end of section. <break time="1.5s" /> Start of next...
每个 break 最长 3 秒。过多的 break 可能导致语速异常。
**使用 multilingual_v2 / v3 / v4 时:**不支持 SSML。可选方式:
- 分段(空行)——会产生约 0.3-0.5 秒的自然停顿
- v3/v4:使用
[long pause]等音频标签 - 使用 ffmpeg 后期处理:分割音频并插入静音
警告:...(省略号)不是可靠的停顿方式——它可能会被读成一个词或声音。请勿使用省略号来制造停顿。
发音控制
**语音拼写(任意模型):**按期望的发音拼写单词:
Janus→Jan-usnginx→engine-x- 使用连字符、大写字母和撇号来引导发音
SSML 音素标签(仅限 flash):
<phoneme alphabet="ipa" ph="ˈdʒeɪnəs">Janus</phoneme>
**v4 中的 IPA:**无需标签。用斜线括起 IPA,并用双引号替代原词:
The term "/ˌbaɪoʊˈkemɪstri/" refers to the study of chemical processes.
迭代工作流
- 生成 → 聆听 → 找出发音和节奏问题
- 调整:音标拼写、停顿标签、语音设置
- 重新生成。如果停顿不够精准,请使用 ffmpeg 在后期添加静音,而不是反复调整 TTS 引擎。
语音转文本(Scribe)
with open("voiceover.mp3", "rb") as f:
result = client.speech_to_text.convert(file=f, model_id="scribe_v2", tag_audio_events=False)
words = [w for w in result.words if w.type == "word"] # .text, .start, .end (seconds)
scribe_v2 是当前版本,也是工具包的默认版本。scribe_v1 已弃用,并已宣布将于 2026-07-09 移除(更新日志),但目前仍可用,因此 --stt-model scribe_v1(redub)和 --model scribe_v1(align_captions)仍会运行该版本,并显示警告。scribe_v1_experimental 是 scribe_v1 的 2025 年预览版,接受时会显示警告,并以 scribe_v2 发送。工具包在 redub.py(转录 + --sync 词语时间)和 align_captions.py 中使用 Scribe。
声音克隆
即时声音克隆
with open("sample.mp3", "rb") as f:
voice = client.voices.ivc.create(
name="My Voice",
files=[f],
remove_background_noise=True
)
print(f"Voice ID: {voice.voice_id}")
- 使用
client.voices.ivc.create()(而非client.voices.clone()) - 以二进制模式(
"rb")传入文件句柄,而非路径 - 先转换 m4a:
ffmpeg -i input.m4a -codec:a libmp3lame -qscale:a 2 output.mp3 - 使用多个样本(2-3 段音频)可提高准确度
- 保存声音 ID 以便重复使用
**专业声音克隆:**需要 Creator 计划或更高版本,以及 30 分钟以上的音频。请参阅 reference.md。
音效
每次生成最长 22 秒。
result = client.text_to_sound_effects.convert(
text="Thunder rumbling followed by heavy rain",
duration_seconds=10,
prompt_influence=0.3
)
with open("thunder.mp3", "wb") as f:
for chunk in result:
f.write(chunk)
**提示词技巧:**描述要具体——“木地板上沉重的脚步声,缓慢而稳健,并伴有吱嘎声”
音乐生成
时长为 10 秒至 5 分钟。使用 client.music.compose()(而非 .generate())。
result = client.music.compose(
prompt="Upbeat indie rock, catchy guitar riff, energetic drums, travel vlog",
music_length_ms=60000,
force_instrumental=True
)
with open("music.mp3", "wb") as f:
for chunk in result:
f.write(chunk)
**提示词结构:**流派、情绪、乐器、节奏、使用场景。生成背景音乐时,添加“no vocals”,或使用 force_instrumental=True。
Remotion 集成
完整工作流:从脚本到同步场景
VOICEOVER-SCRIPT.md → voiceover.py → public/audio/ → Remotion composition
↓ ↓ ↓ ↓
Scene narration Generate MP3 Audio files <Audio> component
with durations per scene with timing synced to scenes
步骤 1:生成每个场景的音频
使用工具包的配音工具为每个场景生成音频:
# Generate voiceover files for each scene
uv run tools/voiceover.py --scene-dir public/audio/scenes --json
# Output:
# public/audio/scenes/
# ├── scene-01-title.mp3
# ├── scene-02-problem.mp3
# ├── scene-03-solution.mp3
# └── manifest.json (durations for each file)
manifest.json 包含时间信息:
{
"scenes": [
{ "file": "scene-01-title.mp3", "duration": 4.2 },
{ "file": "scene-02-problem.mp3", "duration": 12.8 },
{ "file": "scene-03-solution.mp3", "duration": 15.3 }
],
"totalDuration": 32.3
}
步骤 2:在 Remotion 合成中使用音频
// src/Composition.tsx
import { Audio, staticFile, Series, useVideoConfig } from 'remotion';
// Import scene components
import { TitleSlide } from './scenes/TitleSlide';
import { ProblemSlide } from './scenes/ProblemSlide';
import { SolutionSlide } from './scenes/SolutionSlide';
// Scene durations (from manifest.json, converted to frames at 30fps)
const SCENE_DURATIONS = {
title: Math.ceil(4.2 * 30), // 126 frames
problem: Math.ceil(12.8 * 30), // 384 frames
solution: Math.ceil(15.3 * 30), // 459 frames
};
export const MainComposition: React.FC = () => {
return (
<>
{/* Scene sequence */}
<Series>
<Series.Sequence durationInFrames={SCENE_DURATIONS.title}>
<TitleSlide />
</Series.Sequence>
<Series.Sequence durationInFrames={SCENE_DURATIONS.problem}>
<ProblemSlide />
</Series.Sequence>
<Series.Sequence durationInFrames={SCENE_DURATIONS.solution}>
<SolutionSlide />
</Series.Sequence>
</Series>
{/* Audio track - plays continuously across all scenes */}
<Audio src={staticFile('audio/voiceover.mp3')} volume={1} />
{/* Optional: Background music at lower volume */}
<Audio src={staticFile('audio/music.mp3')} volume={0.15} />
</>
);
};
步骤 3:按场景添加音频(替代方案)
如需更精细的控制,可为每个场景单独添加音频:
// src/scenes/ProblemSlide.tsx
import { Audio, staticFile, useCurrentFrame } from 'remotion';
export const ProblemSlide: React.FC = () => {
const frame = useCurrentFrame();
return (
<div style={{ /* slide styles */ }}>
<h1>The Problem</h1>
{/* Scene content */}
{/* Audio starts when this scene starts (frame 0 of this sequence) */}
<Audio src={staticFile('audio/scenes/scene-02-problem.mp3')} />
</div>
);
};
将画面与配音同步
根据音频计算场景时长,而非反过来:
// src/config/timing.ts
import manifest from '../../public/audio/scenes/manifest.json';
const FPS = 30;
// Convert audio durations to frame counts
export const sceneDurations = manifest.scenes.reduce((acc, scene) => {
const name = scene.file.replace(/^scene-\d+-/, '').replace('.mp3', '');
acc[name] = Math.ceil(scene.duration * FPS);
return acc;
}, {} as Record<string, number>);
// Usage in composition:
// <Series.Sequence durationInFrames={sceneDurations.title}>
音频时间安排模式
import { Audio, Sequence, interpolate, useCurrentFrame } from 'remotion';
// Fade in audio
export const FadeInAudio: React.FC<{ src: string; fadeFrames?: number }> = ({
src,
fadeFrames = 30
}) => {
const frame = useCurrentFrame();
const volume = interpolate(frame, [0, fadeFrames], [0, 1], {
extrapolateRight: 'clamp',
});
return <Audio src={src} volume={volume} />;
};
// Delayed audio start
export const DelayedAudio: React.FC<{ src: string; delayFrames: number }> = ({
src,
delayFrames
}) => (
<Sequence from={delayFrames}>
<Audio src={src} />
</Sequence>
);
// Usage:
// <FadeInAudio src={staticFile('audio/music.mp3')} fadeFrames={60} />
// <DelayedAudio src={staticFile('audio/sfx/whoosh.mp3')} delayFrames={45} />
配音与演示视频同步
当场景同时包含配音和演示视频时:
import { Audio, OffthreadVideo, staticFile, useVideoConfig } from 'remotion';
export const DemoScene: React.FC = () => {
const { durationInFrames, fps } = useVideoConfig();
// Calculate playback rate to fit demo into voiceover duration
const demoDuration = 45; // seconds (original demo length)
const sceneDuration = durationInFrames / fps; // seconds (from voiceover)
const playbackRate = demoDuration / sceneDuration;
return (
<>
<OffthreadVideo
src={staticFile('demos/feature-demo.mp4')}
playbackRate={playbackRate}
/>
<Audio src={staticFile('audio/scenes/scene-04-demo.mp3')} />
</>
);
};
错误处理
import { Audio, staticFile, delayRender, continueRender } from 'remotion';
import { useEffect, useState } from 'react';
export const SafeAudio: React.FC<{ src: string }> = ({ src }) => {
const [handle] = useState(() => delayRender());
const [audioReady, setAudioReady] = useState(false);
useEffect(() => {
const audio = new window.Audio(src);
audio.oncanplaythrough = () => {
setAudioReady(true);
continueRender(handle);
};
audio.onerror = () => {
console.error(`Failed to load audio: ${src}`);
continueRender(handle); // Continue without audio rather than hang
};
}, [src, handle]);
if (!audioReady) return null;
return <Audio src={src} />;
};
工具包命令:/generate-voiceover
/generate-voiceover 命令可处理完整工作流:
/generate-voiceover
1. Reads VOICEOVER-SCRIPT.md
2. Extracts narration for each scene
3. Generates audio via ElevenLabs API
4. Saves to public/audio/scenes/
5. Creates manifest.json with durations
6. Updates project.json with timing info
常用声音
- George:
JBFqnCBsd6RMkjVDRZzb(温暖的旁白) - Rachel:
21m00Tcm4TlvDq8ikWAM(清晰的女声) - Adam:
pNInz6obpgDQGcFmaJgB(专业的男声)
列出全部声音:client.voices.get_all()
完整 API 文档请参阅 reference.md。