Metadata-Version: 2.4
Name: trimitdown
Version: 0.1.0
Summary: Convert documents to LLM-ready markdown. Ruled-table-aware PDF extraction, offline, no cloud.
Author: Sergey Dreizin
License-Expression: MIT
Project-URL: Homepage, https://github.com/serjdrej/trimitdown
Project-URL: Repository, https://github.com/serjdrej/trimitdown
Project-URL: Issues, https://github.com/serjdrej/trimitdown/issues
Keywords: markdown,pdf,llm,document-conversion,cli
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Text Processing :: Markup :: Markdown
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: trimitdown-pdf==0.1.0
Requires-Dist: markitdown[docx,outlook,pdf,pptx,xls,xlsx]
Requires-Dist: tiktoken
Requires-Dist: python-pptx
Requires-Dist: pdfminer.six
Provides-Extra: server
Requires-Dist: fastapi; extra == "server"
Requires-Dist: uvicorn; extra == "server"
Requires-Dist: python-multipart; extra == "server"
Dynamic: license-file

<div align="center">

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="brand/wordmark_dark.svg">
  <img src="brand/wordmark_light.svg" alt="TrimItDown" width="360">
</picture>

**Any document → clean, LLM-ready Markdown. On your own server, on every device you own.**

*Read this in: English (this file) · [русский](README.ru.md)*

