Files
recipe-app/.kilo/plans/1779211060426-happy-island.md
Nils-Johan Gynther 187d0283a5
Test Suite / quick-import-pr-quick (push) Has been skipped
Test Suite / backend-full (push) Successful in 2m31s
Test Suite / flutter-quality (push) Failing after 3m48s
Test Suite / backend-pr-quick (push) Failing after 13m57s
feat(flyer-import): integrate AI-based flyer parsing with image support
- Add support for PNG, JPEG, and WebP image formats in flyer import
- Replace external importer service with internal AI-based parsing pipeline
- Add new services: TextExtractorService, AiFlyerParserService, FlyerNormalizerService
- Integrate Mistral AI, pdf-parse, and tesseract.js dependencies
- Add quality confidence indicators and warning panels in Flutter UI
- Update package.json with new dependencies and transform ignore patterns
- Add documentation for flyer importer system
- Add Kilo AI planning file for Happy Island project

BREAKING CHANGE: Flyer import now uses internal AI parsing instead of external importer service
2026-05-19 19:57:54 +02:00

6.8 KiB

Plan: Omgjord flyerimport (pdf-parse + tesseract + Mistral Tiny)

Mål

Ersätta nuvarande flyerimportflöde (som idag delegerar till importer-api) med en robust pipeline som:

  1. extraherar text från flyer-PDF (primärt pdf-parse, fallback OCR via Tesseract),
  2. skickar normaliserad text till Mistral Tiny,
  3. returnerar strikt strukturerad JSON,
  4. behåller befintlig matchning/planeringsflöde i backend + Flutter men förbättrar UX kring importresultat och fel.

Nulägesanalys (projektanpassad)

  • Backend endpoint finns: POST /flyer-import/parse i backend/src/flyer-import/flyer-import.controller.ts.
  • Nuvarande backendlogik i backend/src/flyer-import/flyer-import.service.ts anropar extern tjänst via IMPORTER_SERVICE_URL (/api/flyer/parse).
  • Flutter har redan komplett flyerflik i flutter/lib/features/import/presentation/flyer_import_tab.dart:
    • filval, importknapp, preview, radrendering med checkboxar, bulk-planering.
  • Datamodell för sessions/items finns redan i Prisma (FlyerSession, FlyerItem, FlyerSelection) och stödjer parse+match-metadata.
  • flyerimporter.md beskriver rätt riktning men är generisk; projektet behöver NestJS-integration och kompatibilitet med befintliga DTO/Flutter-modeller.

Föreslagen arkitektur (ersättning av dagens lösning)

1) Ny intern parser i recipe-api (NestJS)

  • Ersätt parseViaImporter(...) i FlyerImportService med lokal pipeline:
    • extractFlyerText(file)
      • PDF/text-extraktion via pdf-parse.
      • Fallback OCR via Tesseract för sidor/underlag utan användbar text.
    • parseFlyerWithMistral(text)
      • Mistral Tiny-anrop med strikt JSON-schema-prompt.
    • normalizeFlyerItems(aiJson)
      • validering, typkonvertering, enhetsnormalisering, confidence/reasonCodes.
  • Behåll resten av tjänsten intakt (matchning, sessionpersistens, selections-kompatibilitet).

2) AI-kontrakt (strikt JSON)

  • Introducera explicit schema för AI-svar (intern typ + runtime-validering):
    • rawName, normalizedName, category, price, priceUnit, comparisonPrice, comparisonUnit, offerText, confidence, reasonCodes.
  • Promptdesign:
    • svensk flyer-kontext,
    • tydlig enhets- och prisnormalisering,
    • "returnera ENDAST JSON" + exempel,
    • fallback vid saknade fält (null, tomma listor).
  • Robust parsing av modelloutput:
    • ta bort ev. markdown fences,
    • fail-fast med tydligt felmeddelande om ogiltigt JSON.

3) OCR-strategi

  • Primärväg: pdf-parse (snabb, billig).
  • OCR-fallback: bara när extraherad text är tom/under tröskel.
  • Preprocess för OCR (vid behov): sidvis rasterisering + språk swe (ev. swe+eng).
  • Timeout/guardrails per steg för att undvika låsta importer.

4) API/infra-anpassning

  • Controller (flyer-import.controller.ts):
    • uppdatera tillåtna MIME-typer så de matchar Flutter-filtyper (PDF + bilder om vi ska stödja bildflyers).
  • compose.yml/env:
    • gör IMPORTER_SERVICE_URL optional eller avveckla för flyerflödet.
    • säkerställ MISTRAL_API_KEY används av recipe-api för flyer.
  • Dokumentation:
    • uppdatera teknisk beskrivning så flyerimport inte längre kräver extern flyer-parser.

