Commit Graph
93 Commits
Author SHA1 Message Date
naeel 637fdce1bc чанки 10KB base64: /chunk_json + uploadFileChunked10k, v1.33 2026-06-17 21:52:50 +04:00
naeel f0c3d93599 пул maxconn 5→10, v1.32 2026-06-17 21:40:18 +04:00
naeel 6187e4dee8 camelot-py 2.0 (pdfium, без Ghostscript/OpenCV), v1.31 2026-06-17 21:31:37 +04:00
naeel e613716178 tabula-py вместо camelot и libreoffice, v1.30 2026-06-17 21:29:29 +04:00
naeel aae6ea2a88 PDF → libreoffice → DOCX таблицы, fallback pdfplumber, v1.29 2026-06-17 21:15:11 +04:00
naeel f7458da9ac camelot-py[cv] в requirements, v1.28 2026-06-17 21:04:44 +04:00
naeel 7e3ea4bc4d camelot для таблиц PDF (lattice+stream), fallback на pdfplumber, v1.27 2026-06-17 20:26:59 +04:00
naeel db8247448b v1.26 в шаблоне 2026-06-17 20:12:42 +04:00
naeel b742389a5a original_bytes DROP NOT NULL, v1.26 2026-06-17 20:08:25 +04:00
naeel 71d9512fd1 v1.25 в шаблоне 2026-06-17 20:01:11 +04:00
naeel 5ce38d0735 полный лог _upload_json: 12 шагов, v1.25 2026-06-17 19:51:33 +04:00
naeel c3232c43e7 лог upload_entry в _upload_json, v1.24.1 2026-06-17 19:50:31 +04:00
naeel 4480b24245 base64 как TEXT (без декодирования), original_b64 колонка, v1.24 2026-06-17 19:09:51 +04:00
naeel 05c41e8c4a upload: всегда одно соединение, убран if cid, v1.23 2026-06-17 18:58:43 +04:00
naeel 6585598fca пул: keepalive, проверка живости, min=2 max=5, reconnect, v1.22 2026-06-17 18:50:33 +04:00
naeel 5c0fb98955 base64 JSON загрузка вместо FormData/multipart — обход лимита Ingress, v1.21 2026-06-17 18:29:34 +04:00
naeel 2615e781ce пул соединений psycopg2 (min=1 max=3), db.put_conn вместо close, v1.20 2026-06-17 18:23:41 +04:00
naeel dfb9a4218b debug_log: таблица + логи на каждом шаге _chunk_upload, v1.19 2026-06-17 17:49:33 +04:00
naeel ba5933b715 одно DB-соединение на сборку чанков (вместо 7 отдельных), v1.18 2026-06-17 17:37:27 +04:00
naeel 0dac6bf37b чанки в БД (таблица chunks), убран _chunk_store в памяти, v1.17 2026-06-17 17:23:43 +04:00
naeel 87026a1fd8 чанковая загрузка 50KB, /chunk endpoint, v1.15 2026-06-17 16:34:27 +04:00
naeel 1714abf766 fix: Promise резолвился на прогрессе, contractId не ставился, v1.14 2026-06-17 12:47:59 +04:00
naeel 31fec1ca84 загрузка при выборе файла: прогресс, таймер, блокировка input, v1.13 2026-06-17 12:42:07 +04:00
naeel f66d188551 elements_json JSONB: структура документа в БД, PDF page, v1.12 2026-06-17 08:22:33 +04:00
naeel 30460cc78c ℹ первые строки таблиц в модалке, v1.11 2026-06-17 07:33:37 +04:00
naeel f627572abb ℹ модальное окно с деталями парсинга (параграфы, таблицы, ошибки, превью), v1.10 2026-06-17 07:19:38 +04:00
naeel 4474190cae мс вместо сек, идемпотентность (кнопка блокируется после успеха), v1.9 2026-06-17 07:14:17 +04:00
naeel e0c58fcbd0 fix: ZIP-счётчик только PDF/Word, expanded тоже пропускать при повторе, v1.8 2026-06-16 15:18:36 +04:00
naeel c710a2df7a fix: прогресс для файлов из ZIP (findRowByName), v1.7 2026-06-16 15:15:50 +04:00
naeel 64b2295d8c загрузка по одному файлу с XHR-прогрессом, ZIP-размеры, v1.6 2026-06-16 15:08:09 +04:00
naeel 435f617a25 ZIP: только PDF/Word, остальные пропускать, v1.5 2026-06-16 14:59:19 +04:00
naeel d5858d7836 ZIP: полные пути файлов (подпапки), v1.4 2026-06-16 14:57:19 +04:00
naeel 21f8c0b072 ZIP: распаковка и парсинг каждого файла внутри, v1.3 2026-06-16 14:56:12 +04:00
naeel 1f7c392934 v1.2 2026-06-16 14:50:50 +04:00
naeel 3cffca73b3 убрал LLM: только парсинг с интерактивным прогрессом в таблице 2026-06-16 14:49:52 +04:00
naeel 84ce99b189 v1.1 2026-06-16 14:37:08 +04:00
naeel fa4c7fe378 SSE-обработка: интерактивный прогресс с таймерами, итоги по времени/байтам 2026-06-16 14:34:00 +04:00
naeel daf58afa34 revert: восстановлен дизайн Nubes после Gemini
Возвращены: логотип, favicon, v1.0, CSS-переменные, карточки,
топбар, таблицы, Lucide-иконки, двухшаговый процесс.
2026-06-15 08:54:49 +04:00
naeel 07344482cd fix(ui): обычный form submit без JS submit()
Форма теперь в DOM, кнопка type=submit.
JS только переносит файлы в скрытый input перед отправкой.
Браузер сам делает POST и следует редиректу.
2026-06-15 07:51:14 +04:00
naeel 87114d701c feat(ui): версия v1.0 и таймер обработки 2026-06-15 07:42:58 +04:00
naeel fdd7d89ce5 fix: двухшаговый процесс — загрузка (быстро) → обработка (LLM)
Шаг 1: POST / → сохранить файлы, парсинг → редирект на /?id=X
Шаг 2: POST /process/X → LLM extract + diff → редирект на /?id=X
Нет таймаута — загрузка мгновенная, LLM по отдельной кнопке.
2026-06-15 07:41:13 +04:00
naeel 105459ef1a feat(ui): ZIP-превью — распаковка в браузере, показ содержимого
- JSZip: при выборе ZIP показывает список файлов внутри
- 📦 ZIP-файл → ниже с отступом файлы из архива
- Дубликаты проверяются по всем именам (включая ZIP-содержимое)
- Красная корзина для удаления
2026-06-15 07:34:13 +04:00
naeel 9899ede8c6 fix(app): полная перезапись — все шаги пайплайна + ZIP-обработка
- ZIP: elements объединяются из всех файлов
- LLM: extractor.extract(text)
- diff: differ.diff(prev, rows)
- spec_rows + spec_history
- Без дубликатов, без replace_string_in_file
2026-06-15 07:29:47 +04:00
naeel 7095d1201f fix: methods=[GET,POST], красная корзина, детект дубликатов
- / принимает GET и POST (было только GET → 405 Method Not Allowed)
- Кнопка удаления: красная иконка trash-2
- Дубликаты: предупреждение + пометка в очереди
2026-06-15 07:15:29 +04:00
naeel 17c4841acf fix(ui): очередь файлов — JS слой, обработка только по кнопке
- Файлы добавляются в очередь при выборе (чистый JS, без сервера)
- Кнопка «Обработать» активна только когда есть файлы
- Скрытая форма отправляется ТОЛЬКО по нажатию кнопки
- Никакой авто-отправки, никакого LLM до нажатия
2026-06-15 07:09:32 +04:00
naeel 4e714f5680 fix: форма без AJAX — обычный POST, сервер всё делает
Убран JS fetch. Форма отправляется напрямую на сервер.
Сервер обрабатывает файлы и возвращает страницу с результатами.
Нет Failed to fetch.
2026-06-15 07:00:44 +04:00
naeel 46b6bee913 fix: лого SVG, убран Добавить (onchange), create_contract возвращает id, JS без лишнего GET 2026-06-15 06:52:54 +04:00
naeel 4b68ad70c5 clean(differ): убран неиспользуемый ambiguous 2026-06-15 06:46:10 +04:00
naeel b3d28bbd38 clean: удалён мёртвый style.css (весь CSS встроен в upload.html) 2026-06-15 06:45:28 +04:00
naeel a1339887fc clean: _guess_mime → общий mimeutil.py (убраны дубликаты) 2026-06-15 06:45:16 +04:00
naeel 8fc4d6a15a clean(app): убран дубликат if __name__, мёртвый _index(), неиспользуемые импорты 2026-06-15 06:43:38 +04:00
naeel 745d83962e fix(ui): убраны дубликаты старого шаблона (replace склеил две версии) 2026-06-15 06:41:13 +04:00
naeel cb92f9072e fix(ui): корень /, лого Nubes + favicon, убраны поля номера/клиента/даты
- Страница перенесена с /upload на / (корень)
- Верхняя панель с логотипом Nubes (nubes-logo.svg)
- favicon.png из ipwhitelist-app
- Поля номера/клиента/даты убраны — договор создаётся авто
- Исправлен JS (относительные URL)
2026-06-15 06:35:02 +04:00
naeel a2affd5be2 fix(ui): двухшаговый UI — очередь файлов → кнопка Обработать
Шаг 1: добавить файлы в очередь (можно несколько)
Шаг 2: нажать «Обработать все файлы»
Прогресс-бар, результаты по каждому файлу, таблица строк.
2026-06-15 06:18:29 +04:00
naeel 54d9924c04 feat(ui): страница загрузки договора /upload
Дизайн: Nubes Design System (карточки, форма, таблица).
Lucide Icons. drag&drop файла docx/pdf/zip.
Пайплайн: создание договора → загрузка допника → таблица строк.
2026-06-15 06:15:12 +04:00
naeel 3912dff112 fix(llm): verify=False — сертификат aillm.ru истёк Jun 14 07:00 GMT
notAfter=Jun 14 07:00:43 2026 GMT (сегодня утром)
2026-06-14 17:13:12 +04:00
naeel cb7a729df7 feat(api): api.py Blueprint — договоры, допники, история
POST /api/contracts          — создать договор
GET  /api/contracts          — список
GET  /api/contracts/<id>     — договор + допники
POST /api/contracts/<id>/supplements  — загрузить допник (полный пайплайн)
GET  /api/contracts/<id>/history      — история изменений

