Всем привет! Я Андрей, ML-разработчик из команды распознавания речи в Т-Банке. Мы занимаемся полным циклом разработки: сбором и разметкой данных, проведением экспериментов по обучению моделей, интеграцией в продакшен.

В русскоязычном сегменте давно не хватает открытых моделей распознавания речи, которые можно было бы быстро кастомизировать под реальные задачи. Более того, почти все доступные модели работают офлайн и не адаптированы под специфику телефонии. Поэтому мы решили опубликовать собственную потоковую акустическую модель с кодом для ее инференса и дообучения, а еще выложить 5-граммную языковую модель.

Акустическая модель является по-настоящему потоковой, легковесной, производительной и конкурирует по качеству с более крупными открытыми офлайн-моделями в телефонии.

В статье расскажу, как устроена потоковая модель распознавания, как и на чем ее обучали и как ее можно использовать.

Краткий экскурс в ASR

ASR — система распознавания речи, которая преобразует аудиозаписи речи в текст. 

Подходы к распознаванию речи:

End-to-end-модель — единая нейросеть, которая принимает на вход аудио и на выходе сразу выдает готовый результат: транскрипцию, тайминги фраз, пунктуацию, денормализацию и прочее. Пример такой модели — Whisper, который может распознавать речь на многих языках, определять язык, переводить речь с одного языка на английский, выдавать тайминги фраз, пунктуацию или денормализацию.

Каскад — состоит из нескольких моделей, каждая из которых решает свою задачу отдельно. В отличие от предыдущего подхода, в каскаде будут отдельно работать акустическая модель, декодер, модель детекции языка, модели пунктуации и денормализации, модель транслитерации.

Каскадный подход имеет ряд преимуществ по сравнению с end-to-end:

  • при просадке качества на определенной задаче или домене можно быстро улучшить качество, дообучив независимо отдельную небольшую модель;

  • каскад хорошо работает в стриминге — естественно поддерживает потоковость, показывает приемлемое качество распознавания с низкой задержкой;

  • обучение акустики занимает меньше времени, поскольку обучаются только encoder-часть и линейная проекция в выходные токены;

  • отдельные компоненты легче дебажить;

  • нейросетевым декодерам свойственны галлюцинации, которые сложно устранить;

  • подготовка данных намного проще, чем для end-to-end.

Акустическая модель — это функция, которая на вход получает аудиосигнал и на выходе возвращает распределение вероятностей символов алфавита на этом сигнале. Модель позволяет оценить вероятность символов для каждого малого участка аудиосигнала (фрейма). На практике модель выдает логарифмические вероятности, которые мы будем кратко называть «логвероятности».

Чтобы обучать акустическую модель, нужно иметь разметку: каждому фрейму необходимо сопоставить символ алфавита. На практике это сделать сложно: фреймов в аудио много, поэтому разметка будет очень долгой, дорогой и сложной. Вместо такой разметки можно использовать специальный CTC-алгоритм, который позволяет автоматически делать выравнивание (alignment) между аудио и текстом. Для выравнивания CTC-алгоритм добавляет к обычному алфавиту специальный символ <BLANK>, который задает границы между группами символов.

Логвероятности имеют размерность T × A, где T — временная координата, задающая длину выходной последовательности, а А — размер расширенного алфавита (с добавленным <BLANK>). Для наглядного представления логвероятности переводят в матрицу вероятностей.

Пример матрицы вероятностей для фразы «алло, добрый день». Размер фрейма соответствует 30 мс исходного аудио. В greedy path для наглядности качестве <BLANK> используется “-”, а в качестве <SPACE> — “|”. Можно заметить, что логвероятности выдаются с некоторой задержкой относительно аудио
Пример матрицы вероятностей для фразы «алло, добрый день». Размер фрейма соответствует 30 мс исходного аудио. В greedy path для наглядности качестве <BLANK> используется “-”, а в качестве <SPACE> — “|”. Можно заметить, что логвероятности выдаются с некоторой задержкой относительно аудио

По матрице вероятностей восстанавливается текст. Чтобы его получить, можно использовать жадный алгоритм Greedy Decoding. Этот алгоритм выбирает наиболее вероятный символ алфавита для каждого временного шага.

