| 1 | import { createZodDto, UserType } from '@yikart/common' |
| 2 | import { z } from 'zod' |
| 3 | |
| 4 | // OpenAI 视频创建请求DTO |
| 5 | const openAIVideoCreateBaseSchema = z.object({ |
| 6 | prompt: z.string().min(1).describe('提示词'), |
| 7 | input_reference: z.string().optional().describe('参考图片URL或base64'), |
| 8 | model: z.string().optional().describe('模型名称'), |
| 9 | seconds: z.string().optional().describe('视频时长(秒)'), |
| 10 | size: z.enum(['720x1280', '1280x720', '1024x1792', '1792x1024']).optional().describe('视频尺寸'), |
| 11 | }) |
| 12 | |
| 13 | export class OpenAIVideoCreateRequestDto extends createZodDto(openAIVideoCreateBaseSchema) {} |
| 14 | |
| 15 | const userOpenAIVideoCreateRequestSchema = z.object({ |
| 16 | userId: z.string(), |
| 17 | userType: z.enum(UserType), |
| 18 | ...openAIVideoCreateBaseSchema.shape, |
| 19 | }) |
| 20 | |
| 21 | export class UserOpenAIVideoCreateRequestDto extends createZodDto(userOpenAIVideoCreateRequestSchema) {} |
| 22 | |
| 23 | // OpenAI Remix 请求DTO |
| 24 | const openAIVideoRemixBaseSchema = z.object({ |
| 25 | prompt: z.string().min(1).describe('新的提示词'), |
| 26 | }) |
| 27 | |
| 28 | export class OpenAIVideoRemixRequestDto extends createZodDto(openAIVideoRemixBaseSchema) {} |
| 29 | |
| 30 | const userOpenAIVideoRemixRequestSchema = z.object({ |
| 31 | userId: z.string(), |
| 32 | userType: z.enum(UserType), |
| 33 | videoId: z.string(), |
| 34 | ...openAIVideoRemixBaseSchema.shape, |
| 35 | }) |
| 36 | |
| 37 | export class UserOpenAIVideoRemixRequestDto extends createZodDto(userOpenAIVideoRemixRequestSchema) {} |
| 38 | |
| 39 | // OpenAI 回调 DTO(对应 Video 类型,包含第三方扩展字段) |
| 40 | const openAIVideoCallbackSchema = z.object({ |
| 41 | id: z.string(), |
| 42 | status: z.enum(['queued', 'in_progress', 'completed', 'failed']), |
| 43 | model: z.string(), |
| 44 | prompt: z.string().nullable(), |
| 45 | progress: z.number(), |
| 46 | created_at: z.number(), |
| 47 | completed_at: z.number().nullable(), |
| 48 | expires_at: z.number().nullable(), |
| 49 | error: z.object({ |
| 50 | code: z.string(), |
| 51 | message: z.string(), |
| 52 | }).nullable(), |
| 53 | remixed_from_video_id: z.string().nullable(), |
| 54 | seconds: z.string(), |
| 55 | size: z.string(), |
| 56 | object: z.literal('video'), |
| 57 | // 第三方扩展字段(直接返回视频 URL) |
| 58 | url: z.string().optional(), |
| 59 | video_url: z.string().optional(), |
| 60 | }) |
| 61 | |
| 62 | export class OpenAIVideoCallbackDto extends createZodDto(openAIVideoCallbackSchema) {} |
| 63 | |
| 64 | // Sora Character 创建请求 DTO |
| 65 | const soraCharacterCreateBaseSchema = z.object({ |
| 66 | prompt: z.string().min(1).describe('角色名称'), |
| 67 | videoUrl: z.string().optional().describe('通过视频 URL 创建'), |
| 68 | taskId: z.string().optional().describe('通过任务 ID 创建'), |
| 69 | timestamps: z.string().regex(/^\d+,\d+$/).describe('两个数字,逗号分隔,间隔 ≤ 3秒,如 "1,3"'), |
| 70 | }) |
| 71 | |
| 72 | export class SoraCharacterCreateRequestDto extends createZodDto(soraCharacterCreateBaseSchema) {} |
| 73 | |
| 74 | const userSoraCharacterCreateRequestSchema = z.object({ |
| 75 | userId: z.string(), |
| 76 | userType: z.enum(UserType), |
| 77 | ...soraCharacterCreateBaseSchema.shape, |
| 78 | }) |
| 79 | |
| 80 | export class UserSoraCharacterCreateRequestDto extends createZodDto(userSoraCharacterCreateRequestSchema) {} |
| 81 | |
| 82 | // Sora Character 回调 DTO |
| 83 | const soraCharacterCallbackSchema = z.object({ |
| 84 | id: z.string(), |
| 85 | object: z.literal('character'), |
| 86 | model: z.literal('sora-2-character'), |
| 87 | status: z.enum(['queued', 'processing', 'completed', 'failed']), |
| 88 | username: z.string(), |
| 89 | avatar_url: z.string().optional(), |
| 90 | video_url: z.string().optional(), |
| 91 | created_at: z.number(), |
| 92 | completed_at: z.number().nullable().optional(), |
| 93 | error: z.object({ |
| 94 | code: z.number(), |
| 95 | message: z.string(), |
| 96 | }).nullable().optional(), |
| 97 | }) |
| 98 | |
| 99 | export class SoraCharacterCallbackDto extends createZodDto(soraCharacterCallbackSchema) {} |
| 100 |