DEV Community

Ayushya Ranjan
Ayushya Ranjan

Posted on

Stop opening the whole PDF: local summaries for reading debt

Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady Submission πŸ¦₯

This is a submission for the Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady

What I Built

tldr-everything is a local reading-debt killer. You hand it a PDF, a Markdown file, or a paste. It gives back three layers, each from its own model call:

  • a 30-second summary, about 60–90 words, the claim and the outcome
  • a 3-minute explanation, about 350–500 words, the why, the how, and the jargon
  • detailed notes grouped by page, with citations like (p. 4), plus the top takeaways and the questions the document never answers

There is a second mode, "tell me only what I need." You type a goal, for example "I want to deploy this with Docker on a VPS." Each chunk gets a relevance score from 0 to 5. Chunks under the cutoff are dropped. From the rest you get prerequisites, practical steps, the pages that matter, what you can skip, and the gotchas. If nothing scores high enough, it says the document does not cover the goal and shows the closest sections. It does not invent a procedure.

The person who gets to be lazier is anyone with a folder of tutorials, docs, and papers they saved "for later." They can spend a minute on the summary, or ask one question, and only open the original when a page citation is worth it.

The default model is Qwen2.5-3B-Instruct through Ollama. It fits in about 8 GB of RAM, including CPU-only. A 3B model will wander if you ask it for five sections at once, so the pipeline never does that. One job per call. Short prompts. Chunks of about 1,500 tokens. If the chunk summaries still do not fit, they are reduced in rounds until they do. Python then checks the work: word counts, commands that must actually appear in the source, and numbers the document never stated. A fenced command that is not in the PDF is dropped. An inline command that is not in the PDF is marked [unverified].

Demo

Local only. Nothing is hosted, and the document stays on the machine unless you point the base URL at a remote server.


ollama pull qwen2.5:3b
ollama create tldr-qwen -f ollama/Modelfile
export LLM_MODEL=tldr-qwen
tldr summarize examples/docker-vps.md --layer 30s
tldr goal examples/docker-vps.md --goal "I want to deploy this with Docker on a VPS"
tldr ui
Enter fullscreen mode Exit fullscreen mode

tldr-qwen is a one-line Modelfile on top of qwen2.5:3b that sets num_ctx 8192. Ollama's OpenAI-compatible endpoint often ignores a per-request context size and silently cuts the prompt. The derived model is how a small local model gets the whole chunk.

A hand-written sample of the shape of the output, taken from the Docker-on-a-VPS note in the repo, is in examples/sample-output.md. The practical steps from that note are the commands that are actually in the file:

sudo apt-get update
sudo apt-get install -y docker.io
docker compose up -d
Enter fullscreen mode Exit fullscreen mode

Code

tldr-everything

The Reading Debt Killer. Turn a PDF or a long paste into a 30-second summary, a 3-minute explanation, and page-cited notes, or ask for only the parts that match a goal.

CI License: MIT Python 3.10+

The code in this repository is MIT. The default model weights are not. See Model licensing.

Demo

A GIF belongs in docs/screenshots/. Record the Streamlit app on examples/docker-vps.md, save it as docs/screenshots/demo.gif, and drop this line in once the file exists:

![tldr-everything summarizing a short Docker guide](docs/screenshots/demo.gif)
Enter fullscreen mode Exit fullscreen mode

Until then, the sample output below is the shape of a result.

The problem

Tutorials, docs, papers, and long articles pile up unread. Opening one means paying the whole reading cost before you know if it answers the question you saved it for.

tldr-everything cuts that cost into layers. Each layer is its own short model call, because the default model is…

MIT license. Python 3.10+. PyMuPDF for the PDF, a small Typer CLI (tldr), and a Streamlit UI. The model client is the OpenAI SDK pointed at any compatible endpoint, default http://localhost:11434/v1.

Tests never call the network. A fake client covers cleanup, chunk overlap, the injection guard, length retries, recursive reduce, scanned PDFs, and the "this document does not cover your goal" path.

How I Built It

The open-weight model is Qwen2.5-3B-Instruct, run locally with Ollama. The app talks to it through Ollama's OpenAI-compatible API, so LM Studio, vLLM, or a larger Qwen is a config change. llama3.2:3b is the other small option documented in the README.

The build is arranged around the fact that 3B is small:

  1. Each prompt in prompts.py has one job, three to six rules, one tiny example, and a plain-text format. Relevance comes back as a single line, SCORE: 0-5, parsed with a regex. Garbage input scores 0, so the chunk is dropped.
  2. Document text is wrapped in <document> tags and labeled untrusted. Literal tags inside the file are neutralized first, so a PDF cannot close the delimiter early.
  3. Map calls run a few at a time (LLM_CONCURRENCY defaults to 2). The CLI and the UI share a progress callback and an ETA from the latency actually observed.
  4. After generation, a post-processor strips "Sure! Here is..." and checks length. Outside a tolerant band, it retries once, then keeps the text and raises a warning badge.

PyMuPDF extracts text page by page. Scanned PDFs, which come back nearly empty, get a clear "OCR is not supported" message. Encrypted PDFs are refused. Cleanup de-hyphenates prose and leaves fenced and indented code alone.

Why Does Open Innovation Matter?

The whole point of the tool is unread private reading: papers, internal docs, a tutorial you would rather not upload. A closed API would mean sending that pile to someone else's server, and paying for every chunk. Here the default path is localhost. Logs record call type and timing, not the document. If the base URL is not local, the CLI and the UI say so before the run.

A small open-weight model also forced the design. I could not hide a sloppy prompt behind a huge context window. The Modelfile, the chunk size, the recursive reduce, and the grounding checks exist because Qwen2.5-3B will invent a plausible docker command if you let it. Those checks are ordinary Python. They keep working if you swap the model later.

It also costs nothing to run after the weights are on disk. The same pipeline that summarizes one saved article can sit on a laptop with no key and no meter.

The Lazy Payoff

The app reports both clocks on every run: minutes to read the source at 220 words per minute, and minutes to read the summary. A 4,000-word article is roughly 18 minutes. The 30-second layer is about 80 words, well under a minute, and it cites the page if you want to check a claim.

Top comments (0)