doc: пайплайн обработки договора — полная схема
This commit is contained in:
@@ -0,0 +1,69 @@
|
|||||||
|
# Блок-схема сервиса Contracts
|
||||||
|
|
||||||
|
## Полный пайплайн обработки допника
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart TD
|
||||||
|
A["📄 POST /api/contracts/{id}/supplements\n(file.docx)"] --> B["💾 documents.original_bytes\n(status=uploaded)"]
|
||||||
|
B --> C["🔧 parser.parse()\nbytes → elements JSON"]
|
||||||
|
C --> D["📝 textify.to_text()\nelements → линейный текст"]
|
||||||
|
D --> E["📄 documents.parsed_text\n(status=parsed)"]
|
||||||
|
E --> F["🤖 extractor.extract()\nтекст → LLM → строки JSON"]
|
||||||
|
F --> G["📊 spec_rows\n(row_num, name, price, qty, sum, date)"]
|
||||||
|
G --> H["🔄 differ.diff()\nсравнение с пред. допником"]
|
||||||
|
H --> I["📋 spec_history\n(added/changed/deleted/unchanged)"]
|
||||||
|
I --> J["✅ ответ API\n{rows, diff_summary}"]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Архитектура слоёв
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
subgraph "Внешний мир"
|
||||||
|
USER["👤 Пользователь"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Flask"
|
||||||
|
APP["app.py\nсборка"]
|
||||||
|
API["api.py\n/contracts"]
|
||||||
|
UPL["upload.py\n/upload"]
|
||||||
|
TEST["test_routes.py\n/test"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Бизнес-логика"
|
||||||
|
PARSER["parser.py\nbytes→JSON"]
|
||||||
|
TEXTIFY["textify.py\nJSON→текст"]
|
||||||
|
LLM["llm_client.py\nHTTP/2→LLM"]
|
||||||
|
EXTRACT["extractor.py\nтекст→строки"]
|
||||||
|
DIFF["differ.py\nсравнение"]
|
||||||
|
end
|
||||||
|
|
||||||
|
subgraph "Данные"
|
||||||
|
DB["db.py\nconnect/query"]
|
||||||
|
SCH["schema.py\nDDL"]
|
||||||
|
PG[("PostgreSQL\n5 таблиц")]
|
||||||
|
end
|
||||||
|
|
||||||
|
USER -->|"POST docx"| API
|
||||||
|
USER -->|"GET /test"| TEST
|
||||||
|
API --> PARSER
|
||||||
|
PARSER --> TEXTIFY
|
||||||
|
TEXTIFY --> EXTRACT
|
||||||
|
EXTRACT --> LLM
|
||||||
|
EXTRACT --> DIFF
|
||||||
|
API --> DB
|
||||||
|
DB --> PG
|
||||||
|
APP --> SCH
|
||||||
|
SCH --> DB
|
||||||
|
```
|
||||||
|
|
||||||
|
## Цепочка данных
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
A["docx\n(байты)"] -->|parser| B["elements\nJSON"]
|
||||||
|
B -->|textify| C["текст\nстрока"]
|
||||||
|
C -->|extractor + LLM| D["spec_rows\nJSON"]
|
||||||
|
D -->|differ| E["changes\nJSON"]
|
||||||
|
E -->|api| F["ответ\nпользователю"]
|
||||||
|
```
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
# Пайплайн обработки договора
|
||||||
|
|
||||||
|
## Схема
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 👤 ПОЛЬЗОВАТЕЛЬ │
|
||||||
|
│ Открывает / → выбирает файлы → жмёт «Обработать» │
|
||||||
|
└──────────────────────────┬──────────────────────────────────────────┘
|
||||||
|
│ 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 |
|
||||||
Reference in New Issue
Block a user