Help pages

Reference index

Session — Create and manage extraction sessions.
mx_session(), mx_profile(), show_steps(), remove_step()

Detection — Scan a PDF for table locations.
detect_tables(), detect_tables_quietly(), locate_area()

Table extraction — Pull tables out of PDF pages.
select_table(), select_table_docling(), select_table_llm(), stack_pages(), stack_tables(), merge_tables(), pdf_table()

Metadata extraction — Extract individual fields and structured records.
select_item(), select_items_batch(), select_struct(), struct_to_df(), show_items(), update_item(), update_llm_schema(), suggest_schema()

LLM configuration — Configure the LLM provider at session or global level.
mx_configure_llm()

Cleaning — Rename, cast, filter, and reshape extracted tables.
rename_columns(), cast_types(), filter_rows(), add_column(), split_column(), split_column_df(), fill_down(), clean_numbers(), clean_numbers_df()

Inspection — Preview and visualise extracted data.
preview(), preview_all(), view_in_pdf()

Macros — Save, load, and replay extraction workflows.
save_macro(), load_macro(), mx_replay(), mx_replay_batch(), validate_macro()

Comparison — Diff macro outputs across two PDFs.
diff_replay(), detail()

Validation — Validate table structure and values.
validate_table(), show_validations()

Export — Write extracted data to files.
export_csv(), export_excel(), export_json()

Testing — Snapshot-test macro outputs in CI.
test_macro(), test_extraction(), expect_table_snapshot()

Shiny — Embed macrox in a Shiny application.
mx_app(), macrox_ui(), macrox_server()

Python backends — Set up optional ML and NLP engines.
setup_docling(), close_docling(), setup_gliner(), close_gliner()

Full manual

-- A -- add_column()

-- C -- cast_types() clean_numbers() clean_numbers_df() close_docling() close_gliner()

-- D -- detail() detect_tables() detect_tables_quietly() diff_replay()

-- E -- expect_table_snapshot() export_csv() export_excel() export_json()

-- F -- fill_down() filter_rows()

-- L -- load_macro() locate_area()

-- M -- macrox_server() macrox_ui() merge_tables() mx_app() mx_configure_llm() mx_profile() mx_replay() mx_replay_batch() mx_session()

-- P -- pdf_table() preview() preview_all()

-- R -- remove_step() rename_columns()

-- S -- save_macro() select_item() select_items_batch() select_struct() select_table() select_table_docling() select_table_llm() setup_docling() setup_gliner() show_items() show_steps() show_validations() split_column() split_column_df() stack_pages() stack_tables() struct_to_df() suggest_schema()

-- T -- test_extraction() test_macro()

-- U -- update_item() update_llm_schema()

-- V -- validate_macro() validate_table() view_in_pdf()

1 Add a derived column to an extracted table

Description

Add a derived column to an extracted table

Usage

add_column(sess, table, name, expr)

Arguments

sess

A macrox_session object.

table

Character label of the target table.

name

Name of the new column.

expr

R expression (as a string) evaluated against the data frame, e.g. "male_count + female_count" or "2024L".

Value

sess invisibly (step is recorded).

2 Cast column types in an extracted table

Description

Cast column types in an extracted table

Usage

cast_types(sess, table, types)

Arguments

sess

A macrox_session object.

table

Character label of the target table.

types

Named character vector: c(col = "integer"). Supported types: "numeric", "integer", "character", "date:<fmt>" e.g. "date:%d/%m/%Y".

Value

sess invisibly (step is recorded).

3 Clean and parse numeric strings in table columns

Description

Strips thousands separators, currency symbols, and parenthetical negatives; maps sentinel strings to NA; optionally coerces columns to numeric.

Usage

clean_numbers(
  sess,
  table,
  cols = NULL,
  currency = c("£", "$", "€", "¥"),
  na_strings = c("-", "—", "n/a", "na", ""),
  negative_parens = TRUE,
  convert = TRUE
)

Arguments

sess

A macrox_session object.

table

Character label of the target table.

cols

Character vector of column names to process. NULL (default) targets all non-numeric columns.

currency

Character vector of currency symbols to strip.

na_strings

Strings that should become NA (case-insensitive after whitespace trimming).

negative_parens

If TRUE (default), converts (123) to -123.

convert

If TRUE (default), coerces a column to numeric when all non-NA values parse successfully.

Value

sess invisibly (step is recorded).

4 Clean and parse numeric strings in a data frame

Description

The data-frame counterpart of clean_numbers(): it takes a data frame and returns a data frame, with no session and no recorded step. Use it when the table is already in hand, for example inside a script or a pipeline.

Usage

clean_numbers_df(
  df,
  cols = NULL,
  currency = c("£", "$", "€", "¥"),
  na_strings = c("-", "—", "n/a", "na", ""),
  negative_parens = TRUE,
  convert = TRUE
)

Arguments

df

A data frame.

cols

Character vector of column names to process. NULL (default) targets all non-numeric columns.

currency

Character vector of currency symbols to strip.

na_strings

Strings that should become NA (case-insensitive after whitespace trimming).

negative_parens

If TRUE (default), converts (123) to -123.

convert

If TRUE (default), coerces a column to numeric when all non-NA values parse successfully.

Value

df with the selected columns cleaned.

5 Release the Docling document cache

Description

Frees the in-memory cache of converted PDF documents. Call this when you are done extracting tables to reduce memory usage.

Usage

close_docling()

Value

Invisible NULL.

6 Unload the GLiNER2 model from memory

Description

Unload the GLiNER2 model from memory

Usage

close_gliner()

Value

NULL invisibly.

7 Inspect cell-level changes for one table in a diff

