AAYMA
RU
Войти

Voice Router (Saqta Insurance)

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

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

О проекте

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

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

Суть

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

Как устроено

Аудио из браузера (WS, PCM 16 kHz) или из Asterisk (ARI + AudioSocket) проходит через Silero VAD с семантическим концом реплики. Затем STT gpt-transcribe (два параллельных запроса) и fast path без LLM для типовых ответов. Если fast path не сработал, LLM-роутер gpt-5.6-luna со строгой JSON-схемой по каталогу из 40 сценариев определяет язык, намерения, уверенность и слоты. Запросы хеджируются, есть резервная модель; при уверенности 0.45–0.75 спрашивается второе мнение gpt-6-sol. Исполнитель ведёт фреймы и стек тем и требует явного «да» для необратимых действий. Ответ строится по шаблону или gpt-6-luna и озвучивается gpt-4o-mini-tts, около 200 фраз синтезированы заранее.

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

  • LLM routing со строгой JSON-схемой
  • Silero VAD
  • hedged requests / fallback model
  • second opinion при средней уверенности
  • стек тем (topic stack)
  • deterministic fast path
  • pre-synthesized TTS cache
  • эволюция каталога: патч + регрессия + откат
  • Asterisk ARI + AudioSocket
  • нормализация слотов (ИИН, телефоны словами, даты)

Метрики

Dev-набор: 99–100% верный основной сценарий, все 40 ходов 10 эталонных диалогов; медиана задержки хода 1.0 с против 2.1 с без оптимизаций

Особенности

Ошибки маршрутизации исправляются правкой человекочитаемого каталога сценариев, а не переобучением. LLM-патчер меняет только описания и примеры, фильтрует хардкод по сходству >85% и прогоняет регрессию на 104 dev-репликах до применения. Задержка снижена за счёт хеджирования запросов, спекулятивного STT, раннего колбэка с заранее озвученным подтверждением и настоящей телефонии с записью звонков в MinIO.

Стек

Python · FastAPI · React · TypeScript · Vite · Docker · Asterisk · MinIO · WebSocket

Модели

gpt-5.6-luna · gpt-6-sol · gpt-6-luna · gpt-transcribe · gpt-4o-mini-tts


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

README

README.md

Voice Router — голосовой AI‑агент Saqta Insurance (DeTeam)

HackAlem AI, трек Halyk Bank, кейс 2 «Voice Router».

Голосовой робот контакт‑центра, у которого сценарий разговора выбирает LLM, а не классификатор намерений. Он понимает живую русскую, казахскую и смешанную речь, переключается между темами, не теряя контекста, и выполняет 40 сценариев страховой компании на данных. Агент работает в вебе и по настоящему телефону через Asterisk. Супервизор видит трассировку каждого решения. Ошибки маршрутизации исправляются правкой каталога за полминуты с регрессионной проверкой, без переобучения модели.

Содержание

  1. Запуск
  2. Что умеет
  3. Как устроен один ход
  4. Сильные стороны
  5. Главная фича: эволюция каталога
  6. Технологический стек
  7. Измеренные результаты
  8. Как проверить самому
  9. Структура репозитория
  10. Ограничения
  11. Документы

Запуск

Бэкенд одной командой (нужны Docker и ключ OpenAI):

echo "OPENAI_API_KEY=sk-..." > backend/.env
docker compose up --build            # http://127.0.0.1:8000

Полный стенд с фронтом, телефонией и записью звонков. Пошаговая инструкция с чек‑листом проверки лежит в docs/RUNBOOK.md:

make venv && npm ci --prefix frontend                     # один раз
docker compose -f infra/asterisk/compose.yaml up -d --build  # Asterisk + MinIO + загрузчик записей
make run                                                  # бэкенд :8000, AudioSocket :9092
make web                                                  # фронт http://127.0.0.1:5173

Звонок: софтфон на аккаунт 1001, номер 757507 звонит от имени клиента Сергея, 9999 включает эхо‑тест.

Что умеет

Обязательные требования кейса:

