← Блог

Выбор API

Speech-to-Text API: как выбрать и не переплатить

Выбор Speech-to-Text API почти никогда не сводится к вопросу «кто точнее». Один сервис даёт идеальный текст на чистой студийной записи и рассыпается на телефонном звонке, второй дешевле в пять раз, но берёт деньги за каждую минуту открытого соединения, а третий отлично распознаёт, но не умеет отдавать таймкоды по словам. Итоговая стоимость и качество продукта зависят от пяти-шести параметров, и почти все они видны только в документации и в честных замерах. В этом разборе я покажу, как сравнивать STT API по существу: какие метрики действительно предсказывают результат, где спрятаны скрытые расходы и как проверить точность на своих данных за один вечер.

Почему «точность 98%» из рекламы ничего не значит

Почти каждый вендор пишет на лендинге «точность распознавания до 98%». Цифра красивая, но у неё есть один недостаток: она почти ничего не говорит о ваших записях. Точность измеряют на конкретном наборе данных - начитанном тексте, подкастах или телефонных звонках, - и модель, которая выигрывает на студийной речи, легко сдаётся на разговоре через гарнитуру. Домен решает больше, чем бренд: для колл-центра критичны узкополосный канал 8 кГц и фоновый шум офиса, для медиа - пунктуация и имена, для медицины - терминология и дозировки.

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

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

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

Метрика, которой можно верить: WER

Стандартная метрика качества распознавания - WER, word error rate, доля ошибочных слов. Считается она так: складывают замены, вставки и пропуски слов и делят на количество слов в эталонном тексте. WER, равный 0.10, означает, что каждое десятое слово распознано неверно; при этом accuracy = 1 - WER. В отличие от «до 98%», у WER есть определение, формула и воспроизводимость: два человека на одних данных получат одну и ту же цифру.

У метрики есть тонкости, о которых полезно знать до сравнения. Регистр и пунктуация обычно нормализуются, иначе запятая превратится в отдельную ошибку. Имена, бренды и термины бьют по WER сильнее всего: редкое название на десять слов даёт заметную долю ошибок. Числа и сокращения записываются то словами, то цифрами, и это тоже нужно нормализовать, иначе метрика наказывает движок за формат, а не за слух. Из-за этого сравнивать WER из разных отчётов почти бессмысленно: важны только замеры на одном и том же эталонном наборе.

Хорошая новость в том, что измерить WER можно, не покидая API. Эндпоинт POST /v1/eval принимает аудио и эталонный текст, распознаёт запись и возвращает разбор по словам: hits, substitutions, insertions, deletions, а также сам WER и accuracy. Вот минимальный пример на Python, которым удобно прогнать сразу десяток своих фрагментов.

Python
import requests

API = "https://ttsapi.ru/v1"
HEADERS = {"X-Api-Key": "rtt_…"}

reference_text = open("reference.txt", encoding="utf-8").read()

with open("sample.wav", "rb") as f:
    r = requests.post(
        f"{API}/eval",
        headers=HEADERS,
        files={"audio": ("sample.wav", f, "audio/wav")},
        data={
            "reference": reference_text,
            "language": "ru",
            "normalize": "true",
        },
    )

report = r.json()
print(report["wer"], report["hits"], report["substitutions"])

Полный список параметров эндпоинта, ответов и ошибок - смотрите документацию.

Русский язык: где модели ломаются чаще всего

Русский - язык с богатой морфологией, и это создаёт характерные ошибки. Падежи и окончания модель часто слышит правильно, но записывает грамматически неверно; омофоны расходятся по смыслу; фамилия из телефонного разговора превращается в случайный набор букв. Отдельная история - смешанная речь, когда в одном предложении звучит «задеплоить на прод» и «созвон в три». Движок не должен переводить технический термин в русское слово и не должен терять его.

