# Запрос для 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`