资产图片资产提示词添加轮询api

This commit is contained in:
小帅 2026-03-27 23:55:59 +08:00
parent 3bcd265c72
commit 353ee38a2e
5 changed files with 532 additions and 193 deletions

View File

@ -1,4 +1,4 @@
// @routes-hash cf18bce0fd0b7cd4d351d3c319cc7205
// @routes-hash 7027f20b3def330f442689eb22769f31
import { Express } from "express";
import route1 from "./routes/agents/clearMemory";
@ -19,94 +19,96 @@ import route15 from "./routes/assets/pollingPromptAssets";
import route16 from "./routes/assets/saveAssets";
import route17 from "./routes/assets/updateAssets";
import route18 from "./routes/assets/uploadClip";
import route19 from "./routes/assetsGenerate/generateAssets";
import route20 from "./routes/assetsGenerate/polishAssetsPrompt";
import route21 from "./routes/cornerScape/getAllAssets";
import route22 from "./routes/general/generalStatistics";
import route23 from "./routes/general/getSingleProject";
import route24 from "./routes/general/updateProject";
import route25 from "./routes/login/login";
import route26 from "./routes/migrate/migrateData";
import route27 from "./routes/modelSelect/getModelDetail";
import route28 from "./routes/modelSelect/getModelList";
import route29 from "./routes/novel/addNovel";
import route30 from "./routes/novel/batchDeleteNovel";
import route31 from "./routes/novel/delNovel";
import route32 from "./routes/novel/event/batchDeleteEvent";
import route33 from "./routes/novel/event/deletEvent";
import route34 from "./routes/novel/event/generateEvents";
import route35 from "./routes/novel/event/getEvent";
import route36 from "./routes/novel/getNovel";
import route37 from "./routes/novel/getNovelEventState";
import route38 from "./routes/novel/getNovelIndex";
import route39 from "./routes/novel/updateNovel";
import route40 from "./routes/other/deleteAllData";
import route41 from "./routes/other/getVersion";
import route42 from "./routes/production/assets/getAssetsData";
import route43 from "./routes/production/editImage/generateFlowImage";
import route44 from "./routes/production/editImage/getImageFlow";
import route45 from "./routes/production/editImage/saveImageFlow";
import route46 from "./routes/production/editImage/updateImageFlow";
import route47 from "./routes/production/exportImage";
import route48 from "./routes/production/getFlowData";
import route49 from "./routes/production/getProductionData";
import route50 from "./routes/production/getStoryboardData";
import route51 from "./routes/production/saveFlowData";
import route52 from "./routes/production/storyboard/downPreviewImage";
import route53 from "./routes/production/storyboard/getStoryboardData";
import route54 from "./routes/production/storyboard/previewImage";
import route55 from "./routes/production/workbench/confirmSelection";
import route56 from "./routes/production/workbench/delVideo";
import route57 from "./routes/production/workbench/generateVideo";
import route58 from "./routes/production/workbench/getChatLines";
import route59 from "./routes/production/workbench/getVideoModelDetail";
import route60 from "./routes/production/workbench/videoPolling";
import route61 from "./routes/project/addProject";
import route62 from "./routes/project/delProject";
import route63 from "./routes/project/editProject";
import route64 from "./routes/project/getProject";
import route65 from "./routes/script/addScript";
import route66 from "./routes/script/delScript";
import route67 from "./routes/script/exportScript";
import route68 from "./routes/script/extractAssets";
import route69 from "./routes/script/getScrptApi";
import route70 from "./routes/script/pollScriptAssets";
import route71 from "./routes/script/updateScript";
import route72 from "./routes/scriptAgent/getPlanData";
import route73 from "./routes/scriptAgent/setPlanData";
import route74 from "./routes/setting/about/checkUpdate";
import route75 from "./routes/setting/about/downloadApp";
import route76 from "./routes/setting/agentDeploy/agentSetKey";
import route77 from "./routes/setting/agentDeploy/deployAgentModel";
import route78 from "./routes/setting/agentDeploy/getAgentDeploy";
import route79 from "./routes/setting/dbConfig/clearData";
import route80 from "./routes/setting/dev/getSwitchAiDevTool";
import route81 from "./routes/setting/dev/updateSwitchAiDevTool";
import route82 from "./routes/setting/fileManagement/openFolder";
import route83 from "./routes/setting/getTextModel";
import route84 from "./routes/setting/loginConfig/getUser";
import route85 from "./routes/setting/loginConfig/updateUserPwd";
import route86 from "./routes/setting/memoryConfig/delAllMemory";
import route87 from "./routes/setting/memoryConfig/getMemory";
import route88 from "./routes/setting/memoryConfig/sureMemory";
import route89 from "./routes/setting/skillManagement/addSkill";
import route90 from "./routes/setting/skillManagement/deleteSkill";
import route91 from "./routes/setting/skillManagement/embeddingSkill";
import route92 from "./routes/setting/skillManagement/generateDescription";
import route93 from "./routes/setting/skillManagement/getSkillList";
import route94 from "./routes/setting/skillManagement/scanSkills";
import route95 from "./routes/setting/skillManagement/updateSkill";
import route96 from "./routes/setting/vendorConfig/addVendor";
import route97 from "./routes/setting/vendorConfig/deleteVendor";
import route98 from "./routes/setting/vendorConfig/getVendorList";
import route99 from "./routes/setting/vendorConfig/modelTest";
import route100 from "./routes/setting/vendorConfig/updateCode";
import route101 from "./routes/setting/vendorConfig/updateVendor";
import route102 from "./routes/task/getProject";
import route103 from "./routes/task/getTaskApi";
import route104 from "./routes/task/getTaskCategories";
import route105 from "./routes/task/taskDetails";
import route106 from "./routes/test/test";
import route19 from "./routes/assetsGenerate/batchGenerateImageAssets";
import route20 from "./routes/assetsGenerate/batchPolishAssetsPrompt";
import route21 from "./routes/assetsGenerate/generateAssets";
import route22 from "./routes/assetsGenerate/polishAssetsPrompt";
import route23 from "./routes/cornerScape/getAllAssets";
import route24 from "./routes/general/generalStatistics";
import route25 from "./routes/general/getSingleProject";
import route26 from "./routes/general/updateProject";
import route27 from "./routes/login/login";
import route28 from "./routes/migrate/migrateData";
import route29 from "./routes/modelSelect/getModelDetail";
import route30 from "./routes/modelSelect/getModelList";
import route31 from "./routes/novel/addNovel";
import route32 from "./routes/novel/batchDeleteNovel";
import route33 from "./routes/novel/delNovel";
import route34 from "./routes/novel/event/batchDeleteEvent";
import route35 from "./routes/novel/event/deletEvent";
import route36 from "./routes/novel/event/generateEvents";
import route37 from "./routes/novel/event/getEvent";
import route38 from "./routes/novel/getNovel";
import route39 from "./routes/novel/getNovelEventState";
import route40 from "./routes/novel/getNovelIndex";
import route41 from "./routes/novel/updateNovel";
import route42 from "./routes/other/deleteAllData";
import route43 from "./routes/other/getVersion";
import route44 from "./routes/production/assets/getAssetsData";
import route45 from "./routes/production/editImage/generateFlowImage";
import route46 from "./routes/production/editImage/getImageFlow";
import route47 from "./routes/production/editImage/saveImageFlow";
import route48 from "./routes/production/editImage/updateImageFlow";
import route49 from "./routes/production/exportImage";
import route50 from "./routes/production/getFlowData";
import route51 from "./routes/production/getProductionData";
import route52 from "./routes/production/getStoryboardData";
import route53 from "./routes/production/saveFlowData";
import route54 from "./routes/production/storyboard/downPreviewImage";
import route55 from "./routes/production/storyboard/getStoryboardData";
import route56 from "./routes/production/storyboard/previewImage";
import route57 from "./routes/production/workbench/confirmSelection";
import route58 from "./routes/production/workbench/delVideo";
import route59 from "./routes/production/workbench/generateVideo";
import route60 from "./routes/production/workbench/getChatLines";
import route61 from "./routes/production/workbench/getVideoModelDetail";
import route62 from "./routes/production/workbench/videoPolling";
import route63 from "./routes/project/addProject";
import route64 from "./routes/project/delProject";
import route65 from "./routes/project/editProject";
import route66 from "./routes/project/getProject";
import route67 from "./routes/script/addScript";
import route68 from "./routes/script/delScript";
import route69 from "./routes/script/exportScript";
import route70 from "./routes/script/extractAssets";
import route71 from "./routes/script/getScrptApi";
import route72 from "./routes/script/pollScriptAssets";
import route73 from "./routes/script/updateScript";
import route74 from "./routes/scriptAgent/getPlanData";
import route75 from "./routes/scriptAgent/setPlanData";
import route76 from "./routes/setting/about/checkUpdate";
import route77 from "./routes/setting/about/downloadApp";
import route78 from "./routes/setting/agentDeploy/agentSetKey";
import route79 from "./routes/setting/agentDeploy/deployAgentModel";
import route80 from "./routes/setting/agentDeploy/getAgentDeploy";
import route81 from "./routes/setting/dbConfig/clearData";
import route82 from "./routes/setting/dev/getSwitchAiDevTool";
import route83 from "./routes/setting/dev/updateSwitchAiDevTool";
import route84 from "./routes/setting/fileManagement/openFolder";
import route85 from "./routes/setting/getTextModel";
import route86 from "./routes/setting/loginConfig/getUser";
import route87 from "./routes/setting/loginConfig/updateUserPwd";
import route88 from "./routes/setting/memoryConfig/delAllMemory";
import route89 from "./routes/setting/memoryConfig/getMemory";
import route90 from "./routes/setting/memoryConfig/sureMemory";
import route91 from "./routes/setting/skillManagement/addSkill";
import route92 from "./routes/setting/skillManagement/deleteSkill";
import route93 from "./routes/setting/skillManagement/embeddingSkill";
import route94 from "./routes/setting/skillManagement/generateDescription";
import route95 from "./routes/setting/skillManagement/getSkillList";
import route96 from "./routes/setting/skillManagement/scanSkills";
import route97 from "./routes/setting/skillManagement/updateSkill";
import route98 from "./routes/setting/vendorConfig/addVendor";
import route99 from "./routes/setting/vendorConfig/deleteVendor";
import route100 from "./routes/setting/vendorConfig/getVendorList";
import route101 from "./routes/setting/vendorConfig/modelTest";
import route102 from "./routes/setting/vendorConfig/updateCode";
import route103 from "./routes/setting/vendorConfig/updateVendor";
import route104 from "./routes/task/getProject";
import route105 from "./routes/task/getTaskApi";
import route106 from "./routes/task/getTaskCategories";
import route107 from "./routes/task/taskDetails";
import route108 from "./routes/test/test";
export default async (app: Express) => {
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/updateAssets", route17);
app.use("/api/assets/uploadClip", route18);
app.use("/api/assetsGenerate/generateAssets", route19);
app.use("/api/assetsGenerate/polishAssetsPrompt", route20);
app.use("/api/cornerScape/getAllAssets", route21);
app.use("/api/general/generalStatistics", route22);
app.use("/api/general/getSingleProject", route23);
app.use("/api/general/updateProject", route24);
app.use("/api/login/login", route25);
app.use("/api/migrate/migrateData", route26);
app.use("/api/modelSelect/getModelDetail", route27);
app.use("/api/modelSelect/getModelList", route28);
app.use("/api/novel/addNovel", route29);
app.use("/api/novel/batchDeleteNovel", route30);
app.use("/api/novel/delNovel", route31);
app.use("/api/novel/event/batchDeleteEvent", route32);
app.use("/api/novel/event/deletEvent", route33);
app.use("/api/novel/event/generateEvents", route34);
app.use("/api/novel/event/getEvent", route35);
app.use("/api/novel/getNovel", route36);
app.use("/api/novel/getNovelEventState", route37);
app.use("/api/novel/getNovelIndex", route38);
app.use("/api/novel/updateNovel", route39);
app.use("/api/other/deleteAllData", route40);
app.use("/api/other/getVersion", route41);
app.use("/api/production/assets/getAssetsData", route42);
app.use("/api/production/editImage/generateFlowImage", route43);
app.use("/api/production/editImage/getImageFlow", route44);
app.use("/api/production/editImage/saveImageFlow", route45);
app.use("/api/production/editImage/updateImageFlow", route46);
app.use("/api/production/exportImage", route47);
app.use("/api/production/getFlowData", route48);
app.use("/api/production/getProductionData", route49);
app.use("/api/production/getStoryboardData", route50);
app.use("/api/production/saveFlowData", route51);
app.use("/api/production/storyboard/downPreviewImage", route52);
app.use("/api/production/storyboard/getStoryboardData", route53);
app.use("/api/production/storyboard/previewImage", route54);
app.use("/api/production/workbench/confirmSelection", route55);
app.use("/api/production/workbench/delVideo", route56);
app.use("/api/production/workbench/generateVideo", route57);
app.use("/api/production/workbench/getChatLines", route58);
app.use("/api/production/workbench/getVideoModelDetail", route59);
app.use("/api/production/workbench/videoPolling", route60);
app.use("/api/project/addProject", route61);
app.use("/api/project/delProject", route62);
app.use("/api/project/editProject", route63);
app.use("/api/project/getProject", route64);
app.use("/api/script/addScript", route65);
app.use("/api/script/delScript", route66);
app.use("/api/script/exportScript", route67);
app.use("/api/script/extractAssets", route68);
app.use("/api/script/getScrptApi", route69);
app.use("/api/script/pollScriptAssets", route70);
app.use("/api/script/updateScript", route71);
app.use("/api/scriptAgent/getPlanData", route72);
app.use("/api/scriptAgent/setPlanData", route73);
app.use("/api/setting/about/checkUpdate", route74);
app.use("/api/setting/about/downloadApp", route75);
app.use("/api/setting/agentDeploy/agentSetKey", route76);
app.use("/api/setting/agentDeploy/deployAgentModel", route77);
app.use("/api/setting/agentDeploy/getAgentDeploy", route78);
app.use("/api/setting/dbConfig/clearData", route79);
app.use("/api/setting/dev/getSwitchAiDevTool", route80);
app.use("/api/setting/dev/updateSwitchAiDevTool", route81);
app.use("/api/setting/fileManagement/openFolder", route82);
app.use("/api/setting/getTextModel", route83);
app.use("/api/setting/loginConfig/getUser", route84);
app.use("/api/setting/loginConfig/updateUserPwd", route85);
app.use("/api/setting/memoryConfig/delAllMemory", route86);
app.use("/api/setting/memoryConfig/getMemory", route87);
app.use("/api/setting/memoryConfig/sureMemory", route88);
app.use("/api/setting/skillManagement/addSkill", route89);
app.use("/api/setting/skillManagement/deleteSkill", route90);
app.use("/api/setting/skillManagement/embeddingSkill", route91);
app.use("/api/setting/skillManagement/generateDescription", route92);
app.use("/api/setting/skillManagement/getSkillList", route93);
app.use("/api/setting/skillManagement/scanSkills", route94);
app.use("/api/setting/skillManagement/updateSkill", route95);
app.use("/api/setting/vendorConfig/addVendor", route96);
app.use("/api/setting/vendorConfig/deleteVendor", route97);
app.use("/api/setting/vendorConfig/getVendorList", route98);
app.use("/api/setting/vendorConfig/modelTest", route99);
app.use("/api/setting/vendorConfig/updateCode", route100);
app.use("/api/setting/vendorConfig/updateVendor", route101);
app.use("/api/task/getProject", route102);
app.use("/api/task/getTaskApi", route103);
app.use("/api/task/getTaskCategories", route104);
app.use("/api/task/taskDetails", route105);
app.use("/api/test/test", route106);
app.use("/api/assetsGenerate/batchGenerateImageAssets", route19);
app.use("/api/assetsGenerate/batchPolishAssetsPrompt", route20);
app.use("/api/assetsGenerate/generateAssets", route21);
app.use("/api/assetsGenerate/polishAssetsPrompt", route22);
app.use("/api/cornerScape/getAllAssets", route23);
app.use("/api/general/generalStatistics", route24);
app.use("/api/general/getSingleProject", route25);
app.use("/api/general/updateProject", route26);
app.use("/api/login/login", route27);
app.use("/api/migrate/migrateData", route28);
app.use("/api/modelSelect/getModelDetail", route29);
app.use("/api/modelSelect/getModelList", route30);
app.use("/api/novel/addNovel", route31);
app.use("/api/novel/batchDeleteNovel", route32);
app.use("/api/novel/delNovel", route33);
app.use("/api/novel/event/batchDeleteEvent", route34);
app.use("/api/novel/event/deletEvent", route35);
app.use("/api/novel/event/generateEvents", route36);
app.use("/api/novel/event/getEvent", route37);
app.use("/api/novel/getNovel", route38);
app.use("/api/novel/getNovelEventState", route39);
app.use("/api/novel/getNovelIndex", route40);
app.use("/api/novel/updateNovel", route41);
app.use("/api/other/deleteAllData", route42);
app.use("/api/other/getVersion", route43);
app.use("/api/production/assets/getAssetsData", route44);
app.use("/api/production/editImage/generateFlowImage", route45);
app.use("/api/production/editImage/getImageFlow", route46);
app.use("/api/production/editImage/saveImageFlow", route47);
app.use("/api/production/editImage/updateImageFlow", route48);
app.use("/api/production/exportImage", route49);
app.use("/api/production/getFlowData", route50);
app.use("/api/production/getProductionData", route51);
app.use("/api/production/getStoryboardData", route52);
app.use("/api/production/saveFlowData", route53);
app.use("/api/production/storyboard/downPreviewImage", route54);
app.use("/api/production/storyboard/getStoryboardData", route55);
app.use("/api/production/storyboard/previewImage", route56);
app.use("/api/production/workbench/confirmSelection", route57);
app.use("/api/production/workbench/delVideo", route58);
app.use("/api/production/workbench/generateVideo", route59);
app.use("/api/production/workbench/getChatLines", route60);
app.use("/api/production/workbench/getVideoModelDetail", route61);
app.use("/api/production/workbench/videoPolling", route62);
app.use("/api/project/addProject", route63);
app.use("/api/project/delProject", route64);
app.use("/api/project/editProject", route65);
app.use("/api/project/getProject", route66);
app.use("/api/script/addScript", route67);
app.use("/api/script/delScript", route68);
app.use("/api/script/exportScript", route69);
app.use("/api/script/extractAssets", route70);
app.use("/api/script/getScrptApi", route71);
app.use("/api/script/pollScriptAssets", route72);
app.use("/api/script/updateScript", route73);
app.use("/api/scriptAgent/getPlanData", route74);
app.use("/api/scriptAgent/setPlanData", route75);
app.use("/api/setting/about/checkUpdate", route76);
app.use("/api/setting/about/downloadApp", route77);
app.use("/api/setting/agentDeploy/agentSetKey", route78);
app.use("/api/setting/agentDeploy/deployAgentModel", route79);
app.use("/api/setting/agentDeploy/getAgentDeploy", route80);
app.use("/api/setting/dbConfig/clearData", route81);
app.use("/api/setting/dev/getSwitchAiDevTool", route82);
app.use("/api/setting/dev/updateSwitchAiDevTool", route83);
app.use("/api/setting/fileManagement/openFolder", route84);
app.use("/api/setting/getTextModel", route85);
app.use("/api/setting/loginConfig/getUser", route86);
app.use("/api/setting/loginConfig/updateUserPwd", route87);
app.use("/api/setting/memoryConfig/delAllMemory", route88);
app.use("/api/setting/memoryConfig/getMemory", route89);
app.use("/api/setting/memoryConfig/sureMemory", route90);
app.use("/api/setting/skillManagement/addSkill", route91);
app.use("/api/setting/skillManagement/deleteSkill", route92);
app.use("/api/setting/skillManagement/embeddingSkill", route93);
app.use("/api/setting/skillManagement/generateDescription", route94);
app.use("/api/setting/skillManagement/getSkillList", route95);
app.use("/api/setting/skillManagement/scanSkills", route96);
app.use("/api/setting/skillManagement/updateSkill", route97);
app.use("/api/setting/vendorConfig/addVendor", route98);
app.use("/api/setting/vendorConfig/deleteVendor", route99);
app.use("/api/setting/vendorConfig/getVendorList", route100);
app.use("/api/setting/vendorConfig/modelTest", route101);
app.use("/api/setting/vendorConfig/updateCode", route102);
app.use("/api/setting/vendorConfig/updateVendor", route103);
app.use("/api/task/getProject", route104);
app.use("/api/task/getTaskApi", route105);
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 = {
id: z.number(),
type: z.enum(["role", "scene", "tool", "storyboard"]),
projectId: z.number(),
name: z.string(),
base64: z.string().optional().nullable(),
prompt: z.string(),
model: 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) => {
const { id, type, projectId, base64, prompt, name, model, resolution } = req.body;
const { projectId, model, resolution, id, type, name, prompt, base64 } = req.body;
// 1. 查询项目 & 获取类型配置
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: "生成中",
assetsId: id,
});
await u.db("o_assets").where("id", id).update({ imageId });
await u.db("o_assets").where("id", id).update({ imageId });
// 3. 准备生成参数
const imagePath = `/${projectId}/${cfg.dir}/${uuidv4()}.jpg`;
@ -107,20 +107,23 @@ export default router.post("/", validateFields(requestSchema), async (req, res)
describe,
projectId,
relatedObjects: JSON.stringify(relatedObjects),
})
});
aiImage.save(imagePath);
// 5. 更新记录 & 返回结果
const imageData = await u.db("o_image").where("id", imageId).select("*").first();
if (!imageData) return res.status(500).send("资产已被删除");
await u.db("o_image").where("id", imageId).update({
state: "已完成",
filePath: imagePath,
type,
model: model.split(":")[1],
resolution,
});
await u
.db("o_image")
.where("id", imageId)
.update({
state: "已完成",
filePath: imagePath,
type,
model: model.split(":")[1],
resolution,
});
const path = await u.oss.getFileUrl(imagePath);
await u.db("o_assets").where("id", id).update({ imageId });

View File

@ -1,4 +1,4 @@
// @db-hash d07435d983861c95bb42e6e4742ef1c1
// @db-hash 05ecfd675f848d88631c1a546996caea
//该文件由脚本自动生成,请勿手动修改
export interface memories {
@ -126,6 +126,8 @@ export interface o_prompt {
export interface o_script {
'content'?: string | null;
'createTime'?: number | null;
'errorReason'?: string | null;
'extractState'?: number | null;
'id'?: number;
'name'?: string | null;
'projectId'?: number | null;