Исходная схема с точечными дополнениями. Один салон · до 10 мастеров · около 200 пишущих клиентов в день.
Структура и основные решения сохранены. Синий пунктир — добавленный шаг; новые требования ещё нужно реализовать.
К веткам записи и консультации ↓ · К конфигурации сервера ↓
OUTBOUND_PROXY_URL (SOCKS5), пусто → напрямую/webhooks/wappi/callback через Caddy · заголовок Authorization = секрет (fail-closed)@g.us — отказ) · голос ptt/audio приходит base64 в телеhub.challenge + POST c HMAC X-Hub-Signature-256 · фильтр эха своих ответовgraph.instagram.com — через IG_PROXY_URL (РКН режет SNI) + форс IPv4/internal/send — ответ администратора (токен, только docker-сеть)group_id + secret (fail-closed) · confirmation-код · только личные message_newmessages.send (random_id) · screen_name с кешемaudio_message по URL (ogg/mp3) · кнопки → то же нумерованное меню/internal/send — ответ администратораИдентификация без миграций: WhatsApp / Instagram / VK живут в зарезервированных отрицательных BIGINT-диапазонах chat_id
(−9·10¹⁸+телефон · −8·10¹⁸+IGSID · −7·10¹⁸+user_id), Telegram — как есть. channels.channel_for_chat() восстанавливает канал из chat_id в любом месте кода.
bot:paused из админкиtrace_id сохраняетсяshard.q.{crc32(chat_id) % 16} — 16 durable-очередей · сообщения persistent, переживают рестартdlq (сообщения-убийцы) · prefetch = 8 на шард (WORKER_SHARD_PREFETCH)WORKER_SHARDS="0-7" — задел на несколько воркеров
worker.received · битый JSON → DLQconsent: · bookflow: · resched: · remind: · rate:tiny
локально в воркере, CPU INT8, русский, VAD, один файл за раз (lock)messages BYTEA (РФ-контур), админка даёт плеерvoice_stt_failedauto
спокойный чат → без искусственной задержкиrapid-флаг на 60 с → склейка: базовая задержка 3.5 с (3 с если бот только что отвечал),ru_core_news_lg — PERSON / LOCATION / ORGANIZATIONworker.pii_masked — счётчики и технические метрикиsec:ok: (TTL 1 ч, байт-в-байт; BLOCK и fail-open не кэшируются)router_down+7XXXXXXXXXXsystem.md (прайс статикой) + canary-токен в концеclaude-haiku-4-5 → все легли: «Перегружен» + алерт llm_down/escalations или карточки чата · «Вернуть бота» →независимые ветки сохраняют свои результаты; ошибка одной не стирает другую
один визит и групповая запись изменяются атомарно; зависимые изменения не запускать одновременно
/bot-control (Redis validator:enabled, действует сразу) · нет ключа → env-дефолт
ТУМБЛЕР АДМИНКИ · дефолт OUTPUT_VALIDATOR_ENABLED=false**жирный**) стрипается/pii/mask для админ-эвала «Стирание ПД»pg_dump | gzip → ./backups, ротация 7 дней (после успешного дампа)gunzip -c … | psql (runbook)| Страница | Роль | Что умеет |
|---|---|---|
/ — диалоги | owner | Список чатов по каналам (@user_tg / +7…_what / @user_inst / id_vk), токены и стоимость по каждому чату |
/chats/{id} — карточка | owner/staff | Прямой чат: ответить от имени бота, атомарно забрать на ручное управление, «вернуть бота» (resume-предохранитель); автообновление; плеер голосовых (/messages/{id}/media); удаление клиента целиком (152-ФЗ ст. 21, все каналы + Redis-ключи, брони обезличиваются) — owner |
/stats | owner | Глобальные токены/стоимость/кэш-экономия · автоответы → сэкономленные часы и рубли оператора · последние инциденты |
/bookings | owner/staff/master | Записи + календарь, walk-in вручную, отметка «пришёл», отмена |
/masters | master — только её | Графики по дням недели, отпуска/отгулы, «уведомить затронутых» при недоступности |
/escalations | owner/staff | Активные эскалации, ответ клиенту в исходный канал (TG/WA/IG/VK), снятие эскалации; обновление раз в 5 с |
/services | owner | Прайс: услуги/цены/длительности → публикация в системный промпт |
/prompt | owner | Редактор system.md, версии + откат, публикация → hot-reload воркера |
/reactivation | owner | Настройки авто-режима (пороги 30/45 дн., лимиты, скидка постоянника, оффер, LLM-инструкция) + ручные кампании по сегментам + журнал доставок sent/skipped/failed |
/eval — 6 вкладок | owner | См. раздел 9 |
/journal · /logs · /bot-control | owner | Журнал по trace_id — полный след пайплайна (счётчики маскирования, security-вердикт с источником, все обрывы: пауза/дедуп/отказы голоса/IDOR) · хвосты логов контейнеров · тумблеры паузы бота и валидатора ответов |
ADMIN_USERS), master приземляется на /mastersX-Real-IP (ставит Caddy, клиент не подделает)ADMIN_COOKIE_SECURE| Сьют | Кейсов | Что проверяет | Как судится |
|---|---|---|---|
| Основная LLM | 100 | Ответы бота на прод-промпте (цены, запись, границы, безопасность); галочка «с валидатором LLM» | 2 ступени: regex/keywords → LLM-судья gpt-5-mini, порог 0.8 |
| Роутер | 100 | одиночные и смешанные намерения, параметры, зависимости, escalation | правильный набор маршрутов и следующий шаг |
| Валидатор | 100 | OK/BAD на готовых ответах (обрывы, не-русский, артефакты) | вердикт nano vs эталон |
| Input Security | 50 | 30 block / 20 ok, ловушки false-positive, PII-маски в тексте | вердикт security-LLM vs эталон |
| Стирание ПД | 100 | Боевой pii.mask_pii через worker /pii/mask: падежи, ошибки, контакты, история и STT; измерять пропуски по типам ПД и ложные срабатывания | детерминированно, без облака |
| CLI: adversarial · NER | 20 · 15 | run_evals.py / ner_eval.py — атаки и качество NER, гоняются руками | |
LLM_REASONING_EFFORT тот же)project/llm/tests/: пайплайн, буфер, каскад, PII, каналы, голос, реактивация, цепочкиload_test.py + флаги LLM_STUB/TG_STUB — проверка каркаса; скорость с реальными LLM и голосом измеряется отдельноmessages (+ voice BYTEA) · consents (pii/ads по каналам) · request_log (журнал по trace_id) · token_usageclients (якорь — телефон) · client_identities (chat_id ↔ канал, склейка профилей)masters · master_schedules · time_off · bookings (статус, переносы, посещение) · services; услуги мастеров, участники/услуги группы и занятые интервалы (EXCLUDE)prompt_versions (версии + откат)reactivation_settings (singleton) · reactivation_campaigns · reactivation_deliveries (резерв/статусы/игноры)eval_cases/runs/results · router_eval_cases · validator_eval_cases · security_eval_cases · pii_erase_eval_cases (+ prompt_guard_eval_cases физически в БД от удалённого Prompt Guard, кодом не используется)chat:{id}:messages (контекст 40, TTL = retention ПД) · escalated: · escalation:resume: · greeted:consent:state: · consent:msg:dedup: · rl: (rate-limit) · processed: · retry: · flushed: · bot:paused · sec:ok: (кэш OK-вердиктов security, TTL 1 ч) · validator:enabledbuf:msgs/deadline/lock/fails/last_resp/last_msg/rapidbookflow: · reschedflow: · pending:confirm: · pending:rating:wappi:callbacks: (нумерованные меню) · worker:alive:{slot} · pub/sub prompt:reloadshard.q.N + fanout DLX → dlq| Сервис | Образ / команда | CPU / RAM | Healthcheck | Роль |
|---|---|---|---|---|
| llm | ./llm target runtime · bot.py | 0.5 / 384 МБ | свежесть bot.log (пульс 60 с) | Telegram-адаптер (polling) |
| worker | ./llm target worker (+PyTorch CPU) · worker.py | 2 / 3072 МБ | свежесть worker.log | Весь пайплайн; NER ~1 ГБ и Whisper в этом же контейнере |
| wappi | ./llm runtime · wappi_adapter.py | 0.3 / 256 МБ | GET /health :8081 | WhatsApp webhook |
./llm runtime · instagram_adapter.py | 0.3 / 256 МБ | GET /health :8082 | Instagram webhook | |
| vk | ./llm runtime · vk_adapter.py | 0.3 / 256 МБ | GET /health :8083 | VK Callback |
| scheduler | ./llm runtime · scheduler.py | 0.3 / 256 МБ | свежесть scheduler.log | Напоминания, оценки, реактивация |
| admin | ./admin · FastAPI :8080 | 0.5 / 384 МБ | GET /login | Дашборд; порт наружу только 127.0.0.1 |
| migrate | ./llm runtime · alembic upgrade head | 0.5 / 512 МБ | разовый (completed) | Миграции до старта обработчиков |
| postgres | postgres:16-alpine | 1 / 1024 МБ | pg_isready | Основное хранилище (РФ-контур) |
| redis | redis:7-alpine · AOF + requirepass | 0.5 / 256 МБ | PING | Кэш/состояния |
| rabbitmq | rabbitmq:4-alpine | 0.5 / 512 МБ | diagnostics ping | Очередь |
| caddy | caddy:2-alpine · порты 80/443 | 0.5 / 256 МБ | admin API :2019 | Авто-HTTPS (Let's Encrypt), см. ниже |
| postgres-backup | postgres:16-alpine · backup.sh | 0.5 / 256 МБ | — | Суточный дамп + ротация 7 дн. |
/privacy · /offer — политика и оферта статикой (152-ФЗ)/webhooks/wappi/* → wappi:8081 · /webhooks/instagram/* → instagram:8082 · /webhooks/vk/* → vk:8083X-Real-IP./llm → 6 образов-тегов (llm, worker, wappi, instagram, vk, scheduler) + migrate; worker — отдельный target с PyTorch. Пересобирать все + admin.OUTBOUND_PROXY_URL — единый SOCKS5 для TG/LLM/алертов (поддержан во всех клиентах)IG_PROXY_URL — отдельный прокси только для graph.instagram.com (SNI-блок) + форс IPv4| Роль | Модель | Где | Примечания |
|---|---|---|---|
| Основная (консультация) | gpt-5.4-nano | облако | LLM_REASONING_EFFORT=none · модель задаётся LLM_MODEL |
| Fallback основной | claude-haiku-4-5 | облако (Anthropic native) | отдельный ключ · подхватывает при quota/fatal/ретраях primary |
| Дешёвая: security · роутер · компакт · валидатор · реактивация | gpt-5.4-nano | облако | reasoning не передаётся (дефолт none) · Structured Outputs для роутера |
| Судья эвалов | gpt-5-mini | облако | порог 0.8 · температура опускается для reasoning-моделей |
| Голос → текст | faster-whisper tiny INT8 | локально, CPU воркера | аудио распознаётся локально · 120 с / 4 МБ |
| PII NER | spaCy ru_core_news_lg + Presidio + pymorphy3 | локально | fail-closed · ~1 ГБ RAM |
Код модель-агностик: LLM_BASE_URL позволяет OpenAI / Anthropic / OpenRouter / DeepSeek / Ollama. LLM_STUB/TG_STUB — нагрузочные заглушки (включение primary-заглушки алертится).
Архитектура чат-бота для консультаций и записи. Исходная структура сохранена; дополнения описывают требования к реализации.