feat(recipe-generation): Cibello Receptkatalog Fas A – STEG 1
- Nytt paket @app/recipe-generation med pipeline, verifieringsgrind, gaprapport och pilotbatch-script. - Ny AAMOS-task GENERATE_RECIPE_CANDIDATES i @app/ai-contracts. - GeminiAamosClient utökat med receptgenereringsstöd. - MockAamosClient uppdaterad med deterministiska kandidater. - Verifieringspipeline: ingrediensmappning (hård spärr), härledda allergener, beräknad näring via nutrition-engine, språk-/kvalitetskontroll, dedup. - Hermetiska tester: 10/10 gröna. - typecheck + test + build: gröna för hela workspace. Refs: docs/32-receptkatalog-buildout.md
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { MockAamosClient } from "@app/ai-contracts";
|
||||
import { runPipeline, type PipelineTarget, type PipelineIngredient } from "../src/pipeline.js";
|
||||
import type { CanonicalIngredientLookup, SimilarityLookup } from "../src/verification.js";
|
||||
|
||||
const mockClient = new MockAamosClient();
|
||||
|
||||
const mockIngredients: CanonicalIngredientLookup = {
|
||||
getById(id: string) {
|
||||
const db: Record<string, ReturnType<CanonicalIngredientLookup["getById"]>> = {
|
||||
kycklingfile: {
|
||||
id: "kycklingfile",
|
||||
nutritionPer100: {
|
||||
basis: "per_100_g",
|
||||
values: {
|
||||
kcal: 165, proteinG: 31, carbsG: 0, fatG: 3.6,
|
||||
saturatedFatG: 1, fiberG: 0, sugarG: 0, saltG: 0.1,
|
||||
},
|
||||
},
|
||||
defaultUnit: "GRAM",
|
||||
densityGPerMl: null,
|
||||
gramsPerPiece: null,
|
||||
allergens: [],
|
||||
isVegan: false,
|
||||
isVegetarian: false,
|
||||
containsGluten: false,
|
||||
containsLactose: false,
|
||||
isPork: false,
|
||||
isBeef: false,
|
||||
isAlcohol: false,
|
||||
},
|
||||
};
|
||||
return db[id] ?? undefined;
|
||||
},
|
||||
};
|
||||
|
||||
const noSimilarity: SimilarityLookup = {
|
||||
async hasSimilarity() {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
|
||||
const catalog: PipelineIngredient[] = [
|
||||
{
|
||||
id: "kycklingfile",
|
||||
nameSv: "kycklingfilé",
|
||||
category: "kott_fagel",
|
||||
defaultUnit: "GRAM",
|
||||
isVegan: false,
|
||||
isVegetarian: false,
|
||||
containsGluten: false,
|
||||
containsLactose: false,
|
||||
allergens: [],
|
||||
},
|
||||
];
|
||||
|
||||
const targets: PipelineTarget[] = [
|
||||
{ mealType: "dinner", mainIngredientId: "kycklingfile", dietVariant: "standard", count: 2 },
|
||||
];
|
||||
|
||||
describe("runPipeline", () => {
|
||||
it("kör med mockad klient och returnerar resultat", async () => {
|
||||
const result = await runPipeline(mockClient, targets, catalog, mockIngredients, noSimilarity);
|
||||
expect(result.geminiResult.status).toBe("ok");
|
||||
// MockAamosClient returnerar nu kandidater för GENERATE_RECIPE_CANDIDATES
|
||||
expect(result.candidates.length).toBeGreaterThan(0);
|
||||
expect(result.verifiedCount + result.unverifiedCount + result.rejectedCount).toBe(result.candidates.length);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user