feat: Enhance recipe import functionality with support for PDF, image, and URL inputs

This commit is contained in:
Nils-Johan Gynther
2026-04-14 22:48:57 +02:00
parent ea5f97ab82
commit a2038ffbec
2 changed files with 57 additions and 33 deletions
+42 -24
View File
@@ -25,6 +25,13 @@ Recipe App är en fullstack-applikation för hantering av hemmavaror, recept och
| Container | Docker | 24+ |
| Converter | Node.js (TypeScript) | Noll externa beroenden |
### Container- och deployupplägg
- `compose.yml` bygger lokala images för frontend och backend
- `pull_policy: never` används för appens lokala images för att undvika felaktiga registry-pulls i Portainer
- Health checks finns för databas, API och frontend
- `depends_on` med hälsovillkor används för stabilare startordning i Docker och Portainer
---
## Frontend
@@ -68,6 +75,7 @@ Recipe App är en fullstack-applikation för hantering av hemmavaror, recept och
| Route | Metod | Syfte |
|-------|-------|-------|
| `/api/quick-import-proxy` | POST | Proxies `POST /api/quick-import` för URL-, PDF- och bildimport |
| `/api/parse-markdown-proxy` | POST | Proxies `POST /api/recipes/parse-markdown` (Markdown-tolkning för skriv-in-recept) |
| `/api/inventory-history-proxy` | GET | Proxies konsumtionshistorik |
| `/api/recipe-preview-proxy` | GET | Proxies receptförhandsvisning |
@@ -154,19 +162,23 @@ backend/src/
**Quick-Import API:** 📌 (Även tillgänglig via [Microservice Importer](../microservice-importer/))
- **Endpoint:** `POST /api/quick-import`
- **Input:** URL (t.ex. `https://ica.se/recept/...`) eller filsökväg (PDF)
- **Input:**
- JSON-body med `input` för URL eller servermonterad filsökväg
- `multipart/form-data` med `file` för uppladdad PDF eller bild
- **Stödda format:** PDF, PNG, JPG, JPEG, WEBP, BMP samt receptlänkar
- **Process:**
1. URL-validering (HTTP fetch med User-Agent)
2. Parser-urval baserat på `canHandle(url)`
3. HTML-parsing och receptextraktion
4. Markdown-konvertering med källlänk i footer
1. Typdetektering av URL, PDF eller bild
2. URL-import via site-specifik eller generisk parser
3. PDF-import via `pdf-parse`
4. Bildimport via `tesseract.js` OCR (`swe+eng`)
5. Normalisering till Markdown-format för vidare receptgranskning
- **Parser-arkitektur:**
- **Base Parser** (`RecipeParser`): Abstract class med gemensam parseIngredientLine()-logik
- Hanterar bråkmängder (1 1/2 dl), parentetiska noter, unit-validering
- Kända enheter: g, kg, hg, mg, ml, dl, l, tl, st, tsk, msk, krm, port, efter smak, förp, klyfta, m.fl.
- **ICA Parser** (`IcaRecipeParser`): Prioriterar JSON-LD structured data, fallback HTML
- **Generic Parser** (`GenericRecipeParser`): Försöker alla webbplatser (JSON-LD → HTML)
- **Output:** Markdown-format recepttext (namn, beskrivning, ingredienser, instruktioner, källa)
- **Output:** Markdown-format recepttext med `source: 'ica' | 'pdf' | 'image' | 'other'`
**Inventarie-API:**
- CRUD för inventarieföremål (produktreferens, kvantitet, enhet, plats, märke, bäst före, mm)
@@ -213,8 +225,8 @@ backend/src/
### 🏥 Health endpoints
```
GET /health Övergripande hälsakontroll (200/503)
GET /health/db Databasspecifik hälsa + responseTime
GET /api/health Övergripande hälsakontroll (200/503)
GET /api/health/db Databasspecifik hälsa + responseTime
```
### 📦 Inventarie-endpoints
@@ -230,8 +242,8 @@ GET /api/inventory/:id/consumption-history Konsumtionshistorik
### 🍽️ Recept-endpoints
```
POST /api/quick-import SNITT: Snabbimport (ICA-skrapning)
Body: { input: string (URL eller filsökväg) }
POST /api/quick-import Snabbimport från URL, PDF eller bild
Body: { input: string } eller multipart-form med file
POST /api/recipes/parse-markdown Tolka Markdown-recept (matchningslogik)
GET /api/recipes Lista alla recept
POST /api/recipes Skapa nytt recept
@@ -364,7 +376,7 @@ Recipe App erbjuder tre vägar för att lägga till recept:
1. **Snabbimport** — Klistra in ICA-länk för automatisk skrapning (ny feature)
2. **Skriv in recept** (`/recipes/write`) — Markdown-baserad inmatning där användaren skriver receptet i enkelt format
3. **Importera från fil** (`/recipes/import`) — Ladda upp PDF, länk eller andra receptkällor (under utveckling)
3. **Importera från fil** (`/recipes/import`) — Ladda upp PDF, bild eller länk och få en första Markdown-version automatiskt
Alla vägar möjliggör automatisk matchning av ingredienser mot databasen.
@@ -383,20 +395,26 @@ Alla vägar möjliggör automatisk matchning av ingredienser mot databasen.
5. Omdirigera till `/recipes/write` med förifylld Markdown
**Backend: `QuickImportService` (ny modul)**
- Ansvarig för ICA-skrapning, PDF-tolkning, URL-validering
- **Huvudmetod:** `importFromInput(input: string)` — Detekterar input-typ och delegerar
- **ICA-specifik:**
- Validerar URL (måste vara ICA.se)
- Fetchar HTML via `fetch()`
- Parsar HTML med regex för: receptnamn, ingredienser, instruktioner
- Konverterar till Markdown-format
- **Felhantering:** Specifika felmeddelanden per scenario
- **PDF-support:** Stubben för framtida integration (throwError: "PDF-import är under utveckling")
- Ansvarig för URL-import, PDF-tolkning, bild-OCR och Markdown-normalisering
- **Huvudmetoder:**
- `importFromInput(input: string)` — Detekterar URL eller serverfilsökväg
- `importFromUpload(file)` — Hanterar uppladdad PDF eller bildfil
- **URL-specifik logik:**
- Validerar URL
- Fetchar HTML via `fetch()` med User-Agent
- Väljer site-specifik parser eller generisk fallback
- Konverterar resultatet till Markdown-format
- **PDF-logik:**
- Extraherar text med `pdf-parse`
- Stoppar om ingen läsbar text hittas
- **Bildlogik:**
- OCR via `tesseract.js`
- Svensk och engelsk språkmodell (`swe+eng`)
- **Error-strategi:**
- `400 Bad Request` — Tomt input, inte URL/fil
- `400 Bad Request`Länken är inte från ICA.se
- `503 Service Unavailable`Network-fel vid hämtning (HTTP-fel från ICA)
- `400 Bad Request` — HTML-parsing misslyckades (receptnamn/ingredienser inte hittade)
- `400 Bad Request` — Tomt input eller saknad fil
- `400 Bad Request`Ostödd filtyp eller ingen läsbar text
- `503 Service Unavailable`Misslyckad PDF- eller OCR-behandling
- `400 Bad Request` — HTML-parsing eller hämtning misslyckades
**API-endpoint:**
```