Compare commits
3
Commits
908dff74a7
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07abb86cab | ||
|
|
1635eed33b | ||
|
|
176b302680 |
@@ -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.
|
||||||
@@ -7,13 +7,37 @@
|
|||||||
Разбирать спецификации договоров и допников (docx/pdf) в структурированный вид,
|
Разбирать спецификации договоров и допников (docx/pdf) в структурированный вид,
|
||||||
отслеживать изменения между версиями, восстанавливать историю договора во времени.
|
отслеживать изменения между версиями, восстанавливать историю договора во времени.
|
||||||
|
|
||||||
## Состав
|
## Архитектура
|
||||||
|
|
||||||
|
Подробное описание архитектуры (компоненты, БД, event sourcing, загрузка через
|
||||||
|
ВМ-буфер, ZIP, конвейер сравнения) — см. **[`DOC/architecture-contracts-flask.md`](DOC/architecture-contracts-flask.md)**.
|
||||||
|
|
||||||
|
Ключевые моменты:
|
||||||
|
|
||||||
|
- **Основной сервис** — `contracts-flask/` (Flask + SQLite WAL, managed на Nubes).
|
||||||
|
- **Загрузка** — браузер PUT файла в ВМ-буфер (WebDAV), бэк сам тянет с ВМ
|
||||||
|
(managed-gateway рвёт тела > 64 КБ, egress ВМ без лимита).
|
||||||
|
- **ZIP** — раскрывается на клиенте (`expandZipClient` → `listZipFiles`).
|
||||||
|
- **Event sourcing** — `spec_events` (журнал) + `spec_current` (текущее состояние).
|
||||||
|
- **Сравнение** — `/process-v2` (SSE): LLM возвращает ops (ADD/UPDATE/DELETE/
|
||||||
|
UNRESOLVED), применяются через `apply_ops()`.
|
||||||
|
- **LLM** — только своя модель `gpt-oss-120b` (api.aillm.ru).
|
||||||
|
|
||||||
|
## Состав репозитория
|
||||||
|
|
||||||
| Папка | Что |
|
| Папка | Что |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `contracts-app/` | Flask-сервис (основной код) |
|
| `contracts-flask/` | Основной сервис (Flask + SQLite, managed на Nubes) |
|
||||||
|
| `contractor-legacy/` | Старый Lucee/CFML-сервис (архив) |
|
||||||
|
| `convert-service/` | Микросервис конвертации doc → docx |
|
||||||
|
| `DOC/` | Документация: архитектура, тестирование |
|
||||||
|
| `History/` | История решений, ревью, протоколы |
|
||||||
|
| `FILES/` | Заметки, ключи LLM, ТЗ |
|
||||||
| `dogovora/` | Примеры договоров и допников |
|
| `dogovora/` | Примеры договоров и допников |
|
||||||
| `FILES/` | Заметки, ключи LLM |
|
| `loadtest/` | Нагрузочное тестирование |
|
||||||
|
| `sim/` | Симуляция сценариев |
|
||||||
|
| `testgen/` | Генерация тестовых кейсов |
|
||||||
|
| `hz/` | Разные заметки |
|
||||||
|
|
||||||
## Конфиденциальность
|
## Конфиденциальность
|
||||||
|
|
||||||
|
|||||||
-1
Submodule contractor deleted from c56b980501
+1
-1
Submodule contracts-flask updated: 5b49e88f1e...87524c54a4
Reference in New Issue
Block a user