AAYMA
RU
Войти

Saqta Voice Router

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

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

О проекте

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

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

Суть

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

Как устроено

Браузер → LiveKit (WebRTC) → voice worker (livekit-agents, Silero VAD, Soniox STT) → FastAPI /turns. Router-вызов GPT-4.1 mini получает весь каталог сценариев с границами not_this_if и возвращает строгий JSON (сценарии с confidence, слоты, язык, согласие); политика уверенности 0.75/0.45 выбирает действие, уточнение или передачу оператору. Data-driven исполнитель 31 действия из actions.json работает на копии mock_backend.json с preview → согласие → execute для необратимых операций, отдельный LLM-вызов формирует реплику, Soniox TTS озвучивает её.

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

  • LLM-роутинг по каталогу с not_this_if
  • пороговая политика уверенности
  • слот-филлинг
  • очередь мульти-интентов
  • preview/consent/execute
  • идемпотентность request_id
  • Silero VAD
  • LiveKit WebRTC

Метрики

evaluate.py, 104 реплики: primary_acc 0.952, full_match 0.942; kk 0.978, ru 0.923, mixed 1.0; multi_intent 0.846/0.769

Особенности

Одна бизнес-логика для голоса и текста (worker только вызывает тот же HTTP /turns); исполнитель полностью управляется JSON кита; согласие привязано к параметрам preview. Честная трасса хода с задержками по этапам и метрики официального оценщика по языкам и типам реплик.

Стек

Python 3.12 · FastAPI · OpenAI SDK · LiveKit · livekit-agents · React 19 · TypeScript · Vite · Zod · Vitest · Playwright · uv

Модели

GPT-4.1 mini · Soniox STT stt-rt-v5 · Soniox TTS tts-rt-v2


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

README

README.md

Saqta Voice Router

Голосовой AI-оператор контакт-центра страховой компании. Клиент говорит в микрофон на русском, казахском или на смеси языков. LLM выбирает один из 40 сценариев Saqta Insurance, сервер выполняет шаг сценария на синтетических данных, клиент слышит ответ голосом. Супервизор после каждой реплики видит трассу решения.

Команда Alt-Tab · HackAlem AI 2026 · кейс 2 «Voice Router»

Все вводные организаторов собраны в папке case/: JSON-данные (scenarios.json, slots.json, actions.json, knowledge_base.json, mock_backend.json, dev_utterances.json, dialogs_sample.json), оценщик evaluate.py, README кита на трёх языках и исходный текст задания. Файлы сохранены без изменений, приложение загружает их с диска. Все данные синтетические: Saqta Insurance, клиенты, полисы и цены вымышлены организаторами.


Содержание

  1. Зачем это нужно
  2. Что умеет
  3. Как выглядит один ход
  4. Архитектура
  5. Как принимается решение
  6. Метрики
  7. Быстрый старт
  8. Проверки
  9. Ограничения
  10. Структура репозитория
  11. Команда и документы

Зачем это нужно

Контакт-центр страховой компании принимает звонки, где одно и то же слово означает разные вещи. «Авария» — это ДТП прямо сейчас (срочно), заявление пострадавшего по ОГПО виновника или убыток по КАСКО. «Выплату одобрили, но мало» — не запрос статуса, а спор с решением. Клиент может начать на казахском, закончить на русском и в одной фразе попросить две вещи.

Классический IVR с кнопками здесь не работает, а энкодерный классификатор намерений запрещён правилами кейса. Наше решение: LLM читает весь каталог сценариев с границами not_this_if и сама объясняет, почему выбрала именно этот сценарий. Голос и текст проходят через одну и ту же бизнес-логику, поэтому поведение агента одинаково в любом канале.

Что умеет

