# Каталогизатор документов Программа принимает папку с документами, разбирает её и строит каталог: для каждого файла — **краткое описание**, **тезисы** и **ключевые слова**, плюс **поиск по каталогу** — в окне программы, в командной строке и в автономной 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), его драйвер может надолго придерживать открытые файлы. На время первого разбора синхронизацию лучше приостановить.