# Анализ ответа Опуса — zip_source, UI-режимы, промпты Дата: 26.06.2025 | Ответ на [opus-request-zip-plan.md](../Files/opus-request-zip-plan.md) --- ## 1. Оценка ответа в целом **Качество: высокое.** Опус прочитал реальный код, разобрался в архитектуре, дал конкретные диффы по слоям. Не «размышления вообще», а точные строки и функции. 95% рекомендаций — правильные. **Что упущено:** - Lucee-слой (`upload.cfm`, `api.cfm`) — тоже участвует в upload, но Опус его не проанализировал - `confidence` — предлагает сохранять в БД, но не говорит где именно брать (LLM возвращает? парсить из промпта?) - Порог 100 файлов для «Потока» — спорный, обсудим ниже --- ## 2. По пунктам ### 2.1. `zip_source` — ✅ СОГЛАСЕН полностью План по слоям правильный. Ключевые моменты: - **`zip_source` не участвует в classify/group/compare** — верно. Чисто визуальный атрибут. - **Формат: имя ZIP с расширением** — да, `«Ромашка.zip»`. - **PK не трогаем (UUID)**, «ID = zip/filename» только для отображения — верно. - **Дедупликация по паре `(zip_source, name)`** — ⚠️ самый критичный момент. Опус прав: если не сменить ключ, одноимённые файлы из разных ZIP будут перезаписываться. Но **надо проверить**: текущий код в `addRegularFile()` (files.js) ищет по `f.name`. При добавлении `zip_source` нужно либо: - Ключ = `zip_source + "/" + filename` (как предлагает заказчик) - Или ключ = `(zip_source || "") + filename` Я за вариант с конкатенацией в одну строку — проще для сравнения. - **unzip.py не трогаем** — верно. Имя ZIP уже есть на фронте (`file.name`). ### 2.2. Вариант отображения — ✅ СОГЛАСЕН (Вариант А) Заголовок-секция ZIP + отступ `padding-left: 24px`. - Просто, без нового состояния - Соответствует тому что описал заказчик - Опциональное сворачивание — да, но не в первой итерации ### 2.3. Два UI-режима — ⚠️ ЧАСТИЧНО СОГЛАСЕН **Плюсы:** - Бэкенд не меняется — правильно - `state.ui.mode` — хорошее место - Сводный отчёт («зелёное сворачиваем, красное показываем») — отличная идея - Авто-определение + ручной override — разумно **Спорные моменты:** - **Порог 100 файлов** — слишком низкий для автоматического предложения. При 100 файлах текущий UI работает нормально (скролл, 50vh). Реальный болевой порог — **200-300+**. Предлагаю порог **200**. - **«Поток» сейчас не нужен.** Если заказчик работает с 5-50 файлами, весь Stream Mode — оверинжиниринг. Но архитектурно заложить `state.ui.mode` — дёшево и правильно. ### 2.4. Промпты — ✅ СОГЛАСЕН, с уточнениями #### Classify — проблемы А-Д: **А. Counterparty / блок про стороны НУБЕС** — 🔴 КРИТИЧНАЯ. Опус абсолютно прав. Промпт сейчас не говорит что НУБЕС = Исполнитель. LLM возвращает случайную сторону. Чинится одной вставкой в промпт. Делать **первым**. НО: Опус предлагает «ИНН 7727... (взять у заказчика)». Это перебор. Достаточно: ``` НУБЕС известен как: «НУБЕС», «ООО НУБЕС», «ООО "НУБЕС"», «Nubes». counterparty — ВСЕГДА вторая сторона, НИКОГДА не НУБЕС. ``` **Б. parent_number у contract** — ✅ верно. `parent_number = null` для contract. **В. Мусорные документы** — ✅ верно. Добавить примеры в `doc_type=other`. **Г. Few-shot примеры в classify** — ✅ верно. 1-2 примера улучшат точность. **Д. confidence** — ⚠️ спорно. Опус говорит «добавить колонку и показывать low в отчёте». Но `confidence` сейчас даже не сохраняется. Предлагаю **сначала убрать из промпта** (меньше путаницы), а потом, когда будет реальная потребность — добавить и колонку, и парсинг. #### Compare (diff) — ✅ СОГЛАСЕН - «UNRESOLVED вместо дубль-ADD при сомнении» — верно - `temperature=0.1` для diff — проверить (скорее всего уже) - `full_replace` → автоматическое удаление старых строк на стороне Python — **умная идея**, снижает нагрузку на LLM #### Разные промпты под сценарии — ✅ СОГЛАСЕН Не нужно. Один classify + один diff. Меньше рассинхрона. ### 2.5. Гомоглифы — ⚠️ ОСТОРОЖНО Опус предлагает: - `С/C → C` (латиница) - `О/0` — «трактовать осторожно» - `Ё → Е` **Моё мнение:** - `С→C` и `Ё→Е` — **опасно**. Это меняет семантику номера. `МЭС-123` ≠ `МЭC-123`. Лучше: **не заменять, а добавить второй проход сравнения** — если точное совпадение не найдено, попробовать с гомоглифами. Или нормализовать ОБА варианта (и кириллицу, и латиницу) к единому представлению, но сохранять оригинал для отображения. - Конкретно для `Ё`: да, `Ё→Е` допустимо (в делопроизводстве Ё часто заменяют на Е). Но лучше сделать настраиваемым. ### 2.6. Приоритеты — ✅ СОГЛАСЕН с корректировкой | Что | Приоритет Опуса | Моя оценка | |-----|----------------|-----------| | Counterparty в промпте | P0 | P0 ✅ | | doc_type=other мусор | P0 | P0 ✅ | | Гомоглифы | P0 | P1 ⚠️ (осторожно, не ломать) | | zip_source | P1 | P1 ✅ | | Группировка по ZIP в UI | P1 | P1 ✅ | | Режим «Поток» | P2 | P3 (отложить, нет потребности) | | confidence в БД | P3 | P3 (или убрать из промпта) | | diff-UNRESOLVED | P3 | P2 (дёшево, большой эффект) | --- ## 3. Что Опус упустил ### 3.1. Lucee-слой `upload.cfm` и `api.cfm` на Lucee тоже обрабатывают загрузку. Если файл идёт через Lucee (а не напрямую на VM), `zip_source` нужно прокинуть и там. Надо проверить — идёт ли upload через Lucee или напрямую на VM. **Факт:** судя по `index.cfm`, JS грузится с VM (`contracts.kube5s.ru/static/app.js`), а upload идёт на `VM_API + '/upload'`. Значит Lucee в upload **не участвует**. `zip_source` в Lucee не нужен. Опус оказался прав молча. ### 3.2. Промпты в БД vs хардкод Опус верно заметил: «промпты берутся из БД (Lucee), fallback — хардкод. Менять надо в БД через интерфейс промптов». Это **критично важно для исполнителя**: если просто поправить `FALLBACK_EXTRACT`/`FALLBACK_DIFF` в `llm_prompt.py` — в проде ничего не изменится, потому что используется версия из БД. **Порядок правки промптов:** 1. Сначала в БД через UI (`/prompt.cfm`) 2. Потом в хардкоде (для fallback) ### 3.3. Порог для «Потока» 100 файлов — слишком консервативно. Таблица с `max-height: 50vh` и `overflow-y: auto` нормально работает при 100-150 файлах. Предлагаю **200** как порог для автопредложения. Но лучше — **сделать настраиваемым** (константа в начале app.js). --- ## 4. Итоговое мнение **Ответ Опуса — хороший план.** 95% рекомендаций принимаю. **Что делаем прямо сейчас (P0):** 1. Правка classify-промпта: блок про стороны НУБЕС + parent_number=null + примеры мусора 2. Правка diff-промпта: UNRESOLVED вместо дубль-ADD, temperature проверка **Что делаем дальше (P1):** 3. `zip_source` сквозь все слои (БД → Python → JS) 4. Группировка по ZIP в таблице (Вариант А) 5. Дедупликация по `(zip_source, filename)` **Что откладываем:** 6. Режим «Поток» — пока нет потребности 7. Гомоглифы — нужно больше примеров от заказчика 8. confidence — убрать из промпта, вернуть когда будет нужно **Главный риск (ещё раз):** дедупликация в `addRegularFile()`. Без правки ключа на `(zip_source, name)` — фича сломается на первом же случае одинаковых имён в разных ZIP.