How to Summarize PDF Files with Python and LLMs

Tested prompts for summarize pdf using python compared across 5 leading AI models.

BEST BY JUDGE SCORE Claude Opus 4.7 9/10

If you searched 'summarize pdf using python', you're probably staring at a pile of PDFs — research papers, contracts, reports, or documentation — and you need the key points without reading every page. Python gives you the tools to extract that text programmatically, and modern LLMs let you turn raw extracted text into clean, accurate summaries in seconds.

The core workflow is straightforward: extract text from the PDF using a library like PyMuPDF or pdfplumber, pass that text to an LLM via API (OpenAI, Anthropic, Google, or an open-source model), and capture the structured summary as output. You can run this on a single file or batch-process hundreds at once with a loop.

This page shows you exactly how that prompt is structured, how four leading models respond to the same PDF content, and a side-by-side comparison so you can pick the right model for your specific use case — whether you need dense technical accuracy or a clean executive-level summary.

When to use this

This approach is the right move when you have PDFs with meaningful text content and need summaries you can act on, automate, or pipe into another system. It works best when the volume is too high for manual reading, the content is text-heavy rather than image-heavy, and you need repeatable, consistent output across many documents.

  • Summarizing a batch of research papers or academic PDFs to identify which ones are worth reading in full
  • Extracting key clauses and obligations from legal contracts before a lawyer review
  • Processing weekly financial or analyst reports into executive briefing bullets
  • Building a document Q&A tool where summaries serve as pre-processed context
  • Automating intake summaries for support tickets, RFPs, or policy documents uploaded by users

When this format breaks down

  • The PDF is primarily scanned images with no embedded text layer — you'll extract empty strings unless you add an OCR step with Tesseract or a similar tool first.
  • The document exceeds the LLM's context window and you haven't implemented chunking — feeding 80 pages of raw text into a 4k-token model will silently truncate content and produce summaries that miss most of the document.
  • You need legally defensible accuracy, such as summarizing medical records or court filings for official use — LLM summaries can hallucinate or omit critical details, and human review is required.
  • The PDF uses complex tables, charts, or figures as its primary information carrier — current text-extraction pipelines drop visual data, so summaries will be incomplete or misleading.

The prompt we tested

You are an expert technical assistant helping a user summarize a PDF document using Python. Based on the user's input describing their PDF content, goals, or environment, produce a clear, actionable Python-based workflow for summarizing PDFs using libraries such as PyPDF2, pdfplumber, or pymupdf combined with an LLM (e.g., OpenAI API, Anthropic API, or local models via transformers).

Follow these instructions strictly:
Respond with: (1) a short overview paragraph, (2) a numbered step-by-step guide, (3) a fully working Python code block using pdfplumber or PyPDF2 for text extraction and an LLM API call for summarization with chunking for long PDFs, and (4) a short note on handling large files and API keys. Keep the total response under 500 words and use clear headings.

User input:
I have a folder of 50-page research PDFs and I want to generate a 200-word executive summary for each one using Python and the OpenAI API. I'm running Python 3.11 on macOS and would prefer pdfplumber for extraction since some PDFs have tables.

Return a complete, copy-pasteable Python solution with a brief explanation of each step, followed by a sample summary output structure the user can expect.

Model comparison

ModelQualityCostLatencyTokens
Claude Opus 4.7 9 $0.1182 16.7s 413 / 1493
Claude Haiku 4.5 7 $0.0064 8.7s 303 / 1211
GPT-5.4 8 $0.0153 11.8s 267 / 973
Gemini 2.5 Pro 5 $0.0034 16.1s 278 / 618
Grok 4.1 Fast Reasoning 8 $0.0005 9.3s 414 / 746

Outputs

Claude Opus 4.7 9/10
# PDF Executive Summary Generator

## Overview
This workflow processes a folder of research PDFs, extracts text (including tables) using `pdfplumber`, chunks long documents to respect LLM context limits, and uses the OpenAI API to generate ~200-word executive summaries via a map-reduce strategy (summarize chunks, then combine). Results are saved as JSON for easy downstream use.

