A PDF table contains the number 12.5. Your application needs to know whether it means dollars, kilograms, a percentage, or thousands of units.

A document model can recognize the number and still produce an unusable record if it loses the column heading, footnote, or measurement unit.

The Gemini 3.8 Flash API supports PDF input. This tutorial uses that capability to design a table-extraction workflow that preserves the information needed by a downstream application.

The goal is a traceable collection of rows, not a polished summary of the document.

1. Start with a defined table

Choose one table from a small, non-sensitive PDF.

A product specification sheet is a useful starting point because its rows usually have identifiable products and measurable properties.

Define the table you want before sending the document:

Extract the table titled "Shipping Specifications".
Include each product row.
Exclude the revision-history table and marketing comparisons.

A document may contain several tables with similar column names. A vague request to “extract all data” can combine unrelated sections.

Specify whether the application needs one table, a page range, or every occurrence of a particular table type.

2. Preserve the original value before normalizing it

Use separate fields for the source representation and the normalized interpretation.

An application-level record might look like this:

{
  "product_code": "BX-12",
  "field": "shipping_weight",
  "raw_value": "12.5 kg",
  "numeric_value": 12.5,
  "unit": "kg",
  "source_page": 2,
  "note": null
}

This is a synthetic example.

Keeping raw_value allows a reviewer to inspect what the extraction claims the document contained.

A dash should not automatically become zero. A blank cell should not become an estimated value. A range such as 10–12 kg should not silently become 11.

Define these cases in the output instructions.

3. Choose the exact Gemini interface

Google’s Gemini 3.8 Flash model documentation lists PDF among its supported inputs.

The document-understanding guide shows how to send PDF content through the current API.

The example below follows that documented Interactions workflow for direct Google access.

When using an API gateway, confirm the supported Gemini interface and document payload. Do not assume that a text-only OpenAI-compatible route accepts the same file structure.

For TreeRouter, use the model directory and integration documentation to check the account route before moving the request.

4. Send one small PDF

Install the SDK:

python -m pip install google-genai

Set GEMINI_API_KEY for direct Google access.

Save a small test document as specification.pdf, then run:

import base64
import json
import os
from pathlib import Path

from google import genai

client = genai.Client(api_key=os.environ["GEMINI_API_KEY"])

pdf_bytes = Path("specification.pdf").read_bytes()

instructions = """
Extract only the table titled Shipping Specifications.

Return JSON with one top-level key: rows.
Each row must contain:
product_code, field, raw_value, numeric_value, unit,
source_page, note.

Preserve product codes and original units.
Use null for unknown numeric values and missing units.
Do not turn a dash or blank cell into zero.
Keep ranges in raw_value and set numeric_value to null.
Use the PDF's physical page order, starting at 1.
Source-page numbers are proposed references for later checking.
Do not calculate values that are not stated.
Return JSON without Markdown fences.
"""

result = client.interactions.create(
    model="gemini-3.8-flash",
    input=[
        {
            "type": "document",
            "data": base64.b64encode(pdf_bytes).decode("ascii"),
            "mime_type": "application/pdf",
        },
        {"type": "text", "text": instructions},
    ],
)

text = result.output_text

if not text or not text.strip():
    raise RuntimeError("No extraction text was returned.")

data = json.loads(text)

if not isinstance(data, dict) or set(data) != {"rows"}:
    raise ValueError("Unexpected top-level structure.")

if not isinstance(data["rows"], list):
    raise ValueError("rows must be a list.")

Path("extracted-rows.json").write_text(
    json.dumps(data, ensure_ascii=False, indent=2),
    encoding="utf-8",
)

print(f"Rows returned: {len(data['rows'])}")

This example requests JSON through instructions and parses it locally. It does not enable native schema-constrained output.

The local check is intentionally limited to the top-level structure. Add row-level validation before importing the records into a production system.

An empty rows list is not automatically a successful extraction. If your test document contains a known table, an empty result needs investigation.

