docs: описание архитектуры contracts-flask + gitignore contractor-legacy; contracts-flask → v2.0.16 docs; удалён подмодуль contractor

This commit is contained in:
“Naeel”
2026-08-26 16:29:55 +03:00
parent 1635eed33b
commit 07abb86cab
4 changed files with 93 additions and 2 deletions
+1
View File
@@ -4,5 +4,6 @@ dogovora/
testgen/out/
testgen/out_100files/
contracts-flask/hz/
contractor-legacy/
llm.key
loadtest/
+91
View File
@@ -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)`.
Слои 34 (in-memory session) — НЕ используются в contracts.
Submodule contractor deleted from c56b980501
Submodule contracts-flask updated: ebdab731ff...87524c54a4