## Step-by-Step Guide
1. **Install dependencies**: `pdfplumber`, `openai`, and `tiktoken` for token counting.
2. **Set your API key** as an environment variable (`OPENAI_API_KEY`) — never hardcode it.
3. **Extract text page-by-page** with `pdfplumber`, including table rows converted to readable strings.
4. **Chunk the text** by token count (e.g., 3,000 tokens/chunk) to fit comfortably within model limits.
5. **Map step**: summarize each chunk concisely.
6. **Reduce step**: combine chunk summaries into a single 200-word executive summary.
7. **Iterate over the folder** and save outputs to a JSON file.

## Complete Python Solution

```python
import os
import json
from pathlib import Path
import pdfplumber
import tiktoken
from openai import OpenAI

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
MODEL = "gpt-4o-mini"
enc = tiktoken.get_encoding("cl100k_base")

def extract_pdf_text(pdf_path: Path) -> str:
    text_parts = []
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            text_parts.append(page.extract_text() or "")
            for table in page.extract_tables() or []:
                for row in table:
                    text_parts.append(" | ".join(c or "" for c in row))
    return "\n".join(text_parts)

def chunk_text(text: str, max_tokens: int = 3000) -> list[str]:
    tokens = enc.encode(text)
    return [enc.decode(tokens[i:i+max_tokens]) for i in range(0, len(tokens), max_tokens)]

def summarize(prompt: str, text: str, max_tokens: int = 400) -> str:
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "system", "content": prompt},
                  {"role": "user", "content": text}],
        temperature=0.3,
        max_tokens=max_tokens,
    )
    return resp.choices[0].message.content.strip()

def summarize_pdf(pdf_path: Path) -> str:
    text = extract_pdf_text(pdf_path)
    chunks = chunk_text(text)
    partials = [summarize("Summarize the key findings, methods, and conclusions concisely.", c)
                for c in chunks]
    combined = "\n\n".join(partials)
    final = summarize(
        "Write a polished ~200-word executive summary covering objective, methods, findings, and implications.",
        combined, max_tokens=350)
    return final

def process_folder(folder: str, out_file: str = "summaries.json"):
    results = {}
    for pdf in Path(folder).glob("*.pdf"):
        print(f"Processing {pdf.name}...")
        try:
            results[pdf.name] = summarize_pdf(pdf)
        except Exception as e:
            results[pdf.name] = f"ERROR: {e}"
    Path(out_file).write_text(json.dumps(results, indent=2))
    print(f"Saved to {out_file}")

if __name__ == "__main__":
    process_folder("./pdfs")
```

## Expected Output Structure
```json
{
  "paper_01.pdf": "This study investigates ... Methods included ... Results show ... Implications suggest ...",
  "paper_02.pdf": "The authors examine ..."
}
```

## Notes on Large Files & API Keys
- **Large PDFs**: 50-page papers typically produce 15k–30k tokens; the map-reduce chunking handles this safely. Increase `max_tokens` per chunk only if using a larger-context model.
- **API keys**: Store in `~/.zshrc` as `export OPENAI_API_KEY="sk-..."`. Consider adding retry logic (`tenacity`) and rate-limit backoff for batch jobs.
Judge notes: Nearly flawless and production-ready with the exact libraries requested, proper map-reduce chunking, error handling, and JSON output — the only minor gap is no explicit mention of installing dependencies via pip or a requirements.txt, and retry/rate-limit logic is mentioned but not implemented.
Claude Haiku 4.5 7/10
# PDF Summarization Workflow for Research Documents

## Overview
This workflow extracts text from multi-page research PDFs using **pdfplumber** (ideal for table handling), chunks the content to respect OpenAI API token limits, and generates concise 200-word executive summaries via the GPT-4 API. The solution processes entire folders efficiently with error handling.

## Step-by-Step Guide

1. **Install dependencies** – pdfplumber for extraction, openai for API calls
2. **Set up OpenAI API key** – store securely as environment variable
3. **Extract text from PDF** – use pdfplumber to preserve structure
4. **Chunk long content** – split text to stay within token limits (~3,000 tokens per chunk)
5. **Call OpenAI API** – send concatenated chunks with summarization prompt
6. **Save results** – write summaries to CSV or text files
7. **Process folder** – loop through all PDFs with error handling

## Complete Python Code