Пайплайн допника: upload→parse→textify→extract→diff→spec_rows→spec_history
2026-06-14 17:02:31 +04:00
naeel f40792c523 feat(differ): differ.py — сравнение строк между допниками
diff(rows_old, rows_new) → {changes, ambiguous, summary}
change_type: added | deleted | changed | unchanged
changed_fields: только изменённые поля {old, new}
2026-06-14 14:27:36 +04:00
naeel 37894ebd08 feat(test): action 'extract' — извлечение строк спецификации через LLM 2026-06-14 08:06:24 +04:00
naeel 33542d3649 feat(extractor): extractor.py — извлечение строк спецификации через LLM 2026-06-14 08:06:01 +04:00
naeel 04daa35b56 debug: показываем середину ключа для поиска опечаток 2026-06-14 07:58:18 +04:00
naeel 667cd0c306 debug: расширенный вывод в /test debug (hash + края ключа) 2026-06-14 07:57:06 +04:00
naeel 5dd06c6dce Revert "fix(llm): DeepSeek напрямую (api.deepseek.com) вместо LiteLLM"
This reverts commit b6492f2241.
2026-06-14 07:53:53 +04:00
naeel b6492f2241 fix(llm): DeepSeek напрямую (api.deepseek.com) вместо LiteLLM
LiteLLM не видит токены (token_not_found_in_db).
DeepSeek напрямую работает с ключом sk-78ec52... без HTTP/2 проблем.
2026-06-14 07:53:24 +04:00
naeel 14c8984ed2 debug(llm): показать HTTP-версию в ошибке 2026-06-14 07:51:06 +04:00
naeel 8cb7139924 fix(llm): httpx + h2 раздельно в requirements
httpx[http2] мог не парситься платформой. httpx и h2 отдельными строками.
2026-06-14 07:45:15 +04:00
naeel a684d51169 fix(llm): h2+socket вместо curl — HTTP/2 на чистом Python
h2 — pure Python, ставится без компиляции в slim-контейнерах.
ssl.create_default_context() + ALPN h2 + h2.connection.H2Connection.
2026-06-14 07:44:21 +04:00
naeel 099edbcb61 fix(llm): curl --http2 вместо httpx
httpx требует h2, который не ставится в облаке.
curl есть везде и гарантированно держит HTTP/2.
subprocess.run(['curl','-s','--http2',...])
2026-06-14 07:40:12 +04:00
naeel b457de4bb3 debug: проверка h2/httpx в /test debug 2026-06-14 07:39:02 +04:00
naeel c97f26d04d fix: h2 явно в requirements (httpx без h2 молча падает на HTTP/1.1) 2026-06-14 07:36:11 +04:00
naeel 0d0ba18a10 fix(test): debug показывает длину ключа (len=...) 2026-06-14 07:34:05 +04:00
naeel cc3203a1fc feat(test): action 'debug' — показать переменные окружения (маскированно)
POST /test {"action":"debug"} → LLM_API_KEY, DB_*, etc.
2026-06-14 07:29:53 +04:00
naeel 59048308e4 fix(llm): httpx с HTTP/2 вместо requests
api.aillm.ru за ddos-guard — требует HTTP/2. requests (HTTP/1.1) не работал.
httpx[http2] — поддержка HTTP/2, работает с ddos-guard.
2026-06-14 07:27:16 +04:00
naeel c580c935ac fix(llm): модель gpt-oss-120b, max_tokens 8000
Доступные модели на api.aillm.ru: whisper, qwen3.6-27b, gpt-oss-120b.
gpt-oss-120b — та самая 120B модель.
max_tokens поднят до 8000 (reasoning съедает часть токенов).
2026-06-14 07:22:10 +04:00
naeel fe8a5563bf feat(test): action 'llm' — тест LLM через /test
POST /test {"action":"llm", "prompt":"...", "model":"...", "max_tokens":500}
→ вызывает llm_client.ask() → возвращает {text, model, usage}
2026-06-14 07:00:50 +04:00
naeel 44e53edc72 feat(llm): llm_client.py — HTTP-клиент к aillm.ru
ask(prompt, model, max_tokens) → {text, model, usage} | {error}
OpenAI-совместимый формат, temperature=0.1 для стабильности.
Переменные: LLM_API_URL, LLM_API_KEY.
2026-06-14 07:00:04 +04:00
naeel db2f6cc6f1 fix(upload): MIME по расширению, а не content_type
curl/браузеры шлют application/octet-stream — _guess_mime() не вызывался.
Теперь приоритет: расширение файла > content_type
2026-06-14 06:52:37 +04:00
naeel 4635ed4c57 feat(test): action 'exec' — INSERT/UPDATE/DDL через db.execute()
/test sql → db.query() → fetchall() → ломается на CREATE TABLE
/test exec → db.execute() → commit без fetch → для DDL/INSERT/UPDATE
2026-06-14 06:44:39 +04:00
naeel 9d01dbae00 fix(schema): db.query → db.execute для DDL
DDL (CREATE TABLE) не возвращает строк — db.query() делал fetchall() и ломался.
db.execute() делает commit без fetch — правильно для DDL.
2026-06-14 06:44:01 +04:00
naeel 8db35e3b9d feat(upload): слой загрузки документов + регистрация в app.py
POST /upload (multipart/form-data: file):
  1. Сохраняет original_bytes в documents (status='uploaded')
  2. parser.parse() → elements
  3. textify.to_text() → parsed_text
  4. UPDATE documents SET parsed_text, status='parsed'
  5. Возвращает {document_id, filename, status, elements_count}

