Files
microservice-importer/README.md
T
Nils-Johan Gynther e18bf79395 feat: Implement PDF document import functionality with Markdown conversion
- Added DocumentImportModule, DocumentImportController, and DocumentImportService for handling PDF uploads.
- Integrated pdf-parse for extracting text from PDF files.
- Created PdfParser for parsing PDF documents and converting them to Markdown format.
- Updated frontend to support file uploads via drag-and-drop and file input for PDF documents.
- Modified API routes to handle document import requests.
- Enhanced error handling for unsupported file types and file size limits.
- Updated README to reflect new features and usage instructions.
2026-04-12 18:57:40 +02:00

10 KiB

Microservice Importer

Standalone-tjänst för import och konvertering av dokument till Markdown-format. Primärt fokus på PDF-filer — textbaserad extraction samt OCR för skannade dokument. Webb-skrapning finns som sekundär funktion för referens och framtida integration.

Kan användas helt oberoende som fristående microservice.


Features

Dokument-Import via PDF

  • Textbaserad extraction — Snabb och precis för digitalt skapade PDFs
  • OCR-detektering — Identifierar skannade bild-PDFs och rapporterar tydligt (OCR-stöd under utveckling)
  • Automatisk konvertering:
    • Titeln extraheras från filnamnet
    • Texten struktureras till Markdown-stycken
    • Metadata sparas (antal sidor, teckenantal, producent, skapelsedatum)
  • Filstorlek: Max 50 MB per fil
  • Format: Multipart/form-data uppladdning

Webb-skrapning (sekundär funktion)

  • Skrapa från ICA.se — JSON-LD structured data + HTML-parsing
  • Generisk parser — Fallback för andra webbplatser
  • Automatisk extraction: Namn, beskrivning, ingredienser, instruktioner

Parse-Markdown endpoint

Tolka Markdown-format utan databaskomplikationer. Användbar för API-integration utan lokal DB.


Arkitektur

Backend (NestJS 10.3, TypeScript 5.4.5)

Port: 3001

src/
├── app.module.ts                           # Root module
├── main.ts                                 # Startpunkt
├── common/
│   ├── filters/
│   │   └── global-exception.filter.ts      # Centraliserad felhantering (svenska meddelanden)
│   └── utils/
│       └── normalize-name.ts               # Namnormalisering (åäö-handling)
├── document-import/                        # PDF-import & konvertering (primär funktion)
│   ├── document-import.controller.ts       # POST /api/document-import
│   ├── document-import.service.ts          # Filvalidering, parser-routing
│   ├── document-import.module.ts
│   └── parsers/
│       ├── document.parser.ts              # Abstrakt bas-klass
│       └── pdf.parser.ts                   # PDF-extraction via pdf-parse
├── quick-import/                           # Webb-skrapning (sekundär funktion)
│   ├── quick-import.controller.ts          # POST /api/quick-import
│   ├── quick-import.service.ts             # Scraping-logik, parser-selection
│   ├── quick-import.module.ts
│   └── parsers/
│       ├── base.parser.ts                  # Abstrakt bas-klass
│       ├── ica.parser.ts                   # ICA.se-specifik (JSON-LD prioritet)
│       └── generic.parser.ts               # Fallback för alla webbplatser
└── recipes/                                # Markdown-tolkning (utan DB)
    ├── recipes.controller.ts               # POST /api/recipes/parse-markdown
    ├── recipes.service.ts
    ├── recipes.module.ts
    └── dto/
        └── parse-markdown.dto.ts

Viktigt: Backend har INGEN databaskonfiguration — stateless service.

Frontend (Next.js 16.2, React 19.2, TypeScript 5.4.5)

Port: 3000

app/
├── layout.tsx                              # Root layout
├── page.tsx                                # Home page
├── Navigation.tsx                          # Minimal nav (Home + Import)
├── import/page.tsx                         # PRIMARY FEATURE — Drag-and-drop filuppladdning
├── api/
│   ├── document-import-proxy/route.ts      # Proxy: multipart/form-data → backend
│   └── parse-markdown-proxy/route.ts       # Proxy: Markdown-tolkning → backend
└── lib/
    ├── api.ts                              # Centraliserad API-access (fetchJson)
    └── error-handler.ts                    # parseErrorResponse (svenska meddelanden)

Quick-Start

Prerequisites

  • Node.js 22.x
  • Docker & Docker Compose (valfritt)

Local Development

# 1. Installera backend
cd backend
npm install
npm run start:dev
# Backend kör på http://localhost:3001

# 2. (I ny terminal) Installera frontend
cd frontend
npm install
npm run dev
# Frontend kör på http://localhost:3000

Öppna http://localhost:3000 → Gå till /import → Klistra in URL

Docker

# Bygg och starta
docker compose up -d

# Frontend: http://localhost:3000
# Backend: http://localhost:3001

Stoppa:

docker compose down

API-dokumentation

POST /api/document-import

Syfte: Ladda upp en PDF och returnera Markdown-text

Request: multipart/form-data med fältet file (PDF, max 50 MB)

curl -X POST http://localhost:3001/api/document-import \
  -F "file=@dokument.pdf"

Response (Success 200):

{
  "markdown": "# Dokument\n\nInnehåll från PDFen...",
  "title": "Dokument",
  "documentType": "pdf",
  "metadata": {
    "pageCount": 5,
    "characterCount": 12400,
    "producer": "Adobe PDF Library",
    "creationDate": "D:20260101120000"
  }
}

