@space-operator/mistral-ocr-pipeline (0.4.0)

Published 2026-09-23 20:08:26 +00:00 by amir

Installation

@space-operator:registry=
npm install @space-operator/mistral-ocr-pipeline@0.4.0
"@space-operator/mistral-ocr-pipeline": "0.4.0"

About this package

@space-operator/mistral-ocr-pipeline

A server-side OCR pipeline plugin built on the official Mistral TypeScript SDK. It defaults to the pinned mistral-ocr-4-1 model and exposes OCR, text correction, vision correction, and vision verification through one client contract. Version 0.4 adds remote document and image inputs, existing-file processing, JSON-schema annotations, usage reporting, and normalized rich page metadata without changing the 0.3 PDF APIs.

Requirements

  • Node.js 20 or newer
  • A Mistral API key

Install

After publishing the package:

npm install @space-operator/mistral-ocr-pipeline

To consume it from this repository without publishing, create a tarball and install that tarball in the other project:

npm run plugin:pack
npm install /path/to/space-operator-mistral-ocr-pipeline-0.4.0.tgz

Use as a pipeline plugin

import { mistralOcrPipelinePlugin } from "@space-operator/mistral-ocr-pipeline";

const plugins = new Map([
  [mistralOcrPipelinePlugin.id, mistralOcrPipelinePlugin],
]);

const client = mistralOcrPipelinePlugin.createClient({
  apiKey: process.env.MISTRAL_API_KEY!,
  visionFixModel: "mistral-medium-3-5",
  correctionMaxTokens: 4_096,
  timeoutMs: 90_000,
  retryConfig: {
    strategy: "backoff",
    retryConnectionErrors: true,
    backoff: {
      initialInterval: 1_000,
      maxInterval: 10_000,
      exponent: 2,
      maxElapsedTime: 240_000,
    },
  },
  ocr: {
    includeBlocks: true,
    tableFormat: "markdown",
    confidenceScoresGranularity: "word",
  },
});

const pages = await client.processPdf({
  source: { kind: "path", path: "./document.pdf" },
  pages: [0, 1, 2],
  chunkSize: 10,
  onProgress: ({ phase, processedPages, totalPages }) => {
    console.log(phase, `${processedPages}/${totalPages}`);
  },
});

processPdf uploads once, processes pages in bounded chunks, and deletes the temporary Mistral upload whether processing succeeds, fails, or is cancelled. Chunk responses are checked for missing, duplicate, invalid, and unexpected page indexes, then returned in the same order as the requested pages.

To keep a successful upload for another operation and receive its ID, use the detailed API:

const { pages, uploadedFileId } = await client.processPdfDetailed({
  source: { kind: "path", path: "./document.pdf" },
  pages: [0, 1, 2],
  retainUploadedFile: true,
});

// Later, when no other operation needs it:
await client.deleteFile(uploadedFileId!);

Failed and cancelled operations are cleaned up even when retainUploadedFile is enabled.

Remote documents, images, and existing files

processDocument and processDocumentDetailed accept sources that do not need a temporary upload:

const remotePages = await client.processDocument({
  source: {
    kind: "document-url",
    url: "https://example.com/report.pdf",
    fileName: "report.pdf",
  },
  pages: [0, 1],
});

const imagePages = await client.processDocument({
  source: { kind: "image-url", url: "https://example.com/scan.png" },
  pages: [0],
});

const existingPages = await client.processDocument({
  source: { kind: "file-id", fileId: "mistral-file-id" },
  pages: [0, 1],
});

Existing file IDs remain caller-owned by default. Set deleteAfterProcessing: true on a file-id source to have the pipeline delete it after success, failure, or cancellation. Document and image URLs are sent directly to Mistral and never enter the upload lifecycle.

The package does not read environment variables itself. Consumers pass all credentials and model overrides through createClient, which keeps the plugin portable across Next.js apps, CLIs, background jobs, and other Node.js pipelines. The package also exports the generic OcrPipelinePlugin interface for typed registries.

