8.7 KiB
8.7 KiB
Пайплайн обработки договора
Схема
┌─────────────────────────────────────────────────────────────────────┐
│ 👤 ПОЛЬЗОВАТЕЛЬ │
│ Открывает / → выбирает файлы → жмёт «Обработать» │
└──────────────────────────┬──────────────────────────────────────────┘
│ multipart/form-data (files)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ app.py: _upload_page() POST │
│ Принимает файлы, запускает пайплайн │
└──────────────────────────┬──────────────────────────────────────────┘
│
┌──────────────┼──────────────┐
▼ ▼ ▼
file.docx file.pdf file.zip
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────────┐
│ ① parser.py │
│ docx → python-docx → elements JSON │
│ pdf → pdfplumber → elements JSON │
│ doc → libreoffice → docx → python-docx │
│ zip → zipfile → каждый файл рекурсивно │
│ │
│ Выход: [{type:"paragraph", style, text}, {type:"table", rows}] │
│ НИЧЕГО не фильтрует, не теряет │
└──────────────────────────┬──────────────────────────────────────────┘
│ elements JSON
▼
┌─────────────────────────────────────────────────────────────────────┐
│ ② textify.py │
│ elements → линейный текст │
│ │
│ [No Spacing] Приложение № 1 │
│ [Heading 3] Состав и стоимость Услуг │
│ --- Таблица (9×6) --- │
│ | № | Наименование | Цена | Объем | Сумма | Дата | │
│ | 1 | Аренда стойко-места | 213 905 | 3 | 641 716 | 01.04.2026 | │
└──────────────────────────┬──────────────────────────────────────────┘
│ текст (строка)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ ③ extractor.py + llm_client.py │
│ текст → промпт → LLM (gpt-oss-120b) → JSON │
│ │
│ Промпт: «Найди таблицы услуг, извлеки строки в JSON» │
│ Ответ: [{"row_num":1, "name":"Аренда...", "price":213905, │
│ "qty":3, "sum":641716, "date_start":"2026-04-01"}, ...] │
└──────────────────────────┬──────────────────────────────────────────┘
│ строки спецификации
▼
┌─────────────────────────────────────────────────────────────────────┐
│ ④ differ.py │
│ Сравнение с предыдущим допником │
│ │
│ rows_old vs rows_new → changes: │
│ added: новая услуга │
│ changed: цена 213905 → 250000, дата 01.04 → 25.04 │
│ deleted: услуга убрана │
│ unchanged: без изменений │
└──────────────────────────┬──────────────────────────────────────────┘
│ изменения
▼
┌─────────────────────────────────────────────────────────────────────┐
│ ⑤ Сохранение в PostgreSQL │
│ │
│ documents ← исходный файл + распарсенный текст │
│ contracts ← договор │
│ supplements ← допник │
│ spec_rows ← строки спецификации │
│ spec_history ← история изменений │
└──────────────────────────┬──────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Ответ пользователю: HTML-страница с таблицей результатов │
│ «Извлечено 14 строк, добавлено 14, изменено 0, удалено 0» │
│ + полная таблица услуг с ценами │
└─────────────────────────────────────────────────────────────────────┘
Кратко
файлы → parser → textify → LLM → differ → PostgreSQL → HTML-страница
Слои
| # | Слой | Что делает |
|---|---|---|
| ① | parser.py |
docx/pdf/doc/zip → JSON |
| ② | textify.py |
JSON → текст |
| ③ | extractor.py + llm_client.py |
текст → LLM → строки |
| ④ | differ.py |
сравнение с предыдущим |
| ⑤ | db.py + schema.py |
сохранение в БД |
| — | app.py |
сборка, приём формы, отдача HTML |