5. Validate row identity

A number can be correct but attached to the wrong product.

Use a stable row key, such as a product code or a combination of document identifier, table name, and row identifier.

Do not rely on a model-generated row number when the document already provides a business identifier.

Compare the extracted product codes with the source table. Check for missing rows, duplicated rows, and codes that appeared only in nearby explanatory text.

For multi-page tables, repeated column headings should not become data rows.

If the table has no reliable identifier, preserve the original row label and mark ambiguous associations for review.

6. Check units and scaling separately

Column headings often carry information that does not appear in each cell.

Examples include:

  • Revenue in thousands of dollars.
  • Weight in grams.
  • Percentages expressed without a % symbol in every row.
  • Dimensions listed in millimeters.
  • Footnotes changing the interpretation of selected values.

A row containing 12.5 under “Weight (kg)” should retain kg. A row under “Revenue, USD thousands” requires both currency and scaling information.

Avoid merging extraction and conversion in the first request. Preserve source values first. Perform deterministic conversions in application code once the source interpretation has been reviewed.

This makes mistakes easier to locate.

7. Treat page references as claims to verify

The example asks for physical PDF page numbers starting at one.

That convention may differ from printed page labels. A document can have an unnumbered cover, Roman-numbered introduction, or appendix numbering.

Keep the convention explicit in both the prompt and the reviewer interface.

The returned page number is model-generated metadata. It is not automatically a verified citation pointer.

Open a sample of the referenced pages and check that the table and row actually appear there. For important records, retain the source document version so later revisions do not break the relationship.

8. Handle scanned and difficult documents

Test difficult layouts separately.

A clean digital table and a low-resolution scan are not equivalent inputs. Rotated pages, merged cells, faint text, and overlapping stamps can change extraction quality.

When a cell is unreadable, an explicit unknown value is more useful than a plausible guess.

If preprocessing is necessary, keep the original PDF and record the transformation. Page splitting, rotation, and image enhancement can affect page references and the visual context available to the model.

Do not describe preprocessing as improving every document. Evaluate it on the document types your users actually submit.

9. Add deterministic business checks

After row-level type validation, apply rules your application can verify without another model call.

Examples include:

  • Product codes must exist in the selected document’s reviewed product list.
  • Required fields cannot be omitted.
  • Units must belong to the expected set for that field.
  • Duplicate row keys require review.
  • Numeric values cannot be accepted from unreadable cells.
  • A stated total can be compared with extracted line items.

A total mismatch does not prove which row is wrong. It provides a reason to inspect the extraction.

Also avoid assuming that totals must always equal a simple sum. Discounts, rounding, exclusions, and footnotes may explain the difference.

10. Introduce the workflow gradually

Begin by exporting records to a review screen or spreadsheet.

Keep the original value, normalized fields, and page reference visible together. Reviewers should not need to search the entire PDF to understand a flagged row.

Measure field accuracy and row completeness separately. A workflow can extract most values correctly while consistently missing the final row on each page.

For larger document systems, the enterprise RAG and document-processing guide discusses the surrounding preparation and retrieval stages.

Table extraction is one part of that pipeline, not a replacement for document access control or version management.

Frequently asked questions

Can I send extracted text instead of the PDF?

You can build a text-based workflow, but converting a document to plain text may remove layout relationships needed to interpret the table.

Does requesting JSON guarantee correct values?

No. JSON syntax, field structure, and factual accuracy need separate checks.

Can the gateway use the same uploaded file identifier as Google?

Do not assume that. File identifiers belong to the service and account that issued them unless the gateway explicitly documents another arrangement.

Should the model calculate unit conversions?

Preserve source values first. Use deterministic application code for conversions once units and scaling are established.

Build a document workflow around a real model route

Visit TreeRouter and confirm a Gemini route that supports the document interface your application needs.

Create an account, test one representative PDF, and compare the extracted rows with the original table before expanding to batch processing.