ТребованиеКак сделано
Голос в вебеМикрофон браузера, WebSocket /ws/voice, серверный VAD, ответ голосом. Текст как запасной канал
Выбор сценария на LLMgpt-5.6-luna со строгой JSON‑схемой по каталогу из 40 сценариев. Классификаторов намерений нет
Корректность выбораDev‑набор: 99–100% основного сценария, все 40 ходов десяти эталонных диалогов кита
Панель трассировкиПосле каждой реплики: транскрипт, язык, сценарии с уверенностью и причиной, альтернативы, слоты, действия, задержка по этапам
Русский и казахскийВключая смену языка посреди диалога и смешанную речь в одной фразе

Опциональные пункты ТЗ, все реализованы:

ОпцияРеализация
Гибридная архитектура с измеримым выигрышемДетерминированный fast path без LLM и шаблонные ответы с готовым аудио. Медиана задержки хода 1.0 с против 2.1 с без этих приёмов
Удержание контекста и возврат к темеСтек тем: прерванная тема откладывается, после новой бот предлагает вернуться. Слоты не теряются
Переспросить вместо угадыванияУверенность 0.45–0.75 уходит на второе мнение gpt-6-sol, при сомнении бот задаёт уточняющий вопрос с двумя вариантами
Передача оператору с контекстомПо просьбе, после трёх неясных реплик подряд и по правилам сценария. Оператор получает резюме, слоты и хвост диалога
Извлечение параметров из речиТелефоны словами на русском и казахском, ИИН, госномера, даты «ертең», «три дня назад», суммы «двадцать лямов»
Потоковая обработкаСтриминг роутера с ранним решением, стриминг ответа по предложениям, стриминг синтеза
Эмоция и подстройка тонаРоутер оценивает эмоцию, ответ начинается с эмпатии при жалобе или ДТП
Панель супервизора со статистикой ошибокСессии, трассировки, распределение уверенности, спорные ходы, запись звонка с плеером
Редактирование каталога без разработчиковЭволюция каталога: патч, регрессия, применение, откат. Подробнее ниже

Плюс сверх ТЗ: настоящая телефония через Asterisk, полная запись каждого звонка в MinIO, экран оператора, генератор каверзных реплик для поиска ошибок роутера.

Как устроен один ход

 Браузер (WS, PCM 16 kHz)                 Софтфон → Asterisk → ARI + External Media (AudioSocket, 8 kHz)
            └──────────────────────┬──────────────────────┘
                                   ▼
 1. VAD Silero + конец реплики     семантический (≈0.3 с тишины и законченная фраза) / по тишине 0.8 с / push‑to‑talk
                                   ▼  распознавание стартует спекулятивно уже на паузе
 2. STT gpt-transcribe             два запроса параллельно (казахский + автоопределение), берётся первый непустой
                                   ▼
 3. Понимание                      a) fast path без LLM: ожидаемый слот по шаблону, «да/нет», «оператор», «алло, слышите?», прощание
                                   b) LLM-роутер gpt-5.6-luna: 2 одинаковых стрима, побеждает первый; запасной стрим на gpt-6-luna,
                                      если первого токена нет 1.8 с; каталог 40 сценариев в кэше промпта; строгая JSON-схема
                                   c) ранний колбэк: первый scenario_id в потоке → сразу играем подтверждение из кэша аудио
                                   d) уверенность 0.45–0.75 → второе мнение gpt-6-sol
                                   ▼  решение: run / continue / confirm / cancel / clarify / handoff / goodbye
 4. Исполнитель сценариев          фреймы, стек тем, план на каждый из 40 сценариев: идентификация → слоты по одному →
                                   действия над моками → для необратимых: озвучить данные → явное «да» → выполнить
                                   ▼  план ответа: факты + вопрос
 5. Ответ                          шаблон без LLM (вопросы слотов, уточнения, прощание) или gpt-6-luna стримом строго по фактам;
                                   числа словами, email маскируется, один вопрос за ход
                                   ▼
 6. TTS gpt-4o-mini-tts, голос marin   ≈200 фраз заранее синтезированы; следующее предложение синтезируется, пока звучит текущее
                                   ▼
 PCM обратно в браузер / кадрами по 20 мс в Asterisk; события и trace → фронт, /ws/supervisor, журнал сессии

Сильные стороны

