OpenCreator 中 KrillinAI TTS 技能实战:从 SRT 字幕生成目标语言配音与配音视频
【免费下载链接】OpenCreatorFormerly KrillinAI. Open-source AI workspace for creators, powered by Codex. Create videos, images, voice, avatars, translations, and edits with Agents in one place.项目地址: https://gitcode.com/GitHub_Trending/kr/OpenCreator
导读
krillinai-tts是 OpenCreator 项目为创作者 Agent 提供的配音阶段(ttsstage)专用技能,核心能力是读取目标语言 SRT 字幕,调用已配置的 TTS 服务生成配音音频tts_final_audio.wav,并在提供原视频时进一步产出带配音的视频video_with_tts.mp4。本文以 skills/krillinai-tts/SKILL.md 为骨架,结合 KrillinAI 运行时(Go 实现)的源码与配置,完整讲解命令用法、行模式(line-mode)选择、配音参数调优、产物清单与验收方法,帮助读者掌握从字幕到成片配音的完整可复现流程。
技能定位与使用前提
krillinai-tts是一个面向 Agent 的技能文件,其 Frontmatter 声明了触发条件:
--- name: krillinai-tts description: Use when generating target-language dubbing with KrillinAI CLI from SRT subtitles, including TTS audio creation and optional dubbed video generation. ---它的适用场景非常明确:输入是已存在的 SRT 字幕(通常为翻译完成的目标语言字幕target_language_srt.srt),输出是配音音频与(可选的)配音视频。在 OpenCreator 的多阶段创作流程中,它通常位于字幕翻译(subtitlestage)之后、渲染(render-horizontal/render-vertical)之前,是"翻译字幕 → 合成人声 → 封装成片"链路中的承上启下环节。
使用该技能前有两个强制前置动作:
- 先阅读 CLI 契约:SKILL.md 明确要求先读 skills/krillinai-cli/references/cli-contract.md,其中规定了二进制位置、执行工作目录、配置文件与 JSON 行为约定。
- 确保 TTS Provider 已配置:配音能力依赖
config/config.toml中的[tts]段,未配置时 CLI 会直接报错退出(详见下文"配置 TTS Provider")。
核心命令与参数详解
SKILL.md 给出的标准调用命令如下:
(cd "$KRILLINAI_CWD" && "$KRILLINAI_CLI" tts \ --workdir "$WORKDIR" \ --input-srt "$WORKDIR/target_language_srt.srt" \ --line-mode target-only \ --video "$WORKDIR/origin_video.mp4")其中路径变量按 CLI 契约约定设置:
REPO_ROOT="$PWD" TARGET="$(node -p "process.platform + '-' + process.arch")" SUFFIX="$(node -p "process.platform === 'win32' ? '.exe' : ''")" KRILLINAI_CLI="$REPO_ROOT/.runtime/build/krillinai/$TARGET/bin/krillinai-cli$SUFFIX" KRILLINAI_CWD="$REPO_ROOT/runtime/krillinai" WORKDIR="$REPO_ROOT/tasks/demo" test -f "$KRILLINAI_CLI" mkdir -p "$WORKDIR"构建脚本pnpm krillinai:build会编译 cmd/cli 与cmd/server两个入口,并把原生二进制与 manifest 写入.runtime/build/krillinai/<platform>-<arch>/目录。契约文档特别强调:执行工作目录($KRILLINAI_CWD)必须是 CLI 加载config/config.toml的基准,当改变进程工作目录时必须使用绝对路径传入--workdir、输入、字幕、音频与输出路径。
关键 Flag 一览
SKILL.md 将tts阶段的可配置 Flag 整理为下表,本文补充了类型与行为说明:
| Flag | 用途 | 补充说明 |
|---|---|---|
--workdir | 任务工作目录,存放输入与产物 | 必填;manfiest 与中间产物(如dubbing/目录)都写入此处 |
--input-srt | 待合成的 SRT 字幕 | 必填;通常用target_language_srt.srt;pipeline/tts.go 显示缺省时会回退到 manifest 中的target_srt路径 |
--line-mode target-only | 仅使用目标语言行 | 默认值;GenerateTTS中req.LineMode == ""时自动设为target-only |
--line-mode bilingual-target-top | 双语模式,目标语言在上 | 非 target-only 时会先通过ExtractTargetSRT抽取目标语言行生成tts_input.srt再合成 |
--line-mode bilingual-target-bottom | 双语模式,目标语言在下 | 同上 |
--voice | Provider 特定音色编码 | 例如阿里云/OpenAI/MiniMax 的 voice code;可通过voices命令枚举 |
--voice-clone-source | 音色克隆源音频 URL/路径 | 受 Provider 支持时生效;对应源码中的VoiceCloneAudioUrl |
--video | 原视频路径 | 可选;提供时才产出video_with_tts.mp4,见 srt2speech.go 的VideoWithTtsFilePath逻辑 |
--dry-run | 仅校验命令形态 | 不消耗 Provider 配额;tts的 dry-run 会应用默认输出并写入krillinai_manifest.json,但不产生媒体 |
行模式(line-mode)背后的实现
当--line-mode为bilingual-target-top或bilingual-target-bottom时,CLI 并不会把双语字幕原样交给 TTS,而是先执行抽取逻辑(pipeline/tts.go):
if req.LineMode != LineModeTargetOnly { ttsSource = filepath.Join(req.Workdir, ttsInputFileName) if err := ExtractTargetSRT(inputSRT, ttsSource, req.LineMode); err != nil { return failTTSStage(req, manifest, "extract_tts_input_failed", err) } }即从双语 SRT 中按行模式剥离出目标语言文本(tts_input.srt),再以该文件作为 TTS 的输入。这意味着无论选择哪种行模式,最终合成的人声都只对应目标语言内容,双语模式的意义在于保留时间轴与画面排版信息,供后续渲染阶段使用。
音色与克隆(voice / voice-clone-source)
--voice与--voice-clone-source在源码中分别映射为TtsVoiceCode与VoiceCloneAudioUrl(见 internal/pipeline/tts.go)。最终决策逻辑位于 srt2speech.go:
func resolveDubbingVoiceCode(baseVoice, cloneURL string, clone voiceCloneFunc) (string, error) { if cloneURL == "" { return baseVoice, nil } if clone == nil { return "", fmt.Errorf("srtFileToSpeech CosyVoiceClone error: voice clone client is nil") } code, err := clone("krillinai", cloneURL) ... }规则可以概括为:
- 未提供克隆源:直接使用
--voice指定的 Provider 音色编码; - 提供克隆源但客户端未初始化:返回
CosyVoiceClone error错误(属于"配置不完整",需检查 Provider 依赖); - 两者都可用:先调用克隆接口获取临时音色编码,再以该编码合成。
配置 TTS Provider
TTS 是tts阶段唯一的强外部依赖,Provider 必须在<execution-cwd>/config/config.toml中配置。以仓库根目录 runtime/krillinai/config/config-example.toml 为模板,[tts]段完整示例:
[tts] provider = "aliyun" # 可选值:openai,aliyun,edge-tts,minimax [tts.openai] base_url = "" api_key = "" model = "" # gpt-4o-mini-tts, tts-1, tts-1-hd [tts.minimax] # MiniMax TTS(T2A v2),provider选minimax时填写 base_url = "" # 留空默认海外版 https://api.minimax.io,国内可填 https://api.minimaxi.com api_key = "" # MiniMax API密钥 model = "" # 留空默认 speech-2.8-hd,可选 speech-2.8-turbo, speech-2.6-hd, speech-2.6-turbo [tts.aliyun] # 阿里云百炼语音合成,仅 API Key 必填 base_url = "https://dashscope.aliyuncs.com/api/v1" api_key = "" model = "qwen3-tts-flash"要点归纳:
provider支持openai、aliyun、edge-tts、minimax四类,不同 Provider 对应不同的子表字段;- 阿里云百炼方案仅 API Key 必填,默认模型为
qwen3-tts-flash; - MiniMax 留空
base_url时走海外版https://api.minimax.io,国内可填https://api.minimaxi.com,默认模型speech-2.8-hd,可选speech-2.8-turbo、speech-2.6-hd、speech-2.6-turbo; - OpenAI 兼容方案支持
gpt-4o-mini-tts、tts-1、tts-1-hd等模型。
从 cmd/cli/main.go 可以看到tts命令的启动检查顺序:先config.ValidateTTSConfig()(校验 Provider 配置,失败为 usage 错误),再deps.CheckTTSDependency()(校验 ffmpeg 等运行时依赖,失败为 dependency 错误)。因此配置缺失会在第一时间暴露,而不是在合成中途失败。
配音(dubbing)调优参数
除 Provider 外,[dubbing]段直接控制配音质量与节奏,且与 dubbing/types.go 中的DefaultConfig()一一对应:
| 配置项 | 默认值 | 含义 |
|---|---|---|
min_subtitle_duration | 2.5 | 最短配音字幕时长(秒),过短的句子会优先合并 |
max_chunk_size | 5 | 单个配音 chunk 最多合并的字幕条数 |
gap_tolerance | 1.5 | 可吸收的相邻字幕空隙(秒) |
speed_min | 0.95 | 允许的最慢调速倍率 |
speed_accept | 1.15 | 推荐的最大自然调速倍率 |
speed_max | 1.30 | 调速硬上限,超过后优先改写文本 |
enable_text_rewrite | true | 是否允许 LLM 将字幕改写为自然口播 |
rewrite_max_attempts | 2 | 单条字幕最多改写次数 |
estimator | statistical | 时长估时器,当前仅支持statistical |
这些参数在 srt2speech.go 中被注入dubbing.Runner,并由 Planner 消费(planner.go):当字幕的预估朗读时长超过"原始时长 + gap_tolerance",且允许文本改写时,LLM 优化器会尝试把字幕改写得更口语化以适配时间轴;分句与合并则由max_chunk_size、min_subtitle_duration与gap_tolerance共同决定。
产出与产物清单
tts阶段的输出路径统一记录在任务工作目录的krillinai_manifest.json中,SKILL.md 要求"从 manifest 读取路径",而不是硬编码猜测。两个核心产物:
tts_final_audio.wav:最终合成配音音频(对应 manifest 输出键tts_audio);video_with_tts.mp4:仅当提供了视频输入时产出(对应video_with_tts)。
契约文档给出了 manifest 中与本阶段相关的默认路径映射:
| Output key | 默认路径 |
|---|---|
tts_audio | <workdir>/tts_final_audio.wav |
video_with_tts | <workdir>/video_with_tts.mp4 |
target_srt | <workdir>/target_language_srt.srt |
origin_video | <workdir>/origin_video.mp4 |
内部流水线:从 SRT 到 WAV
理解产物形态有助于排障。srtFileToSpeech将参数组装为dubbing.Runner(runner.go)后执行以下步骤:
- 解析并清洗 SRT(
cleanCuesForSpeech); - Planner 估算每句时长、合并 chunk、必要时改写文本;
- 逐 chunk 调用 TTS 生成
raw/chunk_N.wav(纯静音文本直接写入静音片段,见 tts.go),单条失败自动重试 3 次(retryTTS); - 用统计估时器 + 测得的真实时长做时间轴拟合(
FitTimeline); - 通过 ffmpeg 拼接所有 chunk 得到
tts_final_audio.wav,再与原视频 mux 得到video_with_tts.mp4。
中间产物会落在<workdir>/dubbing/目录:dubbing_input.srt(清洗后字幕)、dubbing_plan.json(时间轴计划)、dubbing_report.json(警告、失败索引、最大倍速、改写次数)、dub.srt(配音字幕)。这些文件对排查"某句读快了/读慢了"非常有用。
验收标准与错误处理
SKILL.md 规定tts阶段完成后必须执行以下验收:
- 终端 JSON 必须为成功形态:解析 stdout 逐行 JSON,最后一条对象须满足
"ok": true; - 音频文件非空:确认
tts_final_audio.wav存在且大小非零(源码中ensureNonEmptyFile正是这个检查的 Go 实现); - 视频流校验:若产出
video_with_tts.mp4,用ffprobe检查时长与音频流:ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$WORKDIR/video_with_tts.mp4" ffprobe -v error -select_streams a -show_entries stream=codec_type -of csv=p=0 "$WORKDIR/video_with_tts.mp4" - JSON/错误契约:完整契约见 skills/krillinai-cli/references/cli-contract.md。
错误分类与退出码
CLI 契约定义如下错误分类,tts阶段应据此处置:
| 退出码 | 含义 | 对应处理 |
|---|---|---|
0 | 成功 | 进入产物验收 |
1 | 用法错误(usage) | 修正 Flag 或缺失输入 |
2 | 可重试错误(retryable) | 延迟后重试,或更换 Provider/源 |
3 | 依赖错误(dependency) | 安装/暴露ffmpeg、ffprobe、yt-dlp |
失败 JSON 的典型形态:
{ "ok": false, "error": { "kind": "retryable", "code": "audio_transcription_failed", "message": "connection timeout", "retryable": true } }需要注意:内部错误当前也可能以退出码 1 结束,因此分类时应以error.kind为准,而不是只看退出码(cli-contract.md 中明确提示)。tts阶段的失败分支会将 manifest 中的tts阶段标记为失败并保存(pipeline/tts.go),便于后续审计。
进度上报与长任务观察
当环境变量OPENCREATOR_KRILLINAI_CLI=1时,tts会像subtitle一样在终端响应前输出进度帧(cmd/cli/main.go):
{"type":"progress","phase":"generating_voice","percent":42,"message":"正在生成配音"}进度百分比由 dubbing runner 的ReportProgress回调映射到 20%~90% 区间(srt2speech.go),配合preparing_voice、collecting_outputs等 phase 值,可以在长任务中实时观测阶段推进,而不是干等最终 JSON。
与 CLI 其他命令的衔接
tts是 KrillinAI CLI 八大命令之一(cli-contract.md):
| 命令 | 用途 |
|---|---|
subtitle | 生成源语言/目标语言/双语/短竖屏字幕 |
tts | 生成 TTS 音频与可选配音视频(本文主题) |
speech | 从文本或 UTF-8 文本文件生成单个音频文件 |
render-horizontal/render-vertical | 渲染横屏/竖屏字幕或配音视频 |
cover | 根据完整文本提示生成封面图 |
voices | 列出aliyun/openai/minimax的音色编码(Edge TTS 无 CLI 音色目录) |
pipeline | 以--dry-run校验输出计划 |
典型链路是:subtitle(含翻译)→tts(配音)→render-horizontal/render-vertical(封装渲染)。执行tts前如需确认音色编码,可先运行voices --dry-run——它返回本地音色列表而不发起外部调用,且subtitle、render-*、speech、pipeline的 dry-run 都不会写任务 manifest,可以安全地用于命令形态自检。
常见问题速查
- 报
config_not_found或usage错误:config/config.toml缺失或[tts]未配置。按 config-example.toml 复制并填入对应 Provider 的 API Key;注意 CLI 以进程工作目录为基准加载配置。 video_with_tts.mp4没有产出:确认是否传入--video;源码中InputVideo为必填项,dubbing runner 的validate()会直接拒绝空视频路径。- 某句配音时间轴对不上:查看
<workdir>/dubbing/dubbing_report.json中的max_speed_factor、rewrite_count、warnings,并检查[dubbing]中speed_*、enable_text_rewrite、min_subtitle_duration等参数。 - 退出码 3(dependency):
ffmpeg/ffprobe不可用,安装并确保在 PATH 中后再重试。 - 长任务无输出:确认设置了
OPENCREATOR_KRILLINAI_CLI=1,否则 CLI 只会在结束时输出最终 JSON。
【免费下载链接】OpenCreatorFormerly KrillinAI. Open-source AI workspace for creators, powered by Codex. Create videos, images, voice, avatars, translations, and edits with Agents in one place.项目地址: https://gitcode.com/GitHub_Trending/kr/OpenCreator
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考