import { generateObject } from "ai"; import { z } from "zod"; import { resolveModel, type AiConfig } from "../factory"; const RecipeOutputSchema = z.object({ title: z.string(), description: z.string(), baseServings: z.number().int().min(1).max(100), prepMins: z.number().int().min(0).optional(), cookMins: z.number().int().min(0).optional(), difficulty: z.enum(["easy", "medium", "hard"]), dietaryTags: z.object({ vegan: z.boolean().optional(), vegetarian: z.boolean().optional(), glutenFree: z.boolean().optional(), dairyFree: z.boolean().optional(), nutFree: z.boolean().optional(), halal: z.boolean().optional(), kosher: z.boolean().optional(), }), ingredients: z.array(z.object({ rawName: z.string(), quantity: z.number().optional(), unit: z.string().optional(), note: z.string().optional(), })), steps: z.array(z.object({ instruction: z.string(), timerSeconds: z.number().int().optional(), })), }); export type GeneratedRecipe = z.infer; export async function generateRecipe( prompt: string, config?: AiConfig & { language?: string } ): Promise { const model = resolveModel(config); const lang = config?.language ?? "en"; const langInstruction = lang !== "en" ? ` Write the entire recipe (title, description, ingredient names, step instructions) in ${lang}.` : ""; const { object } = await generateObject({ model, schema: RecipeOutputSchema, system: `You are a professional chef and culinary writer. Generate detailed, accurate, and delicious recipes. For ingredients: quantity must be a number only (e.g. 0.25, 1.5, 2), unit is a separate string (e.g. 'cup', 'tbsp', 'g', 'ml'). Never combine quantity and unit into one string. Include helpful notes for ingredients when relevant.${langInstruction}`, prompt: `Create a recipe for: ${prompt}`, }); return object; }