На практике Greedy Decoding страдает по точности транскрипций: слова содержат ошибки, теряется согласованность в окончаниях и прочее. Для повышения точности применяется алгоритм Beam Search Decoding, который из всех путей выбирает top-k наиболее правдоподобных. В Beam Search добавляется языковая модель, чтобы дополнительно улучшить качество распознавания. Модель переоценивает вероятность слов и фраз, опираясь на общий смысл произнесенного.

Таким образом, акустическая модель переводит аудио в логвероятности, а декодер переводит логвероятности в транскрипцию. При этом декодер оценивает вероятность фразы на основе выходов акустики и отдельной языковой модели.

Архитектура акустической модели

Отличие офлайн-распознавания от потокового в том, что в офлайн-распознавании аудио доступно целиком, а в потоковом куски аудио поступают постепенно.

Потоковое распознавание обычно предполагает получение транскрипций максимально быстро, «в прямом эфире», поэтому иногда его называют «онлайн», «стриминговым» или real-time.

Поскольку наша модель предназначена для потокового распознавания, она должна возвращать результат быстро. Значит, для вычисления новых выходов акустики недопустимо использовать всю предыдущую информацию с фреймов (левый контекст) из-за трудоемкости вычислений. Поэтому контекст слева ограничивается, а информация между чанками сохраняется в качестве промежуточных состояний, которые называются стейтами. Ограничение левого контекста не только облегчает модель, но и почти не влияет на качество. 

Например, для мел-спектрограммы стейтом являются последние N аудиосэмплов, для causal convolutions — обрезанный по времени входной тензор, для MHSA-слоя — key-value cache.

Схематичная работа акустической модели
Схематичная работа акустической модели

На вход модель принимает сегмент аудио размером 300 мс и стейт, а возвращает логвероятности и обновленный стейт. Внутри сегмента каждый фрейм получает информацию от остальных фреймов, а также от предыдущих 30 фреймов (или 900 мс) до сегмента. За счет увеличения количества слоев receptive field информации с предыдущих фреймов линейно увеличивается.

Модель базируется на архитектуре Conformer. От Conformer взят encoder, который мы модифицировали.

Модифицированная версия архитектуры конформера
Модифицированная версия архитектуры конформера

Обучали модель с использованием CTC-Loss. В качестве токенов использовались символы русского алфавита (с добавлением пробела и токена <BLANK>).

В качестве входных фич используются мел-спектрограммы с hop-length = 10 мс. Далее сверточный 2d-subsampling сжимает временную размерность в три раза, чтобы снизить вычислительную трудоемкость на последующих слоях. Затем идут линейный слой, dropout и модифицированные конформер-блоки.

Для улучшения качества мы применили следующие техники:

  • Feed-forward-модуль заменен на SwiGLU-модуль, он дал улучшение качества на −3% WERR

SwiGLU-module
SwiGLU-module
  • Активации с ReLU заменены на SiLU (Swish) в Convolution Subsampling, LayerNorm заменили на RMSNorm. Swish дал улучшение качества −2% WERR, RMSNorm дал улучшение качества −2% WERR.

Convolution subsampling module
Convolution subsampling module

Для ускорения вычислений в акустической модели применяются техники:

  • Relative positional embedding из TransformerXL заменяются на более быстрые RoPE-эмбеддинги. RoPE повысил качество на −1% WERR, при этом скорость обучения акустической модели выросла на 15%.

  • U-Net-like-архитектура: на 8-м слое конформер-блоков уменьшаем временную размерность в 2 раза, на 15-м слое затем ее обратно увеличиваем. Downsampling осуществляется через свертку, upsampling — через repeat. Так на первых слоях конформер-блоков размерность входного фрейма составляет 30 мс аудиосигнала, в средних слоях — 60 мс, а в конце — снова 30 мс.

Конформер-блоки при использовании U-Net-like-архитектуры
Конформер-блоки при использовании U-Net-like-архитектуры
  • Переиспользование attention scores: слои MHSA объединяются между собой в несколько групп, внутри каждой группы attention scores вычисляются один раз в начале и используются одни и те же для всех слоев MHSA внутри группы.

  • В MHSA-модулях стейты используются только на двух последних слоях. Использование стейтов в MHSA на всех слоях сильно замедляет инференс. Мы провели несколько экспериментов и убедились, что достаточно использовать стейты только на последних двух слоях, чтобы не получать значимую деградацию качества.

Обучение акустической модели