ВозможностьСостояние
Живой голос в браузере: микрофон → STT → LLM → TTS → динамики✅ Проверено в Chrome на RU, KK и mixed репликах
Маршрутизация по 40 сценариям + 3 системным намерениям✅ Каталог загружается из scenarios.json, ID валидируются
Русский, казахский, смешанная речь✅ Язык определяется моделью, ответ — на языке клиента
Несколько намерений в одной фразе✅ Срочное первым, остальные — в очередь сессии и исполняются следом
Извлечение и проверка слотов (43 типа из slots.json)✅ Один уточняющий вопрос за ход
Трасса решения после каждой реплики✅ Сценарии, confidence, альтернативы, обоснование, слоты, действия, задержки
Политика уверенности: выбор / уточнение / оператор✅ Пороги 0.75 и 0.45 из правил кита
Все 31 mock-действие из actions.json✅ Data-driven исполнитель над копией mock_backend.json в памяти сессии
Идентификация клиента по телефону или ИИН✅ Номер полиса или заявления подставляется из данных клиента
Расчёты по формулам базы знаний✅ Цены ОГПО, travel, возврат при расторжении КАСКО сверены с диалогами кита
Preview → явное согласие → execute для необратимых действий✅ Согласие привязано к параметрам preview, новые параметры снимают старый preview
Идемпотентность: повтор request_id не повторяет действие✅
Честный отказ: ошибка провайдера или данных не превращается в фиктивный успех✅ Коды ошибок только из error_codes кита, клиент слышит понятное сообщение
Передача оператору с резюме контекста✅ Очередь из actions.json, в UI помечена как симуляция

Как выглядит один ход

Реальный прогон в браузере 2026-09-23 (Chrome → LiveKit → Soniox → GPT-4.1 mini). Клиент говорит смешанной речью и просит две вещи сразу:

🎤 Клиент: «Маған терапевтке жазылу керек, и ещё список клиник в Алматы»

Что увидел супервизор в панели трассы (сокращённый TurnResult, значения из лога прогона):

{
  "turn": 1,
  "transcript": "Маған терапевтке жазылу керек, и ещё список клиник в Алматы.",
  "language": "kk",
  "response_language": "kk",
  "scenarios": [
    {"scenario_id": "SC21", "confidence": 0.9},
    {"scenario_id": "SC23", "confidence": 0.8}
  ],
  "decision": "collect_slots",
  "slots": {"doctor_specialty": "терапевт", "city": "Almaty"},
  "missing_slots": ["policy_number", "preferred_date"],
  "queued_scenarios": ["SC23"],
  "reply": "Полис нөмірі қолыңызда болса, айтып жіберіңізші.",
  "latency_ms": {"stt": null, "router": 1820, "response": 696, "tts_first_audio": null, "total": null}
}

🔊 Агент (на казахском): «Полис нөмірі қолыңызда болса, айтып жіберіңізші» — просит номер полиса ДМС, чтобы записать к терапевту. Список клиник (SC23) ждёт в очереди сессии и исполнится после записи.

Оба намерения распознаны, слоты извлечены из одной фразы, ответ дан на языке клиента. Язык помечен kk, а не mixed: казахских слов больше. null в задержках означает «не измерено», а не «ноль»: worker пока не снимает STT и время до первого звука.

Архитектура

flowchart LR
    subgraph Browser["Браузер · React + Vite"]
        MIC[🎤 Микрофон]
        UI[Чат + панель трассы]
        SPK[🔊 Динамики]
    end

    subgraph Voice["Голосовой контур"]
        LK[LiveKit<br/>WebRTC-сервер]
        W[Voice worker<br/>livekit-agents]
        STT[Soniox STT<br/>stt-rt-v5 · ru/kk]
        TTS[Soniox TTS<br/>tts-rt-v2]
    end

    subgraph Backend["FastAPI · единая бизнес-логика"]
        API["/api/sessions/{id}/turns"]
        SVC[TurnService<br/>сессия · слоты · очередь · политика]
        RT[LLM Router<br/>GPT-4.1 mini]
        EX[Executor<br/>31 действие · preview/execute]
        RP[LLM Reply<br/>GPT-4.1 mini]
        KB[(Каталог + KB + mock_backend<br/>из JSON кита)]
    end

    MIC -->|WebRTC| LK --> W --> STT
    STT -->|текст реплики| API
    UI -->|текстовый резерв| API
    API --> SVC --> RT
    SVC --> EX --> KB
    SVC --> RP
    SVC -->|TurnResult + trace| W
    W -->|data channel saqta.trace| UI
    W --> TTS --> LK --> SPK
