Вы просматриваете старую версию данной страницы. Смотрите текущую версию.

Сравнить с текущим просмотр истории страницы

Версия 1 Текущий »

Краткий обзор архитектуры

Приложение секретаря организовано в виде композиции docker-контейнеров, взаимодействующих через HTTP/HTTPS и WebSocket-соединения, которые устанавливаются на отдельном хосте (рисунок 1).


Рисунок 1

Компоненты системы

Docker-контейнеры

КонтейнерОписаниеПорт(ы)Технологии
clerkHTTP-сервер для приёма аудио, поиска контактов и управления телефонной книгой8000/tcpGo
asr-serverРаспознавание речи и компиляция моделей8003/tcpPython
vosk-serverWebSocket-сервер для распознавания аудио2700/tcpPython, Vosk
mongoХранилище истории вызовов и статистики27017/tcpMongoDB
keycloakСервис авторизации и управления учётными записями8085/tcpJava, Keycloak
keycloak-dbБаза данных для Keycloak5432/tcpPostgreSQL
nginxПрокси-сервер для веб-интерфейса8080/tcpNginx
webbackendБэкенд для веб-интерфейса8091/tcp

ECSS-10 SSW

СервисОписание
RestFSHTTP интерфейс с помощью которого взаимодействует MSR и IVR script взаимодействуют с clerk
MSR

Медиа сервер. Отправляет аудио поток от абонента через restfs в clerk

IVR Script

Скрипт реализующий основную логику работы с clerk

Структура docker compose

Проект построен на модульном принципе, что позволяет гибко комбинировать сервисы:

МодульФайлНазначение
Базовое ядроcompose.yamlОсновные сервисы: Clerk, ASR-Server, Vosk-Server, Mongo, Nginx, WebBackend. Обязателен для запуска
Модуль авторизацииcompose.keycloak.yamlИнтеграция Keycloak + Keycloak-DB + Keycloak-Importer в общую сеть
Модуль мониторингаcompose.peeper.yamlСтек для сбора метрик и логов (опционально)

Варианты запуска

КонфигурацияСоставИспользование
Встроенный KeycloakЯдро + KeycloakПолноценная автономная система с авторизацией
Внешний KeycloakТолько ядроИнтеграция с существующим Keycloak-сервером. Параметры задаются через .env или переменные окружения
Встроенный Keycloak + МониторингЯдро + Keycloak + PeeperПолный стек с мониторингом
Внешний Keycloak + МониторингЯдро + PeeperМониторинг с внешней авторизацией

Детальное описание сервисов

Clerk (Go-сервер)

Назначение: Основной сервис, реализующий логику голосового помощника.

Функции:

  • Приём аудиопотока от MSR/Softswitch через HTTP POST /speech-recognition/{filename};
  • Проксирование аудио в ASR-Server по WebSocket;

  • Получение гипотез распознавания от ASR;

  • Диалоговый поиск контакта в телефонной книге с учётом контекста;

  • Формирование ответов для MSR (номер, уточняющий вопрос, ошибка);

  • Ведение истории в MongoDB;

  • Обновление телефонной книги (по расписанию и вручную через /pb_update);

  • Запуск перекомпиляции ASR-модели;

  • Публикация статусов через WebSocket /status.

ASR-Server (Python-сервер)

Назначение: Обработка аудио, распознавание речи и управление голосовой моделью.

Функции:

  • WebSocket /ws/asr_vad — приём аудио, VAD-сегментация и распознавание через Vosk;

  • Отправка partial и final результатов в Clerk;

  • Получение телефонной книги от Clerk для подготовки словаря;

  • Компиляция модели с новым словарём (фонетика, граф распознавания);

  • Перезапуск Vosk-Server с новой моделью;

  • Предоставление статуса компиляции через /status/compile.

Vosk-Server (Python-сервер)

Назначение: Непосредственное распознавание речи на основе модели Vosk.

Функции:

  • Приём аудио по WebSocket;

  • Распознавание с возвратом промежуточных (partial) и финальных (final) результатов;

  • Перезагрузка модели по команде от ASR-Server.

Mongo (MongoDB)

Назначение: Хранение истории и статистики.

Коллекции:

  • history — записи вызовов с полями:

    • call_ref — уникальный идентификатор вызова;

    • source — номер звонящего;

    • clerk_num — номер автосекретаря;

    • number — найденный номер;

    • status — unknown/good/bad/call_ended/no_number;

    • date — дата и время;

    • files — сопоставление аудиофайлов и распознанных текстов;

    • additional — дополнительные параметры (частота дискретизации, источник).

  • stats — агрегированная статистика по источникам:

    • Source — источник вызовов;

    • RequestCount — общее количество;

    • Correct — успешные;

    • Failed — неуспешные.

