import { z } from "npm:zod"; export const IngredientSchema = z.object({ quantity: z.string().describe( "e.g., '2', '1/2', or an empty string for 'to taste'", ), unit: z.string().describe('e.g., "g", "tbsp", "cup"'), name: z.string().describe('e.g., "sugar", "flour"'), // note: z.string().describe('optional, e.g., "sifted", "chopped finely"'), }); export type Ingredient = z.infer; export const IngredientGroupSchema = z.object({ name: z.string(), items: z.array(IngredientSchema), }); export type IngredientGroup = z.infer; const recipeSchema = z.object({ title: z.string().describe( "Title of the Recipe, without the name of the website or author", ), image: z.string().describe("URL of the main image of the recipe"), author: z.string().describe("author of the Recipe (optional)"), description: z.string().describe("Optional, short description of the recipe"), ingredients: z.array(z.union([IngredientSchema, IngredientGroupSchema])) .describe("List of ingredients"), instructions: z.array(z.string()).describe("List of instructions"), servings: z.number().describe("Amount of Portions"), prepTime: z.number().describe("Preparation time in minutes"), cookTime: z.number().describe("Cooking time in minutes"), totalTime: z.number().describe("Total time in minutes"), tags: z.array(z.string()).describe( "List of tags (e.g., ['vegan', 'dessert'])", ), notes: z.array(z.string()).describe("Optional notes about the recipe"), }); const noRecipeSchema = z.object({ errorMessages: z.array(z.string()).describe( "List of error messages, if no recipe was found", ), }); export const recipeResponseSchema = z.union([recipeSchema, noRecipeSchema]); export function isValidRecipe( recipe: | { ingredients?: unknown[]; instructions?: string[]; name?: string } | null | undefined, ) { return recipe?.ingredients?.length && recipe.ingredients.length > 1 && recipe?.instructions?.length && recipe.name?.length; } export default recipeSchema;