СлойТехнологииРоль
FrontendReact 19, TypeScript, Vite, livekit-client, ZodДиалог слева, трасса хода справа. Микрофон, звук, autoplay, восстановление истории
ТранспортLiveKit (локальный, WebRTC)Звук в обе стороны и data channel для трассы
Voice workerlivekit-agents, Soniox STT/TTS, Silero VADРаспознаёт речь, вызывает тот же HTTP /turns, озвучивает ответ
BackendFastAPI, Python 3.12, OpenAI SDKСессии, LLM-router, слоты, политика уверенности, исполнитель, трасса
LLMGPT-4.1 mini, temperature=0Выбор сценариев, извлечение слотов, разбор согласия, реплика агента

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

  • Одна бизнес-логика для голоса и текста. Worker не думает сам, он вызывает тот же POST /turns, что и текстовый ввод. Состояние живёт только в HTTP-сервисе.
  • Исполнитель управляется данными. Интерфейсы действий, необратимость, очереди handoff и коды ошибок берутся из actions.json, формулы — из knowledge_base.json. Каждая сессия работает с собственной копией mock_backend.json в памяти.
  • Голосовой конвейер на LiveKit + Soniox, а страховая логика, роутер и API написаны для кита.
  • Ключи провайдеров только на сервере. Браузер получает токен конкретной комнаты LiveKit на 15 минут.

Как принимается решение

Каждая реплика проходит один и тот же путь:

  1. Router-вызов LLM. В системный промпт входят все 40 сценариев с description и not_this_if, 3 системных намерения, каталог слотов и бизнес-дата 2026-10-01. Модель возвращает строгий JSON: упорядоченные сценарии с confidence, альтернативы, язык, извлечённые слоты, признак продолжения, согласие или отказ на ожидающий preview и краткое обоснование на русском. ID вне каталога отбрасываются.
  2. Политика уверенности из правил кита:
    • confidence ≥ 0.75 → сценарий выбран;
    • 0.45 ≤ confidence < 0.75 или SYS_UNCLEAR → один уточняющий вопрос;
    • два хода подряд ниже 0.45, сценарий с handoff.when = always или просьба клиента → передача оператору с резюме контекста.
  3. Слоты и очередь. Извлечённые слоты проверяются по форматам slots.json. Если не хватает обязательного — один вопрос. Короткий ответ («Алматы») заполняет ожидаемый слот, а не открывает новую тему. Второе и следующие намерения ставятся в очередь сессии, срочные (urgent) обрабатываются первыми. Когда первый сценарий завершён, следующий из очереди исполняется в том же ходу, если его слоты уже известны.
  4. Идентификация. find_client ищет клиента по телефону или ИИН в копии mock_backend.json. Если у клиента ровно один подходящий полис или заявление, номер подставляется без вопроса. Неизвестный клиент: один переспрос, затем handoff по error_handling из actions.json.
  5. Исполнение. Действия с irreversible: true останавливаются на preview: результат считается на копии данных и озвучивается клиенту вместе с параметрами. Согласие или отказ распознаёт LLM в следующей реплике. Исполняются ровно сохранённые параметры; изменение параметров или новая тема снимают старый preview. Обратимые действия выполняются сразу.
  6. Reply-вызов LLM. Отдельный запрос формирует реплику агента: 1–2 предложения, язык клиента, числа словами, имена собственные из KB не переводятся.
  7. Трасса. Всё выше собирается в один TurnResult с turn_id, уходит в UI по data channel и сохраняется в истории сессии.

Метрики

Реальный прогон evaluate.py организаторов на 104 репликах dev-набора. Predictions получены настоящими вызовами GPT-4.1 mini без контекста сессии; поле expected модели не передавалось.

