11 KiB
KPgenerator
Назначение
Генератор коммерческих предложений (КП) для МПО-Информ / servaki. Реализован не как обычное приложение, а как набор n8n-воркфлоу (http://192.168.1.158:5678, доступ через finik). Репозиторий хранит исходники Code-нод n8n (файлы build_*.js / prep_*.js), shell-воркеры на finik, парсер прайсов и документацию.
Возможности: чат-страница для сборки КП → запись в Postgres (таблица quotes), HTML-рендер КП с печатью, генерация PDF (wkhtmltopdf) в MinIO, история/поиск по КП, ИИ-подбор шаблона (Ollama qwen2.5:1.5b с откатом на regex-правила), прайс-лист (price_list, импорт/поиск), отправка КП в Telegram (sendDocument) и голосовые комментарии (Voicebox TTS → sendVoice). Секреты вырезаны (хранятся на Я.Диске).
- Язык: JavaScript (тела n8n Code-нод) + Bash-воркеры + Python (парсер прайсов).
- LOC (исходники): ~731 (JS ≈ 542, Bash ≈ 91, Python ≈ 78). Плюс не-код артефакты: README (~500 стр.), HTML-снапшот базы знаний, дубли zip.
- Ключевые ID: воркфлоу «KP Dialog»
JT6mVXd7LV8Dmuog, «Price List API»mxPgqVNbxALGrMYx, «KP CRUD»kpgencrud01; Postgres credkpgenpg0001.
Архитектура
graph TD
subgraph Client["Браузер / чат kp.servaki.online"]
PAGE["prep_page.js — SPA-чат + Telegram-логин"]
VIEW["build_view.js — HTML/PDF рендер КП"]
end
subgraph N8N["n8n .158 — воркфлоу KP Dialog / Price API"]
CREATE["prep_create.js — создать КП"]
HIST["prep_history.js — история/поиск"]
TPL["build_templates.js — шаблоны КП"]
AI["build_ai.js — ИИ-подбор шаблона"]
SETPDF["prep_setpdf.js — запись pdf_url"]
TG["build_tg.js / prep_tg.js — отправка в Telegram"]
TGAUTH["build_tgauth.js — проверка Telegram-подписи"]
VENQ["prep_voice_enq.js — очередь голоса"]
VPEND["prep_voice_pending.js — выдача задач воркеру"]
VDONE["prep_voice_done.js — отметка готово"]
end
subgraph DB["Postgres (.158)"]
QUOTES[("quotes")]
PRICE[("price_list")]
VQ[("tg_voice_queue")]
end
subgraph Workers["finik — cron-воркеры"]
PDFSH["kp-pdf.sh — wkhtmltopdf → MinIO"]
VOICESH["kp-voice.sh — TTS → MinIO → sendVoice"]
end
IMP["catalog-source/import_prices.py — парсер xlsx"]
MINIO["MinIO aimedia / s3.servaki.online"]
OLLAMA["Ollama .158:11434"]
VOICEBOX["Voicebox 89.125.89.16:5501"]
TGAPI["api.telegram.org @servaki_online_bot"]
PAGE --> CREATE --> QUOTES
PAGE --> HIST --> QUOTES
PAGE --> TPL
PAGE --> AI --> OLLAMA
PAGE --> VIEW
PAGE --> TGAUTH --> TGAPI
VIEW --> TG --> TGAPI
VIEW --> VENQ --> VQ
IMP --> PRICE
PDFSH --> VIEW
PDFSH --> MINIO
PDFSH --> SETPDF --> QUOTES
VOICESH --> VPEND --> VQ
VOICESH --> VOICEBOX
VOICESH --> MINIO
VOICESH --> TGAPI
VOICESH --> VDONE --> VQ
Entry-points / маршруты
База: http://192.168.1.158:5678/webhook. Price-эндпоинты защищены заголовком X-API-Key (иначе 403).
| Метод | Путь | Исходник | Назначение |
|---|---|---|---|
| GET | /webhook/kp-chat |
prep_page.js | Главная SPA-страница чата + Telegram-логин |
| POST | /webhook/kp-chat/create |
prep_create.js | Создать КП (INSERT в quotes) |
| GET | /webhook/kp-chat/view?id=&pdf= |
build_view.js | HTML/PDF-рендер КП (?pdf=1 — режим для wkhtmltopdf) |
| GET | /webhook/kp-chat/history?q= |
prep_history.js | История/поиск по quotes (ILIKE, LIMIT 50) |
| — | (templates) | build_templates.js | Каталог шаблонов КП |
| POST | /webhook/kp-chat/ai |
build_ai.js | ИИ-подбор шаблона (Ollama + откат на правила) |
| POST | /webhook/kp-chat/setpdf |
prep_setpdf.js | UPDATE quotes.pdf_url (только эта колонка) |
| POST | /webhook/kp-chat/telegram |
build_tg.js / prep_tg.js | sendDocument/sendMessage КП в Telegram |
| POST | /webhook/kp-chat/tg-auth |
build_tgauth.js | Проверка Telegram-подписи (чистый JS SHA-256/HMAC) |
| POST | /webhook/kp-chat/voice |
prep_voice_enq.js | Enqueue голосового комментария (tg_voice_queue) |
| GET | /webhook/kp-chat/voice-pending?key= |
prep_voice_pending.js | Выдача задач воркеру (key-protected) |
| POST | /webhook/kp-chat/voice-done |
prep_voice_done.js | Отметка задачи выполненной |
| GET | /webhook/kp |
(n8n нода) | Список КП (используется kp-pdf.sh) |
| GET | /webhook/price/init |
(Price API) | Создать таблицу price_list (идемпотентно) |
| POST | /webhook/price/import |
(Price API) | UPSERT позиций прайса |
| GET | /webhook/price/search?q=&category= |
(Price API) | Поиск позиций (LIMIT 50) |
| PUT | /api/v1/workflows/JT6mVXd7LV8Dmuog |
n8n API | Деплой/откат воркфлоу из бэкапа |
Ключевые цепочки вызовов
- Ручная сборка КП:
/kp-chat(prep_page) → правка позиций →POST /kp-chat/create(prep_create → INSERTquotes) →GET /kp-chat/view?id=(build_view) → кнопка «Печать». - *PDF-пайплайн (cron /5 на finik): kp-pdf.sh берёт
GET /webhook/kp→ для КП без pdf_urlwkhtmltopdf '<view>?pdf=1'→mc cpв MinIOaimedia/kp/→POST /kp-chat/setpdf {id,pdf_url}→ публичная ссылкаs3.servaki.online:8443/aimedia/kp/.... - ИИ-подбор:
POST /kp-chat/ai {text}(build_ai) → regex-правила (база) + попытка Ollamaqwen2.5:1.5bна.158:11434(извлекает объект) → при таймауте/ошибке автооткат на правила → загрузка шаблона в чат. - Отправка в Telegram: кнопка «В Telegram» (build_view) →
POST /kp-chat/telegram {id,chat_id}(build_tg) → sendDocument PDF из MinIO через @servaki_online_bot (chat_id из Telegram-логина, tg-auth → build_tgauth). - Голосовой комментарий (cron * на finik): кнопка «Голосом» →
POST /kp-chat/voice(enq →tg_voice_queue) → kp-voice.sh:GET /voice-pending?key=→ Voicebox TTS (89.125.89.16) →mc cpopus в MinIO → sendVoice по URL →POST /voice-done. - Импорт прайса:
catalog-source/import_prices.pyпарсит.xlsx(openpyxl) →_catalog_import.json→POST /webhook/price/import(через finik).
Тех-долг
Пометка: всё ниже — предположение по грепу/структуре; точность — через codebase-memory-mcp.
- Дубли-артефакты (dead):
zi2jSxII(56622 б = байт-в-байтkpgen-full.zip) иziB7i0OA(55738 б =kpgen-full-project.zip) — безымянные копии архивов, кандидаты на удаление. Плюс три zip (KP_Generator_MPOall.zip,kpgen-full.zip,kpgen-full-project.zip) — снапшоты, не участвуют в рантайме. - Не-код в репо:
KP-knowledge-base-2026-06-27.html— статический снапшот базы знаний (документация, не исполняется). build_templates.js— не найдено явного webhook-роута в коде/README (шаблоны, вероятно, отдаются из prep_page или отдельной ноды); проверить, живой ли (ПРЕДПОЛОЖЕНИЕ).- Токены/секреты зашиты в
build_tg.js(санитизированы в Gitea) — риск рассинхрона с Я.Диском. - Хрупкость деплоя: правка нод n8n только base64/quoted-heredoc (bash раскрывает
${...}/$json); нет CI — откат вручную черезPUT /api/v1/workflows. - Общий прод-бот @servaki_online_bot делится с ТИНКО-парсером на Proxmox — трогать webhook/getUpdates нельзя (жёсткая внешняя связанность).
Cross-service links
- finik — шлюз к n8n
.158, хост cron-воркеров (kp-pdf.sh, kp-voice.sh), Caddy для публичных ссылок (kp-pdf.sh, kp-voice.sh, import_prices.py, README). - vm-mts / .158 —
192.168.1.158: n8n :5678, Postgres, Ollama :11434 (build_ai.js, kp-pdf.sh, kp-voice.sh). - s3.servaki.online / MinIO aimedia — хранилище PDF и voice-ogg (kp-pdf.sh, kp-voice.sh).
- kp.servaki.online — домен чата (Telegram
/setdomain). - Telegram @servaki_online_bot (id 8142796440) — общий прод-бот, только исходящие (build_tg.js, kp-voice.sh, build_tgauth.js).
- Voicebox/Piper
89.125.89.16:5501— TTS (kp-voice.sh). - Внешние: Ollama, api.telegram.org, прайсы Wirenboard/ТИНКО. Ссылок на другие наши репо из списка (agent-sync, Heritage, egorin, orbit-bot и т.д.) — не обнаружено.
TODO для Лилии (codebase-memory-mcp)
- Точный call-graph: воркфлоу собран из n8n-нод — граф связей восстановлен по README/грепу, а не из JSON воркфлоу. Дообогатить из экспортов
JT6mVXd7LV8Dmuog/mxPgqVNbxALGrMYx(реальные связи WH→Prep→PG→Build→Resp). - Dead-code: подтвердить, что
zi2jSxII/ziB7i0OA= дубли zip и удалимы; проверить живостьbuild_templates.js(есть ли входящий роут). - Cross-service: зафиксировать рёбра KPgenerator → finik / .158 / MinIO / Voicebox / Telegram; свести с картами servaki-infra и orbit-bot (общий бот).
- Секреты: сверить санитизированные
build_tg.js/ voice-скрипты с полной версией на Я.Диске. - Снапшот
graph.db.zst: сохранить call-graph + маршруты + cross-service рёбра для инкрементального обновления при правке нод.