Skip to main content

pdf2notes

Turn a page range of a PDF book into descriptive, review-ready study notes (Markdown) — ready to drop into Obsidian or import into Notion.

Works with any OpenAI-compatible chat completion API: NVIDIA NIM (integrate.api.nvidia.com), OpenAI, Groq, Together AI, OpenRouter, or a local server (Ollama, vLLM, LM Studio). You bring your own API key.

Setup

pip install -r requirements.txt

Get an API key (NVIDIA NIM example — free tier available)

  1. Go to https://build.nvidia.com
  2. Sign in, pick a model (e.g. meta/llama-3.1-70b-instruct), click "Get API Key"
  3. Export it:
    export NVIDIA_API_KEY="nvapi-xxxxxxxxxxxxxxxx"
    

Any other OpenAI-compatible provider works the same way — just pass --base-url and --api-key-env for that provider.

Usage

python pdf2notes.py --pdf book.pdf --pages 120-180 --api-key-env NVIDIA_API_KEY

This writes book_notes_120-180.md in the current folder. Requests run concurrently and are throttled to a requests-per-minute cap, so a 100-page range finishes in a couple of minutes instead of an hour.

If the run is interrupted, hits a persistent error, or you just Ctrl-C it, rerun the exact same command — chunks already saved in the output file are detected and skipped, so you only pay for/wait on what's missing.

Common options

Flag Meaning Default
--pdf Path to the source PDF required
--pages Page range, e.g. 120-180 (1-indexed, inclusive) required
--output Output .md path <pdf-name>_notes_<range>.md
--style descriptive, cornell, qa, or outline descriptive
--chunk-chars Max source characters sent per API call 6000
--concurrency Max simultaneous API requests 5
--rpm Max API requests per minute (across all workers) 40
--model Model name as your provider expects it nvidia/llama-3.3-nemotron-super-49b-v1.5
--base-url OpenAI-compatible API base URL NVIDIA NIM endpoint
--api-key-env Env var holding your key NVIDIA_API_KEY

Tune --rpm to your actual plan. NVIDIA's free tier, OpenAI's free/low tiers, etc. all cap requests per minute — check your provider's dashboard and set --rpm a bit under that. Setting it too high just means the tool eats a 429 and backs off; setting --concurrency too high does the same without helping speed once you're rpm-bound.

Model IDs get retired. NVIDIA (and other providers) periodically pull old model IDs from the catalog — you'll get an HTTP 404/410 if that happens. The tool detects this as non-retryable and fails immediately with the error instead of burning your rate-limit budget retrying a request that will never succeed. Check https://build.nvidia.com/models for current IDs and pass the right one via --model.

Examples

Using OpenAI instead of NVIDIA:

export OPENAI_API_KEY="sk-..."
python pdf2notes.py --pdf book.pdf --pages 1-50 \
  --base-url https://api.openai.com/v1 \
  --model gpt-4o-mini \
  --api-key-env OPENAI_API_KEY

Q&A flashcard-style notes instead of descriptive prose:

python pdf2notes.py --pdf book.pdf --pages 200-260 --style qa

Notes on how it works

  1. Extracts text from the given page range with pdfplumber.
  2. Groups pages into chunks (default ~6000 chars each) so each API call covers a coherent span without blowing past context limits.
  3. Sends each chunk to the model with a prompt tuned to produce learnable notes, not a shortened summary — definitions, examples, and important details are preserved and explained.
  4. Stitches everything into one Markdown file with YAML frontmatter (title, source, page range, style, timestamp) so it's ready to file straight into Obsidian, or import into Notion via Import → Markdown.

Limitations

  • Scanned/image-only PDFs won't extract text — OCR the PDF first (e.g. with pytesseract + pdf2image), then run this tool on the OCR'd version.
  • Very dense chunking settings (--chunk-chars too high) can exceed your model's context window — 6000–8000 is a safe default for most models.
  • Quality depends on the model you point it at — bigger instruction-tuned models produce noticeably better notes than small ones.
  • Memory: page text is extracted one page at a time and each page's internal pdfplumber cache (fonts, layout objects) is flushed immediately, so memory stays roughly proportional to a chunk's text, not the whole page range. For genuinely huge ranges (500+ pages in one run), consider splitting into a couple of --pages calls instead of one giant one.
  • A crash/segfault message after "Done.": if you see a SIGSEGV or similar right as the process exits but after your notes file is already complete and readable, it's happening during Python interpreter teardown, not during note generation — a known quirk of some PDF C extensions (e.g. pypdfium2, used internally by pdfplumber) not tearing down cleanly at exit. It doesn't affect your output file. If you want to suppress the noise, run with python pdf2notes.py ... ; true in a script, or ignore the exit code.

Metadata

Release files for pdf2notes 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pdf2notes 1.0.1
File Size Uploaded
pdf2notes-1.0.1.tar.gz 12.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pdf2notes 1.0.1
File Interpreter ABI Platform
pdf2notes-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 24.3 kB

Release files / pdf2notes-1.0.1.tar.gz

Download URL pdf2notes-1.0.1.tar.gz
Size 12.8 kB
Tags Source
SHA-256 checksum
How to use checksums
afcb57f43d0dd5b96561608ffe9b33ec78f63593173bbdea13fd15ce2545f9b3
BLAKE2b-256 checksum
How to use checksums
f52cf017e6ef556ed1eeb4ca2777d126de90bd4e3113738234ccee6b2ab508ce
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / pdf2notes-1.0.1-py3-none-any.whl

Download URL pdf2notes-1.0.1-py3-none-any.whl
Size 11.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5a9040ef2a539a295425d1d60adb2f0e318b1f9757b9503f674ff252bab07187
BLAKE2b-256 checksum
How to use checksums
37a4dc4034abf998a49b30f41ae4c3db2fd8cebb9df46c118aa8cb4916cec5bc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

1.0.2

2 release files

This release

1.0.1 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page