CLAUDE LABJP
FORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as OctoberFORK — Claude Code 2.1.212 changes what /fork does: it copies your conversation into a new background session with its own row in claude agents, so you can keep working. The old in-session subagent is now /subtaskLIMITS — WebSearch calls are now capped at 200 per session by default, and subagent spawns get the same 200 ceiling, so a runaway search or delegation loop stops on its ownMCPBG — MCP tool calls running past two minutes now move to the background automatically, keeping the session usable. Tune the threshold with CLAUDE_CODE_MCP_AUTO_BACKGROUND_MSPLANFIX — Fixed plan mode auto-running file-modifying Bash commands such as touch and rm without a permission prompt or an SDK canUseTool callbackSONNET5 — Claude Sonnet 5 is running on introductory pricing of $2 per million input tokens and $10 per million output. After August 31 it moves to $3 and $15IPO — Bankers are reportedly lining up investor meetings for Anthropic ahead of a possible public listing as soon as October
Articles/API & SDK
API & SDK/2026-03-26Intermediate

Build a PDF Analysis and Summarization App with Claude API — Vision plus Extended Thinking

Learn how to build a PDF analysis and summarization application using Claude API's Vision capabilities and Extended Thinking, with step-by-step Python implementation.

claude-api81vision7extended-thinking7pdf3python22tutorial3

The Cost of Reading PDFs by Hand

Businesses deal with a constant stream of PDFs—contracts, reports, research papers, and financial statements. Manually reading, summarizing, and extracting key information from these documents is incredibly time-consuming.

By combining Claude API's Vision capabilities with Extended Thinking, you can build an application that directly analyzes PDF page images and generates high-quality, deeply reasoned summaries. Below, a working PDF analysis pipeline is built up in Python piece by piece, from page rendering to the final summary.

For Claude API fundamentals, check out our Claude API Chatbot Complete Guide. For details on Extended Thinking, see our Extended Thinking Explainer.

Prerequisites and Setup

What You'll Need

  • Python 3.10 or later
  • Anthropic API key (get one at console.anthropic.com)
  • anthropic Python SDK (v0.40+)
  • pdf2image (for PDF-to-image conversion)
  • Poppler (dependency for pdf2image)

Environment Setup

# Install required packages
pip install anthropic pdf2image Pillow
 
# On macOS, install Poppler
brew install poppler
 
# On Ubuntu/Debian
# sudo apt-get install poppler-utils

Architecture Overview

The application works in three stages:

  1. PDF → Image Conversion: Convert each PDF page to a PNG image using pdf2image
  2. Vision Analysis: Use Claude API's Vision to extract text content from each page image
  3. Extended Thinking Summarization: Analyze the extracted text with Extended Thinking to produce structured, deeply reasoned summaries

This design handles scanned PDFs, complex layouts, charts, and diagrams—capturing visual information that traditional text extraction libraries often miss.

Step 1: Convert PDF Pages to Images

First, let's create a function that converts each PDF page into a base64-encoded image.

import base64
from io import BytesIO
from pdf2image import convert_from_path
from PIL import Image
 
def pdf_to_base64_images(pdf_path: str, dpi: int = 200) -> list[str]:
    """
    Convert each page of a PDF to a base64-encoded PNG image.
 
    Args:
        pdf_path: Path to the PDF file
        dpi: Image resolution (default: 200)
 
    Returns:
        List of base64-encoded image strings
    """
    # Convert PDF to list of images
    pages = convert_from_path(pdf_path, dpi=dpi)
 
    base64_images = []
    for page in pages:
        # Convert image to byte stream
        buffer = BytesIO()
        page.save(buffer, format="PNG")
        buffer.seek(0)
 
        # Base64 encode
        img_base64 = base64.b64encode(buffer.read()).decode("utf-8")
        base64_images.append(img_base64)
 
    return base64_images
 
# Usage example
# images = pdf_to_base64_images("report.pdf")
# print(f"Total pages: {len(images)}")
# Expected output: Total pages: 12