Для обучения модели мы использовали библиотеку NeMo. Мы адаптировали фреймворк под специфику наших задач: доработали модуль загрузки данных для эффективной обработки больших датасетов, добавили эффективные стратегии батчинга и сэмплирования данных, реализовали новые фичи в модуле Conformer (описанные в предыдущих разделах), настроили код обучения для интеграции с внутренней ML-платформой, оптимизировали экспорт модели.

Мы обучали модель со случайной инициализацией весов (без претрейна). При обучении акустической модели использовались semi-sorted batching и сэмплирование датасетов. Так как целевым доменом является телефонный канал, нужно, чтобы чаще в батч попадали аудио с телефонным доменом. Для этого больший вес получают целевые датасеты (телефония), а меньший — нецелевые.

Обучалась модель в 16 bit-precision. В качестве шедулера выбран Cosine scheduler: он не убывает так быстро, как стандартный Noam.

Сравнение шедулеров
Сравнение шедулеров

Для выложенной модели мы не стали выкладывать громоздкий код обучения, а решили выложить простой и понятный код для быстрого дообучения под свой домен.

Домен телефонии имеет свои особенности:

  • низкое качество записей: sample rate = 8 kHz, низкий bitrate;

  • использование аудиокодеков, которые сильно сжимают записи;

  • при передаче аудио по сети могут теряться пакеты;

  • акустические условия самые разнообразные: метро, улица, аэропорт, рынок, автомобиль, магазин, фоновая речь и что угодно еще.

Для достижения приемлемого качества нужно много данных. Мы собрали датасет из более чем 80 тысяч часов разнообразных русскоязычных данных для обучения. Длина аудио варьируется от 100 мс до 20 с. Распределение по объему часов:

домен

часы

источник

телефония

57.9к

внутренние данные

far-field

2.2к

внутренние данные

mix

18.4k

внутренние данные

mix

2.3k

open source

Из всех аудиоданных 64% получены через pseudo-labeling. Для псевдоразметки использовался внутренний ансамбль моделей: базовая продовая модель с больши́м чанком (3600 мс), офлайн-конформер (видит весь контекст слева и справа), зафайнтюненный под телефонию Whisper и encoder-decoder-модель на основе трансформера. Транскрипции от ансамбля агрегировались с помощью ROVER.

Построение языковой модели

Языковые модели помогают улучшать качество распознавания CTC-моделей. В частности, языковые модели способствуют уменьшению количества различного рода грамматических ошибок.

Языковые модели в каскадном подходе не зависят от аудиосигнала напрямую и фокусируются только на текстовом уровне: насколько та или иная последовательность слов похожа на естественный язык.

Языковая модель присваивает вероятности последовательностям слов:

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

где n задает размер n-граммы (т. е. размер последовательности идущих подряд слов).

Языковые модели строятся на корпусе текстовых данных. Для каждой n-граммы вероятность вычисляется как:

где

задает чисто последовательностей

в корпусе.

Мы собрали 5-граммную языковую модель с помощью кода из репозитория. KenLM представляет собой хитро оптимизированную структуру данных для быстрого поиска n-грамм (hash-table либо trie).

В качестве данных брали тексты из открытых источников: Common Crawl, новости, посты, отзывы, субтитры, сгенерированные тексты и спаршенные адреса.

Качество распознавания модели

Для оценки качества распознавания используется метрика Word Error Rate (WER), она имеет интерпретацию как доля ошибок в распознанном тексте.

WER сильно зависит от разметки, поэтому при подсчете WER разных моделей мы переводим текст в lower case, заменяем ё на е, а также применяем нормализацию (например, «алё» → «алло», «ща» → «сейчас», «скока» → «сколько» и пр.).

WER является абсолютной метрикой. Чтобы оценить относительное улучшение, используется WERR:

\frac{WER_{new} - WER_{old}}{WER_{old}} \cdot 100 \%

Чем ниже WER (WERR), тем лучше.

Мы замерили качество open-source-решений с использованием языковой модели и без. 

WER Greedy на различных доменах без LM.

Категория

T-one

GigaAM-CTC-v2

71M

242M

Колл-центр

9.19

10.57

Прочая телефония

6.67

8.15

Именованные сущности

7.11

9.81

CommonVoice19 (test)

7.07

3.14

OpenSTT (asr_calls_2_val)

исходная разметка

21.03

21.14