```python
import os
import pdfplumber
from openai import OpenAI
import csv
from pathlib import Path

# Initialize OpenAI client (uses OPENAI_API_KEY environment variable)
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def extract_text_from_pdf(pdf_path):
    """Extract text from PDF using pdfplumber."""
    text = ""
    try:
        with pdfplumber.open(pdf_path) as pdf:
            for page in pdf.pages:
                text += page.extract_text() or ""
        return text
    except Exception as e:
        print(f"Error extracting {pdf_path}: {e}")
        return None

def chunk_text(text, chunk_size=3000):
    """Split text into chunks by approximate token count."""
    words = text.split()
    chunks = []
    current_chunk = []
    
    for word in words:
        current_chunk.append(word)
        if len(" ".join(current_chunk)) > chunk_size:
            chunks.append(" ".join(current_chunk))
            current_chunk = []
    
    if current_chunk:
        chunks.append(" ".join(current_chunk))
    return chunks

def generate_summary(text, pdf_name):
    """Generate 200-word summary using OpenAI API."""
    chunks = chunk_text(text)
    combined_text = " ".join(chunks[:5])  # Use first ~15k tokens
    
    try:
        response = client.chat.completions.create(
            model="gpt-4",
            messages=[
                {
                    "role": "system",
                    "content": "You are an expert research analyst. Write clear, concise executive summaries."
                },
                {
                    "role": "user",
                    "content": f"Summarize this research paper in exactly 200 words, focusing on key findings, methodology, and conclusions:\n\n{combined_text}"
                }
            ],
            max_tokens=250,
            temperature=0.5
        )
        return response.choices[0].message.content
    except Exception as e:
        print(f"API error for {pdf_name}: {e}")
        return None

def process_pdf_folder(folder_path, output_csv="summaries.csv"):
    """Process all PDFs in folder and save summaries."""
    pdf_files = list(Path(folder_path).glob("*.pdf"))
    results = []
    
    for i, pdf_path in enumerate(pdf_files, 1):
        print(f"Processing {i}/{len(pdf_files)}: {pdf_path.name}")
        
        text = extract_text_from_pdf(str(pdf_path))
        if not text:
            continue
        
        summary = generate_summary(text, pdf_path.name)
        if summary:
            results.append({"filename": pdf_path.name, "summary": summary})
    
    # Save to CSV
    with open(output_csv, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=["filename", "summary"])
        writer.writeheader()
        writer.writerows(results)
    
    print(f"\n✓ Processed {len(results)} PDFs. Results saved to {output_csv}")

# Usage
if __name__ == "__main__":
    process_pdf_folder("./research_pdfs")
```

## Key Configuration Notes

**API Key Setup (macOS):**
```bash
export OPENAI_API_KEY="sk-your-key-here"
python script.py
```

**Large File Handling:** The code chunks text intelligently and samples the first ~15k tokens to avoid excessive API costs. For 50-page PDFs, budget ~$0.05–0.10 per summary (GPT-4 pricing). Monitor usage via OpenAI dashboard.

**Expected Output:** CSV with filename and 200-word summary per row.
Judge notes: The chunking strategy has a real weakness: it joins only the first 5 chunks and discards the rest of the document rather than implementing a proper map-reduce summarization approach for long PDFs, which is critical for 50-page research documents where conclusions and results may appear later in the text.
GPT-5.4 8/10
## Overview

Use `pdfplumber` to extract text page by page from each PDF, split the text into manageable chunks, summarize each chunk with the OpenAI API, then combine those chunk summaries into a final ~200-word executive summary. This works well for 50-page research PDFs and is easy to run on macOS with Python 3.11.

## Step-by-Step Guide

1. **Install dependencies**
   ```bash
   pip install pdfplumber openai python-dotenv
   ```

2. **Set your API key**
   Create a `.env` file:
   ```env
   OPENAI_API_KEY=your_api_key_here
   ```

3. **Prepare your PDF folder**
   Put all PDFs in a folder like `./pdfs`.

4. **Extract text with pdfplumber**
   `pdfplumber` handles many research PDFs better than basic extractors and can preserve table text more reliably.

5. **Chunk long documents**
   Split extracted text into chunks so each API request stays within model limits.

