feat(ai): Vercel AI SDK provider factory with BYOK and per-use-case model prefs
Provider factory (OpenAI/Anthropic/OpenRouter/Ollama). generateObject for all outputs. Features: recipe generation, photo-to-recipe vision, variations, drink/meal pairings, ingredient substitution, recipe adaptation, nutrition analysis, URL import, meal plan gen. User BYOK keys (AES-256-GCM). Per-use-case model preferences (text/vision/mealPlan). Site-level key override via admin settings.
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import { generateObject } from "ai";
|
||||
import { z } from "zod";
|
||||
import { resolveModel, type AiConfig } from "../factory";
|
||||
|
||||
const DietaryOutputSchema = z.object({
|
||||
vegan: z.boolean(),
|
||||
vegetarian: z.boolean(),
|
||||
glutenFree: z.boolean(),
|
||||
dairyFree: z.boolean(),
|
||||
nutFree: z.boolean(),
|
||||
halal: z.boolean(),
|
||||
kosher: z.boolean(),
|
||||
reasoning: z.record(z.string(), z.string()).optional(),
|
||||
});
|
||||
|
||||
export type InferredDietaryTags = Omit<z.infer<typeof DietaryOutputSchema>, "reasoning">;
|
||||
|
||||
export async function inferDietaryTags(
|
||||
ingredients: Array<{ rawName: string; unit?: string | null }>,
|
||||
config?: AiConfig
|
||||
): Promise<InferredDietaryTags> {
|
||||
const model = resolveModel(config);
|
||||
|
||||
const ingredientList = ingredients.map((i) => i.rawName).join(", ");
|
||||
|
||||
const { object } = await generateObject({
|
||||
model,
|
||||
schema: DietaryOutputSchema,
|
||||
system:
|
||||
"You are a dietary classification expert. Analyze recipe ingredients and determine dietary tags accurately. Be conservative — only mark something as true if you are confident based on the ingredients listed.",
|
||||
prompt: `Classify these ingredients for dietary tags: ${ingredientList}`,
|
||||
});
|
||||
|
||||
const { reasoning: _reasoning, ...tags } = object;
|
||||
return tags;
|
||||
}
|
||||
Reference in New Issue
Block a user