OpenSTT (asr_calls_2_val)

исправленная разметка

9.14

12.43

Обозначения:

  • Колл-центр: общий колл-центр, телемаркетинг,  клиенты, операторы 

  • Прочая телефония: роботы, мобильный секретарь

  • Именованные сущности: термины, адреса, числа

Сравнение показывает, что наша акустическая модель работает лучше на домене телефонии по сравнению с GigaAM-CTC. 

На академическом датасете CommonVoice наша модель показывает качество хуже GigaAM. Записанная речь и акустические условия отличаются от домена телефонии — фразы зачитываются, речь не спонтанная, паузы спикеров неестественные и тому подобное.

Зачастую обе модели не допускают ошибки, но из-за трудностей нормализации и ошибок в разметке метрики хуже.

Разметка OpenSTT слишком неточная: очень много опечаток, грамматических ошибок или размечен только один спикер из нескольких, встречаются обрезанные фразы. Для более корректных результатов мы переразметили датасет.

WER на различных доменах с использованием нашей LM для CTC-моделей:

Категория

T-one + LM

GigaAM-RNNT-v2

GigaAM-CTC-v2 + LM

Vosk-model-ru (0.54)

Vosk-model-small-streaming-ru (0.54)

Whisper large-v3

71M

243M

242M

65M

20M

1540M

Колл-центр

8.63

10.22

9.29

11.28

15.53

19.39

Прочая телефония

6.20

7.88

7.07

8.69

13.49

17.29

Именованные сущности

5.83

9.55

7.14

12.12

17.65

17.87

CommonVoice19 (test)

5.32

2.68

2.76

6.22

11.30

5.78

OpenSTT (asr_calls_2_val)

исходная разметка

20.27

20.07

19.81

22.64

29.45

29.02

OpenSTT (asr_calls_2_val)

исправленная разметка

7.94

11.14

9.97

13.22

21.03

20.82

Для GigaAM-RNNT, VOSK и Whisper дополнительная языковая модель не применялась. Замеры сделаны out-of-the-box с дефолтными параметрами, а для Whisper дополнительно нормализовали числительные.

Добавление нашей языковой модели дополнительно улучшает качество на домене телефонии. Но нужно быть осторожным: добавка LM, не обученной на нужном домене, может привести к деградации качества.

Сравнение показывает, что наша акустическая модель работает лучше на домене телефонии по сравнению с open-source-решениями.

Отметим, что Whisper из коробки очень сильно галлюцинирует на наших данных и нужно придумывать разные дополнительные эвристики для снижения WER: фильтрацию VAD-ом участков без речи, прокидывание suppress_tokens в промпт, дополнительную нормализацию и так далее.

Итоги сравнения качества моделей:

  • Наша модель, несмотря на компактные размеры и то, что она является потоковой, а не офлайн, показывает отличные результаты в телефонном домене.

  • GigaAM — хорошая робастная модель, которая демонстрирует стабильно высокое качество как в телефонии, так и в других доменах. Но она реализована как офлайн-модель, что может осложнять ее использование в потоковых сценариях.

  • Разметка данных может влиять на результаты замеров WER.

  • Открытые и академические датасеты далеко не всегда отражают специфику условий из реальной жизни и зачастую содержат большое количество ошибок в разметке. Всегда стоит замеряться на внутренних бенчмарках, чтобы точно быть уверенным, насколько модель подходит под собственные задачи.

Скорость модели

Для стриминговой модели основной метрикой скорости является Latency, которая оценивает задержку модели. Есть несколько компонент latency:

  • result latency — задержка между тем, когда фраза была произнесена, и тем, когда на нее пришла финальная гипотеза;

  • tail latency — время, прошедшее с момента отправки последнего куска данных и до получения последней финальной гипотезы;

  • head latency — время, прошедшее с момента начала отправки данных до получения первого промежуточного результата.

Примеры latency. Здесь interim — промежуточные (не финальные) гипотезы, final — финальные гипотезы
Примеры latency. Здесь interim — промежуточные (не финальные) гипотезы, final — финальные гипотезы

Акустическая модель обучалась на CTC-loss, который позволяет выравнивать аудио и текст. Для этого рассматриваются все допустимые выравнивания с использованием специального технического символа <BLANK>, который для удобства переобозначим как "-". 

