import type { Cuisine } from "@app/shared-types"; export interface ParsedCraving { tags: string[]; cuisine?: Cuisine | undefined; maxKcal?: number | undefined; keywords: string[]; } /** * Deterministisk grundtolkning av "Jag är sugen på …" (spec §19). * Täcker vanliga svenska uttryck utan AI-anrop; AAMOS kan förfina tolkningen * (GENERATE_RECIPE_OPTIONS) men denna bas fungerar alltid, även offline-nära. */ const CUISINE_KEYWORDS: Array<[Cuisine, string[]]> = [ ["thai", ["thai", "thailändskt", "asiatiskt"]], ["japanese", ["japanskt", "sushi", "ramen"]], ["chinese", ["kinesiskt", "wok"]], ["korean", ["koreanskt", "kimchi"]], ["vietnamese", ["vietnamesiskt", "pho"]], ["indian", ["indiskt", "curry"]], ["italian", ["italienskt", "pasta", "pizza"]], ["french", ["franskt"]], ["spanish", ["spanskt", "tapas", "paella"]], ["greek", ["grekiskt", "gyros", "tzatziki"]], ["mexican", ["mexikanskt", "tacos", "tex mex", "texmex"]], ["american", ["amerikanskt", "burgare", "hamburgare"]], ["turkish", ["turkiskt", "kebab"]], ["lebanese", ["libanesiskt", "meze"]], ["moroccan", ["marockanskt", "tagine"]], ["swedish", ["svenskt", "husman", "husmanskost"]], ["nordic", ["nordiskt"]], ]; const TAG_KEYWORDS: Array<[string, string[]]> = [ ["creamy", ["krämigt", "krämig", "gräddigt"]], ["spicy", ["starkt", "stark", "hett", "chili"]], ["fresh", ["fräscht", "fräsch", "lätt", "somrigt"]], ["comfort", ["comfort", "mysmat", "husman", "tröstmat"]], ["luxury", ["lyxigt", "lyx", "fest"]], ["quick", ["snabbt", "snabb", "enkelt", "enkel"]], ["kid_friendly", ["barnvänligt", "barnvänlig", "barn"]], ["high_protein", ["proteinrikt", "protein"]], ["vegetarian", ["vegetariskt", "vegetarisk", "vego"]], ["vegan", ["veganskt", "vegansk"]], ["soup", ["soppa"]], ["stew", ["gryta", "långkok"]], ["grill", ["grill", "grillat"]], ]; export function parseCraving(text: string): ParsedCraving { const lower = text.toLowerCase(); const tags: string[] = []; let cuisine: Cuisine | undefined; for (const [c, words] of CUISINE_KEYWORDS) { if (words.some((w) => lower.includes(w))) { cuisine = c; break; } } for (const [tag, words] of TAG_KEYWORDS) { if (words.some((w) => lower.includes(w))) tags.push(tag); } let maxKcal: number | undefined; const kcalMatch = lower.match(/under\s+(\d{2,4})\s*(?:kcal|kalorier)/); if (kcalMatch?.[1]) maxKcal = Number(kcalMatch[1]); 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 }; }