import { generateObject } from "ai"; import { z } from "zod"; import { resolveModel, type AiConfig } from "../factory"; const ImportedRecipeSchema = z.object({ title: z.string(), description: z.string().optional(), baseServings: z.number().int().min(1).optional(), prepMins: z.number().int().min(0).optional(), cookMins: z.number().int().min(0).optional(), difficulty: z.enum(["easy", "medium", "hard"]).optional(), 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(), }).optional(), ingredients: z.array(z.object({ rawName: z.string(), quantity: z.string().optional(), unit: z.string().optional(), note: z.string().optional(), })), steps: z.array(z.object({ instruction: z.string(), timerSeconds: z.number().int().optional(), })), }); export type ImportedRecipe = z.infer; export async function importFromPhoto( imageBase64: string, mimeType: "image/jpeg" | "image/png" | "image/webp", config?: AiConfig, _locale?: string, ): Promise { const model = resolveModel(config); const { object } = await generateObject({ model, schema: ImportedRecipeSchema, system: "You are a recipe extraction specialist. Extract the complete recipe from the provided image. Be precise with ingredient quantities and cooking instructions.", messages: [ { role: "user", content: [ { type: "image", image: imageBase64, mediaType: mimeType }, { type: "text", text: "Extract the complete recipe from this image." }, ], }, ], }); return object; }