Худший сценарий для любого STT - узкополосный телефонный канал. Полоса 8 кГц отрезает высокие частоты, по которым различаются шипящие, а шум офиса добавляет свою долю. Если ваш продукт - контроль качества звонков или расшифровка поддержки, тестируйте именно этот сценарий: запись с телефона, два собеседника, перекрытие голосов, иногда сжатие кодеком. Для встреч и подкастов условия мягче, но и там мешают эхо и одновременная речь.

Здесь и приходит на помощь keyterm prompting. В запрос можно передать список ключевых слов - названий, терминов, аббревиатур, - и движок будет подсказан искать именно их. Это самый дешёвый способ поднять точность на домене, не меняя модель: вместо переобучения вы просто сообщаете сервису, какие слова в записи точно есть. Для колл-центра это названия тарифов, для медицины - препараты, для интервью - имена спикеров.

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

Потоковое распознавание или отложенное: за что вы платите

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

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

Третий вариант - компромисс, и его стоит предусмотреть заранее. Короткие файлы быстрее обрабатывать синхронно, длинные - асинхронными заданиями с прогрессом. Именно так устроено у нас: POST /v1/transcribe/sync для коротких записей, POST /v1/transcribe для всех остальных и флаг long_form для материалов до четырёх часов с отслеживанием прогресса по чанкам. Один и тот же API закрывает оба режима, и переключаться между ними можно по длине файла.

Цена режимов отличается, и это стоит держать в голове при проектировании. Асинхронная обработка обычно дешевле синхронной, а потоковая - дороже обеих, потому что платит за низкую задержку. Поэтому разумная архитектура выглядит так: короткие интерактивные запросы идут в синхронный режим, объёмные архивы - в асинхронный, а поток включается только там, где пользователь реально ждёт текст на экране. Так экономия получается без потери качества продукта.

bash
# short files: synchronous request
curl -X POST https://ttsapi.ru/v1/transcribe/sync \
  -H "X-Api-Key: rtt_…" \
  -F "audio=clip.wav" \
  -F "language=ru"

# long files: asynchronous job with a webhook
curl -X POST https://ttsapi.ru/v1/transcribe \
  -H "X-Api-Key: rtt_…" \
  -F "audio=meeting.mp3" \
  -F "language=ru" \
  -F "long_form=true" \
  -F "webhookUrl=https://example.com/hooks/stt"

Цена за минуту: считаем unit-экономику, а не прайс

Прайс на сайте вендора редко совпадает с ценой в вашем бюджете. Начните с базовой ставки: у Яндекс SpeechKit это 0.65 рубля за минуту синхронного и потокового распознавания и 0.61 за отложенное, у AssemblyAI около 0.28 рубля за минуту асинхронной обработки, у OpenAI примерно 0.48, у ElevenLabs Scribe около 0.53. Разброс почти двукратный, и это ещё до платных надстроек.

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

И отдельный фактор для команд из России - валюта и способ оплаты. Зарубежный сервис с ценой в долларах означает карту, которую не всегда можно провести, валютный курс и налоги на стороне покупателя; OpenAI для оплаты из РФ недоступен. Рублёвый прайс с оплатой картой или по СБП убирает этот слой риска. Поэтому считайте не цену за минуту, а стоимость обработки часа реальных звонков: вместе с аддонами, минимальными блоками и конвертацией.

Тарифы, включённые объёмы и поминутные ставки - смотрите тарифы.

Лимиты, форматы и длина файлов: где API упирается

Технические лимиты либо вписываются в ваш продукт, либо ломают его задним числом, когда переделывать дорого. Первое, что стоит проверить, - ограничение на размер и длину файла. У обычной транскрипции это, как правило, 25 МБ и 15 минут; часовая встреча или смена колл-центра в такие рамки не влезает. Длинный путь снимает ограничение: до 512 МБ и четырёх часов на запись, но обычно он доступен только на старших тарифах.

Второй блок - форматы и параметры аудио. Практический минимум, который должен принимать сервис: wav, mp3, ogg и flac, моно и стерео, разные частоты дискретизации, потому что файлы приходят из самых разных источников. Хорошо, если стереоканалы можно расшифровывать отдельно: это простой способ разделить участников телефонного разговора без диаризации и без дополнительной платы.