Маршрутизация, которая понимает, а не сопоставляет

  • Роутер видит весь каталог: описания, правила разграничения not_this_if и примеры. Кроме того, он видит состояние диалога: активный сценарий, ожидаемый слот, стек тем, последнюю реплику бота.
  • В одном вызове роутер определяет язык, режет реплику на несколько намерений, выбирает сценарии с уверенностью и причиной, извлекает и нормализует слоты. Он же распознаёт продолжение сценария и ответ на подтверждение.
  • Срочные сценарии идут первыми: ДТП прямо сейчас, болезнь за границей, мошенничество.
  • Честная уверенность и второе мнение: модель не угадывает, в зоне сомнения бот переспрашивает.

Задержка, которую можно проверить секундомером

  • Мгновенное подтверждение понимания. Как только роутер выдал первый сценарий, звучит первая фраза opening этого сценария из кита, аудио для неё готово заранее. Правила кейса сами требуют начинать с понимания.
  • Хеджирование: два одинаковых запроса к роутеру и запасной на другую модель при всплеске задержки у API.
  • Спекулятивное распознавание, семантический конец реплики, прогретые соединения к OpenAI.
  • Задержка замеряется честно: от последнего озвученного кадра клиента до отправки первого кадра ответа. Все этапы видны в трассировке.

Безопасность и качество ответа

  • Необратимые действия выполняются только после явного «да»: оформление, продление, изменение, расторжение полиса, заявления, записи. Перед этим бот зачитывает данные.
  • Ответы строятся только из фактов плана: результаты моков и разделы базы знаний. Цены считаются по формулам кита, а не придумываются моделью.
  • Персональные данные при повторном озвучивании маскируются. На вопрос «вы робот?» бот отвечает честно.

Живой диалог

  • Бот переспрашивает, если значение не подходит, и называет допустимые варианты с ценами.
  • Держит контекст: «а если дом, а не квартира?» он пересчитывает по уже известной сумме.
  • Спокойно реагирует на грубость и остаётся в теме. Бота можно перебить голосом.
  • Опознаёт клиента по номеру звонящего или по телефону, продиктованному словами на русском или казахском.

Инженерия

  • Контракты раньше кода: JSON‑схемы событий, трассировки, вывода роутера и эволюции, OpenAPI. По ним параллельно работали фронт, телефония и бэкенд.
  • Проверки на каждом уровне: dev‑набор, 10 эталонных диалогов, 80 сценарных диалогов, сквозные голосовой и телефонный тесты, валидация событий по схемам.

Главная фича: эволюция каталога

Знание о маршрутизации живёт не в весах модели, а в человекочитаемом каталоге сценариев. Поэтому ошибку роутера можно исправить за полминуты с регрессионной проверкой. У классификатора намерений тот же цикл занимает дни: разметка, переобучение, релиз.

 ошибка в трассировке ─► кейс ─► патч каталога (gpt-6-sol) ─► валидатор ─► регрессия до/после ─► супервизор применяет ─► новая версия
       ▲                                                                                                                  │
       └───────────────────────────── откат в один клик, заморозка на время зачётного прогона ◄────────────────────────────┘
  • Кейсы. Кнопка «Неверно» у любого хода или генератор каверзных реплик на стыках похожих сценариев. Генератор сохраняет только те реплики, на которых роутер реально ошибся.
  • Патчер. Меняет только description, not_this_if и примеры: не больше 4 операций и 2 сценариев. Идентификаторы, слоты и действия не трогает, поэтому оценка по исходным 40 сценариям остаётся честной.
  • Защита от хардкода. Пример, похожий на текст кейса или dev‑реплику больше чем на 85%, отклоняется, и патчер переписывает его обобщённо.
  • Регрессия. Роутер прогоняется по 104 dev‑репликам и всем кейсам на старой и новой версии каталога. Спорные пункты перепроверяются пятью прогонами. Показываются починенные и сломанные кейсы.
  • Версии. Каждое применение даёт новую версию с хэшем. Промпт роутера пересобирается и прогревается за 2 секунды.

Технологический стек

