bloat2md
Превращает документ в markdown, который не стыдно положить в промпт. PDF, docx, xlsx, pptx, OpenDocument, rtf, html, epub, csv, json, yaml, xml, ipynb, картинки и zip — на выходе один markdown, а страницы, на которых текста нет, приезжают пережатыми jpeg.
Пакет — это две половины. bloat2md без экстры ставит только SDK: класс,
который умеет сходить в сервис по HTTP. bloat2md[server] добавляет парсеры и
сам сервис.
Установка
pip install bloat2md
pip install 'bloat2md[server]'
SDK
from bloat2md import Client
client = Client("http://bloat2md:8084", timeout=45.0)
rendered = await client.convert("report.pdf", raw)
if rendered is not None:
print(rendered.markdown)
convert не бросает: сервис лежит, документ не распознан, ответ невнятный —
везде None и запись в лог. Вызывающему остаётся решить, что делать с
документом, который прочитать не вышло, и это обычно «пропустить».
Rendered — это kind, markdown, images (список пар mime/bytes), pages,
truncated и dropped. Последнее — счётчики того, что выкинули по дороге:
hidden_nodes, hidden_spans, hidden_sheets, unsafe_names, bidi,
zero_width и прочее.
Сервис
bloat2md
POST /convert принимает файл как есть, application/octet-stream, имя — в
заголовке X-File-Name. Имя нужно только там, где по содержимому не отличить
csv от txt, а yaml от чего угодно.
| Код | Когда |
|---|---|
| 200 | markdown, картинки, счётчики |
| 413 | файл больше BLOAT2MD_INPUT_LIMIT_MB |
| 415 | это не документ |
| 422 | документ, но прочитать не вышло |
| 504 | воркер не уложился в BLOAT2MD_TIMEOUT |
GET /healthz отвечает {"status": "ok"} и не попадает в трейсы.
Песочница
Документ — чужой ввод, и парсеры у него на пути написаны не нами. Поэтому
конвертация уходит в дочерний процесс: своя сессия, свой TMPDIR, урезанное
окружение и RLIMIT_AS, RLIMIT_CPU, RLIMIT_FSIZE, RLIMIT_CORE. Воркер
общается с сервисом одним JSON через stdout, а по таймауту его группа процессов
получает SIGKILL.
Из этого следует, что MemoryError в парсере стоит одного запроса, а не пода.
Инъекции
Текст, которого человек в документе не увидит, до промпта не доходит: скрытые
css-ом узлы html, невидимый и микроскопический текст в pdf, спрятанные листы
xlsx. Bidi-управляющие символы, теги Unicode, нулевой ширины и длинные цепочки
joiner'ов вырезаются, а сколько чего вырезали — видно в dropped.
Zip не распаковывается, а описывается: имена и размеры. Архив с ratio выше
BLOAT2MD_MAX_ARCHIVE_RATIO отвергается целиком.
Настройки
Переменные окружения с префиксом BLOAT2MD_, читается и .env.
| Переменная | По умолчанию | Что делает |
|---|---|---|
HOST, PORT |
127.0.0.1, 8084 |
что слушать |
ENV |
prod |
окружение для трейсов |
TIMEOUT |
30 |
секунд на документ |
MEMORY_LIMIT_MB |
512 |
RLIMIT_AS воркера |
CPU_SECONDS |
20 |
RLIMIT_CPU воркера |
OUTPUT_LIMIT_MB |
64 |
RLIMIT_FSIZE воркера |
INPUT_LIMIT_MB |
20 |
больше — 413 |
MAX_PAGES |
50 |
страниц pdf читаем |
MAX_RENDER_PAGES |
10 |
страниц отдаём картинкой |
RENDER_EDGE |
1536 |
длинная сторона картинки |
RENDER_QUALITY |
80 |
jpeg |
MAX_MARKDOWN_CHARS |
200000 |
дальше режем с серединой |
MAX_IMAGE_PIXELS |
50000000 |
защита от decompression bomb |
MAX_ARCHIVE_MEMBERS |
2000 |
членов в архиве |
MAX_ARCHIVE_RATIO |
100 |
во сколько раз член вправе распухнуть |
MAX_ARCHIVE_BYTES |
104857600 |
суммарный размер после распаковки |
LIBREOFFICE |
true |
пускать ли soffice |
LibreOffice
Doc, xls, ppt и всё, на чём споткнулись питонячьи парсеры, уходят в
soffice --convert-to pdf, а дальше идут как pdf. Если бинаря нет, формат
просто становится неподдерживаемым — падать по этому поводу незачем.
Образ ghcr.io/wprhvso/bloat2md собирается с libreoffice-*-nogui внутри.
CI
Раннеры здесь ubuntu-latest, а не pool, как в остальных репозиториях.
Флот self-hosted раннеров разворачивается по списку реп в runners.toml, а тот
лежит зашифрованным в кластере — новый репозиторий в него сам собой не попадёт,
и job'ы висели бы в очереди вечно. Репозиторий публичный, GitHub считает его
минуты бесплатными, так что цена нулевая. Появится строка в runners.toml —
можно вернуть pool и убрать шаги установки uv и earthly.
cd собирает и публикует только тогда, когда версии в pyproject.toml ещё нет
тега: PyPI по trusted publishing, образ в ghcr, следом тег vX.Y.Z.
Пин образа по digest в deploy/bloat2md/deployment.yaml CD ставит сам: сразу
после пуша в ghcr он спрашивает у реестра digest тега и коммитит его в main.
Руками digest не резолвится и в манифесте не выдумывается никогда.
Лицензия
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file bloat2md-0.1.0.tar.gz.
File metadata
- Download URL: bloat2md-0.1.0.tar.gz
- Upload date:
- Size: 105.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df4f4499550d563e968baeea62d1984b9c778050f3d2bd302ad25d7faa905299
|
|
| MD5 |
40c4efd38d0b0c2df5477b604ff0270e
|
|
| BLAKE2b-256 |
b4fe5bfa2ad520dc36afab7309436d0c914729a377a786d52dfd53582e71ba2e
|
File details
Details for the file bloat2md-0.1.0-py3-none-any.whl.
File metadata
- Download URL: bloat2md-0.1.0-py3-none-any.whl
- Upload date:
- Size: 27.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.12.6 {"installer":{"name":"uv","version":"0.12.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
acc01be3d8a06028b0f2a2f3783a5f3ded58a046ca5eebe392da01fe2f4c49d6
|
|
| MD5 |
511229cb72458cb525b127add0b354a3
|
|
| BLAKE2b-256 |
a0b74c20cfc3f4a7dd604fee0b519b7e62a92d314f86f56c7f984a73ab8b01e6
|