docs: описание архитектуры contracts-flask + gitignore contractor-legacy; contracts-flask → v2.0.16 docs; удалён подмодуль contractor
This commit is contained in:
@@ -4,5 +4,6 @@ dogovora/
|
|||||||
testgen/out/
|
testgen/out/
|
||||||
testgen/out_100files/
|
testgen/out_100files/
|
||||||
contracts-flask/hz/
|
contracts-flask/hz/
|
||||||
|
contractor-legacy/
|
||||||
llm.key
|
llm.key
|
||||||
loadtest/
|
loadtest/
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# Архитектура contracts-flask (актуально на v2.0.16)
|
||||||
|
|
||||||
|
Сервис сверки договоров. Flask + vanilla JS (без frontend-фреймворков).
|
||||||
|
Managed на Nubes (Штурвал), redeploy через панель (не kubectl).
|
||||||
|
|
||||||
|
## Компоненты
|
||||||
|
|
||||||
|
```
|
||||||
|
Браузер (vanilla JS: files.js, compare.js, app.js)
|
||||||
|
│
|
||||||
|
├─ PUT файла → ВМ-буфер (WebDAV /contracts-upload/)
|
||||||
|
│ Браузер кладёт файл на ВМ, т.к. managed-gateway рвёт тело >64 КБ.
|
||||||
|
│ ВМ: 5.172.178.213, домен contracts.kube5s.ru.
|
||||||
|
│
|
||||||
|
├─ /, /static/*, /templates/* → Managed Flask
|
||||||
|
│ Отдаёт HTML + JS.
|
||||||
|
│
|
||||||
|
└─ API (SQLite, WAL) → LLM (api.aillm.ru, gpt-oss-120b)
|
||||||
|
/api/upload_refs — бэк сам тянет файл с ВМ (egress не лимитирован)
|
||||||
|
/process-v2 (SSE) — конвейер сравнения
|
||||||
|
/api/classify-* — классификация
|
||||||
|
/chat — чат по спецификации
|
||||||
|
```
|
||||||
|
|
||||||
|
## БД
|
||||||
|
|
||||||
|
- **SQLite**, WAL-режим, `/tmp/contracts.db`.
|
||||||
|
- Thread-local соединения (`db/connection.py`), API совместим с PostgreSQL
|
||||||
|
через `_pg_to_sqlite()`.
|
||||||
|
- Таблицы: `documents`, `supplements`, `spec_current`, `spec_events`,
|
||||||
|
`prompts`, `upload_chunks`.
|
||||||
|
|
||||||
|
## Event sourcing (спецификация)
|
||||||
|
|
||||||
|
- `spec_events` — append-only журнал операций (история).
|
||||||
|
- `spec_current` — материализованное текущее состояние (для рендера/сравнения).
|
||||||
|
- `_hash(name, date_start)` = sha256(name.strip().lower() + "|" + normalize_date)[:16] — ключ строки.
|
||||||
|
- `apply_ops()` обрабатывает ADD / UPDATE / DELETE / UNRESOLVED.
|
||||||
|
|
||||||
|
## Загрузка файлов
|
||||||
|
|
||||||
|
1. `uploadFile()` (files.js) — браузер PUT файла в ВМ-буфер (WebDAV).
|
||||||
|
2. `POST /api/upload_refs {files:[{name,size,url}]}` — бэк тянет файл с ВМ
|
||||||
|
по `url` (egress без лимита), конвертирует `.doc` → `.docx`
|
||||||
|
(`contracts_upload_sink`), парсит и кладёт в БД.
|
||||||
|
3. Парсинг: pdfplumber / python-docx → `elements_json`.
|
||||||
|
|
||||||
|
## ZIP (важно: клиентское раскрытие)
|
||||||
|
|
||||||
|
⚠️ ZIP раскрывается **на клиенте**, НЕ серверным `/unzip-upload` (тот — legacy).
|
||||||
|
|
||||||
|
- `expandZipClient(f)` (files.js) — рекурсивно раскрывает архив через
|
||||||
|
`window.listZipFiles` (endpoint drhider, подтянут в браузере).
|
||||||
|
- Каждый вложенный файл получает `zip_source = имя архива` для группировки
|
||||||
|
в таблице.
|
||||||
|
- Fallback: если раскрыть не удалось — архив кладётся как есть.
|
||||||
|
- Фильтр вложений: `.pdf`, `.doc`, `.docx`.
|
||||||
|
|
||||||
|
## Сравнение (`/process-v2`, SSE)
|
||||||
|
|
||||||
|
1. `run_pipeline()` шлёт SSE-события браузеру.
|
||||||
|
2. Текущая спецификация → текст → LLM → `{mode, ops[]}`.
|
||||||
|
3. **Трансляция `target_id` → `target_hash`**: LLM возвращает `target_id: "r1"`
|
||||||
|
(индекс строки), а `apply_ops()` читает `target_hash`. Без трансляции
|
||||||
|
UPDATE/DELETE уходили бы в UNRESOLVED.
|
||||||
|
4. `apply_ops()` пишет `spec_events` + обновляет `spec_current`.
|
||||||
|
|
||||||
|
### Режимы LLM
|
||||||
|
|
||||||
|
- `partial` — точечные ADD/UPDATE/DELETE (UPDATE/DELETE по `target_hash`).
|
||||||
|
- `full_replace` — LLM возвращает полную новую редакцию (все ADD).
|
||||||
|
⚠️ Перед применением очищается **только** `spec_current` (`clear_current()`),
|
||||||
|
чтобы ADD-строки новой редакции не дублировали старые. История
|
||||||
|
`spec_events` сохраняется.
|
||||||
|
|
||||||
|
## Классификация
|
||||||
|
|
||||||
|
- `api.aillm.ru`, модель `gpt-oss-120b` (конфиденциальные данные — только своя модель).
|
||||||
|
- `ThreadPoolExecutor(max_workers=4)`.
|
||||||
|
- Поля: `doc_type`, `own_number`, `parent_number`, `counterparty`, `doc_date`.
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
`site/config.py`: VERSION, LLM_URL/KEY/MODEL, CONVERT_SERVICE_URL,
|
||||||
|
VM_UPLOAD_URL/VM_UPLOAD_PREFIX/VM_UPLOAD_MAX_BYTES (50 МБ), PULL_RETRIES (3).
|
||||||
|
|
||||||
|
## Модуль `upload/`
|
||||||
|
|
||||||
|
Переиспользован из drhider (слои 1–2). Плаг-ин через `sink`:
|
||||||
|
`create_upload_refs_blueprint(cfg, sink=contracts_upload_sink)`.
|
||||||
|
Слои 3–4 (in-memory session) — НЕ используются в contracts.
|
||||||
-1
Submodule contractor deleted from c56b980501
+1
-1
Submodule contracts-flask updated: ebdab731ff...87524c54a4
Reference in New Issue
Block a user