Между собой выравнивания имеют одинаковый вес: например, если аудио состоит из слова «привет» и паузы, то оба выравнивания «------пр-иве-т--------------------» и «----------------пр-иве-т----------» будут входить в лосс с одним весом (но разной вероятностью) 1/N, где N — кол-во допустимых выравниваний. 

Из-за отсутствия штрафа за выдачу текста в конце модель может выдавать текст позже истинного момента времени, так как это ей помогает использовать информацию с будущих фреймов. Такое смещение называется emission latency, то есть предсказанные символы алфавита находятся на latency милисекунд правее.

Пример смещения для фразы «привет». В данном случае emission latency = 300 ms
Пример смещения для фразы «привет». В данном случае emission latency = 300 ms

Для подсчета смещения можно взять набор аудиозаписей с таймстемпами слов, получить выходы акустики и через forced alignment оценить распределение смещений. Таймстемпы слов мы получили с помощью офлайн-модели (у которой emission latency = 0).

Emission latency не является константной величиной и имеет разброс. По нашим замерам в среднем он находится в районе 330 мс.

При потоковом распознавании нужно быстро определять конец фразы. Для этого используется простой алгоритм: если вероятность отсутствия речи P(<blank>) + P(<space>) больше заданного порога, считаем, что речи в данном фрейме нет. Если таких фреймов накопилось N штук подряд, считаем, что фраза завершилась. 

У нас в продакшене используется более сложный алгоритм, комбинирующий выходы акустической модели и отдельной модели End-of-query detection, определяющей законченность фразы: вероятность речи, вероятность тишины внутри фразы, вероятность тишины вне фразы. Пока не накопилось достаточное количество тишины, фраза выдана не будет.

Задержка возникает из-за особенности почанковой обработки: в зависимости от того, как лягут границы чанков на аудио, может возникнуть дополнительная задержка. Допустим, мы решили выдавать фразу, если 300 мс подряд не было речи. Если речь была задетектирована только в первом фрейме чанка (т. е. в первые 30 мс), то, чтобы выдать фразу, придется ждать еще целый чанк (хотя в действительности нужно 30 мс с нового чанка).

Время инференса модели также влияет на latency. Инференс зависит от архитектуры модели и ее размера. Наша модель относительно маленькая — 71.6М параметров. Для ускорения инференса применяются различные техники: архитектурные улучшения, квантование и прочее.

Latency пайплайна распознавания складывается из факторов:

  • emission latency;

  • детекция конца фразы;

  • размер чанка;

  • инференс акустической модели;

  • инференс декодера.

Для замера latency нашего пайплайна распознавания мы разметили тайминги фраз (audio_end_time) с помощью офлайн-модели. Дальше отправляли сегменты аудио в пайплайн с RTF = 1. При получении очередной фразы вычисляли текущее время (recognition_end_time) и считали latency.

Наш пайплайн распознавания имеет задержку порядка 1—1,2 с: emission latency = 330 ms + silence_duration_threshold = 600 ms + накладные расходы на преобразования данных и декодер. Здесь silence_duration_threshold — длительность паузы, после которой фраза считается завершенной.

Репозиторий

Предлагаем попробовать нашу стриминговую модель на Github. 

Возможности репозитория:

  • Примеры инференса для офлайн- и потокового распознавания: можно распознавать аудио целиком или в потоковом режиме (кусками по 300 мс).

  • Демо — можно через docker мгновенно развернуть локальный сервис и распознавать аудиофайлы или записи с микрофона в режиме реального времени.

  • Примеры дообучения модели, чтобы дообучить модель под свой домен.

  • Примеры инференса, запуск через Triton Inference Server.

  • Код архитектуры модели: можно модифицировать для своих нужд или исследований.

Особенности модели: применимость, потоковость и адаптация. Изначально модель ориентирована для телефонного канала, но благодаря обучению на разнородных данных может быть использована не только для телефонии. Она поддерживает обработку длинных аудиозаписей из коробки и можно дообучить под конкретный домен. В репозитории есть код дообучения акустики на парах аудио + текст.

Возможные сценарии использования:

  • Потоковое распознавание звонков. Пользователь отправляет небольшие сегменты аудио в модель, модель обрабатывает очередной сегмент по мере наступления и выдает распознанный текст финальной фразы и тайминги.

  • Транскрибация видеовстреч в реальном времени.

  • Разметка аудиоданных.

  • Поиск информации по аудиозаписям.

