Skip to main content

Concatenate PDFs with table of contents, cover pages, and optional LLM summaries

Project description

pdf-concatenator

Bundle many PDFs into a single submission-ready document.

This tool was built to pull together a large set of PDFs for a contract submission: one combined file with a table of contents, cover pages, and optional short summaries so reviewers can navigate the bundle easily.

Features

  • Recursively discover PDFs from a directory or glob pattern
  • Sort files by path and concatenate them into one output PDF
  • Generate a table of contents with folder structure, page numbers, and alternating row shading
  • Insert a cover page before each source PDF (path, optional summary, page number)
  • Optionally generate LLM summaries via a sidecar file per PDF (*.pdf.sidecar.json)
  • Regenerate sidecars without concatenating (--regenerate-summaries)
  • Exclude specific files or patterns (--exclude)
  • Progress bar while summaries are processed

Installation

With pipx (recommended):

pipx install pdf-concatenator

With pip:

pip install pdf-concatenator

For development:

git clone https://github.com/lorenzowood/pdf-concatenator.git
cd pdf-concatenator
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

Quick start

Concatenate all PDFs under a folder:

pdf-concatenator -o submission.pdf contracts/

With summaries (requires LLM config — see below):

pdf-concatenator -o submission.pdf --include-summaries contracts/

Regenerate sidecar summaries only:

pdf-concatenator --regenerate-summaries contracts/

Exclude files:

pdf-concatenator -o submission.pdf \
  --exclude "drafts/*" \
  --exclude "broken.pdf" \
  contracts/

Patterns can be a directory (all PDFs beneath it) or a glob, e.g. contracts/**/*.pdf.

LLM configuration

When using --include-summaries or --regenerate-summaries, create ~/.config/pdf-concatenator:

LLM_API=open_ai
LLM_SERVER=127.0.0.1:28911
LLM_API_KEY=your-api-key
LLM_MODEL=your-model-id
LLM_PROMPT_TITLE_AND_SUMMARY=Your prompt here

The server should expose an OpenAI-compatible /v1/chat/completions endpoint. The whole PDF is sent to the model. If the prompt key is missing but everything else is valid, a default prompt is written to the config file.

Summaries are stored beside each PDF as document.pdf.sidecar.json and reused when the file hash matches.

Output structure

  1. Contents — tree of folders and files; page numbers point to each document's cover page. When summaries are included, a disclaimer appears in the footer.
  2. Cover page per PDF — relative path, optional summary, page number.
  3. Original PDF pages — unchanged (no added page numbers).

If any PDF cannot be read, or summary generation fails when required, the run aborts and no output file is produced.

Options

usage: pdf-concatenator [-h] [-o filename] [--include-summaries]
                        [--regenerate-summaries] [--exclude pattern]
                        [--config CONFIG] [--verbose]
                        pattern
Option Description
-o, --output Output PDF path (required unless --regenerate-summaries)
--include-summaries Include summaries in contents and cover pages
--regenerate-summaries Regenerate sidecar files only; do not concatenate
--exclude Glob pattern to exclude (repeatable)
--config Path to LLM config (default: ~/.config/pdf-concatenator)
--verbose Show library warnings while reading/merging PDFs

Development

pytest

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pdf_concatenator-1.0.0.tar.gz (18.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pdf_concatenator-1.0.0-py3-none-any.whl (13.8 kB view details)

Uploaded Python 3

File details

Details for the file pdf_concatenator-1.0.0.tar.gz.

File metadata

  • Download URL: pdf_concatenator-1.0.0.tar.gz
  • Upload date:
  • Size: 18.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.13

File hashes

Hashes for pdf_concatenator-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ca733268ad34cc7c10fdd65cb6b1915434eef1828eff8517cedc0c7ee0fe1105
MD5 d420bfeddb37918ce2268ced4901f40c
BLAKE2b-256 47c48f6fd32028a672c262662794fe770ee6f965815fb95e4b7798f983f279b1

See more details on using hashes here.

File details

Details for the file pdf_concatenator-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for pdf_concatenator-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8e73dd9d5e45befc1b82d11015a777454d8672b81e71acbf96d9e2ed958e8930
MD5 a39cca6999edd9535c225af393417d1b
BLAKE2b-256 393b9cc995469ae17af322354f6206025a35adbb05b051f1c8fe4f3c662fe33f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page