v1.0.177: submodule bump + History docs (Opus, Sonnet audit, auto-classify)

This commit is contained in:
“Naeel”
2026-06-24 19:41:46 +04:00
parent d960e2cdfc
commit af1fed1077
10 changed files with 592 additions and 1 deletions
+103
View File
@@ -0,0 +1,103 @@
# Запрос для Opus — План: группировка, прогресс, промежуточные результаты
## Что сказал заказчик (дословно)
> Не распознано (8 файлов)
> [supplement] допник-1-XXX002-01200_3.docx ... — нет базового договора №01219_3
> ...
> зачем нам базовый договор? Вся информация есть в допниках и спеках
> Было бы хорошо пояснить или показать процесс, что в каком порядке происходит. Так видно только текущую операцию
> наверно я захочу иметь возможность посмотреть любые промежуточные результаты
## Что нужно
Заказчик хочет три улучшения (без фанатизма, главное — устойчивость и понятный UI):
### #1 — Группировка без базовых договоров
**Проблема:** сейчас `group_documents()` требует contract-файл как якорь группы. Без него допники/спеки попадают в unresolved с текстом «нет базового договора №X». Заказчик: «зачем нам базовый договор? Вся информация есть в допниках и спеках».
**Нужно:** группировать документы по `parent_number` / `own_number`, даже если contract-файл отсутствует в загрузке. Создавать «виртуальную» группу без contract-файла.
**Вопросы:**
1. Алгоритм: что приоритетнее — `parent_number` от допника или `own_number` от спеки? Если оба ссылаются на один нормализованный номер — это одна группа?
2. Если два допника с одним `parent_number`, но разными `counterparty` — одна группа или разные?
3. Как назвать группу без contract-файла: `"№01300_2 — ЗАО XXX003"` из данных классификации? Достаточно?
4. Минимальный diff в `group_documents()` — чтобы не сломать текущую логику с contract-файлами?
### #2 — Прогресс пайплайна
**Проблема:** юзер видит только статус текущей операции. Непонятно что уже сделано, что предстоит.
**Нужно:** визуальная шкала этапов с иконками статуса.
**Вопросы:**
1. Достаточно 4 этапов: Загрузка → Классификация → Группировка → Сравнение? (Парсинг — подэтап загрузки, не показывать отдельно)
2. Где разместить: в топбаре (всегда видно, не скроллится) или в карточке с результатами?
3. При переклассификации после удаления/добавления файла — сбрасывать всю шкалу или только затрагиваемые этапы?
### #3 — Промежуточные результаты
**Проблема:** юзер хочет видеть что LLM вернула на каждом шаге: сырой ответ, как определился номер/тип/дата.
**Нужно:** раскрывающийся блок с деталями для каждого файла.
**Вопросы:**
1. Что хранить: сырой ответ LLM + распарсенный JSON? Достаточно двух новых полей в `documents`?
2. Где показывать: раскрывающийся блок под строкой файла в таблице? Или модалка при клике на статус?
3. Нужно ли для сравнения (process-v2 SSE) или только для классификации?
### #4 — Общие ограничения
Что из трёх самое трудозатратное и что можно упростить без потери юзабилити?
---
## Релевантные файлы (читать)
### Группировка (#1)
- `contractor/deploy/services/grouping.py` — `group_documents()`, `normalize_number()`, `apply_groups()`
- `contractor/deploy/db/documents.py` — поля `doc_type`, `own_number`, `parent_number`, `counterparty`, `classify_status`
- `contractor/deploy/db/contracts.py` — `insert()`, поля `number`, `client`
- `contractor/deploy/db/supplements.py` — `insert()`, `list_by_contract()`
### Прогресс-бар (#2) + Промежуточные результаты (#3)
- `contractor/index.cfm` — HTML-оболочка, топбар (`.topbar`, `position: sticky`), карточки, модалки
- `contractor/deploy/app.js` — весь фронтенд: загрузка, `runClassify()`, `loadGroups()`, `runCompareForGroup()`, `showClassifyBtn()`, рендеринг таблицы и групп
- `contractor/deploy/app_utils.js` — утилиты: `removeFile()`, `renderTable()`
- `contractor/deploy/convert_server.py` — роутер (`do_GET`, `do_POST`, `do_DELETE`), SSE (`_handle_process_v2`), эндпоинты `/api/classify-batch`, `/api/groups`, `/api/batch-progress`, `/api/sync`
### Общий контекст
- `contractor/deploy/services/classify.py` — `classify_batch()`, `_smart_extract()`, `_call_llm_classify()`, `_safe_json_parse()`
- `contractor/deploy/services/process.py` — `run_pipeline()` (SSE для сравнения: extract/diff)
- `contractor/deploy/services/grouping.py` — `group_documents()`, `apply_groups()`
- `contractor/deploy/llm_prompt.py` — `build_prompt()`, `build_classify_prompt()`
- `contractor/deploy/db/connection.py` — `query()`, `execute()`, `execute_returning()`
---
## Игнорировать (не относится к делу)
- `contracts-app/` — старый Python-бэкенд (Flask), не используется
- `contracts-vm/` — старые конфиги ВМ
- `DOC/`, `FILES/` — документация, заметки
- `dogovora/` — тестовые файлы договоров
- `history/`, `History/` — старые сессионные заметки (кроме этого файла)
- `contractor/*.cfm` кроме `index.cfm` — старый Lucee-код, не используется
- `contractor/deploy/nginx-contracts.conf` — конфиг nginx
- `contractor/deploy/convert_doc.py` — конвертер .doc → .docx
- `contractor/deploy/sync.sh` — скрипт деплоя
- `contractor/upload.cfm`, `contractor/process.cfm`, `contractor/parser.cfm` и т.д. — старый Lucee-код
---
## Архитектура (кратко)
- **Фронт:** `index.cfm` (Lucee, только HTML-оболочка) → грузит `app.js` + `app_utils.js` с ВМ (`https://contracts.kube5s.ru/static/`)
- **Бэкенд:** Python 3.12 `http.server` + `ThreadingMixIn` на ВМ (5.172.178.213), порт 8766, systemd-сервис `contracts`
- **Все endpoint'ы:** в `convert_server.py` (один файл-роутер, ~400 строк)
- **БД:** PostgreSQL 16, прямой доступ через `psycopg2`, connection pool
- **Таблицы:** `documents`, `supplements`, `contracts`, `spec_events`, `spec_current`, `prompts`
- **LLM:** gpt-oss-120b через `api.aillm.ru`, httpx с http2, `temperature=0.1`, `max_tokens=8000`