СлойТехнологии
Модели, только OpenAIроутер gpt-5.6-luna; запасной роутер gpt-6-luna; второе мнение и патчер gpt-6-sol; ответы gpt-6-luna; STT gpt-transcribe; TTS gpt-4o-mini-tts-2025-12-15, голос marin. Везде priority tier и кэш промпта
БэкендPython 3.12, FastAPI, asyncio, OpenAI SDK (Responses API, structured outputs strict, streaming), onnxruntime + Silero VAD, numpy, num2words
Голос в вебеWebSocket, PCM16 16 kHz на вход и 24 kHz на выход, AudioWorklet в браузере, перебивание
ТелефонияAsterisk 20 (Docker), ARI‑приложение voice-ai, External Media с инкапсуляцией AudioSocket, PJSIP, перевод на оператора через ARI; запасной режим через диалплан
Записи звонковMixMonitor → MinIO (S3) → загрузчик → callback в бэкенд → плеер в карточке сессии
ФронтендReact, Vite, TypeScript: экраны звонка, супервизора, сессии, эволюции, оператора и каталога
ИнфраструктураDocker Compose, Makefile, JSON Schema + OpenAPI контракты, журналы сессий в JSONL
ДанныеСтартовый кит кейса: сценарии, слоты, действия, база знаний, мок‑бэкенд, эталонные диалоги, dev‑набор

Почему такая схема, а не speech‑to‑speech модель. В gpt-realtime и gpt-live выбор сценария происходит внутри модели. Тогда нельзя показать слой решения, замерить этапы и проверить маршрутизацию на dev‑наборе. Каскад STT → роутер → ответ → TTS даёт прозрачную трассировку и дословный контроль над тем, что произносит бот.

Выбор модели роутера по замеру на нашем промпте (8 реплик на модель, один запрос без хеджа):

МодельПервый токен, медиана / p90Ответ целиком, медиана / p90Верно
gpt-5.6-luna1.03 / 1.33 с1.63 / 1.91 с8/8
gpt-6-luna0.95 / 1.29 с1.65 / 2.82 с8/8
gpt-6-sol1.05 / 1.33 с1.86 / 2.16 с8/8
gpt-5.6-sol1.05 / 1.23 с1.89 / 2.29 с8/8

gpt-5.6-luna даёт лучший ответ целиком и стабильный хвост, на полном dev‑наборе у неё выше точность. gpt-6-luna стоит запасной на случай всплеска задержки.

Измеренные результаты

МетрикаЗначениеКак воспроизвести
Dev‑набор, основной сценарий0.99–1.00make bench
Dev‑набор, полное совпадение и намерения в мульти‑запросах0.99–1.00make bench
Эталонные диалоги кита40 из 40 ходовmake replay
Сценарные диалоги: 40 основных и 40 краевых80 из 80make test
Задержка хода в текстовом режиме, медиана≈1.0 сmake replay
Голос в вебе, от конца речи до первого звука1.5–2.5 сmake probe-voice
Телефон, ход с роутером / fast path1.9–2.6 с / ≈1 сзвонок или make probe-phone
Патч эволюции от запроса до готовности27–38 свкладка «Эволюция»
События WS по JSON‑схемам контракта0 ошибокmake validate, голосовой тест

Как проверить самому

make validate     # фикстуры и схемы контрактов
make replay       # 10 эталонных диалогов кита, печатает каждый ход с решением и задержкой
make test         # 80 сценарных диалогов, без сервера
make bench        # dev-набор + официальный data/evaluate.py
make probe-voice  # сквозной голосовой тест без микрофона (сервер запущен)
make probe-phone  # сквозной тест телефонии: притворяемся Asterisk по AudioSocket

Реплики для проверки голосом лежат в docs/RUNBOOK.md, раздел 4. Там же чек‑лист телефонии и таблица «если что‑то не так».

Структура репозитория

ПутьЧто внутри
backend/голосовой агент: VAD, STT, роутер, исполнитель, ответы, TTS, телефония, эволюция, тесты
frontend/веб: звонок, супервизор, сессии, эволюция, оператор, каталог
infra/asterisk/Asterisk в Docker (PJSIP, ARI), MinIO и загрузчик полных записей звонков
contracts/JSON‑схемы событий, трассировки, роутера и эволюции, OpenAPI, конфиги Asterisk
fixtures/шаблонные сессии и данные супервизора для фронта
tools/мок‑сервер, проверка фикстур против схем
data/стартовый кит кейса и evaluate.py
docs/runbook, концепт, контракты фронта и телефонии, условия кейса