6. **Summarize in two passes**
   First summarize each chunk, then summarize the combined chunk summaries into one 200-word executive summary.

7. **Save results**
   Write each summary to a `.txt` file or print it to the console.

## Python Code

```python
import os
from pathlib import Path
from dotenv import load_dotenv
import pdfplumber
from openai import OpenAI

load_dotenv()
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

PDF_FOLDER = Path("./pdfs")
OUTPUT_FOLDER = Path("./summaries")
OUTPUT_FOLDER.mkdir(exist_ok=True)

MODEL = "gpt-4o-mini"

def extract_text_from_pdf(pdf_path):
    pages = []
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            text = page.extract_text() or ""
            tables = page.extract_tables()
            table_text = ""
            for table in tables:
                for row in table:
                    row = [cell if cell else "" for cell in row]
                    table_text += " | ".join(row) + "\n"
            pages.append(text + "\n" + table_text)
    return "\n".join(pages).strip()

def chunk_text(text, max_chars=12000):
    chunks, current = [], ""
    for para in text.split("\n\n"):
        if len(current) + len(para) < max_chars:
            current += para + "\n\n"
        else:
            if current.strip():
                chunks.append(current.strip())
            current = para + "\n\n"
    if current.strip():
        chunks.append(current.strip())
    return chunks

def chat_summary(prompt):
    response = client.chat.completions.create(
        model=MODEL,
        messages=[
            {"role": "system", "content": "You summarize research papers clearly for executives."},
            {"role": "user", "content": prompt}
        ],
        temperature=0.2
    )
    return response.choices[0].message.content.strip()

def summarize_pdf(pdf_path):
    text = extract_text_from_pdf(pdf_path)
    if not text:
        return "No extractable text found."

    chunks = chunk_text(text)
    chunk_summaries = []

    for i, chunk in enumerate(chunks, 1):
        prompt = f"Summarize this research PDF section in 120 words or less, focusing on purpose, methods, findings, and implications:\n\n{chunk}"
        chunk_summaries.append(chat_summary(prompt))

    combined = "\n".join(chunk_summaries)
    final_prompt = (
        "Create a concise executive summary of about 200 words from these section summaries. "
        "Include: objective, methodology, key findings, and business/scientific implications.\n\n"
        f"{combined}"
    )
    return chat_summary(final_prompt)

def main():
    for pdf_file in PDF_FOLDER.glob("*.pdf"):
        print(f"Processing: {pdf_file.name}")
        summary = summarize_pdf(pdf_file)
        out_file = OUTPUT_FOLDER / f"{pdf_file.stem}_summary.txt"
        out_file.write_text(summary, encoding="utf-8")
        print(f"Saved: {out_file}")

if __name__ == "__main__":
    main()
```

## Expected Output Structure

```text
Title: [Optional paper title]

Executive Summary:
This paper examines...
The authors used...
Key findings show...
The main implication is...
```

## Notes

For large files, chunking is essential to avoid token limits and reduce API errors. Keep your API key in `.env` and never hardcode or commit it to version control.
Judge notes: The solution is nearly production-ready and directly addresses the user's specific requirements (pdfplumber, 50-page PDFs, 200-word summaries, macOS/Python 3.11), but the "Expected Output Structure" section is a placeholder template rather than a realistic sample output, and the response slightly exceeds the 500-word limit specified in the instructions.
Gemini 2.5 Pro 5/10
Of course. Here is a complete, actionable workflow to summarize your research PDFs using Python, `pdfplumber`, and the OpenAI API.

### Overview

This solution automates the summarization of PDF documents located in a specified folder. The script will iterate through each PDF, extract its text content using `pdfplumber`, and handle long documents by breaking the text into smaller chunks. It then calls the OpenAI API to summarize these chunks and combines them into a final, concise 200-word executive summary for each file.

### Step-by-Step Guide

1.  **Install Libraries:** Open your terminal and install the necessary Python libraries.
    ```bash
    pip install pdfplumber openai python-dotenv
    ```
2.  **Set Up OpenAI API Key:** Create a file named `.env` in the same directory as your script. Add your API key to this file to keep it secure:
    ```
    OPENAI_API_KEY="your-api-key-here"
    ```
