diff --git a/src/router.ts b/src/router.ts index cd26f7a..0f66d09 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,4 +1,4 @@ -// @routes-hash 57463134da0d81d65d10c163ee8a2b26 +// @routes-hash 4397feb795394ec5313dafe4f6a9aa67 import { Express } from "express"; import route1 from "./routes/agents/clearMemory"; @@ -96,12 +96,13 @@ import route92 from "./routes/setting/vendorConfig/addVendor"; import route93 from "./routes/setting/vendorConfig/deleteVendor"; import route94 from "./routes/setting/vendorConfig/getVendorList"; import route95 from "./routes/setting/vendorConfig/modelTest"; -import route96 from "./routes/setting/vendorConfig/updateVendor"; -import route97 from "./routes/task/getProject"; -import route98 from "./routes/task/getTaskApi"; -import route99 from "./routes/task/getTaskCategories"; -import route100 from "./routes/task/taskDetails"; -import route101 from "./routes/test/test"; +import route96 from "./routes/setting/vendorConfig/updateCode"; +import route97 from "./routes/setting/vendorConfig/updateVendor"; +import route98 from "./routes/task/getProject"; +import route99 from "./routes/task/getTaskApi"; +import route100 from "./routes/task/getTaskCategories"; +import route101 from "./routes/task/taskDetails"; +import route102 from "./routes/test/test"; export default async (app: Express) => { app.use("/api/agents/clearMemory", route1); @@ -199,10 +200,11 @@ export default async (app: Express) => { app.use("/api/setting/vendorConfig/deleteVendor", route93); app.use("/api/setting/vendorConfig/getVendorList", route94); app.use("/api/setting/vendorConfig/modelTest", route95); - app.use("/api/setting/vendorConfig/updateVendor", route96); - app.use("/api/task/getProject", route97); - app.use("/api/task/getTaskApi", route98); - app.use("/api/task/getTaskCategories", route99); - app.use("/api/task/taskDetails", route100); - app.use("/api/test/test", route101); + app.use("/api/setting/vendorConfig/updateCode", route96); + app.use("/api/setting/vendorConfig/updateVendor", route97); + app.use("/api/task/getProject", route98); + app.use("/api/task/getTaskApi", route99); + app.use("/api/task/getTaskCategories", route100); + app.use("/api/task/taskDetails", route101); + app.use("/api/test/test", route102); } diff --git a/src/routes/setting/vendorConfig/updateCode.ts b/src/routes/setting/vendorConfig/updateCode.ts new file mode 100644 index 0000000..aa1cf43 --- /dev/null +++ b/src/routes/setting/vendorConfig/updateCode.ts @@ -0,0 +1,115 @@ +import express from "express"; +import { serializeError } from "serialize-error"; +import { success, error } from "@/lib/responseFormat"; +import { validateFields } from "@/middleware/middleware"; +import u from "@/utils"; +import { z } from "zod"; +import { transform } from "sucrase"; +const router = express.Router(); + +const vendorConfigSchema = z.object({ + id: z.string(), + author: z.string(), + description: z.string().optional(), + name: z.string(), + icon: z.string().optional(), + inputs: z.array( + z.object({ + key: z.string(), + label: z.string(), + type: z.enum(["text", "password", "url"]), + required: z.boolean(), + placeholder: z.string().optional(), + }), + ), + inputValues: z.record(z.string(), z.string()), + models: z.array( + z.discriminatedUnion("type", [ + z.object({ + name: z.string(), + modelName: z.string(), + type: z.literal("text"), + multimodal: z.boolean(), + tool: z.boolean(), + }), + z.object({ + name: z.string(), + modelName: z.string(), + type: z.literal("image"), + mode: z.array(z.enum(["text", "singleImage", "multiReference"])), + }), + z.object({ + name: z.string(), + modelName: z.string(), + type: z.literal("video"), + mode: z.array( + z.union([ + z.enum([ + "singleImage", + "multiImage", + "gridImage", + "startEndRequired", + "endFrameOptional", + "startFrameOptional", + "text", + "audioReference", + "videoReference", + ]), + z.array(z.enum(["video", "image", "audio", "text"])), + ]), + ), + audio: z.union([z.literal("optional"), z.boolean()]), + durationResolutionMap: z.array( + z.object({ + duration: z.array(z.number()), + resolution: z.array(z.string()), + }), + ), + }), + ]), + ), +}); + +export default router.post( + "/", + validateFields({ + id: z.string(), + tsCode: z.string(), + }), + async (req, res) => { + try { + const { tsCode, id } = req.body; + const jsCode = transform(tsCode, { transforms: ["typescript"] }).code; + const exports = u.vm(jsCode); + if (!exports) return res.status(400).send(success("脚本文件必须导出对象")); + if (!exports.textRequest) return res.status(400).send(success("脚本文件必须导出文本请求对象")); + if (!exports.imageRequest) return res.status(400).send(success("脚本文件必须导出图像请求对象")); + if (!exports.videoRequest) return res.status(400).send(success("脚本文件必须导出视频请求对象")); + if (!exports.vendor) return res.status(400).send(success("脚本文件必须导出vendor对象")); + const vendor = exports.vendor; + const result = vendorConfigSchema.safeParse(vendor); + if (!result.success) { + const errorMsg = result.error.issues.map((e) => `${e.path.join(".")}: ${e.message}`).join("; "); + return res.status(400).send(error(`vendor配置校验失败: ${errorMsg}`)); + } + await u + .db("o_vendorConfig") + .where("id", id) + .update({ + author: vendor.author, + description: vendor.description || "", + name: vendor.name, + icon: vendor.icon || "", + inputs: JSON.stringify(vendor.inputs ?? []), + inputValues: JSON.stringify(vendor.inputValues ?? {}), + models: JSON.stringify(vendor.models ?? []), + code: tsCode, + createTime: Date.now(), + }); + res.status(200).send(success(result.data)); + } catch (err) { + console.log(err); + res.status(400).send(error(serializeError(err).message || "未知错误")); + } + }, +); diff --git a/src/routes/setting/vendorConfig/updateVendor.ts b/src/routes/setting/vendorConfig/updateVendor.ts index d9073f8..499c3a4 100644 --- a/src/routes/setting/vendorConfig/updateVendor.ts +++ b/src/routes/setting/vendorConfig/updateVendor.ts @@ -158,14 +158,6 @@ export default router.post( return code.slice(0, valueStart) + newValue + code.slice(valueEnd + 1); }; - // 替换 tsCode 中指定 key 的字符串/数字值(如 name: "xxx" 或 version: 1) - const replacePrimitiveValue = (code: string, key: string, newValue: string | number): string => { - return code.replace( - new RegExp(`(\\b${key}\\s*:\\s*)(?:"[^"]*"|'[^']*'|\\d+)`), - (_, prefix) => `${prefix}${typeof newValue === "string" ? JSON.stringify(newValue) : newValue}`, - ); - }; - let updatedTsCode = tsCode; updatedTsCode = replaceBlockValue(updatedTsCode, "inputs", JSON.stringify(inputs ?? vendor.inputs, null, 2)); updatedTsCode = replaceBlockValue(updatedTsCode, "inputValues", JSON.stringify(inputValues ?? vendor.inputValues, null, 2));