From f7830d862c04a1288679418c69f714b4a85dc269 Mon Sep 17 00:00:00 2001 From: zhishi <1951671751@qq.com> Date: Wed, 1 Apr 2026 02:21:29 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=A7=86=E9=A2=91=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E8=AF=8D=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/initDB.ts | 3 + .../storyboard/batchAddStoryboardInfo.ts | 61 ++++++++++++++++++- src/routes/script/extractAssets.ts | 24 ++------ src/types/database.d.ts | 12 +++- 4 files changed, 79 insertions(+), 21 deletions(-) diff --git a/src/lib/initDB.ts b/src/lib/initDB.ts index 6c30f9f..892fead 100644 --- a/src/lib/initDB.ts +++ b/src/lib/initDB.ts @@ -536,6 +536,9 @@ description: 专注于从剧本内容中提取所使用的资产(角色、场 table.integer("videoId"); table.integer("projectId"); table.integer("scriptId"); + table.text("state"); + table.text("reason"); + table.text("prompt"); table.primary(["id"]); table.unique(["id"]); }, diff --git a/src/routes/production/storyboard/batchAddStoryboardInfo.ts b/src/routes/production/storyboard/batchAddStoryboardInfo.ts index f238cd2..cd8e80b 100644 --- a/src/routes/production/storyboard/batchAddStoryboardInfo.ts +++ b/src/routes/production/storyboard/batchAddStoryboardInfo.ts @@ -72,7 +72,11 @@ export default router.post( .db("o_storyboard") .where("scriptId", scriptId) .select("id", "trackId", "prompt", "duration", "state", "scriptId", "reason", "filePath"); - if (!lastStoryboard || !lastStoryboard.length) return res.status(400).send(error("为查到分镜数据")); + if (!lastStoryboard || !lastStoryboard.length) return res.status(400).send(error("未查到分镜数据")); + batchGenerateVideoPrompts( + data.map((i: any) => i.id), + projectId, + ); const storyboardData = await Promise.all( lastStoryboard.map(async (i) => { return { @@ -91,3 +95,58 @@ export default router.post( return res.status(200).send(success(storyboardData)); }, ); + +async function batchGenerateVideoPrompts(storyboardIds: number[], projectId: number) { + const lastStoryboard = await u.db("o_storyboard").whereIn("id", storyboardIds).select("id", "trackId", "prompt"); + const allTrackIds = lastStoryboard.map((i) => i.trackId); + const storyboardPromptRecord: Record = {}; + lastStoryboard.forEach((i) => { + if (i.trackId) { + if (!storyboardPromptRecord[i.trackId]) { + storyboardPromptRecord[i.trackId] = []; + } + storyboardPromptRecord[i.trackId].push(i.prompt!); + } + }); + const projectSetting = await u.db("o_project").where("id", projectId).select("artStyle").first(); + const systemPrompt = u.getArtPrompt(projectSetting?.artStyle!, "art_storyboard_video"); + await u + .db("o_videoTrack") + .whereIn("id", allTrackIds as number[]) + .update({ + state: "生成中", + }); + for (const trackId in storyboardPromptRecord) { + const storboardPrompts = storyboardPromptRecord[trackId]; + try { + const { text } = await u.Ai.Text("universalAi").invoke({ + messages: [ + { + role: "system", + content: systemPrompt, + }, + { + role: "user", + content: `请根据我所提供的 ${storboardPrompts.length} 条分镜内容,为我生成一条视频提示词,请直接输出提示词内容,不做任何解释说明。 + 分镜内容如下: + ${storboardPrompts.map((i, index) => `${index + 1}.${i}`).join("\n")}`, + }, + ], + }); + await u.db("o_videoTrack").where("id", trackId).update({ + state: "已完成", + prompt: text, + }); + console.log("%c Line:116 🍎 text", "background:#42b983", text); + } catch (e) { + console.error("生成视频提示词失败", e); + await u + .db("o_videoTrack") + .where("id", trackId) + .update({ + state: "生成失败", + reason: u.error(e).message, + }); + } + } +} diff --git a/src/routes/script/extractAssets.ts b/src/routes/script/extractAssets.ts index 008e0af..d666584 100644 --- a/src/routes/script/extractAssets.ts +++ b/src/routes/script/extractAssets.ts @@ -58,37 +58,23 @@ export default router.post( }), async (req, res) => { const { scriptIds, projectId, groupSize = 5 } = req.body; + if (!scriptIds.length) return res.status(400).send(error("请先选择剧本")); const scripts = await u.db("o_script").whereIn("id", scriptIds); const intansce = u.Ai.Text("universalAi"); - // 查询已有的剧本-资产关联,找出已经提取过资产的剧本 - const existingScriptAssets = await u.db("o_scriptAssets").whereIn("scriptId", scriptIds).select("scriptId"); - const scriptIdsWithAssets = new Set(existingScriptAssets.map((sa: any) => sa.scriptId)); - // 构建 scriptId -> script 内容的映射 const scriptMap = new Map(scripts.map((s: o_script) => [s.id, s])); - // 过滤掉已成功提取过资产的剧本(extractState === 1 且有关联资产) - const filteredScriptIds = scriptIds.filter((id: number) => { - const script = scriptMap.get(id); - return !(script?.extractState === 1 && scriptIdsWithAssets.has(id)); - }); - const skippedCount = scriptIds.length - filteredScriptIds.length; - - if (!filteredScriptIds.length) { - return res.send(success("所有剧本已提取过资产,无需重复提取")); - } - - await u.db("o_script").whereIn("id", filteredScriptIds).update({ + await u.db("o_script").whereIn("id", scriptIds).update({ extractState: 0, }); const errors: { scriptId: number; error: string }[] = []; let successCount = 0; - // 将过滤后的 scriptIds 按 groupSize(默认5)分组,每组一起发给 AI - const scriptGroups = chunkArray(filteredScriptIds, groupSize); + // 将 scriptIds 按 groupSize(默认5)分组,每组一起发给 AI + const scriptGroups = chunkArray(scriptIds, groupSize); /** 一组剧本提取完成后统一入库并建立关联 */ async function persistGroupResult(result: GroupResult) { @@ -257,6 +243,6 @@ export default router.post( }); } - return res.send(success(skippedCount > 0 ? `开始提取资产,跳过 ${skippedCount} 个已提取的剧本` : "开始提取资产")); + return res.send(success("开始提取资产")); }, ); diff --git a/src/types/database.d.ts b/src/types/database.d.ts index 3839c18..f39f1f2 100644 --- a/src/types/database.d.ts +++ b/src/types/database.d.ts @@ -1,6 +1,12 @@ -// @db-hash ae0b5b1d792b614db036441010965ace +// @db-hash f82eb99171699f051830710c1f816b59 //该文件由脚本自动生成,请勿手动修改 +export interface _o_videoTrack_old_20260401 { + 'id'?: number; + 'projectId'?: number | null; + 'scriptId'?: number | null; + 'videoId'?: number | null; +} export interface memories { 'content': string; 'createTime': number; @@ -217,11 +223,15 @@ export interface o_video { export interface o_videoTrack { 'id'?: number; 'projectId'?: number | null; + 'prompt'?: string | null; + 'reason'?: string | null; 'scriptId'?: number | null; + 'state'?: string | null; 'videoId'?: number | null; } export interface DB { + "_o_videoTrack_old_20260401": _o_videoTrack_old_20260401; "memories": memories; "o_agentDeploy": o_agentDeploy; "o_agentWorkData": o_agentWorkData;