[![Latest release](https://img.shields.io/github/v/release/serjdrej/trimitdown)](https://github.com/serjdrej/trimitdown/releases/latest)
[![Downloads](https://img.shields.io/github/downloads/serjdrej/trimitdown/total)](https://github.com/serjdrej/trimitdown/releases)
[![macOS build](https://github.com/serjdrej/trimitdown/actions/workflows/build-macos.yml/badge.svg)](https://github.com/serjdrej/trimitdown/actions/workflows/build-macos.yml)
[![PyPI](https://img.shields.io/pypi/v/trimitdown-pdf?label=trimitdown-pdf&color=3775A9)](https://pypi.org/project/trimitdown-pdf/)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
![Platforms](https://img.shields.io/badge/platforms-iOS%20PWA%20·%20Windows%20·%20macOS%20·%20Docker-8A6FE8)

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="docs/images/result-dark.png">
  <img src="docs/images/result-light.png" alt="TrimItDown converting a PDF: live Markdown preview with a real table and a token counter" width="850">
</picture>

</div>

TrimItDown turns PDF, Word (docx), PowerPoint (pptx), Excel (xlsx/xls) and Outlook (.msg)
files into clean, readable Markdown — ready to paste into Claude/ChatGPT, Obsidian, Notion,
or any markdown vault. It runs as an iPhone/iPad app (installed straight from Safari, no App
Store), a portable Windows program, a macOS app, and a self-hosted Docker server — with one
shared archive of conversions across all your devices.

## The PDF engine

Most converters — including the stock [MarkItDown](https://github.com/microsoft/markitdown)
PDF path — stumble on real-world PDFs in three measurable ways: they **glue words together**,
**invent tables out of ordinary prose**, and **drop genuine ruled tables**. Measured over 891
real documents from two independent collections, the stock converter emitted 5,624 table rows
on documents containing no ruled grid at all — prose reshaped into tables — against 2 from the
engine below. On the 885 of those documents that are not broken at the source, it roughly
halves glued words (107 runs vs 53). Those corpora are third-party
copyrighted material and are not redistributable — the full method, the numbers, the cases
where this engine *loses*, and what a reader **can** reproduce are in
[docs/pdf-engine.md](docs/pdf-engine.md).

So TrimItDown replaced it with a custom extraction engine:

- **Words split at a measured word-gap threshold** — a fraction of the font size, not a fixed
  point value, so it holds across small print and large headings alike.
- **A dedicated table-detection stage** validates every candidate grid by how its cells are
  actually filled (a row-fill vote), instead of trusting every ruled rectangle. Diagrams and
  decorative frames get rejected; their text flows back into prose instead of vanishing.
- **Genuine ruled tables render as honest Markdown tables**, cell for cell.

Here is one document converted both ways. The file is committed to this repo, so you can run
the comparison yourself:

```bash
python scripts/compare_pdf_engines.py tests/data/sample-service-report.pdf
```

**Stock converter** — a phantom empty column splits the data, shifting every value one column
right of its header:

```markdown
| Parameter                 | Unit | Before service |     | After service | Limit |
| ------------------------- | ---- | -------------- | --- | ------------- | ----- |
| Supply airflow            | m³/h |                | 352 | 398           | ≥ 380 |
| Extract airflow           | m³/h |                | 341 | 402           | ≥ 380 |
| Filter pressure drop      | Pa   |                | 184 | 92            | ≤ 150 |
| Heat recovery efficiency  | %    |                | 61  | 78            | ≥ 70  |
| Motor current, supply fan | A    |                | 1.9 | 1.6           | ≤ 2.2 |
```

**TrimItDown** — the table as it appears on the page:

```markdown
| Parameter | Unit | Before service | After service | Limit |
| --- | --- | --- | --- | --- |
| Supply airflow | m³/h | 352 | 398 | ≥ 380 |
| Extract airflow | m³/h | 341 | 402 | ≥ 380 |
| Filter pressure drop | Pa | 184 | 92 | ≤ 150 |
| Heat recovery efficiency | % | 61 | 78 | ≥ 70 |
| Motor current, supply fan | A | 1.9 | 1.6 | ≤ 2.2 |
```

One sample proves nothing about a corpus, and ours is third-party material we cannot publish.
So the measurement ships instead of the documents — point it at your own PDFs and it runs both
converters over all of them and prints a comparable summary, counts only, no filenames:

```bash
python scripts/measure_corpus.py /path/to/your/pdfs --limit 50
```

**Please send that summary back whatever it says** — a win, a loss, or a tie
([issue template](https://github.com/serjdrej/trimitdown/issues/new?template=measurement.yml)).
Results collected only when something breaks are a sample made of breakage, and nothing
honest can be concluded from it. Pooled across enough corpora, these numbers stop being one
person's collection. Details in
[docs/pdf-engine.md](docs/pdf-engine.md#re-measuring-on-your-own-pdfs).

In short: we add the table-*validation* stage that the classic tabula-java pipeline has and
Python extractors lack, expressed as a cell-fill vote on pdfplumber's ruled grids, with
per-grid fallback to prose — no ML models, no cloud, small enough to ship inside a portable
binary. Every non-PDF format still goes through MarkItDown.

## Why TrimItDown

- **Made for the LLM workflow.** Clean Markdown out, a live preview, and a token counter that
  shows what a document will cost before you paste it into a model's context.
- **Your files never leave your infrastructure.** Conversion happens on your own server (home
  NAS, VPS) or fully offline on your computer. No third-party SaaS, no per-page fees.
- **One archive, every device.** Convert on your phone — the result is already on your
  computer, and vice versa. Searchable, with batch conversion and ZIP export.
- **A real app experience everywhere.** iPhone PWA installed from Safari (no App Store), a
  portable Windows exe, a macOS app. Russian and English UI, light/dark, two color themes.

## Get it

| Platform | How |
|---|---|
| **Windows** | Download `TrimItDown-windows-x64.exe` from [Releases](https://github.com/serjdrej/trimitdown/releases/latest) — portable, no install |
| **macOS** (Apple Silicon / Intel) | Download the matching `.zip` from [Releases](https://github.com/serjdrej/trimitdown/releases/latest), unzip, right-click → Open |
| **iPhone / iPad** | Served by your own Docker server — open it in Safari → Share → *Add to Home Screen* |
| **Docker server** | See [Self-hosting](#self-hosting) below |

The desktop apps work fully offline out of the box. Point them at your server in **Settings**
to get the shared archive.

## Command-line package

Run a conversion without installing anything permanently:

```bash
uvx trimitdown convert report.pdf > report.md
```

Or install it with `pip install trimitdown` and write directly to a file with
`trimitdown convert report.pdf -o report.md`. Without `-o`, Markdown goes to standard output.
The CLI works fully offline.

## Self-hosting

The Docker server is the source of truth: it converts, stores the shared archive, and serves
the iPhone PWA.

```bash
git clone https://github.com/serjdrej/trimitdown.git
cd trimitdown/docker-server
# one-time: generate a self-signed HTTPS certificate (copy-paste command in docker-server/README.md)
docker-compose up -d --build
```

Then open `https://YOUR_SERVER:8002`. Full instructions — certificate generation, trusting it
on iOS/Windows/macOS, and the API — in [`docker-server/README.en.md`](docker-server/README.en.md).

## Screenshots

| Archive, shared across devices | Settings |
|---|---|
| ![Archive with search](docs/images/archive-light.png) | ![Settings screen](docs/images/settings-dark.png) |

| Ocean theme, light | Ocean theme, dark |
|---|---|
| ![Ocean light theme](docs/images/home-ocean-light.png) | ![Ocean dark theme](docs/images/home-ocean-dark.png) |

| The iPhone PWA — home screen | Converting a PDF |
|---|---|
| <img src="docs/images/iphone-home-en.png" alt="TrimItDown PWA on iPhone, empty state" width="260"> | <img src="docs/images/iphone-result-en.png" alt="TrimItDown PWA on iPhone, conversion result" width="260"> |

## How it works

- **The Docker server** is a FastAPI service with HTTPS; the archive lives on the server. The
  same service serves the PWA for iPhone.
- **The Windows/macOS apps** check at startup whether your server is reachable: if yes, they
  open straight on it (shared archive); if not, they spin up a bundled local server and work
  fully offline. The shell is [pywebview](https://pywebview.flowrl.com/) (WebView2 / WKWebView),
  packaged with PyInstaller.
- **Conversion:** PDFs go through TrimItDown's own engine ([`trimitdown-pdf`](packages/trimitdown-pdf),
  built on pdfplumber); every other format goes through Microsoft's
  [MarkItDown](https://github.com/microsoft/markitdown).

## Repository layout

- [`src/trimitdown/`](src/trimitdown/) — published CLI package and conversion logic
- [`core/`](core/) — HTTP-layer and archive support for the desktop and server applications
- [`packages/trimitdown-pdf/`](packages/trimitdown-pdf/) — separately published PDF engine
- [`docker-server/`](docker-server/) — the self-hosted service + iPhone PWA
- [`static/`](static/), [`main.py`](main.py), [`server_app.py`](server_app.py) — desktop apps (UI, entry point, offline mode)
- [`tests/`](tests/) — unit tests + a labeled corpus harness for the table-detection stage
- [`docs/pdf-engine.md`](docs/pdf-engine.md) — PDF engine design, measurements, reproduction

## Contributing

Bug reports and PRs are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
[DEVELOPMENT.md](DEVELOPMENT.md) documents the dev setup and the desktop build internals.

## Limitations

- The server's self-signed HTTPS certificate needs a one-time manual trust on each device
  (iOS: profile + full trust; Windows: import into `CurrentUser\Root`; macOS: Keychain).
- The binaries aren't code-signed (no Apple/Microsoft developer certificate) — first launch
  needs a one-time override (macOS: right-click → Open; Windows: SmartScreen).

## License and credits

Code is [MIT](LICENSE). Non-PDF conversion is powered by
[MarkItDown](https://github.com/microsoft/markitdown) (Microsoft, MIT); the bundled
third-party licenses are listed in [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md).
