144 lines
5.2 KiB
TypeScript

import { z } from "zod";
const textPartSchema = z.object({
type: z.enum(["text"]),
text: z.string().min(1).max(2000),
});
const filePartSchema = z.object({
type: z.enum(["file"]),
mediaType: z.enum(["image/jpeg", "image/png", "image/webp", "image/gif", "image/jpg", "image/bmp", "image/svg+xml"]),
name: z.string().min(1).max(100),
url: z.string().url(),
assetId: z.string().uuid().optional(),
width: z.number().positive().optional(),
height: z.number().positive().optional(),
});
const partSchema = z.union([textPartSchema, filePartSchema]);
// 视频参数 schema
const videoParamsSchema = z.object({
mode: z.enum(["text-to-video", "first-frame", "first-last-frame", "reference-images"]),
resolution: z.enum(["480p", "720p", "1080p"]).optional(),
ratio: z.string().optional(),
duration: z.number().optional(),
generateAudio: z.boolean().optional(),
watermark: z.boolean().optional(),
cameraFixed: z.boolean().optional(),
cameraMove: z.string().optional(),
fps: z.number().optional(),
seed: z.number().optional(),
returnLastFrame: z.boolean().optional(),
}).optional();
const imageSizeValues = ["1K", "2K", "4K"] as const;
function normalizeImageSizeInput(value: unknown) {
if (typeof value !== "string") return undefined;
const normalized = value.trim().toUpperCase();
return imageSizeValues.includes(normalized as (typeof imageSizeValues)[number])
? normalized
: undefined;
}
// 🆕 图片生成参数 schema
const imageParamsSchema = z.object({
aspectRatio: z.string().optional(),
imageSize: z.preprocess(normalizeImageSizeInput, z.enum(imageSizeValues).optional()),
imageCount: z.number().min(1).max(10).optional(),
// 阿里生图专用参数
size: z.string().optional(), // 自定义分辨率,如 "1024*1024"
negativePrompt: z.string().optional(), // 反向提示词
promptExtend: z.boolean().optional(), // 提示词智能优化
watermark: z.boolean().optional(), // 水印
seed: z.number().optional(), // 随机种子
n: z.number().min(1).max(10).optional(), // 兼容 n 参数
}).optional();
const contextPayloadSchema = z
.object({
source: z.enum(["chat", "canvas", "realtime-canvas"]).optional(),
projectId: z.string().uuid().optional(),
selectedNodeIds: z.array(z.string().min(1).max(128)).max(20).optional(),
selectedAssetIds: z.array(z.string().uuid()).max(20).optional(),
focusPolicy: z.enum(["auto", "selected", "latest_result", "original"]).optional(),
canvasImageNodes: z
.array(
z.object({
nodeId: z.string().min(1).max(128),
assetId: z.string().uuid().optional(),
url: z.string().url(),
title: z.string().max(256).optional(),
prompt: z.string().max(2000).optional(),
x: z.number(),
y: z.number(),
width: z.number().optional(),
height: z.number().optional(),
isSelected: z.boolean().optional(),
}),
)
.max(20)
.optional(),
})
.optional();
const agentModeReferenceSchema = z.object({
id: z.string().min(1).max(128),
label: z.string().min(1).max(255),
imageUrl: z.string().url(),
candidateId: z.string().min(1).max(128).nullable().optional(),
sortOrder: z.number().min(0).max(999).optional(),
assignedProductIndex: z.number().min(0).max(9).nullable().optional(),
passthrough: z.boolean().nullable().optional(),
});
const agentModeSourceImageSchema = z.object({
url: z.string().url(),
label: z.string().max(255).optional(),
name: z.string().max(255).optional(),
assetId: z.string().min(1).max(128).nullable().optional(),
});
const agentModePayloadSchema = z
.object({
modeType: z.enum(["detail_replacement", "sku_replacement"]),
replacementStrategy: z.enum(["scene_replace", "product_only"]).optional(),
query: z.string().max(64).optional(),
queryType: z.enum(["sku", "spu", "productId"]).optional(),
selectedCandidateId: z.string().min(1).max(128).nullable().optional(),
references: z.array(agentModeReferenceSchema).max(40),
sourceImages: z
.object({
productImages: z.array(agentModeSourceImageSchema).max(16).optional(),
modelImage: agentModeSourceImageSchema.nullable().optional(),
})
.optional(),
})
.optional();
export const postRequestBodySchema = z.object({
id: z.string().uuid(),
message: z.object({
id: z.string().uuid(),
role: z.enum(["user"]),
parts: z.array(partSchema),
}),
hiddenPrompt: z.string().max(4000).optional(),
workflowPromptOptimizationEnabled: z.boolean().optional(),
autoContext: z.string().max(4000).optional(),
agentPresetId: z.string().uuid().optional(),
// 支持预定义模型名称或数据库中的模型 UUID
selectedChatModel: z.string().min(1).max(128),
selectedVisibilityType: z.enum(["public", "private"]),
composerMode: z.enum(["agent", "image", "video", "detail"]).optional(),
deepThinkingEnabled: z.boolean().optional(),
debugProtocol: z.boolean().optional(),
videoParams: videoParamsSchema, // 视频参数
imageParams: imageParamsSchema, // 🆕 图片生成参数
contextPayload: contextPayloadSchema,
agentModePayload: agentModePayloadSchema,
});
export type PostRequestBody = z.infer<typeof postRequestBodySchema>;