修改生成视频api和生成视频提示词api

This commit is contained in:
小帅 2026-03-31 19:01:05 +08:00
parent 36d985b23d
commit e4ba419f44
7 changed files with 72 additions and 175 deletions

View File

@ -527,27 +527,20 @@ description: 专注于从剧本内容中提取所使用的资产(角色、场
table.integer("time"); table.integer("time");
table.text("state"); table.text("state");
table.integer("scriptId"); table.integer("scriptId");
table.integer("storyboardId");
table.integer("projectId"); table.integer("projectId");
table.integer("videoTrackId");
table.primary(["id"]); table.primary(["id"]);
table.unique(["id"]); table.unique(["id"]);
}, },
}, },
// 视频轨道
{ {
name: "o_videoConfig", name: "o_videoTrack",
builder: (table) => { builder: (table) => {
table.integer("id").notNullable(); table.integer("id").notNullable();
table.integer("storyboardId");
table.integer("videoId"); table.integer("videoId");
table.integer("audio"); // 声音 table.integer("projectId");
table.text("model"); // 模型 table.integer("scriptId");
table.text("mode"); // 模式:
table.text("data"); // 所选数据集图片 JSON
table.text("resolution"); // 分辨率
table.integer("duration"); // 时长
table.text("prompt"); // 提示词
table.integer("createTime"); // 创建时间
table.integer("updateTime"); // 更新时间
table.primary(["id"]); table.primary(["id"]);
table.unique(["id"]); table.unique(["id"]);
}, },

View File

@ -1,4 +1,4 @@
// @routes-hash 8b0a09b55cd1b98ff83ad988d077fee3 // @routes-hash 4bd2ce809f84bc7049bfcf3accb58805
import { Express } from "express"; import { Express } from "express";
import route1 from "./routes/agents/clearMemory"; import route1 from "./routes/agents/clearMemory";
@ -65,11 +65,11 @@ import route61 from "./routes/production/storyboard/getStoryboardData";
import route62 from "./routes/production/storyboard/pollingImage"; import route62 from "./routes/production/storyboard/pollingImage";
import route63 from "./routes/production/storyboard/previewImage"; import route63 from "./routes/production/storyboard/previewImage";
import route64 from "./routes/production/storyboard/removeFrame"; import route64 from "./routes/production/storyboard/removeFrame";
import route65 from "./routes/production/workbench/confirmSelection"; import route65 from "./routes/production/workbench/addTrack";
import route66 from "./routes/production/workbench/delVideo"; import route66 from "./routes/production/workbench/confirmSelection";
import route67 from "./routes/production/workbench/generateVideo"; import route67 from "./routes/production/workbench/delVideo";
import route68 from "./routes/production/workbench/generateVideoPrompt"; import route68 from "./routes/production/workbench/generateVideo";
import route69 from "./routes/production/workbench/getChatLines"; import route69 from "./routes/production/workbench/generateVideoPrompt";
import route70 from "./routes/production/workbench/getVideoModelDetail"; import route70 from "./routes/production/workbench/getVideoModelDetail";
import route71 from "./routes/production/workbench/videoPolling"; import route71 from "./routes/production/workbench/videoPolling";
import route72 from "./routes/project/addProject"; import route72 from "./routes/project/addProject";
@ -189,11 +189,11 @@ export default async (app: Express) => {
app.use("/api/production/storyboard/pollingImage", route62); app.use("/api/production/storyboard/pollingImage", route62);
app.use("/api/production/storyboard/previewImage", route63); app.use("/api/production/storyboard/previewImage", route63);
app.use("/api/production/storyboard/removeFrame", route64); app.use("/api/production/storyboard/removeFrame", route64);
app.use("/api/production/workbench/confirmSelection", route65); app.use("/api/production/workbench/addTrack", route65);
app.use("/api/production/workbench/delVideo", route66); app.use("/api/production/workbench/confirmSelection", route66);
app.use("/api/production/workbench/generateVideo", route67); app.use("/api/production/workbench/delVideo", route67);
app.use("/api/production/workbench/generateVideoPrompt", route68); app.use("/api/production/workbench/generateVideo", route68);
app.use("/api/production/workbench/getChatLines", route69); app.use("/api/production/workbench/generateVideoPrompt", route69);
app.use("/api/production/workbench/getVideoModelDetail", route70); app.use("/api/production/workbench/getVideoModelDetail", route70);
app.use("/api/production/workbench/videoPolling", route71); app.use("/api/production/workbench/videoPolling", route71);
app.use("/api/project/addProject", route72); app.use("/api/project/addProject", route72);

View File

@ -0,0 +1,21 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
export default router.post(
"/",
validateFields({
projectId: z.number(),
scriptId: z.number(),
}),
async (req, res) => {
const { projectId, scriptId } = req.body;
const [id] = await u.db("o_videoTrack").insert({
projectId,
scriptId,
});
res.status(200).send(success(id));
},
);

View File

@ -5,30 +5,26 @@ import { v4 as uuidv4 } from "uuid";
import { success } from "@/lib/responseFormat"; import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware"; import { validateFields } from "@/middleware/middleware";
const router = express.Router(); const router = express.Router();
export default router.post( export default router.post(
"/", "/",
validateFields({ validateFields({
scriptId: z.number(),
projectId: z.number(), projectId: z.number(),
storyboardId: z.number(), scriptId: z.number(),
uploadData: z.array(
z.object({
id: z.number(),
type: z.string(),
}),
),
prompt: z.string(), prompt: z.string(),
data: z
.array(
z.object({
id: z.number(),
type: z.string(),
}),
)
.optional(),
model: z.string(), model: z.string(),
duration: z.number(),
resolution: z.string(),
audio: z.boolean().optional(),
mode: z.string(), mode: z.string(),
resolution: z.string(),
duration: z.number(),
audio: z.boolean().optional(),
}), }),
async (req, res) => { async (req, res) => {
const { scriptId, projectId, storyboardId, prompt, data, model, duration, resolution, audio, mode } = req.body; const { scriptId, projectId, prompt, uploadData, model, duration, resolution, audio, mode } = req.body;
//获取生成视频比例 //获取生成视频比例
const ratio = await u.db("o_project").select("videoRatio").where("id", projectId).first(); const ratio = await u.db("o_project").select("videoRatio").where("id", projectId).first();
const videoPath = `/${projectId}/video/${uuidv4()}.mp4`; //视频保存路径 const videoPath = `/${projectId}/video/${uuidv4()}.mp4`; //视频保存路径
@ -38,35 +34,12 @@ export default router.post(
time: Date.now(), time: Date.now(),
state: "生成中", state: "生成中",
scriptId, scriptId,
storyboardId,
projectId, projectId,
}; };
const [videoId] = await u.db("o_video").insert(videoData); const [videoId] = await u.db("o_video").insert(videoData);
//查询分镜是否已有配置
const config = await u.db("o_videoConfig").where({ storyboardId }).first();
//保存配置
if (config) {
await u
.db("o_videoConfig")
.update({ audio, model, mode, data: JSON.stringify(data), resolution, duration, prompt, updateTime: Date.now() })
.where({ id: config.id });
} else {
await u.db("o_videoConfig").insert({
storyboardId,
audio,
model,
mode,
data: JSON.stringify(data),
resolution,
duration,
prompt,
createTime: Date.now(),
updateTime: Date.now(),
});
}
//查询出图片数据 //查询出图片数据
const images = await Promise.all( const images = await Promise.all(
data.map(async (item: { id: number; type: string }) => { uploadData.map(async (item: { id: number; type: string }) => {
if (item.type === "storyboard") { if (item.type === "storyboard") {
const filePath = await u.db("o_storyboard").where("id", item.id).select("filePath").first(); const filePath = await u.db("o_storyboard").where("id", item.id).select("filePath").first();
return filePath?.filePath; return filePath?.filePath;
@ -93,17 +66,11 @@ export default router.post(
(async () => { (async () => {
try { try {
const relatedObjects = { const relatedObjects = {
id: storyboardId,
projectId, projectId,
videoId,
scriptId,
type: "视频", type: "视频",
}; };
const systemPrompt = `你是一个专业的视频生成引擎,能够根据用户提供的提示词、图片和参数生成高质量的视频内容。请严格按照用户的需求进行视频创作,确保输出的视频符合以下要求:
1.
2.
3.
4.
5. `;
const aiVideo = u.Ai.Video(model); const aiVideo = u.Ai.Video(model);
await aiVideo.run( await aiVideo.run(
{ {
@ -124,7 +91,6 @@ export default router.post(
); );
await aiVideo.save(videoPath); await aiVideo.save(videoPath);
await u.db("o_video").where("id", videoId).update({ state: "生成成功" }); await u.db("o_video").where("id", videoId).update({ state: "生成成功" });
// await u.db("o_videoConfig").where("storyboardId", storyboardId).update({ videoId, updateTime: Date.now() });
} catch (error: any) { } catch (error: any) {
await u await u
.db("o_video") .db("o_video")

View File

@ -9,49 +9,24 @@ export default router.post(
"/", "/",
validateFields({ validateFields({
projectId: z.number(), projectId: z.number(),
storyboardId: z.number(), prompt: z.array(z.string()),
model: z.string(),
}), }),
async (req, res) => { async (req, res) => {
const { projectId, storyboardId } = req.body; const { projectId, prompt, model } = req.body;
const [id, modelData] = model.split(":");
// 查询分镜及其关联的资产提示词 const projectData = await u.db("o_project").select("*").where({ id: projectId }).first();
const data = await u const artStyle = projectData?.artStyle || "无";
.db("o_storyboard") const visualManual = await u.getArtPrompt(artStyle, "art_storyboard_video");
.leftJoin("o_assets2Storyboard", "o_storyboard.id", "o_assets2Storyboard.storyboardId")
.leftJoin("o_assets", "o_assets2Storyboard.assetId", "o_assets.id")
.leftJoin("o_videoConfig", "o_storyboard.id", "o_videoConfig.storyboardId")
.where("o_storyboard.id", storyboardId)
.select("o_storyboard.id", "o_storyboard.prompt", "o_assets.prompt as assetPrompt", "o_videoConfig.model as videoModel");
if (data.length === 0) {
return res.status(200).send(success({ data: null }));
}
// 聚合资产提示词
const prompt = data[0].prompt || "";
const videoModel = data[0].videoModel || "";
const assetPrompts = data.map((row) => row.assetPrompt).filter(Boolean) as string[];
// 确定视频模型
let model = videoModel;
if (!model) {
const project = await u.db("o_project").where("id", projectId).select("videoModel").first();
model = project?.videoModel || "";
}
if (!model) {
return res.status(200).send(success({ data: null }));
}
const systemPrompt = `你是一个专业的${model}视频生成助手。请根据分镜提示词和关联资产提示词,生成一段完整的、可直接用于视频生成模型的中文提示词。`;
const userContent = `分镜提示词:${prompt || "无"}\n资产提示词${assetPrompts.length > 0 ? assetPrompts.join("\n") : "无"}`;
const { text } = await u.Ai.Text("universalAi").invoke({ const { text } = await u.Ai.Text("universalAi").invoke({
system: systemPrompt, system: visualManual,
messages: [{ role: "user", content: userContent }], messages: [
{
role: "user",
content: `你是一个专业的${modelData}视频生成助手。请根据以下提示词,生成一段完整的、可直接用于视频生成模型的中文提示词。${prompt.join(",")}`,
},
],
}); });
res.status(200).send(success(text));
await u.db("o_storyboard").where("id", storyboardId).update({ videoPrompt: text });
res.status(200).send(success({ data: { storyboardId, videoPrompt: text } }));
}, },
); );

View File

@ -1,50 +0,0 @@
import express from "express";
import u from "@/utils";
import { z } from "zod";
import { useSkill } from "@/utils/agent/skillsTools";
import { success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
import { Output } from "ai";
const router = express.Router();
export default router.post(
"/",
validateFields({
list: z.array(
z.object({
prompt: z.string(),
videoId: z.number(),
}),
),
}),
async (req, res) => {
const { list } = req.body;
const data = await Promise.all(
list.map(async (item: any) => {
const output = await getLines(item.prompt);
return { ...item, prompt: output };
}),
);
res.status(200).send(success(data));
},
);
async function getLines(prompt: string) {
const skill = await useSkill("universal_agent.md");//todo改为AI
const resText = await u.Ai.Text("universalAi").invoke({
system: skill.prompt,
messages: [{ role: "user", content: prompt }],
tools: skill.tools,
output: Output.array({
element: z.object({
lines: z.string().describe("台词内容"),
}),
}),
});
console.log("%c Line:36 🍉 resText", "background:#e41a6a", resText);
const parseLines = JSON.parse(resText.text);
const chatLines = parseLines.elements.map((i: any) => i.lines);
return chatLines;
}

View File

@ -1,4 +1,4 @@
// @db-hash 125ad64f9dc929a01dd6bfb955f16031 // @db-hash b1210691844e077e9df7dc16c802ce5a
//该文件由脚本自动生成,请勿手动修改 //该文件由脚本自动生成,请勿手动修改
export interface _o_project_old_20260331 { export interface _o_project_old_20260331 {
@ -230,21 +230,13 @@ export interface o_video {
'projectId'?: number | null; 'projectId'?: number | null;
'scriptId'?: number | null; 'scriptId'?: number | null;
'state'?: string | null; 'state'?: string | null;
'storyboardId'?: number | null;
'time'?: number | null; 'time'?: number | null;
'videoTrackId'?: number | null;
} }
export interface o_videoConfig { export interface o_videoTrack {
'audio'?: number | null;
'createTime'?: number | null;
'data'?: string | null;
'duration'?: number | null;
'id'?: number; 'id'?: number;
'mode'?: string | null; 'projectId'?: number | null;
'model'?: string | null; 'scriptId'?: number | null;
'prompt'?: string | null;
'resolution'?: string | null;
'storyboardId'?: number | null;
'updateTime'?: number | null;
'videoId'?: number | null; 'videoId'?: number | null;
} }
@ -275,5 +267,5 @@ export interface DB {
"o_user": o_user; "o_user": o_user;
"o_vendorConfig": o_vendorConfig; "o_vendorConfig": o_vendorConfig;
"o_video": o_video; "o_video": o_video;
"o_videoConfig": o_videoConfig; "o_videoTrack": o_videoTrack;
} }