UX-analys Flutter (nuvarande) och planerade förbättringar

Nuvarande UX (bra att bygga vidare på)

  • Enkel 3-stegsinteraktion: välj fil -> importera -> markera/planera.
  • Förhandsvisning finns och passar arbetsflödet.
  • Offer-badge + pris/jämförpris + matchvisning ger snabb scanning.

UX-gap att täppa till i denna implementation

  • Ingen tydlig visning av parserwarnings från backend (fältet warnings finns i modellen).
  • Ingen kvalitetssignal i UI trots att parseConfidence/matchConfidence finns.
  • Felmeddelanden är relativt råa; saknar råd per feltyp (timeout, ogiltig fil, AI-svar oformaterat).

Föreslagna UX-förbättringar (inkrementella, kompatibla)

  1. Visa warnings över resultatlistan i en kompakt varningspanel.
  2. Lägg till "kvalitetsindikator" per rad (t.ex. låg/medel/hög) baserat på parseConfidence + matchConfidence.
  3. Lägg till filterchips: Endast erbjudanden, Saknar matchning, Låg kvalitet.
  4. Förbättra loading-state med stegnära text ("Extraherar text", "Tolkar med AI", "Matchar produkter").
  5. Felmappning till användarvänliga meddelanden i showErrorDialog (teknisk detalj i kopierbar sekundärtext).

Implementationsplan (ordning)

Fas A - Backend kärna

  1. Lägg till dependencies i backend/package.json för PDF/OCR/Mistral-klient.
  2. Skapa intern flyer-parser service i backend/src/flyer-import/ (text extraction + AI parse).
  3. Byt parseViaImporter till intern implementation i FlyerImportService.
  4. Lägg till runtime-validering och normalisering av AI-svar.

Fas B - Kontrakt och robusthet

  1. Säkerställ att response-format fortsatt matchar FlyerImportResponse (ingen breaking change mot Flutter).
  2. Förbättra controller MIME-regler så de stämmer med faktiska stödda format.
  3. Lägg till tydliga felkoder/meddelanden för:
    • tom/oläsbar flyer,
    • AI-parsefel,
    • timeout/service unavailable.

Fas C - Flutter UX på befintlig skärm

  1. Visa backend warnings i flyer_import_tab.dart.
  2. Lägg till kvalitetsindikator + minimala filterchips.
  3. Förfina loading/feltexter utan att ändra grundlayouten.

Fas D - Verifiering

  1. Backendtester för intern flyer-parser (happy path + fallback + felbanor).
  2. Uppdatera/addera Flutter widgettester för warnings/indikator/filter.
  3. Manuell E2E: PDF med text, PDF med skannade sidor, bildflyer, trasig fil.

Filer som sannolikt berörs vid implementation

  • backend/src/flyer-import/flyer-import.service.ts
  • backend/src/flyer-import/flyer-import.controller.ts
  • backend/src/flyer-import/dto/flyer-import.response.ts (endast om extra metadata behövs)
  • backend/package.json
  • flutter/lib/features/import/presentation/flyer_import_tab.dart
  • Ev. flutter/lib/features/import/domain/flyer_import_item.dart (om ny UI-metadata exponeras)
  • Dokumentation: TEKNISK_BESKRIVNING.md (kort uppdatering av arkitektur)

Risker och mitigering

  • OCR-prestanda/latens: använd fallback-only och timeout.
  • Mistral kan ge semistrukturerat svar: strikt schema + robust JSON-sanitizing + validering.
  • Kostnad/kvot på AI-anrop: minimera promptstorlek, trunkera brus, återanvänd normalisering.
  • Driftöverraskningar: behåll endpoint-kontrakt oförändrat mot Flutter.

Acceptance criteria

  • Flyerimport fungerar utan beroende av extern /api/flyer/parse i importer-api.
  • Minst en PDF med inbäddad text och en skannad PDF importeras framgångsrikt.
  • Backend returnerar valid FlyerImportResponse och befintlig planeringsfunktion fortsätter fungera.
  • Flutter visar warnings och gör det tydligare vilka rader som behöver manuell granskning.

Fastställt beslut

  • Första leveransen ska stödja PDF + bildfiler (png/jpg/webp) fullt ut.