Description

Returns a data frame of every cell that changed between the two replays, with columns row, col, ref, new, and delta (numeric difference, or NA for non-numeric columns).

Usage

detail(x, ...)

Arguments

x

A macrox_diff object returned by diff_replay().

...

Passed to methods. For macrox_diff objects, table names the table to inspect.

Value

A data frame with one row per changed cell.

8 Scan a PDF for tables

Description

Scans the specified pages of the PDF for tables and prints a summary. This function is NOT recorded in the macro — it is for exploration only.

Usage

detect_tables(
  sess,
  pages = NULL,
  method = c("lattice", "stream", "docling"),
  min_rows = 1L,
  max_header_chars = 40L
)

Arguments

sess

A macrox_session object.

pages

Integer vector of pages to scan. Defaults to all pages.

method

Extraction method: "lattice" (default), "stream", or "docling". Docling converts all requested pages in one pass and is best for scanned PDFs or complex layouts.

min_rows

Minimum number of data rows a table must have to be shown and stored. Default 1. Set to 0 to see everything.

max_header_chars

Maximum character length allowed for the first column name before the table is flagged as a likely chart/figure and skipped. Default 40. Set to Inf to disable. (Lattice/stream only — Docling's layout model distinguishes charts from tables natively.)

Details

Results are stored in sess$detect as a list of list(page, index, df) entries that can be passed directly to select_table() via table_index. When method = "docling", pages are converted in a single pass and the results are cached so that subsequent select_table_docling() calls on those pages run instantly.

Value

sess invisibly (not recorded).

9 Detect tables without console output

Description

Like detect_tables() but returns a named list silently. Intended for agent/programmatic use.

Usage

detect_tables_quietly(
  path,
  pages = NULL,
  method = c("lattice", "stream", "docling"),
  min_rows = 1L,
  max_header_chars = 40L
)

Arguments

path

Path to a PDF file.

pages

Integer vector of pages to scan. Defaults to all pages.

method

Extraction method: "lattice" (default), "stream", or "docling".

min_rows

Minimum data rows required (default 1).

max_header_chars

Maximum first-column name length before skipping (default 40). Ignored when method = "docling".

Value

Named list: page number (character) → list of data frames.

10 Compare macro outputs across two PDF files

Description

Replays the same macro against two files and returns a structured diff showing added, removed, and changed tables. For changed tables the diff includes per-column numeric delta statistics. Use detail() on the result to inspect which cells changed.

Usage

diff_replay(
  file1,
  file2,
  macro,
  macro_path = ".",
  params = list(),
  params2 = NULL
)

Arguments

file1

Path to the reference PDF.

file2

Path to the new PDF.

macro

Macro name, path to a .yml, or a step list.

macro_path

Directory for macro lookup (default .).

params

Named list of parameter values applied to both replays (e.g. list(year = 2024L)). Use params2 to supply different values for the second file.

params2

Named list of parameter values for file2 only. Defaults to params when NULL.

Value

A macrox_diff object. Print gives a summary; detail() drills into a single table.

11 Snapshot-test an extracted table

Description

Wraps testthat::expect_snapshot() to lock in the printed representation of a table stored in a session. On first run the snapshot is written to tests/testthat/_snaps/; subsequent runs compare against that baseline.

Usage

expect_table_snapshot(sess, label = NULL, variant = NULL)

Arguments

sess

A macrox_session object, or a plain data frame.

label

Character label of the table to snapshot. Ignored when sess is already a data frame.

variant

Optional variant string passed to testthat::expect_snapshot(), allowing multiple snapshots per test.

Details

Must be called inside a testthat test (i.e., within test_that()).

Value

The result of expect_snapshot(), invisibly.

12 Export all extracted tables to CSV files

Description

Writes one .csv per table into dir. Existing files are overwritten.

Usage

export_csv(sess, dir = ".", tables = NULL)

Arguments

sess

A macrox_session object.

dir

Directory to write into (created if it doesn't exist).

tables

Character vector of table labels to export. Default: all tables.

Value

Named character vector of output file paths, invisibly.

13 Export all extracted tables to an Excel workbook

Description

Writes one worksheet per table. Requires the writexl or openxlsx package.

Usage

export_excel(sess, path = "macrox_tables.xlsx", tables = NULL)

Arguments

sess

A macrox_session object.

path

Output .xlsx file path (default "macrox_tables.xlsx").

tables

Character vector of table labels to include. Default: all.

Value

path invisibly.

14 Export session data as a structured JSON payload

Description

Combines extracted items (document metadata) and tables into a single self-describing JSON document. Suitable for API ingestion, database loading, and RAG pipelines.

Usage

export_json(sess, path = NULL, pretty = TRUE, include_steps = FALSE)

Arguments

sess

A macrox_session object.

path

File path to write the JSON. NULL (default) returns the JSON string invisibly without writing.

pretty

Logical; pretty-print the JSON (default TRUE).

include_steps

Include the recorded step list in the output (default FALSE).

Value

The JSON string, invisibly.

15 Forward-fill blank or NA cells in specified columns

Description

Fills each blank or NA cell downward from the last non-blank value. Useful when merged header cells in government PDFs leave empty values in rows below the merged cell boundary.

Usage

fill_down(sess, table, cols = NULL)

Arguments

sess

A macrox_session object.

table

Character label of the target table.

cols

Character vector of column names to fill. NULL (default) fills all columns.

Value

sess invisibly (step is recorded).

16 Remove rows matching an expression

Description

Remove rows matching an expression

Usage

filter_rows(sess, table, exclude_where)

Arguments

sess

A macrox_session object.

table

Character label of the target table.

exclude_where

Character string expression evaluated against the data frame columns. Rows where the expression is TRUE are removed.

Value

sess invisibly (step is recorded).

17 Load a YAML macro

Description

Load a YAML macro

Usage

load_macro(name, path = ".")

Arguments

name

Macro name (stem) or full path to a .yml file.

path

Directory to look in when name has no extension (default .).

Value

The list of step definitions. If the macro declares parameters, a params attribute is attached — inspect with attr(steps, "params").

18 Interactively select a table area

Description

Opens a click-and-drag gadget (via tabulapdf::locate_areas) to capture bounding box coordinates. Returns a named c(top, left, bottom, right) vector suitable for passing directly to select_table().

Usage

locate_area(sess, page = 1)

Arguments

sess

A macrox_session object.

page

Page number to display (default 1).

Value

Named numeric vector c(top, left, bottom, right), invisibly.

19 Shiny module server for PDF table extraction

Description

Shiny module server for PDF table extraction

Usage

macrox_server(id)

Arguments

id

Module namespace ID (must match macrox_ui()).

Value

A list with two reactives: tables (named list of data frames) and steps (list of step definitions).

20 Shiny module UI for PDF table extraction

Description

Provides a split-pane interface: PDF viewer on the left, live extracted table on the right. Transforms (rename, type-cast, filter) open in modal dialogs so both panes remain visible.

Usage

macrox_ui(id, title = "PDF · Table Extractor", height = "600px")

Arguments

id

Module namespace ID.

title

Card title shown in the header (default "PDF · Table Extractor").

height

Height of the PDF image pane (default "600px").

Value

A bslib card UI element.

21 Join two extracted tables

Description

Wraps base::merge() and records the step so it replays automatically.

Usage

merge_tables(
  sess,
  label,
  left,
  right,
  by,
  all = FALSE,
  all.x = FALSE,
  all.y = FALSE
)

Arguments

sess

A macrox_session object.

label

Label for the merged output table.

left

Label of the left table.

right

Label of the right table.

by

Character vector of column names to join on.

all

Logical; FALSE (default) = inner join, TRUE = full outer.

all.x

Left join when TRUE.

all.y

Right join when TRUE.

Value

sess invisibly (step is recorded).

22 Launch the macrox standalone app

Description

Opens a full Shiny application for interactive PDF table extraction, cleaning, and export. The app is self-contained — no existing session or macro is required.

Usage

mx_app(viewer = c("browser", "dialog", "pane"))

Arguments

viewer

Where to display the app:

  • "browser" (default) — system web browser

  • "dialog" — floating RStudio dialog (1 200 × 900)

  • "pane" — RStudio Viewer pane

Value

Called for its side-effect. Returns invisibly when the app is closed.

23 Configure a session-level default LLM

Description

Sets a single LLM configuration for the session so that select_table_llm() and select_item() can be called without specifying provider, model, or chat on every call. The configured chat object is cloned for each extraction so its conversation history is never shared between calls.

Usage

mx_configure_llm(
  sess,
  chat = NULL,
  provider = getOption("macrox.llm.provider", "anthropic"),
  model = getOption("macrox.llm.model", NULL),
  base_url = NULL,
  system = NULL
)

Arguments

sess

A macrox_session object.

chat

An existing ellmer Chat object, e.g. ellmer::chat_anthropic(). When supplied, provider, model, base_url, and system are ignored.

provider

Provider name (default "anthropic"). Any provider for which ellmer exports chat_<provider>() is supported. Ignored when chat is supplied.

model

Model name. NULL uses a sensible default for the provider. Ignored when chat is supplied.

base_url

Base URL for "openai_compatible" providers.

system

System prompt passed to the provider constructor. NULL (default) uses a built-in extraction-focused prompt for the "anthropic" provider; other providers receive no default. Ignored when chat is supplied.

Value

sess invisibly.

Examples

sess <- mx_session("report.pdf")

# Use Anthropic with ellmer's default model (Claude Sonnet 5 in ellmer 0.5.0)
sess |> mx_configure_llm(provider = "anthropic")
sess |> select_table_llm("my_table", page = 5)
sess |> select_item("date", prompt = "Publication date")

# Or pin to a specific model for reproducibility
sess |> mx_configure_llm(provider = "anthropic", model = "claude-opus-4-8")

# Or pass a fully configured chat object for maximum control
chat <- ellmer::chat_anthropic(
  model  = "claude-sonnet-5",
  system = "Extract data exactly as shown."
)
sess |> mx_configure_llm(chat = chat)

24 Profile a PDF for agent consumption

Description

Returns a structured machine-readable description of the PDF's tables and surrounding text context. Pass the result to an LLM to generate a macro.

Usage

mx_profile(path, pages = NULL, method = "lattice", context_lines = 3)

Arguments

path

Path to a PDF file.

pages

Integer vector of pages to scan. Defaults to all pages (capped at 60).

method

Extraction method: "lattice" (default) or "stream".

context_lines

Number of text lines above/below each table's header row to include as context (default 3).

Value

A macrox_profile list.

25 Replay a macro against a new PDF file

Description

Replay a macro against a new PDF file

Usage

mx_replay(file, macro, macro_path = ".", params = list())

Arguments

file

Path to the PDF file.

macro

Either a macro name / path (character) or a step list returned by load_macro().

macro_path

Directory to look for the macro file (default .).

params

Named list of parameter values for parameterised macros, e.g. list(year = 2025L, region = "Cork"). Each $name placeholder in step fields is replaced with the corresponding value.

Value

Named list of extracted data frames.

26 Replay a macro across multiple PDF files

Description

Replay a macro across multiple PDF files

Usage

mx_replay_batch(
  files,
  macro,
  macro_path = ".",
  params = list(),
  .progress = TRUE,
  .parallel = FALSE
)

Arguments

files

Character vector of PDF file paths.

macro

Macro name, path, or step list (see mx_replay()).

macro_path

Directory for macro lookup (default .).

params

Named list of parameter values passed to each mx_replay() call. Useful when all files share the same parameters. To vary parameters per file, call mx_replay() directly in a loop.

.progress

Show file-level progress messages (default TRUE).

.parallel

If TRUE, run files in parallel using purrr + mirai. Requires purrr >= 1.1.0 and mirai. Set up workers first with mirai::daemons(n). Defaults to FALSE (sequential).

Value

Named list (file basenames) of table lists. Files that fail are NULL.

27 Open a macrox session

Description

Creates a session object that holds the PDF path, extracted tables, and a running log of every recorded step.

Usage

mx_session(path = NULL)

Arguments

path

Path to a PDF file, or an image file (PNG, JPG, TIFF, BMP, GIF, WEBP). Image files are automatically converted to PDF; only select_table_llm() and select_table_docling() work on the resulting session.

Value

An invisible macrox_session environment.

28 Extract a table from a PDF page as a data frame

Description

Reads one table from one page of a PDF with the word-position (bbox) engine and returns it as a data frame. It needs no session and records no step, which makes it convenient in scripts and pipelines.

Usage

pdf_table(
  path,
  page,
  area = NULL,
  header_rows = 1L,
  row_tol = NULL,
  col_gap = NULL
)

Arguments

path

Path to a PDF file.

page

Page number.

area

Optional named numeric vector c(top, left, bottom, right) in PDF points. NULL (the default) scans the whole page.

header_rows

Number of header rows. Several rows are joined into a single column name.

row_tol, col_gap

Optional tuning for row clustering and column gap detection. NULL (the default) detects them automatically.

Value

A data frame.

Examples

pdf_table("report.pdf", page = 9, header_rows = 4)

29 Preview one extracted table

Description

Preview one extracted table

Usage

preview(sess, table, n = 6)

Arguments

sess

A macrox_session object.

table

Character label of the table to preview.

n

Number of rows to show (default 6).

Value

sess invisibly. # not recorded

30 Preview all extracted tables with numeric totals

Description

Preview all extracted tables with numeric totals

Usage

preview_all(sess, n = 6)

Arguments

sess

A macrox_session object.

n

Number of rows to show per table (default 6).

Value

sess invisibly. # not recorded

31 Remove a recorded step by index

Description

Remove a recorded step by index

Usage

remove_step(sess, index)

Arguments

sess

A macrox_session object.

index

Integer index of the step to remove (see show_steps()).

Value

sess invisibly.

32 Rename columns in an extracted table

Description

Rename columns in an extracted table

Usage

rename_columns(sess, table, mapping)

Arguments

sess

A macrox_session object.

table

Character label of the target table.

mapping

Named character vector: c(OldName = "new_name", ...).

Value

sess invisibly (step is recorded).

33 Save the session's recorded steps as a YAML macro

Description

Save the session's recorded steps as a YAML macro

Usage

save_macro(sess, name, path = ".", overwrite = FALSE, params = NULL)

Arguments

sess

A macrox_session object.

name

Macro name (used as the filename stem).

path

Directory to write the .yml file (default .).

overwrite

Logical; overwrite an existing file? (default FALSE)

params

Optional parameter declarations for parameterised macros. Accepts a named character vector c(year = "integer", month = "character") or a bare character vector of names c("year", "month"). Declared parameters can be referenced as $name in any step field (e.g. expr = "$year") and supplied at replay time via mx_replay(..., params = list(year = 2025L)).

Value

The output file path, invisibly.

34 Extract a single metadata field from a PDF

Description

Extracts a single structured value from a PDF using either an LLM or a local GLiNER2 model. Results are stored in sess$items[[label]] and recorded as a step.

Usage

select_item(
  sess,
  label,
  prompt,
  cast = NULL,
  page = NULL,
  area = NULL,
  backend = c("llm", "gliner"),
  chat = NULL,
  provider = getOption("macrox.llm.provider", "anthropic"),
  model = getOption("macrox.llm.model", NULL),
  base_url = NULL,
  dpi = 120L,
  gliner_model = "fastino/gliner2-base-v1",
  all_matches = FALSE
)

Arguments

sess

A macrox_session object.

label

Character label for the item (e.g. "invoice_number").

prompt

Description of the field to extract. For the LLM backend this is the full instruction; for GLiNER it is the field description passed alongside label as the entity type.

cast

Optional type to cast the returned string to: "character" (default), "numeric", "integer", or "date:<fmt>" e.g. "date:%d/%m/%Y".

page

Page number. For backend = "llm", NULL sends all page text and a non-NULL value renders an image. For backend = "gliner", NULL uses all pages' text and a non-NULL value uses only that page's text (no image rendering).

area

Named c(top, left, bottom, right) in PDF points. Only used when backend = "llm" and page is non-NULL.

backend

Extraction backend: "llm" (default, requires ellmer) or "gliner" (local GLiNER2 model, requires reticulate + gliner2 Python package installed via setup_gliner()).

chat

An existing ellmer Chat object. Only used when backend = "llm". See select_table_llm().

provider

LLM provider (default "anthropic"). Only used when backend = "llm" and chat is NULL.

model

Model name. Only used when backend = "llm".

base_url

Base URL for "openai_compatible" providers.

dpi

Render resolution when backend = "llm" and page is set (default 120).

gliner_model

GLiNER2 model name (HuggingFace repo). Only used when backend = "gliner". Default "fastino/gliner2-base-v1" (205M params); use "fastino/gliner2-large-v1" for higher accuracy.

all_matches

Logical; only used when backend = "gliner". If TRUE, return every occurrence of the entity found in the text as a character vector instead of just the first match. Default FALSE.

Value

sess invisibly (step is recorded).

Examples

# LLM backend (default)
sess |> select_item("invoice_number",
  prompt = "Extract the invoice ID or reference number.")

# GLiNER backend — local, no API key needed
setup_gliner()
sess |> select_item("invoice_number",
  prompt  = "Invoice ID or reference number",
  backend = "gliner")

# GLiNER on a specific page
sess |> select_item("total_amount",
  prompt  = "Grand total amount payable",
  page    = 1L,
  cast    = "numeric",
  backend = "gliner")

35 Extract multiple metadata fields in one GLiNER model pass

Description

Runs a single GLiNER2 inference call to extract several named fields from a PDF, which is significantly faster than calling select_item() once per field. Each field is recorded as a separate select_item step so macros replay with the standard select_item mechanism.

Usage

select_items_batch(
  sess,
  items,
  page = NULL,
  cast = NULL,
  gliner_model = "fastino/gliner2-base-v1",
  all_matches = FALSE
)

Arguments

sess

A macrox_session object.

items

Named character vector: names are field labels, values are natural-language prompts describing the field. E.g. c(invoice_no = "Invoice ID or reference number", total = "Grand total amount payable").

page

Page number to extract from. NULL (default) concatenates all pages' text.

cast

Named character vector of cast types keyed by label. Unlisted fields default to "character". Supported types: "character", "numeric", "integer", "date:<fmt>" (e.g. "date:%d/%m/%Y").

gliner_model

GLiNER2 model identifier. Default "fastino/gliner2-base-v1" (205M); use "fastino/gliner2-large-v1" for higher accuracy.

all_matches

If TRUE, return every occurrence found per label as a character vector. Labels listed in cast are still applied element-wise. Default FALSE.

Details

GLiNER2 can return multiple occurrences of the same entity type when they are present in the text; select_items_batch surfaces the first match per field (the same behaviour as select_item()).

Value

sess invisibly (one select_item step recorded per field).

36 Extract structured records from a PDF page using GLiNER2

Description

Uses GLiNER2's extract_json to extract a structured entity schema (multiple fields, optional list fields, multiple records) from a PDF page. Results are stored as a data frame in sess$tables[[label]], identical to tabulapdf / LLM table extraction — downstream steps and exports work unchanged.

Usage

select_struct(
  sess,
  label,
  entity = label,
  fields,
  list_fields = character(0),
  enum_fields = character(0),
  page = 1L,
  gliner_model = "fastino/gliner2-base-v1"
)

Arguments

sess

A macrox_session object.

label

Table label to store results under.

entity

Entity type name used in the GLiNER2 schema. Defaults to label.

fields

Named character vector: field_name = "description". Every name becomes a column in the resulting data frame.

list_fields

Character vector of field names that may contain multiple values (GLiNER2 list type). Multiple values are collapsed with "; ". Default character(0).

enum_fields

Named character vector of enumerated field types: field_name = "[val1|val2|val3]". Restricts what the model extracts to the listed choices. Default character(0).

page

Integer or integer vector of pages to extract from. Multiple pages use a single batch_extract_json call. Default 1L.

gliner_model

GLiNER2 model identifier. Default "fastino/gliner2-base-v1".

Value

sess invisibly (step recorded).

37 Extract a table from the PDF and record the step

Description

Three selection modes: by page + index, by bounding box (area), or by fuzzy caption match (label_match). These can be mixed across different tables in the same session.

Usage

select_table(
  sess,
  label,
  page = NULL,
  table_index = 1,
  area = NULL,
  label_match = NULL,
  method = c("lattice", "stream", "bbox"),
  header_rows = 1,
  fuzzy_method = "jw",
  max_dist = 0.2,
  row_tol = NULL,
  col_gap = NULL
)

Arguments

sess

A macrox_session object.

label

Character label for the extracted table.

page

Page number (integer). Required unless label_match is supplied.

table_index

Which table on the page (1-based, tabulapdf methods only). Default 1.

area

Named numeric vector c(top, left, bottom, right) in PDF points. Use locate_area() to capture interactively. Strongly recommended with method = "bbox" to isolate the table from surrounding charts/text.

label_match

Text caption to fuzzy-search across all pages.

method

Extraction engine:

  • "lattice" (default) — tabulapdf, best for grid-lined tables.

  • "stream" — tabulapdf, best for whitespace-separated tables.

  • "bbox" — pdftools::pdf_data() word-position engine. Handles PDFs where tabulapdf fails: charts on the same page, missing grid lines, numbers running together. Use with area to clip to the table region.

header_rows

Number of header rows to merge (default 1). Use 2+ for multi-row spanning headers.

fuzzy_method

stringdist method for caption matching (default "jw").

max_dist

Maximum normalised distance for a fuzzy match (default 0.2).

row_tol

bbox method only. Vertical gap (pts) above which a new row is started. Default NULL auto-computes from median character height.

col_gap

bbox method only. Horizontal gap (pts) between word groups that signals a new column. Default NULL auto-computes from median word width.

Value

sess invisibly (step is recorded).

38 Extract a table using Docling

Description

Converts the PDF page using Docling's ML layout pipeline and returns a clean data frame. Works fully offline after the initial one-time model download; handles scanned PDFs and complex layouts where bbox fails.

Usage

select_table_docling(sess, label, page, table_index = 1L)

Arguments

sess

A macrox_session object.

label

Character label for the extracted table.

page

Page number (integer).

table_index

Which table to use when multiple are detected on the page (default 1).

Details

Docling converts the target page the first time it is called and caches the result in the Python session, so repeated calls for different tables on the same page do not re-run the conversion pipeline. Call close_docling() to release the cache when done.

Value

sess invisibly (step is recorded).

39 Extract a table using an LLM

Description

Renders the PDF page (optionally cropped to area), sends it to an LLM with a structured schema, and returns a clean data frame. Good for multi-level headers, tables embedded in mixed-content pages, and any situation where positional extraction fails.

Usage

select_table_llm(
  sess,
  label,
  page,
  area = NULL,
  chat = NULL,
  provider = getOption("macrox.llm.provider", "anthropic"),
  model = getOption("macrox.llm.model", NULL),
  base_url = NULL,
  schema = NULL,
  prompt = NULL,
  dpi = 150L,
  header_rows = 1L,
  mode = c("structured", "page"),
  table_index = 1L
)

Arguments

sess

A macrox_session object.

label

Character label for the extracted table.

page

Page number (integer).

area

Named numeric vector c(top, left, bottom, right) in PDF points. When supplied the image sent to the LLM is cropped to that region, which improves accuracy on pages with multiple tables.

chat

An existing ellmer Chat object, e.g. ellmer::chat_anthropic(), ellmer::chat_openrouter(), or ellmer::chat_openai_compatible(base_url = "http://localhost:11434/v1", model = "llama2"). The chat is cloned before use (its history is left untouched). When supplied, provider, model, and base_url are ignored for the call but recorded (derived from the chat object) so the step can be replayed.

provider

Name of an ellmer chat constructor, without the chat_ prefix, e.g. "anthropic" (default), "openai", "google_gemini", "openrouter", "groq", "ollama", or "openai_compatible". Any provider for which ellmer exports chat_<provider>() is supported. Note: "github" is no longer valid; GitHub Models was retired in ellmer 0.5.0. Ignored when chat is supplied.

model

Model name. NULL uses a sensible default for "anthropic", "openai", and "google_gemini"; other providers require model to be set explicitly. Ignored when chat is supplied.

base_url

Base URL for "openai_compatible" providers. Ignored when chat is supplied.

schema

Named character vector mapping column names to R types: c(Month = "character", Male = "integer", Total = "integer"). Supported types: "character", "integer", "numeric". NULL (default) asks the LLM to auto-detect the columns.

prompt

Optional extra instructions appended to the base prompt, e.g. "Ignore the footnote row at the bottom.".

dpi

Render resolution for the page image (default 150).

header_rows

Number of header rows. When > 1 the prompt asks the LLM to flatten them with _ separators. Ignored in "page" mode.

mode

Extraction mode:

  • "structured" (default) — renders the area (or full page if no area) and asks the LLM to return a typed JSON object. Best when you know the table's location and can supply a schema.

  • "page" — renders the full page, asks the LLM to convert it to markdown, and parses the resulting markdown tables. No schema or area is required; good for quick extraction when the layout is unknown. area is ignored. Use table_index to pick among multiple tables.

table_index

When mode = "page" and multiple tables are detected on the page, which one to return (default 1).

Details

Requires the ellmer package (install.packages("ellmer")) and an API key for the chosen provider set as an environment variable (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY).

Value

sess invisibly (step is recorded).

40 Install Docling into a Python environment

Description

Creates (or reuses) a Python environment and installs the docling package. Run once and restart R before calling select_table_docling().

Usage

setup_docling(envname = "r-macrox", pip_options = character(0))

Arguments

envname

Name of the Python environment (default "r-macrox").

pip_options

Extra pip flags, e.g. c("--index-url", "https://pypi.internal.corp/simple").

Details

On the first extraction call Docling downloads its ML models (~2-3 GB) and caches them locally. Subsequent calls are fully offline.

Value

Invisible NULL.

41 Install GLiNER2 in the macrox Python environment

Description

Installs the gliner2 Python package and pre-loads the requested model so it is ready for select_item() calls with backend = "gliner".

Usage

setup_gliner(
  model = "fastino/gliner2-base-v1",
  envname = "r-macrox",
  pip_options = character(0)
)

Arguments

model

Pre-trained model identifier (HuggingFace repo). Defaults to the 205M base model "fastino/gliner2-base-v1". The 340M large variant is "fastino/gliner2-large-v1".

envname

Python virtual environment name (default "r-macrox").

pip_options

Additional pip install options (character vector).

Value

NULL invisibly.

42 Show all extracted items

Description

Show all extracted items

Usage

show_items(sess)

Arguments

sess

A macrox_session object.

Value

sess invisibly. # not recorded

43 Show recorded steps

Description

Prints a numbered list of all steps in the session, with flagged steps highlighted.

Usage

show_steps(sess)

Arguments

sess

A macrox_session object.

Value

sess invisibly.

44 Show validation results for all tables

Description

Prints a summary of every validate_table() result stored in the session.

Usage

show_validations(sess)

Arguments

sess

A macrox_session object.

Value

sess invisibly. # not recorded

45 Split one column into several by a separator

Description

Splits each cell in col on sep (a regex) and stores the resulting pieces in new columns named by into. The original column is removed unless keep = TRUE. Cells with fewer pieces than length(into) are padded with NA; cells with more are truncated.

Usage

split_column(sess, table, col, into, sep = "\\s+", keep = FALSE)

Arguments

sess

A macrox_session object.

table

Character label of the target table.

col

Name of the column to split.

into

Character vector of names for the new columns.

sep

Regex separator (default "\\s+" — one or more whitespace chars).

keep

If TRUE, keep the original column alongside the new ones.

Value

sess invisibly (step is recorded).

46 Split one column of a data frame into several

Description

The data-frame counterpart of split_column(): it takes a data frame and returns a data frame, with no session and no recorded step.

Usage

split_column_df(df, col, into, sep = "\\s+", keep = FALSE)

Arguments

df

A data frame.

col

Name of the column to split.

into

Character vector of names for the new columns.

sep

Regex separator (default "\\s+" — one or more whitespace chars).

keep

If TRUE, keep the original column alongside the new ones.

Value

df with col replaced (or, with keep = TRUE, followed) by the new columns named in into.

47 Extract and stack the same table across multiple PDF pages

Description

Extracts a table from each page in pages and row-binds them into a single data frame. Supports all extraction engines including "llm".

Usage

stack_pages(
  sess,
  label,
  pages,
  area = NULL,
  method = c("bbox", "lattice", "stream", "llm"),
  chat = NULL,
  provider = getOption("macrox.llm.provider", "anthropic"),
  model = getOption("macrox.llm.model", NULL),
  base_url = NULL,
  schema = NULL,
  prompt = NULL,
  dpi = 150L,
  mode = c("structured", "page"),
  table_index = 1L,
  header_rows = 1L,
  header_match = TRUE,
  row_tol = NULL,
  col_gap = NULL
)

Arguments

sess

A macrox_session object.

label

Character label for the combined table.

pages

Integer vector of page numbers to extract and stack (minimum 2).

area

Named c(top, left, bottom, right) in PDF points, or NULL for the full page. Applied identically to every page.

method

Extraction engine: "bbox" (default), "lattice", "stream", or "llm".

chat

An existing ellmer Chat object (LLM method only). See select_table_llm().

provider

LLM provider (LLM method only, default "anthropic"). Ignored when chat is supplied. Reads getOption("macrox.llm.provider") when set.

model

Model name (LLM method only). NULL uses the provider default. Ignored when chat is supplied. Reads getOption("macrox.llm.model") when set.

base_url

Base URL for "openai_compatible" providers (LLM only).

schema

Named character vector of column types, e.g. c(Month = "character", Total = "integer") (LLM method only). NULL asks the model to auto-detect columns — a consistent schema is strongly recommended for multi-page stacking.

prompt

Extra instructions appended to the base prompt (LLM only).

dpi

Render resolution for page images (LLM only, default 150).

mode

LLM extraction mode: "structured" (default) or "page". See select_table_llm().

table_index

Which table to pick when mode = "page" returns multiple tables (LLM only, default 1).

header_rows

Number of header rows (non-LLM methods, default 1).

header_match

Logical (non-LLM methods, default TRUE). When TRUE repeated headers are consumed as column names on every page.

row_tol

bbox method only.

col_gap

bbox method only.

Details

For "bbox", "lattice", and "stream": repeated header rows are handled automatically when header_match = TRUE (default) — the header is consumed as column names on each page and dropped from the data. Set header_match = FALSE when pages 2+ start directly with data.

For "llm": the model returns schema-defined columns directly so there are no repeated headers to consume; header_match is ignored. Supply schema for best accuracy and consistent column names across pages.

Value

sess invisibly (step is recorded).

48 Row-bind multiple extracted tables into one

Description

Useful after batch replay to combine monthly or regional tables that share the same schema.

Usage

stack_tables(sess, label, tables, .fill = FALSE)

Arguments

sess

A macrox_session object.

label

Label for the combined output table.

tables

Character vector of existing table labels to stack.

.fill

Fill missing columns with NA when schemas differ (default FALSE).

Value

sess invisibly (step is recorded).

49 Convert raw struct extraction to a data frame

Description

Takes the raw GLiNER2 records stored by select_struct() (which include per-field confidence scores) and converts them to a data frame stored in sess$tables[[label]]. Optionally filters out low-confidence records.

Usage

struct_to_df(sess, label, min_confidence = NULL)

Arguments

sess

A macrox_session object.

label

Label matching a prior select_struct() call.

min_confidence

Numeric in [0, 1]. Records whose mean field confidence is below this threshold are dropped. NULL (default) keeps all.

Value

sess invisibly (step recorded).

50 Suggest column types for an extracted table

Description

Inspects values in each column and returns a named character vector of type specs compatible with cast_types(). Useful as a starting point before calling cast_types() or providing a schema to select_table_llm().

Usage

suggest_schema(sess, label)

Arguments

sess

A macrox_session object.

label

Character label of the table to inspect.

Value

Named character vector of type specs (invisibly).

51 Test extraction parameters and return a structured evaluation report

Description

The R-Core Judge for the MCP agent loop. Runs a single extraction pass with the given parameters and returns a structured report indicating whether the result is clean or needs adjustment. The MCP test_parameters tool calls this in a loop until status == "success".

Usage

test_extraction(
  file,
  page,
  area = NULL,
  method = c("bbox", "lattice", "stream", "llm"),
  header_rows = 1L,
  label = "target",
  provider = "anthropic",
  schema = NULL,
  preview_rows = 3L,
  ...
)

Arguments

file

Path to a PDF file.

page

Page number (integer).

area

Named c(top, left, bottom, right) in PDF points, or NULL for the full page.

method

Extraction method: "bbox" (default), "lattice", "stream", or "llm".

header_rows

Number of header rows (default 1).

label

Internal table label used during extraction (default "target").

provider

LLM provider, only used when method = "llm".

schema

Named character vector of column types, only used when method = "llm".

preview_rows

Number of data rows to include in the response preview (default 3). Keeps the agent context window small.

...

Additional arguments forwarded to the extraction function.

Details

Returns a list that serialises cleanly to JSON via jsonlite::toJSON().

Value

A list with:

status

"success", "needs_alignment", "empty", or "crash".

metrics

Structural quality metrics: row/col counts, unnamed headers, empty columns, header-spill detection, likely-numeric character columns.

guidance

Plain-English action string for the agent when status is not "success".

preview

First preview_rows rows as a list of named lists for JSON serialisation.

52 Snapshot-test a macro against a stored reference

Description

Replays a macro (or accepts a pre-replayed table list) and compares the output against a stored YAML snapshot. On the first call the snapshot is written; subsequent calls compare against it. Designed for use inside testthat::test_that() blocks but also works standalone.

Usage

test_macro(
  file = NULL,
  macro = NULL,
  tables = NULL,
  macro_path = ".",
  params = list(),
  snapshot_dir = file.path("tests", "testthat", "macro-snapshots"),
  name = NULL,
  update = identical(Sys.getenv("TESTTHAT_SNAPSHOT_UPDATE"), "true"),
  n_head = 5L
)

Arguments

file

Path to the PDF file. Ignored when tables is supplied.

macro

Macro name, path, or step list. Ignored when tables is supplied.

tables

A pre-replayed named list of data frames (the result of mx_replay()). When supplied, file and macro are ignored.

macro_path

Directory for macro lookup (default .).

params

Named list of macro parameter values passed to mx_replay().

snapshot_dir

Directory in which to read/write snapshot files (default "tests/testthat/macro-snapshots").

name

Snapshot file stem. Defaults to the macro name when macro is a string, otherwise "macro_snapshot".

update

If TRUE, overwrite the stored snapshot with the current output. Also triggered by the environment variable TESTTHAT_SNAPSHOT_UPDATE=true (set automatically by testthat::snapshot_accept()).

n_head

Number of header rows captured in the snapshot for spot-checking (default 5).

Details

Workflow:

  1. Call test_macro(file, macro = "my_macro") locally with the reference PDF. The snapshot is written to snapshot_dir.

  2. Commit the snapshot file alongside your package.

  3. In CI, either replay with the same PDF or supply tables directly. test_macro() compares against the committed snapshot and fails on drift.

Value

The replayed table list, invisibly.

53 Update the prompt for a recorded select_item step and re-extract

Description

Update the prompt for a recorded select_item step and re-extract

Usage

update_item(
  sess,
  label,
  prompt = NULL,
  cast = NULL,
  chat = NULL,
  re_extract = TRUE
)

Arguments

sess

A macrox_session object.

label

Label of the item to update.

prompt

New prompt string.

cast

New cast type, or NULL to keep existing.

chat

An existing ellmer Chat object to use for the re-extraction. See select_table_llm(). NULL (default) reuses the provider/model recorded for the step.

re_extract

Re-run the LLM call immediately (default TRUE).

Value

sess invisibly.

54 Update the schema for a recorded LLM extraction step and re-extract

Description

Finds the most recent select_table_llm step for label, replaces its schema, and re-runs the extraction against the same page/area. Useful when the auto-detected columns need renaming or the types need adjustment.

Usage

update_llm_schema(
  sess,
  label,
  schema,
  prompt = NULL,
  chat = NULL,
  re_extract = TRUE
)

Arguments

sess

A macrox_session object.

label

Label of the table to update.

schema

New named character vector: c(Month = "character", Male = "integer").

prompt

Replacement prompt, or NULL to keep the existing one.

chat

An existing ellmer Chat object to use for the re-extraction. See select_table_llm(). NULL (default) reuses the provider/model recorded for the step.

re_extract

Re-run the LLM call immediately (default TRUE).

Value

sess invisibly.

55 Validate a macro against a PDF without extracting data

Description

Runs a pre-flight check on every step. Agents should call this after generating a macro and fix any errors before the human runs mx_replay().

Usage

validate_macro(file, macro)

Arguments

file

Path to a PDF file.

macro

Either a step list or a path to a .yml file.

Value

A macrox_validation list with $valid, $steps (data frame), and $errors (character vector).

56 Validate an extracted table against a set of rules

Description

Uses the validate package DSL. Rules are named character strings containing R expressions evaluated against the data frame. Both row-level predicates (total_count > 0) and table-level aggregates (nrow(.) == 12) are supported.

Usage

validate_table(sess, table, rules, strict = FALSE)

Arguments

sess

A macrox_session object.

table

Character label of the table to validate.

rules

Named character vector or named list of R expression strings. Names become the rule identifiers shown in reports. Alternatively, a validate::validator() object.

strict

If TRUE, any rule failure calls cli_abort() instead of cli_warn(). Default FALSE.

Details

Results are stored in sess$validations[[table]] for later inspection. On replay, failures produce warnings by default; set strict = TRUE to abort.

Value

sess invisibly (step is recorded).

Examples

sess |> validate_table("calf_monthly", rules = c(
  no_na_month    = "!anyNA(month)",
  positive_males = "all(male_count > 0, na.rm = TRUE)",
  twelve_rows    = "nrow(.) == 12"
))

57 View a recorded step's location in the PDF

Description

Renders the PDF page for a select_table or select_table_llm step and opens it in the RStudio Viewer or system browser. If the step used a bounding box, the selected area is highlighted in blue. Requires magick for annotations (Suggests).

Usage

view_in_pdf(sess, step = NULL, dpi = 150)

Arguments

sess

A macrox_session object.

step

Integer step index. Defaults to the most recent step with a page location (select_table or select_table_llm).

dpi

Render resolution (default 150).

Value

The bounding box area (named numeric vector or NULL), invisibly.