AAYMA
RU
Войти

Saqta Voice Router

Голосовой и текстовый симулятор страхового контакт-центра: AI выбирает сценарий из 40 бизнес-сценариев, собирает поля, отвечает по базе знаний и…

Доведённый продукт
Команда «QosQanat» 20💬 0 комментариевс 23 сентября 2026 г.

О проекте

Команда: QosQanat
Кейс HackAlem.ai: Коммуникации — Halyk Bank · кейс 2
Стадия: Доведённый продукт

Задача кейса: «Voice Router»: голосовой AI, маршрутизирующий звонки в контакт-центре страховой компании

Суть

Голосовой и текстовый симулятор страхового контакт-центра: AI выбирает сценарий из 40 бизнес-сценариев, собирает поля, отвечает по базе знаний и передаёт обращение оператору с контекстом. Есть рабочее место оператора и супервизора.

Как устроено

Браузер передаёт PCM-аудио по WebSocket (AudioWorklet, детектор речи и пауз, перебивание) в gateway, где OpenAI делает потоковую транскрипцию. Realtime-модель возвращает структурированный вызов route_turn со сценариями и извлечёнными полями, который проверяется по Zod-схемам и правилам каталога. Scenario-service и core-движок выбирают факты из JSON-базы знаний, запрашивают недостающие слоты, считают стоимость и возврат кодом. Для 9 необратимых действий требуется отдельное подтверждение. Состояние, история и журнал операций хранятся в SQLite, после передачи человеку AI перестаёт отвечать.

Ключевые решения

  • OpenAI Realtime API
  • function calling (route_turn)
  • streaming STT
  • TTS
  • VAD
  • barge-in
  • slot filling
  • Zod validation
  • idempotent actions
  • knowledge base retrieval

Особенности

Решения модели проходят проверку: она не имеет доступа к БД, а необратимые операции требуют подтверждения с повторной проверкой параметров. Предложение отменяется при изменении данных или обрыве связи. Поддержано перебивание помощника, несколько тем в одном обращении с отложенными запросами и смешанная казахско-русская речь. Голосовые eval-тесты синтезируют входные фразы через TTS.

Стек

TypeScript · Node.js 22 · pnpm monorepo · React 19 · Vite 6 · Express · ws/WebSocket · Zod · SQLite (node:sqlite) · Docker Compose

Модели

gpt-realtime-2.1 · gpt-realtime · gpt-4.1-mini · gpt-live-transcribe · gpt-4o-mini-tts


Проект создан за 5 часов на финале хакатона HackAlem.ai (23 сентября 2026, Астана). Код — BAITC-Hacks/hack-7b90b090-qosqanat.

README

README.md

Saqta Voice Router

Проект команды QosQanat для HackAlem. Голосовой симулятор страхового контакт-центра с AI-маршрутизацией обращений.

Клиент описывает вопрос своими словами на русском, казахском или смешанном языке. Помощник выбирает сценарий, уточняет недостающие данные и отвечает по учебной базе Saqta. Если нужен сотрудник, он получает обращение вместе с историей и следующим шагом.

Проект решает задачу первичного обслуживания клиентов страховой компании: разобраться в запросе, собрать данные и сохранить контекст при передаче оператору. Клиенту доступен разговор в браузере, оператору и супервизору - рабочее место для обработки обращений.

Это демонстрационный прототип. Клиенты, полисы и тарифы синтетические. Покупка полиса, запись на приём и отправка документов изменяют только демонстрационное состояние; реальных страховых операций приложение не выполняет.

