🏗️ Архитектура — блок-схемы

1. Система — компоненты и связи

👤 Пользователь Браузер Загрузка файлов HTTPS SSE ⚡ Flask-фронтенд Managed Python (Nubes) Jinja2-шаблоны Промпт-редактор Чат с LLM REST API Выделенная VM 📄 Парсинг документов pdfplumber · python-docx 🏷️ Классификация 3-этапный фильтр мусора 🤖 LLM-сравнение extract + diff · группировка HTTP/2 🧠 LLM api.aillm.ru gpt-oss-120b 🗄️ PostgreSQL 15 JSONB · Event Sourcing · spec_events

2. Пайплайн обработки одного файла

📤 Загрузка Multipart-парсинг SHA-256 хеш Формат: pdf/docx/zip 🔍 Парсинг Извлечение текста Извлечение таблиц → elements_json 🏷️ Фильтр #1-#2 Имя файла → мусор? Заголовки → мусор? 0 токенов LLM мусор → стоп 🤖 Фильтр #3 — LLM Тип: договор/допник/ спецификация/мусор Номер, дата, контрагент мусор → стоп 📋 Группи- ровка По номерам договоров Срав- нение ADD UPDATE 🛡️ Защита: ZIP-бомба (500/500/100×) · Path traversal · Whitelist форматов · content_hash · UNRESOLVED · нормализация чисел/дат · price×qty=sum 📊 База: documents (метаданные + elements_json) · classify_results · spec_events (аудит) · spec_current (спецификация) · prompts (версионирование) Бинарные файлы удаляются после парсинга. Промежуточные данные — требуется автоочистка.

3. Event Sourcing — как работает сравнение

Документы группы (отсортированы по doc_date) 📄 Договор базовый 📄 Допник #1 📄 Допник #2 ... 🤖 LLM: промпт extract Извлечение всех услуг → массив ADD-операций 🗄️ spec_events ADD услуга X ADD услуга Y (неизменяемый лог) 📊 spec_current Услуга X | 100₽ | 10 шт Услуга Y | 200₽ | 5 шт 🤖 LLM: промпт diff (допник #1) vs spec_current → ADD / UPDATE / DELETE 🗄️ spec_events UPDATE услуга X DELETE услуга Y ADD услуга Z 📊 spec_current (обн.) Услуга X | 150₽ | 10 шт Услуга Z | 300₽ | 2 шт цикл по допникам Каждый допник сравнивается с актуальной spec_current → операции накапливаются в spec_events → spec_current пересчитывается

4. Защита — эшелоны

🔴 Уровень 1 — Загрузка: ZIP-бомба (500 файлов / 500MB / ratio 100×) · Path traversal · Whitelist .pdf .docx .doc .zip 🟠 Уровень 2 — Парсинг: cp437→utf8 для битых имён · content_hash (SHA-256) · дедупликация · try/except → logging.warning 🟡 Уровень 3 — Классификация: фильтр по имени файла · фильтр по заголовкам (2000 симв.) · LLM-фильтр · мусор → garbage 🟢 Уровень 4 — Сравнение: ADD без имени → UNRESOLVED · UPDATE/DELETE без цели → UNRESOLVED · нормализация 1 000,50→1000.50 · дат · price×qty=sum