Группаnprimary_accfull_match
all1040.9520.942
lang=kk450.9780.956
lang=ru520.9230.923
lang=mixed71.0001.000
type=single840.9880.988
type=multi_intent130.8460.769
type=out_of_scope41.0001.000
type=unclear30.3330.333

intent_recall для multi-intent: 0.885. Предыдущий прогон того же router дал 0.962 / 0.962: разница в 1–2 реплики — колебания модели.

6 ошибок из 104, все объяснимы:

IDРепликаОжидалосьПолученоПочему
U030«Шетелде аяғымды сындырып алдым, сақтандыруым бар»SC15SC16Травма за границей: соседние сценарии «медслучай за рубежом» и «травма по НС»
U086«Шетелге шығуға сақтандыру керек, қалай төлеуге болады?»SC06 + SC31SC06Пропущено второе намерение «как оплатить»
U087«Отказали в выплате, и ваш оператор ещё и нагрубил»SC19 + SC35SC35Пропущено намерение «спор с решением»
U090«Соседи затопили квартиру, что делать и какие документы собирать?»SC14 + SC18SC14Пропущено второе намерение «документы»
U102«Алло, я по поводу страховки»SYS_UNCLEARSC37Слишком короткая реплика, модель предпочла сценарий
U104«Ну там с машиной вопрос»SYS_UNCLEARSC13То же

10 диалогов кита (case/dialogs_sample.json) прогнаны через живой API скриптом scripts/run_dialogs.py: 40 ходов, 0 ошибок HTTP, средний router 1,7–1,9 с. Полные циклы preview → согласие → execute прошли в D01 (покупка ОГПО, 38 000), D02 (заявление потерпевшего, KK), D07 (расторжение КАСКО, возврат 163 800, KK), D10 (travel, 15 400); идентификация по телефону с автоподстановкой полиса — D03, D05, D07; неизвестный клиент — переспрос и handoff. Промахи router: после «спасибо» модель иногда остаётся в сценарии вместо SYS_GOODBYE, а смену темы после жалобы или фрода (D06 t2, D09 t3) держит в прежнем сценарии.

Dev-набор используется как диагностика, а не как цель подгонки: хардкода проверочных реплик нет. Разница между прогонами в пределах 1–2 реплик — колебания модели.

Задержки на прогретом соединении в браузерном прогоне: router 2,0–3,3 с, генерация ответа 0,7–2,5 с, первый запрос после старта до 9 с (холодное соединение). Сквозная задержка от конца речи до первого звука worker'ом пока не измеряется и честно возвращается как null.

Быстрый старт

Нужны: Python 3.12, uv, Node.js 24, Chrome. Данные сессий живут в памяти и сбрасываются при перезапуске.

Ключи провайдеров (вставить в .env):

  • OPENAI_API_KEY — https://platform.openai.com/api-keys (модель GPT-4.1 mini).
  • SONIOX_API_KEY — зарегистрироваться на https://console.soniox.com, раздел API Keys → Create. Новому аккаунту даётся стартовый бесплатный баланс, его хватает на демо. Один ключ работает и для STT, и для TTS.

1. Backend и LiveKit (Windows, PowerShell):

$env:UV_CACHE_DIR = Join-Path $PWD '.cache/uv'
$env:UV_PYTHON_INSTALL_DIR = Join-Path $PWD '.cache/python'
uv sync --python 3.12 --all-extras --locked
if (-not (Test-Path .env)) { Copy-Item .env.example .env }   # заполнить OPENAI_API_KEY и SONIOX_API_KEY
powershell -ExecutionPolicy Bypass -File scripts/install-livekit.ps1
.venv/Scripts/python scripts/dev.py

На macOS и Linux: те же команды uv sync и копирование .env, вместо install-livekit.ps1 нужен запущенный Docker Desktop, путь к интерпретатору — .venv/bin/python.