3.  **Organize Files:** Create a folder named `pdfs` in the same directory and place all the PDF files you want to summarize inside it.
4.  **Run the Script:** Save the code below as a Python file (e.g., `summarize_pdfs.py`) and run it from your terminal:
    ```bash
    python summarize_pdfs.py
    ```

### Python Summarization Script

```python
import os
import pdfplumber
import openai
from dotenv import load_dotenv

# --- Configuration ---
# Load environment variables from .env file (for OPENAI_API_KEY)
load_dotenv()
openai.api_key = os.getenv("OPENAI_API_KEY")

# Folder containing your PDF files
PDF_FOLDER = "pdfs"
MAX_TOKENS_PER_CHUNK = 2000 # Max tokens for the model (GPT-3.5 is ~4096)
SUMMARY_WORD_COUNT = 200

def extract_text_from_pdf(pdf_path):
    """Extracts text from a PDF file using pdfplumber."""
    full_text = ""
    try:
        with pdfplumber.open(pdf_path) as pdf:
            for page in pdf.pages:
                page_text = page.extract_text()
                if page_text:
                    full_text += page_text + "\n"
    except Exception as e:
        print(f"Error reading {pdf_path}: {e}")
        return None
    return full_text

def get_summary_from_openai(text, word_count):
    """Generates a summary for the given text using the OpenAI API."""
    try:
        response = openai.chat.completions.create(
            model="gpt-3
Judge notes: The code is cut off mid-execution (truncated at `"gpt-3`) and never delivers the chunking logic, the loop over the PDF folder, the sample output structure, or the note on large files/API keys — all of which were explicitly required.
Grok 4.1 Fast Reasoning 8/10
### Overview
This Python script processes a folder of research PDFs using pdfplumber for robust text extraction (including tables as text), chunks long docs to fit OpenAI limits, generates chunk summaries, then creates a final 200-word executive summary per PDF via GPT-4o-mini. Outputs JSON with summaries. Install: `pip install pdfplumber openai`.

### Step-by-Step Guide
1. **Set up**: Add your OpenAI API key as env var `OPENAI_API_KEY`. Place PDFs in a folder (e.g., `./pdfs/`).
2. **Run script**: Update `folder_path`, execute `python summarize_pdfs.py`. Handles 50-page PDFs by chunking ~4k chars each.
3. **Process**: Extracts text/tables per page, chunks text, summarizes chunks (100 words each), meta-summarizes to 200-word executive summary.
4. **Output**: JSON file `summaries.json` with `{ "filename.pdf": "200-word summary..." }`. Sample: `{"research1.pdf": "Key findings: ... (198 words)"}`.

### Python Code
```python
import pdfplumber
import openai
import os
import json
from dotenv import load_dotenv  # Optional: pip install python-dotenv

load_dotenv()  # Loads .env with OPENAI_API_KEY
client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

def extract_text(pdf_path):
    text = ""
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            page_text = page.extract_text()
            if page_text:
                text += page_text + "\n"
            tables = page.extract_tables()
            for table in tables:
                text += "\n".join([" | ".join(row) for row in table if row]) + "\n"
    return text

def chunk_text(text, chunk_size=4000):
    return [text[i:i+chunk_size] for i in range(0, len(text), chunk_size)]

def summarize_chunk(chunk):
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": f"Summarize this PDF chunk in 100 words:\n{chunk}"}]
    )
    return response.choices[0].message.content

def executive_summary(chunks):
    chunk_summaries = [summarize_chunk(chunk) for chunk in chunks]
    full_summary = " ".join(chunk_summaries)
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[{"role": "user", "content": f"Create a 200-word executive summary from these chunk summaries:\n{full_summary}"}]
    )
    return response.choices[0].message.content.strip()

folder_path = "./pdfs/"  # Update this
summaries = {}
for filename in os.listdir(folder_path):
    if filename.lower().endswith('.pdf'):
        pdf_path = os.path.join(folder_path, filename)
        text = extract_text(pdf_path)
        chunks = chunk_text(text)
        summary = executive_summary(chunks)
        summaries[filename] = summary
        print(f"Summarized {filename}")

with open("summaries.json", "w") as f:
    json.dump(summaries, f, indent=2)
```