Что реализовано

  • Голосовой и текстовый диалог. В голосовом режиме доступны промежуточная расшифровка, автоматический ответ после паузы, озвучивание и перебивание помощника. Есть отключение микрофона и резервный режим с ручным завершением реплики.
  • Выбор сценария языковой моделью из каталога: 40 бизнес-сценариев и 3 системных исхода. Каталог охватывает страховые продукты, страховые случаи, ДМС, обслуживание полисов, платежи, офисы, жалобы и запрос оператора.
  • Сбор и проверка полей, уточняющие вопросы, обработка нескольких тем с сохранением отложенных запросов.
  • Ответы по базе знаний с указанием файла и раздела источника. Панель решения показывает выбранные сценарии, извлечённые данные и ход обработки.
  • Расчёт стоимости и возврата по правилам в коде. В каталоге есть 31 действие; для 9 действий с признаком необратимости предусмотрено отдельное подтверждение параметров.
  • Привязка демонстрационного клиента к телефону, просмотр прошлых обращений, начало нового и продолжение незавершённого разговора.
  • Сохранение истории, состояния сценария и журнала операций в SQLite. Повтор запроса с тем же идентификатором не выполняет действие повторно.
  • Рабочее место оператора: очередь, принятие обращения, переписка и передача коллеге. Супервизор может переназначать и закрывать обращения. После передачи человеку AI прекращает ответы и действия.
  • Интерфейс на русском, казахском и английском. Его язык выбирается отдельно от языка разговора; сохранённые сообщения не переводятся при переключении.

Как работает решение

  1. Клиент вводит телефон. Сервер нормализует номер и находит либо создаёт демонстрационного клиента.
  2. На экране истории клиент начинает новое обращение или продолжает незавершённое. До выбора ввод сообщения недоступен.
  3. Клиент говорит в микрофон или печатает запрос. Голос поступает на сервер по WebSocket и преобразуется в текст через OpenAI.
  4. AI-маршрутизатор возвращает структурированный вызов route_turn: сценарии и извлечённые поля. Сервер проверяет ответ модели по схемам и правилам каталога.
  5. Сервис сценариев выбирает факты из JSON, запрашивает недостающие данные или выполняет расчёт. Для операции с обязательным подтверждением сначала сохраняет предложение с конкретными параметрами.
  6. После отдельного подтверждения сервер повторно проверяет параметры и выполняет действие. Изменение данных или обрыв связи отменяет прежнее предложение.
  7. Клиент получает текстовый ответ и, при включённом голосе, звук. История и результат сохраняются. При передаче оператору тот продолжает работу с этим же обращением.

Технологии

ОбластьИспользуется в репозитории
Язык и средаTypeScript 5.8, strict, ESM; Node.js от 22.13
Организация проектаpnpm 10.8.0, workspace-монорепозиторий
ИнтерфейсReact 19, Vite 6, CSS, иконки Lucide React
HTTP и соединенияExpress 4, библиотека ws, WebSocket
Проверка данныхZod 3
ХранениеSQLite через встроенный node:sqlite, режим WAL
Звук в браузереWeb Audio API, AudioWorklet, PCM 24 кГц; детектор речи и пауз
AI и внешние APIOpenAI Realtime API и Responses API
Настройки и запускdotenv, Docker, Docker Compose
ПроверкиTypeScript, встроенный node:test, tsx; собственные сценарии в evals

Имена моделей по умолчанию заданы в .env.example. Их доступность зависит от OpenAI-аккаунта и проверяется при реальном вызове API.

ПеременнаяЗначениеНазначение
REALTIME_MODELgpt-realtime-2.1Маршрутизация и работа Realtime
REALTIME_FALLBACK_MODELgpt-realtimeРезервная модель маршрутизатора
TEXT_MODELgpt-4.1-miniФормирование ответа по результатам обработки
TRANSCRIPTION_MODELgpt-live-transcribeПотоковое распознавание речи

В голосовых тестах дополнительно используется OpenAI Audio API с моделью gpt-4o-mini-tts для синтеза входных фраз.

Модель подключена через интерфейс RoutingProvider. Реализован провайдер OpenAI; адаптера NVIDIA в текущей версии нет. Graphify и humanizer-ru используются при разработке и не нужны для запуска приложения.