WebBackend

Назначение: Бэкенд для веб-интерфейса.

Функции:

  • Аутентификация через Keycloak;

  • Предоставление WebSocket-каналов для UI;

  • Работа с MongoDB для отображения истории и статистики.

Nginx/Frontend

Назначение: Веб-интерфейс и проксирование.

Функции:

  • Раздача статического фронтенда;

  • Проксирование запросов UI к:

    • Clerk (история, статистика, поиск, телефонная книга, статусы);

    • WebBackend (WebSocket-каналы).

  • Отдача логов и PCM-файлов для анализа.

Keycloak + Keycloak-DB + Keycloak-Importer

Назначение: Авторизация и управление пользователями.

Компоненты:

  • Keycloak — сервер авторизации;

  • Keycloak-DB — PostgreSQL для хранения realm'ов, клиентов, пользователей;

  • Keycloak-Importer — однократный импорт настроек (clerk-realm.json) при старте.

Процесс загрузки телефонной книги и компиляции модели

Источники телефонной книги

Система поддерживает два источника, настраиваемых через переменную PB_SOURCES:

AddressBook (GraphQL-сервис)

  • Корпоративный источник с иерархической структурой (отделы, группы, подгруппы);

  • Авторизация через Keycloak (JWT) или API-ключ;

  • Параметры:

    • ADDRESS_BOOK_URL — URL GraphQL-API;

    • AB_AUTH_TYPE — BY_KEYCLOAK_JWT или API_KEY;

    • AB_AUTH_HOSTAB_AUTH_PORTAB_AUTH_REALMAB_CLIENT_IDAB_CLIENT_SECRET — для JWT;

    • AB_API_KEY — для API-ключа.

VCF-файл (HTTP-источник)

  • Статический файл формата vCard;

  • Доступен по HTTP/HTTPS;

  • Параметр: PB_URL — URL файла.

Комбинированный режим

  • PB_SOURCES=ADDRESSBOOK,VCF — Address Book имеет приоритет, VCF игнорируется;

  • PB_SOURCES=ADDRESSBOOK — только Address Book;

  • PB_SOURCES=VCF — только VCF.

Процесс загрузки и подготовки

  1. Инициализация (при старте):

    • Clerk загружает телефонную книгу из настроенного источника;

    • Выполняется маппинг данных во внутренний формат (contact.Contact);

    • Контакты валидируются (обязательные поля, корректность номеров, ФИО).

  2. Периодическое обновление (каждые 12 часов или по запросу /pb_update):

    • Повторная загрузка из источника;

    • Применение изменений через ApplyDiff (добавление, обновление, удаление);

    • Сохранение пользовательских настроек (множители);

    • Отправка подготовленного словаря в ASR-Server.

Компиляция голосовой модели

  1. Подготовка словаря:

    • Контакты транслитерируются и форматируются;

    • Учитывается поле «Множитель» для увеличения веса контакта;

    • Словарь отправляется в ASR-Server через SendPrepare.

  2. Запуск компиляции:

    • ASR-Server получает запрос SendRecompile;

    • Запускается фоновая задача компиляции;

    • Создаются фонетические данные и пересобирается поисковый граф.

  3. Ожидание завершения:

    • Clerk периодически опрашивает статус (GetStatusCompile);

    • Статусы: wait → compile → ready / fail.

  4. Перезапуск Vosk-Server:

    • Новая модель копируется в Vosk-Server;

    • Через WebSocket подаётся команда на загрузку модели.

  5. Публикация статусов:

    • Статус компиляции транслируется всем подписчикам через WebSocket /status.

Механизм «тюнинга» модели

В веб-интерфейсе для контакта можно задать значение «Множитель». Значение сохраняется в оперативной памяти и в backup.pb.

При обновлении телефонной книги:

  1. Загружается актуальный список контактов из источника;
  2. Сохранённые значения множителей переносятся по UID контактов;
  3. Контакт с множителем N фигурирует в тренировочном словаре N раз;
  4. Запускается перекомпиляция модели.

Множитель меняет относительный вес контакта, повышая вероятность его выбора при распознавании.


Обработка вызова

Приём аудио от MSR/Softswitch

  • Запрос: POST /speech-recognition/domain/{domain}/{filename};

  • Формат аудио: PCM/WAV, 48 kHz, моно, 16 бит (s16E);

  • Заголовки:

    • x-call-ref — уникальный идентификатор вызова;

    • x-asr-service — целевой ASR (для балансировки);

    • Expect: 100-continue — ожидание подтверждения.

Процесс:

  1. Clerk извлекает домен, имя файла, call-ref;

  2. По имени файла определяет номера звонящего и автосекретаря;

  3. Создаёт контекст обработки;

  4. Запускает потоковую отправку аудио в ASR-Server по WebSocket.