Одна команда scripts/dev.py поднимает локальный LiveKit, HTTP API на :8000 и голосовой worker. Swagger: http://127.0.0.1:8000/docs. Установщик скачивает официальный LiveKit 1.13.7 и сверяет SHA-256. Если нативный LiveKit не установлен, dev.py сам поднимет контейнер из deploy/compose.yaml через Docker Desktop. Если LiveKit уже слушает порт 7880, запускать с флагом --external-livekit.

2. Frontend (отдельный терминал):

cd frontend
npm ci
npm run dev

3. Открыть http://127.0.0.1:5174, нажать «Начать разговор», разрешить микрофон, дождаться приветствия и говорить.

Примеры реплик для проверки:

  • RU: «Где ближайший офис в Алматы?»
  • KK: «Алматыдағы кеңселеріңіз қайда?»
  • KK: «Терапевтке жазып қойыңызшы»
  • mixed: «Маған терапевтке жазылу керек, и ещё список клиник в Алматы»
  • preview → согласие: «Хочу расторгнуть КАСКО», затем «да»

Демо-сценарий с подтверждением (клиент Камила, КАСКО SQ-CASCO-204350):

  1. «Продал машину, хочу расторгнуть КАСКО и вернуть деньги» → бот просит номер полиса или телефон.
  2. «Плюс семь семьсот один ноль ноль ноль ноль ноль десять» → find_client находит клиента, полис подставляется сам, бот уточняет причину, если не понял её из первой фразы.
  3. «Продал машину» → в трассе get_policy и cancel_policy preview, заполнен pending_confirmation; бот озвучивает возврат 163 800 тенге и спрашивает подтверждение. Данные ещё не изменены.
  4. «Нет, подождите» → preview снят, ничего не изменилось. «Всё же расторгните» → новый preview.
  5. «Да, подтверждаю» → cancel_policy execute ok, полис в статусе cancelled, повтор «да» ничего не исполняет.

Тестовые клиенты (телефоны +7 701 000 00 XX): 07 — Сергей, статус заявления CL-500330; 08 — Алибек, проверка полиса ОГПО; 09 — Рустем, повторная отправка документов; 02 — Айгерим, запись к терапевту (ДМС, Астана); 99 — нет в базе, переспрос и оператор. Полный список — case/mock_backend.json.

Без голосового контура: scripts/dev.py --text-only запускает только API. Текстовый ввод в UI работает как резервный канал. API стартует без ключей, но запрос к LLM вернёт 503: mock-успеха вместо провайдера нет. После изменения .env процессы нужно перезапустить.

Проверки

.venv/Scripts/python -m pytest -q                     # 43 backend-тестов: router, service, executor, API, voice
.venv/Scripts/python scripts/evaluate_router.py       # predictions реальным LLM → artifacts/
.venv/Scripts/python case/evaluate.py artifacts/predictions.json case/dev_utterances.json
.venv/Scripts/python scripts/run_dialogs.py           # 10 диалогов кита через живой API → отчёт
.venv/Scripts/python scripts/smoke_transport.py       # API + LiveKit подключение
cd frontend && npm test && npm run build              # 28 unit-тестов

Автоматическая браузерная приёмка голоса: node scripts/e2e_live_voice.mjs <реплика.wav> <папка отчёта> при запущенных dev.py и npm run dev. Скрипт подаёт WAV в fake-микрофон Chrome, проходит весь путь через LiveKit и worker, сохраняет лог и скриншот.

Результаты браузерного прогона 2026-09-23:

РепликаSTTRouterОтвет
RU «Где ближайший офис в Алматы?»дословноSC33 execute, city=Almatyадрес и часы, RU
KK «Алматыдағы кеңселеріңіз қайда?»дословноSC33 executeадрес и часы, KK
KK «Терапевтке жазып қойыңызшы»дословноSC21 collect_slotsпросит номер полиса, KK
mixed «Маған терапевтке жазылу керек, и ещё список клиник»дословноSC21 + очередь SC23KK, язык помечен kk

В одном из шести прогонов первый ход получил 503 от LLM: интерфейс показал ошибку с request_id, агент озвучил «Не удалось обработать реплику», фиктивного ответа не было.