Архитектура проекта

flowchart LR
    Client[Клиент и сотрудники] --> Web[web: React и Vite]
    Web <-->|HTTP и WebSocket| Gateway[gateway: доступ и AI]
    Gateway <-->|распознавание, маршрутизация, ответ и звук| OpenAI[OpenAI API]
    Gateway -->|внутренний HTTP API| Scenario[scenario-service]
    Scenario --> Core[core: правила и действия]
    Core --> Knowledge[knowledge: каталог и база знаний]
    Scenario --> DB[db: SQLite]
    Core --> DB
КаталогОтветственность
apps/webКлиентский экран, история, голос и рабочее место сотрудников
apps/gatewayПубличный HTTP API, WebSocket, проверка доступа, вызовы AI
apps/scenario-serviceСостояние обращения, внутренний API, запуск бизнес-правил
packages/coreДиалоговый движок, расчёты, подтверждения, выполнение действий
packages/dbСхема SQLite, клиенты, обращения, сообщения и журнал операций
packages/aiOpenAI, распознавание, маршрутизация и потоковые ответы
packages/knowledgeЗагрузка каталога и выбор фактов по сценарию
packages/contractsОбщие типы и схемы проверки данных
packages/i18nПереводы интерфейса
docs/voice_router_datasetИсходные учебные данные и примеры
evalsПроверки маршрутизации, диалогов, HTTP и голоса
scriptsЗапуск, настройка окружения, сброс демонстрации и граф проекта

Бизнес-состояние меняют сервис сценариев и его движок через пакет db. Модель не получает прямого доступа к SQLite. Внутренний API защищён INTERNAL_SECRET; Compose не публикует порт сервиса сценариев.

Телефон клиента, обращение и сессия соединения учитываются отдельно. При перезапуске сервер восстанавливает состояние оборванных сессий. Запросы одной сессии обрабатываются последовательно; число одновременных обращений к модели ограничивается настройкой MAX_ACTIVE_MODELS.

Установка и запуск

Все команды ниже выполняются из корня репозитория, где находятся package.json и compose.yaml. Если открыт родительский каталог HackAlem, сначала выполните:

cd hack-7b90b090-qosqanat

Для диалога нужен интернет и ключ OpenAI с доступом к настроенным моделям, включая Realtime. Это относится и к текстовому режиму. Вызовы API платные. Для микрофона нужен браузер с доступом к Web Audio и разрешением на запись; открывайте приложение через localhost или HTTPS.

Локально через Node.js

  1. Установите Node.js версии 22.13 или новее и pnpm 10.8.0. Если используете Corepack:

    corepack enable
    corepack prepare [email protected] --activate
    
  2. Установите зависимости:

    pnpm install --frozen-lockfile
    
  3. При первом запуске создайте файл настроек. Если .env уже существует, сохраните его и измените нужные значения вручную.

    cp .env.example .env
    pnpm env:setup
    

    Команда env:setup заполняет пустые INTERNAL_SECRET и STAFF_PASSWORD. Откройте .env и укажите свой OPENAI_API_KEY. Секреты остаются на сервере; не добавляйте .env в Git.

  4. Запустите три приложения:

    pnpm dev
    
  5. Откройте клиентский экран или рабочее место сотрудников.

По умолчанию web слушает порт 3000, gateway - 3001, scenario-service - 3002. Локальная база хранится в var/voice-router.sqlite. Проверить HTTP-доступность gateway и сервиса сценариев можно командой:

curl http://localhost:3000/api/health

Успешный ответ этого адреса не проверяет доступ к AI-моделям. После изменения .env перезапустите процессы. Для отдельного запуска приложений предусмотрены pnpm dev:web, pnpm dev:gateway и pnpm dev:scenario.

Через Docker Compose

