From bd60524fdeaff01a7ea0621f2b53d10e98b2e839 Mon Sep 17 00:00:00 2001 From: zhishi <1951671751@qq.com> Date: Fri, 1 May 2026 18:42:29 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storyboard/batchGenerateImage.ts | 39 ++++---- .../workbench/batchGenerateVideo.ts | 90 +++++++++---------- .../production/workbench/generateVideo.ts | 60 ++++++------- src/utils/ai.ts | 48 ++++++---- 4 files changed, 116 insertions(+), 121 deletions(-) diff --git a/src/routes/production/storyboard/batchGenerateImage.ts b/src/routes/production/storyboard/batchGenerateImage.ts index 80ee1df..e36160b 100644 --- a/src/routes/production/storyboard/batchGenerateImage.ts +++ b/src/routes/production/storyboard/batchGenerateImage.ts @@ -90,15 +90,15 @@ export default router.post( })), ), ); + const generateTask = async (item: (typeof storyboardData)[number]) => { const repeloadObj = { prompt: item.prompt!, size: projectSettingData?.imageQuality as "1K" | "2K" | "4K", aspectRatio: projectSettingData?.videoRatio as `${number}:${number}`, }; - - await u.Ai.Image(projectSettingData?.imageModel as `${string}:${string}`) - .run( + try { + const imageCls = await u.Ai.Image(projectSettingData?.imageModel as `${string}:${string}`).run( { referenceList: await getAssetsImageBase64(assetRecord[item.id!] || []), ...repeloadObj, @@ -109,25 +109,22 @@ export default router.post( relatedObjects: JSON.stringify(repeloadObj), projectId: projectId, }, - ) - .then(async (imageCls) => { - const savePath = `/${projectId}/assets/${scriptId}/${u.uuid()}.jpg`; - await imageCls.save(savePath); - await u.db("o_storyboard").where("id", item.id).update({ - filePath: savePath, - state: "已完成", - }); - }) - .catch(async (e) => { - await u - .db("o_storyboard") - .where("id", item.id) - .update({ - filePath: "", - reason: u.error(e).message, - state: "生成失败", - }); + ); + const savePath = `/${projectId}/assets/${scriptId}/${u.uuid()}.jpg`; + await imageCls.save(savePath); + await u.db("o_storyboard").where("id", item.id).update({ + filePath: savePath, + state: "已完成", }); + } catch (e) { + u.db("o_storyboard") + .where("id", item.id) + .update({ + filePath: "", + reason: u.error(e).message, + state: "生成失败", + }); + } }; // 按 concurrentCount 控制并发数,分批执行;跳过 shouldGenerateImage === 0 的分镜 let generateList = []; diff --git a/src/routes/production/workbench/batchGenerateVideo.ts b/src/routes/production/workbench/batchGenerateVideo.ts index d36da55..4ecd84a 100644 --- a/src/routes/production/workbench/batchGenerateVideo.ts +++ b/src/routes/production/workbench/batchGenerateVideo.ts @@ -94,55 +94,45 @@ export default router.post( ); res.status(200).send(success(tasks.map((t) => ({ videoId: t.videoId, trackId: t.trackId })))); - - // 分批执行,3个一批 - (async () => { - const batchSize = 3; - for (let i = 0; i < tasks.length; i += batchSize) { - const batch = tasks.slice(i, i + batchSize); - await Promise.all( - batch.map(async ({ videoId, videoPath, prompt, duration, images }) => { - // 调用时再转 base64 - const base64 = await Promise.all( - images.map(async (item) => { - if (!item) return null; - return { base64: await u.oss.getImageBase64(item.path), type: item.sources == "audio" ? "audio" : "image" }; - }), - ); - const relatedObjects = { projectId, videoId, scriptId, type: "视频" }; - const aiVideo = u.Ai.Video(model); - return aiVideo - .run( - { - prompt, - referenceList: base64.filter(Boolean) as ReferenceList[], - mode: modeData.length > 0 ? modeData : mode, - duration, - aspectRatio: (ratio?.videoRatio as "16:9" | "9:16") || "16:9", - resolution, - audio, - }, - { - projectId, - taskClass: "视频生成", - describe: "根据提示词生成视频", - relatedObjects: JSON.stringify(relatedObjects), - }, - ) - .then(() => aiVideo.save(videoPath)) - .then(() => u.db("o_video").where("id", videoId).update({ state: "生成成功" })) - .catch(async (error: any) => { - await u - .db("o_video") - .where("id", videoId) - .update({ - state: "生成失败", - errorReason: u.error(error).message, - }); - }); - }), - ); - } - })(); + for (const { videoId, videoPath, prompt, duration, images } of tasks) { + // 所有任务全部并发后台执行,完全不阻塞任何进程 + const base64 = await Promise.all( + images.map(async (item) => { + if (!item) return null; + return { base64: await u.oss.getImageBase64(item.path), type: item.sources == "audio" ? "audio" : "image" }; + }), + ); + const relatedObjects = { projectId, videoId, scriptId, type: "视频" }; + const aiVideo = u.Ai.Video(model); + aiVideo + .run( + { + prompt, + referenceList: base64.filter(Boolean) as ReferenceList[], + mode: modeData.length > 0 ? modeData : mode, + duration, + aspectRatio: (ratio?.videoRatio as "16:9" | "9:16") || "16:9", + resolution, + audio, + }, + { + projectId, + taskClass: "视频生成", + describe: "根据提示词生成视频", + relatedObjects: JSON.stringify(relatedObjects), + }, + ) + .then(async () => await aiVideo.save(videoPath)) + .then(async () => await u.db("o_video").where("id", videoId).update({ state: "生成成功" })) + .catch(async (error: any) => { + await u + .db("o_video") + .where("id", videoId) + .update({ + state: "生成失败", + errorReason: u.error(error).message, + }); + }); + } }, ); diff --git a/src/routes/production/workbench/generateVideo.ts b/src/routes/production/workbench/generateVideo.ts index 192451f..a297f43 100644 --- a/src/routes/production/workbench/generateVideo.ts +++ b/src/routes/production/workbench/generateVideo.ts @@ -84,37 +84,34 @@ export default router.post( videoTrackId: trackId, }); res.status(200).send(success(videoId)); - (async () => { - try { - const relatedObjects = { + const relatedObjects = { + projectId, + videoId, + scriptId, + type: "视频", + }; + const aiVideo = u.Ai.Video(model); + aiVideo + .run( + { + prompt, + referenceList: base64.filter(Boolean) as ReferenceList[], + mode: modeData.length > 0 ? modeData : mode, + duration, + aspectRatio: (ratio?.videoRatio as "16:9" | "9:16") || "16:9", + resolution, + audio, + }, + { projectId, - videoId, - scriptId, - type: "视频", - }; - const aiVideo = u.Ai.Video(model); - - console.log("%c Line:47 🍩 modeData", "background:#93c0a4", modeData); - await aiVideo.run( - { - prompt, - referenceList: base64.filter(Boolean) as ReferenceList[], - mode: modeData.length > 0 ? modeData : mode, - duration, - aspectRatio: (ratio?.videoRatio as "16:9" | "9:16") || "16:9", - resolution, - audio, - }, - { - projectId, - taskClass: "视频生成", - describe: "根据提示词生成视频", - relatedObjects: JSON.stringify(relatedObjects), - }, - ); - await aiVideo.save(videoPath); - await u.db("o_video").where("id", videoId).update({ state: "生成成功" }); - } catch (error: any) { + taskClass: "视频生成", + describe: "根据提示词生成视频", + relatedObjects: JSON.stringify(relatedObjects), + }, + ) + .then(async () => await aiVideo.save(videoPath)) + .then(async () => await u.db("o_video").where("id", videoId).update({ state: "生成成功" })) + .catch(async (error: any) => { await u .db("o_video") .where("id", videoId) @@ -122,7 +119,6 @@ export default router.post( state: "生成失败", errorReason: u.error(error).message, }); - } - })(); + }); }, ); diff --git a/src/utils/ai.ts b/src/utils/ai.ts index 6ff0548..14cc4fa 100644 --- a/src/utils/ai.ts +++ b/src/utils/ai.ts @@ -152,11 +152,12 @@ async function withTaskRecord( const taskRecord = await u.task(projectId, taskClass, model, { describe: describe, content: relatedObjects }); try { const result = await fn(modelName, false, 0); + taskRecord(1); return result; } catch (e) { taskRecord(-1, u.error(e).message); - throw e; + throw new Error(u.error(e).message); } } @@ -258,9 +259,11 @@ class AiImage { return this; }; if (taskRecord) { - return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, exec); + await withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, exec); + return this; } - return exec(modelName); + await exec(modelName); + return this; } async save(path: string) { await u.oss.writeFile(path, this.result); @@ -294,18 +297,24 @@ class AiVideo { } async run(input: VideoConfig, taskRecord?: TaskRecord) { const modelName = await resolveModelName(this.key); - const exec = async (mn: `${string}:${string}`) => { - const fn = await getVendorTemplateFn("videoRequest", mn); - await referenceList2imageBase642(mn.split(/:(.+)/)[0], input); + try { + const exec = async (mn: `${string}:${string}`) => { + const fn = await getVendorTemplateFn("videoRequest", mn); + await referenceList2imageBase642(mn.split(/:(.+)/)[0], input); - this.result = await fn(input); - if (this.result.startsWith("http")) this.result = await urlToBase64(this.result); + this.result = await fn(input); + + if (this.result.startsWith("http")) this.result = await urlToBase64(this.result); + }; + if (taskRecord) { + await withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, exec); + return this; + } + await exec(modelName); return this; - }; - if (taskRecord) { - return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, exec); + } catch (e) { + throw e; } - return exec(modelName); } async save(path: string) { await u.oss.writeFile(path, this.result); @@ -321,16 +330,19 @@ class AiAudio { async run(input: VideoConfig, taskRecord?: TaskRecord) { const modelName = await resolveModelName(this.key); const exec = async (mn: `${string}:${string}`) => { - const fn = await getVendorTemplateFn("ttsRequest", mn); - await referenceList2imageBase642(mn.split(/:(.+)/)[0], input); - this.result = await fn(input); - if (this.result.startsWith("http")) this.result = await urlToBase64(this.result); - return this; + try { + const fn = await getVendorTemplateFn("ttsRequest", mn); + await referenceList2imageBase642(mn.split(/:(.+)/)[0], input); + this.result = await fn(input); + + if (this.result.startsWith("http")) this.result = await urlToBase64(this.result); + return this; + } catch (e) {} }; if (taskRecord) { return withTaskRecord(this.key, taskRecord.taskClass, taskRecord.describe, taskRecord.relatedObjects, taskRecord.projectId, exec); } - return exec(modelName); + return await exec(modelName); } async save(path: string) { await u.oss.writeFile(path, this.result);