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

126 lines
6.8 KiB
Markdown

# 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
5. Säkerställ att response-format fortsatt matchar `FlyerImportResponse` (ingen breaking change mot Flutter).
6. Förbättra controller MIME-regler så de stämmer med faktiska stödda format.
7. 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
8. Visa backend `warnings` i `flyer_import_tab.dart`.
9. Lägg till kvalitetsindikator + minimala filterchips.
10. Förfina loading/feltexter utan att ändra grundlayouten.
### Fas D - Verifiering
11. Backendtester för intern flyer-parser (happy path + fallback + felbanor).
12. Uppdatera/addera Flutter widgettester för warnings/indikator/filter.
13. 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.