### Notes
For large files (>50 pages), chunking prevents token limits (add error handling if needed). Secure API key in `.env`. Costs ~$0.01/PDF. Test on macOS Python 3.11. (347 words)
Judge notes: Minor weakness: table extraction rows may contain None values causing join errors, and no error handling for failed API calls or empty PDFs, but otherwise production-ready and closely matches all specified requirements.

What makes these work

  1. 01
    Chunk large PDFs before sending

    Most LLMs have token limits that a full PDF will exceed. Split the extracted text into chunks of 2,000-4,000 words, summarize each chunk individually, then run a second pass to summarize the chunk summaries. This map-reduce pattern produces accurate results on documents of any length and is easy to implement with a simple Python loop.

  2. 02
    Preserve document structure in extraction

    Use pdfplumber or PyMuPDF rather than basic text extraction to retain section headers, page numbers, and paragraph breaks. Feeding the LLM structured text with visible section labels produces summaries that are organized and easier to verify against the source. Flat text blobs tend to produce flat, harder-to-skim summaries.

  3. 03
    Specify summary format in your prompt

    Tell the model exactly what you want: bullet points, a paragraph, a table, or a JSON object with specific fields like 'key findings', 'risks', and 'next steps'. Vague prompts return vague summaries. When you define the output schema in the prompt, you get consistent structure you can reliably parse and display downstream.

  4. 04
    Pass metadata alongside the text

    Include context like document type, author, date, and intended audience in your prompt. Telling the model 'this is a legal contract, summarize for a non-lawyer business owner' produces dramatically more useful output than sending raw text alone. Metadata steers the model's word choice, detail level, and what it treats as important.

More example scenarios

#01 · Academic research paper summary
Input
A 12-page machine learning paper titled 'Efficient Transformers for Long-Document Understanding'. The abstract, methods, results, and conclusion sections have been extracted as plain text. The model achieved a 4.2% improvement over baseline on the SCROLLS benchmark using a sparse attention mechanism.
Expected output
This paper proposes a sparse attention variant that reduces computational cost for long documents. The method was evaluated on the SCROLLS benchmark, achieving a 4.2% performance gain over the baseline. The approach is practical for documents exceeding standard context limits and requires no fine-tuning on downstream tasks.
#02 · Commercial lease agreement summary
Input
A 34-page commercial lease PDF for a retail space in Austin, TX. Key extracted sections include: 5-year term starting March 1 2025, base rent $8,500/month with 3% annual escalation, tenant responsible for HVAC maintenance, personal guarantee required, 60-day termination notice clause, and a 6-month free-rent period in year one.
Expected output
5-year lease from March 2025 at $8,500/month, escalating 3% annually. Tenant covers HVAC maintenance costs. A personal guarantee is required. First 6 months are rent-free. Either party must give 60 days notice to terminate. Review the guarantee clause and maintenance scope carefully before signing.
#03 · Quarterly earnings report briefing
Input
The Q3 2024 earnings report PDF for a mid-cap SaaS company. Revenue came in at $142M, up 18% YoY. Net loss narrowed to $4.1M from $9.8M in Q3 2023. ARR grew to $560M. Churn rate improved to 4.2% from 5.7%. The company raised FY2024 revenue guidance from $545M to $570M.
Expected output
Q3 revenue hit $142M, up 18% year-over-year. Net loss shrank significantly to $4.1M from $9.8M. ARR reached $560M with churn improving to 4.2%. Management raised full-year guidance to $570M. The business is trending toward profitability with improving retention metrics.
#04 · Internal HR policy document
Input
A 22-page employee handbook PDF covering remote work policy updates for 2025. Key points extracted: employees can work remotely up to 3 days per week, must be reachable during core hours 10am-3pm local time, home office stipend increased to $800 one-time, international remote work capped at 30 days per year, and manager approval required for exceptions.
Expected output
Employees may work remotely up to 3 days per week with availability required between 10am and 3pm local time. A one-time $800 home office stipend is available. International remote work is limited to 30 days annually. Any exceptions to these limits require explicit manager approval.
#05 · Medical research PDF for clinical context
Input
A 9-page clinical trial summary PDF for a Phase 2 study of a cholesterol-lowering drug. Extracted text includes: 240 participants, 16-week double-blind placebo-controlled design, LDL reduction of 38% in treatment group vs 4% in placebo, adverse events reported in 12% of treatment group (mostly GI), no serious adverse events recorded.
Expected output
Phase 2 trial with 240 participants over 16 weeks. The treatment group saw a 38% LDL reduction compared to 4% in the placebo group. Adverse events, mostly gastrointestinal, occurred in 12% of the treatment group. No serious adverse events were recorded. Results support moving to Phase 3 evaluation.

