Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ragaeeb/kokokor/llms.txt

Use this file to discover all available pages before exploring further.

Your First Paragraph Reconstruction

This guide will walk you through using Kokokor to reconstruct paragraphs from OCR output.
1

Install Kokokor

If you haven’t already, install Kokokor using your preferred package manager:
npm install kokokor
See the installation guide for other package managers.
2

Prepare Your OCR Data

Kokokor expects OCR observations with bounding box coordinates and text content. Here’s a typical structure:
const ocrResult = {
  dpi: { x: 300, y: 300 },
  page: { width: 2480, height: 3508 },
  observations: [
    { 
      text: 'This is the first', 
      bbox: { x: 100, y: 100, width: 200, height: 20 } 
    },
    { 
      text: 'line of text.', 
      bbox: { x: 310, y: 100, width: 150, height: 20 } 
    },
    { 
      text: 'This is a new paragraph.', 
      bbox: { x: 100, y: 150, width: 300, height: 20 } 
    },
  ],
};
The bbox object contains x, y (top-left corner), width, and height in pixels.
3

Import and Use reconstructParagraphs

Import the main function and process your OCR data:
import { reconstructParagraphs } from 'kokokor';

const result = reconstructParagraphs({
  observations: ocrResult.observations,
  page: {
    dpiX: ocrResult.dpi.x,
    dpiY: ocrResult.dpi.y,
    height: ocrResult.page.height,
    width: ocrResult.page.width,
  },
});

console.log(result.text);
4

View the Results

The reconstructParagraphs function returns an object with:
  • text: The reconstructed text with proper paragraph breaks
  • textBlocks: Array of text blocks with metadata (centering, poetry, headings, etc.)
Expected output:
This is the first line of text.
This is a new paragraph.
Each text block also includes metadata:
result.textBlocks.forEach(block => {
  console.log(block.text);
  console.log('Centered:', block.isCentered);
  console.log('Poetry:', block.isPoetic);
  console.log('Heading:', block.isHeading);
  console.log('Footnote:', block.isFootnote);
});

Complete Example

Here’s a complete working example you can copy and run:
index.ts
import { reconstructParagraphs } from 'kokokor';

// Example OCR result from a document scanner
const ocrResult = {
  dpi: { x: 300, y: 300 },
  page: { width: 2480, height: 3508 },
  observations: [
    { text: 'This is the first', bbox: { x: 100, y: 100, width: 200, height: 20 } },
    { text: 'line of text.', bbox: { x: 310, y: 100, width: 150, height: 20 } },
    { text: 'This is a new paragraph.', bbox: { x: 100, y: 150, width: 300, height: 20 } },
  ],
};

// Reconstruct paragraphs
const result = reconstructParagraphs({
  observations: ocrResult.observations,
  page: {
    dpiX: ocrResult.dpi.x,
    dpiY: ocrResult.dpi.y,
    height: ocrResult.page.height,
    width: ocrResult.page.width,
  },
});

console.log(result.text);
// Output:
// This is the first line of text.
// This is a new paragraph.

Understanding the Output

Text Property

The text property contains the fully reconstructed text with:
  • Lines merged within paragraphs
  • Double newlines between paragraphs
  • Poetry lines preserved individually
  • Footnotes separated from body text

Text Blocks Property

The textBlocks array provides structured access to each paragraph with metadata:
type TextBlock = {
  text: string;
  bbox: BoundingBox;
  isCentered?: boolean;  // Text is centered on the page
  isPoetic?: boolean;    // Detected as poetry (not merged into paragraphs)
  isHeading?: boolean;   // Detected as a heading
  isFootnote?: boolean;  // Detected as a footnote
};

Next Steps

Advanced Configuration

Customize paragraph detection parameters for your specific use case

API Reference

Explore the complete API documentation

Poetry Detection

Learn how Kokokor identifies and preserves poetic content

RTL Text Support

Working with Arabic, Hebrew, and other right-to-left languages

Common Use Cases

Working with Surya OCR

If you’re using the Surya OCR library, convert the output format:
import { reconstructParagraphs, mapMatrixToBoundingBox } from 'kokokor';

// Surya returns bounding boxes as [x1, y1, x2, y2]
const suryaResult = {
  text_lines: [
    { bbox: [100, 100, 400, 120], text: 'Text from Surya OCR' },
  ],
};

// Convert to Kokokor format
const observations = suryaResult.text_lines.map(line => ({
  text: line.text,
  bbox: mapMatrixToBoundingBox(line.bbox as [number, number, number, number]),
}));

const result = reconstructParagraphs({
  observations,
  page: { dpiX: 300, dpiY: 300, width: 2480, height: 3508 }
});

Processing RTL Text

For right-to-left languages like Arabic:
import { flipAndAlignObservations, reconstructParagraphs } from 'kokokor';

// Flip coordinates for RTL text
const flipped = flipAndAlignObservations(
  observations,
  imageWidth,
  dpiX
);

const result = reconstructParagraphs({
  observations: flipped,
  page: { dpiX, dpiY, width: imageWidth, height: imageHeight }
});

Custom Paragraph Detection

Adjust the paragraph detection sensitivity:
const result = reconstructParagraphs(
  {
    observations,
    page: pageContext
  },
  {
    verticalJumpFactor: 2,    // Higher = more sensitive to vertical gaps
    widthTolerance: 0.85      // Lower = more sensitive to short lines
  }
);
The default parameters work well for most documents. Only customize if you’re seeing incorrect paragraph breaks.

Build docs developers (and LLMs) love