> ## Documentation Index
> Fetch the complete documentation index at: https://docs.talosjs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# PDF Extraction

> Extract PDF content to Markdown with automatic OCR fallback for scanned pages

The `RAG` class turns a PDF into Markdown ready to chunk and embed into a [vector table](/ai/rag/vector-table). It wraps [`@talosjs/pdf`](/utilities/pdf) for classification and text extraction, then automatically OCRs any page the extractor flags as needing it, using a vision model over OpenRouter.

## Extracting a PDF

Create a `RAG` instance with the path to a source file, then call `extract()`.

```typescript theme={null}
import { RAG } from "@talosjs/rag";

const rag = new RAG("./docs/handbook.pdf", { apiKey: process.env.OPENROUTER_API_KEY });
const result = await rag.extract();

console.log(result.pdfType);  // "TextBased" | "Scanned" | "ImageBased" | "Mixed"
console.log(result.markdown); // extracted text merged with any OCR'd pages
console.log(result.ocrPages); // pages that went through OCR
```

`RAG` accepts the same `PDFExtractOptionsType` as [`PDF.extract()`](/utilities/pdf), so you can restrict extraction to specific 0-indexed pages:

```typescript theme={null}
const result = await rag.extract({ pages: [0, 1, 2] });
```

### Feeding the result into a table

The merged `markdown` is your chunking input; split it however fits your content, then add records with your own `id` and `metadata`.

```typescript theme={null}
const table = await db.open("handbook");

await table.add([
  {
    id: "handbook-1",
    text: result.markdown ?? "",
    metadata: { source: "handbook.pdf" },
  },
]);
```

## How OCR fallback works

1. `extract()` runs `PDF.extract()` first. If no pages need OCR, the result is returned as-is with an empty `ocrPages` array.
2. Otherwise, each page in `pagesNeedingOcr` is rendered to a PNG image and sent to a vision model on OpenRouter (`qwen/qwen3-vl-235b-a22b-instruct`) with a transcription prompt.
3. Every OCR'd page's Markdown is appended to the extracted `markdown`, each preceded by an HTML comment marking its page number (`<!-- page N -->`), and returned in ascending page order via `ocrPages`.

```typescript theme={null}
type RAGOcrPageType = {
  page: number;     // 1-indexed page that was OCR'd
  markdown: string; // Markdown transcribed from the page image
};

type RAGExtractResultType = PDFExtractResultType & {
  ocrPages: RAGOcrPageType[];
};
```

<Note>
  OCR only runs for the pages `@talosjs/pdf` flags in `pagesNeedingOcr` — scanned or image-based pages, or pages with extraction issues. Fully text-based PDFs never touch OpenRouter.
</Note>

## Options

```typescript theme={null}
type RAGOptionsType = {
  apiKey?: string; // OpenRouter API key; defaults to OPENROUTER_API_KEY
};
```

The API key is only required when a page actually needs OCR. Set it in the environment so you don't have to pass it explicitly:

```bash theme={null}
OPENROUTER_API_KEY=sk-or-...
```

## Exceptions

`RAGException` is thrown when OCR fails. It carries a machine-readable `key` and the `source` path in its `data`.

| Key                  | When                                                                           |
| -------------------- | ------------------------------------------------------------------------------ |
| `MISSING_API_KEY`    | A page needs OCR but no API key was provided or found in `OPENROUTER_API_KEY`. |
| `OCR_EMPTY_RESPONSE` | The vision model returned no content for a page.                               |
| `OCR_FAILED`         | Rendering a page to an image or calling the vision model failed.               |

```typescript theme={null}
import { RAG, RAGException } from "@talosjs/rag";

try {
  const rag = new RAG("./docs/handbook.pdf");
  await rag.extract();
} catch (error) {
  if (error instanceof RAGException) {
    console.error(`[${error.key}] ${error.message}`, error.data);
  }
}
```

Errors from the underlying `PDF.extract()` call (a `PDFException`, for example a missing file) propagate unchanged — see [PDF exceptions](/utilities/pdf#exceptions).