Нужны Docker Engine и Compose. Node.js на хосте для этого варианта не требуется.

  1. Создайте .env из .env.example, если файла ещё нет.

  2. Заполните OPENAI_API_KEY, INTERNAL_SECRET случайной строкой длиной не менее 24 символов и STAFF_PASSWORD длиной не менее 12 символов.

  3. Запустите:

    docker compose up --build
    
  4. Откройте localhost:3000.

Compose собирает интерфейс, запускает три сервиса и хранит SQLite в volume history. Для остановки с сохранением данных используйте docker compose down. Добавление флага -v удаляет volume с историей.

В отчёте проверки указано, что конфигурация Compose проверена, но полный контейнерный запуск не подтверждён из-за недоступного Docker Engine. Локальный запуск через pnpm dev описан там как проверенный.

Настройки и учётные записи

НастройкаНазначение
OPENAI_API_KEYСерверный ключ OpenAI
INTERNAL_SECRETЗащита внутреннего API
STAFF_PASSWORDОбщий демонстрационный пароль сотрудников
PUBLIC_ORIGINРазрешённый адрес интерфейса, по умолчанию http://localhost:3000
SCENARIO_URLАдрес сервиса сценариев; Compose задаёт его отдельно
DATABASE_PATHПуть к SQLite; в Compose используется /data/voice-router.sqlite
MAX_ACTIVE_MODELSОграничение одновременных вызовов моделей, в примере окружения 8

На /staff доступны operator1, operator2 и supervisor. Пароль при описанном выше запуске берётся из .env. Если запускать pnpm dev без заданных служебных переменных, он создаёт локальные значения в var/local-config.json. Пустые строки из скопированного .env нужно предварительно заполнить через pnpm env:setup.

Как проверить решение жюри

Для первого прохода используйте текст: он позволяет отдельно проверить сценарии без влияния микрофона. Затем повторите запрос голосом.

  1. На клиентском экране введите +77010000001. Это номер синтетического клиента C001 из mock_backend.json. Начните новое обращение.
  2. Напишите «Где находится ваш офис в Алматы?». Ожидается сценарий SC33, ответ по офисам и источник knowledge_base.json#/offices в панели решения. При необходимости откройте эту панель в интерфейсе.
  3. Спросите «Алматыдағы кеңсеңіз қайда?». Проверьте ответ на казахском. Смените язык интерфейса и убедитесь, что прошлые сообщения остались на исходном языке.
  4. Попросите «Измените мой email на [email protected]». Отвечайте на уточнения помощника. До подтверждения должно появиться предложение с параметрами изменения. Проверьте их и отдельно подтвердите замену. В истории должен появиться результат действия. Адрес предназначен только для демонстрации.
  5. Напишите «Соедините меня с оператором». В другом окне откройте /staff, войдите как operator1 с STAFF_PASSWORD и примите обращение. Проверьте историю, результат изменения и возможность ответить клиенту.
  6. Передайте обращение operator2. В отдельном профиле браузера войдите как второй оператор: история должна сохраниться, прежний сотрудник теряет право отвечать. Отдельный профиль нужен, чтобы учётные записи не делили одну cookie.
  7. В новом AI-обращении включите голос, разрешите микрофон и повторите вопрос об офисе. После паузы должны появиться текст и звук ответа. Попробуйте перебить помощника. При ошибке сохраните её текст: эта проверка зависит от браузера, микрофона, сети и доступа к моделям.

Для проверки восстановления закройте клиентское соединение, затем снова введите тот же номер и выберите незавершённое обращение. Проверьте сохранённые сообщения и отсутствие повторного выполнения уже подтверждённого действия.

Автоматические проверки

Без вызовов AI API:

pnpm typecheck
pnpm test
pnpm build

pnpm build проверяет синтаксис аудиомодуля и собирает web-приложение. Автотесты проверяют правила, подтверждения, повторы операций, изоляцию истории, сохранение SQLite и обработку речи на уровне кода.

