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)
  • Tinted background colours on contents and cover pages so they stand out when scrolling (default: legal-pad yellow)
  • 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.

Customise the tinted backgrounds on contents and cover pages (hex colours, default #f3f2a3):

pdf-concatenator -o submission.pdf \
  --contents-background "#f3f2a3" \
  --cover-background "#f3f2a3" \
  contracts/

Alternating row stripes in the contents are derived from the contents background (5% black overlay), so they stay readable on any colour.

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. Alternating rows are shaded. When summaries are included, a disclaimer appears in the footer.
  2. Cover page per PDF — relative path, optional summary, page number. Both contents and cover pages use a tinted background (legal-pad yellow by default).
  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.

Splitting large outputs

Upload limits (e.g. 50 MB) can be handled by splitting:

pdf-concatenator -o submission.pdf --max-output-size 50M contracts/

This produces submission_part_1.pdf, submission_part_2.pdf, and so on. Each part stays under the limit. Every part includes the full table of contents; entries in other parts are labelled Part 2, Part 3, etc. Under the Contents heading, each part also notes:

This archive is split into n parts. This is part m.

If everything fits in one file, the original output name is used with no _part_ suffix.

Options

usage: pdf-concatenator [-h] [-o filename] [--include-summaries]
                        [--regenerate-summaries] [--exclude pattern]
                        [--config CONFIG] [--verbose]
                        [--max-output-size SIZE]
                        [--contents-background color]
                        [--cover-background color]
                        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
--max-output-size Split output into parts under this size (e.g. 50M, 2G)
--contents-background Background colour for contents pages (default: #f3f2a3)
--cover-background Background colour for cover pages (default: #f3f2a3)

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.1.4.tar.gz (26.9 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.1.4-py3-none-any.whl (20.1 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: pdf_concatenator-1.1.4.tar.gz
  • Upload date:
  • Size: 26.9 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.1.4.tar.gz
Algorithm Hash digest
SHA256 5f8d1a2f8379d76e6105d9d41b28050bd9a456c7b3970b82078b87b427ccfaf1
MD5 837641ec8f5b41ee5c628f7995eaf6f0
BLAKE2b-256 9de89a82051930a1617e1833f357cf0d8075503b9a4e715cc15c92e635336b4c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pdf_concatenator-1.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 3cba1e3242fdba195240a65bc9d7422a5c33f1b693ba3dd0023d50321a3dcc9f
MD5 d84c170c5be12be3533f157ded7ecfde
BLAKE2b-256 6ea44c52c25a81a11342aaa50bb747791a2f4f217637e12d80e0e89c566ce2f9

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