Третий блок - как именно вы получаете результат. Для интеграции важны вебхуки: сервис сам сообщает о готовности задания, и вам не нужно опрашивать статус в цикле. Проверьте и лимиты частоты запросов: они редко упоминаются на лендинге, но именно они приводят к ошибке 429 в самый неподходящий момент. У нас лимит растёт вместе с тарифом - от 5 запросов в секунду на Free до 60 на Business, с отдельным запасом на краткие всплески.

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

JSON
{
  "job_id": "tr_9f31c2",
  "status": "processing",
  "progress": 42,
  "chunks_completed": 8,
  "chunks_total": 19
}

Чек-лист: десять вопросов до оплаты

Чтобы не утонуть в деталях, сведите выбор к десяти вопросам. Один: какая метрика качества и на каком домене замерялась. Два: есть ли способ измерить WER на своих данных прямо в API. Три: как сервис справляется с телефонным каналом и перекрытием речи. Четыре: поддерживаются ли ключевые слова и подсказки терминов. Пять: есть ли по-словные таймкоды и оценка уверенности, ведь без них не собрать качественные субтитры, поиск по записям и удобную вычитку.

Шесть: сколько стоит минута с учётом аддонов и минимального шага оплаты. Семь: какие лимиты по размеру и длине файла и на каких тарифах открывается длинная обработка. Восемь: есть ли потоковый режим и сколько он стоит. Девять: как устроена отдача результата - вебхук или опрос, и какие лимиты частоты запросов. Десять: можно ли прогнать собственный тест до покупки, а не после. Эти десять пунктов покрывают почти все причины, по которым интеграция с STT API оказывается дороже или сложнее, чем выглядела на лендинге.

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

Собранный чек-лист удобно превратить в таблицу и заполнить по каждому кандидату. Там, где вендор молчит, ставьте наихудшее предположение: нет вебхуков - считайте опрос, нет по-словных таймкодов - считайте, что субтитры придётся править руками. Оцените суммарную стоимость владения за квартал, включая инженерное время на интеграцию: иногда дешёвый API требует втрое больше кода, и экономия на минутах съедается разработкой.

Итог: как выбрать за один вечер

Соберите тестовый набор из 20-50 фрагментов своих записей: разного качества, с именами и терминами, с телефонным и студийным звуком. Прогоните его через кандидатов, посчитайте WER и стоимость обработки часа. Прибавьте аддоны, которые вам действительно нужны, и проверьте лимиты длины, потоковый режим и частоту запросов. Обычно после этого остаётся один-два варианта, между которыми выбор делается по цене и удобству интеграции.

У нас этот путь максимально короткий. Бесплатный тариф включает 150 аудио-минут в месяц, и этого достаточно, чтобы прогнать тестовый набор и увидеть WER на своих данных без карты. Дальше Basic за 390 рублей в месяц даёт 1 800 аудио-минут и диаризацию, Pro за 1 490 добавляет потоковое распознавание, длинные записи до четырёх часов и перевод, а Business за 7 990 - приоритетную очередь и 30 000 минут. Если подписка не нужна, работает поминутная оплата с баланса: 0.40 рубля за минуту асинхронной расшифровки и 0.50 за синхронную.

И главное: WER - это не разовая проверка, а метрика, которую стоит держать в мониторинге. Домен меняется, появляются новые имена и термины, меняется качество записи. Регулярный замер на эталонном наборе показывает, что движок по-прежнему попадает в ваши ожидания, и это намного дешевле, чем обнаружить деградацию по жалобам пользователей спустя месяц после релиза.

Если распознавание для вас в новинку, начните с базового руководства - Как распознать русскую речь в текст через API: пошаговое руководство.

Начните с бесплатного замера

Бесплатный тариф даёт 150 аудио-минут в месяц - этого хватит, чтобы прогнать свой тестовый набор и сравнить WER на собственных записях. Карта не нужна.

Проверить точность на своих файлах смотрите тарифы
← Все статьи