С ключом OpenAI и платными вызовами API:

pnpm eval
pnpm eval dialogs

Первый прогон проверяет маршрутизацию 104 реплик, второй - примеры диалогов через модель, движок и SQLite. Отчёты сохраняются в evals/artifacts. Для запущенного приложения также предусмотрены:

# Проверка телефона и истории через HTTP, без вызовов модели
node --import tsx evals/src/phone-http.ts

# Голосовые проверки с реальным API
node --import tsx evals/src/live-transcription.ts
node --import tsx evals/src/live-voice.ts
node --import tsx evals/src/live-interruption.ts

В docs/validation.md зафиксированы прошлые результаты: 104 совпадения из 104 на предоставленном наборе реплик и 38 из 40 на ходах примерных диалогов. Это отчёт о конкретных прогонах, а не гарантия качества на новых данных. Синтетические голосовые тесты не заменяют проверку человеком.

Для возврата локальной демонстрации к исходным данным остановите сервисы и выполните pnpm demo:reset. Команда архивирует локальную базу; при следующем запуске она создаётся заново. На Docker volume эта команда не действует.

Данные и интеграции

Исходный набор находится в docs/voice_router_dataset. Его описание доступно на русском.

ФайлСодержимое
scenarios.json40 бизнес-сценариев и 3 системных исхода, приоритеты и границы выбора
slots.json43 поля: типы, допустимые значения и вопросы для уточнения
actions.json31 действие, параметры, ошибки и требования подтверждения
knowledge_base.jsonУчебные продукты, тарифы, офисы, клиники и правила
mock_backend.jsonСинтетические клиенты, полисы, страховые случаи и платежи
dev_utterances.jsonРазмеченные реплики для проверки маршрутизации
dialogs_sample.jsonПримеры многошаговых диалогов

Поиск знаний выбирает разделы JSON по сценарию, без векторной базы. Исходные файлы не изменяются; операции записываются в SQLite. В расчётах используется фиксированная дата учебного набора 2026-10-01, поэтому результат не следует трактовать как расчёт на текущую календарную дату.

Реальная внешняя интеграция приложения - OpenAI: текст, контекст и аудио отправляются в API для обработки. По умолчанию аудио не сохраняется локально. Страховая система, платёжный шлюз, SMS-провайдер, телефония и сервис записи клиник не подключены. Адреса, контакты и ссылки из учебной базы не являются адресом развёрнутого приложения.

Ограничения текущей версии

  • Ввод телефона не подтверждается по SMS. Зная демонстрационный номер, можно начать сессию этого клиента. Для настоящих клиентских данных такой способ идентификации непригоден.
  • Учётные записи сотрудников демонстрационные, с общим паролем. Отдельной административной панели нет.
  • Приложение рассчитано на одну копию каждого сервиса. Распределённая очередь и работа нескольких экземпляров не реализованы.
  • Голос рассчитан на русский, казахский и смешанную речь. Английский доступен в интерфейсе, но не входит в заявленный объём голосового MVP.
  • При паузе около 700 мс детектор завершает реплику. Длинная пауза внутри вопроса может преждевременно запустить ответ. Полная приёмка свободной речи, эха и перебиваний человеком в отчёте не завершена.
  • Ответ зависит от нескольких обращений к AI, поэтому задержка заметна и зависит от сети и моделей. Тестовые измерения получения звука не равны времени слышимого воспроизведения в браузере.
  • Для части возрастов автомобиля нет тарифа КАСКО; реальное расписание клиник отсутствует. При недостатке тарифа требуется оператор, запись использует демонстрационное расписание.
  • Защита и тесты покрывают конкретные сценарии, но не доказывают устойчивость ко всем ошибкам модели или атакам. Для промышленной эксплуатации нужны проверка личности, отдельные аккаунты и политика хранения данных.

Подробности проверки и расхождения с заданием находятся в docs/validation.md и docs/task-audit.md.

