# Conflicts:
#	src/types/database.d.ts
This commit is contained in:
zhishi 2026-03-28 00:04:20 +08:00
commit c78c991ead
5 changed files with 532 additions and 203 deletions

View File

@ -1,4 +1,4 @@
// @routes-hash cf18bce0fd0b7cd4d351d3c319cc7205 // @routes-hash 7027f20b3def330f442689eb22769f31
import { Express } from "express"; import { Express } from "express";
import route1 from "./routes/agents/clearMemory"; import route1 from "./routes/agents/clearMemory";
@ -19,94 +19,96 @@ import route15 from "./routes/assets/pollingPromptAssets";
import route16 from "./routes/assets/saveAssets"; import route16 from "./routes/assets/saveAssets";
import route17 from "./routes/assets/updateAssets"; import route17 from "./routes/assets/updateAssets";
import route18 from "./routes/assets/uploadClip"; import route18 from "./routes/assets/uploadClip";
import route19 from "./routes/assetsGenerate/generateAssets"; import route19 from "./routes/assetsGenerate/batchGenerateImageAssets";
import route20 from "./routes/assetsGenerate/polishAssetsPrompt"; import route20 from "./routes/assetsGenerate/batchPolishAssetsPrompt";
import route21 from "./routes/cornerScape/getAllAssets"; import route21 from "./routes/assetsGenerate/generateAssets";
import route22 from "./routes/general/generalStatistics"; import route22 from "./routes/assetsGenerate/polishAssetsPrompt";
import route23 from "./routes/general/getSingleProject"; import route23 from "./routes/cornerScape/getAllAssets";
import route24 from "./routes/general/updateProject"; import route24 from "./routes/general/generalStatistics";
import route25 from "./routes/login/login"; import route25 from "./routes/general/getSingleProject";
import route26 from "./routes/migrate/migrateData"; import route26 from "./routes/general/updateProject";
import route27 from "./routes/modelSelect/getModelDetail"; import route27 from "./routes/login/login";
import route28 from "./routes/modelSelect/getModelList"; import route28 from "./routes/migrate/migrateData";
import route29 from "./routes/novel/addNovel"; import route29 from "./routes/modelSelect/getModelDetail";
import route30 from "./routes/novel/batchDeleteNovel"; import route30 from "./routes/modelSelect/getModelList";
import route31 from "./routes/novel/delNovel"; import route31 from "./routes/novel/addNovel";
import route32 from "./routes/novel/event/batchDeleteEvent"; import route32 from "./routes/novel/batchDeleteNovel";
import route33 from "./routes/novel/event/deletEvent"; import route33 from "./routes/novel/delNovel";
import route34 from "./routes/novel/event/generateEvents"; import route34 from "./routes/novel/event/batchDeleteEvent";
import route35 from "./routes/novel/event/getEvent"; import route35 from "./routes/novel/event/deletEvent";
import route36 from "./routes/novel/getNovel"; import route36 from "./routes/novel/event/generateEvents";
import route37 from "./routes/novel/getNovelEventState"; import route37 from "./routes/novel/event/getEvent";
import route38 from "./routes/novel/getNovelIndex"; import route38 from "./routes/novel/getNovel";
import route39 from "./routes/novel/updateNovel"; import route39 from "./routes/novel/getNovelEventState";
import route40 from "./routes/other/deleteAllData"; import route40 from "./routes/novel/getNovelIndex";
import route41 from "./routes/other/getVersion"; import route41 from "./routes/novel/updateNovel";
import route42 from "./routes/production/assets/getAssetsData"; import route42 from "./routes/other/deleteAllData";
import route43 from "./routes/production/editImage/generateFlowImage"; import route43 from "./routes/other/getVersion";
import route44 from "./routes/production/editImage/getImageFlow"; import route44 from "./routes/production/assets/getAssetsData";
import route45 from "./routes/production/editImage/saveImageFlow"; import route45 from "./routes/production/editImage/generateFlowImage";
import route46 from "./routes/production/editImage/updateImageFlow"; import route46 from "./routes/production/editImage/getImageFlow";
import route47 from "./routes/production/exportImage"; import route47 from "./routes/production/editImage/saveImageFlow";
import route48 from "./routes/production/getFlowData"; import route48 from "./routes/production/editImage/updateImageFlow";
import route49 from "./routes/production/getProductionData"; import route49 from "./routes/production/exportImage";
import route50 from "./routes/production/getStoryboardData"; import route50 from "./routes/production/getFlowData";
import route51 from "./routes/production/saveFlowData"; import route51 from "./routes/production/getProductionData";
import route52 from "./routes/production/storyboard/downPreviewImage"; import route52 from "./routes/production/getStoryboardData";
import route53 from "./routes/production/storyboard/getStoryboardData"; import route53 from "./routes/production/saveFlowData";
import route54 from "./routes/production/storyboard/previewImage"; import route54 from "./routes/production/storyboard/downPreviewImage";
import route55 from "./routes/production/workbench/confirmSelection"; import route55 from "./routes/production/storyboard/getStoryboardData";
import route56 from "./routes/production/workbench/delVideo"; import route56 from "./routes/production/storyboard/previewImage";
import route57 from "./routes/production/workbench/generateVideo"; import route57 from "./routes/production/workbench/confirmSelection";
import route58 from "./routes/production/workbench/getChatLines"; import route58 from "./routes/production/workbench/delVideo";
import route59 from "./routes/production/workbench/getVideoModelDetail"; import route59 from "./routes/production/workbench/generateVideo";
import route60 from "./routes/production/workbench/videoPolling"; import route60 from "./routes/production/workbench/getChatLines";
import route61 from "./routes/project/addProject"; import route61 from "./routes/production/workbench/getVideoModelDetail";
import route62 from "./routes/project/delProject"; import route62 from "./routes/production/workbench/videoPolling";
import route63 from "./routes/project/editProject"; import route63 from "./routes/project/addProject";
import route64 from "./routes/project/getProject"; import route64 from "./routes/project/delProject";
import route65 from "./routes/script/addScript"; import route65 from "./routes/project/editProject";
import route66 from "./routes/script/delScript"; import route66 from "./routes/project/getProject";
import route67 from "./routes/script/exportScript"; import route67 from "./routes/script/addScript";
import route68 from "./routes/script/extractAssets"; import route68 from "./routes/script/delScript";
import route69 from "./routes/script/getScrptApi"; import route69 from "./routes/script/exportScript";
import route70 from "./routes/script/pollScriptAssets"; import route70 from "./routes/script/extractAssets";
import route71 from "./routes/script/updateScript"; import route71 from "./routes/script/getScrptApi";
import route72 from "./routes/scriptAgent/getPlanData"; import route72 from "./routes/script/pollScriptAssets";
import route73 from "./routes/scriptAgent/setPlanData"; import route73 from "./routes/script/updateScript";
import route74 from "./routes/setting/about/checkUpdate"; import route74 from "./routes/scriptAgent/getPlanData";
import route75 from "./routes/setting/about/downloadApp"; import route75 from "./routes/scriptAgent/setPlanData";
import route76 from "./routes/setting/agentDeploy/agentSetKey"; import route76 from "./routes/setting/about/checkUpdate";
import route77 from "./routes/setting/agentDeploy/deployAgentModel"; import route77 from "./routes/setting/about/downloadApp";
import route78 from "./routes/setting/agentDeploy/getAgentDeploy"; import route78 from "./routes/setting/agentDeploy/agentSetKey";
import route79 from "./routes/setting/dbConfig/clearData"; import route79 from "./routes/setting/agentDeploy/deployAgentModel";
import route80 from "./routes/setting/dev/getSwitchAiDevTool"; import route80 from "./routes/setting/agentDeploy/getAgentDeploy";
import route81 from "./routes/setting/dev/updateSwitchAiDevTool"; import route81 from "./routes/setting/dbConfig/clearData";
import route82 from "./routes/setting/fileManagement/openFolder"; import route82 from "./routes/setting/dev/getSwitchAiDevTool";
import route83 from "./routes/setting/getTextModel"; import route83 from "./routes/setting/dev/updateSwitchAiDevTool";
import route84 from "./routes/setting/loginConfig/getUser"; import route84 from "./routes/setting/fileManagement/openFolder";
import route85 from "./routes/setting/loginConfig/updateUserPwd"; import route85 from "./routes/setting/getTextModel";
import route86 from "./routes/setting/memoryConfig/delAllMemory"; import route86 from "./routes/setting/loginConfig/getUser";
import route87 from "./routes/setting/memoryConfig/getMemory"; import route87 from "./routes/setting/loginConfig/updateUserPwd";
import route88 from "./routes/setting/memoryConfig/sureMemory"; import route88 from "./routes/setting/memoryConfig/delAllMemory";
import route89 from "./routes/setting/skillManagement/addSkill"; import route89 from "./routes/setting/memoryConfig/getMemory";
import route90 from "./routes/setting/skillManagement/deleteSkill"; import route90 from "./routes/setting/memoryConfig/sureMemory";
import route91 from "./routes/setting/skillManagement/embeddingSkill"; import route91 from "./routes/setting/skillManagement/addSkill";
import route92 from "./routes/setting/skillManagement/generateDescription"; import route92 from "./routes/setting/skillManagement/deleteSkill";
import route93 from "./routes/setting/skillManagement/getSkillList"; import route93 from "./routes/setting/skillManagement/embeddingSkill";
import route94 from "./routes/setting/skillManagement/scanSkills"; import route94 from "./routes/setting/skillManagement/generateDescription";
import route95 from "./routes/setting/skillManagement/updateSkill"; import route95 from "./routes/setting/skillManagement/getSkillList";
import route96 from "./routes/setting/vendorConfig/addVendor"; import route96 from "./routes/setting/skillManagement/scanSkills";
import route97 from "./routes/setting/vendorConfig/deleteVendor"; import route97 from "./routes/setting/skillManagement/updateSkill";
import route98 from "./routes/setting/vendorConfig/getVendorList"; import route98 from "./routes/setting/vendorConfig/addVendor";
import route99 from "./routes/setting/vendorConfig/modelTest"; import route99 from "./routes/setting/vendorConfig/deleteVendor";
import route100 from "./routes/setting/vendorConfig/updateCode"; import route100 from "./routes/setting/vendorConfig/getVendorList";
import route101 from "./routes/setting/vendorConfig/updateVendor"; import route101 from "./routes/setting/vendorConfig/modelTest";
import route102 from "./routes/task/getProject"; import route102 from "./routes/setting/vendorConfig/updateCode";
import route103 from "./routes/task/getTaskApi"; import route103 from "./routes/setting/vendorConfig/updateVendor";
import route104 from "./routes/task/getTaskCategories"; import route104 from "./routes/task/getProject";
import route105 from "./routes/task/taskDetails"; import route105 from "./routes/task/getTaskApi";
import route106 from "./routes/test/test"; import route106 from "./routes/task/getTaskCategories";
import route107 from "./routes/task/taskDetails";
import route108 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);
@ -127,92 +129,94 @@ export default async (app: Express) => {
app.use("/api/assets/saveAssets", route16); app.use("/api/assets/saveAssets", route16);
app.use("/api/assets/updateAssets", route17); app.use("/api/assets/updateAssets", route17);
app.use("/api/assets/uploadClip", route18); app.use("/api/assets/uploadClip", route18);
app.use("/api/assetsGenerate/generateAssets", route19); app.use("/api/assetsGenerate/batchGenerateImageAssets", route19);
app.use("/api/assetsGenerate/polishAssetsPrompt", route20); app.use("/api/assetsGenerate/batchPolishAssetsPrompt", route20);
app.use("/api/cornerScape/getAllAssets", route21); app.use("/api/assetsGenerate/generateAssets", route21);
app.use("/api/general/generalStatistics", route22); app.use("/api/assetsGenerate/polishAssetsPrompt", route22);
app.use("/api/general/getSingleProject", route23); app.use("/api/cornerScape/getAllAssets", route23);
app.use("/api/general/updateProject", route24); app.use("/api/general/generalStatistics", route24);
app.use("/api/login/login", route25); app.use("/api/general/getSingleProject", route25);
app.use("/api/migrate/migrateData", route26); app.use("/api/general/updateProject", route26);
app.use("/api/modelSelect/getModelDetail", route27); app.use("/api/login/login", route27);
app.use("/api/modelSelect/getModelList", route28); app.use("/api/migrate/migrateData", route28);
app.use("/api/novel/addNovel", route29); app.use("/api/modelSelect/getModelDetail", route29);
app.use("/api/novel/batchDeleteNovel", route30); app.use("/api/modelSelect/getModelList", route30);
app.use("/api/novel/delNovel", route31); app.use("/api/novel/addNovel", route31);
app.use("/api/novel/event/batchDeleteEvent", route32); app.use("/api/novel/batchDeleteNovel", route32);
app.use("/api/novel/event/deletEvent", route33); app.use("/api/novel/delNovel", route33);
app.use("/api/novel/event/generateEvents", route34); app.use("/api/novel/event/batchDeleteEvent", route34);
app.use("/api/novel/event/getEvent", route35); app.use("/api/novel/event/deletEvent", route35);
app.use("/api/novel/getNovel", route36); app.use("/api/novel/event/generateEvents", route36);
app.use("/api/novel/getNovelEventState", route37); app.use("/api/novel/event/getEvent", route37);
app.use("/api/novel/getNovelIndex", route38); app.use("/api/novel/getNovel", route38);
app.use("/api/novel/updateNovel", route39); app.use("/api/novel/getNovelEventState", route39);
app.use("/api/other/deleteAllData", route40); app.use("/api/novel/getNovelIndex", route40);
app.use("/api/other/getVersion", route41); app.use("/api/novel/updateNovel", route41);
app.use("/api/production/assets/getAssetsData", route42); app.use("/api/other/deleteAllData", route42);
app.use("/api/production/editImage/generateFlowImage", route43); app.use("/api/other/getVersion", route43);
app.use("/api/production/editImage/getImageFlow", route44); app.use("/api/production/assets/getAssetsData", route44);
app.use("/api/production/editImage/saveImageFlow", route45); app.use("/api/production/editImage/generateFlowImage", route45);
app.use("/api/production/editImage/updateImageFlow", route46); app.use("/api/production/editImage/getImageFlow", route46);
app.use("/api/production/exportImage", route47); app.use("/api/production/editImage/saveImageFlow", route47);
app.use("/api/production/getFlowData", route48); app.use("/api/production/editImage/updateImageFlow", route48);
app.use("/api/production/getProductionData", route49); app.use("/api/production/exportImage", route49);
app.use("/api/production/getStoryboardData", route50); app.use("/api/production/getFlowData", route50);
app.use("/api/production/saveFlowData", route51); app.use("/api/production/getProductionData", route51);
app.use("/api/production/storyboard/downPreviewImage", route52); app.use("/api/production/getStoryboardData", route52);
app.use("/api/production/storyboard/getStoryboardData", route53); app.use("/api/production/saveFlowData", route53);
app.use("/api/production/storyboard/previewImage", route54); app.use("/api/production/storyboard/downPreviewImage", route54);
app.use("/api/production/workbench/confirmSelection", route55); app.use("/api/production/storyboard/getStoryboardData", route55);
app.use("/api/production/workbench/delVideo", route56); app.use("/api/production/storyboard/previewImage", route56);
app.use("/api/production/workbench/generateVideo", route57); app.use("/api/production/workbench/confirmSelection", route57);
app.use("/api/production/workbench/getChatLines", route58); app.use("/api/production/workbench/delVideo", route58);
app.use("/api/production/workbench/getVideoModelDetail", route59); app.use("/api/production/workbench/generateVideo", route59);
app.use("/api/production/workbench/videoPolling", route60); app.use("/api/production/workbench/getChatLines", route60);
app.use("/api/project/addProject", route61); app.use("/api/production/workbench/getVideoModelDetail", route61);
app.use("/api/project/delProject", route62); app.use("/api/production/workbench/videoPolling", route62);
app.use("/api/project/editProject", route63); app.use("/api/project/addProject", route63);
app.use("/api/project/getProject", route64); app.use("/api/project/delProject", route64);
app.use("/api/script/addScript", route65); app.use("/api/project/editProject", route65);
app.use("/api/script/delScript", route66); app.use("/api/project/getProject", route66);
app.use("/api/script/exportScript", route67); app.use("/api/script/addScript", route67);
app.use("/api/script/extractAssets", route68); app.use("/api/script/delScript", route68);
app.use("/api/script/getScrptApi", route69); app.use("/api/script/exportScript", route69);
app.use("/api/script/pollScriptAssets", route70); app.use("/api/script/extractAssets", route70);
app.use("/api/script/updateScript", route71); app.use("/api/script/getScrptApi", route71);
app.use("/api/scriptAgent/getPlanData", route72); app.use("/api/script/pollScriptAssets", route72);
app.use("/api/scriptAgent/setPlanData", route73); app.use("/api/script/updateScript", route73);
app.use("/api/setting/about/checkUpdate", route74); app.use("/api/scriptAgent/getPlanData", route74);
app.use("/api/setting/about/downloadApp", route75); app.use("/api/scriptAgent/setPlanData", route75);
app.use("/api/setting/agentDeploy/agentSetKey", route76); app.use("/api/setting/about/checkUpdate", route76);
app.use("/api/setting/agentDeploy/deployAgentModel", route77); app.use("/api/setting/about/downloadApp", route77);
app.use("/api/setting/agentDeploy/getAgentDeploy", route78); app.use("/api/setting/agentDeploy/agentSetKey", route78);
app.use("/api/setting/dbConfig/clearData", route79); app.use("/api/setting/agentDeploy/deployAgentModel", route79);
app.use("/api/setting/dev/getSwitchAiDevTool", route80); app.use("/api/setting/agentDeploy/getAgentDeploy", route80);
app.use("/api/setting/dev/updateSwitchAiDevTool", route81); app.use("/api/setting/dbConfig/clearData", route81);
app.use("/api/setting/fileManagement/openFolder", route82); app.use("/api/setting/dev/getSwitchAiDevTool", route82);
app.use("/api/setting/getTextModel", route83); app.use("/api/setting/dev/updateSwitchAiDevTool", route83);
app.use("/api/setting/loginConfig/getUser", route84); app.use("/api/setting/fileManagement/openFolder", route84);
app.use("/api/setting/loginConfig/updateUserPwd", route85); app.use("/api/setting/getTextModel", route85);
app.use("/api/setting/memoryConfig/delAllMemory", route86); app.use("/api/setting/loginConfig/getUser", route86);
app.use("/api/setting/memoryConfig/getMemory", route87); app.use("/api/setting/loginConfig/updateUserPwd", route87);
app.use("/api/setting/memoryConfig/sureMemory", route88); app.use("/api/setting/memoryConfig/delAllMemory", route88);
app.use("/api/setting/skillManagement/addSkill", route89); app.use("/api/setting/memoryConfig/getMemory", route89);
app.use("/api/setting/skillManagement/deleteSkill", route90); app.use("/api/setting/memoryConfig/sureMemory", route90);
app.use("/api/setting/skillManagement/embeddingSkill", route91); app.use("/api/setting/skillManagement/addSkill", route91);
app.use("/api/setting/skillManagement/generateDescription", route92); app.use("/api/setting/skillManagement/deleteSkill", route92);
app.use("/api/setting/skillManagement/getSkillList", route93); app.use("/api/setting/skillManagement/embeddingSkill", route93);
app.use("/api/setting/skillManagement/scanSkills", route94); app.use("/api/setting/skillManagement/generateDescription", route94);
app.use("/api/setting/skillManagement/updateSkill", route95); app.use("/api/setting/skillManagement/getSkillList", route95);
app.use("/api/setting/vendorConfig/addVendor", route96); app.use("/api/setting/skillManagement/scanSkills", route96);
app.use("/api/setting/vendorConfig/deleteVendor", route97); app.use("/api/setting/skillManagement/updateSkill", route97);
app.use("/api/setting/vendorConfig/getVendorList", route98); app.use("/api/setting/vendorConfig/addVendor", route98);
app.use("/api/setting/vendorConfig/modelTest", route99); app.use("/api/setting/vendorConfig/deleteVendor", route99);
app.use("/api/setting/vendorConfig/updateCode", route100); app.use("/api/setting/vendorConfig/getVendorList", route100);
app.use("/api/setting/vendorConfig/updateVendor", route101); app.use("/api/setting/vendorConfig/modelTest", route101);
app.use("/api/task/getProject", route102); app.use("/api/setting/vendorConfig/updateCode", route102);
app.use("/api/task/getTaskApi", route103); app.use("/api/setting/vendorConfig/updateVendor", route103);
app.use("/api/task/getTaskCategories", route104); app.use("/api/task/getProject", route104);
app.use("/api/task/taskDetails", route105); app.use("/api/task/getTaskApi", route105);
app.use("/api/test/test", route106); app.use("/api/task/getTaskCategories", route106);
app.use("/api/task/taskDetails", route107);
app.use("/api/test/test", route108);
} }

