Реалізація ендпоінтінгу мовлення (End-of-Speech Detection)

Ми стикалися з ситуацією: голосовий бот обривав клієнта на середині фрази, тому що поріг тиші був надто жорстким. Або навпаки — зависав на 3 секунди, створюючи незручність. Обидва випадки — результат поганої реалізації ендпоінтінгу мовлення (end-of-speech detection) та неоптимального VAD. У цій стат

Напрямки AI-розробки

Часті запитання

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1441
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    998
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1267
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    713
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    1003

Ми стикалися з ситуацією: голосовий бот обривав клієнта на середині фрази, тому що поріг тиші був надто жорстким. Або навпаки — зависав на 3 секунди, створюючи незручність. Обидва випадки — результат поганої реалізації ендпоінтінгу мовлення (end-of-speech detection) та неоптимального VAD. У цій статті розберемо, як налаштувати VAD, підібрати пороги та зробити адаптивний ендпоінтінг, який працює для різних сценаріїв.

Проблеми, які вирішуємо

Хибні спрацьовування виникають через занадто короткий поріг тиші (<500 мс) або низьку чутливість VAD. Користувач робить паузу, а система вже відправляє запит. Особливо критично в контакт-центрах: бот перебиває, оператор дратується. Вартість такої помилки — втрата клієнта.

Пропуск кінця висловлювання — зворотна ситуація: високий поріг (>1500 мс) або VAD «не чує» закінчення мовлення на фоні шуму. Діалог розтягується, користувач втрачає терпіння. Наш досвід показує, що 80% проблем вирішуються правильним вибором VAD та адаптацією порогів під сценарій. Економія на реінжинірингу — до 40% бюджету.

Затримка обробки: VAD повинен працювати в реальному часі, з latency p99 <100 мс. Використовуємо Silero VAD [Silero VAD paper] в ONNX Runtime або WebRTC VAD (легкий, але гірше на шумах). Для високонавантажених систем — batching на GPU.

Як вибрати поріг тиші для різних сценаріїв?

Для телефонного голосового бота оптимальні параметри: тиша 600–800 мс, мінімальне мовлення 200 мс. Для диктовки: тиша 1500–2000 мс. Для розумного дому (тихий фон): 500–600 мс. Завжди тестуємо на реальних записах з шумами. Адаптивний підхід дає виграш в UX: на відкритих питаннях поріг збільшується, на командах — знижується.

Тип запиту Поріг тиші (мс) Приклад
Відкрите питання 1200 «Розкажи про себе»
Так/ні 500 «Увімкни світло?»
Команда 600 «Вимкни музику»

Як ми це робимо: стек та реалізація

Використовуємо Python 3.11, PyTorch 2.2, ONNX Runtime 1.17, Silero VAD v4.0. Для асинхронної обробки — asyncio. Ось базова реалізація детектора (використовується в продакшені):