Response (Error 400):

{
  "statusCode": 400,
  "message": "Kunde inte läsa dokumentet: PDFen verkar vara en skannad bild utan textlager.",
  "timestamp": "2026-04-12T10:30:00.000Z"
}

Error-scenarier:

  • 400 — Ingen fil bifogad
  • 400 — Fel filtyp (ej PDF)
  • 400 — Filen överstiger 50 MB
  • 400 — Lösenordsskyddad PDF
  • 400 — Skannad bild-PDF utan textlager (OCR ej implementerat ännu)

POST /api/quick-import

Syfte: Skrapa webbsida och returnera Markdown (sekundär funktion)

Request:

{
  "input": "https://ica.se/recept/kottfarssas-1234"
}

Response (Success 200):

{
  "markdown": "# Köttfärssås\n\nEn klassisk...",
  "source": "ica"
}

Error-scenarier:

  • 400 — Tomt input, inte en URL
  • 400 — HTML-parsing misslyckades
  • 503 — Network-fel

POST /api/recipes/parse-markdown

Syfte: Tolka Markdown-format utan databas

Request:

{
  "markdown": "# Titel\n\n## Ingredienser\n- 500 g mjöl\n\n## Tillvägagångssätt\nBlanda..."
}

Response (Success 200):

{
  "name": "Titel",
  "description": "",
  "instructions": "Blanda...",
  "ingredients": [
    { "rawName": "mjöl", "quantity": 500, "unit": "g", "note": null }
  ]
}

Parser-arkitektur

Dokument-parsers (document-import/parsers/)

Abstrakt bas DocumentParser som alla dokumenttyp-specifika parsers ärver från:

abstract class DocumentParser {
  abstract parse(buffer: Buffer, filename: string): Promise<ParsedDocument>;

  protected textToMarkdown(text: string, title: string): string {
    // Slår ihop sammanhängande textrader, bevarar stycken
  }
}

PDF Parser (pdf.parser.ts)

Hanterar textbaserade PDFs via pdf-parse.

Strategi:

  1. Extrahera text med pdf-parse
  2. Kontrollera att text hittades (annars: skannad PDF-varning)
  3. Konvertera text → Markdown via textToMarkdown()
  4. Returnera titel (från filnamn), innehåll och metadata

Felhantering:

  • Lösenordsskyddade PDFs → tydligt felmeddelande
  • Skannade bild-PDFs → informativt felmeddelande om OCR

Webb-parsers (quick-import/parsers/)

Abstrakt bas RecipeParser med canHandle(url) + parse(html). Implementationer:

  • ica.parser.ts — ICA.se, prioriterar JSON-LD structured data
  • generic.parser.ts — Fallback för alla webbplatser, försöker JSON-LD sedan HTML

Deployment

cd microservice-importer
docker compose up -d

Services:

  • importer-api — NestJS backend (port 3001)
  • importer-frontend — Next.js frontend (port 3000)

Stoppa:

docker compose down

Loggar:

docker compose logs -f importer-api
docker compose logs -f importer-frontend

Manuell Docker build

# Backend
docker build -f backend/Dockerfile -t importer-api:local .
docker run -p 3001:3001 importer-api:local

# Frontend (ny terminal)
docker build -f frontend/Dockerfile -t importer-frontend:local .
docker run -p 3000:3000 importer-frontend:local

Environment variables

Konfigureras i docker compose eller .env:

Backend:

PORT=3001
NODE_ENV=production

Frontend:

NEXT_PUBLIC_API_URL_INTERNAL=http://importer-api:3001

Integration med andra tjänster

Microservicen kan anropas som extern API från andra applikationer:

const IMPORTER_URL = process.env.MICROSERVICE_IMPORTER_URL || 'http://localhost:3001';

// PDF-konvertering
const formData = new FormData();
formData.append('file', pdfFile);

const response = await fetch(`${IMPORTER_URL}/api/document-import`, {
  method: 'POST',
  body: formData,
});

const { markdown, title, metadata } = await response.json();

Tekniska detaljer

Backend Stack

  • NestJS 10.3 — REST API & modular architecture
  • TypeScript 5.4.5 — Type safety
  • Node.js 22.x — Runtime
  • pdf-parse 1.1.x — PDF text extraction
  • tesseract.js 5.x — OCR (förberett, ej aktivt ännu)
  • multer — Multipart file upload handling
  • class-validator — DTO validation (svenska felmeddelanden)
  • Ingen databas — Stateless service

Frontend Stack

  • Next.js 16.2 — React framework (App Router)
  • React 19.2 — UI components
  • TypeScript 5.4.5
  • Inline CSS — Minimal styling, inga framework-beroenden

Error Handling

  • Centraliserad GlobalExceptionFilter (svenska meddelanden)
  • Konsistent JSON-responsformat: { statusCode, message, timestamp, path }
  • HTTP status codes: 200, 400, 503

Framtida utbyggnader

  • PDF-import — textbaserad extraction
  • OCR för skannade bild-PDFs (Tesseract.js förberett)
  • Word (.docx) import
  • Batch-processing (flera filer samtidigt)
  • Strukturerad data-extraction (tabeller, listor)
  • Stöd för fler webbplatser i webb-skraparen (mat.se, kokaihop.se, etc.)
  • Caching av konverterade dokument
  • Rate limiting

Licens

MIT


Support

  • Git Repo — Gitea på 192.168.50.2:2222/nilsjohan/microservice-importer