Каталогизатор документов: разбор папки, тезисы, поиск, 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:
140
catalogizer/ui/theme.py
Normal file
140
catalogizer/ui/theme.py
Normal file
@@ -0,0 +1,140 @@
|
||||
"""@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; }
|
||||
"""
|
||||
Reference in New Issue
Block a user