/** * Phase: assemble — CapCut 成片组装 * * 图片/视频 + TTS → 剪映草稿 */ const { log, getManifestDir } = require('./pipeline-utils') async function phaseAssemble(manifest, manifestPath, options) { const dir = getManifestDir(manifestPath) const accountConfig = options.accountConfig || {} const capcutConfig = accountConfig.capcut || {} const videoItems = manifest.items.filter(it => it.video && it.status === 'done') const hasVideos = videoItems.length > 0 const mode = hasVideos ? 'videos' : 'images' const assembleArgs = { input: dir, manifest: manifestPath, mode, format: manifest.format || accountConfig.defaultFormat || '9:16', subtitles: mode === 'images' ? 'true' : 'false', voiceover: manifest.items.some(it => it.audio) ? 'true' : 'false', duration: '4', animation: capcutConfig.animation || 'kenburns-zoom', } if (capcutConfig.defaultBGM) assembleArgs.bgm = capcutConfig.defaultBGM if (capcutConfig.effects) assembleArgs.effects = capcutConfig.effects.join(',') if (capcutConfig.filter) assembleArgs.filter = capcutConfig.filter log('assemble', `模式: ${mode}, 字幕: true, 配音: ${assembleArgs.voiceover}, 动画: ${assembleArgs.animation}`) try { const { assemble } = require('../capcut_assemble') await assemble(assembleArgs) log('assemble', '成片完成') } catch (err) { log('assemble', `成片失败: ${err.message}`) throw err } } module.exports = { phaseAssemble }