feat: multimodal AI event creation with image support #1
@@ -1,12 +1,26 @@
|
||||
import { z } from "zod";
|
||||
import { MAX_IMAGE_SIZE_BYTES } from "@/lib/constants";
|
||||
|
||||
/** Validates that a base64 data URL string decodes to binary under the max size. */
|
||||
const isValidImageSize = (val: string | undefined): boolean => {
|
||||
if (!val) return true;
|
||||
const base64Part = val.split(",")[1] ?? "";
|
||||
const binarySize = Math.ceil(base64Part.length * 0.75);
|
||||
return binarySize <= MAX_IMAGE_SIZE_BYTES;
|
||||
};
|
||||
|
||||
export const AiEventRequestSchema = z
|
||||
.object({
|
||||
prompt: z.string().trim().max(2000).optional(),
|
||||
imageBase64: z
|
||||
.string()
|
||||
.startsWith("data:", "Must be a valid data URL")
|
||||
.max(10 * 1024 * 1024 * 1.37, "Image must be less than 10MB")
|
||||
.regex(
|
||||
/^data:image\/(png|jpeg|webp);base64,/,
|
||||
"Must be a valid image data URL (PNG, JPEG, or WebP)",
|
||||
)
|
||||
.refine(isValidImageSize, {
|
||||
message: "Image must be less than 10MB",
|
||||
})
|
||||
.optional(),
|
||||
})
|
||||
.refine((data) => data.prompt || data.imageBase64, {
|
||||
@@ -21,25 +35,18 @@ export const AiEventResponseItemSchema = z.object({
|
||||
description: z.string().optional(),
|
||||
location: z.string().optional(),
|
||||
url: z.string().optional(),
|
||||
start: z.string(),
|
||||
end: z.string().optional(),
|
||||
start: z.string().datetime({ offset: true }),
|
||||
end: z.string().datetime({ offset: true }).optional(),
|
||||
allDay: z.boolean().optional(),
|
||||
recurrenceRule: z.string().optional(),
|
||||
});
|
||||
|
||||
export const AiEventResponseSchema = z.array(AiEventResponseItemSchema);
|
||||
|
||||
export type CalendarEvent = {
|
||||
export type AiEventResponseItem = z.infer<typeof AiEventResponseItemSchema>;
|
||||
|
||||
export type CalendarEvent = AiEventResponseItem & {
|
||||
id: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
location?: string;
|
||||
url?: string;
|
||||
start: string;
|
||||
end?: string;
|
||||
allDay?: boolean;
|
||||
createdAt?: string;
|
||||
lastModified?: string;
|
||||
|
||||
recurrenceRule?: string;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user