import collections import time from enum import Enum class SpeechState(Enum): SILENCE = 0 SPEECH = 1 class EndpointDetector: def __init__( self, vad, sample_rate: int = 16000, frame_ms: int = 30, silence_threshold_ms: int = 700, # пауза для завершення min_speech_ms: int = 300, # мінімальна довжина висловлювання ): self.vad = vad self.sample_rate = sample_rate self.frame_bytes = int(sample_rate * frame_ms / 1000) * 2 self.silence_frames_needed = silence_threshold_ms // frame_ms self.min_speech_frames = min_speech_ms // frame_ms self.state = SpeechState.SILENCE self.silence_counter = 0 self.speech_buffer = bytearray() self.speech_frame_count = 0 def process_frame(self, frame: bytes) -> tuple[bool, bytes | None]: """ Returns: (endpoint_detected, speech_audio_or_none) """ is_speech = self.vad.is_speech(frame, self.sample_rate) if is_speech: self.state = SpeechState.SPEECH self.silence_counter = 0 self.speech_buffer.extend(frame) self.speech_frame_count += 1 else: if self.state == SpeechState.SPEECH: self.silence_counter += 1 self.speech_buffer.extend(frame) # включаємо фінальну тишу if self.silence_counter >= self.silence_frames_needed: if self.speech_frame_count >= self.min_speech_frames: audio = bytes(self.speech_buffer) self._reset() return True, audio else: self._reset() return False, None def _reset(self): self.state = SpeechState.SILENCE self.silence_counter = 0 self.speech_buffer = bytearray() self.speech_frame_count = 0 

У реальних діалогах потрібен адаптивний endpointing. Ми використовуємо класифікатор на основі Intent Detection (наприклад, через малу модель типу DistilBERT), який визначає тип запиту та динамічно змінює поріг. Адаптивний ендпоінтінг обробляє відкриті питання в 2 рази швидше, ніж фіксований поріг 700 мс.

# Різні пороги для різних типів запитів THRESHOLDS = { "open_question": 1200, # мс тиші "yes_no": 500, "command": 600, "default": 700, } 
Докладніше про адаптивний класифікатор

Класифікатор намірів — це lightweight модель (DistilBERT або TinyBERT), яку ми запускаємо на перших 300 мс аудіо. Вона передбачає тип запиту до того, як користувач закінчить мовлення. Це дозволяє заздалегідь встановити поріг тиші та скоротити загальний час очікування. Середня точність передбачення — 94% на наших даних.

Порівняння VAD-рішень

VAD Точність на шумах Latency (p99) CPU Load
Silero VAD (ONNX) 0.97 50 мс Низьке
WebRTC VAD 0.85 10 мс Дуже низьке
RNNoise 0.91 30 мс Середнє

Вибір VAD — компроміс між точністю та ресурсами. Для контакт-центру ми рекомендуємо Silero, для IoT — WebRTC. Latency p99 критичний для голосових ботів: при перевищенні 100 мс діалог стає неприродним.

Процес роботи над endpointing

  1. Аналіз — збираємо записи діалогів, заміряємо поточні метрики (latency, помилки).
  2. Проектування — обираємо VAD (зазвичай Silero), задаємо конфігурацію порогів, вирішуємо, чи потрібен адаптивний класифікатор.
  3. Реалізація — інтегруємо детектор у голосовий потік (WebRTC або власна реалізація). Додаємо моніторинг через MLflow.
  4. Тестування — A/B тест на 10% трафіку, порівнюємо з поточним рішенням.
  5. Деплой — контейнеризація, запуск на CPU-нодах (Triton Inference Server). Навчання команди.

Що входить в роботу під ключ

  • Документація — опис архітектури, параметрів, інструкція з моніторингу.
  • Код — Python-модуль з VAD, адаптивним порогом, обробкою помилок.
  • Тестовий стенд — симулятор з реальними записами.
  • Навчання — дзвінок з командою, відповіді на питання.
  • Підтримка — 2 тижні після деплою (виправлення багів, налаштування під навантаження).

Терміни: базова реалізація — 2-3 дні, адаптивний з ML — 1 тиждень. Вартість розраховується індивідуально, але таке доопрацювання окупається за 2-3 місяці завдяки скороченню пауз та підвищенню конверсії. Правильне налаштування ендпоінтінгу може скоротити операційні витрати на 20-30%.

Наш досвід: понад 5 років роботи з голосовими асистентами, 30+ успішних проєктів. Ми гарантуємо стабільну роботу endpointing на зашумлених лініях. Для оцінки вашого проєкту зв'яжіться з нами – ми проаналізуємо ваші записи та запропонуємо оптимальне рішення.

Як не помилитися при впровадженні?

  • Не копіюйте пороги з одного сценарію в інший: testbed повинен включати ваші реальні аудіо (з шумами, різною гучністю).
  • Задокументуйте метрики: latency p99, false positive rate, false negative rate. Без них ви не дізнаєтеся, чи стало краще.
  • Використовуйте адаптивний підхід: навіть проста зміна порогу за типом запиту покращує UX на 30%.

Отримайте консультацію: пишіть — ми оцінимо ваш проєкт і запропонуємо рішення.