Мы выложили исходный код архитектуры модели. Это открывает возможности для проведения экспериментов в области потокового распознавания речи — как для профессиональных исследователей, так и для начинающих студентов:

  • можно экспериментировать с уменьшением задержки (путем снижения emission latency);

  • искать новые способы ускорения инференса;

  • использовать при написании своей дипломной работы или научных статей.

Пример инференса демонстрирует, как можно потоково обрабатывать аудио. Расскажу, как он устроен:

  1. Сегменты аудио 300 мс отправляются в акустическую модель.

  2. Выходы акустики (логвероятности) отправляются в LogprobSplitter, который вырезает фразы с таймингами.

  3. Вырезанные фразы идут в декодер: greedy decoder или beam search decoder. Декодер выдает распознанный текст.

Общая схема работы пайплайна
Общая схема работы пайплайна

Модели и репозиторий имеют лицензию Apache 2.0, так что их можно использовать как в своих личных целях, так и в коммерческих.

Итоги

Я рассказал о задаче ASR и одном из подходов к ее решению. Наша команда выложила потоковую легковесную модель для домена телефонии. По качеству она не уступает более крупным офлайн-моделям. 

Модель обучалась на разнообразных доменах, и ее можно использовать не только для телефонии.

В нашем репозитории вы обязательно найдете что-то для себя полезное:

  • можно изучить, как работает настоящая потоковость;

  • можно изучить интересные архитектурные решения, позволяющие ускорить инференс (U-Net-like, переиспользование attention scores);

  • есть много полезных примеров: потоковый инференс, deploy, demo;

  • есть код дообучения.

Надеемся, что наш репозиторий с моделями и описанными архитектурными решениями окажется полезным — как для исследователей и разработчиков, так и для студентов.

Мы верим, что открытый обмен знаниями и моделями формирует среду, которая способствует прогрессу в области речевых технологий. Она позволяет не только объективно оценить текущие достижения, но и привлекать в профессиональное сообщество новые таланты. Это, в свою очередь, мотивирует исследователей к разработке передовых подходов для улучшения качества систем и оптимизации их производительности, тем самым ускоряя общее развитие направления.

Код и модели имеют свободную лицензию. Распознавайте и наслаждайтесь!

Полезные ссылки:

  1. Репозиторий NeMo

  2. Краткий обзор СТС

  3. CTC-loss и Beam search

  4. CTC-Loss

  5. Описание работы алгоритма ROVER для агрегации транскрипций 

  6. A post-processing system to yield reduced word error rates: Recognizer Output Voting Error Reduction (ROVER)

  7. Репозиторий kenlm 

  8. Transformer-XL 

  9. RoFormer: Enhanced Transformer with Rotary Position Embedding

  10. Squeezeformer: An Efficient Transformer for Automatic Speech Recognition

  11. Zipformer: A faster and better encoder for automatic speech recognition

  12. UCONV-CONFORMER: HIGH REDUCTION OF INPUT SEQUENCE LENGTH
    FOR END-TO-END SPEECH RECOGNITION

  13. Understanding the Role of Self Attention for Efficient Speech Recognition 

  14. Митап по speech на Ютубе или в VK Видео

  15. Репозиторий pyctcdecode

  16. Статья про работу kelnm

Комментарии (3)


  1. rsashka
    22.07.2025 11:22

    Спасибо за статью.

    Сразу вспомнилась молодость, когда я тоже работал над распознаванием человеческой речи и испытал реальное дежавю. Чанки фиксированной длительности для анализа сигнала, сохранение предистории, потоковое преобразование с записью наиболее вероятного звука, борьба статистки за увеличение качества распознавания и как финал, стеклянный потолок, выше которого прыгнуть так и не получается.

    Кончено сейчас совершенно другие вычислительные мощности, но решаемые задачи и проблемы все те же, что и двадцать пять лет назад :-)


  1. n0isy
    22.07.2025 11:22

    Убейтесь ап стенку, спамеры. /sarcasm off.

    И когда нибудь банк поймет, что клиентоориентированность приносит больше денег, чем зп работников колл центра уносит. Но это эффективный менеджер, выписывающий себе премию за инноваторство, вряд ли покажет начальству.


  1. iliakb
    22.07.2025 11:22

    А можно ли ещё и как подключить диаризацию (разделение по голосам)?