Files
Cibello-app/docs/30-sökrobusthet-matvaror.md
T
Sven (AAMOS AI) 9197d93a92 feat(inventory): naturlig-språklig fritextsökning med FoodTwin-fakta, trust-hedge och i18n ×12
- Nytt endpoint GET /v1/inventory/natural-search.
- Robust matchning med unaccent + pg_trgm similarity mot display_name,
  brand och kanoniska ingrediensnamn (sv/en).
- Svar byggs deterministiskt från faktisk data: lagringsplats + sublocation
  om registrerad, trust-state-hedge från befintlig trust-motor.
- Server-sidan i18n-katalog för 12 språk.
- Tester för svensk träff och noll-träff på flera språk.
- Design-dokument docs/30-sökrobusthet-matvaror.md.
2026-08-08 05:53:06 +07:00

2.9 KiB
Raw Blame History

Sökrobusthet för matvaror i hushållslagret

Målbild: användaren kan ställa en fritextfråga om vad som finns hemma och få ett svar som känns mänskligt, visar exakt lagring (FoodTwin) och ärligt berättar hur säker appen är utan att hitta på något.

Befintliga motorer

Sökmotor: /v1/inventory

  • Enkel ILIKE mot inventory_items.display_name och brand.
  • Inga synonymer, ingen fonetisk matchning, ingen felstavningstolerans.
  • Filtrering på storage_location_id, expiry_status, paginering.
  • Kombinerar unaccent(...) ILIKE unaccent(...) med PostgreSQL pg_trgm-similarity.
  • Söker även mot kanoniska ingrediensnamn (name_sv, name_en).
  • Sorterar på GREATEST(similarity(...)).
  • Returnerar både strukturerade träffar och ett naturligt-språkligt svar.

Trust-motor (@app/inventory-engine)

  • computeTrust(...) ger trustState (trusted/decaying/stale/unverified) och trustScore 0100.
  • Baserat på confidence, verifiedByUser, ålder och förruttnelseprofil.
  • Används redan i /v1/inventory och vid skanning/konsumtion.

FoodTwin-data

  • storage_locations: namn, typ, sublocations.
  • inventory_items: storage_location_id, sublocation, kvantitet, enhet, trust_state.
  • canonical_ingredients: kanoniskt namn, synonymer, hållbarhetsriktlinjer.

Svarsformat

GET /v1/inventory/natural-search?q=mjölk&languageTag=sv-SE

{
  "query": "mjölk",
  "response": "Jag hittade **Mjölk** i Kylen (mellanmålshyllan). Jag är ganska säker på att den finns kvar.",
  "items": [
    {
      "id": "...",
      "displayName": "Mjölk",
      "quantity": 1,
      "unit": "LITER",
      "locationName": "Kylen",
      "locationType": "fridge",
      "sublocation": "mellanmålshyllan",
      "trustState": "trusted",
      "trustScore": 95
    }
  ]
}

i18n

Server-sidan använder en minimal katalog i apps/api/src/lib/inventorySearchResponse.ts. Stödja språk (12): sv, en, da, de, es, fi, fr, it, nb, nl, pl, pt. Vid okänt språk faller vi tillbaka till engelska och sedan svenska.

Hårda regler

  1. Inga påhittade fakta. Om sublocation saknas visas inte "på hylla X".
  2. Trust-hedge måste matcha trustState. stale ger en osäker formulering; trusted ger en trygg.
  3. Noll träffar ska erkänna det och erbjuda att lägga till.
  4. Flera träffar ska lista dem med lagring och peka på listan för trust-score.

Nästa steg / öppna frågor

  • Ska vi också söka i canonical_ingredients.aliases (array)? Kräver en unnest/CROSS JOIN LATERAL eller en trigram-index på en materialiserad vy.
  • Ska vi lägga till fonetisk matchning (fuzzystrmatch) för vanliga felstavningar?
  • Ska svaret också inkludera hållbarhetsstatus för träffarna?
  • Behövs en separat vector/embedding-sökning för semantiska matchningar (t.ex. "mjölkprodukter")?