import { generateObject } from "ai"; import { z } from "zod"; import { resolveModel, type AiConfig } from "../factory"; const ScaledIngredientsSchema = z.object({ ingredients: z.array( z.object({ rawName: z.string().describe("Ingredient name only, e.g. 'flour' — never include the scaled quantity or unit here."), quantity: z.string().describe("The scaled quantity as a number only, e.g. '3' or '1.5'."), unit: z.string().nullable(), note: z.string().optional(), }) ), }); export type ScaledIngredient = z.infer["ingredients"][number]; type RecipeInput = { title: string; baseServings: number; ingredients: Array<{ rawName: string; quantity: string | null; unit: string | null; }>; }; export async function scaleRecipe( recipe: RecipeInput, targetServings: number, originalServings: number, config?: AiConfig, locale?: string ): Promise { const model = resolveModel(config); const ingredientList = recipe.ingredients .map((ing) => { const parts = [ing.quantity, ing.unit, ing.rawName].filter(Boolean); return `- ${parts.join(" ")}`; }) .join("\n"); const { object } = await generateObject({ model, schema: ScaledIngredientsSchema, system: `You are a culinary scaling expert. Scale recipe ingredients from ${originalServings} to ${targetServings} servings. Use practical quantities — no 0.33 eggs (round to whole), no 0.17 cans (use 0.25 or 0.5), avoid impractical fractions. Substitute whole units where sensible. Add a note when rounding significantly.`, prompt: `Recipe: "${recipe.title}"\n\nIngredients to scale:\n${ingredientList}`, }); return object.ingredients; }