Files
contracts/History/llm-analysis/opus-plan-groups-progress.md
T

104 lines
7.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Запрос для 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`