Программа принимает папку с документами, извлекает из них текст и метаданные и строит каталог: краткое описание, тезисы и ключевые слова для каждого файла плюс поиск по всему собранному. Ядро: - 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>
141 lines
3.8 KiB
Python
141 lines
3.8 KiB
Python
"""@file theme.py
|
||
@brief Единая спокойная тёмная тема каталогизатора без внешних ресурсов.
|
||
|
||
Палитра и правила оформления совпадают со стилем SETGUI, чтобы обе
|
||
программы выглядели частями одного инструментария.
|
||
"""
|
||
|
||
APP_STYLESHEET = """
|
||
QWidget {
|
||
background: #10151d;
|
||
color: #dce6f2;
|
||
font-family: "Segoe UI", "SF Pro Text", "Helvetica Neue", "Noto Sans",
|
||
sans-serif;
|
||
font-size: 10pt;
|
||
}
|
||
QMainWindow { background: #0d1219; }
|
||
QFrame#header {
|
||
background: #151d28;
|
||
border-bottom: 1px solid #263345;
|
||
}
|
||
QFrame[panel="true"] {
|
||
background: #151d28;
|
||
border: 1px solid #263345;
|
||
border-radius: 8px;
|
||
}
|
||
QLabel[muted="true"] { color: #8291a5; }
|
||
QLabel[title="true"] {
|
||
color: #f4f8fc;
|
||
font-size: 15pt;
|
||
font-weight: 600;
|
||
}
|
||
QLabel[section="true"] {
|
||
color: #f4f8fc;
|
||
font-size: 11pt;
|
||
font-weight: 600;
|
||
}
|
||
QPushButton {
|
||
background: #243247;
|
||
border: 1px solid #344762;
|
||
border-radius: 5px;
|
||
padding: 7px 14px;
|
||
}
|
||
QPushButton:hover { background: #2d405b; }
|
||
QPushButton:pressed { background: #1c293b; }
|
||
QPushButton:disabled { color: #627086; background: #192230; }
|
||
QPushButton[primary="true"] {
|
||
background: #1570d8;
|
||
border-color: #2584ec;
|
||
font-weight: 600;
|
||
}
|
||
QPushButton[primary="true"]:hover { background: #2584ec; }
|
||
QLineEdit, QComboBox, QSpinBox, QDoubleSpinBox {
|
||
background: #0d131c;
|
||
border: 1px solid #34445a;
|
||
border-radius: 5px;
|
||
padding: 6px;
|
||
selection-background-color: #1570d8;
|
||
}
|
||
QComboBox::drop-down { border: 0; width: 24px; }
|
||
QComboBox QAbstractItemView {
|
||
background: #0d131c;
|
||
border: 1px solid #34445a;
|
||
selection-background-color: #1570d8;
|
||
}
|
||
QTabWidget::pane {
|
||
border: 1px solid #263345;
|
||
background: #10151d;
|
||
}
|
||
QTabBar::tab {
|
||
background: #151d28;
|
||
color: #91a0b4;
|
||
border: 1px solid #263345;
|
||
padding: 9px 15px;
|
||
}
|
||
QTabBar::tab:selected {
|
||
color: #ffffff;
|
||
background: #1c2838;
|
||
border-bottom: 2px solid #2f91ff;
|
||
}
|
||
QHeaderView::section {
|
||
background: #1b2635;
|
||
color: #b9c5d5;
|
||
border: 0;
|
||
border-right: 1px solid #2b394c;
|
||
padding: 6px;
|
||
}
|
||
QTableWidget, QTreeWidget {
|
||
background: #0d131c;
|
||
alternate-background-color: #111a25;
|
||
gridline-color: #263345;
|
||
border: 1px solid #263345;
|
||
selection-background-color: #1570d8;
|
||
selection-color: #ffffff;
|
||
}
|
||
QTextBrowser, QPlainTextEdit {
|
||
background: #090e14;
|
||
color: #aabbd0;
|
||
border: 1px solid #263345;
|
||
font-family: "Cascadia Mono", "SF Mono", Menlo, "DejaVu Sans Mono",
|
||
monospace;
|
||
font-size: 9pt;
|
||
}
|
||
QProgressBar {
|
||
background: #0d131c;
|
||
border: 1px solid #34445a;
|
||
border-radius: 5px;
|
||
text-align: center;
|
||
}
|
||
QProgressBar::chunk { background: #1570d8; border-radius: 4px; }
|
||
QScrollBar:vertical {
|
||
background: #10151d;
|
||
width: 11px;
|
||
margin: 0;
|
||
}
|
||
QScrollBar::handle:vertical {
|
||
background: #34445a;
|
||
min-height: 24px;
|
||
border-radius: 5px;
|
||
}
|
||
QSplitter::handle { background: #1b2635; }
|
||
QStatusBar { background: #151d28; color: #8291a5; }
|
||
"""
|
||
|
||
#: Цвета карточки документа: HTML-разметка QTextBrowser темы не наследует.
|
||
CARD_CSS = """
|
||
body { color: #dce6f2;
|
||
font-family: "Segoe UI", "SF Pro Text", "Helvetica Neue", sans-serif;
|
||
font-size: 10pt; }
|
||
h2 { color: #f4f8fc; font-size: 12pt; margin: 0 0 4px 0; }
|
||
.facts { color: #8291a5; font-size: 9pt; margin-bottom: 10px; }
|
||
.desc { margin-bottom: 10px; }
|
||
.label { color: #2f91ff; font-weight: 600; }
|
||
li { margin-bottom: 4px; }
|
||
.kw { color: #b9c5d5; }
|
||
.mine { color: #2f91ff; font-weight: 600; }
|
||
.path { color: #627086;
|
||
font-family: "Cascadia Mono", "SF Mono", Menlo, monospace;
|
||
font-size: 8pt; }
|
||
mark { background: #1570d8; color: #ffffff; }
|
||
"""
|