Запись истории и аудио

  • Для каждого вызова создаётся запись в MongoDB (история);

  • Аудиопоток сохраняется на диск для последующего анализа;

  • Итоговый результат обновляет запись истории.

Передача аудио в ASR по WebSocket

  • Clerk устанавливает WebSocket-соединение с ASR-Server;

  • Аудио отправляется бинарными сообщениями;

  • В конце передаётся сигнал EOF;

  • ASR-Server возвращает текстовые сообщения:

    • partial — промежуточный результат;

    • result — финальный результат.

VAD и сегментация речи (в ASR-Server)


Клиент шлёт аудио-чанки


   [Буфер VAD]


  Анализ (200 мс)

        ├─ Тишина → ожидание
        ├─ Начало речи → старт сегмента
        └─ Конец речи → завершение сегмента


  Накопление секундных порций


  Отправка в Vosk (порциями по 1 секунде)


  Получение partial-результатов → отправка в Clerk


  Завершение сегмента → отправка целого отрезка в Vosk


  Получение final-результата → отправка в Clerk

Диалоговый поиск контакта

Алгоритм для каждого текстового сегмента:

  1. Добавить сегмент к общему накопленному тексту;

  2. Нормализовать текст (регистр, лишние символы);

  3. Выполнить поиск в телефонной книге:

    • По полному имени, фамилии, отчеству;

    • По подразделению, группе (при наличии).

  4. Возможные исходы:

    • Однозначный номер → немедленный ответ 200 OK с номером;

    • Несколько контактов → уточняющий вопрос;

    • Нет контакта → сообщение об ошибке;

    • У контакта нет номера → сообщение об ошибке;

    • Пустой текст → ожидание следующих сегментов.

Контекст диалога:

  • Хранится по call_ref;

  • Содержит предыдущий запрос и «следующий атрибут» для уточнения (фамилия, имя, подразделение).

Итоговый ответ и взаимодействие с MSR

Ничего не распознано

HTTP/1.1 206 Partial Content
{
  "done": false,
  "recognized": "",
  "negative_url": "negative/<callRef>"
}

Уточнение / Нет контакта

HTTP/1.1 206 Partial Content
{
  "done": true,
  "recognized": "<текст>",
  "answer": "<фраза для TTS>",
  "negative_url": "negative/<callRef>"
}

Успешный поиск

HTTP/1.1 200 OK
{
  "done": true,
  "recognized": "<текст>",
  "number": "<найденный номер>",
  "positive_url": "positive/<callRef>",
  "negative_url": "negative/<callRef>"
}

История и статистика

Статусы истории:

  • unknown — автоматически при создании записи или при неоднозначном результате;

  • good — при успешном поиске или по запросу /positive/{callRef};

  • bad — по запросу /negative/{callRef};

  • call_ended — при обрыве вызова или таймауте ASR;

  • no_number — контакт найден, но без номера.

История вызовов

Эндпоинты Clerk:

  • GET /history — список всех записей;

  • GET /history/{callRef} — конкретная запись;

  • DELETE /history — удаление истории.

Структура записи:

{
  "_id": "ObjectId(...)",
  "call_ref": "3095-6666",
  "req_source": "ivr",
  "detection_attr": "fio",
  "status": "unknown",
  "date": "2026-03-20T11:17:57.709Z",
  "files": {
    "2026-03-20_11-17-54-519208_asr_3095-6666.wav": "ковалев"
  },
  "additional": {
    "source": "msr",
    "sample_rate": 48000
  },
  "source": "3095",
  "clerk_num": "6666",
  "number": null
}

Статистика

  • Периодический пересчёт (раз в 10 минут);

  • Хранится в коллекции stats;

  • Поля: Source, RequestCount, Correct, Failed;

  • Эндпоинт: GET /stats.

Мониторинг (опционально)

Модуль мониторинга (compose.peeper.yaml) включает стек для сбора метрик и логов:

  • Сбор метрик с Docker-контейнеров;

  • Визуализация состояния системы;

  • Анализ логов.

Порты и сетевые взаимодействия

СервисПортПротоколНазначение
Clerk8000/tcpHTTP/WSОсновное API, WebSocket статусов
ASR-Server8003/tcpHTTP/WSРаспознавание, компиляция
Vosk-Server2700/tcpWebSocketРаспознавание аудио
Mongo27017/tcpTCPБаза данных
Keycloak8085/tcpHTTPАвторизация
Keycloak-DB5432/tcpTCPPostgreSQL
Nginx8080/tcpHTTPFrontend, прокси
WebBackend8091/tcpHTTP/WSBackend для UI


  • Нет меток