View File

@ -0,0 +1,169 @@
import express from "express";
import pLimit from "p-limit";
import u from "@/utils";
import { z } from "zod";
import { v4 as uuidv4 } from "uuid";
import { error, success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
const router = express.Router();
type AssetType = "role" | "scene" | "tool";
interface AssetTypeConfig {
label: string;
taskClass: string;
dir: string;
promptTitle: string;
promptEnd: string;
}
const assetTypeConfig: Record<AssetType, AssetTypeConfig> = {
role: {
label: "角色",
taskClass: "角色图生成",
dir: "role",
promptTitle: "角色标准四视图",
promptEnd: "人物角色四视图",
},
scene: {
label: "场景",
taskClass: "场景图生成",
dir: "scene",
promptTitle: "标准场景图",
promptEnd: "标准场景图",
},
tool: {
label: "道具",
taskClass: "道具图生成",
dir: "props",
promptTitle: "标准道具图",
promptEnd: "标准道具图",
},
};
function buildPrompt(cfg: AssetTypeConfig, artStyle: string, name: string, prompt: string): string {
return `
${cfg.promptTitle}
****
- 画风风格: ${artStyle || "未指定"}
**${cfg.label}**
- 名称:${name},
- 提示词:${prompt},
${cfg.promptEnd}
`;
}
const requestSchema = {
projectId: z.number(),
model: z.string(),
resolution: z.string(),
concurrentCount: z.number().int().min(1).optional(),
items: z.array(
z.object({
id: z.number(),
type: z.enum(["role", "scene", "tool", "storyboard"]),
name: z.string(),
prompt: z.string(),
base64: z.string().optional().nullable(),
}),
),
};
export default router.post("/", validateFields(requestSchema), async (req, res) => {
const { projectId, model, resolution, concurrentCount, items } = req.body;
// 1. 查询项目
const project = await u.db("o_project").where("id", projectId).select("artStyle", "type", "intro").first();
if (!project) return res.status(500).send(error("项目为空"));
// 2. 逐条插入 o_image 占位记录,收集 imageId 列表
const totalNovelId: number[] = [];
for (const item of items) {
const [imageId] = await u.db("o_image").insert({
type: item.type,
state: "生成中",
assetsId: item.id,
});
totalNovelId.push(imageId);
}
// 3. 按并发数限制并发生成
const limit = pLimit(concurrentCount ?? 1);
const results: { assetsId: number; success: boolean; path?: string; message?: string }[] = [];
const tasks = items.map((item: { id: number; type: string; name: string; prompt: string; base64: string | null | undefined }, index: number) =>
limit(async () => {
const imageId = totalNovelId[index];
const cfg = assetTypeConfig[item.type as AssetType];
if (!cfg) {
results.push({ assetsId: item.id, success: false, message: `不支持的类型: ${item.type}` });
return;
}
await u.db("o_assets").where("id", item.id).update({ imageId });
const imagePath = `/${projectId}/${cfg.dir}/${uuidv4()}.jpg`;
const userPrompt = buildPrompt(cfg, project.artStyle ?? "", item.name, item.prompt);
const describe = `生成${cfg.label}图,名称:${item.name},提示词:${item.prompt}`;
const relatedObjects = { id: item.id, projectId, type: cfg.label };
try {
const aiImage = u.Ai.Image(model);
await aiImage.run({
prompt: userPrompt,
imageBase64: item.base64 ? [item.base64] : [],
size: resolution,
aspectRatio: "16:9",
taskClass: cfg.taskClass,
describe,
projectId,
relatedObjects: JSON.stringify(relatedObjects),
});
aiImage.save(imagePath);
const imageData = await u.db("o_image").where("id", imageId).select("*").first();
if (!imageData) {
results.push({ assetsId: item.id, success: false, message: "资产已被删除" });
return;
}
await u
.db("o_image")
.where("id", imageId)
.update({
state: "已完成",
filePath: imagePath,
type: item.type,
model: model.split(":")[1],
resolution,
});
const path = await u.oss.getFileUrl(imagePath);
await u.db("o_assets").where("id", item.id).update({ imageId });
results.push({ assetsId: item.id, success: true, path });
} catch (e: any) {
await u.db("o_image").where("id", imageId).update({ state: "生成失败" });
results.push({ assetsId: item.id, success: false, message: u.error(e).message || "图片生成失败" });
}
}),
);
await Promise.all(tasks);
const successCount = results.filter((r) => r.success).length;
const failCount = results.filter((r) => !r.success).length;
return res.status(200).send(
success({
total: items.length,
successCount,
failCount,
results,
}),
);
});

View File

@ -0,0 +1,161 @@
import express from "express";
import u from "@/utils";
import pLimit from "p-limit";
import * as zod from "zod";
import { error, success } from "@/lib/responseFormat";
import { validateFields } from "@/middleware/middleware";
import { useSkill } from "@/utils/agent/skillsTools";
const router = express.Router();
interface OutlineItem {
description: string;
name: string;
}
interface OutlineData {
chapterRange: number[];
characters?: OutlineItem[];
props?: OutlineItem[];
scenes?: OutlineItem[];
}
interface NovelChapter {
id: number;
reel: string;
chapter: string;
chapterData: string;
projectId: number;
}
type ItemType = "characters" | "props" | "scenes";
interface ResultItem {
type: ItemType;
name: string;
chapterRange: number[];
}
function findItemByName(items: ResultItem[], name: string, type?: ItemType): ResultItem | undefined {
return items.find((item) => (!type || item.type === type) && item.name === name);
}
function mergeNovelText(novelData: NovelChapter[]): string {
if (!Array.isArray(novelData)) return "";
return novelData
.map((chap) => {
return `${chap.chapter.trim()}\n\n${chap.chapterData.trim().replace(/\r?\n/g, "\n")}\n`;
})
.join("\n");
}
//润色提示词
export default router.post(
"/",
validateFields({
items: zod.array(
zod.object({
assetsId: zod.number(),
type: zod.string(),
name: zod.string(),
describe: zod.string(),
}),
),
projectId: zod.number(),
concurrentCount: zod.number().int().min(1).optional(),
}),
async (req, res) => {
const { projectId, items, concurrentCount } = req.body;
//获取风格
const project = await u.db("o_project").where("id", projectId).select("artStyle", "type", "intro").first();
//如果没有找到对应的项目,返回错误
if (!project) return res.status(500).send(success({ message: "项目为空" }));
// 预加载公共数据
const allOutlineDataList: { data: string }[] = await u.db("o_outline").where("projectId", projectId).select("data");
const itemMap: Record<string, ResultItem> = {};
if (allOutlineDataList.length > 0)
allOutlineDataList.forEach((row) => {
const data: OutlineData = JSON.parse(row?.data || "{}");
(["characters", "props", "scenes"] as ItemType[]).forEach((type) => {
(data[type] || []).forEach((item) => {
const key = `${type}-${item.name}`;
if (!itemMap[key]) {
itemMap[key] = { type, name: item.name, chapterRange: [...(data.chapterRange || [])] };
} else {
itemMap[key].chapterRange = Array.from(new Set([...itemMap[key].chapterRange, ...(data.chapterRange || [])]));
}
});
});
});
const result: ResultItem[] = Object.values(itemMap);
const typeConfig: Record<string, { promptKey: string; itemType: ItemType; label: string; nameLabel: string }> = {
role: { promptKey: "role-polish", itemType: "characters", label: "角色标准四视图", nameLabel: "角色" },
scene: { promptKey: "scene-polish", itemType: "scenes", label: "场景图", nameLabel: "场景" },
tool: { promptKey: "tool-polish", itemType: "props", label: "道具图", nameLabel: "道具" },
};
const novelData = (await u.db("o_novel").whereIn("chapterIndex", [1]).select("*")) as NovelChapter[];
const novelText = mergeNovelText(novelData);
const skill = await useSkill("universal_agent.md");
// 批量更新所有 item 状态为生成中
const assetsIds = items.map((item: { assetsId: number }) => item.assetsId);
await u.db("o_assets").whereIn("id", assetsIds).update({ promptState: "生成中" });
// 按并发数限制并发生成
const limit = pLimit(concurrentCount ?? 1);
const results: { assetsId: number; success: boolean; prompt?: string; message?: string }[] = [];
const tasks = items.map((item: { assetsId: number; type: string; name: string; describe: string }) =>
limit(async () => {
const config = typeConfig[item.type];
if (!config) {
results.push({ assetsId: item.assetsId, success: false, message: "不支持的类型" });
return;
}
findItemByName(result, item.name, config.itemType);
const systemPrompt = `${skill.prompt}
${config.label}
****
- 风格: ${project?.artStyle || "未指定"}
- 小说类型: ${project?.type || "未指定"}
- 小说背景: ${project?.intro || "未指定"}
**${config.nameLabel}**
- ${config.nameLabel}名称:${item.name},
- ${config.nameLabel}描述:${item.describe},
skill规范生成${item.type === "role" ? "人物角色四视图" : config.label}
`;
try {
const { _output } = (await u.Ai.Text("universalAgent").invoke({
system: systemPrompt,
messages: [{ role: "user", content: "小说原文" + novelText }],
tools: skill.tools,
})) as any;
if (!_output) {
results.push({ assetsId: item.assetsId, success: false, message: "生成结果为空" });
await u.db("o_assets").where("id", item.assetsId).update({ promptState: "生成失败" });
return;
}
await u.db("o_assets").where("id", item.assetsId).update({ prompt: _output, promptState: "已完成" });
results.push({ assetsId: item.assetsId, success: true, prompt: _output });
} catch (e: any) {
await u.db("o_assets").where("id", item.assetsId).update({ promptState: "生成失败" });
results.push({ assetsId: item.assetsId, success: false, message: e?.data?.error?.message ?? e?.message ?? "生成失败" });
}
}),
);
await Promise.all(tasks);
const successCount = results.filter((r) => r.success).length;
const failCount = results.filter((r) => !r.success).length;
return res.status(200).send(success({ total: items.length, successCount, failCount, results }));
},
);

View File

@ -61,18 +61,18 @@ function buildPrompt(cfg: AssetTypeConfig, artStyle: string, name: string, promp
// ─── 生成资产图片 ──────────────────────────────────────────── // ─── 生成资产图片 ────────────────────────────────────────────
const requestSchema = { const requestSchema = {
id: z.number(),
type: z.enum(["role", "scene", "tool", "storyboard"]),
projectId: z.number(), projectId: z.number(),
name: z.string(),
base64: z.string().optional().nullable(),
prompt: z.string(),
model: z.string(), model: z.string(),
resolution: z.string(), resolution: z.string(),
id: z.number(),
type: z.enum(["role", "scene", "tool", "storyboard"]),
name: z.string(),
prompt: z.string(),
base64: z.string().optional().nullable(),
}; };
export default router.post("/", validateFields(requestSchema), async (req, res) => { export default router.post("/", validateFields(requestSchema), async (req, res) => {
const { id, type, projectId, base64, prompt, name, model, resolution } = req.body; const { projectId, model, resolution, id, type, name, prompt, base64 } = req.body;
// 1. 查询项目 & 获取类型配置 // 1. 查询项目 & 获取类型配置
const project = await u.db("o_project").where("id", projectId).select("artStyle", "type", "intro").first(); const project = await u.db("o_project").where("id", projectId).select("artStyle", "type", "intro").first();
@ -87,7 +87,7 @@ export default router.post("/", validateFields(requestSchema), async (req, res)
state: "生成中", state: "生成中",
assetsId: id, assetsId: id,
}); });
await u.db("o_assets").where("id", id).update({ imageId }); await u.db("o_assets").where("id", id).update({ imageId });
// 3. 准备生成参数 // 3. 准备生成参数
const imagePath = `/${projectId}/${cfg.dir}/${uuidv4()}.jpg`; const imagePath = `/${projectId}/${cfg.dir}/${uuidv4()}.jpg`;
@ -107,20 +107,23 @@ export default router.post("/", validateFields(requestSchema), async (req, res)
describe, describe,
projectId, projectId,
relatedObjects: JSON.stringify(relatedObjects), relatedObjects: JSON.stringify(relatedObjects),
}) });
aiImage.save(imagePath); aiImage.save(imagePath);
// 5. 更新记录 & 返回结果 // 5. 更新记录 & 返回结果
const imageData = await u.db("o_image").where("id", imageId).select("*").first(); const imageData = await u.db("o_image").where("id", imageId).select("*").first();
if (!imageData) return res.status(500).send("资产已被删除"); if (!imageData) return res.status(500).send("资产已被删除");
await u.db("o_image").where("id", imageId).update({ await u
state: "已完成", .db("o_image")
filePath: imagePath, .where("id", imageId)
type, .update({
model: model.split(":")[1], state: "已完成",
resolution, filePath: imagePath,
}); type,
model: model.split(":")[1],
resolution,
});
const path = await u.oss.getFileUrl(imagePath); const path = await u.oss.getFileUrl(imagePath);
await u.db("o_assets").where("id", id).update({ imageId }); await u.db("o_assets").where("id", id).update({ imageId });

