Каталогизатор документов: разбор папки, тезисы, поиск, GUI
Программа принимает папку с документами, извлекает из них текст и метаданные и строит каталог: краткое описание, тезисы и ключевые слова для каждого файла плюс поиск по всему собранному. Ядро: - extract: PDF, DJVU, DOC(X), RTF, ODT, CHM, EPUB, FB2, PPT(X), XLS(X), TXT; PDF передаётся MuPDF потоком в память (работают длинные пути) и ограничен по времени — повреждённый файл иначе чинится минутами; - summarize: экстрактивное реферирование по TF-IDF, посчитанному на самой библиотеке, с лёгким стеммером для русского и английского; - db: SQLite с полнотекстовым индексом FTS5, морфологический поиск с BM25; - scanner: инкрементальный многопоточный обход, счётчик попыток защищает от файла, обрывающего разбор; - report: автономный HTML с поиском, Markdown, JSON, CSV. Интерфейс: - окно PySide6 в тёмной теме: вкладки разбора и поиска, фоновый поток, карточка документа, правка своих ключевых слов; - командная строка: build, scan, analyze, report, search, show, tag, stats; - у каждой папки свой каталог, последняя обработанная запоминается. Сборка: scripts/build_exe.py даёт Catalogizer.exe в Windows и Catalogizer.app в macOS, иконки .ico и .icns рисуются кодом. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
254
README.md
Normal file
254
README.md
Normal file
@@ -0,0 +1,254 @@
|
||||
# Каталогизатор документов
|
||||
|
||||
Программа принимает папку с документами, разбирает её и строит каталог:
|
||||
для каждого файла — **краткое описание**, **тезисы** и **ключевые слова**,
|
||||
плюс **поиск по каталогу** — в окне программы, в командной строке и в
|
||||
автономной HTML-странице.
|
||||
|
||||
Всё работает локально: файлы только читаются, никаких обращений в сеть.
|
||||
|
||||
Программа работает в Windows, macOS и Linux — исходники одни и те же.
|
||||
|
||||
## Запуск
|
||||
|
||||
**Windows** — двойной щелчок по `CATALOG.bat` или `dist\Catalogizer.exe`.
|
||||
**macOS** — двойной щелчок по `CATALOG.command` или `dist/Catalogizer.app`.
|
||||
Ни Python, ни библиотек при этом не требуется.
|
||||
|
||||
**Из исходников** (любая система):
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
python catalog_gui.py
|
||||
```
|
||||
|
||||
## Окно программы
|
||||
|
||||
Две вкладки:
|
||||
|
||||
* **Разбор папки** — поле пути и «Обзор…», параметры (потоков чтения, страниц
|
||||
на документ, «перечитать всё заново»), кнопки «Построить каталог» и
|
||||
«Остановить», индикатор хода работы и журнал. Разбор идёт в фоновом потоке,
|
||||
окно не подвисает; остановка безопасна — разобранное уже в базе, следующий
|
||||
запуск продолжит с того же места.
|
||||
* **Каталог и поиск** — строка поиска, фильтры по формату, языку и разделу,
|
||||
таблица найденного и карточка документа с описанием, тезисами, ключевыми
|
||||
словами и фрагментом текста с подсветкой. Двойной щелчок открывает документ,
|
||||
«Показать в папке» — проводник на нём.
|
||||
|
||||
Кнопки «Пересобрать отчёты» и «Открыть HTML-каталог» — на вкладке разбора.
|
||||
|
||||
## Командная строка
|
||||
|
||||
Папка — обычный аргумент:
|
||||
|
||||
```bash
|
||||
python catalog.py build "E:\Yandex.Disk\литература"
|
||||
```
|
||||
|
||||
| Команда | Что делает |
|
||||
|---|---|
|
||||
| `gui [ПАПКА]` | графическое окно (то же, что запуск без аргументов) |
|
||||
| `scan ПАПКА` | обход папки, извлечение текста и метаданных в базу |
|
||||
| `analyze` | ключевые слова, тезисы и описания по всей библиотеке |
|
||||
| `report` | выгрузка `catalog.html`, `catalog.md`, `catalog.json`, `catalog.csv` |
|
||||
| `build ПАПКА` | полный цикл: `scan` + `analyze` + `report` |
|
||||
| `search ЗАПРОС` | поиск по каталогу |
|
||||
| `show ID\|ИМЯ` | карточка одного документа |
|
||||
| `tag ДОКУМЕНТ СЛОВА` | свои ключевые слова документа |
|
||||
| `stats` | сводка: форматы, разделы, частые темы |
|
||||
|
||||
Последняя обработанная папка запоминается, поэтому дальше путь можно не
|
||||
повторять: `python catalog.py search "инвертор"`. Обратиться к другому
|
||||
каталогу — ключ `-c`: `python catalog.py -c "D:\books" stats`.
|
||||
|
||||
У каждой папки своя база (`catalogs/<имя>-<хеш>.db`) и своя папка отчётов
|
||||
(`out/<имя>-<хеш>/`), каталоги разных папок не смешиваются.
|
||||
|
||||
Полезные ключи `scan`/`build`:
|
||||
|
||||
```bash
|
||||
python catalog.py scan --ext pdf djvu # только выбранные форматы
|
||||
python catalog.py scan --max-pages 40 # читать больше страниц из каждого файла
|
||||
python catalog.py scan --jobs 8 # потоков чтения: HDD 2-4, SSD 8-16
|
||||
python catalog.py scan --limit 50 # пробный прогон на 50 файлах
|
||||
python catalog.py scan --force # перечитать всё заново
|
||||
python catalog.py scan --retry-broken # снова попробовать «битые» файлы
|
||||
```
|
||||
|
||||
## Поиск
|
||||
|
||||
```bash
|
||||
python catalog.py search "инвертор"
|
||||
python catalog.py search "цифровая обработка сигналов" -n 30
|
||||
python catalog.py search stm32 dma --ext pdf
|
||||
python catalog.py search "операционный усилитель" --lang ru --year-from 2010
|
||||
python catalog.py search "\"частотное преобразование\"" # точная фраза
|
||||
python catalog.py search fpga -verilog # минус — исключить слово
|
||||
python catalog.py search can --section datasheet # только в разделе
|
||||
```
|
||||
|
||||
Поиск морфологический: слова приводятся к основе, поэтому «инвертор» находит
|
||||
«инверторы» и «инвертора». Ранжирование — BM25 с повышенным весом названия и
|
||||
ключевых слов; в выдаче показывается фрагмент текста с подсветкой.
|
||||
|
||||
## Свои ключевые слова
|
||||
|
||||
Кроме слов, вычисленных из текста, к любому документу можно добавить свои —
|
||||
рубрику, проект, пометку «нужное». Они полноправно участвуют в поиске и даже
|
||||
весят в нём больше вычисленных.
|
||||
|
||||
В окне: выбрать документ, вписать слова через запятую в строку «Свои
|
||||
ключевые слова» под карточкой и нажать «Сохранить» (или Enter, или Ctrl+S).
|
||||
При вводе подсказываются слова, уже заведённые в этом каталоге.
|
||||
|
||||
В командной строке:
|
||||
|
||||
```bash
|
||||
python catalog.py tag opamp "силовая электроника, к проекту А" # добавить
|
||||
python catalog.py tag 137 --remove "к проекту А" # убрать
|
||||
python catalog.py tag 137 --set "только это" # заменить список
|
||||
python catalog.py tag 137 --set # очистить
|
||||
python catalog.py tag 137 # показать
|
||||
python catalog.py tag --all # все слова каталога
|
||||
python catalog.py search "к проекту А" # найти помеченные
|
||||
```
|
||||
|
||||
Документ указывается номером `id` или частью имени, пути либо названия.
|
||||
|
||||
Слова хранятся отдельно от результатов разбора и привязаны к пути файла,
|
||||
поэтому переживают повторный разбор папки и перестроение каталога. В отчёты
|
||||
они попадают отдельной строкой («Свои ключевые слова»), в HTML-каталоге
|
||||
выделены цветом, в CSV — отдельной колонкой.
|
||||
|
||||
## Отчёты
|
||||
|
||||
После `report` в папке `out/`:
|
||||
|
||||
* **`catalog.html`** — автономная страница: поиск по мере ввода, фильтры,
|
||||
тезисы и ключевые слова у каждого документа, ссылки на файлы. Открывается
|
||||
двойным щелчком, без сервера;
|
||||
* `catalog.md` — каталог по разделам для чтения и печати;
|
||||
* `catalog.json`, `catalog.csv` — выгрузка для других программ (CSV с BOM,
|
||||
открывается в Excel).
|
||||
|
||||
## Как строятся описания и тезисы
|
||||
|
||||
Реферирование экстрактивное — фразы берутся из самого документа, ничего не
|
||||
досочиняется:
|
||||
|
||||
1. из файла читаются первые `--max-pages` страниц, оглавление и метаданные;
|
||||
2. слова приводятся к основе (лёгкий стеммер для русского и английского),
|
||||
считаются частоты; слова из названия и оглавления получают больший вес;
|
||||
3. по всей библиотеке считается IDF — так отсеиваются слова, общие для всей
|
||||
техлитературы, и остаются характерные именно для этого документа;
|
||||
4. **ключевые слова** — верхние основы по TF-IDF, показанные самой короткой
|
||||
частой словоформой;
|
||||
5. **тезисы** — предложения с наибольшей плотностью ключевых слов, с бонусом
|
||||
началу документа (аннотация, введение) и оборотам вида «рассматривается»,
|
||||
«предназначено», `this book describes`; близкие по составу фразы отбрасываются;
|
||||
6. **описание** — тип издания, язык, объём, темы и первый тезис.
|
||||
|
||||
Для сканов без текстового слоя тезисы берутся из оглавления PDF, а если его
|
||||
нет — документ попадает в каталог с пометкой «скан» и описанием по имени файла.
|
||||
Найти такие файлы: `python catalog.py stats`.
|
||||
|
||||
## Форматы и внешние утилиты
|
||||
|
||||
Разбираются PDF, DJVU, DOC, DOCX, RTF, ODT, CHM, EPUB, FB2, PPT, PPTX, XLS,
|
||||
XLSX, TXT, MD. Обязательна только `pymupdf` (PDF); дополнительно, если есть
|
||||
в PATH:
|
||||
|
||||
* `antiword` — качественный разбор старых `.doc` (иначе грубая выборка строк);
|
||||
* `djvutxt` из DjVuLibre — текстовый слой `.djvu` (иначе для DJVU остаются
|
||||
только название, число страниц и раздел).
|
||||
|
||||
## Сборка исполняемого файла
|
||||
|
||||
Сборщик один — `scripts/build_exe.py`; что получится, зависит от системы,
|
||||
**на которой идёт сборка**: PyInstaller не умеет собирать под чужую
|
||||
платформу. Программу для macOS собирают на Mac, для Windows — на Windows.
|
||||
|
||||
**Windows** → `dist\Catalogizer.exe`:
|
||||
|
||||
```bash
|
||||
BUILD_EXE.bat --setup # один раз: .venv с PySide6, pymupdf, PyInstaller
|
||||
BUILD_EXE.bat # сборка
|
||||
```
|
||||
|
||||
**macOS** → `dist/Catalogizer.app`:
|
||||
|
||||
```bash
|
||||
chmod +x BUILD_APP.command CATALOG.command # один раз, после переноса файлов
|
||||
./BUILD_APP.command --setup # один раз: .venv и зависимости
|
||||
./BUILD_APP.command # сборка
|
||||
```
|
||||
|
||||
Оба сценария можно просто запустить двойным щелчком. Ключи передаются в
|
||||
`scripts/build_exe.py`: `--onedir` (папка вместо одного файла, запускается
|
||||
быстрее; в macOS так всегда — `.app` и есть папка), `--console` (оставить
|
||||
консоль для traceback), `--cli` (собрать ещё и консольную программу
|
||||
`catalog`). После сборки автоматически выполняется самопроверка `--check`:
|
||||
окно строится целиком и программа выходит.
|
||||
|
||||
Иконки генерируются кодом — `python scripts/make_icon.py` создаёт
|
||||
`ico/catalog.ico` для Windows и `ico/catalog.icns` для macOS.
|
||||
|
||||
Куда программа кладёт базы и отчёты: в Windows и Linux — **рядом с
|
||||
исполняемым файлом**, в macOS — в `~/Library/Application Support/Catalogizer`,
|
||||
потому что содержимое `.app` считается неизменяемым.
|
||||
|
||||
### Что учтено для macOS
|
||||
|
||||
* пути и `\?\`-префикс применяются только в Windows;
|
||||
* «Показать в папке» открывает Finder на файле (`open -R`), «Открыть
|
||||
документ» — `open`;
|
||||
* ссылки на файлы в HTML-каталоге строятся из абсолютного пути и работают
|
||||
и с `/Users/...`, и с `E:\...`;
|
||||
* в теме заданы системные шрифты (`SF Pro Text`, `SF Mono`) как замена
|
||||
windows-овским;
|
||||
* папка по умолчанию — `~/Documents`, если жёстко прописанной библиотеки нет;
|
||||
* `.command`-файлы сохранены с переводами строк LF, иначе bash их не примет.
|
||||
|
||||
Первый запуск неподписанного `.app` macOS блокирует: правой кнопкой по
|
||||
`Catalogizer.app` → «Открыть» → «Открыть» в диалоге. Либо снять карантин:
|
||||
`xattr -dr com.apple.quarantine dist/Catalogizer.app`.
|
||||
|
||||
## Устройство
|
||||
|
||||
```
|
||||
CATALOG.bat запуск окна в Windows
|
||||
CATALOG.command запуск окна в macOS
|
||||
BUILD_EXE.bat сборка exe в Windows
|
||||
BUILD_APP.command сборка .app в macOS
|
||||
catalog_gui.py точка входа окна (её упаковывает PyInstaller)
|
||||
catalog.py точка входа командной строки
|
||||
catalogizer/
|
||||
app.py сборка QApplication, ключ --check
|
||||
config.py папка по умолчанию, форматы, ограничения разбора
|
||||
extract.py чтение PDF, DJVU, DOC(X), RTF, CHM, EPUB, FB2, XLS(X), TXT
|
||||
textutil.py язык, токенизация, стемминг, разбиение на предложения
|
||||
summarize.py TF-IDF, ключевые слова, тезисы, описание
|
||||
scanner.py обход папки, многопоточное извлечение
|
||||
analyze.py проход анализа по всей базе
|
||||
search.py запросы к полнотекстовому индексу
|
||||
report.py HTML, Markdown, JSON, CSV
|
||||
db.py SQLite + FTS5
|
||||
ui/ тёмная тема, главное окно, вкладки, фоновый поток
|
||||
scripts/build_exe.py сборка exe/.app — под ту систему, где запущен
|
||||
scripts/make_icon.py генерация иконок .ico и .icns
|
||||
```
|
||||
|
||||
## Замечания по работе
|
||||
|
||||
* Файлы длиннее 260 символов пути читаются через префикс `\\?\`; PDF
|
||||
передаются MuPDF потоком в память, поэтому нестандартные пути не мешают.
|
||||
* Кодировка русских `.txt` определяется перебором (utf-8, cp1251, koi8-r, cp866).
|
||||
* Разбор одного PDF ограничен по времени (`PDF_TIME_BUDGET`, 25 с):
|
||||
повреждённый файл MuPDF чинит страницу за страницей и может занять минуты.
|
||||
* Сбой на файле не останавливает обход: причина сохраняется в поле `error`
|
||||
и видна в `stats`. Файл, трижды оборвавший разбор, дальше пропускается —
|
||||
вернуть его в очередь можно ключом `--retry-broken`.
|
||||
* Если папка лежит под управлением клиента синхронизации (Яндекс.Диск,
|
||||
OneDrive), его драйвер может надолго придерживать открытые файлы. На время
|
||||
первого разбора синхронизацию лучше приостановить.
|
||||
Reference in New Issue
Block a user