feat: 视频阶段诊断增强 + 新账号 product_viral_factory + 执黑先行提示词更新

- phase-videos.js: 增加 item 不符合条件时的逐项诊断日志,明确 confirmed 校验
- pipeline-utils.js: saveManifest 先直写,EPERM 时回退 tmp+rename
- 执黑先行: 分镜/图片/视频提示词完善
- 新增 product_viral_factory 账号(PPT产品宣传片方向)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
lc
2026-05-10 17:07:06 +08:00
parent 1c0703cc80
commit 2232be4eee
15 changed files with 1073 additions and 37 deletions

View File

@@ -3,6 +3,8 @@
*
* 图生视频,批量提交,生成后自动上传 OSS
* 支持 task ID 恢复:中断后重跑时优先恢复已有任务
*
* ⚠注意items 必须 confirmed=true 才能进入视频生成阶段
*/
const fs = require('fs')
@@ -27,6 +29,25 @@ async function phaseVideos(manifest, manifestPath, options) {
if (['done', 'pending', 'failed'].includes(it.status)) return true
return false
})
if (videoCandidates.length === 0) {
console.log("\n⚠ [videos] 没有符合条件的 item 进入视频生成阶段")
console.log(" manifest 中共有", manifest.items.length, "个 item逐一诊断:")
for (const it of manifest.items) {
const reasons = []
if (it.confirmed === false) reasons.push("confirmed=false")
if (!it.url) reasons.push("缺少 url图片未上传")
if (!it.videoPrompt) reasons.push("缺少 videoPrompt")
if (it.confirmed !== false && it.url && it.videoPrompt && !["done","pending","failed"].includes(it.status)) {
reasons.push("status=" + (it.status || "undefined") + "(不在 done/pending/failed 中)")
}
console.log(" - item", it.id || manifest.items.indexOf(it), ":", reasons.length > 0 ? reasons.join(", ") : "已满足全部条件(不应在此)")
}
console.log("\n 修复命令:")
console.log(" node .claude/skills/video-from-script/scripts/pipeline.js confirm --manifest", manifestPath, "--all")
console.log()
}
// 对重试 item 自动清理旧视频引用,无需 agent 手动删除
const items = []
for (const it of videoCandidates) {

View File

@@ -27,9 +27,16 @@ function loadManifest(manifestPath) {
}
function saveManifest(manifestPath, manifest) {
const tmp = manifestPath + '.tmp'
fs.writeFileSync(tmp, JSON.stringify(manifest, null, 2), 'utf-8')
fs.renameSync(tmp, manifestPath)
try {
fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8')
} catch (err) {
if (err.code === 'EPERM') {
// rename/tmp fallback on EPERM
const tmp = manifestPath + '.tmp'
fs.writeFileSync(tmp, JSON.stringify(manifest, null, 2), 'utf-8')
try { fs.renameSync(tmp, manifestPath) } catch (_) {}
}
}
}
function loadAccountConfig(accountId) {