Развёрнутая версия

Подтверждённая ссылка на публичную развёрнутую версию в репозитории не указана. Для проверки используйте локальный адрес http://localhost:3000 после запуска.

Звёзды
⭐ 0
Форки
0
Язык
HTML
Последний push
в прошлом месяце
Коммиты
5
Авторы
1
Файлы
85
Ветки
1

Авторы коммитов

Maksim Mukharev 5

История коммитов

  • 2026-09-23 17:54fix: preserve request context and scope knowledge retrievalMaksim Mukharev
  • 2026-09-23 17:48docs: prepare Russian README for hackathon juryMaksim Mukharev
  • 2026-09-23 17:40fix: detect voice pauses and preserve utterances on muteMaksim Mukharev
  • 2026-09-23 17:22feat: bind conversations to phones and add streaming voice chatMaksim Mukharev
  • 2026-09-23 16:17feat: implement Saqta Voice Router MVPMaksim Mukharev
Структура репозитория (85 файлов)
.dockerignore
.env.example
.gitignore
.graphifyignore
AGENTS.md
Dockerfile
README.md
apps/gateway/package.json
apps/gateway/src/index.ts
apps/gateway/src/live.ts
apps/scenario-service/package.json
apps/scenario-service/src/index.ts
apps/web/index.html
apps/web/package.json
apps/web/public/voice-worklet.js
apps/web/src/capture.ts
apps/web/src/live-voice.ts
apps/web/src/main.tsx
apps/web/src/style.css
apps/web/src/vad.ts
apps/web/src/voice.ts
apps/web/vite.config.ts
compose.yaml
docs/HackAlem AI_ Voice Router - гибридный голосовой AI-робот с LLM-слоем выбора сценария.docx
docs/task-audit.md
docs/tool-versions.json
docs/validation-results.json
docs/validation.md
docs/voice_router_dataset/README.kz.md
docs/voice_router_dataset/README.md
docs/voice_router_dataset/README.ru.md
docs/voice_router_dataset/actions.json
docs/voice_router_dataset/dev_utterances.json
docs/voice_router_dataset/dialogs_sample.json
docs/voice_router_dataset/evaluate.py
docs/voice_router_dataset/knowledge_base.json
docs/voice_router_dataset/mock_backend.json
docs/voice_router_dataset/scenarios.json
docs/voice_router_dataset/slots.json
evals/package.json
evals/src/http.ts
evals/src/live-interruption.ts
evals/src/live-transcription.ts
evals/src/live-voice.ts
evals/src/phone-http.ts
evals/src/run.ts
evals/src/voice.ts
graphify-out/GRAPH_REPORT.md
graphify-out/cost.json
graphify-out/graph.html
graphify-out/graph.json
graphify-out/semantic-docs.json
graphify-out/source-manifest.json
package.json
packages/ai/package.json
packages/ai/src/index.ts
packages/ai/src/streaming.ts
packages/ai/src/transcription.ts
packages/contracts/package.json
packages/contracts/src/index.ts
packages/core/package.json
packages/core/src/actions.ts
packages/core/src/index.ts
packages/core/src/language.ts
packages/core/test/engine.test.ts
packages/core/test/knowledge.test.ts
packages/core/test/phone.test.ts
packages/core/test/streaming.test.ts
packages/db/package.json
packages/db/src/index.ts
packages/i18n/package.json
packages/i18n/src/index.ts
packages/knowledge/package.json
packages/knowledge/src/index.ts
pnpm-lock.yaml
pnpm-workspace.yaml
scripts/dev.mjs
scripts/env.ts
scripts/graph-docs.py
scripts/graph-update.mjs
scripts/reset.ts
scripts/setup.mjs
scripts/smoke-ai.ts
tsconfig.base.json
tsconfig.json

Обсуждение 0 комментариев

Войдите, чтобы комментировать

Пока нет комментариев — будьте первым.