From 40c91c12114497f7c1c335654242665ff2b89527 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Mon, 15 Jun 2026 08:44:24 +0400 Subject: [PATCH] FIX: client-side file queue, JSZip support, HTTP2 timeout bypass --- history/session-02-problems.md | 49 +++++++++++++++++++++++++++++++++ history/session-03-fix-http2.md | 40 +++++++++++++++++++++++++++ history/session-04-prg-fix.md | 21 ++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 history/session-02-problems.md create mode 100644 history/session-03-fix-http2.md create mode 100644 history/session-04-prg-fix.md diff --git a/history/session-02-problems.md b/history/session-02-problems.md new file mode 100644 index 0000000..f72f2e5 --- /dev/null +++ b/history/session-02-problems.md @@ -0,0 +1,49 @@ +# Проблемы проекта Contracts App (15.06.2026) + +_Дата: 15.06.2026_ +_Статус: Анализ и выученные уроки_ + +--- + +## 1. Технические ошибки и инструменты + +### ⛔ replace_string_in_file портит файлы +Инструмент заменяет подстроку, а не файл целиком. При повторных правках возникали дубликаты кода (например, два блока `if __name__ == "__main__"`) или обрезка функций. +**Решение:** При больших правках использовать `create_file` для перезаписи файла целиком, либо очень внимательно выбирать контекст в `oldString`. + +### ⛔ Опечатка в API-ключе (c772c3e5 vs 5fad79ba) +Два часа отладки HTTP/2 и `httpx` из-за опечатки в `LLM_API_KEY` (перепутаны символы `9K` -> `K9`). +**Урок:** Проверять валидность ключей и выводить первые/последние символы хеша в логи при ошибках 401. + +### ⛔ Истёкший SSL-сертификат api.aillm.ru +Сертификат протух 14 июня 2026. `httpx` блокировал запросы. +**Временное решение:** `verify=False` в клиенте LLM. + +--- + +## 2. Архитектура и Сеть + +### ⛔ ERR_HTTP2_PROTOCOL_ERROR (Таймауты Ingress) +LLM обрабатывает документ 30-40 секунд. Ingress в K8s обрывает соединение на 30-й секунде. +**Решение:** Разделение процессов. Загрузка — мгновенно. Обработка LLM — по отдельному запросу с фронтенда с визуальным таймером, чтобы пользователь понимал, что процесс идет. + +### ⛔ AJAX fetch() -> Failed to fetch +Сложная логика на фронте (очереди, JSZip) ломалась. +**Решение:** Упрощение до стандартных форм. Паттерн **PRG (Post-Redirect-Get)** для устранения проблемы «Подтвердите повторную отправку формы» при нажатии F5. + +--- + +## 3. Фронтенд и Контент + +### ⛔ Битый логотип +`nubes-logo.svg` содержал текст "Forbidden" (ошибка копирования через `curl`). +**Урок:** Проверять содержимое статических файлов после скачивания. + +--- + +## Текущее состояние (v1.0) + +1. **Упрощение:** Форма `` + стандартный `submit`. +2. **Надежность:** POST на `/` загружает и парсит файлы, затем делает `redirect` на страницу договора. +3. **LLM:** Отдельная кнопка «Обработать (LLM)» внутри договора, чтобы избежать таймаутов при массовой загрузке. +4. **Интерфейс:** Добавлен таймер обработки и версия **v1.0** в шапке. diff --git a/history/session-03-fix-http2.md b/history/session-03-fix-http2.md new file mode 100644 index 0000000..6c1e159 --- /dev/null +++ b/history/session-03-fix-http2.md @@ -0,0 +1,40 @@ +# Анализ ошибки ERR_HTTP2_PROTOCOL_ERROR (15.06.2026) + +## Проблема +При загрузке нескольких или тяжелых файлов (PDF/DOCX) через форму на главной странице, браузер через 30 секунд выдает ошибку `ERR_HTTP2_PROTOCOL_ERROR`. + +## Причина +В текущей реализации `app.py` функция `_upload_files` выполняет **синхронный парсинг** каждого файла в цикле: +1. Сохранение байтов в БД. +2. `parser_mod.parse(file_bytes, mime)` — тяжелая операция (особенно PDF через `pdfplumber` или DOC через `libreoffice`). +3. Формирование текста через `textify`. +4. Обновление БД. + +Если суммарное время парсинга всех файлов превышает 30 секунд, K8s Ingress обрывает соединение, не дождавшись HTTP-ответа (Redirect) от Flask. + +## План действий +1. **Разделить загрузку и парсинг**: + * В `_upload_files` (POST /) только сохранять файлы в БД со статусом `uploaded`. + * Сразу делать редирект на страницу договора. +2. **Перенести парсинг в процесс обработки**: + * В `_process` (POST /process/) добавить шаг: если документ еще не распарсен (`status='uploaded'`), сначала вызвать `parser` и `textify`. +3. **Визуализация**: + * Пользователь на странице договора увидит кнопку «Обработать» с таймером. Теперь и парсинг, и LLM будут работать под этим таймером, не блокируя загрузку. + +## Статус +- [x] Оптимизировать `app.py` (убрать парсинг из загрузки). +- [x] Обновить `_process` (добавить ленивый парсинг). +- [x] Добавить таймер на загрузку. +- [x] **РЕШЕНО**: Перевод обработки в Background Thread (threading) для обхода таймаутов Ingress. +- [x] **ФИКС ZIP**: Добавлена логика обхода вложенных файлов в `_run_processing_task` (раньше ZIP возвращал пустой текст). + +## План "Асинхронное спасение" (15.06.2026 16:00) +1. **Threading**: В `app.py` запуск обработки в фоновом потоке, чтобы сразу вернуть ответ 200 OK. +2. **Polling**: Фронтенд опрашивает статус обработки. +3. **No More POST**: Замена классической формы на `fetch()`, чтобы убрать окно "Подтвердите отправку" при F5. + +## Дополнение от 15:40 +Проблема `ERR_HTTP2_PROTOCOL_ERROR` на загрузке (даже без парсинга) указывает на то, что сама передача байтов в БД через `db.execute` для нескольких файлов занимает более 30 секунд. +Решение: +1. Визуальный таймер поможет понять реальное время «зависания». +2. Если ошибка повторится — это жесткий лимит Ingress на размер тела запроса (Client Max Body Size) или таймаут записи в сетевую БД. diff --git a/history/session-04-prg-fix.md b/history/session-04-prg-fix.md new file mode 100644 index 0000000..730ba6b --- /dev/null +++ b/history/session-04-prg-fix.md @@ -0,0 +1,21 @@ +# Исправление PRG-паттерна и окна повторной отправки (15.06.2026) + +## Проблема +При нажатии F5 (перезагрузка) браузер выдает окно «Подтвердите повторную отправку формы». Это происходит потому, что последним запросом был POST (на загрузку или на обработку), и страница отображается как результат этого POST-запроса. + +## Решение: PRG (Post-Redirect-Get) +Все POST-обработчики должны завершаться инструкцией `redirect(...)`. +1. Пользователь отправляет POST. +2. Сервер обрабатывает данные. +3. Сервер возвращает статус 302 (Redirect). +4. Браузер делает автоматический GET на новый URL. +5. Теперь в истории браузера последний запрос — GET. При нажатии F5 просто обновится страница без всяких окон. + +## Что сделано: +- В `app.py` проверено, что `_upload_files` делает `redirect("/?id=" + contract_id)`. +- В `app.py` проверено, что `_process` делает `redirect("/?id=" + cid)`. +- Добавлена очистка параметров, если они могут вызвать зацикливание. + +## Статус +- [x] Реализован Redirect после всех POST-запросов. +- [x] Окно подтверждения больше не должно появляться при F5 на странице договора.