Unit-тесты подменяют LLM и HTTP и проверяют логику, а не качество речи. Всё, что требует провайдеров, проверялось живыми вызовами.

Ограничения

Пишем честно, потому что это влияет на оценку:

  • Сквозная задержка не измеряется: stt, tts_first_audio, total возвращаются как null.
  • Короткие неясные реплики («Алло, я по поводу страховки») модель иногда относит к сценарию вместо SYS_UNCLEAR.
  • Mixed иногда помечается как kk, если казахских слов больше. На язык ответа это не влияет.
  • Зона travel определяется списком стран в коде: база знаний даёт только описание зон. check_coverage сравнивает услугу с пакетом по ключевым словам.
  • Согласие и отказ разбирает LLM в составе router-вызова, отдельного классификатора нет.
  • После завершённого сценария короткое «спасибо» или смена темы иногда остаются в прежнем сценарии: router получает историю и слоты сессии и предпочитает продолжение.
  • Телефон казахскими числительными («жеті жүз бір…») распознаётся нестабильно; неверный формат отбрасывается и переспрашивается, а не подставляется.
  • Если клиент начинает говорить во время приветствия агента, STT может потерять первое слово. Система переспрашивает, а не угадывает.
  • Удалённый доступ требует HTTPS/WSS и не настроен: демо работает на localhost.

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

backend/          FastAPI: app.py (HTTP), service.py (сессии, политика, слоты, preview/confirm),
                  executor.py (31 действие над mock_backend), router.py (LLM-router и reply),
                  voice.py (LiveKit worker), catalog.py (загрузка JSON кита)
frontend/         React + Vite симулятор: чат, микрофон, панель трассы, LiveKit-клиент
scripts/          dev.py (запуск всего), evaluate_router.py, run_dialogs.py,
                  e2e_live_voice.mjs, smoke_transport.py, install-livekit.ps1
tests/backend/    pytest: router, service, executor, API и voice-адаптер
case/             вводные организаторов без изменений: 7 JSON-файлов данных, evaluate.py,
                  README кита (en/ru/kz), task-original.txt — исходный текст задания
ТЗ/               api-contract.md — контракт API v2 между frontend и backend
deploy/           compose.yaml — LiveKit в Docker, если нативный сервер не установлен

Команда и документы

Alt-Tab. Backend, LLM, исполнитель и голосовой контур — Акежан. Frontend и браузерный симулятор — тиммейт команды.

ДокументСодержание
ТЗ/api-contract.mdКонтракт API v2 между frontend и backend
frontend/README.mdСимулятор: запуск, режимы Live/Mock, обработка ошибок
Звёзды
⭐ 0
Форки
0
Язык
Python
Последний push
в прошлом месяце
Коммиты
28
Авторы
2
Файлы
74
Ветки
3

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

Акежан 25Almas 3

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

  • 2026-09-23 17:49README: запуск на macOS/Linux, откуда взять ключи OpenAI и SonioxАкежан
  • 2026-09-23 17:40Voice: приветствие агента на казахскомАкежан
  • 2026-09-23 17:38Репозиторий: чистка документации, compose.yaml перенесён в deploy/Акежан
  • 2026-09-23 17:30Frontend: кнопка голоса читаема после нажатия, виден статус подключенияАкежан
  • 2026-09-23 17:29Voice: скорость TTS 1.1Акежан
  • 2026-09-23 17:23README: метрики после B3, демо-сценарий с подтверждением, итоги прогона 10 диалоговАкежан
  • 2026-09-23 17:12B3: правки по живому прогону 10 диалоговАкежан
  • 2026-09-23 16:54Вводные организаторов собраны в case/Акежан
