Files
microservice-importer/next_steps_MSImporter.md
T
Nils-Johan Gynther bf4e1d48bf
Test Suite / test (24.15.0) (push) Has been cancelled
fix: enhance PDF parsing and retry logic; improve reproducibility and AI filtering
Co-authored-by: Copilot <copilot@github.com>
2026-05-03 22:29:37 +02:00

6.5 KiB

Plan för vidareutveckling av Microservice Importer

Dokumentstatus (2026-05-03)

Detta dokument riktar sig till utvecklare och driftansvariga för microservice-importer.

Senast avklarat i angränsande flöden

  • Regelbaserad kvittotolkning har stärkts för multipack/enheter och svårare radformat.
  • Bröd-/rostbrödklassning har utökade guardrails för att minska felaktig kategorisering.
  • Klientens granskningsflöde och sessionpersistens i Flutter är implementerat, vilket minskar avbrott mellan parse och spara.
  • Kvittokategorisering: nya regler för pasta, grädde, ägg, juice, godis, och potatis samt justerad AI-guardrail.
  • Testinfrastruktur: parametriserade enhetstester för kvittoimport (18 testfall) och CI/CD-pipeline med automatiserad testkörning på push.
  • PDF-parsning stabiliserad: pdf-parse använder nu require() för CJS-kompatibilitet; pdfjs-dist/legacy/build/pdf.js används som fallback för att undvika DOMMatrix-fel i Node.js-miljö.
  • Retry-logik förbättrad: Mistral-anrop vid 429/503 väntar nu 3000 * attempt ms (3s, 6s, 9s) i stället för fast 1s.
  • Reproducerbart bygge: package-lock.json är nu spårat i repot; Dockerfile använder npm ci.
  • AI-optimering implementerad: looksLikeReceiptProductLine() filtrerar bort PDF-rader utan siffra (header/footer/butiksinformation) innan Mistral-anrop. Minskar drastiskt antal onödiga AI-anrop vid kvittoimport.

Status (2026-05-03) — Driftsatt och integrerad med recipe-app

microservice-importer körs som intern tjänst (importer-api) i recipe-app/compose.yml. Alla importflöden är delegerade och driftsatta.

Endpoint Funktion Status
POST /api/quick-import URL-skrapning (ICA, generisk), PDF, OCR-bild Driftsatt
POST /api/recipes/parse-markdown Markdown → ingrediensstruktur (utan DB) Driftsatt
POST /api/receipt-import/parse Kvittobild/PDF → ParsedReceiptItem[] via Mistral AI Driftsatt
GET /api/health Hälsokontroll (används av Docker healthcheck) Driftsatt

Serverstruktur:

/opt/containers/
  microservice-importer/   ← klonas och pullas separat
  recipe-app/
    compose.yml            ← bygger importer-api från ../microservice-importer
    deploy.sh

Deploy:

cd /opt/containers/microservice-importer && git pull
cd /opt/containers/recipe-app && git pull && ./deploy.sh

Nästa steg

Hög prioritet

  • Kvittoimport Fas 6b — Granskningssteg och bulk-spara i Flutter-klienten (backend-logiken är klar)

Medel prioritet

  • Fler webbplats-parsers — Specifika parsers för t.ex. Tasteline, Köket.se, Arla
  • Swagger/OpenAPI — Automatisk API-dokumentation via @nestjs/swagger
  • Testtäckning — Utökad enhetstesttäckning för parsers och receipt-parsing.service.ts (18 testfall för kvittoimport)

Låg prioritet / Framtida

  • Caching — Cacha skrapade sidor för att minska belastning på externa webbplatser
  • Puppeteer — Hantera JavaScript-renderade receptsidor
  • Word-dokument — Stöd för .docx-import

AI-optimering: Mistral-modell och pipeline

Nuläge: mistral-small-2603 används för bildinput (vision). För PDF-flödet extraheras text först via pdf-parse/pdfjs-dist; sedan regelbaserad parsning; sedan AI enbart för återstående rader.

Implementerad optimering: AI sist i pipeline (PDF)

Kvittopipelinen för PDF ser nu ut:

PDF → pdf-parse / pdfjs-dist → preprocessPdfLines → isIgnoredReceiptLine → ruleBasedParseLine → looksLikeReceiptProductLine → AI

looksLikeReceiptProductLine(line) filtrerar bort rader som saknar siffra (butiksnamn, datum, välkomsttext m.m.) innan Mistral-anropet. Enbart rader med namnliknande text OCH minst ett tal skickas till AI.

Fördelar:

  • Regelbaserad parsning hanterar standardfall gratis och snabbt (t.ex. "MJÖLK 1,5L", "BLANDFÄRS 997G")
  • AI anropas bara för rader som regelverket inte kan tolka entydigt
  • Möjlighet att använda en mindre/billigare modell för enklare tolkningsuppgifter

Modellval för olika deluppgifter

Uppgift Rekommenderad modell Motivering
Kvittoparsning (hela bilden, nuläge) mistral-small-2603 Vision-förmåga krävs för bild-input
Tolka OCR-text (textbaserad input) mistral-small-latest eller mindre Enklare uppgift när text redan extraherats
Kategorisering av enskild produktrad open-mistral-nemo (7B) Klassificering, ej vision — kan vara mycket liten

OBS: För bild-input (JPEG/PNG/HEIC/WebP) krävs alltid en vision-kapabel modell. Optimering med mindre modell är bara möjlig när Tesseract/pdf-parse redan har extraherat text.


Framtida förbättringar

Schemalagd Uppdatering av Kategorier

  • Mål: Implementera en schemalagd uppdatering av kategorierna en gång i veckan för att säkerställa att cachen alltid är uppdaterad.
  • Metod: Använda cron för att schemalägga ett anrop till POST /receipt-import/refresh-categories en gång i veckan.

Nuvarande Implementering

Manuell Uppdatering av Kategorier

  • Mål: Låta användaren manuellt uppdatera kategorierna via Flutter-UI.
  • Implementering:
    • En knapp i Flutter-UI:n som låter användaren trigga uppdateringen.
    • Anropa POST /receipt-import/refresh-categories från Flutter-UI:n när användaren klickar på knappen.
// Exempel på hur du kan anropa endpointen från Flutter
Future<void> refreshCategories() async {
  final response = await http.post(
    Uri.parse('http://YOUR_API_URL/receipt-import/refresh-categories'),
    headers: {'Authorization': 'Bearer YOUR_JWT_TOKEN'},
  );

  if (response.statusCode == 200) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Kategorier har uppdaterats.')),
    );
  } else {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Misslyckades med att uppdatera kategorier.')),
    );
  }
}

Arkitektur-noteringar

  • Tjänsten är helt stateless — ingen databas, ingen session
  • Kommunicerar aldrig direkt med internet-klienter — exponeras bara på recipe-internal-nätverket
  • MISTRAL_API_KEY injiceras via env (samma nyckel som recipe-api använder)
  • Alpine Docker-image: systempaket tesseract-ocr, tesseract-ocr-data-swe, tesseract-ocr-data-eng installerade via apk
  • Host-port 3001 är upptagen av wetty på servern — importer-api exponeras aldrig till host