723730fd2f
Co-authored-by: Copilot <copilot@github.com>
133 lines
5.7 KiB
Markdown
133 lines
5.7 KiB
Markdown
# 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.
|
|
|
|
## 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:**
|
|
```bash
|
|
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 kvittoparsning. Modellen tar emot hela kvittobilden/PDF-texten och returnerar strukturerad JSON.
|
|
|
|
### Möjlig optimering: AI sist i pipeline
|
|
|
|
Eftersom tjänsten redan har OCR (Tesseract) och regelbaserad parsning (regex för `NxYg`, `Ydl`, `Y kg` etc.) finns möjlighet att omstrukturera kvittopipelinen:
|
|
|
|
```
|
|
Bild/PDF → OCR/pdf-parse → Regelbaserad parsning → AI (för rader som inte lösts ut)
|
|
```
|
|
|
|
**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.
|
|
|
|
```dart
|
|
// 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
|