Merge branch '108' of https://github.com/HBAI-Ltd/Toonflow-app into 108
This commit is contained in:
commit
57ca496e97
@ -138,6 +138,7 @@ function createSubAgent(parentCtx: AgentContext) {
|
|||||||
"你必须使用如下XML格式写入工作区:\n```",
|
"你必须使用如下XML格式写入工作区:\n```",
|
||||||
"拍摄计划:<scriptPlan>内容</scriptPlan>",
|
"拍摄计划:<scriptPlan>内容</scriptPlan>",
|
||||||
"分镜表:<storyboardTable>内容</storyboardTable>",
|
"分镜表:<storyboardTable>内容</storyboardTable>",
|
||||||
|
"分镜面板:<storyboard> <items prompt=提示词内容 group=分组 duration=视频推荐时间 associateAssetsIds=[资产ID列表] /></storyboard>",
|
||||||
"```",
|
"```",
|
||||||
].join("\n");
|
].join("\n");
|
||||||
// "剧本:<script>内容</script>",
|
// "剧本:<script>内容</script>",
|
||||||
@ -190,7 +191,7 @@ async function createArtSkills(artName: string) {
|
|||||||
}
|
}
|
||||||
const res = {
|
const res = {
|
||||||
prompt: buildSkillPrompt(mainSkills),
|
prompt: buildSkillPrompt(mainSkills),
|
||||||
tools: createSkillTools(mainSkills, { mainSkill: mainSkills, secondarySkills: [], tertiarySkills: [] },workerPath),
|
tools: createSkillTools(mainSkills, { mainSkill: mainSkills, secondarySkills: [], tertiarySkills: [] }, workerPath),
|
||||||
};
|
};
|
||||||
return res
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -175,7 +175,7 @@ export default (toolCpnfig: ToolConfig) => {
|
|||||||
generate_storyboard: tool({
|
generate_storyboard: tool({
|
||||||
description: "生成分镜图片",
|
description: "生成分镜图片",
|
||||||
inputSchema: z.object({
|
inputSchema: z.object({
|
||||||
ids: z.array(z.number()).describe("分镜面板中需要更新的分镜 ID 列表,传入id仅作对应分镜更新用,不传入则全部生成"),
|
ids: z.array(z.number()).describe("必须获取真实的分镜ID,支持批量生成"),
|
||||||
}),
|
}),
|
||||||
execute: async ({ ids }) => {
|
execute: async ({ ids }) => {
|
||||||
console.log("%c Line:176 🍒 ids", "background:#ea7e5c", ids);
|
console.log("%c Line:176 🍒 ids", "background:#ea7e5c", ids);
|
||||||
|
|||||||
236
src/router.ts
236
src/router.ts
@ -1,4 +1,4 @@
|
|||||||
// @routes-hash 01a3e214a845cf74065af521bc0794cc
|
// @routes-hash 8b0a09b55cd1b98ff83ad988d077fee3
|
||||||
import { Express } from "express";
|
import { Express } from "express";
|
||||||
|
|
||||||
import route1 from "./routes/agents/clearMemory";
|
import route1 from "./routes/agents/clearMemory";
|
||||||
@ -65,65 +65,64 @@ 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/storyboard/updateStoryboardInfo";
|
import route65 from "./routes/production/workbench/confirmSelection";
|
||||||
import route66 from "./routes/production/workbench/confirmSelection";
|
import route66 from "./routes/production/workbench/delVideo";
|
||||||
import route67 from "./routes/production/workbench/delVideo";
|
import route67 from "./routes/production/workbench/generateVideo";
|
||||||
import route68 from "./routes/production/workbench/generateVideo";
|
import route68 from "./routes/production/workbench/generateVideoPrompt";
|
||||||
import route69 from "./routes/production/workbench/generateVideoPrompt";
|
import route69 from "./routes/production/workbench/getChatLines";
|
||||||
import route70 from "./routes/production/workbench/getChatLines";
|
import route70 from "./routes/production/workbench/getVideoModelDetail";
|
||||||
import route71 from "./routes/production/workbench/getVideoModelDetail";
|
import route71 from "./routes/production/workbench/videoPolling";
|
||||||
import route72 from "./routes/production/workbench/videoPolling";
|
import route72 from "./routes/project/addProject";
|
||||||
import route73 from "./routes/project/addProject";
|
import route73 from "./routes/project/addVisual";
|
||||||
import route74 from "./routes/project/addVisual";
|
import route74 from "./routes/project/addVisualManual";
|
||||||
import route75 from "./routes/project/addVisualManual";
|
import route75 from "./routes/project/deleteVisualManual";
|
||||||
import route76 from "./routes/project/deleteVisualManual";
|
import route76 from "./routes/project/delProject";
|
||||||
import route77 from "./routes/project/delProject";
|
import route77 from "./routes/project/editProject";
|
||||||
import route78 from "./routes/project/editProject";
|
import route78 from "./routes/project/editVisualManual";
|
||||||
import route79 from "./routes/project/editVisualManual";
|
import route79 from "./routes/project/getProject";
|
||||||
import route80 from "./routes/project/getProject";
|
import route80 from "./routes/project/getVisualManual";
|
||||||
import route81 from "./routes/project/getVisualManual";
|
import route81 from "./routes/project/visualManual";
|
||||||
import route82 from "./routes/project/visualManual";
|
import route82 from "./routes/script/addScript";
|
||||||
import route83 from "./routes/script/addScript";
|
import route83 from "./routes/script/delScript";
|
||||||
import route84 from "./routes/script/delScript";
|
import route84 from "./routes/script/exportScript";
|
||||||
import route85 from "./routes/script/exportScript";
|
import route85 from "./routes/script/extractAssets";
|
||||||
import route86 from "./routes/script/extractAssets";
|
import route86 from "./routes/script/getScrptApi";
|
||||||
import route87 from "./routes/script/getScrptApi";
|
import route87 from "./routes/script/pollScriptAssets";
|
||||||
import route88 from "./routes/script/pollScriptAssets";
|
import route88 from "./routes/script/updateScript";
|
||||||
import route89 from "./routes/script/updateScript";
|
import route89 from "./routes/scriptAgent/getPlanData";
|
||||||
import route90 from "./routes/scriptAgent/getPlanData";
|
import route90 from "./routes/scriptAgent/setPlanData";
|
||||||
import route91 from "./routes/scriptAgent/setPlanData";
|
import route91 from "./routes/scriptAgent/updateData";
|
||||||
import route92 from "./routes/scriptAgent/updateData";
|
import route92 from "./routes/setting/about/checkUpdate";
|
||||||
import route93 from "./routes/setting/about/checkUpdate";
|
import route93 from "./routes/setting/about/downloadApp";
|
||||||
import route94 from "./routes/setting/about/downloadApp";
|
import route94 from "./routes/setting/agentDeploy/agentSetKey";
|
||||||
import route95 from "./routes/setting/agentDeploy/agentSetKey";
|
import route95 from "./routes/setting/agentDeploy/deployAgentModel";
|
||||||
import route96 from "./routes/setting/agentDeploy/deployAgentModel";
|
import route96 from "./routes/setting/agentDeploy/getAgentDeploy";
|
||||||
import route97 from "./routes/setting/agentDeploy/getAgentDeploy";
|
import route97 from "./routes/setting/dbConfig/clearData";
|
||||||
import route98 from "./routes/setting/dbConfig/clearData";
|
import route98 from "./routes/setting/dev/getSwitchAiDevTool";
|
||||||
import route99 from "./routes/setting/dev/getSwitchAiDevTool";
|
import route99 from "./routes/setting/dev/updateSwitchAiDevTool";
|
||||||
import route100 from "./routes/setting/dev/updateSwitchAiDevTool";
|
import route100 from "./routes/setting/fileManagement/openFolder";
|
||||||
import route101 from "./routes/setting/fileManagement/openFolder";
|
import route101 from "./routes/setting/getTextModel";
|
||||||
import route102 from "./routes/setting/getTextModel";
|
import route102 from "./routes/setting/loginConfig/getUser";
|
||||||
import route103 from "./routes/setting/loginConfig/getUser";
|
import route103 from "./routes/setting/loginConfig/updateUserPwd";
|
||||||
import route104 from "./routes/setting/loginConfig/updateUserPwd";
|
import route104 from "./routes/setting/memoryConfig/delAllMemory";
|
||||||
import route105 from "./routes/setting/memoryConfig/delAllMemory";
|
import route105 from "./routes/setting/memoryConfig/getMemory";
|
||||||
import route106 from "./routes/setting/memoryConfig/getMemory";
|
import route106 from "./routes/setting/memoryConfig/sureMemory";
|
||||||
import route107 from "./routes/setting/memoryConfig/sureMemory";
|
import route107 from "./routes/setting/promptManage/getPrompt";
|
||||||
import route108 from "./routes/setting/promptManage/getPrompt";
|
import route108 from "./routes/setting/promptManage/updatePrompt";
|
||||||
import route109 from "./routes/setting/promptManage/updatePrompt";
|
import route109 from "./routes/setting/skillManagement/getSkillContent";
|
||||||
import route110 from "./routes/setting/skillManagement/getSkillContent";
|
import route110 from "./routes/setting/skillManagement/getSkillList";
|
||||||
import route111 from "./routes/setting/skillManagement/getSkillList";
|
import route111 from "./routes/setting/skillManagement/saveSkillContent";
|
||||||
import route112 from "./routes/setting/skillManagement/saveSkillContent";
|
import route112 from "./routes/setting/vendorConfig/addVendor";
|
||||||
import route113 from "./routes/setting/vendorConfig/addVendor";
|
import route113 from "./routes/setting/vendorConfig/deleteVendor";
|
||||||
import route114 from "./routes/setting/vendorConfig/deleteVendor";
|
import route114 from "./routes/setting/vendorConfig/getVendorList";
|
||||||
import route115 from "./routes/setting/vendorConfig/getVendorList";
|
import route115 from "./routes/setting/vendorConfig/modelTest";
|
||||||
import route116 from "./routes/setting/vendorConfig/modelTest";
|
import route116 from "./routes/setting/vendorConfig/updateCode";
|
||||||
import route117 from "./routes/setting/vendorConfig/updateCode";
|
import route117 from "./routes/setting/vendorConfig/updateVendor";
|
||||||
import route118 from "./routes/setting/vendorConfig/updateVendor";
|
import route118 from "./routes/task/getProject";
|
||||||
import route119 from "./routes/task/getProject";
|
import route119 from "./routes/task/getTaskApi";
|
||||||
import route120 from "./routes/task/getTaskApi";
|
import route120 from "./routes/task/getTaskCategories";
|
||||||
import route121 from "./routes/task/getTaskCategories";
|
import route121 from "./routes/task/taskDetails";
|
||||||
import route122 from "./routes/task/taskDetails";
|
import route122 from "./routes/test/test";
|
||||||
import route123 from "./routes/test/test";
|
|
||||||
|
|
||||||
export default async (app: Express) => {
|
export default async (app: Express) => {
|
||||||
app.use("/api/agents/clearMemory", route1);
|
app.use("/api/agents/clearMemory", route1);
|
||||||
@ -190,63 +189,62 @@ 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/storyboard/updateStoryboardInfo", route65);
|
app.use("/api/production/workbench/confirmSelection", route65);
|
||||||
app.use("/api/production/workbench/confirmSelection", route66);
|
app.use("/api/production/workbench/delVideo", route66);
|
||||||
app.use("/api/production/workbench/delVideo", route67);
|
app.use("/api/production/workbench/generateVideo", route67);
|
||||||
app.use("/api/production/workbench/generateVideo", route68);
|
app.use("/api/production/workbench/generateVideoPrompt", route68);
|
||||||
app.use("/api/production/workbench/generateVideoPrompt", route69);
|
app.use("/api/production/workbench/getChatLines", route69);
|
||||||
app.use("/api/production/workbench/getChatLines", route70);
|
app.use("/api/production/workbench/getVideoModelDetail", route70);
|
||||||
app.use("/api/production/workbench/getVideoModelDetail", route71);
|
app.use("/api/production/workbench/videoPolling", route71);
|
||||||
app.use("/api/production/workbench/videoPolling", route72);
|
app.use("/api/project/addProject", route72);
|
||||||
app.use("/api/project/addProject", route73);
|
app.use("/api/project/addVisual", route73);
|
||||||
app.use("/api/project/addVisual", route74);
|
app.use("/api/project/addVisualManual", route74);
|
||||||
app.use("/api/project/addVisualManual", route75);
|
app.use("/api/project/deleteVisualManual", route75);
|
||||||
app.use("/api/project/deleteVisualManual", route76);
|
app.use("/api/project/delProject", route76);
|
||||||
app.use("/api/project/delProject", route77);
|
app.use("/api/project/editProject", route77);
|
||||||
app.use("/api/project/editProject", route78);
|
app.use("/api/project/editVisualManual", route78);
|
||||||
app.use("/api/project/editVisualManual", route79);
|
app.use("/api/project/getProject", route79);
|
||||||
app.use("/api/project/getProject", route80);
|
app.use("/api/project/getVisualManual", route80);
|
||||||
app.use("/api/project/getVisualManual", route81);
|
app.use("/api/project/visualManual", route81);
|
||||||
app.use("/api/project/visualManual", route82);
|
app.use("/api/script/addScript", route82);
|
||||||
app.use("/api/script/addScript", route83);
|
app.use("/api/script/delScript", route83);
|
||||||
app.use("/api/script/delScript", route84);
|
app.use("/api/script/exportScript", route84);
|
||||||
app.use("/api/script/exportScript", route85);
|
app.use("/api/script/extractAssets", route85);
|
||||||
app.use("/api/script/extractAssets", route86);
|
app.use("/api/script/getScrptApi", route86);
|
||||||
app.use("/api/script/getScrptApi", route87);
|
app.use("/api/script/pollScriptAssets", route87);
|
||||||
app.use("/api/script/pollScriptAssets", route88);
|
app.use("/api/script/updateScript", route88);
|
||||||
app.use("/api/script/updateScript", route89);
|
app.use("/api/scriptAgent/getPlanData", route89);
|
||||||
app.use("/api/scriptAgent/getPlanData", route90);
|
app.use("/api/scriptAgent/setPlanData", route90);
|
||||||
app.use("/api/scriptAgent/setPlanData", route91);
|
app.use("/api/scriptAgent/updateData", route91);
|
||||||
app.use("/api/scriptAgent/updateData", route92);
|
app.use("/api/setting/about/checkUpdate", route92);
|
||||||
app.use("/api/setting/about/checkUpdate", route93);
|
app.use("/api/setting/about/downloadApp", route93);
|
||||||
app.use("/api/setting/about/downloadApp", route94);
|
app.use("/api/setting/agentDeploy/agentSetKey", route94);
|
||||||
app.use("/api/setting/agentDeploy/agentSetKey", route95);
|
app.use("/api/setting/agentDeploy/deployAgentModel", route95);
|
||||||
app.use("/api/setting/agentDeploy/deployAgentModel", route96);
|
app.use("/api/setting/agentDeploy/getAgentDeploy", route96);
|
||||||
app.use("/api/setting/agentDeploy/getAgentDeploy", route97);
|
app.use("/api/setting/dbConfig/clearData", route97);
|
||||||
app.use("/api/setting/dbConfig/clearData", route98);
|
app.use("/api/setting/dev/getSwitchAiDevTool", route98);
|
||||||
app.use("/api/setting/dev/getSwitchAiDevTool", route99);
|
app.use("/api/setting/dev/updateSwitchAiDevTool", route99);
|
||||||
app.use("/api/setting/dev/updateSwitchAiDevTool", route100);
|
app.use("/api/setting/fileManagement/openFolder", route100);
|
||||||
app.use("/api/setting/fileManagement/openFolder", route101);
|
app.use("/api/setting/getTextModel", route101);
|
||||||
app.use("/api/setting/getTextModel", route102);
|
app.use("/api/setting/loginConfig/getUser", route102);
|
||||||
app.use("/api/setting/loginConfig/getUser", route103);
|
app.use("/api/setting/loginConfig/updateUserPwd", route103);
|
||||||
app.use("/api/setting/loginConfig/updateUserPwd", route104);
|
app.use("/api/setting/memoryConfig/delAllMemory", route104);
|
||||||
app.use("/api/setting/memoryConfig/delAllMemory", route105);
|
app.use("/api/setting/memoryConfig/getMemory", route105);
|
||||||
app.use("/api/setting/memoryConfig/getMemory", route106);
|
app.use("/api/setting/memoryConfig/sureMemory", route106);
|
||||||
app.use("/api/setting/memoryConfig/sureMemory", route107);
|
app.use("/api/setting/promptManage/getPrompt", route107);
|
||||||
app.use("/api/setting/promptManage/getPrompt", route108);
|
app.use("/api/setting/promptManage/updatePrompt", route108);
|
||||||
app.use("/api/setting/promptManage/updatePrompt", route109);
|
app.use("/api/setting/skillManagement/getSkillContent", route109);
|
||||||
app.use("/api/setting/skillManagement/getSkillContent", route110);
|
app.use("/api/setting/skillManagement/getSkillList", route110);
|
||||||
app.use("/api/setting/skillManagement/getSkillList", route111);
|
app.use("/api/setting/skillManagement/saveSkillContent", route111);
|
||||||
app.use("/api/setting/skillManagement/saveSkillContent", route112);
|
app.use("/api/setting/vendorConfig/addVendor", route112);
|
||||||
app.use("/api/setting/vendorConfig/addVendor", route113);
|
app.use("/api/setting/vendorConfig/deleteVendor", route113);
|
||||||
app.use("/api/setting/vendorConfig/deleteVendor", route114);
|
app.use("/api/setting/vendorConfig/getVendorList", route114);
|
||||||
app.use("/api/setting/vendorConfig/getVendorList", route115);
|
app.use("/api/setting/vendorConfig/modelTest", route115);
|
||||||
app.use("/api/setting/vendorConfig/modelTest", route116);
|
app.use("/api/setting/vendorConfig/updateCode", route116);
|
||||||
app.use("/api/setting/vendorConfig/updateCode", route117);
|
app.use("/api/setting/vendorConfig/updateVendor", route117);
|
||||||
app.use("/api/setting/vendorConfig/updateVendor", route118);
|
app.use("/api/task/getProject", route118);
|
||||||
app.use("/api/task/getProject", route119);
|
app.use("/api/task/getTaskApi", route119);
|
||||||
app.use("/api/task/getTaskApi", route120);
|
app.use("/api/task/getTaskCategories", route120);
|
||||||
app.use("/api/task/getTaskCategories", route121);
|
app.use("/api/task/taskDetails", route121);
|
||||||
app.use("/api/task/taskDetails", route122);
|
app.use("/api/test/test", route122);
|
||||||
app.use("/api/test/test", route123);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,47 +42,27 @@ export default router.post(
|
|||||||
const rolePrompt = u.getArtPrompt(projectSettingData!.artStyle!, "art_character_derivative");
|
const rolePrompt = u.getArtPrompt(projectSettingData!.artStyle!, "art_character_derivative");
|
||||||
const toolPrompt = u.getArtPrompt(projectSettingData!.artStyle!, "art_prop_derivative");
|
const toolPrompt = u.getArtPrompt(projectSettingData!.artStyle!, "art_prop_derivative");
|
||||||
const scenePrompt = u.getArtPrompt(projectSettingData!.artStyle!, "art_scene_derivative");
|
const scenePrompt = u.getArtPrompt(projectSettingData!.artStyle!, "art_scene_derivative");
|
||||||
const promptRecord: Record<string, { prompt: string; label: string; focus: string }> = {
|
const promptRecord: Record<string, { prompt: string }> = {
|
||||||
role: {
|
role: {
|
||||||
prompt: rolePrompt,
|
prompt: rolePrompt,
|
||||||
label: "角色衍生资产",
|
|
||||||
focus: "注重人物的姿态、表情、服饰细节、体态特征与情绪表达,保持与原始角色设计的一致性(如发型、瞳色、服装风格),同时体现衍生场景下的变化。",
|
|
||||||
},
|
},
|
||||||
tool: {
|
tool: {
|
||||||
prompt: toolPrompt,
|
prompt: toolPrompt,
|
||||||
label: "道具衍生资产",
|
|
||||||
focus:
|
|
||||||
"注重道具的材质质感、光影效果、结构细节与功能特征,保持与原始道具设计的一致性(如形状、配色、标志性元素),清晰展示道具在不同状态或角度下的视觉表现。",
|
|
||||||
},
|
},
|
||||||
scene: {
|
scene: {
|
||||||
prompt: scenePrompt,
|
prompt: scenePrompt,
|
||||||
label: "场景衍生资产",
|
|
||||||
focus:
|
|
||||||
"注重场景的空间层次、光影氛围、环境细节与情绪渲染,保持与原始场景设计的一致性(如建筑风格、色调、标志性地标),体现不同时间段或天气条件下的视觉变化。",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const imageData = [];
|
const imageData = [];
|
||||||
for (const item of assetsDataArr) {
|
for (const item of assetsDataArr) {
|
||||||
const typeConfig = promptRecord[item.type!] || promptRecord["role"];
|
const typeConfig = promptRecord[item.type!] || promptRecord["role"];
|
||||||
const hasRefImage = !!imageUrlRecord[item.assetsId!];
|
|
||||||
|
|
||||||
const { text } = await u.Ai.Text("universalAi").invoke({
|
const { text } = await u.Ai.Text("universalAi").invoke({
|
||||||
system: `你是一位专业的 AI 绘画提示词工程师,擅长将资产描述转化为高质量的图片生成提示词。
|
system: `${typeConfig.prompt}`,
|
||||||
|
|
||||||
## 任务
|
|
||||||
根据用户提供的${typeConfig.label}名称与描述,结合项目美术风格规范,生成一段精准的图片生成提示词(Prompt)。
|
|
||||||
|
|
||||||
## 输出要求
|
|
||||||
- 直接输出最终提示词,不要包含任何解释、标题或标记
|
|
||||||
- ${typeConfig.focus}
|
|
||||||
${hasRefImage ? "- 当前资产有参考图作为风格锚点,提示词应侧重描述衍生变化部分,避免重复参考图已有的基础特征" : "- 当前资产无参考图,提示词需要完整描述视觉特征"}
|
|
||||||
|
|
||||||
## 项目美术风格与提示词规范参考
|
|
||||||
${typeConfig.prompt || "(未指定特定美术风格,请根据资产描述选择合适的画面风格)"}`,
|
|
||||||
messages: [
|
messages: [
|
||||||
{
|
{
|
||||||
role: "user",
|
role: "user",
|
||||||
content: `资产名称: ${item.name}\n资产描述: ${item.describe || "无详细描述"}`,
|
content: `资产描述: ${item.describe || "无详细描述"}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,6 +11,11 @@ export default router.post(
|
|||||||
data: z.array(
|
data: z.array(
|
||||||
z.object({
|
z.object({
|
||||||
prompt: z.string(),
|
prompt: z.string(),
|
||||||
|
duration: z.number(),
|
||||||
|
group: z.number(),
|
||||||
|
state: z.string(),
|
||||||
|
src: z.string().nullable(),
|
||||||
|
associateAssetsIds: z.array(z.number()),
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
scriptId: z.number(),
|
scriptId: z.number(),
|
||||||
@ -18,14 +23,25 @@ export default router.post(
|
|||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const { data, scriptId } = req.body;
|
const { data, scriptId } = req.body;
|
||||||
if (!data.length) return res.status(400).send({ success: false, message: "数据不能为空" });
|
if (!data.length) return res.status(400).send({ success: false, message: "数据不能为空" });
|
||||||
await u.db("o_storyboard").insert(
|
for (const item of data) {
|
||||||
data.map((i: { prompt: string }) => ({
|
const [id] = await u.db("o_storyboard").insert({
|
||||||
...i,
|
prompt: item.prompt,
|
||||||
|
duration: String(item.duration),
|
||||||
|
group: String(item.group),
|
||||||
|
state: item.state,
|
||||||
scriptId,
|
scriptId,
|
||||||
createTime: Date.now(),
|
createTime: Date.now(),
|
||||||
state: "未生成",
|
});
|
||||||
})),
|
if (item.associateAssetsIds?.length) {
|
||||||
);
|
await u.db("o_assets2Storyboard").insert(
|
||||||
return res.status(200).send(success());
|
item.associateAssetsIds.map((assetId: number) => ({
|
||||||
|
assetId,
|
||||||
|
storyboardId: id,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const lastStoryboard = await u.db("o_storyboard").where("scriptId", scriptId);
|
||||||
|
return res.status(200).send(success(lastStoryboard));
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import express from "express";
|
|||||||
import u from "@/utils";
|
import u from "@/utils";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import sharp from "sharp";
|
import sharp from "sharp";
|
||||||
import { success } from "@/lib/responseFormat";
|
import { error, success } from "@/lib/responseFormat";
|
||||||
import { validateFields } from "@/middleware/middleware";
|
import { validateFields } from "@/middleware/middleware";
|
||||||
import { Output, tool } from "ai";
|
import { Output, tool } from "ai";
|
||||||
import { urlToBase64 } from "@/utils/vm";
|
import { urlToBase64 } from "@/utils/vm";
|
||||||
@ -13,115 +13,27 @@ export type AssetData = z.infer<typeof assetItemSchema>;
|
|||||||
export default router.post(
|
export default router.post(
|
||||||
"/",
|
"/",
|
||||||
validateFields({
|
validateFields({
|
||||||
storyboardIds: z.array(z.number()).optional(),
|
storyboardIds: z.array(z.number()),
|
||||||
projectId: z.number(),
|
projectId: z.number(),
|
||||||
scriptId: z.number(),
|
scriptId: z.number(),
|
||||||
script: z.string(),
|
|
||||||
scriptPlan: z.string(),
|
|
||||||
storyboardTable: z.string(),
|
|
||||||
assets: z.array(assetItemSchema),
|
|
||||||
}),
|
}),
|
||||||
async (req, res) => {
|
async (req, res) => {
|
||||||
const {
|
const {
|
||||||
storyboardIds,
|
storyboardIds,
|
||||||
projectId,
|
projectId,
|
||||||
scriptId,
|
scriptId,
|
||||||
script,
|
|
||||||
scriptPlan,
|
|
||||||
storyboardTable,
|
|
||||||
assets,
|
|
||||||
}: {
|
}: {
|
||||||
storyboardIds: number[];
|
storyboardIds: number[];
|
||||||
projectId: number;
|
projectId: number;
|
||||||
scriptId: number;
|
scriptId: number;
|
||||||
script: string;
|
|
||||||
scriptPlan: string;
|
|
||||||
storyboardTable: string;
|
|
||||||
assets: AssetData[];
|
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
if (!storyboardIds || storyboardIds.length === 0) return res.status(400).send(error("storyboardIds不能为空"));
|
||||||
// 当没有 storyboardIds 时,通过 AI 生成新的分镜面板数据
|
// 当没有 storyboardIds 时,通过 AI 生成新的分镜面板数据
|
||||||
let finalStoryboardIds: number[] = storyboardIds || [];
|
let finalStoryboardIds: number[] = storyboardIds || [];
|
||||||
if (!storyboardIds || storyboardIds.length === 0) {
|
|
||||||
await u.db("o_storyboard").where("scriptId", scriptId).delete();
|
|
||||||
const createdIds: number[] = [];
|
|
||||||
const resultTools = tool({
|
|
||||||
description: "结果输出工具(必须调用)",
|
|
||||||
inputSchema: z.object({
|
|
||||||
items: z.array(
|
|
||||||
z.object({
|
|
||||||
title: z.string().describe("分镜名称"),
|
|
||||||
description: z.string().describe("分镜详细描述"),
|
|
||||||
relatedAssets: z.array(z.number()).describe("关联衍生资产id数组"),
|
|
||||||
duration: z.number().describe("用于生成的视频时长(秒)"),
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
}),
|
|
||||||
execute: async (resData) => {
|
|
||||||
console.log("%c Line:46 🌰 resData", "background:#93c0a4", resData.items);
|
|
||||||
for (const item of resData.items) {
|
|
||||||
const [id] = await u.db("o_storyboard").insert({
|
|
||||||
title: item.title,
|
|
||||||
description: item.description,
|
|
||||||
scriptId: scriptId,
|
|
||||||
duration: String(item.duration),
|
|
||||||
});
|
|
||||||
createdIds.push(id);
|
|
||||||
if (item.relatedAssets.length === 0) continue;
|
|
||||||
await u.db("o_assets2Storyboard").insert(item.relatedAssets.map((i) => ({ storyboardId: id, assetId: i })));
|
|
||||||
console.log("%c Line:68 🍷 createdIds", "background:#33a5ff", createdIds);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
const { text } = await u.Ai.Text("universalAi").invoke({
|
|
||||||
system: `你是一位专业的动画分镜师。你的任务是根据剧本内容、分镜表、拍摄计划和可用资产,拆分并生成完整的分镜面板数据。
|
|
||||||
|
|
||||||
## 工作流程
|
|
||||||
1. 仔细阅读剧本,理解故事情节、角色关系和情感节奏。
|
|
||||||
2. 参照分镜表和拍摄计划,确定每个分镜的镜头语言(景别、角度、运镜方式)。
|
|
||||||
3. 将可用资产合理分配到对应分镜中,确保每个分镜关联的资产与画面内容一致。
|
|
||||||
4. 为每个分镜撰写详细的画面描述,包含:场景环境、角色动作与表情、镜头构图、光影氛围。
|
|
||||||
5. 根据镜头内容合理分配视频时长(一般 2~8 秒,对话或动作复杂的场景可适当延长)。
|
|
||||||
|
|
||||||
## 输出要求
|
|
||||||
- 你 **必须** 调用 resultTools 工具来输出结果,不要在回复中添加任何文字说明。
|
|
||||||
- items 数组中每个元素包含:
|
|
||||||
- title:简洁的分镜名称(如"开场远景"、"角色对话特写")
|
|
||||||
- description:详细的分镜画面描述(至少 50 字),需包含镜头景别、角色状态、环境氛围等具体视觉信息
|
|
||||||
- relatedAssets:该分镜关联的衍生资产 ID 数组,仅关联与画面内容直接相关的资产
|
|
||||||
- duration:建议视频时长(秒),根据画面复杂度和叙事节奏合理分配`,
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: `## 剧本
|
|
||||||
${script}
|
|
||||||
|
|
||||||
## 分镜表
|
|
||||||
${storyboardTable}
|
|
||||||
|
|
||||||
## 拍摄计划
|
|
||||||
${scriptPlan}
|
|
||||||
|
|
||||||
## 可用资产列表
|
|
||||||
${assets.map((i) => i.derive.map((t) => `- 衍生资产名称: ${t.name} | 类型: ${t.type} | 资产ID: ${t.assetsId}`).join("\n")).join("\n")}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tools: { resultTools },
|
|
||||||
});
|
|
||||||
console.log("%c Line:52 🍢 text", "background:#93c0a4", text);
|
|
||||||
finalStoryboardIds = createdIds;
|
|
||||||
}
|
|
||||||
await u.db("o_storyboard").whereIn("id", finalStoryboardIds).where("scriptId", scriptId).update({ state: "生成中" });
|
await u.db("o_storyboard").whereIn("id", finalStoryboardIds).where("scriptId", scriptId).update({ state: "生成中" });
|
||||||
console.log("%c Line:98 🍯 finalStoryboardIds", "background:#3f7cff", finalStoryboardIds);
|
|
||||||
|
|
||||||
if (finalStoryboardIds.length === 0) {
|
|
||||||
res.status(200).send(success());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const projectSettingData = await u.db("o_project").where("id", projectId).select("imageModel", "imageQuality", "artStyle").first();
|
const projectSettingData = await u.db("o_project").where("id", projectId).select("imageModel", "imageQuality", "artStyle").first();
|
||||||
|
|
||||||
const sceneArkPrompt = u.getArtPrompt(projectSettingData?.artStyle || "", "art_storyboard");
|
|
||||||
const storyboardData = await u.db("o_storyboard").where("scriptId", scriptId).whereIn("id", finalStoryboardIds);
|
const storyboardData = await u.db("o_storyboard").where("scriptId", scriptId).whereIn("id", finalStoryboardIds);
|
||||||
const assetData = await u
|
const assetData = await u
|
||||||
.db("o_assets")
|
.db("o_assets")
|
||||||
@ -139,9 +51,7 @@ ${assets.map((i) => i.derive.map((t) => `- 衍生资产名称: ${t.name} | 类
|
|||||||
success(
|
success(
|
||||||
storyboardData.map((i) => ({
|
storyboardData.map((i) => ({
|
||||||
id: i.id,
|
id: i.id,
|
||||||
title: i.title,
|
prompt: i.prompt,
|
||||||
description: i.description,
|
|
||||||
prompt: "",
|
|
||||||
associateAssetsIds: assetRecord[i.id!],
|
associateAssetsIds: assetRecord[i.id!],
|
||||||
src: null,
|
src: null,
|
||||||
state: i.state,
|
state: i.state,
|
||||||
@ -149,30 +59,12 @@ ${assets.map((i) => i.derive.map((t) => `- 衍生资产名称: ${t.name} | 类
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
for (const item of storyboardData) {
|
for (const item of storyboardData) {
|
||||||
const { text } = await u.Ai.Text("universalAi").invoke({
|
|
||||||
system: `你是一位专业的 AI 绘画提示词工程师,擅长将分镜描述转化为高质量的图片生成提示词。
|
|
||||||
|
|
||||||
## 任务
|
|
||||||
根据分镜的标题与描述,结合项目美术风格要求,生成一段精准的英文图片生成提示词(Prompt)。
|
|
||||||
|
|
||||||
## 项目美术风格与提示词规范参考
|
|
||||||
${sceneArkPrompt || "(未指定特定美术风格,请根据分镜内容选择合适的画面风格)"}`,
|
|
||||||
messages: [
|
|
||||||
{
|
|
||||||
role: "user",
|
|
||||||
content: `分镜标题: ${item.title}\n分镜描述: ${item.description}`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
console.log("%c Line:27 🍫 text", "background:#ffdd4d", text);
|
|
||||||
|
|
||||||
const repeloadObj = {
|
const repeloadObj = {
|
||||||
prompt: text,
|
prompt: item.prompt!,
|
||||||
size: projectSettingData?.imageQuality as "1K" | "2K" | "4K",
|
size: projectSettingData?.imageQuality as "1K" | "2K" | "4K",
|
||||||
aspectRatio: "16:9" as `${number}:${number}`,
|
aspectRatio: "16:9" as `${number}:${number}`,
|
||||||
};
|
};
|
||||||
await u.db("o_storyboard").where("id", item.id).update({
|
await u.db("o_storyboard").where("id", item.id).update({
|
||||||
prompt: text,
|
|
||||||
state: "生成中",
|
state: "生成中",
|
||||||
});
|
});
|
||||||
u.Ai.Image(projectSettingData?.imageModel as `${string}:${string}`)
|
u.Ai.Image(projectSettingData?.imageModel as `${string}:${string}`)
|
||||||
|
|||||||
@ -1,22 +0,0 @@
|
|||||||
import express from "express";
|
|
||||||
import u from "@/utils";
|
|
||||||
import { z } from "zod";
|
|
||||||
import { success } from "@/lib/responseFormat";
|
|
||||||
import { validateFields } from "@/middleware/middleware";
|
|
||||||
import { id } from "zod/locales";
|
|
||||||
const router = express.Router();
|
|
||||||
|
|
||||||
export default router.post(
|
|
||||||
"/",
|
|
||||||
validateFields({
|
|
||||||
id: z.number(),
|
|
||||||
prompt: z.string(),
|
|
||||||
}),
|
|
||||||
async (req, res) => {
|
|
||||||
const { id, prompt } = req.body;
|
|
||||||
await u.db("o_storyboard").where({ id }).update({
|
|
||||||
prompt,
|
|
||||||
});
|
|
||||||
res.status(200).send(success({ message: "更新提示词成功" }));
|
|
||||||
},
|
|
||||||
);
|
|
||||||
@ -11,7 +11,6 @@ const router = express.Router();
|
|||||||
|
|
||||||
/** 新资产:AI 首次识别到的资产,需要完整信息 */
|
/** 新资产:AI 首次识别到的资产,需要完整信息 */
|
||||||
const NewAssetSchema = z.object({
|
const NewAssetSchema = z.object({
|
||||||
prompt: z.string().describe("生成提示词"),
|
|
||||||
name: z.string().describe("资产名称,仅为名称不做其他任何表述"),
|
name: z.string().describe("资产名称,仅为名称不做其他任何表述"),
|
||||||
desc: z.string().describe("资产描述"),
|
desc: z.string().describe("资产描述"),
|
||||||
type: z.enum(["role", "tool", "scene"]).describe("资产类型"),
|
type: z.enum(["role", "tool", "scene"]).describe("资产类型"),
|
||||||
@ -25,7 +24,6 @@ const ExistingAssetRefSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const AssetSchema = z.object({
|
export const AssetSchema = z.object({
|
||||||
prompt: z.string().describe("生成提示词"),
|
|
||||||
name: z.string().describe("资产名称,仅为名称不做其他任何表述"),
|
name: z.string().describe("资产名称,仅为名称不做其他任何表述"),
|
||||||
desc: z.string().describe("资产描述"),
|
desc: z.string().describe("资产描述"),
|
||||||
type: z.enum(["role", "tool", "scene"]).describe("资产类型"),
|
type: z.enum(["role", "tool", "scene"]).describe("资产类型"),
|
||||||
@ -108,7 +106,6 @@ export default router.post(
|
|||||||
await u.db("o_assets").insert(
|
await u.db("o_assets").insert(
|
||||||
toInsert.map((asset) => ({
|
toInsert.map((asset) => ({
|
||||||
name: asset.name,
|
name: asset.name,
|
||||||
prompt: asset.prompt,
|
|
||||||
type: asset.type,
|
type: asset.type,
|
||||||
describe: asset.desc,
|
describe: asset.desc,
|
||||||
projectId: projectId,
|
projectId: projectId,
|
||||||
@ -218,12 +215,11 @@ export default router.post(
|
|||||||
content:
|
content:
|
||||||
data?.data +
|
data?.data +
|
||||||
"\n\n提取剧本中涉及的资产(角色、场景、道具),参考技能 script_assets_extract 规范,结果必须通过 resultTool 工具返回。" +
|
"\n\n提取剧本中涉及的资产(角色、场景、道具),参考技能 script_assets_extract 规范,结果必须通过 resultTool 工具返回。" +
|
||||||
"\n\n注意:本次会同时提供多集剧本,每集剧本以 ===== 【剧本ID: xxx】 ===== 分隔。你需要分析每集剧本使用了哪些资产,并在输出中用 scriptIds 数组标明每个资产在哪些剧本中出现。" +
|
"\n\n注意:本次会同时提供多集剧本,每集剧本以 ===== 【剧本ID: xxx】 ===== 分隔。你需要分析每集剧本使用了哪些资产,并在输出中用 scriptIds 数组标明每个资产在哪些剧本中出现。",
|
||||||
existingHint,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
role: "user",
|
role: "user",
|
||||||
content: `请根据以下${validScripts.length}集剧本提取对应的剧本资产(角色、场景、道具):\n\n${scriptsContent}`,
|
content: `当前已有资产列表:${existingHint}\n\n请根据以下${validScripts.length}集剧本提取对应的剧本资产(角色、场景、道具):\n\n${scriptsContent}`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
tools: { resultTool },
|
tools: { resultTool },
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user