GEMINI LABJP
NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20
Articles/API / SDK
API / SDK/2026-03-14Advanced

Gemini Advanced Document Processing — PDF Analysis, Table Extraction & Automated Review

Advanced document processing with Gemini's multimodal capabilities. Covers full PDF analysis, table and chart extraction, multi-document comparison, automated contract and invoice review. Includes File API integration and context caching patterns.

Gemini75document processingPDFmultimodal44OCRstructured extraction

Setup and context

Gemini 2.5 Pro's multimodal capabilities enable document processing far beyond simple text extraction. Layout recognition, structured table extraction, cross-document analysis, and intelligent document understanding are now within reach for enterprise-grade applications.

Gemini's Document Understanding Capabilities

Advantages Over Traditional OCR

Traditional OCR focuses purely on character recognition, while Gemini understands image content contextually:

  • Layout Understanding: Recognition of sections, columns, indentation, and visual hierarchy
  • Table Structure Recognition: Accurate parsing of complex matrix layouts with merged cells
  • Chart Interpretation: Extracting numeric values and trends from visual data
  • Contextual Analysis: Comprehending meaning and relationships within document structure
ℹ️
Gemini API excels with complex structured documents like financial reports, legal contracts, and medical records where layout and context matter.

PDF Processing with File API

Upload and Processing Status

import google.generativeai as genai
import time
 
# Initialize client
client = genai.Client(api_key="YOUR_API_KEY")
 
def upload_and_process_pdf(file_path: str):
    """
    Upload PDF and wait for processing completion
    """
 
    print(f"Uploading file: {file_path}")
 
    # Upload file
    with open(file_path, "rb") as f:
        pdf_file = client.files.upload(
            file=f,
            mime_type="application/pdf"
        )
 
    file_uri = pdf_file.uri
    print(f"Upload complete: {file_uri}")
 
    # Poll processing status
    for attempt in range(30):
        file = client.files.get(pdf_file.name)
 
        if file.state.name == "ACTIVE":
            print(f"File processing complete")
            return file_uri
 
        elif file.state.name == "FAILED":
            raise Exception(f"File processing failed: {file.state.name}")
 
        print(f"Processing... ({attempt + 1}/30)")
        time.sleep(2)
 
    raise TimeoutError("File processing timeout")
 
# Example usage
pdf_uri = upload_and_process_pdf("contract.pdf")

Full Document Analysis and Text Extraction

Structure-Preserving Full Text Extraction

def analyze_full_pdf_content(pdf_uri: str):
    """
    Extract complete PDF text preserving document structure
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    prompt = """
    Extract the complete content of this PDF document in the following structure:
 
    # Document Structure Analysis
 
    ## Metadata
    - Title:
    - Date Published:
    - Total Pages:
 
    ## Section-by-Section Content
    Organize sections in hierarchical structure
 
    ### [Section 1 Title]
    Content...
 
    ### [Section 2 Title]
    Content...
 
    ## Key Terms and Named Entities
    - Term 1: Definition
    - Term 2: Definition
 
    ## Numerical Data
    - Value 1: Amount
    - Value 2: Amount
    """
 
    response = model.generate_content([
        prompt,
        {
            "mime_type": "application/pdf",
            "data": pdf_uri
        }
    ])
 
    return response.text
 
# Implementation example
full_content = analyze_full_pdf_content(pdf_uri)
print(full_content)

Section Identification

def identify_pdf_sections(pdf_uri: str):
    """
    Automatically identify document section structure
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    prompt = """
    Extract the document's section structure in JSON format:
 
    {
        "sections": [
            {
                "section_id": 1,
                "title": "Section Title",
                "page_numbers": [1, 2],
                "subsections": [
                    {
                        "title": "Subsection Title",
                        "content_summary": "Brief summary"
                    }
                ]
            }
        ]
    }
    """
 
    response = model.generate_content([
        prompt,
        {
            "mime_type": "application/pdf",
            "data": pdf_uri
        }
    ])
 
    import json
    return json.loads(response.text)

Table Extraction to Structured Format

Converting Tables to JSON

