arys 99d169ec67 fix: stop the no-answer retry from racing the dialplan hangup + fix event catalog validation
Two bugs found via a live test with two real registered browser softphones:

1. retry_escalation_no_answer() re-resolved the client channel via
   _resolve_handoff_channel() -> a live AMI CoreShowChannels round-trip that
   can take ~10s. The new mvpcc-transfer dialplan wait window (MusicOnHold,
   also ~10s, added to give the backend time to redirect before the final
   Hangup) was consistently LOST to this exact same duration: the backend's
   AMI Redirect fired against a channel the dialplan had already hung up
   ('Channel does not exist: PJSIP/...', confirmed in escalation timeline).
   Fixed by reusing the actively-maintained AsteriskCallLinkRow.channel_name
   directly (unchanged for a PJSIP channel across Redirect between contexts
   of the same call) instead of re-discovering it, falling back to the slow
   path only if that field is empty.

2. VoiceEventIn.event_type is a pydantic Literal restricted to 6 legacy
   values (call.started/ivr.completed/...). None of the Phase 2 event
   catalog names (AgentReserved/AgentRinging/AgentNoAnswer/AgentConnected/
   TransferCompleted/TransferFailed) were ever in it, so every single
   _emit_escalation_event() call has been failing with 422 since Phase 2
   shipped (swallowed silently by the broad except there) - confirmed by
   calling app._emit_voice_event() directly against the running service.
   Extended the Literal to include all six.
2026-08-31 01:03:47 +05:00
2026-05-09 09:16:06 +05:00
2026-05-09 09:16:06 +05:00

call-center

Омниканальный контакт-центр: телефония (Asterisk), Telegram, WhatsApp, веб-чат, email — плюс встроенный голосовой ИИ-оператор (распознавание речи → LLM → синтез речи). Написан на Python (FastAPI), ~25 сервисов вокруг одной SQLAlchemy-схемы, локально работает на SQLite, в проде — на PostgreSQL.

Документация

Документ Про что
docs/architecture/overview.md Обзор микросервисов и их ролей
docs/architecture/voice-ai.md Голосовой ИИ-оператор подробно
docs/architecture/real-time-voice-service.md Рантайм голосового моста (AudioSocket, TTS/ASR)
docs/architecture/event-schemas.md Схемы событий шины (RabbitMQ)
docs/runbooks/local-setup.md Как поднять проект локально (демо-режим и ручной запуск)
docs/runbooks/deployment.md Как разворачивать (Docker Compose / Kubernetes)
longread.md Сквозной архитектурный ревью репозитория — что реально есть, где технический долг

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

Подробности — в docs/runbooks/local-setup.md. Коротко:

python -m pip install -r requirements.txt
cp .env.example .env      # по умолчанию SQLite, без Docker

python scripts/migrate_core_db.py
uvicorn gateway.app:app --reload --port 8080

Точки входа (после старта gateway): /operator, /supervisor, /admin, /analyst на http://localhost:8080.

Демо-режим одной командой (поднимает весь стек + тестовые данные): scripts/prepare_demo.ps1.

Тесты

pytest -q

Частые задачи

  • Поменять greeting/system prompt голосового бота Айнур — правится в коде: services/shared/ai_operator_config.pyai_operator_default_config(), коммит и деплой; сервис сам синкает значение в БД при старте.
S
Description
migrated from gitlab.konturai.kz
Readme
3.3 MiB
Languages
Python 74.2%
JavaScript 18.8%
HTML 3.4%
CSS 2.9%
PowerShell 0.4%
Other 0.3%