Все коммиты (28)
  • 2026-09-23 16:51README: убрать ссылки на документы вне GitАкежан
  • 2026-09-23 16:51README: главный README проекта для жюри вместо README кита и README.app.mdАкежан
  • 2026-09-23 16:48B3: data-driven исполнитель 31 действия, идентификация, preview → согласие → executeАкежан
  • 2026-09-23 16:23Reply: имена собственные из KB транслитерировать, не подменять; temperature 0Акежан
  • 2026-09-23 16:18README: метрики evaluate.py после правил языкаАкежан
  • 2026-09-23 16:17Router: явные правила языка реплики и языка ответаАкежан
  • 2026-09-23 16:15Скрипт браузерной приёмки голоса и README после слияния frontendАкежан
  • 2026-09-23 16:13Merge codex/backend-router: backend, LLM-router, LiveKit workerАкежан
  • 2026-09-23 16:13Merge codex/frontend-simulator: браузерный симулятор с LiveKitАкежан
  • 2026-09-23 16:04README: транзиентный 503 в браузерном прогоне и его обработкаАкежан
  • 2026-09-23 16:04API: логировать класс причины ProviderError без тела ответа провайдераАкежан
  • 2026-09-23 16:00Браузерный голос проверен на frontend тиммейта: voice_ready по конфигурацииАкежан
  • 2026-09-23 15:49feat(frontend): implement Saqta simulator with LiveKit v2Almas
  • 2026-09-23 15:29README: метрики реального прогона evaluate.pyАкежан
  • 2026-09-23 15:27Контракт API v2 в репозитории для frontendАкежан
  • 2026-09-23 15:22Исправления по code review: комната worker, валидация слотов, handoff из каталогаАкежан
  • 2026-09-23 15:11README: статус живой проверки OpenAI и SonioxАкежан
  • 2026-09-23 15:07Backend: FastAPI, LLM-router 40+3, сессии, LiveKit-адаптерАкежан
  • 2026-09-23 14:46feat(frontend): scaffold Saqta simulator and typed REST contractAlmas
  • 2026-09-23 13:56Вводные данныеAlmas
Структура репозитория (74 файлов)
.env.example
.gitignore
README.md
backend/__init__.py
backend/app.py
backend/catalog.py
backend/config.py
backend/executor.py
backend/models.py
backend/router.py
backend/service.py
backend/voice.py
case/README.kz.md
case/README.md
case/README.ru.md
case/actions.json
case/dev_utterances.json
case/dialogs_sample.json
case/evaluate.py
case/knowledge_base.json
case/mock_backend.json
case/scenarios.json
case/slots.json
case/task-original.txt
deploy/compose.yaml
frontend/.env.example
frontend/.gitattributes
frontend/.gitignore
frontend/DESIGN.md
frontend/PLAN.md
frontend/README.md
frontend/e2e/simulator.spec.ts
frontend/index.html
frontend/package-lock.json
frontend/package.json
frontend/playwright.config.ts
frontend/src/App.test.tsx
frontend/src/App.tsx
frontend/src/api/client.test.ts
frontend/src/api/client.ts
frontend/src/api/mock.ts
frontend/src/api/types.ts
frontend/src/components/Icon.tsx
frontend/src/components/TracePanel.tsx
frontend/src/components/VoiceControls.test.tsx
frontend/src/components/VoiceControls.tsx
frontend/src/data/labels.ts
frontend/src/data/scenarios.json
frontend/src/data/slots.json
frontend/src/main.tsx
frontend/src/styles.css
frontend/src/test/fixture.ts
frontend/src/test/setup.ts
frontend/src/ui.css
frontend/src/useConversation.test.ts
frontend/src/useConversation.ts
frontend/src/voice/livekit.test.ts
frontend/src/voice/livekit.ts
frontend/tsconfig.json
frontend/vite.config.ts
frontend/vitest.config.ts
pyproject.toml
scripts/dev.py
scripts/e2e_live_voice.mjs
scripts/evaluate_router.py
scripts/install-livekit.ps1
scripts/run_dialogs.py
scripts/smoke_transport.py
tests/backend/test_api_voice.py
tests/backend/test_executor.py
tests/backend/test_router.py
tests/backend/test_service.py
uv.lock
ТЗ/api-contract.md
Ветки (3)

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

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

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