View File

@ -1,20 +1,12 @@
// @db-hash 662752a8a62a88e2dc636b6d985d3b87 // @db-hash 05ecfd675f848d88631c1a546996caea
//该文件由脚本自动生成,请勿手动修改 //该文件由脚本自动生成,请勿手动修改
export interface _o_script_old_20260327 {
'content'?: string | null;
'createTime'?: number | null;
'id'?: number;
'name'?: string | null;
'projectId'?: number | null;
}
export interface memories { export interface memories {
'content': string; 'content': string;
'createTime': number; 'createTime': number;
'embedding'?: string | null; 'embedding'?: string | null;
'id'?: string; 'id'?: string;
'isolationKey': string; 'isolationKey': string;
'name'?: string | null;
'relatedMessageIds'?: string | null; 'relatedMessageIds'?: string | null;
'role'?: string | null; 'role'?: string | null;
'summarized'?: number | null; 'summarized'?: number | null;
@ -54,6 +46,7 @@ export interface o_assets {
'name'?: string | null; 'name'?: string | null;
'projectId'?: number | null; 'projectId'?: number | null;
'prompt'?: string | null; 'prompt'?: string | null;
'promptState'?: string | null;
'remark'?: string | null; 'remark'?: string | null;
'scriptId'?: number | null; 'scriptId'?: number | null;
'startTime'?: number | null; 'startTime'?: number | null;
@ -128,7 +121,7 @@ export interface o_project {
export interface o_prompt { export interface o_prompt {
'id'?: number; 'id'?: number;
'name'?: string | null; 'name'?: string | null;
'rompt'?: string | null; 'prompt'?: string | null;
} }
export interface o_script { export interface o_script {
'content'?: string | null; 'content'?: string | null;
@ -236,7 +229,6 @@ export interface o_videoConfig {
} }
export interface DB { export interface DB {
"_o_script_old_20260327": _o_script_old_20260327;
"memories": memories; "memories": memories;
"o_agentDeploy": o_agentDeploy; "o_agentDeploy": o_agentDeploy;
"o_agentWorkData": o_agentWorkData; "o_agentWorkData": o_agentWorkData;