refactor(video-from-script): 提取轮询重试逻辑为共享工具
提取三个视频生成器中重复的 `pollWithRetry` 函数到共享模块 `video-poll-utils`,消除代码重复。新增两层重试机制:轮询级(处理网络瞬断)和任务级(创建新任务 + 提示词优化)。同时优化 `phase-videos` 中视频状态管理和 manifest 保存逻辑。
This commit is contained in:
@@ -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 }
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user