90 lines
11 KiB
TypeScript
90 lines
11 KiB
TypeScript
/** Fixed business operations, never an arbitrary URL or administrator API proxy. */
|
||
export type ProjectAgentOperation = {
|
||
id: string; title: string; group: string; path: string; method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
||
hint: string; readOnly: boolean; result: "json"; authorized: true;
|
||
};
|
||
export const PROJECT_AGENT_OPERATIONS: ProjectAgentOperation[] = [];
|
||
function add(group: string, id: string, title: string, path: string, methods: string, hint: string) {
|
||
for (const method of methods.split(",") as ProjectAgentOperation["method"][]) PROJECT_AGENT_OPERATIONS.push({
|
||
id: `${id}.${method.toLowerCase()}`, title, group, path, method, hint, readOnly: method === "GET", result: "json", authorized: true,
|
||
});
|
||
}
|
||
add("技能", "skills", "可访问技能列表", "/api/agents", "GET", "query: categoryId、search(可选)。执行技能前用 loadProjectSkill 读取真实提示词和参数,再由当前原生核心编排已有工具。");
|
||
add("技能", "skill-categories", "技能分类", "/api/agent-categories", "GET", "无需参数");
|
||
add("素材", "materials", "商品 SKU/SPU 素材检索", "/api/agent-workflow/material-search", "GET", "query: keyword必填,source=primary/secondary、queryType=sku/spu、requiredCount可选");
|
||
add("素材", "references", "参考图检索", "/api/agent-workflow/reference-search", "GET", "query: keyword、source、queryType;以接口返回的实际素材为准");
|
||
add("素材", "appearance", "素材外观识别", "/api/agent-workflow/material-appearance", "POST", "body: imageUrls等图片参数,接口验证服务配置与格式");
|
||
add("素材", "third-party-materials", "第三方图片素材检索", "/api/third-party-image-materials/search", "GET", "query: keyword、page、pageSize;沿用站点数据权限");
|
||
add("素材", "gallery", "图库素材", "/api/gallery", "GET", "query: page、pageSize、category、keyword可选");
|
||
add("素材", "featured", "精选素材", "/api/featured", "GET", "query: category、page可选");
|
||
add("素材", "ranking", "素材排行榜", "/api/featured/ranking", "GET", "query: type、limit可选");
|
||
add("PSD", "psd-templates", "PSD 模板列表", "/api/psd-templates", "GET", "query: category、keyword可选");
|
||
add("PSD", "psd-template", "PSD 模板图层信息", "/api/psd-templates/[id]", "GET", "pathParams: id=模板编号");
|
||
add("PSD", "psd-render", "PSD 真正渲染与任务状态", "/api/psd-templates/render", "GET,POST", "POST body: templateId必填,imageAssignments/textAssignments/hiddenLayerIds/layerOrderIds/imagePlacements等;GET query: taskId。pending/running只代表已受理,必须轮询到succeeded且有result.url才可交付。");
|
||
add("详情与设计", "detail-plan", "详情页与 UI 设计规划", "/api/canvas/detail-plan", "POST", "body: prompt、图片和设计上下文;遵循接口校验");
|
||
add("详情与设计", "detail-review", "详情结果验收", "/api/canvas/detail-review", "POST", "body: prompt、imageUrls等真实设计图信息");
|
||
add("详情与设计", "detail-subject", "详情主体分析", "/api/canvas/detail-subject-analyze", "POST", "body: 图片与产品信息");
|
||
add("详情与设计", "ui-review", "UI 页面验收", "/api/canvas/ui-screen/review", "POST", "body: 真实页面设计文档与审核要求");
|
||
add("详情与设计", "text-copy", "图片文案建议", "/api/canvas/text-copy-suggestions", "POST", "body: imageUrl、prompt等文案上下文");
|
||
add("详情与设计", "detail-stitch", "详情图片拼接", "/api/agent-workflow/detail-stitch", "POST", "body: images或imageUrls等拼接参数");
|
||
add("详情与设计", "detail-normalize", "详情图片归一化", "/api/agent-workflow/detail-image-normalize", "POST", "body: 图片链接与尺寸参数");
|
||
add("详情与设计", "style-models", "风格化可用模型", "/api/style-pro/model-options", "GET", "无需参数,不返回密钥");
|
||
add("详情与设计", "style-generate", "风格化 PRO 生成", "/api/style-pro/generate", "POST", "body: 模型、提示词与参考图,遵守用户指定模型;不改站点配置");
|
||
add("详情与设计", "wash-models", "AI 图像处理可用模型", "/api/ai-wash/model-options", "GET", "无需参数");
|
||
add("详情与设计", "wash-generate", "AI 图像处理", "/api/ai-wash/generate", "POST", "body: 用户图像与参数;结果未确认不能重提收费任务");
|
||
add("商品策划", "planning-image", "商品图片分析", "/api/product-planning/analyze-image", "POST", "body: imageUrl与产品上下文;底层功能开关仍生效");
|
||
add("商品策划", "planning-sku", "商品 SKU 分析", "/api/product-planning/analyze-sku", "POST", "body: sku与用户商品信息");
|
||
add("商品策划", "planning-analysis", "评价与问大家分析", "/api/product-planning/analyze", "POST", "body: kind=review/qa,rows为真实评价或问答数组");
|
||
add("商品策划", "planning-keywords", "关键词洞察", "/api/product-planning/keyword-insight", "GET", "query: keyword等检索参数");
|
||
for (const platform of ["taobao", "jd"]) add("商品策划", `planning-${platform}-item`, `${platform} 商品详情`, `/api/product-planning/${platform}/item`, "GET", "query: itemId等商品编号");
|
||
add("商品策划", "planning-reviews", "淘宝真实评价", "/api/product-planning/taobao/reviews", "GET", "query: itemId、page等");
|
||
add("商品策划", "planning-sales", "淘宝月销量", "/api/product-planning/taobao/month-sale", "GET", "query: itemId");
|
||
add("商品策划", "planning-qa", "淘宝问大家", "/api/product-planning/taobao/qa", "POST", "body: itemId等商品编号");
|
||
add("商品策划", "planning-market-items", "平台商品检索", "/api/product-planning/marketplace/items", "POST", "body: platform、keyword等检索参数");
|
||
add("商品策划", "planning-templates", "策划模板列表与保存", "/api/product-planning/templates", "GET,POST", "POST body: title与策划内容;只保存当前用户自己的模板");
|
||
add("商品策划", "planning-template", "策划模板读取与删除", "/api/product-planning/templates/[id]", "GET,DELETE", "pathParams: id;删除需要用户明确指定此编号");
|
||
add("流程白板", "flow-files", "白板文件列表与创建", "/api/flow-board/files", "GET,POST", "POST body: title、snapshot;snapshot必须为真实白板快照");
|
||
add("流程白板", "flow-file", "白板文件读取、修改、删除", "/api/flow-board/files/[id]", "GET,PUT,DELETE", "pathParams: id;PUT body: title、snapshot;先读取原文件,保留无关节点和工作表;删除需明确指定编号");
|
||
add("流程白板", "flow-draft", "白板草稿读取与保存", "/api/flow-board/draft", "GET,PUT", "PUT body: title、snapshot;只操作当前用户草稿");
|
||
add("分镜任务", "video-capabilities", "视频模型能力与参数", "/api/video-model-capabilities", "GET", "query: modelId等;沿用用户模型");
|
||
add("分镜任务", "video-tasks", "用户视频任务列表", "/api/video-tasks", "GET", "query: page、limit等;仅当前用户任务");
|
||
add("分镜任务", "storyboard-task", "分镜任务与阶段推进", "/api/video/storyboard/tasks/[taskId]", "GET", "pathParams: taskId;读取实际状态后再按接口动作推进,不重启已有收费任务");
|
||
add("分镜任务", "storyboard-confirm", "确认用户分镜参数", "/api/video/storyboard/tasks/[taskId]/confirm", "POST", "pathParams: taskId;body: 用户实际确认的镜头与参数,不虚构用户确认");
|
||
add("分镜任务", "storyboard-cancel", "停止指定分镜任务", "/api/video/storyboard/tasks/[taskId]/cancel", "POST", "pathParams: taskId;需用户明确要求停止此编号");
|
||
add("分镜任务", "storyboard-shot", "分镜镜头修订", "/api/video/storyboard/tasks/[taskId]/shots/[shotIndex]", "PATCH", "pathParams: taskId、shotIndex;body: 用户要求的镜头修改");
|
||
add("分镜任务", "storyboard-hd", "指定镜头高清处理", "/api/video/storyboard/tasks/[taskId]/shots/[shotIndex]/regenerate-hd", "POST", "pathParams: taskId、shotIndex;会产生费用,只有用户要求高清才执行");
|
||
add("项目", "agent-projects", "Agent 创作项目列表与创建", "/api/agent-projects", "GET,POST", "POST body: title等项目数据;不写入其他用户项目");
|
||
add("项目", "agent-project", "Agent 创作项目读写", "/api/agent-projects/[id]", "GET,PUT,DELETE", "pathParams: id;修改先读当前内容,删除需用户明确指定编号");
|
||
add("项目", "canvas-list", "用户画布列表与创建", "/api/canvas", "GET,POST", "POST body: title、workspaceType=canvas/video等");
|
||
add("项目", "canvas-read", "读取用户画布", "/api/canvas/[id]", "GET", "pathParams: id;只读取当前用户有权限的画布,节点写入使用专用画布工具");
|
||
add("项目", "detail-archives", "画布详情归档", "/api/canvas/[id]/detail-archives", "GET,POST,PATCH,DELETE", "pathParams: id=当前画布编号;body/query按详情归档接口,删除需明确授权");
|
||
add("项目", "model-assets", "3D 资产归档", "/api/canvas/[id]/model3d-assets", "GET,POST,PATCH,DELETE", "pathParams: id=当前画布编号;只处理拥有权限的资产");
|
||
add("3D", "3d-task", "3D 生成任务状态", "/api/canvas/3d/tasks/[taskId]", "GET", "pathParams: taskId;生成用已有3D专用能力,不重复提交");
|
||
add("3D", "world-task", "场景生成任务状态", "/api/canvas/world/tasks/[taskId]", "GET", "pathParams: taskId;生成用已有场景专用能力");
|
||
add("智能编辑", "smart-edit", "智能图层编辑能力", "/api/canvas/smart-edit/capabilities", "GET", "无需参数;仅当该部署版本已有此功能时可用");
|
||
add("文档", "documents", "读取与保存用户文档", "/api/document", "GET,POST", "query: id=文档UUID;POST body: title、kind=text/code/sheet/image、content。更新前先读取原文档,不操作其他用户文档。");
|
||
add("图像处理", "enhance-pro", "专业高清处理任务与查询", "/api/enhance/pro", "GET,POST", "POST body按接口实际模型与尺寸要求,GET query: taskId。仅任务成功后才能交付,不能重复付费提交。");
|
||
export function projectOperationAuthorized(operation: ProjectAgentOperation) {
|
||
return operation.group !== "分镜任务";
|
||
}
|
||
export function projectOperationUrl(operation: ProjectAgentOperation, pathParams: Record<string, string>, query: Record<string, unknown>) {
|
||
const path = operation.path.replace(/\[([^\]]+)\]/g, (_all, key: string) => {
|
||
const value = pathParams[key];
|
||
if (!value || !/^[a-zA-Z0-9_-]{1,180}$/.test(value)) throw new Error(`缺少或无效的路径参数:${key}`);
|
||
return encodeURIComponent(value);
|
||
});
|
||
const values = new URLSearchParams();
|
||
for (const [key, value] of Object.entries(query)) {
|
||
if (!/^[\w.-]{1,80}$/.test(key) || !["string", "number", "boolean"].includes(typeof value)) throw new Error("查询参数格式无效");
|
||
values.set(key, String(value));
|
||
}
|
||
return path + (values.size ? `?${values}` : "");
|
||
}
|
||
export function sanitizeProjectToolOutput(value: unknown): unknown {
|
||
if (Array.isArray(value)) return value.map(sanitizeProjectToolOutput);
|
||
if (value && typeof value === "object") return Object.fromEntries(Object.entries(value)
|
||
.filter(([key]) => !/^(?:api[-_]?key|access[-_]?key|secret(?:[-_]?key)?|token|password(?:hash)?|ak|sk|accessKeyId|secretAccessKey|clientSecret|accessToken|refreshToken|authorization|cookie|headers|credentials|providerConfig)$/i.test(key))
|
||
.map(([key, entry]) => [key, sanitizeProjectToolOutput(entry)]));
|
||
return value;
|
||
}
|