修改生成视频api和生成视频提示词api
This commit is contained in:
parent
36d985b23d
commit
e4ba419f44
@ -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"]);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
21
src/routes/production/workbench/addTrack.ts
Normal file
21
src/routes/production/workbench/addTrack.ts
Normal 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));
|
||||||
|
},
|
||||||
|
);
|
||||||
@ -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")
|
||||||
|
|||||||
@ -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 } }));
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
20
src/types/database.d.ts
vendored
20
src/types/database.d.ts
vendored
@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user