A DPI of 200 offers a good balance between text readability and image size. For PDFs with detailed charts or small tables, bump this up to 300.

Step 2: Extract Page Content with Vision

Now let's use Claude's Vision capability to analyze each page image.

import anthropic
 
client = anthropic.Anthropic()  # Uses ANTHROPIC_API_KEY env variable
 
def extract_page_content(base64_image: str, page_number: int) -> str:
    """
    Extract text content from a PDF page image using Claude Vision.
 
    Args:
        base64_image: Base64-encoded page image
        page_number: Page number for logging
 
    Returns:
        Extracted text content
    """
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=4096,
        messages=[
            {
                "role": "user",
                "content": [
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": "image/png",
                            "data": base64_image,
                        },
                    },
                    {
                        "type": "text",
                        "text": (
                            f"Extract all content from page {page_number} of this PDF. "
                            "Include all text, tables, figure captions, and equations. "
                            "Reproduce tables in Markdown format. "
                            "Describe the content of any figures or charts."
                        ),
                    },
                ],
            }
        ],
    )
    return response.content[0].text
 
def extract_all_pages(base64_images: list[str]) -> list[dict]:
    """Extract content from all pages."""
    results = []
    for i, img in enumerate(base64_images, start=1):
        print(f"Processing page {i}/{len(base64_images)}...")
        text = extract_page_content(img, i)
        results.append({"page": i, "content": text})
    return results
 
# Usage example
# pages = extract_all_pages(images)
# print(pages[0]["content"][:200])

Sonnet 4.6 provides excellent cost-performance for Vision tasks. For maximum accuracy on complex documents, you can switch to claude-opus-4-6.

Step 3: Generate Deep Summaries with Extended Thinking

def summarize_with_extended_thinking(
    pages: list[dict],
    thinking_budget: int = 10000,
    summary_language: str = "en",
) -> dict:
    """
    Generate a deep summary using Extended Thinking.
 
    Args:
        pages: List of page content dictionaries
        thinking_budget: Maximum thinking tokens
        summary_language: Output language ("en" or "ja")
 
    Returns:
        Dict with "thinking" and "summary" keys
    """
    # Combine all page text
    full_text = "\n\n".join(
        f"--- Page {p['page']} ---\n{p['content']}" for p in pages
    )
 
    lang_instruction = (
        "Summarize in English." if summary_language == "en"
        else "日本語で要約してください。"
    )
 
    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=16000,
        thinking={
            "type": "enabled",
            "budget_tokens": thinking_budget,
        },
        messages=[
            {
                "role": "user",
                "content": (
                    f"Below is the content of a PDF document ({len(pages)} pages).\n\n"
                    f"{full_text}\n\n"
                    "Create a structured summary in the following format. "
                    f"{lang_instruction}\n\n"
                    "1. **Executive Summary** (3-5 sentences covering the key takeaways)\n"
                    "2. **Key Points** (5-10 bullet points)\n"
                    "3. **Important Data & Figures** (notable numbers and statistics)\n"
                    "4. **Conclusions & Recommendations** (the document's main conclusions)\n"
                    "5. **Caveats & Limitations** (easily overlooked details)"
                ),
            }
        ],
    )
 
    thinking_text = ""
    summary_text = ""
    for block in response.content:
        if block.type == "thinking":
            thinking_text = block.thinking
        elif block.type == "text":
            summary_text = block.text
 
    return {"thinking": thinking_text, "summary": summary_text}
 
# Usage example
# result = summarize_with_extended_thinking(pages, thinking_budget=10000)
# print(result["summary"])

Setting thinking_budget to 10,000 tokens provides ample reasoning time for most documents. For academic papers or complex financial reports, consider increasing it to 20,000 for deeper analysis.

Putting It All Together

Here's the complete pipeline combining all three steps:

import sys
import json
from pathlib import Path
 