def extract_tables_to_json(pdf_uri: str):
    """
    Extract all tables from PDF as JSON structures
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    prompt = """
    Extract all tables in this PDF in JSON format:
 
    {
        "tables": [
            {
                "table_id": 1,
                "title": "Table Title",
                "location": "Page X",
                "headers": ["Column 1", "Column 2", "Column 3"],
                "rows": [
                    ["Data11", "Data12", "Data13"],
                    ["Data21", "Data22", "Data23"]
                ],
                "notes": "Any footnotes"
            }
        ]
    }
 
    Guidelines:
    - Empty cells represented as null
    - Handle merged cells appropriately
    - Include units with values
    """
 
    response = model.generate_content([
        prompt,
        {
            "mime_type": "application/pdf",
            "data": pdf_uri
        }
    ])
 
    import json
    return json.loads(response.text)
 
# Example usage
tables = extract_tables_to_json(pdf_uri)
for table in tables["tables"]:
    print(f"Table: {table['title']}")
    print(f"Location: {table['location']}")
    for row in table["rows"]:
        print(row)

Handling Complex Tables

def extract_complex_tables_with_context(pdf_uri: str):
    """
    Process complex tables with multi-level headers and merged cells
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    prompt = """
    Analyze all tables in this document carefully:
 
    1. Capture multi-level header structures precisely
    2. Record cell merging and splitting
    3. Include units and supplementary information
    4. Identify subtotals and summary rows
 
    Return as JSON:
 
    {
        "tables": [
            {
                "table_id": 1,
                "structure": {
                    "header_rows": 2,
                    "header_columns": 1,
                    "data_rows": 10
                },
                "columns": [
                    {
                        "name": "Column Name",
                        "type": "string|number|date",
                        "unit": "Unit"
                    }
                ],
                "data": [...]
            }
        ]
    }
    """
 
    response = model.generate_content([
        prompt,
        {
            "mime_type": "application/pdf",
            "data": pdf_uri
        }
    ])
 
    import json
    return json.loads(response.text)

Chart and Graph Interpretation

Extracting Numeric Values from Charts

def analyze_charts_and_graphs(pdf_uri: str):
    """
    Extract numeric data from all charts and graphs in PDF
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    prompt = """
    Analyze all charts, graphs, and visual data in this document.
    Return in JSON format:
 
    {
        "charts": [
            {
                "chart_id": 1,
                "type": "bar|line|pie|scatter",
                "title": "Chart Title",
                "x_axis": {
                    "label": "X Axis Label",
                    "values": ["Value1", "Value2"]
                },
                "y_axis": {
                    "label": "Y Axis Label",
                    "scale": "linear|logarithmic"
                },
                "series": [
                    {
                        "name": "Series Name",
                        "data": [100, 150, 120]
                    }
                ],
                "insights": "Key trends and findings visible in chart"
            }
        ]
    }
    """
 
    response = model.generate_content([
        prompt,
        {
            "mime_type": "application/pdf",
            "data": pdf_uri
        }
    ])
 
    import json
    return json.loads(response.text)

Multi-Document Comparison

Comparative Document Analysis

def compare_multiple_documents(pdf_uris: list):
    """
    Compare and analyze multiple PDF documents
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    # Build prompt
    prompt = """
    Analyze and compare the following documents, identifying similarities and differences:
 
    Return JSON:
    {
        "comparison": {
            "document_count": N,
            "similarities": [
                {
                    "aspect": "Comparison Point",
                    "details": "Description of commonalities"
                }
            ],
            "differences": [
                {
                    "aspect": "Comparison Point",
                    "document_1": "Value 1",
                    "document_2": "Value 2",
                    "significance": "Importance of difference"
                }
            ],
            "summary": "Overall assessment"
        }
    }
    """
 
    # Construct content
    content = [prompt]
    for pdf_uri in pdf_uris:
        content.append({
            "mime_type": "application/pdf",
            "data": pdf_uri
        })
 
    response = model.generate_content(content)
 
    import json
    return json.loads(response.text)
 
# Example usage
comparison = compare_multiple_documents([pdf_uri_1, pdf_uri_2])
print(comparison)

Automated Contract Review

Extracting Contract Terms

