126 lines
3.7 KiB
TypeScript

import express from "express";
import u from "@/utils";
import { z } from "zod";
import { v4 as uuidv4 } from "uuid";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
type Type = "imageReference" | "startImage" | "endImage" | "videoReference" | "audioReference";
interface UploadItem {
fileType: "image" | "video" | "audio";
type: Type;
sources?: "assets" | "storyboard";
id?: number;
src?: string;
label?: string;
prompt?: string;
}
export default router.post(
"/",
validateFields({
projectId: z.number(),
scriptId: z.number(),
uploadData: z.array(
z.object({
id: z.number(),
sources: z.string(),
}),
),
prompt: z.string(),
model: z.string(),
mode: z.string(),
resolution: z.string(),
duration: z.number(),
audio: z.boolean().optional(),
trackId: z.number(),
}),
async (req, res) => {
const { scriptId, projectId, prompt, uploadData, model, duration, resolution, audio, mode, trackId } = req.body;
let modeData = [];
if (Array.isArray(mode)) {
} else if (typeof mode === "string" && mode.startsWith('["') && mode.endsWith('"]')) {
try {
modeData = JSON.parse(mode);
} catch (e) {}
}
//获取生成视频比例
const ratio = await u.db("o_project").select("videoRatio").where("id", projectId).first();
const videoPath = `/${projectId}/video/${uuidv4()}.mp4`; //视频保存路径
//查询出图片数据
const images = await Promise.all(
uploadData.map(async (item: UploadItem) => {
if (item.sources === "storyboard") {
const filePath = await u.db("o_storyboard").where("id", item.id).select("filePath").first();
return filePath?.filePath;
}
if (item.sources === "assets") {
const filePath = await u
.db("o_assets")
.where("o_assets.id", item.id)
.leftJoin("o_image", "o_assets.imageId", "o_image.id")
.select("o_image.filePath")
.first();
return filePath?.filePath;
}
}),
);
//把images里面的图片转成base64格式
const base64 = await Promise.all(
images.map(async (item) => {
if (!item) return null;
return await u.oss.getImageBase64(item);
}),
);
//新增
const [videoId] = await u.db("o_video").insert({
filePath: videoPath,
time: Date.now(),
state: "生成中",
scriptId,
projectId,
videoTrackId: trackId,
});
res.status(200).send(success(videoId));
(async () => {
try {
const relatedObjects = {
projectId,
videoId,
scriptId,
type: "视频",
};
const aiVideo = u.Ai.Video(model);
await aiVideo.run(
{
prompt,
imageBase64: base64.filter((item) => item !== null) as string[],
mode: modeData.length > 0 ? modeData : mode,
duration,
aspectRatio: (ratio?.videoRatio as `${number}:${number}`) || "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) {
await u
.db("o_video")
.where("id", videoId)
.update({
state: "生成失败",
errorReason: error instanceof Error ? error.message : "未知错误",
});
}
})();
},
);