feat(video-from-script): 批量生产元数据增强 — 选题/转发文案/草稿命名/导出/草稿箱改名
- batch-pipeline.js: 新增 mark 元数据字段(topicA/B, draftName, forwardCopy, hashtags) - batch-pipeline.js: 新增 export 命令导出 CSV/XLSX 最终表格 - batch-pipeline.js: 新增 rename-drafts 命令批量重命名剪映草稿(Mac 直接 mv 文件夹) - batch-pipeline.js: 完善 displayTitle 向后兼容旧 topic 字段 - lib/phase-tts: 增强 TTS 生成稳定性 - lib/phase-videos: 视频生成优化 - lib/video-poll-utils: 提取轮询重试共享工具 - CLAUDE.md: 补充批量生产选题/转发文案/草稿命名/导出/草稿箱改名文档 - 执黑先行 account.json: 配置更新 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -119,14 +119,32 @@ async function phaseTts(manifest, manifestPath, options = {}) {
|
||||
const segInput = rawSegments[j]
|
||||
const segId = `${item.id}_${j + 1}`
|
||||
|
||||
try {
|
||||
const { filePath, duration: realDuration } = await synthesize(segInput.text, {
|
||||
outputDir: audioDir,
|
||||
id: segId,
|
||||
voice: manifest.ttsVoice || undefined,
|
||||
instruction: manifest.ttsInstruction || undefined,
|
||||
rate: ttsRate,
|
||||
})
|
||||
// 带重试的合成(最多3次,指数退避)
|
||||
let synthResult = null
|
||||
let lastErr = null
|
||||
for (let retry = 0; retry < 3; retry++) {
|
||||
try {
|
||||
synthResult = await synthesize(segInput.text, {
|
||||
outputDir: audioDir,
|
||||
id: segId,
|
||||
voice: manifest.ttsVoice || undefined,
|
||||
model: manifest.ttsModel || undefined,
|
||||
instruction: manifest.ttsInstruction || undefined,
|
||||
rate: ttsRate,
|
||||
})
|
||||
break
|
||||
} catch (e) {
|
||||
lastErr = e
|
||||
if (retry < 2) {
|
||||
const delay = Math.pow(2, retry) * 3000
|
||||
log('tts', `[${idx}/${items.length}] 段${j + 1} 重试 ${retry + 1}/3, ${delay / 1000}s 后重试...`)
|
||||
await new Promise(r => setTimeout(r, delay))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (synthResult) {
|
||||
const { filePath, duration: realDuration } = synthResult
|
||||
|
||||
const segment = {
|
||||
id: segId,
|
||||
@@ -140,8 +158,8 @@ async function phaseTts(manifest, manifestPath, options = {}) {
|
||||
globalOffset += realDuration
|
||||
|
||||
log('tts', `[${idx}/${items.length}] 段${j + 1}: 估算${segInput.estimatedDuration.toFixed(2)}s → 实测${realDuration.toFixed(2)}s | ${segInput.text.slice(0, 15)}...`)
|
||||
} catch (err) {
|
||||
log('tts', `[${idx}/${items.length}] 段${j + 1} 合成失败: ${err.message}`)
|
||||
} else {
|
||||
log('tts', `[${idx}/${items.length}] 段${j + 1} 合成失败(重试3次后): ${lastErr?.message || '未知错误'}`)
|
||||
segments.push({
|
||||
id: segId,
|
||||
text: segInput.text,
|
||||
@@ -149,7 +167,7 @@ async function phaseTts(manifest, manifestPath, options = {}) {
|
||||
estimatedDuration: segInput.estimatedDuration,
|
||||
duration: 0,
|
||||
startOffset: globalOffset,
|
||||
error: err.message,
|
||||
error: lastErr?.message || '未知错误',
|
||||
})
|
||||
globalOffset += segInput.estimatedDuration
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user