In-memory documents

const pages = await client.processPdf({
  source: {
    kind: "bytes",
    content: pdfBytes,
    fileName: "document.pdf",
  },
  pages: [0, 1],
});

OCR options

Client-level defaults and per-call overrides support:

  • includeBlocks and includeImageBase64
  • tableFormat: "markdown" | "html"
  • confidenceScoresGranularity: "word" | "page" | "block"
  • extractHeader and extractFooter
  • imageLimit and imageMinSize
  • bboxAnnotationFormat for structured image/bounding-box annotations
  • documentAnnotationFormat and documentAnnotationPrompt for structured document extraction

Every normalized page can include aggregate page confidence. Blocks can include OCR 4.1 content and type confidence when block granularity is requested. Word granularity continues to populate lowConfidenceWords using the configured threshold.

Normalized pages can also expose extracted images, tables, hyperlinks, header, footer, and dimensions. Image and document annotations retain the provider's raw string and include parsed when it is valid JSON.

Structured output and detailed metadata

Structured output uses a provider-neutral JSON-schema shape:

const result = await client.processDocumentDetailed({
  source: {
    kind: "document-url",
    url: "https://example.com/invoice.pdf",
  },
  pages: [0, 1],
  ocr: {
    documentAnnotationFormat: {
      type: "json_schema",
      jsonSchema: {
        name: "invoice",
        strict: true,
        schema: {
          type: "object",
          properties: {
            invoiceNumber: { type: "string" },
            total: { type: "number" },
          },
          required: ["invoiceNumber", "total"],
        },
      },
    },
    documentAnnotationPrompt: "Extract the invoice fields.",
  },
});

console.log(result.model, result.usage.pagesProcessed);
console.log(result.chunks[0]?.documentAnnotation?.parsed);

Detailed results include the response model, aggregate usage, and one metadata entry per chunk. Document annotations stay attached to their chunk because a chunked run makes multiple OCR requests. documentSizeBytes is retained once using the largest value reported across those requests rather than being double-counted.

Cancellation and progress

processPdf and processPdfDetailed accept an AbortSignal. The same signal is passed into file reads, uploads, and OCR requests; any upload created before cancellation is still deleted.

const controller = new AbortController();

const pending = client.processPdf({
  source: { kind: "path", path: "./document.pdf" },
  pages: [0, 1, 2],
  signal: controller.signal,
  onProgress: (event) => {
    if (event.processedPages === 2) controller.abort();
  },
});

Progress phases are uploading, processing, cleaning-up, and completed. Callbacks may be synchronous or asynchronous. Direct URL and caller-owned file sources start at processing; lifecycle phases are emitted only when an upload or managed existing file requires them.

Regional endpoints (global, eu, or us), custom server URLs, request timeouts, SDK retry policies, model names, bounded correction output, and a custom fetch implementation are configurable on the client.

Direct client use

import { MistralOcrClient } from "@space-operator/mistral-ocr-pipeline";

const client = new MistralOcrClient({
  apiKey: process.env.MISTRAL_API_KEY!,
});

MistralOcrClient implements the exported OcrPipelineClient interface. It also provides uploadPdfBytes(content, fileName) for pipelines that already hold documents in memory, plus deleteFile(fileId) for explicit low-level lifecycle control. Low-level consumers can call processDocumentPages or processDocumentPagesDetailed with a document URL, image URL, or file ID.

Build and package

From the repository root:

npm run plugin:build
npm run plugin:pack

Dependencies

Dependencies

ID Version
@mistralai/mistralai ^2.6.4

Development dependencies

ID Version
@types/node ^20
typescript ^5

Keywords

mistral ocr pipeline plugin document-ai
Details
npm
2026-09-23 20:08:26 +00:00
0
latest
23 KiB
Assets (1)
Versions (1) View all
0.4.0 2026-09-23