新增视觉手册
This commit is contained in:
parent
5832c261e4
commit
ae8aa4fe63
@ -0,0 +1 @@
|
|||||||
|
123123
|
||||||
208
src/router.ts
208
src/router.ts
@ -1,4 +1,4 @@
|
|||||||
// @routes-hash 9f9223eb87c107e9ece3145f1b4b254a
|
// @routes-hash ebc81322f1e60446bf41d1ecb72f2b96
|
||||||
import { Express } from "express";
|
import { Express } from "express";
|
||||||
|
|
||||||
import route1 from "./routes/agents/clearMemory";
|
import route1 from "./routes/agents/clearMemory";
|
||||||
@ -65,56 +65,59 @@ import route61 from "./routes/production/workbench/getChatLines";
|
|||||||
import route62 from "./routes/production/workbench/getVideoModelDetail";
|
import route62 from "./routes/production/workbench/getVideoModelDetail";
|
||||||
import route63 from "./routes/production/workbench/videoPolling";
|
import route63 from "./routes/production/workbench/videoPolling";
|
||||||
import route64 from "./routes/project/addProject";
|
import route64 from "./routes/project/addProject";
|
||||||
import route65 from "./routes/project/delProject";
|
import route65 from "./routes/project/addVisual";
|
||||||
import route66 from "./routes/project/editProject";
|
import route66 from "./routes/project/deleteVisualManual";
|
||||||
import route67 from "./routes/project/getProject";
|
import route67 from "./routes/project/delProject";
|
||||||
import route68 from "./routes/project/getVisualManual";
|
import route68 from "./routes/project/editProject";
|
||||||
import route69 from "./routes/project/visualManual";
|
import route69 from "./routes/project/editVisualManual";
|
||||||
import route70 from "./routes/script/addScript";
|
import route70 from "./routes/project/getProject";
|
||||||
import route71 from "./routes/script/delScript";
|
import route71 from "./routes/project/getVisualManual";
|
||||||
import route72 from "./routes/script/exportScript";
|
import route72 from "./routes/project/visualManual";
|
||||||
import route73 from "./routes/script/extractAssets";
|
import route73 from "./routes/script/addScript";
|
||||||
import route74 from "./routes/script/getScrptApi";
|
import route74 from "./routes/script/delScript";
|
||||||
import route75 from "./routes/script/pollScriptAssets";
|
import route75 from "./routes/script/exportScript";
|
||||||
import route76 from "./routes/script/updateScript";
|
import route76 from "./routes/script/extractAssets";
|
||||||
import route77 from "./routes/scriptAgent/getPlanData";
|
import route77 from "./routes/script/getScrptApi";
|
||||||
import route78 from "./routes/scriptAgent/setPlanData";
|
import route78 from "./routes/script/pollScriptAssets";
|
||||||
import route79 from "./routes/setting/about/checkUpdate";
|
import route79 from "./routes/script/updateScript";
|
||||||
import route80 from "./routes/setting/about/downloadApp";
|
import route80 from "./routes/scriptAgent/getPlanData";
|
||||||
import route81 from "./routes/setting/agentDeploy/agentSetKey";
|
import route81 from "./routes/scriptAgent/setPlanData";
|
||||||
import route82 from "./routes/setting/agentDeploy/deployAgentModel";
|
import route82 from "./routes/setting/about/checkUpdate";
|
||||||
import route83 from "./routes/setting/agentDeploy/getAgentDeploy";
|
import route83 from "./routes/setting/about/downloadApp";
|
||||||
import route84 from "./routes/setting/dbConfig/clearData";
|
import route84 from "./routes/setting/agentDeploy/agentSetKey";
|
||||||
import route85 from "./routes/setting/dev/getSwitchAiDevTool";
|
import route85 from "./routes/setting/agentDeploy/deployAgentModel";
|
||||||
import route86 from "./routes/setting/dev/updateSwitchAiDevTool";
|
import route86 from "./routes/setting/agentDeploy/getAgentDeploy";
|
||||||
import route87 from "./routes/setting/fileManagement/openFolder";
|
import route87 from "./routes/setting/dbConfig/clearData";
|
||||||
import route88 from "./routes/setting/getTextModel";
|
import route88 from "./routes/setting/dev/getSwitchAiDevTool";
|
||||||
import route89 from "./routes/setting/loginConfig/getUser";
|
import route89 from "./routes/setting/dev/updateSwitchAiDevTool";
|
||||||
import route90 from "./routes/setting/loginConfig/updateUserPwd";
|
import route90 from "./routes/setting/fileManagement/openFolder";
|
||||||
import route91 from "./routes/setting/memoryConfig/delAllMemory";
|
import route91 from "./routes/setting/getTextModel";
|
||||||
import route92 from "./routes/setting/memoryConfig/getMemory";
|
import route92 from "./routes/setting/loginConfig/getUser";
|
||||||
import route93 from "./routes/setting/memoryConfig/sureMemory";
|
import route93 from "./routes/setting/loginConfig/updateUserPwd";
|
||||||
import route94 from "./routes/setting/promptManage/getPrompt";
|
import route94 from "./routes/setting/memoryConfig/delAllMemory";
|
||||||
import route95 from "./routes/setting/promptManage/updatePrompt";
|
import route95 from "./routes/setting/memoryConfig/getMemory";
|
||||||
import route96 from "./routes/setting/skillManagement/backup/addSkill";
|
import route96 from "./routes/setting/memoryConfig/sureMemory";
|
||||||
import route97 from "./routes/setting/skillManagement/backup/deleteSkill";
|
import route97 from "./routes/setting/promptManage/getPrompt";
|
||||||
import route98 from "./routes/setting/skillManagement/backup/embeddingSkill";
|
import route98 from "./routes/setting/promptManage/updatePrompt";
|
||||||
import route99 from "./routes/setting/skillManagement/backup/generateDescription";
|
import route99 from "./routes/setting/skillManagement/backup/addSkill";
|
||||||
import route100 from "./routes/setting/skillManagement/backup/getSkillList";
|
import route100 from "./routes/setting/skillManagement/backup/deleteSkill";
|
||||||
import route101 from "./routes/setting/skillManagement/backup/scanSkills";
|
import route101 from "./routes/setting/skillManagement/backup/embeddingSkill";
|
||||||
import route102 from "./routes/setting/skillManagement/backup/updateSkill";
|
import route102 from "./routes/setting/skillManagement/backup/generateDescription";
|
||||||
import route103 from "./routes/setting/skillManagement/getSkillList";
|
import route103 from "./routes/setting/skillManagement/backup/getSkillList";
|
||||||
import route104 from "./routes/setting/vendorConfig/addVendor";
|
import route104 from "./routes/setting/skillManagement/backup/scanSkills";
|
||||||
import route105 from "./routes/setting/vendorConfig/deleteVendor";
|
import route105 from "./routes/setting/skillManagement/backup/updateSkill";
|
||||||
import route106 from "./routes/setting/vendorConfig/getVendorList";
|
import route106 from "./routes/setting/skillManagement/getSkillList";
|
||||||
import route107 from "./routes/setting/vendorConfig/modelTest";
|
import route107 from "./routes/setting/vendorConfig/addVendor";
|
||||||
import route108 from "./routes/setting/vendorConfig/updateCode";
|
import route108 from "./routes/setting/vendorConfig/deleteVendor";
|
||||||
import route109 from "./routes/setting/vendorConfig/updateVendor";
|
import route109 from "./routes/setting/vendorConfig/getVendorList";
|
||||||
import route110 from "./routes/task/getProject";
|
import route110 from "./routes/setting/vendorConfig/modelTest";
|
||||||
import route111 from "./routes/task/getTaskApi";
|
import route111 from "./routes/setting/vendorConfig/updateCode";
|
||||||
import route112 from "./routes/task/getTaskCategories";
|
import route112 from "./routes/setting/vendorConfig/updateVendor";
|
||||||
import route113 from "./routes/task/taskDetails";
|
import route113 from "./routes/task/getProject";
|
||||||
import route114 from "./routes/test/test";
|
import route114 from "./routes/task/getTaskApi";
|
||||||
|
import route115 from "./routes/task/getTaskCategories";
|
||||||
|
import route116 from "./routes/task/taskDetails";
|
||||||
|
import route117 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);
|
||||||
@ -181,54 +184,57 @@ export default async (app: Express) => {
|
|||||||
app.use("/api/production/workbench/getVideoModelDetail", route62);
|
app.use("/api/production/workbench/getVideoModelDetail", route62);
|
||||||
app.use("/api/production/workbench/videoPolling", route63);
|
app.use("/api/production/workbench/videoPolling", route63);
|
||||||
app.use("/api/project/addProject", route64);
|
app.use("/api/project/addProject", route64);
|
||||||
app.use("/api/project/delProject", route65);
|
app.use("/api/project/addVisual", route65);
|
||||||
app.use("/api/project/editProject", route66);
|
app.use("/api/project/deleteVisualManual", route66);
|
||||||
app.use("/api/project/getProject", route67);
|
app.use("/api/project/delProject", route67);
|
||||||
app.use("/api/project/getVisualManual", route68);
|
app.use("/api/project/editProject", route68);
|
||||||
app.use("/api/project/visualManual", route69);
|
app.use("/api/project/editVisualManual", route69);
|
||||||
app.use("/api/script/addScript", route70);
|
app.use("/api/project/getProject", route70);
|
||||||
app.use("/api/script/delScript", route71);
|
app.use("/api/project/getVisualManual", route71);
|
||||||
app.use("/api/script/exportScript", route72);
|
app.use("/api/project/visualManual", route72);
|
||||||
app.use("/api/script/extractAssets", route73);
|
app.use("/api/script/addScript", route73);
|
||||||
app.use("/api/script/getScrptApi", route74);
|
app.use("/api/script/delScript", route74);
|
||||||
app.use("/api/script/pollScriptAssets", route75);
|
app.use("/api/script/exportScript", route75);
|
||||||
app.use("/api/script/updateScript", route76);
|
app.use("/api/script/extractAssets", route76);
|
||||||
app.use("/api/scriptAgent/getPlanData", route77);
|
app.use("/api/script/getScrptApi", route77);
|
||||||
app.use("/api/scriptAgent/setPlanData", route78);
|
app.use("/api/script/pollScriptAssets", route78);
|
||||||
app.use("/api/setting/about/checkUpdate", route79);
|
app.use("/api/script/updateScript", route79);
|
||||||
app.use("/api/setting/about/downloadApp", route80);
|
app.use("/api/scriptAgent/getPlanData", route80);
|
||||||
app.use("/api/setting/agentDeploy/agentSetKey", route81);
|
app.use("/api/scriptAgent/setPlanData", route81);
|
||||||
app.use("/api/setting/agentDeploy/deployAgentModel", route82);
|
app.use("/api/setting/about/checkUpdate", route82);
|
||||||
app.use("/api/setting/agentDeploy/getAgentDeploy", route83);
|
app.use("/api/setting/about/downloadApp", route83);
|
||||||
app.use("/api/setting/dbConfig/clearData", route84);
|
app.use("/api/setting/agentDeploy/agentSetKey", route84);
|
||||||
app.use("/api/setting/dev/getSwitchAiDevTool", route85);
|
app.use("/api/setting/agentDeploy/deployAgentModel", route85);
|
||||||
app.use("/api/setting/dev/updateSwitchAiDevTool", route86);
|
app.use("/api/setting/agentDeploy/getAgentDeploy", route86);
|
||||||
app.use("/api/setting/fileManagement/openFolder", route87);
|
app.use("/api/setting/dbConfig/clearData", route87);
|
||||||
app.use("/api/setting/getTextModel", route88);
|
app.use("/api/setting/dev/getSwitchAiDevTool", route88);
|
||||||
app.use("/api/setting/loginConfig/getUser", route89);
|
app.use("/api/setting/dev/updateSwitchAiDevTool", route89);
|
||||||
app.use("/api/setting/loginConfig/updateUserPwd", route90);
|
app.use("/api/setting/fileManagement/openFolder", route90);
|
||||||
app.use("/api/setting/memoryConfig/delAllMemory", route91);
|
app.use("/api/setting/getTextModel", route91);
|
||||||
app.use("/api/setting/memoryConfig/getMemory", route92);
|
app.use("/api/setting/loginConfig/getUser", route92);
|
||||||
app.use("/api/setting/memoryConfig/sureMemory", route93);
|
app.use("/api/setting/loginConfig/updateUserPwd", route93);
|
||||||
app.use("/api/setting/promptManage/getPrompt", route94);
|
app.use("/api/setting/memoryConfig/delAllMemory", route94);
|
||||||
app.use("/api/setting/promptManage/updatePrompt", route95);
|
app.use("/api/setting/memoryConfig/getMemory", route95);
|
||||||
app.use("/api/setting/skillManagement/backup/addSkill", route96);
|
app.use("/api/setting/memoryConfig/sureMemory", route96);
|
||||||
app.use("/api/setting/skillManagement/backup/deleteSkill", route97);
|
app.use("/api/setting/promptManage/getPrompt", route97);
|
||||||
app.use("/api/setting/skillManagement/backup/embeddingSkill", route98);
|
app.use("/api/setting/promptManage/updatePrompt", route98);
|
||||||
app.use("/api/setting/skillManagement/backup/generateDescription", route99);
|
app.use("/api/setting/skillManagement/backup/addSkill", route99);
|
||||||
app.use("/api/setting/skillManagement/backup/getSkillList", route100);
|
app.use("/api/setting/skillManagement/backup/deleteSkill", route100);
|
||||||
app.use("/api/setting/skillManagement/backup/scanSkills", route101);
|
app.use("/api/setting/skillManagement/backup/embeddingSkill", route101);
|
||||||
app.use("/api/setting/skillManagement/backup/updateSkill", route102);
|
app.use("/api/setting/skillManagement/backup/generateDescription", route102);
|
||||||
app.use("/api/setting/skillManagement/getSkillList", route103);
|
app.use("/api/setting/skillManagement/backup/getSkillList", route103);
|
||||||
app.use("/api/setting/vendorConfig/addVendor", route104);
|
app.use("/api/setting/skillManagement/backup/scanSkills", route104);
|
||||||
app.use("/api/setting/vendorConfig/deleteVendor", route105);
|
app.use("/api/setting/skillManagement/backup/updateSkill", route105);
|
||||||
app.use("/api/setting/vendorConfig/getVendorList", route106);
|
app.use("/api/setting/skillManagement/getSkillList", route106);
|
||||||
app.use("/api/setting/vendorConfig/modelTest", route107);
|
app.use("/api/setting/vendorConfig/addVendor", route107);
|
||||||
app.use("/api/setting/vendorConfig/updateCode", route108);
|
app.use("/api/setting/vendorConfig/deleteVendor", route108);
|
||||||
app.use("/api/setting/vendorConfig/updateVendor", route109);
|
app.use("/api/setting/vendorConfig/getVendorList", route109);
|
||||||
app.use("/api/task/getProject", route110);
|
app.use("/api/setting/vendorConfig/modelTest", route110);
|
||||||
app.use("/api/task/getTaskApi", route111);
|
app.use("/api/setting/vendorConfig/updateCode", route111);
|
||||||
app.use("/api/task/getTaskCategories", route112);
|
app.use("/api/setting/vendorConfig/updateVendor", route112);
|
||||||
app.use("/api/task/taskDetails", route113);
|
app.use("/api/task/getProject", route113);
|
||||||
app.use("/api/test/test", route114);
|
app.use("/api/task/getTaskApi", route114);
|
||||||
|
app.use("/api/task/getTaskCategories", route115);
|
||||||
|
app.use("/api/task/taskDetails", route116);
|
||||||
|
app.use("/api/test/test", route117);
|
||||||
}
|
}
|
||||||
|
|||||||
85
src/routes/project/addVisual.ts
Normal file
85
src/routes/project/addVisual.ts
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import express from "express";
|
||||||
|
import u from "@/utils";
|
||||||
|
import { success } from "@/lib/responseFormat";
|
||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import { validateFields } from "@/middleware/middleware";
|
||||||
|
import { z } from "zod";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// 新增视觉手册
|
||||||
|
export default router.post(
|
||||||
|
"/",
|
||||||
|
validateFields({
|
||||||
|
name: z.string(),
|
||||||
|
image: z.string(),
|
||||||
|
data: z.array(
|
||||||
|
z.object({
|
||||||
|
label: z.string(),
|
||||||
|
value: z.string(),
|
||||||
|
data: z.string(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { name, image, data } = req.body as {
|
||||||
|
name: string;
|
||||||
|
image: string;
|
||||||
|
data: { label: string; value: string; data: string }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const mainPath = u.getPath(["skills", "art_prompts", name]);
|
||||||
|
|
||||||
|
// 将 image 写入 mainPath/images/image 文件(无后缀)
|
||||||
|
if (image) {
|
||||||
|
const imagesDir = path.join(mainPath, "images");
|
||||||
|
if (!fs.existsSync(imagesDir)) {
|
||||||
|
fs.mkdirSync(imagesDir, { recursive: true });
|
||||||
|
}
|
||||||
|
fs.writeFileSync(path.join(imagesDir, "image"), image, "utf-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字段映射表(与 getVisualManual 保持一致)
|
||||||
|
const DATA_MAP: { label: string; value: string; subDir?: string }[] = [
|
||||||
|
{ label: "README", value: "README" },
|
||||||
|
{ label: "前缀", value: "prefix" },
|
||||||
|
{ label: "角色", value: "art_character", subDir: "art_prompt" },
|
||||||
|
{ label: "角色衍生", value: "art_character_derivative", subDir: "art_prompt" },
|
||||||
|
{ label: "道具", value: "art_prop", subDir: "art_prompt" },
|
||||||
|
{ label: "道具衍生", value: "art_prop_derivative", subDir: "art_prompt" },
|
||||||
|
{ label: "场景", value: "art_scene", subDir: "art_prompt" },
|
||||||
|
{ label: "场景衍生", value: "art_scene_derivative", subDir: "art_prompt" },
|
||||||
|
{ label: "分镜", value: "art_storyboard", subDir: "art_prompt" },
|
||||||
|
{ label: "分镜视频", value: "art_storyboard_video", subDir: "art_prompt" },
|
||||||
|
{ label: "技法-导演规划", value: "director_planning", subDir: "driector_skills" },
|
||||||
|
{ label: "技法-分镜表设计", value: "director_storyboard_table", subDir: "driector_skills" },
|
||||||
|
];
|
||||||
|
|
||||||
|
// 根据 DATA_MAP 构建 value -> subDir 的映射
|
||||||
|
const SUB_DIR_MAP = new Map(DATA_MAP.map(({ value, subDir }) => [value, subDir ?? ""]));
|
||||||
|
|
||||||
|
// 合法的 value 值集合,用于校验
|
||||||
|
const VALID_KEYS = new Set(DATA_MAP.map(({ value }) => value));
|
||||||
|
|
||||||
|
for (const item of data) {
|
||||||
|
if (!VALID_KEYS.has(item.value)) continue;
|
||||||
|
|
||||||
|
const subDir = SUB_DIR_MAP.get(item.value)!;
|
||||||
|
const dirArr = subDir ? [mainPath, subDir] : [mainPath];
|
||||||
|
const filePath = u.getPath([...dirArr, `${item.value}.md`]);
|
||||||
|
|
||||||
|
const fileDir = path.dirname(filePath);
|
||||||
|
// 目录不存在时递归创建
|
||||||
|
if (!fs.existsSync(fileDir)) {
|
||||||
|
fs.mkdirSync(fileDir, { recursive: true });
|
||||||
|
}
|
||||||
|
fs.writeFileSync(filePath, item.data, "utf-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).send(success());
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500).send({ error: String(err) });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
43
src/routes/project/deleteVisualManual.ts
Normal file
43
src/routes/project/deleteVisualManual.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import express from "express";
|
||||||
|
import u from "@/utils";
|
||||||
|
import fs from "fs";
|
||||||
|
import { z } from "zod";
|
||||||
|
import { success } from "@/lib/responseFormat";
|
||||||
|
import { validateFields } from "@/middleware/middleware";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// 删除视觉手册
|
||||||
|
export default router.post(
|
||||||
|
"/",
|
||||||
|
validateFields({
|
||||||
|
name: z.string(),
|
||||||
|
}),
|
||||||
|
async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { name } = req.body as { name: string };
|
||||||
|
|
||||||
|
// 安全校验:不允许包含路径分隔符、纯数字,防止越级删除或误删项目目录
|
||||||
|
if (name.includes("/") || name.includes("\\") || name === "." || name === ".." || /^\d+$/.test(name)) {
|
||||||
|
res.status(400).send({ error: "非法的名称" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const artPromptsDir = u.getPath(["skills", "art_prompts", name]);
|
||||||
|
|
||||||
|
// 1. 删除 skills/art_prompts 下的同名文件夹
|
||||||
|
if (fs.existsSync(artPromptsDir)) {
|
||||||
|
fs.rmSync(artPromptsDir, { recursive: true, force: true });
|
||||||
|
// 2. 删除 oss 下的同名文件夹(存放图片)
|
||||||
|
try {
|
||||||
|
await u.oss.deleteDirectory(name);
|
||||||
|
} catch {
|
||||||
|
// oss 下不存在该目录则忽略
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).send(success({ message: "删除成功" }));
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500).send({ error: String(err) });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
100
src/routes/project/editVisualManual.ts
Normal file
100
src/routes/project/editVisualManual.ts
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import express from "express";
|
||||||
|
import u from "@/utils";
|
||||||
|
import { success } from "@/lib/responseFormat";
|
||||||
|
import fs from "fs";
|
||||||
|
import path from "path";
|
||||||
|
import { validateFields } from "@/middleware/middleware";
|
||||||
|
import { z } from "zod";
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
// 编辑视觉手册
|
||||||
|
export default router.post(
|
||||||
|
"/",
|
||||||
|
validateFields({
|
||||||
|
name: z.string(),
|
||||||
|
images: z.array(z.string()),
|
||||||
|
data: z.array(
|
||||||
|
z.object({
|
||||||
|
label: z.string(),
|
||||||
|
value: z.string(),
|
||||||
|
data: z.string(),
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { name, images, data } = req.body as {
|
||||||
|
name: string;
|
||||||
|
images: string[];
|
||||||
|
data: { label: string; value: string; data: string }[];
|
||||||
|
};
|
||||||
|
|
||||||
|
if (/^\d+$/.test(name)) {
|
||||||
|
res.status(400).send({ error: "名称不能为纯数字" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mainPath = u.getPath(["skills", "art_prompts", name]);
|
||||||
|
|
||||||
|
// 字段映射表(与 getVisualManual 保持一致)
|
||||||
|
const DATA_MAP: { label: string; value: string; subDir?: string }[] = [
|
||||||
|
{ label: "README", value: "README" },
|
||||||
|
{ label: "前缀", value: "prefix" },
|
||||||
|
{ label: "角色", value: "art_character", subDir: "art_prompt" },
|
||||||
|
{ label: "角色衍生", value: "art_character_derivative", subDir: "art_prompt" },
|
||||||
|
{ label: "道具", value: "art_prop", subDir: "art_prompt" },
|
||||||
|
{ label: "道具衍生", value: "art_prop_derivative", subDir: "art_prompt" },
|
||||||
|
{ label: "场景", value: "art_scene", subDir: "art_prompt" },
|
||||||
|
{ label: "场景衍生", value: "art_scene_derivative", subDir: "art_prompt" },
|
||||||
|
{ label: "分镜", value: "art_storyboard", subDir: "art_prompt" },
|
||||||
|
{ label: "分镜视频", value: "art_storyboard_video", subDir: "art_prompt" },
|
||||||
|
{ label: "技法-导演规划", value: "director_planning", subDir: "driector_skills" },
|
||||||
|
{ label: "技法-分镜表设计", value: "director_storyboard_table", subDir: "driector_skills" },
|
||||||
|
];
|
||||||
|
|
||||||
|
// 根据 DATA_MAP 构建 value -> subDir 的映射
|
||||||
|
const SUB_DIR_MAP = new Map(DATA_MAP.map(({ value, subDir }) => [value, subDir ?? ""]));
|
||||||
|
|
||||||
|
// 合法的 value 值集合,用于校验
|
||||||
|
const VALID_KEYS = new Set(DATA_MAP.map(({ value }) => value));
|
||||||
|
|
||||||
|
for (const item of data) {
|
||||||
|
if (!VALID_KEYS.has(item.value)) continue;
|
||||||
|
|
||||||
|
const subDir = SUB_DIR_MAP.get(item.value)!;
|
||||||
|
const dirArr = subDir ? [mainPath, subDir] : [mainPath];
|
||||||
|
const filePath = u.getPath([...dirArr, `${item.value}.md`]);
|
||||||
|
|
||||||
|
const fileDir = path.dirname(filePath);
|
||||||
|
// 目录不存在时递归创建
|
||||||
|
if (!fs.existsSync(fileDir)) {
|
||||||
|
fs.mkdirSync(fileDir, { recursive: true });
|
||||||
|
}
|
||||||
|
fs.writeFileSync(filePath, item.data, "utf-8");
|
||||||
|
}
|
||||||
|
const ossImagesDir = u.getPath(["oss", name]);
|
||||||
|
|
||||||
|
let existingFiles: string[] = [];
|
||||||
|
try {
|
||||||
|
const allFiles = fs.readdirSync(ossImagesDir);
|
||||||
|
existingFiles = allFiles.filter((f) => /\.(png|jpe?g|gif|webp|svg)$/i.test(f));
|
||||||
|
} catch {}
|
||||||
|
|
||||||
|
const retainedFileNames = new Set(images.filter((item) => item.includes("http")).map((url) => path.basename(new URL(url).pathname)));
|
||||||
|
|
||||||
|
for (const file of existingFiles) {
|
||||||
|
if (!retainedFileNames.has(file)) {
|
||||||
|
await u.oss.deleteFile(`${name}/${file}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const item of images) {
|
||||||
|
if (!item.includes("http")) await u.oss.writeFile(`${name}/${u.uuid()}.jpg`, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.status(200).send(success());
|
||||||
|
} catch (err) {
|
||||||
|
res.status(500).send({ error: String(err) });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
@ -30,19 +30,19 @@ function readMd(filePath: string): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取 images 文件夹第一张图片的 base64,无图片返回空字符串
|
// 获取 images 文件夹下所有图片文件路径列表
|
||||||
function readFirstImage(imagesDir: string): string {
|
async function readAllImages(imagesDir: string) {
|
||||||
try {
|
try {
|
||||||
const files = fs.readdirSync(imagesDir);
|
const ossPath = u.getPath(["oss", imagesDir]);
|
||||||
const imgFile = files.find((f) => /\.(png|jpe?g|gif|webp|svg)$/i.test(f));
|
const files = fs.readdirSync(ossPath);
|
||||||
if (!imgFile) return "";
|
const images = files.filter((f) => /\.(png|jpe?g|gif|webp|svg)$/i.test(f)).map((f) => path.join(imagesDir, f));
|
||||||
const imgPath = path.join(imagesDir, imgFile);
|
if (images.length) {
|
||||||
const ext = path.extname(imgFile).slice(1).toLowerCase();
|
return Promise.all(images.map(async (i) => await u.oss.getFileUrl(i)));
|
||||||
const mimeType = ext === "jpg" ? "jpeg" : ext;
|
} else {
|
||||||
const base64 = fs.readFileSync(imgPath).toString("base64");
|
return [];
|
||||||
return `data:image/${mimeType};base64,${base64}`;
|
}
|
||||||
} catch {
|
} catch {
|
||||||
return "";
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,32 +57,34 @@ export default router.post("/", async (req, res) => {
|
|||||||
.filter((d) => d.isDirectory())
|
.filter((d) => d.isDirectory())
|
||||||
.map((d) => d.name);
|
.map((d) => d.name);
|
||||||
|
|
||||||
const result = styleDirs.map((styleName) => {
|
const result = await Promise.all(
|
||||||
const styleDir = path.join(artPromptsDir, styleName);
|
styleDirs.map(async (styleName) => {
|
||||||
const imagesDir = path.join(styleDir, "images");
|
const styleDir = path.join(artPromptsDir, styleName);
|
||||||
|
const imagesDir = path.join(styleDir, "images");
|
||||||
|
|
||||||
const image = readFirstImage(imagesDir);
|
const images = await readAllImages(styleName);
|
||||||
|
|
||||||
|
const data = DATA_MAP.map(({ label, value, subDir }) => {
|
||||||
|
let mdPath: string;
|
||||||
|
if (subDir) {
|
||||||
|
mdPath = path.join(styleDir, subDir, `${value}.md`);
|
||||||
|
} else {
|
||||||
|
mdPath = path.join(styleDir, `${value}.md`);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
data: readMd(mdPath),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
const data = DATA_MAP.map(({ label, value, subDir }) => {
|
|
||||||
let mdPath: string;
|
|
||||||
if (subDir) {
|
|
||||||
mdPath = path.join(styleDir, subDir, `${value}.md`);
|
|
||||||
} else {
|
|
||||||
mdPath = path.join(styleDir, `${value}.md`);
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
label,
|
name: styleName,
|
||||||
value,
|
image: images,
|
||||||
data: readMd(mdPath),
|
data,
|
||||||
};
|
};
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
return {
|
|
||||||
name: styleName,
|
|
||||||
image,
|
|
||||||
data,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
res.status(200).send(success(result));
|
res.status(200).send(success(result));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
res.status(500).send({ error: String(err) });
|
res.status(500).send({ error: String(err) });
|
||||||
|
|||||||
@ -144,7 +144,11 @@ class OSS {
|
|||||||
const absPath = resolveSafeLocalPath(userRelPath, this.rootDir);
|
const absPath = resolveSafeLocalPath(userRelPath, this.rootDir);
|
||||||
await fs.mkdir(path.dirname(absPath), { recursive: true });
|
await fs.mkdir(path.dirname(absPath), { recursive: true });
|
||||||
// 如果 data 是 string,则视为 base64 编码,先解码再写入
|
// 如果 data 是 string,则视为 base64 编码,先解码再写入
|
||||||
const buffer = typeof data === "string" ? Buffer.from(data, "base64") : data;
|
// 自动去除可能存在的 Data URL 前缀(如 "data:image/png;base64,")
|
||||||
|
const buffer =
|
||||||
|
typeof data === "string"
|
||||||
|
? Buffer.from(data.replace(/^data:[^;]+;base64,/, ""), "base64")
|
||||||
|
: data;
|
||||||
await fs.writeFile(absPath, buffer);
|
await fs.writeFile(absPath, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user