Ограничения

  • Задержка зависит от OpenAI. Медиана укладывается в 3 с, но при всплесках API отдельные ходы бывают дольше. Запасной запрос режет большую часть таких хвостов.
  • Бенчи параллельно со звонком нельзя. Все компоненты работают на одном ключе, бенч съедает лимит токенов в минуту и замедляет живой разговор.
  • Моки вместо реальных систем. Все действия работают поверх mock_backend.json и базы знаний из кита.
  • Сценарий SC16 не проходит до конца. В данных кита ни у одного клиента нет полиса от несчастного случая, поэтому бот переводит такого клиента на оператора.
  • Роутер недетерминирован. Между прогонами dev‑набора разница около одного процентного пункта.
  • Качество казахского синтеза и распознавания ниже русского. Для казахского распознавание идёт двумя вариантами параллельно.

Документы

КомуКуда смотреть
Запуск и проверкаdocs/RUNBOOK.md
АрхитектураARCHITECTURE.md, ROUTER.md, EVOLUTION.md
Бэкендbackend/README.md
Фронтендdocs/frontend/README.md, DIALOG_EXAMPLES.md, frontend/README.md
Телефонияdocs/telephony/README.md, infra/asterisk/README.md
Контрактыcontracts/
Условия кейсаdocs/case/README.ru.md, ТЗ
Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
36
Авторы
3
Файлы
181
Ветки
3

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

Bekzat Uteulin 23tsukilun 10Solidiguana 3

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

  • 2026-09-23 17:57Merge branch 'frontend'Bekzat Uteulin
  • 2026-09-23 17:57README: case requirements mapping, strengths, full stack, model speed comparison, measured results, limitationsBekzat Uteulin
  • 2026-09-23 17:57Correct transparent logo and align interface colorstsukilun
  • 2026-09-23 17:50Slot hints: prices only for the client's property typeBekzat Uteulin
  • 2026-09-23 17:49Merge branch 'frontend'Bekzat Uteulin
  • 2026-09-23 17:49Repeated slot asks explain allowed values with prices; unclear/rude reply mid-scenario stays on topicBekzat Uteulin
  • 2026-09-23 17:48Refresh NotSoFar frontend visual designtsukilun
  • 2026-09-23 17:42Softphone 1001 is an unknown caller (personas via 7575NN); client name once per call; no repeated lead-in on revisited topicsBekzat Uteulin
Все коммиты (36)
  • 2026-09-23 17:36Dialog quality from live phone test: hearing check, unclear policy, buy offer, lead-in, STT and router tailsBekzat Uteulin
  • 2026-09-23 17:18Runbook for setup and verification; UTF-8 file IO for Windows; make web reuses node_modulesBekzat Uteulin
  • 2026-09-23 17:04Merge branch 'frontend': /ws/voice call, evolution, operator, recording playerBekzat Uteulin
  • 2026-09-23 17:04infra: extra_hosts for recording-uploader so the backend callback resolves on LinuxBekzat Uteulin
  • 2026-09-23 17:02Improve supervisor UX and add recording playertsukilun
  • 2026-09-23 16:57Telephony: full call recording callback from MinIO uploaderBekzat Uteulin
  • 2026-09-23 16:55Merge branch 'diDocker': ARI smoke stack, call recording upload to MinIOBekzat Uteulin
  • 2026-09-23 16:53Add full call recording upload and backend callback contractSolidiguana
  • 2026-09-23 16:42Merge remote-tracking branch 'origin/main'Bekzat Uteulin
  • 2026-09-23 16:41Backend: voice, latency, evolution, telephony (AudioSocket + ARI), scenario QA, Docker, docsBekzat Uteulin
  • 2026-09-23 16:36Prepare local ARI AudioSocket telephony smoke stackSolidiguana
  • 2026-09-23 15:55Telephony contract: switch Asterisk integration to ARI + External Media (AudioSocket)Bekzat Uteulin
  • 2026-09-23 15:45Add Silero VAD onnx model (MIT)Bekzat Uteulin
  • 2026-09-23 15:45Supervisor: keep four headline numbers, move engineering metrics downtsukilun
  • 2026-09-23 15:44Backend: voice pipeline (Silero VAD, gpt-transcribe, cached TTS player), hub, FastAPI app, feature module stubsBekzat Uteulin
  • 2026-09-23 15:38Backend: mocks for 31 actions, scenario plans, dialog session, responder, kit dialog replayBekzat Uteulin
  • 2026-09-23 15:34Frontend: call over /ws/voice, evolution and operator screenstsukilun
  • 2026-09-23 15:26Backend: kit loader, versioned catalog, LLM router with second opinion, dev benchBekzat Uteulin
  • 2026-09-23 15:22Frontend: switch supervisor to team contracts and mock servertsukilun
  • 2026-09-23 15:07Restructure repository layoutBekzat Uteulin
  • 2026-09-23 15:06Merge branch 'diDocker' (Asterisk)Bekzat Uteulin
  • 2026-09-23 15:05Merge branch 'frontend'Bekzat Uteulin
  • 2026-09-23 15:05Add concept, contracts, fixtures and mock server for Voice RouterBekzat Uteulin
  • 2026-09-23 14:42Add Docker Asterisk setup with AMI and ARISolidiguana
  • 2026-09-23 14:21Fix blank call page: effect returned scrollIntoView promisetsukilun
  • 2026-09-23 14:17Supervisor: journal of all calls and call detail pagetsukilun
  • 2026-09-23 13:53Frontend skeleton: call simulator, trace panel, supervisor, scenario catalogtsukilun
  • 2026-09-23 13:16Set up frontend: Vite + React + TypeScripttsukilun