При ошибке парсинга: status='error', error_message, 422
2026-06-14 06:11:23 +04:00
naeel ba2e8552e7 feat(db): execute() + query_one() — INSERT/UPDATE/DELETE и единичный SELECT
- execute(sql, params) → (rowcount, error) — для INSERT/UPDATE/DELETE
- query_one(sql, params) → (dict, error) — первая строка как словарь
- авто-commit и rollback при ошибке
2026-06-14 06:11:02 +04:00
naeel cbfba0bc54 feat: schema.py (DDL 5 таблиц), db.py без DDL, app.py минимальный, test_routes с комментариями
По рекомендации Sonnet:
- schema.py — все DDL (documents, contracts, supplements, spec_rows, spec_history)
- db.py — только транспорт (connect/query), DDL убран
- app.py — минимальный: ensure_schema() + register_blueprint()
- test_routes.py — подробные комментарии, исправлен импорт psysql
2026-06-13 17:14:48 +04:00
naeel 308be45ce8 feat: parser.py — слой парсера docx/pdf/doc/zip (без фильтрации) 2026-06-13 13:05:35 +04:00
naeel 6b5a6f79aa feat: /test createdb — создание БД через API 2026-06-13 12:48:33 +04:00
naeel b5c007044f feat: ensure_db() — автосоздание БД при старте 2026-06-13 12:46:18 +04:00
naeel c7fbc4dc07 fix: db.connect() возвращает ошибку, /test показывает детали 2026-06-13 12:34:55 +04:00
naeel 23cec8686e fix: абсолютные импорты вместо относительных (ImportError) 2026-06-13 12:17:57 +04:00
naeel dbbc8ea5fe feat: слои db.py + test_routes (Blueprint /test) 2026-06-13 12:02:46 +04:00
naeel 684b4cc9c0 feat: PostgreSQL подключение, переменные в .env.example 2026-06-13 11:57:31 +04:00
naeel 9b6f5b9c5e fix: убрал debug=True, смягчил версии в requirements, health возвращает plain text 2026-06-13 11:45:39 +04:00
naeel 96d85189c1 align: классовый app.py, static/, Dockerfile как в шаблоне 2026-06-13 11:45:04 +04:00
naeel bbf65527b1 restructure: код в site/, согласно платформе Flask 2026-06-13 11:37:13 +04:00
naeel 77dff4d3d4 init: minimal Flask app 2026-06-13 11:29:47 +04:00