def analyze_pdf(pdf_path: str, output_path: str = None) -> dict:
    """
    Analyze a PDF file and generate a structured summary.
 
    Args:
        pdf_path: Path to the target PDF
        output_path: Where to save results (prints to stdout if omitted)
 
    Returns:
        Analysis results dictionary
    """
    print(f"📄 Loading PDF: {pdf_path}")
 
    # Step 1: PDF → Images
    images = pdf_to_base64_images(pdf_path)
    print(f"✅ Converted {len(images)} pages to images")
 
    # Step 2: Vision text extraction
    pages = extract_all_pages(images)
    print(f"✅ Text extraction complete")
 
    # Step 3: Extended Thinking summary
    result = summarize_with_extended_thinking(pages)
    print(f"✅ Summary generation complete")
 
    # Structure output
    output = {
        "source": pdf_path,
        "total_pages": len(pages),
        "pages": pages,
        "summary": result["summary"],
        "thinking_process": result["thinking"],
    }
 
    # Save to file
    if output_path:
        Path(output_path).write_text(
            json.dumps(output, ensure_ascii=False, indent=2),
            encoding="utf-8",
        )
        print(f"💾 Results saved to: {output_path}")
 
    return output
 
if __name__ == "__main__":
    pdf_file = sys.argv[1] if len(sys.argv) > 1 else "document.pdf"
    analyze_pdf(pdf_file, output_path="analysis_result.json")

Running the Pipeline

# Set your API key
export ANTHROPIC_API_KEY="YOUR_API_KEY"
 
# Analyze a PDF
python pdf_analyzer.py quarterly_report.pdf
 
# Expected output:
# 📄 Loading PDF: quarterly_report.pdf
# ✅ Converted 12 pages to images
# Processing page 1/12...
# ...
# ✅ Text extraction complete
# ✅ Summary generation complete
# 💾 Results saved to: analysis_result.json

Common Errors and Solutions

Poppler Not Found

pdf2image.exceptions.PDFInfoNotInstalledError

This occurs when Poppler isn't installed. Run brew install poppler (macOS) or apt-get install poppler-utils (Ubuntu) to fix it.

Image Too Large

Claude API has image size limits. Lower the DPI or add resizing logic:

def resize_if_needed(image: Image.Image, max_size: int = 2048) -> Image.Image:
    """Resize image if it exceeds the maximum dimension."""
    w, h = image.size
    if max(w, h) > max_size:
        ratio = max_size / max(w, h)
        new_size = (int(w * ratio), int(h * ratio))
        return image.resize(new_size, Image.LANCZOS)
    return image

Extended Thinking Token Limits

If thinking_budget is too low, the reasoning may be truncated, leading to shallow summaries. Increase the budget if quality feels lacking—but keep in mind that costs scale proportionally.

Summary

In this guide, we built a PDF analysis and summarization application that combines Claude API's Vision capabilities with Extended Thinking. The Vision-based approach handles scanned PDFs, complex layouts, and visual elements that traditional text extraction tools struggle with.

By layering Extended Thinking on top, we get summaries that go beyond simple text conversion—they demonstrate genuine understanding of document structure, key arguments, and nuances. Try integrating this pipeline into your document management or research workflows to dramatically speed up information processing.

Share

Thank You for Reading

Claude 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-05-06
Claude API × Python in Practice: Building an AI Assistant with Tool Calling and Streaming
A practical guide to combining Claude API's Tool Use and Streaming in Python. Build a working AI assistant with real tool execution, complete source code included, plus a breakdown of the tricky parts that trip up most developers.
API & SDK2026-05-05
Building a 'Think-and-Search' AI Agent — Claude API Extended Thinking × Tool Use
A deep dive into combining Claude API Extended Thinking and Tool Use. Covers frequent errors, a complete research agent implementation in Python, plus cost estimation, timeout design, and error recovery for production use.
API & SDK2026-06-12
Handing Monthly Revenue CSVs to the Claude API Code Execution Tool — Files API Wiring, Container Reuse, and Billing Traps
How I moved monthly revenue-CSV reconciliation for four apps into the Claude API Code Execution tool — Files API integration, container reuse, the 5-minute billing minimum, and the file-preload charge that surprises almost everyone.
📚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 →