Структура репозитория (181 файлов)
.dockerignore
.gitignore
.nvmrc
Makefile
README.md
backend/.dockerignore
backend/Dockerfile
backend/Dockerfile.dockerignore
backend/README.md
backend/app/__init__.py
backend/app/ari.py
backend/app/assets/scenario_phrases.json
backend/app/assets/silero_vad.onnx
backend/app/audio.py
backend/app/bench.py
backend/app/call.py
backend/app/catalog.py
backend/app/config.py
backend/app/dialog.py
backend/app/evolution.py
backend/app/hub.py
backend/app/kit.py
backend/app/main.py
backend/app/mocks.py
backend/app/normalize.py
backend/app/plans.py
backend/app/policy.py
backend/app/replay.py
backend/app/responder.py
backend/app/router.py
backend/app/session.py
backend/app/speech.py
backend/app/telephony.py
backend/requirements.txt
backend/tests/__init__.py
backend/tests/scenario_dialogs.py
backend/tools/phone_probe.py
backend/tools/voice_probe.py
contracts/README.md
contracts/asterisk/ari.conf
contracts/asterisk/extensions.conf
contracts/asterisk/http.conf
contracts/asterisk/manager.conf
contracts/asterisk/pjsip.conf
contracts/dialog-state.schema.json
contracts/evolution.schema.json
contracts/openapi.yaml
contracts/router-output.schema.json
contracts/trace.schema.json
contracts/ws-events.schema.json
data/actions.json
data/dev_utterances.json
data/dialogs_sample.json
data/evaluate.py
data/knowledge_base.json
data/mock_backend.json
data/scenarios.json
data/slots.json
docker-compose.yml
docs/RUNBOOK.md
docs/case/README.kz.md
docs/case/README.md
docs/case/README.ru.md
docs/case/TZ_Voice_Router.pdf
docs/concept/ARCHITECTURE.md
docs/concept/EVOLUTION.md
docs/concept/ROUTER.md
docs/frontend/DIALOG_EXAMPLES.md
docs/frontend/README.md
docs/telephony/README.md
fixtures/README.md
fixtures/catalog/actions.min.json
fixtures/catalog/clients.min.json
fixtures/catalog/scenarios.min.json
fixtures/sessions/index.json
fixtures/sessions/phone-p01.jsonl
fixtures/sessions/web-d03.jsonl
fixtures/sessions/web-d04.jsonl
fixtures/supervisor/bench_runs.json
fixtures/supervisor/cases.json
fixtures/supervisor/catalog_versions.json
fixtures/supervisor/patches.json
fixtures/supervisor/sessions.json
fixtures/supervisor/stats.json
frontend/.env.example
frontend/.gitignore
frontend/.oxlintrc.json
frontend/README.md
frontend/index.html
frontend/package-lock.json
frontend/package.json
frontend/public/favicon.svg
frontend/public/fonts/OFL.txt
frontend/public/fonts/Onest-Variable.woff2
frontend/public/notsofar-mark.png
frontend/public/pcm-capture-worklet.js
frontend/src/App.tsx
frontend/src/api/http.ts
frontend/src/api/index.ts
frontend/src/api/types.ts
frontend/src/assets/icons/arrow-right.svg
frontend/src/assets/icons/check.svg
frontend/src/assets/icons/chevron-down.svg
frontend/src/assets/icons/close.svg
frontend/src/assets/icons/lock.svg
frontend/src/assets/icons/microphone-off.svg
frontend/src/assets/icons/microphone.svg
frontend/src/assets/icons/phone-off.svg
frontend/src/assets/icons/phone.svg
frontend/src/assets/icons/search.svg
frontend/src/assets/icons/sound.svg
frontend/src/assets/icons/status-dot.svg
frontend/src/assets/icons/stop.svg
frontend/src/assets/icons/unlock.svg
frontend/src/audio/capture.ts
frontend/src/audio/player.ts
frontend/src/components/Icon.tsx
frontend/src/components/call/DialogStatePanel.tsx
frontend/src/components/call/LiveTranscript.tsx
frontend/src/components/evolution/BenchPanel.tsx
frontend/src/components/evolution/CasesPanel.tsx
frontend/src/components/evolution/PatchCard.tsx
frontend/src/components/evolution/PatchProgress.tsx
frontend/src/components/evolution/VersionsPanel.tsx
frontend/src/components/supervisor/CaseForm.tsx
frontend/src/components/supervisor/FlaggedQueue.tsx
frontend/src/components/supervisor/SessionInspector.css
frontend/src/components/supervisor/SessionInspector.tsx
frontend/src/components/supervisor/SessionJournal.tsx
frontend/src/components/supervisor/SessionOutcome.tsx
frontend/src/components/supervisor/SessionRecordingPlayer.css
frontend/src/components/supervisor/SessionRecordingPlayer.tsx
frontend/src/components/supervisor/SessionTimeline.css
frontend/src/components/supervisor/SessionTimeline.tsx
frontend/src/components/supervisor/StatsPanel.tsx
frontend/src/components/trace/LatencyWaterfall.tsx
frontend/src/components/trace/TracePanel.tsx
frontend/src/components/ui.tsx
frontend/src/hooks/useResource.ts
frontend/src/hooks/useVoiceSession.ts
frontend/src/hooks/voiceState.ts
frontend/src/index.css
frontend/src/lib/catalog-context.ts
frontend/src/lib/catalog.tsx
frontend/src/lib/format.ts
frontend/src/lib/live-context.ts
frontend/src/lib/live.tsx
frontend/src/main.tsx
frontend/src/pages/CallPage.tsx
frontend/src/pages/EvolutionPage.tsx
frontend/src/pages/OperatorPage.tsx
frontend/src/pages/ScenariosPage.tsx
frontend/src/pages/SessionPage.tsx
frontend/src/pages/SupervisorPage.tsx
frontend/tsconfig.app.json
frontend/tsconfig.json
frontend/tsconfig.node.json
frontend/vite.config.ts
infra/asterisk/.dockerignore
infra/asterisk/.env.example
infra/asterisk/.gitignore
infra/asterisk/Dockerfile
infra/asterisk/Dockerfile.smoke
infra/asterisk/README.md
infra/asterisk/VOICE_ROUTER.md
infra/asterisk/compose.smoke.yaml
infra/asterisk/compose.yaml
infra/asterisk/config/pjsip_trunk.conf.example
infra/asterisk/docker/entrypoint.py
infra/asterisk/docker/recording_finished.py
infra/asterisk/recording/Dockerfile
infra/asterisk/recording/requirements.txt
infra/asterisk/recording/uploader.py
infra/asterisk/scripts/ari_smoke.py
infra/asterisk/scripts/requirements-smoke.txt
infra/asterisk/scripts/setup.ps1
infra/asterisk/scripts/test-ami.ps1
tools/README.md
tools/mock-server/requirements.txt
tools/mock-server/server.py
tools/validate_contracts.py
Ветки (3)

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

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

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