def review_contract_automatically(contract_uri: str):
    """
    Automatically extract and analyze key contract terms
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    prompt = """
    Analyze this contract from a legal perspective.
 
    Return as JSON:
 
    {
        "contract_analysis": {
            "contract_type": "Type of contract",
            "parties": [
                {
                    "name": "Party Name",
                    "role": "Role"
                }
            ],
            "key_terms": {
                "effective_date": "Start date",
                "duration": "Contract period",
                "termination_clause": "Termination conditions"
            },
            "financial_terms": {
                "payment_amount": "Amount",
                "currency": "Currency",
                "payment_schedule": "Payment schedule",
                "penalties": "Penalty clauses"
            },
            "obligations": [
                {
                    "party": "Party",
                    "obligation": "Obligation description"
                }
            ],
            "risk_factors": [
                {
                    "risk": "Risk description",
                    "severity": "high|medium|low",
                    "mitigation": "Mitigation strategy"
                }
            ],
            "compliance_requirements": [
                "Compliance requirement"
            ],
            "recommendations": "Reviewer recommendations"
        }
    }
    """
 
    response = model.generate_content([
        prompt,
        {
            "mime_type": "application/pdf",
            "data": contract_uri
        }
    ])
 
    import json
    return json.loads(response.text)
 
# Example usage
contract_review = review_contract_automatically(contract_uri)
print(f"Risk factors: {contract_review['contract_analysis']['risk_factors']}")

Detecting Unfavorable Clauses

def detect_unfavorable_clauses(contract_uri: str, company_context: str):
    """
    Automatically identify clauses that are unfavorable to your company
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    prompt = f"""
    Company context: {company_context}
 
    Identify clauses in this contract that are unfavorable or concerning to our company:
 
    {{
        "unfavorable_clauses": [
            {{
                "clause_location": "Article X Section Y",
                "clause_text": "Original clause text",
                "concern": "Specific concern",
                "impact": "Impact on our company",
                "suggested_revision": "Recommended modification"
            }}
        ],
        "negotiation_priorities": [
            {{
                "priority": 1,
                "clause": "Clause to modify",
                "rationale": "Reason for modification"
            }}
        ]
    }}
    """
 
    response = model.generate_content([
        prompt,
        {
            "mime_type": "application/pdf",
            "data": contract_uri
        }
    ])
 
    import json
    return json.loads(response.text)

Invoice Processing

Structured Data Extraction from Invoices

def process_invoice(invoice_uri: str):
    """
    Extract financial data from invoice in structured format
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    prompt = """
    Extract the following information from this invoice as JSON:
 
    {
        "invoice_metadata": {
            "invoice_number": "Invoice number",
            "invoice_date": "Date issued",
            "due_date": "Due date",
            "currency": "Currency"
        },
        "parties": {
            "vendor": {
                "name": "Vendor name",
                "address": "Address",
                "contact": "Contact info"
            },
            "customer": {
                "name": "Customer name",
                "address": "Address"
            }
        },
        "line_items": [
            {
                "description": "Item description",
                "quantity": 10,
                "unit_price": 100.00,
                "line_total": 1000.00
            }
        ],
        "summary": {
            "subtotal": Subtotal,
            "tax_amount": Tax amount,
            "tax_rate": "Tax rate",
            "total": Total amount,
            "payment_terms": "Payment terms"
        },
        "payment_information": {
            "bank_account": "Bank account",
            "payment_method": "Payment method"
        }
    }
    """
 
    response = model.generate_content([
        prompt,
        {
            "mime_type": "application/pdf",
            "data": invoice_uri
        }
    ])
 
    import json
    return json.loads(response.text)
 
# Example usage
invoice_data = process_invoice(invoice_uri)
print(f"Total amount: {invoice_data['summary']['total']}")

Financial Statement Analysis

Automated Key Metrics Extraction

def analyze_financial_statement(statement_uri: str):
    """
    Extract key metrics from financial reports and statements
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    prompt = """
    Analyze this financial statement and return in JSON format:
 
    {
        "statement_info": {
            "company_name": "Company name",
            "fiscal_year": "Fiscal year",
            "statement_type": "balance_sheet|income_statement|cash_flow"
        },
        "balance_sheet": {
            "assets": {
                "current_assets": Amount,
                "non_current_assets": Amount,
                "total_assets": Amount
            },
            "liabilities": {
                "current_liabilities": Amount,
                "non_current_liabilities": Amount,
                "total_liabilities": Amount
            },
            "equity": {
                "total_equity": Amount
            }
        },
        "income_statement": {
            "revenue": Revenue,
            "cost_of_revenue": Cost,
            "gross_profit": Profit,
            "operating_expenses": Expenses,
            "operating_income": Income,
            "net_income": Net income
        },
        "key_ratios": {
            "current_ratio": Current ratio,
            "debt_to_equity": Debt to equity,
            "profit_margin": "Profit margin",
            "return_on_assets": "ROA"
        },
        "year_over_year_analysis": {
            "revenue_change": "Revenue growth rate",
            "profit_trend": "Profit trend",
            "key_observations": "Key findings"
        }
    }
    """
 
    response = model.generate_content([
        prompt,
        {
            "mime_type": "application/pdf",
            "data": statement_uri
        }
    ])
 
    import json
    return json.loads(response.text)

