Развёртывание¶
Страница для тех, кто ставит и обновляет платформу на сервере. Боевой стек описан в файле docker-compose.yml в корне репозитория и рассчитан на Coolify: четыре сервиса платформы, а PostgreSQL и Redis вы создаёте в Coolify сами и передаёте адреса переменными окружения.
Из чего состоит стек¶
| Сервис | Что делает | Порт | Снаружи | Данные |
|---|---|---|---|---|
tgt-asr |
распознавание речи (модель T-one), хранит только модели | 8000 | нет | том asr-models (/models) |
tgt-migrate |
один раз за развёртывание приводит схему базы к текущей версии и завершается | нет | нет | нет |
tgt-api |
API, фоновые очереди и расписание обслуживания в одном процессе | 3001 | да | том audio-data (/data) |
tgt-dashboard |
веб-интерфейс, перенаправляет запросы браузера в API | 3000 | да | нет |
| PostgreSQL | записи, расшифровки, люди, настройки, копия CRM | 5432 | нет | ресурс Coolify |
| Redis | очереди фоновых заданий (это не кэш) | 6379 | нет | ресурс Coolify |
Файл не публикует ни одного порта: два публичных сервиса отдаёт прокси Coolify. Распознаватель, PostgreSQL и Redis остаются закрытыми. Порядок запуска задан зависимостями: tgt-api стартует после успешной миграции и готового распознавателя, tgt-dashboard после готового API.
Контейнеры tgt-asr, tgt-api и tgt-dashboard перезапускаются сами (unless-stopped). Журнал каждого из них ограничен тремя файлами по 10 МБ.
Порядок первого запуска¶
- Домены. Создайте две A-записи DNS на адрес сервера: для панели и для API.
- Базы. В том же проекте и окружении Coolify добавьте ресурсы PostgreSQL и Redis. Скопируйте их внутренние адреса подключения. Для Redis оставьте политику
noevictionи постоянное хранение (appendonly): очередь не должна терять задания. Включите расписание резервных копий PostgreSQL. - Приложение. New Resource → репозиторий, ветка
main, сборка Docker Compose, файл/docker-compose.yml. В настройках приложения (Advanced) включите Connect To Predefined Network, чтобы контейнеры видели базы по внутренним именам. - Домены в Coolify. Сервису
tgt-dashboardзадайтеhttps://<адрес-платформы>:3000, сервисуtgt-apiзадайтеhttps://<адрес-API>:3001. - Переменные. Задайте обязательные переменные из таблицы ниже. Секреты (
ASR_API_KEY,SESSION_SECRET) сгенерируйте случайными строками (openssl rand -hex 24иopenssl rand -hex 32). - Развёртывание. Образы собираются несколько минут. При первом запуске распознаватель скачивает модели с Hugging Face в том
asr-models, и развёртывание ждёт его: серверу нужен исходящий доступ в интернет и около 7 ГБ свободного места под модели (меньше 1 ГБ с декодеромgreedy). Держите не менее 15 ГБ свободного места на диске: образы и сборка занимают ещё несколько гигабайт. - Проверка. Откройте
https://<адрес-API>/readyz: в ответе"status":"ready". Затем откройте панель и войдите под первым владельцем.
Чтобы проверить всё остальное до долгой загрузки модели, запустите первый раз с DECODER=greedy, а потом переключите на beam_search: докачается только языковая модель, пересборка не нужна.
Переменные окружения¶
Задавайте их в Coolify. Пустое значение равно отсутствующему. Контейнеры получают только те переменные, которые перечислены в разделе environment файла docker-compose.yml; значения по умолчанию в таблицах ниже взяты из этого файла. В файле зафиксированы и из окружения не меняются: NODE_ENV=production, порт API 3001, адрес распознавателя http://tgt-asr:8000, каталог звука /data/audio, адрес API для панели http://tgt-api:3001 и один процесс распознавателя.
Обязательные¶
Без них compose отказывается запускаться.
| Переменная | Что задаёт |
|---|---|
DATABASE_URL |
Подключение к PostgreSQL (внутренний адрес ресурса Coolify). Нужно и миграции, и API |
REDIS_URL |
Подключение к Redis; rediss:// включает TLS |
ASR_API_KEY |
Секрет, общий для API и распознавателя |
SESSION_SECRET |
Подпись cookie сессии, не короче 32 символов. Смена выводит всех из системы |
Первый пользователь¶
| Переменная | Что задаёт | По умолчанию |
|---|---|---|
BOOTSTRAP_ADMIN_EMAIL, BOOTSTRAP_ADMIN_PASSWORD |
Создают первого владельца, только если в базе нет ни одного пользователя. Пароль не короче 8 символов | не заданы |
Пока пользователей нет, без этих переменных войти нельзя. После первого входа удалите пароль из окружения.
Распознавание и очередь¶
| Переменная | Что задаёт | По умолчанию |
|---|---|---|
DECODER |
Декодер распознавателя: beam_search или greedy. Читается при старте: смена требует перезапуска, не пересборки |
beam_search |
ASR_MAX_CONCURRENCY |
Сколько файлов распознаватель обрабатывает одновременно, остальные ждут | 2 |
ASR_MEMORY_LIMIT |
Лимит памяти контейнера распознавателя | 3g |
TRANSCRIPTION_CONCURRENCY |
Сколько записей API передаёт распознавателю одновременно (от 1 до 8); не больше ASR_MAX_CONCURRENCY |
2 |
MAX_UPLOAD_MB |
Наибольший размер загружаемого или скачиваемого файла | 512 |
API_RUN_MODE |
all: HTTP и очереди в одном процессе; api: только HTTP; worker: только очереди |
all |
Доступ и сессии¶
| Переменная | Что задаёт | По умолчанию |
|---|---|---|
COOKIE_SECURE |
Cookie сессии только по HTTPS | true |
TRUSTED_PROXY_HOPS |
Сколько обратных прокси стоит перед API (нужно, чтобы видеть настоящий адрес клиента) | 1 |
LOGIN_MAX_FAILURES, LOGIN_FAILURE_WINDOW_SECONDS |
Сколько неудачных входов с одного адреса за какое окно (секунды) до ответа 429 | 10, 300 |
CALLBACK_SIGNING_SECRET |
Секрет подписи колбэков, не короче 16 символов. Без него колбэки идут без подписи | не задан |
Хранилище и источники записей¶
| Переменная | Что задаёт | По умолчанию |
|---|---|---|
STORAGE_KIND |
Где хранится звук: local (том audio-data) или s3 |
local |
INGESTION_SOURCE |
Источник старого забора записей: none, local-inbox или s3 |
none |
INGESTION_LOCAL_PREFIX |
Папка внутри хранилища для local-inbox |
inbox |
S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY |
Бакет и ключ доступа; обязательны при STORAGE_KIND=s3 |
не заданы |
S3_ENDPOINT_URL, S3_REGION |
Адрес и регион провайдера (нужны, если это не AWS) | пусто, us-east-1 |
S3_UPLOAD_PREFIX, S3_INGEST_PREFIX |
Куда складываются загрузки и откуда забираются чужие файлы; не должны пересекаться | uploads/, пусто |
S3_FORCE_PATH_STYLE |
Адресация «путь в адресе»; для AWS false |
true |
Подробнее: Хранилище и модели.
Битрикс24 и адрес платформы¶
| Переменная | Что задаёт | По умолчанию |
|---|---|---|
BITRIX24_WEBHOOK_URL |
Входящий вебхук для чтения (секрет) | не задан |
BITRIX24_EVENT_TOKEN |
Токен приложения исходящего вебхука «звонок завершён» | не задан |
BITRIX24_WRITE_WEBHOOK_URL |
Отдельный вебхук для записи комментариев в сделки (секрет) | не задан |
PUBLIC_BASE_URL |
Публичный адрес панели для ссылки на запись в комментарии | не задан |
Подробнее: Подключение Битрикс24.
Проверка звонков¶
| Переменная | Что задаёт | По умолчанию |
|---|---|---|
ANALYSIS_PROVIDER |
Чем проверяются звонки: rules (словари на сервере, ничего не отправляется), openai-compatible (внешняя языковая модель), mock (выдуманные оценки для демонстраций), none (проверки нет) |
rules |
ANALYSIS_BASE_URL, ANALYSIS_MODEL, ANALYSIS_API_KEY |
Адрес API модели, имя модели и ключ; адрес и имя обязательны при openai-compatible |
не заданы |
ANALYSIS_ALLOW_EXTERNAL_EGRESS |
Разрешение отправлять тексты звонков за пределы сервера; при openai-compatible без true сервер не запускается |
false |
ANALYSIS_RESPONSE_FORMAT |
Как просить ответ у модели: json_object или json_schema |
json_object |
ANALYSIS_EXTRA_BODY |
Дополнительные параметры каждого запроса, JSON-объект | отключает «рассуждения» модели |
ANALYSIS_CONCURRENCY, ANALYSIS_REQUESTS_PER_MINUTE, ANALYSIS_REQUEST_TIMEOUT_SECONDS |
Параллельные вопросы модели (1-8), запросов в минуту (1-600), время ожидания ответа в секундах (5-600) | 2, 60, 180 |
ANALYSIS_PRICE_INPUT_PER_MILLION, ANALYSIS_PRICE_OUTPUT_PER_MILLION, ANALYSIS_PRICE_CURRENCY |
Цена миллиона токенов для расчёта стоимости в редакторе правил; цены задаются парой | не заданы, BYN |
ANALYSIS_SEED_RULES |
Загружать ли при старте правила, поставляемые с системой, для наборов без опубликованной версии | true |
Подробнее о том, что уходит модели: Персональные данные и хранение.
Прочее¶
| Переменная | Что задаёт | По умолчанию |
|---|---|---|
APP_TIMEZONE |
Часовой пояс дней в статистике, каталоге и выгрузках | Europe/Moscow |
CORRELATION_BOOTSTRAP_REPLICATES |
Сколько повторных выборок при расчёте интервала на странице «Связь с продажами» (20-5000) | 1000 |
Что compose не передаёт в контейнеры¶
Эти переменные есть в коде, но в docker-compose.yml их нет, поэтому в Coolify они не действуют: работают значения по умолчанию. Чтобы изменить, добавьте переменную в environment сервиса в файле.
| Переменная | Что задаёт | По умолчанию |
|---|---|---|
SESSION_TTL_HOURS |
Срок жизни сессии | 168 (7 суток) |
TRANSCRIPTION_ATTEMPTS, TRANSCRIPTION_RETRY_DELAY_SECONDS |
Попытки расшифровки одной записи и первая пауза между ними (удваивается) | 5, 30 |
BITRIX24_FETCH_RETRY_DELAY_SECONDS |
Первая пауза между попытками загрузить звонок или шаг чтения CRM (удваивается) | 30 |
BITRIX24_EXPORT_PAUSE_SECONDS, CRM_SYNC_PAUSE_SECONDS |
Паузы между страницами выгрузки звонков и чтения CRM | 2, 1 |
CALLBACK_RETRY_DELAY_SECONDS |
Первая пауза между доставками колбэка (удваивается) | 30 |
ALLOW_PRIVATE_NETWORK_DOWNLOADS |
Разрешить скачивание и колбэки на адреса частной сети (и обращение к модели в частной сети) | false |
QUEUE_PREFIX |
Префикс ключей очередей в Redis; нужен, если два окружения делят один Redis | tgt |
DATABASE_WAIT_SECONDS |
Сколько tgt-migrate ждёт ответа базы |
60 |
Домены и проверки состояния¶
| Сервис | Адрес проверки | Что отвечает |
|---|---|---|
tgt-dashboard |
GET /login |
200, когда страница входа отдаётся |
tgt-api |
GET /healthz |
{"status":"ok"}: процесс жив |
tgt-api |
GET /readyz |
всегда HTTP 200; смотрите поля status (ready или degraded), database, redis, asr (up или down) |
tgt-asr |
GET /healthz, GET /readyz |
ok; ready вместе с моделью, версией, декодером и точностью вычислений |
Все проверки открыты без ключа. Docker использует их как проверки состояния контейнеров: встроенные в образы, поэтому отдельно в Coolify включать их не нужно. У распознавателя стартовый период 30 минут: пока модель скачивается, порт сервиса закрыт и контейнер ещё не считается неисправным.
Примечание
/readyz API отвечает 200 даже при неисправной зависимости. Если следите за сервисом внешним монитором, проверяйте поле status, а не код ответа.
Если Coolify считает развёртывание неудачным из-за tgt-migrate (он завершается с кодом 0 и больше не работает), исключите этот сервис из проверок: в редакторе compose-файла добавьте ему exclude_from_hc: true.
Что делает повторное развёртывание¶
- Coolify собирает образы. Неудачная сборка не трогает работающую версию.
tgt-migrateждёт ответа базы (доDATABASE_WAIT_SECONDS) и применяет миграции. Если он завершился с кодом 1,tgt-apiне стартует.tgt-apiполучает 60 секунд, чтобы завершить текущие задания. Расшифровка, которая шла в этот момент, начинается заново; длинные записи занимают десятки минут, поэтому обновляйте при короткой очереди.- Тома
asr-modelsиaudio-dataи содержимое PostgreSQL сохраняются. Модели повторно не скачиваются.
Если tgt-migrate завершился с кодом 1, откройте его журнал: в первых строках указаны хост, порт, база и пользователь (без пароля) и причина отказа на каждой попытке. Частые причины:
В журнале tgt-migrate |
Что значит | Что делать |
|---|---|---|
does not resolve, ENOTFOUND |
имя базы не находится | включите Connect To Predefined Network и возьмите хост из внутреннего адреса ресурса |
ECONNREFUSED |
хост отвечает, но порт никто не слушает | проверьте порт и что база запущена |
ETIMEDOUT |
адрес не отвечает | проверьте общую сеть приложения и базы и сетевые ограничения |
28P01 или 28000 |
неверный пользователь или пароль | исправьте DATABASE_URL |
3D000 |
базы с таким именем нет | создайте её или используйте ту, с которой стартует сервер (в новом PostgreSQL Coolify это postgres) |
Миграции этого проекта не удаляют и не переименовывают таблицы и столбцы, поэтому откат на предыдущую версию, как правило, возможен без отката схемы. Откат: в Coolify откройте список развёртываний, выберите прежнее и нажмите Redeploy. Часть релизов сбрасывает позиции чтения CRM: тогда следующее чтение перечитывает данные заново и занимает больше времени.
Если между API и PostgreSQL стоит PgBouncer, ему нужно разрешить параметр запуска options (ignore_startup_parameters): API отключает параллельные рабочие процессы запросов, чтобы не зависеть от размера /dev/shm.
Диск не должен заполниться¶
На сервере растут образы и кэш сборки, модели, журналы контейнеров и записи. Модели в образ не входят, поэтому очистка кэша сборки стоит только более долгой сборки.
В Coolify откройте Servers → сервер → Docker Cleanup и задайте:
- частоту
0 * * * *(раз в час); - Force Docker Cleanup выключен, порог 60: очистка срабатывает, когда диск заполнен больше чем на 60%;
- Delete Unused Volumes выключен: иначе удалятся тома остановленных контейнеров, то есть записи и модели.
Внимание
Ошибка no space left on device при сборке или скачивании моделей означает полный диск. Распознаватель сам проверяет свободное место перед скачиванием и пишет в журнал, сколько нужно.
Что владелец делает в панели после первого запуска¶
- Войдите под первым владельцем и удалите
BOOTSTRAP_ADMIN_PASSWORDиз окружения. - «Настройки → Люди»: нажмите «Добавить человека» и заведите руководителей и менеджеров (пароль не короче 8 символов).
- «Настройки → Люди → Отделы»: проверьте номера в «Воронки сделок»: сделки читаются только из этих воронок.
- «Настройки → Система → API-ключи»: создайте ключи для интеграций.
- «Настройки → Автоматика»: убедитесь, что шаг «Битрикс24 подключён» выполнен, включите «Автоматический режим» и подтвердите. Сразу начнётся чтение данных CRM.
- Дождитесь шага «Данные CRM прочитаны», затем нажмите «Определить менеджеров»: откроется «Люди → Отделы → Менеджеры продаж». Нажмите «Определить из Битрикса», отметьте менеджеров продаж каждого отдела и нажмите «Применить состав». Пока состава нет, звонки не загружаются.
- «Настройки → Автоматика → Дополнительно → Загрузить историю»: посмотрите оценку и подтвердите.
- «Настройки → Проверка звонков»: проверьте правила. Автоматический режим сам включает проверку, если задан способ проверки.
- Запись итогов в сделки включайте последней и только если заказчик этого хочет.
Всё, что действует само, после свежего развёртывания выключено: платформа сама ничего не тянет, не читает и не пишет, пока владелец не включит.
См. также¶
- Хранилище и модели: S3, забор записей, декодер и память.
- Эксплуатация: мониторинг, типичные сбои, резервные копии.
- Подключение Битрикс24: вебхуки и права.
- Автоматический режим: что именно включается одним переключателем.