# Сессия #5 — SSE-парсинг, интерактивный прогресс, отказ от LLM _Дата: 2026-06-16_ _Версия: v1.0 → v1.5 (5 повышений)_ _Коммиты: fa4c7fe → 435f617 (6 шт.)_ --- ## Контекст Пользователь (Наиль) захотел: 1. Видеть **интерактивный прогресс** при обработке файлов (имя + таймер в секундах) 2. После обработки — **сводка**: общее время, байты 3. **Никакого LLM** пока — только парсинг 4. Вспомнил что очередь файлов (JS-слой) уже была реализована в коммите `17c4841` --- ## Шаг 1: SSE-поток для LLM (v1.1, fa4c7fe) **Что сделано:** - `_process` в app.py переделан с блокирующего POST на SSE-поток (`text/event-stream`) - Маршрут `/process/` сменён на GET (нужно для `EventSource`) - События: `file_start` → `file_done`/`file_error` → `summary` - В шаблоне — JavaScript с `EventSource`, живые таймеры (каждые 500мс) **Ошибка:** Назвал деплой «поды в Kubernetes» — пользователь поправил: это **managed service** на pythonk8s.services.ngcloud.ru, деплой = `git push master`. **Ошибка:** Забыл повысить версию → v1.1 отдельным коммитом. --- ## Шаг 2: Полный отказ от LLM (v1.2, 3cffca7) **Причина:** Пользователь сказал «НЕ НАДО ЛЛМ и на экране тоже». **Что сделано:** - `_process` → `_parse` — только парсинг, без `extractor.extract()` и `differ.diff()` - `_upload_files` — только сохраняет файлы в БД, без парсинга на этом этапе - `POST /` возвращает JSON `{"contract_id": "..."}` вместо редиректа - Весь LLM (`extractor`, `differ`, `llm_client`) убран из основного потока **Интерфейс:** - Файлы → сразу в таблицу (имя, дата изменения, размер) - ZIP — JSZip показывает содержимое в браузере - Кнопка **«Парсинг»** (не «Обработать LLM») - Клиент: POST файлов через `fetch`, затем SSE `/parse/` - Прогресс в столбце «Статус»: ⏳ Xс → ✓ X.Xс - Итоговая строка: ✓ Готово: N файлов | размер | время --- ## Шаг 3: ZIP — файлы внутри не парсились (v1.3, 21f8c0b) **Проблема:** ZIP-файл парсился как единое целое (✓ 0.2с), а файлы внутри него (`допник-1.doc`, `спецификация.docx`...) оставались с `—` в статусе. **Причина:** В `_parse` парсер просто сливал все elements из ZIP в один документ. Файлы из JSZip-превью были только в браузере, сервер про них не знал. **Решение:** - Сервер сам открывает ZIP (`zipfile.ZipFile`) - Для каждого файла внутри: создаёт отдельный `documents` + `supplements`, парсит, шлёт SSE-события - JSZip и сервер используют одинаковые имена → `findRowByName` находит строку - ZIP-строка показывает `↗ N файлов` вместо галочки --- ## Шаг 4: Подпапки в ZIP (v1.4, d5858d7) **Проблема:** Если в ZIP есть подпапки, и в разных папках файлы с одинаковыми именами — конфликт. **Решение:** Использовать полный относительный путь (`подпапка/файл.docx`) вместо basename. Изменено в двух местах: - **Клиент**: `relativePath` вместо `relativePath.split('/').pop()` - **Сервер**: `zname` вместо `zbasename` --- ## Шаг 5: Только PDF и Word (v1.5, 435f617) **Проблема:** Из ZIP парсились ВСЕ файлы (включая `.txt`, `.xlsx`), давая пустые результаты. **Решение:** Фильтр по MIME-типу: - Сервер: `if zmime not in (pdf, docx, doc): continue` - Клиент (JSZip): `if ['docx','doc','pdf'].indexOf(ext) === -1: return` --- ## Архитектура (текущая) ``` app.py: POST / → _upload_files() → сохранить файлы в БД, вернуть JSON {contract_id} GET / → _index() → render_template("upload.html") GET /parse/ → _parse() → SSE-поток парсинга _parse(): 1. Для каждого документа договора: - Обычный файл → parser_mod.parse() → сохранить parsed_text - ZIP → zipfile.ZipFile() → для каждого PDF/Word внутри: создать document + supplement → parser_mod.parse() → сохранить 2. SSE-события: file_start → file_done/file_error → zip_expanded → summary ``` --- ## Выученные уроки 1. **⛔ Не фантазировать про инфраструктуру.** Managed service ≠ Kubernetes. Деплой = `git push`. 2. **Версия — всегда.** После каждого изменения кода — bump. 3. **ZIP требует особой обработки.** Недостаточно просто распарсить — нужно создать документы для каждого файла внутри. 4. **Имена должны совпадать** между клиентом (JSZip) и сервером (zipfile) — иначе `findRowByName` не находит строку. 5. **`replace_string_in_file` портит файлы** — для больших правок использовать heredoc (`cat > file`).