Context Caching for Efficiency

Document Caching Implementation

def process_document_with_caching(pdf_uri: str, queries: list):
    """
    Run multiple queries against the same document with caching
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
 
    # Cached document reference
    cached_document = {
        "mime_type": "application/pdf",
        "data": pdf_uri
    }
 
    results = []
 
    for i, query in enumerate(queries):
        print(f"Query {i + 1}/{len(queries)}")
 
        content = [
            query,
            cached_document
        ]
 
        # Caching optimization (from 2nd request onwards)
        if i > 0:
            # Caching headers applied automatically by SDK
            pass
 
        response = model.generate_content(content)
        results.append({
            "query": query,
            "response": response.text
        })
 
    return results
 
# Example usage
queries = [
    "What are the key findings in this document?",
    "What are the main financial trends?",
    "What are the identified risk factors?"
]
 
cached_results = process_document_with_caching(pdf_uri, queries)
⚠️
Context caching significantly reduces API costs and improves performance. Use it for frequently accessed documents and multiple queries against the same PDF.

Batch Processing

Efficient Processing of Large Document Sets

from concurrent.futures import ThreadPoolExecutor
import time
 
class BatchDocumentProcessor:
    def __init__(self, max_workers=5):
        self.max_workers = max_workers
        self.results = []
 
    def process_batch(self, document_uris: list, task_type: str):
        """
        Process multiple documents in parallel
        """
 
        def process_single_document(uri, task_type):
            if task_type == "contract_review":
                return review_contract_automatically(uri)
            elif task_type == "invoice":
                return process_invoice(uri)
            elif task_type == "financial":
                return analyze_financial_statement(uri)
 
        with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
            futures = [
                executor.submit(process_single_document, uri, task_type)
                for uri in document_uris
            ]
 
            for i, future in enumerate(futures):
                try:
                    result = future.result(timeout=300)
                    self.results.append({
                        "document_index": i,
                        "status": "success",
                        "result": result
                    })
                    print(f"Processed: Document {i + 1}/{len(document_uris)}")
                except Exception as e:
                    self.results.append({
                        "document_index": i,
                        "status": "failed",
                        "error": str(e)
                    })
 
        return self.results
 
# Example usage
processor = BatchDocumentProcessor(max_workers=5)
results = processor.process_batch(pdf_uris, "contract_review")
 
success_count = sum(1 for r in results if r["status"] == "success")
print(f"Success rate: {success_count}/{len(pdf_uris)}")

Cost Management

class DocumentProcessingCostManager:
    def __init__(self):
        # Gemini API pricing (March 2026)
        self.input_cost_per_million = 0.075  # USD
        self.output_cost_per_million = 0.3
 
    def estimate_cost(self, num_documents, avg_pages_per_doc, queries_per_doc=1):
        """
        Estimate document processing costs
        """
 
        # Convert pages to tokens (1 page ≈ 2000 tokens)
        avg_tokens_per_page = 2000
        total_input_tokens = (
            num_documents * avg_pages_per_doc * avg_tokens_per_page *
            queries_per_doc
        )
 
        # Estimate output tokens (≈20% of input)
        total_output_tokens = int(total_input_tokens * 0.2)
 
        input_cost = (total_input_tokens / 1_000_000) * self.input_cost_per_million
        output_cost = (total_output_tokens / 1_000_000) * self.output_cost_per_million
 
        total_cost = input_cost + output_cost
 
        return {
            "num_documents": num_documents,
            "estimated_input_tokens": total_input_tokens,
            "estimated_output_tokens": total_output_tokens,
            "input_cost": f"${input_cost:.2f}",
            "output_cost": f"${output_cost:.2f}",
            "total_cost": f"${total_cost:.2f}",
            "cost_per_document": f"${total_cost / num_documents:.4f}"
        }
 
# Example usage
cost_mgr = DocumentProcessingCostManager()
estimate = cost_mgr.estimate_cost(
    num_documents=1000,
    avg_pages_per_doc=10,
    queries_per_doc=3
)
print(f"Estimated cost: {estimate['total_cost']}")
print(f"Per document: {estimate['cost_per_document']}")

Document Processing Patterns

Pattern: Invoice Auto-Classification and Reconciliation

def classify_and_process_invoices(invoice_uris: list):
    """
    Classify invoices by vendor and process in batches
    """
 
    model = genai.GenerativeModel("gemini-2.5-pro")
    classified = {"vendors": {}, "failed": []}
 
    for uri in invoice_uris:
        # Classify by vendor
        classify_prompt = "Extract vendor name and amount from this invoice"
 
        classify_response = model.generate_content([
            classify_prompt,
            {"mime_type": "application/pdf", "data": uri}
        ])
 
        vendor_name = extract_vendor_name(classify_response.text)
 
        # Organize by vendor
        if vendor_name not in classified["vendors"]:
            classified["vendors"][vendor_name] = []
 
        classified["vendors"][vendor_name].append(uri)
 
    # Process by vendor
    for vendor, uris in classified["vendors"].items():
        print(f"\nVendor: {vendor} ({len(uris)} invoices)")
        for uri in uris:
            invoice_data = process_invoice(uri)
            print(f"  Amount: {invoice_data['summary']['total']}")
 
    return classified

Conclusion

Gemini API's multimodal capabilities enable enterprise-grade document processing. Key takeaways:

  • File API: Efficient handling of large PDFs with structured processing
  • Structured Extraction: JSON-format output for reliable data capture
  • Multi-Document Analysis: Cross-document comparison and relationship detection
  • Batch Processing: Efficient large-scale document handling
  • Context Caching: Cost reduction and performance optimization

By combining these techniques, you can build high-accuracy, cost-effective document processing systems that rival traditional specialized software while offering superior flexibility and integration.

A note from the field

Automating the Dolice Labs operations as an indie developer, the hard part of document processing was never accuracy — it was deciding how extraction fails. I attach a confidence score to critical fields and route anything below threshold to a human queue rather than silently returning blanks, and I screen out unreadable scans up front so the downstream model costs stay predictable.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

API / SDK2026-07-18
How Well Does Omni Flash Hear 'Rotate the Camera 30 Degrees Right'? Measuring Where Conversational Edits Land
Public-preview Gemini Omni Flash lets you re-edit a generated video in plain language. 'Make the lighting evening' lands; 'rotate the camera 30 degrees' often misses. Here is a running log of where instructions land, sorted mechanically by comparing before/after frames.
API / SDK2026-07-07
Extract Social Media Promo Metadata From Short Videos in One Omni Flash Pass
Hand a short clip to the public preview of Gemini Omni Flash once and get captions, chapters, and highlight timestamps back as structured JSON. Covers how this differs from a frame-extraction multi-call setup, where fps and media_resolution actually matter, and a per-clip cost estimate — from the angle of keeping an indie promo workflow moving.
API / SDK2026-07-05
Collapsing Video Understanding into One Native Call with Omni Flash
How I replaced an ffmpeg frame-extraction pipeline (7-9 calls per clip) with a single native Omni Flash call, the measured differences, and the boundaries where keeping frame sampling still wins.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →