From f5b4d03c951058d32a171a0f8ee73c783eecab12 Mon Sep 17 00:00:00 2001 From: konturai-ops Date: Mon, 10 Aug 2026 15:27:43 +0000 Subject: [PATCH] sync: migrate aimaq-call-center deployment config to Gitea (2026-08-10) --- .gitignore | 18 ++ deploy-backend.sh | 72 ++++++ deploy-frontend.sh | 40 +++ deploy-voice-ai.sh | 41 +++ docker-compose.aimaq.override.yml | 8 + docker-compose.minimal.yml | 212 ++++++++++++++++ docker-compose.override.yml | 38 +++ docker-compose.yml | 400 ++++++++++++++++++++++++++++++ frontend.nginx.conf | 68 +++++ 9 files changed, 897 insertions(+) create mode 100644 .gitignore create mode 100755 deploy-backend.sh create mode 100755 deploy-frontend.sh create mode 100755 deploy-voice-ai.sh create mode 100644 docker-compose.aimaq.override.yml create mode 100644 docker-compose.minimal.yml create mode 100644 docker-compose.override.yml create mode 100644 docker-compose.yml create mode 100644 frontend.nginx.conf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6370798 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# deployment artifacts only — no secrets, no runtime data, no media +.env +.env.* +!.env.example +.data_pg/ +.data_local/ +.models/ +*.wav +*.pdf +*.pcm +*.pid +*.opts +*.bak-* +*.bak +*.TAG +__pycache__/ +*.pyc + diff --git a/deploy-backend.sh b/deploy-backend.sh new file mode 100755 index 0000000..f96db50 --- /dev/null +++ b/deploy-backend.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -euo pipefail + +DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SRC_DIR="/opt/konturai-migration/call-center-src" +IMAGE="call-center-app:active-aimaq" + +SERVICES=( + auth-service + audit-service + customer-service + interaction-service + voice-adapter-service + recording-service + reporting-service + sales-service + asterisk-bridge-service + api-gateway +) + +echo "" +echo "=== AIMAQ BACKEND DEPLOY ===" +echo "Источник : $SRC_DIR" +echo "Образ : $IMAGE" +echo "" + +# 1. Сборка образа +echo "[1/4] Сборка Docker образа..." +docker build -t "$IMAGE" "$SRC_DIR" +echo " Готово." + +# 2. Миграции БД +echo "[2/4] Запуск миграций БД..." +cd "$DEPLOY_DIR" +docker compose -f docker-compose.minimal.yml run --rm migrate +echo " Готово." + +# 3. Перезапуск сервисов +echo "[3/4] Перезапуск сервисов..." +docker compose -f docker-compose.minimal.yml up -d --no-deps --force-recreate "${SERVICES[@]}" +echo " Готово." + +# 4. Проверка +echo "[4/4] Проверка..." +sleep 5 +FAILED=() +for SERVICE in "${SERVICES[@]}"; do + CONTAINER="aimaq-call-center-${SERVICE}-1" + # api-gateway имеет отдельное имя + if [ "$SERVICE" = "api-gateway" ]; then + CONTAINER="aimaq-call-center-app" + fi + STATUS=$(docker inspect --format '{{.State.Status}}' "$CONTAINER" 2>/dev/null || echo "not found") + if [ "$STATUS" != "running" ]; then + FAILED+=("$SERVICE ($STATUS)") + fi +done + +if [ ${#FAILED[@]} -eq 0 ]; then + echo " Все сервисы запущены." +else + echo " ОШИБКА: следующие сервисы не запустились:" + for F in "${FAILED[@]}"; do + echo " - $F" + done + exit 1 +fi + +echo "" +echo "=== ДЕПЛОЙ ЗАВЕРШЁН ===" +echo "API: https://aimaq.konturai.kz/proxy/" +echo "" diff --git a/deploy-frontend.sh b/deploy-frontend.sh new file mode 100755 index 0000000..720111e --- /dev/null +++ b/deploy-frontend.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SRC_DIR="/tmp/cc-frontend-build" +IMAGE="omnichannel-contact-center:active-aimaq" + +echo "" +echo "=== AIMAQ FRONTEND DEPLOY ===" +echo "Источник : $SRC_DIR" +echo "Образ : $IMAGE" +echo "" + +# 1. Сборка образа +echo "[1/3] Сборка Docker образа..." +docker build -t "$IMAGE" "$SRC_DIR" +echo " Готово." + +# 2. Перезапуск контейнера +echo "[2/3] Перезапуск контейнера..." +cd "$DEPLOY_DIR" +docker compose -f docker-compose.minimal.yml up -d --no-deps --force-recreate frontend +echo " Готово." + +# 3. Проверка +echo "[3/3] Проверка..." +sleep 3 +STATUS=$(docker inspect --format '{{.State.Status}}' aimaq-call-center-frontend 2>/dev/null || echo "not found") +if [ "$STATUS" = "running" ]; then + echo " Контейнер запущен." +else + echo " ВНИМАНИЕ: контейнер в статусе '$STATUS'" + docker logs --tail 20 aimaq-call-center-frontend + exit 1 +fi + +echo "" +echo "=== ДЕПЛОЙ ЗАВЕРШЁН ===" +echo "Сайт: https://aimaq.konturai.kz" +echo "" diff --git a/deploy-voice-ai.sh b/deploy-voice-ai.sh new file mode 100755 index 0000000..98535ae --- /dev/null +++ b/deploy-voice-ai.sh @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +# Deploy script: voice-ai backend + updated frontend (nginx + React) +set -euo pipefail + +DEPLOY_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +VOICE_AI_SRC="/root/voice-call-center-ai" +FRONTEND_SRC="/tmp/cc-frontend-build" + +VOICE_AI_IMAGE="voice-call-center-ai:active-aimaq" +FRONTEND_IMAGE="omnichannel-contact-center:active-aimaq" + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " Step 1/4 — Build voice-ai Docker image" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +docker build -t "$VOICE_AI_IMAGE" "$VOICE_AI_SRC" + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " Step 2/4 — Build frontend Docker image (React + nginx)" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +docker build -t "$FRONTEND_IMAGE" "$FRONTEND_SRC" + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " Step 3/4 — Start voice-ai + restart frontend" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +cd "$DEPLOY_DIR" +docker compose -f docker-compose.minimal.yml up -d --force-recreate voice-ai frontend + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " Step 4/4 — Container status" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +docker compose -f docker-compose.minimal.yml ps voice-ai frontend + +echo "" +echo "✓ Done. Voice AI available via wss://aimaq.konturai.kz/voice-ai/ws" +echo "" +echo " ⚠ API keys must be set in: $DEPLOY_DIR/.env.voice-ai" +echo " OPENAI_API_KEY=..." +echo " ELEVENLABS_API_KEY=..." diff --git a/docker-compose.aimaq.override.yml b/docker-compose.aimaq.override.yml new file mode 100644 index 0000000..5cc6eea --- /dev/null +++ b/docker-compose.aimaq.override.yml @@ -0,0 +1,8 @@ +services: + asterisk-bridge-service: + environment: + AI_VOICE_ENABLED: "1" + AI_VOICE_RUNTIME_SERVICE_URL: "http://92.38.48.166:8002" + SALES_VOICE_RUNTIME_ENABLED: "1" + ASTERISK_CALLCONTROL_ENABLED: "1" + ASTERISK_WEBRTC_ENABLED: "1" diff --git a/docker-compose.minimal.yml b/docker-compose.minimal.yml new file mode 100644 index 0000000..f50e41f --- /dev/null +++ b/docker-compose.minimal.yml @@ -0,0 +1,212 @@ +name: aimaq-call-center + +x-app-env: &app_env + CC_DATA_DIR: /app/.data_local + DATABASE_URL: postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} + SCHEMA_MANAGEMENT_MODE: migrations + AUTH_SERVICE_URL: http://auth-service:8000 + AUDIT_SERVICE_URL: http://audit-service:8000 + CUSTOMER_SERVICE_URL: http://customer-service:8000 + INTERACTION_SERVICE_URL: http://interaction-service:8000 + VOICE_ADAPTER_SERVICE_URL: http://voice-adapter-service:8000 + RECORDING_SERVICE_URL: http://recording-service:8000 + ASTERISK_BRIDGE_SERVICE_URL: http://asterisk-bridge-service:8000 + SALES_SERVICE_URL: http://sales-service:8000 + REPORTING_SERVICE_URL: http://reporting-service:8000 + LOCAL_STACK_PUBLIC_BASE_URL: https://aimaq.konturai.kz + ASTERISK_WEBRTC_WS_URL: wss://aimaq.konturai.kz/asterisk-ws + ASTERISK_CALLCONTROL_ENABLED: "0" + ASTERISK_IVR_FASTAGI_ENABLED: "0" + ASTERISK_WEBRTC_ENABLED: "0" + TELEGRAM_BOT_ENABLED: "0" + AI_TELEGRAM_ENABLED: "0" + WHATSAPP_OUTBOUND_ENABLED: "0" + AI_WHATSAPP_ENABLED: "0" + SALES_TELEGRAM_BRIDGE_ENABLED: "0" + EVENT_BUS_ENABLED: "0" + EVENT_BUS_CONSUMER_ENABLED: "0" + AI_VOICE_ENABLED: "0" + AI_VOICE_AUDIOSOCKET_ENABLED: "0" + SALES_VOICE_RUNTIME_ENABLED: "1" + ERROR_TELEGRAM_ALERTS: "0" + +x-service-defaults: &service_defaults + image: ${CALL_CENTER_IMAGE:-call-center-app:active-aimaq} + restart: unless-stopped + env_file: + - ./.env.production + environment: + <<: *app_env + volumes: + - ./.data_local:/app/.data_local + extra_hosts: + - host.docker.internal:host-gateway + +services: + postgres: + image: postgres:16-alpine + container_name: aimaq-call-center-postgres + restart: unless-stopped + env_file: + - ./.env + volumes: + - ./.data_pg:/var/lib/postgresql/data + healthcheck: + test: + - CMD-SHELL + - pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB" + interval: 10s + timeout: 5s + retries: 12 + start_period: 15s + + migrate: + <<: *service_defaults + restart: "no" + depends_on: + postgres: + condition: service_healthy + command: ["python", "scripts/migrate_core_db.py"] + + auth-service: + <<: *service_defaults + depends_on: + - postgres + environment: + <<: *app_env + APP_MODULE: services.auth_service.app:app + + audit-service: + <<: *service_defaults + depends_on: + - postgres + environment: + <<: *app_env + APP_MODULE: services.audit_service.app:app + + customer-service: + <<: *service_defaults + depends_on: + - postgres + environment: + <<: *app_env + APP_MODULE: services.customer_service.app:app + + interaction-service: + <<: *service_defaults + depends_on: + - postgres + environment: + <<: *app_env + APP_MODULE: services.interaction_service.app:app + + voice-adapter-service: + <<: *service_defaults + depends_on: + - postgres + environment: + <<: *app_env + APP_MODULE: services.voice_adapter_service.app:app + + recording-service: + <<: *service_defaults + depends_on: + - postgres + environment: + <<: *app_env + APP_MODULE: services.recording_service.app:app + CC_RECORDINGS_DIR: /app/.data_local/recordings + RECORDING_MAX_BYTES: 26214400 + + reporting-service: + <<: *service_defaults + depends_on: + - postgres + environment: + <<: *app_env + APP_MODULE: services.reporting_service.app:app + + sales-service: + <<: *service_defaults + depends_on: + - postgres + environment: + <<: *app_env + APP_MODULE: services.sales_service.app:app + SALES_AUTOMATION_WORKER_ENABLED: "1" + SALES_AUTOMATION_WORKER_INTERVAL_SECONDS: "5" + SALES_POST_CALL_AI_ENABLED: "1" + SALES_VOICE_RUNTIME_ENABLED: "1" + SALES_TELEGRAM_BRIDGE_ENABLED: "0" + + asterisk-bridge-service: + <<: *service_defaults + depends_on: + - postgres + - interaction-service + - voice-adapter-service + - sales-service + environment: + <<: *app_env + APP_MODULE: services.asterisk_bridge_service.app:app + ASTERISK_BRIDGE_ENABLED: "1" + ASTERISK_BRIDGE_FAILED_RETRY_ENABLED: "0" + AI_VOICE_ENABLED: "0" + SALES_VOICE_RUNTIME_ENABLED: "1" + ports: + - "8036:8000" + + api-gateway: + <<: *service_defaults + container_name: aimaq-call-center-app + depends_on: + - auth-service + - audit-service + - customer-service + - interaction-service + - voice-adapter-service + - recording-service + - reporting-service + - sales-service + - asterisk-bridge-service + environment: + <<: *app_env + APP_MODULE: gateway.app:app + + frontend: + image: ${CALL_CENTER_FRONTEND_IMAGE:-omnichannel-contact-center:active-aimaq} + container_name: aimaq-call-center-frontend + restart: unless-stopped + depends_on: + - api-gateway + - voice-ai + ports: + - "127.0.0.1:3082:80" + volumes: + - ./frontend.nginx.conf:/etc/nginx/conf.d/default.conf:ro + networks: + - default + - common_network + + voice-ai: + image: ${VOICE_AI_IMAGE:-voice-call-center-ai:active-aimaq} + container_name: aimaq-voice-ai + restart: unless-stopped + env_file: + - ./.env.voice-ai + ports: + # AudioSocket-шлюз для входящих звонков из Asterisk (хост-процесс) + - "127.0.0.1:9094:9094" + volumes: + - /root/voice-call-center-ai/knowledge:/app/knowledge:ro + # CALLERID входящего звонка: диалплан пишет .callerid, шлюз читает и удаляет + - /tmp/ainur-meta:/ainur-meta + networks: + - default + - common_network + +networks: + default: + name: aimaq-call-center_default + common_network: + external: true diff --git a/docker-compose.override.yml b/docker-compose.override.yml new file mode 100644 index 0000000..8484466 --- /dev/null +++ b/docker-compose.override.yml @@ -0,0 +1,38 @@ +services: + ai-voice-runtime-service: + environment: + - AI_VOICE_V2_STREAMING_ASR_BACKEND=elevenlabs_realtime + - AI_VOICE_ASR_PROVIDER=elevenlabs + - AI_VOICE_START_DEFAULT_LANGUAGE_ON_UNCLEAR=ru + - AI_VOICE_V2_PARTIAL_ASR=1 + - AI_VOICE_V2_DUPLEX_ENABLED=1 + - AI_VOICE_V2_STREAMING_ASR_TIMEOUT_SECONDS=15 + - AI_VOICE_V2_STREAMING_ASR_SUPPORTED_LANGUAGES=ru,kk + - AI_VOICE_VAD_RMS_THRESHOLD=800 + - AI_VOICE_VAD_MIN_SPEECH_MS=300 + - AI_VOICE_VAD_TRAILING_SILENCE_MS=500 + ports: + - 127.0.0.1:9019:9019 + volumes: + - /tmp/asr_modified.py:/app/services/ai_voice_runtime_service/providers/asr.py:ro + asterisk-bridge-service: + environment: + - ASTERISK_AMI_HOST=172.19.0.1 + - ASTERISK_BRIDGE_ENABLED=1 + - ASTERISK_SFTP_HOST=172.19.0.1 + - MVPCC_AI_AUDIOSOCKET_SERVICE=127.0.0.1:9019 + sales-service: + environment: + - WHATSAPP_OUTBOUND_ENABLED=1 + - SALES_VOICE_RUNTIME_ENABLED=1 + telegram-adapter-service: + environment: + - TELEGRAM_BOT_ENABLED=1 + - AI_TELEGRAM_ENABLED=1 + - SALES_TELEGRAM_BRIDGE_ENABLED=1 + - SALES_VOICE_RUNTIME_ENABLED=1 + whatsapp-adapter-service: + environment: + - WHATSAPP_OUTBOUND_ENABLED=1 + - AI_WHATSAPP_ENABLED=1 + - SALES_VOICE_RUNTIME_ENABLED=1 diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..328d808 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,400 @@ +name: aimaq-call-center + +x-app-env: &app_env + CC_DATA_DIR: /app/.data_local + DATABASE_URL: postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB} + SCHEMA_MANAGEMENT_MODE: migrations + AUTH_SERVICE_URL: http://auth-service:8000 + AUDIT_SERVICE_URL: http://audit-service:8000 + CUSTOMER_SERVICE_URL: http://customer-service:8000 + INTERACTION_SERVICE_URL: http://interaction-service:8000 + ROUTING_SERVICE_URL: http://routing-service:8000 + VOICE_ADAPTER_SERVICE_URL: http://voice-adapter-service:8000 + RECORDING_SERVICE_URL: http://recording-service:8000 + IVR_SERVICE_URL: http://ivr-service:8000 + EVENT_BUS_SERVICE_URL: http://event-bus-service:8000 + ASTERISK_BRIDGE_SERVICE_URL: http://asterisk-bridge-service:8000 + TELEGRAM_ADAPTER_SERVICE_URL: http://telegram-adapter-service:8000 + WHATSAPP_ADAPTER_SERVICE_URL: http://whatsapp-adapter-service:8000 + AI_ORCHESTRATOR_SERVICE_URL: http://ai-orchestrator-service:8000 + AI_VOICE_RUNTIME_SERVICE_URL: http://ai-voice-runtime-service:8000 + WEBCHAT_ADAPTER_SERVICE_URL: http://webchat-adapter-service:8000 + EMAIL_ADAPTER_SERVICE_URL: http://email-adapter-service:8000 + KB_SERVICE_URL: http://kb-service:8000 + REPORTING_SERVICE_URL: http://reporting-service:8000 + SUPERVISOR_SERVICE_URL: http://supervisor-service:8000 + SALES_SERVICE_URL: http://sales-service:8000 + LOCAL_STACK_PUBLIC_BASE_URL: https://aimaq.konturai.kz + ASTERISK_WEBRTC_WS_URL: wss://aimaq.konturai.kz/asterisk-ws + ASTERISK_BRIDGE_ENABLED: "0" + ASTERISK_CALLCONTROL_ENABLED: "0" + ASTERISK_IVR_FASTAGI_ENABLED: "0" + ASTERISK_WEBRTC_ENABLED: "0" + TELEGRAM_BOT_ENABLED: "0" + AI_TELEGRAM_ENABLED: "0" + WHATSAPP_OUTBOUND_ENABLED: "0" + AI_WHATSAPP_ENABLED: "0" + SALES_TELEGRAM_BRIDGE_ENABLED: "0" + SALES_VOICE_RUNTIME_ENABLED: "0" + AI_VOICE_ENABLED: "0" + AI_VOICE_AUDIOSOCKET_ENABLED: "0" + ERROR_TELEGRAM_ALERTS: "0" + EVENT_BUS_ENABLED: "0" + EVENT_BUS_CONSUMER_ENABLED: "0" + AI_VOICE_ASR_PROVIDER: ${AI_VOICE_ASR_PROVIDER:-elevenlabs} + AI_VOICE_TTS_PROVIDER: ${AI_VOICE_TTS_PROVIDER:-elevenlabs} + AI_VOICE_V2_STREAMING_ASR_BACKEND: ${AI_VOICE_V2_STREAMING_ASR_BACKEND:-elevenlabs_realtime} + AI_VOICE_V2_STREAMING_ASR_BASE_URL: http://streaming-asr-sidecar:8021 + AI_VOICE_V2_STREAMING_ASR_TIMEOUT_SECONDS: "4" + AI_VOICE_V2_STREAMING_ASR_PARTIAL_POLL_ENABLED: "1" + +x-service-defaults: &service_defaults + image: ${CALL_CENTER_IMAGE:-call-center-app:active-main} + restart: unless-stopped + env_file: + - ./.env.production + environment: + <<: *app_env + volumes: + - ./.data_local:/app/.data_local + extra_hosts: + - host.docker.internal:host-gateway + healthcheck: + test: + - CMD + - python + - -c + - | + from urllib.request import urlopen + import sys + sys.exit(0 if urlopen("http://127.0.0.1:8000/health", timeout=2).getcode() == 200 else 1) + interval: 15s + timeout: 5s + retries: 10 + start_period: 10s + +services: + postgres: + image: postgres:16-alpine + container_name: aimaq-call-center-postgres + restart: unless-stopped + env_file: + - ./.env + volumes: + - ./.data_pg:/var/lib/postgresql/data + healthcheck: + test: + - CMD-SHELL + - pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB" + interval: 10s + timeout: 5s + retries: 12 + start_period: 15s + + migrate: + <<: *service_defaults + restart: "no" + depends_on: + postgres: + condition: service_healthy + command: ["python", "scripts/migrate_core_db.py"] + healthcheck: + disable: true + + auth-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.auth_service.app:app + + audit-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.audit_service.app:app + + customer-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.customer_service.app:app + + interaction-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.interaction_service.app:app + + routing-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.routing_service.app:app + + voice-adapter-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.voice_adapter_service.app:app + + recording-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.recording_service.app:app + CC_RECORDINGS_DIR: /app/.data_local/recordings + RECORDING_MAX_BYTES: 26214400 + + ivr-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.ivr_service.app:app + + telegram-adapter-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.telegram_adapter_service.app:app + + whatsapp-adapter-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.whatsapp_adapter_service.app:app + + ai-orchestrator-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.ai_orchestrator_service.app:app + + streaming-asr-sidecar: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + command: ["sh", "-c", "uvicorn $${APP_MODULE} --host 0.0.0.0 --port 8021"] + environment: + <<: *app_env + APP_MODULE: services.streaming_asr_sidecar_service.app:app + AI_VOICE_V2_STREAMING_ASR_MODEL: base + AI_VOICE_V2_STREAMING_ASR_COMPUTE_TYPE: int8 + AI_VOICE_V2_STREAMING_ASR_DEVICE: cpu + AI_VOICE_V2_STREAMING_ASR_CACHE_DIR: /models/faster_whisper + AI_VOICE_V2_STREAMING_ASR_SUPPORTED_LANGUAGES: ru + volumes: + - ./.data_local:/app/.data_local + - ./.models/faster_whisper:/models/faster_whisper + healthcheck: + test: + - CMD + - python + - -c + - | + from urllib.request import urlopen + import sys + sys.exit(0 if urlopen("http://127.0.0.1:8021/health", timeout=2).getcode() == 200 else 1) + interval: 15s + timeout: 5s + retries: 10 + start_period: 10s + + ai-voice-runtime-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + streaming-asr-sidecar: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.ai_voice_runtime_service.app:app + AI_VOICE_ENABLED: "1" + AI_VOICE_AUDIOSOCKET_ENABLED: "1" + SALES_VOICE_RUNTIME_ENABLED: "1" + ports: + - "9023:9019" + + webchat-adapter-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.webchat_adapter_service.app:app + + email-adapter-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.email_adapter_service.app:app + + kb-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.kb_service.app:app + + reporting-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.reporting_service.app:app + + supervisor-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.supervisor_service.app:app + + sales-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.sales_service.app:app + SALES_TELEGRAM_BRIDGE_ENABLED: "0" + SALES_VOICE_RUNTIME_ENABLED: "1" + + event-bus-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.event_bus_service.app:app + + asterisk-bridge-service: + <<: *service_defaults + depends_on: + postgres: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: services.asterisk_bridge_service.app:app + ASTERISK_IVR_FASTAGI_HOST: 0.0.0.0 + ASTERISK_IVR_FASTAGI_PORT: 4573 + ASTERISK_BRIDGE_ENABLED: "1" + AI_VOICE_ENABLED: "1" + ASTERISK_BRIDGE_FAILED_RETRY_ENABLED: "0" + ports: + - "8036:8000" + + api-gateway: + <<: *service_defaults + container_name: aimaq-call-center-app + depends_on: + auth-service: + condition: service_healthy + audit-service: + condition: service_healthy + customer-service: + condition: service_healthy + interaction-service: + condition: service_healthy + routing-service: + condition: service_healthy + voice-adapter-service: + condition: service_healthy + recording-service: + condition: service_healthy + ivr-service: + condition: service_healthy + telegram-adapter-service: + condition: service_healthy + whatsapp-adapter-service: + condition: service_healthy + ai-orchestrator-service: + condition: service_healthy + ai-voice-runtime-service: + condition: service_healthy + webchat-adapter-service: + condition: service_healthy + email-adapter-service: + condition: service_healthy + kb-service: + condition: service_healthy + reporting-service: + condition: service_healthy + supervisor-service: + condition: service_healthy + sales-service: + condition: service_healthy + event-bus-service: + condition: service_healthy + asterisk-bridge-service: + condition: service_healthy + environment: + <<: *app_env + APP_MODULE: gateway.app:app + + frontend: + image: ${CALL_CENTER_FRONTEND_IMAGE:-omnichannel-contact-center:latest} + container_name: aimaq-call-center-frontend + restart: unless-stopped + depends_on: + api-gateway: + condition: service_healthy + ports: + - "127.0.0.1:3082:80" + volumes: + - ./frontend.nginx.conf:/etc/nginx/conf.d/default.conf:ro + networks: + - default + - common_network + +networks: + default: + name: aimaq-call-center_default + common_network: + external: true diff --git a/frontend.nginx.conf b/frontend.nginx.conf new file mode 100644 index 0000000..63d4e1c --- /dev/null +++ b/frontend.nginx.conf @@ -0,0 +1,68 @@ +resolver 127.0.0.11 valid=30s ipv6=off; +resolver_timeout 5s; + +server { + listen 80; + server_name _; + root /usr/share/nginx/html; + index index.html; + client_max_body_size 50m; + + location = /health { + set $api_gateway http://aimaq-call-center-app:8000; + proxy_pass $api_gateway/health; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location /proxy/ { + set $api_gateway http://aimaq-call-center-app:8000; + proxy_pass $api_gateway; + proxy_http_version 1.1; + proxy_read_timeout 600s; + proxy_send_timeout 600s; + proxy_connect_timeout 60s; + proxy_set_header Connection "upgrade"; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header Origin $http_origin; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } + + location = /voice-ai/operator-ws { + set $voice_ai_upstream_op http://aimaq-voice-ai:8099; + proxy_pass $voice_ai_upstream_op/operator-ws; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + proxy_buffering off; + } + + location = /voice-ai/ws { + set $voice_ai_upstream http://aimaq-voice-ai:8099; + proxy_pass $voice_ai_upstream/ws; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_read_timeout 3600s; + proxy_send_timeout 3600s; + proxy_buffering off; + } + + location / { + try_files $uri $uri/ /index.html; + } +}