refactor(video-from-script): 提取轮询重试逻辑为共享工具

提取三个视频生成器中重复的 `pollWithRetry` 函数到共享模块 `video-poll-utils`,消除代码重复。新增两层重试机制:轮询级(处理网络瞬断)和任务级(创建新任务 + 提示词优化)。同时优化 `phase-videos` 中视频状态管理和 manifest 保存逻辑。
This commit is contained in:
2026-05-12 01:24:55 +08:00
parent 7b743dc701
commit 06f44ddafa
5 changed files with 132 additions and 152 deletions

View File

@@ -402,57 +402,28 @@ async function batchGenerate(tasks, options = {}) {
return results
}
/**
* 轮询 + 失败重试(单任务)
*/
const { makePollWithRetry } = require('./lib/video-poll-utils')
const pollWithRetryBase = makePollWithRetry({
Api: GrokApi,
suffix: '_grok',
duration: 6,
maxRetries: Config.maxRetries,
optimizePrompt: (prompt, failReason, attempt) => PromptOptimizer.optimize(prompt, failReason, attempt),
buildCreateOpts: (options) => ({ aspectRatio: options.aspectRatio, size: options.size }),
})
async function pollWithRetry(taskId, prompt, options = {}) {
let currentTaskId = taskId
let currentPrompt = prompt
let lastError = null
const result = await pollWithRetryBase(taskId, prompt, options)
for (let attempt = 0; attempt <= Config.maxRetries; attempt++) {
try {
if (attempt > 0) {
currentPrompt = PromptOptimizer.optimize(prompt, lastError, attempt)
console.log(`\n 🔄 重试 (任务 ${currentTaskId.substring(0, 8)}...): ${currentPrompt.substring(0, 50)}`)
currentTaskId = await GrokApi.create(
options.imageUrl || '',
currentPrompt,
{ aspectRatio: options.aspectRatio, size: options.size }
)
}
const result = await GrokApi.poll(currentTaskId)
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
const videoFile = path.join(options.outputDir || './output', `${timestamp}_grok.mp4`)
await download(result.videoUrl, videoFile)
let thumbnailFile = null
if (result.thumbnailUrl) {
thumbnailFile = path.join(options.outputDir || './output', `${timestamp}_thumb.jpg`)
try { await download(result.thumbnailUrl, thumbnailFile) } catch (_) {}
}
return {
taskId: currentTaskId,
prompt: currentPrompt,
originalPrompt: prompt,
attempts: attempt + 1,
file: videoFile,
files: [videoFile],
duration: 6,
thumbnail: thumbnailFile,
}
} catch (err) {
lastError = err.message
if (attempt < Config.maxRetries) {
await new Promise(r => setTimeout(r, 5000))
}
}
let thumbnailFile = null
if (result.thumbnailUrl) {
const timestamp = new Date().toISOString().replace(/[:.]/g, '-')
thumbnailFile = path.join(options.outputDir || './output', `${timestamp}_thumb.jpg`)
try { await download(result.thumbnailUrl, thumbnailFile) } catch (_) {}
}
throw new Error(`重试 ${Config.maxRetries} 次后仍失败: ${lastError}`)
return { ...result, thumbnail: thumbnailFile }
}
// ============================================================================