Common mistakes to avoid

  • Ignoring token limits on long PDFs

    Sending a full 50-page PDF as one prompt will silently exceed the model's context window, causing the API to truncate or error. The resulting summary only reflects the first portion of the document. Always check token count before sending and implement chunking for anything over 10 pages.

  • Using basic PyPDF2 on complex layouts

    PyPDF2 often scrambles text order on PDFs with multi-column layouts, footnotes, or mixed text and tables. This feeds garbled text to the LLM, which produces confidently wrong summaries. Switch to pdfplumber or PyMuPDF for better layout-aware extraction on anything other than simple single-column documents.

  • Not handling scanned PDFs separately

    A scanned PDF contains images, not text. Running standard text extraction returns an empty string, and your LLM will either error or hallucinate a summary from nothing. Detect low text-yield PDFs programmatically and route them through an OCR pipeline before attempting summarization.

  • Treating the summary as ground truth

    LLMs can drop, reorder, or subtly alter facts during summarization. For high-stakes documents like contracts, medical files, or financial reports, always build in a human spot-check step. Ship the summary alongside a link or reference to the source section so reviewers can verify claims quickly.

  • Hardcoding the prompt without iteration

    The first prompt you write for PDF summarization is rarely the best one. Different document types need different instructions. A prompt tuned for research papers will produce poor output on legal contracts. Build a simple prompt versioning system early and test against at least 5-10 real documents before deploying to production.

Related queries

Frequently asked questions

What Python library should I use to extract text from a PDF?

PyMuPDF (imported as fitz) and pdfplumber are the strongest choices for most use cases. PyMuPDF is faster and handles a wider range of PDF versions. pdfplumber gives you better table extraction and more control over layout. Avoid PyPDF2 for anything complex — its text ordering on multi-column PDFs is unreliable.

How do I summarize a PDF that is longer than the LLM context window?

Use a map-reduce approach: split the extracted text into chunks small enough to fit within the model's token limit, summarize each chunk separately, then pass all the chunk summaries together into a final summarization call. Libraries like LangChain and LlamaIndex have built-in document summarization chains that implement this pattern for you.

Which LLM gives the best results for summarizing PDFs?

It depends on the document type. GPT-4o and Claude 3.5 Sonnet consistently produce accurate, well-structured summaries for technical and legal documents. Gemini 1.5 Pro has a very large context window, making it practical for long documents without chunking. For open-source options, Llama 3 70B performs well on general documents. The comparison table on this page shows side-by-side output from four models on the same input.

Can I summarize a scanned PDF using Python?

Yes, but you need an OCR step first. Use pytesseract with pdf2image to convert PDF pages to images and extract text before passing it to an LLM. Alternatively, some LLMs like GPT-4o accept image inputs directly, so you can send page images without a separate OCR library. The accuracy of the summary depends heavily on OCR quality.

How do I summarize multiple PDFs in a batch with Python?

Loop over a directory of PDF files using Python's pathlib or os.walk, extract text from each file, and call your summarization function for each one. Store results in a dictionary keyed by filename or write them to a CSV. Add error handling for files that fail extraction so one bad PDF doesn't stop the whole batch.

Is it safe to send confidential PDF content to an OpenAI or Anthropic API?

Check the provider's data usage policy before sending sensitive documents. OpenAI's API does not use API inputs to train models by default, and enterprise agreements add additional protections. For highly sensitive data like legal contracts or medical records, consider running a local open-source model like Llama 3 via Ollama so the content never leaves your infrastructure.

Try it with a real tool

Run this prompt in one of these tools. Affiliate links help keep Gridlyx free.