From 33c72ddacdad2a42d72c2022c1cc9bfb709701fe Mon Sep 17 00:00:00 2001 From: "Sven (AAMOS AI)" Date: Fri, 14 Aug 2026 20:28:56 +0700 Subject: [PATCH] =?UTF-8?q?fix(reco):=20fria=20s=C3=B6kord=20+=20mjuk-filt?= =?UTF-8?q?er=20s=C3=A5=20r=C3=A5varu-s=C3=B6kning=20(kyckling)=20ger=20r?= =?UTF-8?q?=C3=A4tt=20recept=20(MIKRO=2060)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/api/src/routes/recommendations.ts | 17 +++++++++- packages/recommendation-engine/src/craving.ts | 32 ++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/apps/api/src/routes/recommendations.ts b/apps/api/src/routes/recommendations.ts index 3dbb709..5f3c595 100644 --- a/apps/api/src/routes/recommendations.ts +++ b/apps/api/src/routes/recommendations.ts @@ -393,7 +393,22 @@ export async function recommendationRoutes(app: FastifyInstance) { const weights = personalizationEnabled ? viewWeights(q.view) : depersonalize(viewWeights(q.view)); - let recommendations = rankAll(scoredCandidates, ctx, weights, q.limit); + + // Om användaren sökte specifikt (t.ex. "kyckling") – visa matchande recept först. + let pool = scoredCandidates; + if (craving && (craving.keywords.length > 0 || craving.cuisine)) { + const matches = scoredCandidates.filter((c) => { + const title = c.titleSv.toLowerCase(); + const tagSet = new Set(c.tags as unknown as string[]); + return ( + (!!craving.cuisine && c.cuisine === craving.cuisine) || + craving.keywords.some((k) => title.includes(k) || tagSet.has(k)) + ); + }); + if (matches.length > 0) pool = matches; // annars behåll alla (aldrig tomt) + } + + let recommendations = rankAll(pool, ctx, weights, q.limit); // --- 9. AAMOS-omrankning bakom feature flag (aldrig obligatorisk) --- if (await app.flags.isEnabled("ai_rerank", req.userId)) { diff --git a/packages/recommendation-engine/src/craving.ts b/packages/recommendation-engine/src/craving.ts index 518f867..77891c6 100644 --- a/packages/recommendation-engine/src/craving.ts +++ b/packages/recommendation-engine/src/craving.ts @@ -4,6 +4,7 @@ export interface ParsedCraving { tags: string[]; cuisine?: Cuisine | undefined; maxKcal?: number | undefined; + keywords: string[]; } /** @@ -66,5 +67,34 @@ export function parseCraving(text: string): ParsedCraving { const kcalMatch = lower.match(/under\s+(\d{2,4})\s*(?:kcal|kalorier)/); if (kcalMatch?.[1]) maxKcal = Number(kcalMatch[1]); - return { tags, cuisine, maxKcal }; + const STOPWORDS = new Set([ + "jag", + "är", + "sugen", + "på", + "vill", + "ha", + "något", + "lite", + "och", + "med", + "gärna", + "känner", + "för", + "mig", + "idag", + "ikväll", + "kväll", + "mat", + "äta", + "laga", + "göra", + "en", + "ett", + ]); + const keywords = lower + .split(/[^a-zåäö0-9]+/) + .filter((w) => w.length >= 3 && !STOPWORDS.has(w)); + + return { tags, cuisine, maxKcal, keywords }; }