Аналоги ElevenLabs: русский текст в API — это Cartesia Sonic 3.6, Azure Speech и Google Cloud TTS. Каждый маршрут задаёт произношение даты, времени, номера заявки по цифрам, аббревиатуры и дроби своим параметром или разметкой. Ниже — исходное уведомление, ожидаемая словесная запись и карта переноса по трём API.
Что даёт ElevenLabs на входе
Baseline берём из официальной документации ElevenLabs. Модель Eleven Multilingual v2 поддерживает 29 языков, включая русский, и лимит 10 000 символов; модель Eleven Flash v2.5 поддерживает 32 языка — все языки v2 плюс венгерский, норвежский и вьетнамский. Для длинных текстов документация советует дробить текст на сегменты и использовать параметры previous_text / next_text, чтобы сохранить естественную просодию между фрагментами. Модели интерпретируют эмоциональный контекст прямо из текста: описательные фразы и восклицательные знаки влияют на эмоцию речи, а описательный текст озвучивается и требует ручной обрезки из аудио. Выход модели недетерминирован, для большей согласованности есть параметр seed. Параметры previous_text / next_text — это то, что нужно переносить в первую очередь: они отвечают за стык фрагментов.
Исходное уведомление и ожидаемая запись
Возьмём типовое русское уведомление клиенту:
Заявка № 4821 принята 10-12-2016 в 12:35. Срок — 3–5 рабочих дней.
Оплата: 10,50 ₽. Отдел — ОТК.
Ожидаемая словесная запись неоднозначных полей:
| Поле | В тексте | Ожидаемая запись |
|---|---|---|
| Номер заявки | 4821 | «четыре восемь два один» (по цифрам) |
| Дата | 10-12-2016 | «десятое декабря две тысячи шестнадцатого» |
| Время | 12:35 | «двенадцать тридцать пять» |
| Диапазон | 3–5 | «от трёх до пяти» |
| Сумма | 10,50 ₽ | «десять рублей пятьдесят копеек» |
| Аббревиатура | ОТК | «о тэ ка» |
Это контрольная запись — требование к выходу. Дальше разбираем, каким параметром каждое поле задаётся в трёх API.
Карта переноса: Cartesia Sonic 3.6
Cartesia Sonic 3.6 поддерживает 44 языка, включая русский. Датированный снапшот sonic-3.6-2026-08-27 подтверждён в документации модели: он помечен как стабильный и не меняется после релиза. Для русского передавайте locale: "ru-RU" — документация Cartesia перечисляет ru-RU среди поддерживаемых региональных локалей. Поля language и locale задавайте по одному: оба принимают базовый код (ru) или региональный (ru-RU), но установить оба сразу нельзя.
Нормализация управляется полем normalization:
auto(по умолчанию) — использует конвенции языка или локали запроса;off— пропускает нормализатор;- код языка или локали (
ruилиru-RU) — использует конвенции этого языка.
Документация Cartesia отдельно предупреждает о диапазонах дат вроде 1999-2000 и Dec 5-Dec 12, обыкновенных дробях вроде 2/3 и необычных единицах V, Pa: их нужно раскрывать словами. Обычные форматы валюты входят в автоматическую нормализацию, но для нашего точного эталона выпишите диапазон как «от трёх до пяти», сумму как «десять рублей пятьдесят копеек», номер как «четыре восемь два один» и отправьте полностью подготовленный текст с normalization: "off". Пример смены normalization для английского чтения цифр в Hindi-тексте не подтверждает русский вариант. Для русского ID используйте явную словесную запись.
Карта переноса: Azure Speech
Azure Speech поддерживает ru-RU в таблице TTS-локалей. Голоса для русского: ru-RU-SvetlanaNeural, ru-RU-DmitryNeural, ru-RU-DariyaNeural.
Разметка SSML в Azure даёт точный контроль над полями:
| Поле | SSML | Что делает |
|---|---|---|
| Номер заявки | <say-as interpret-as="number_digit">4821</say-as> |
читает по цифрам |
| Дата | <say-as interpret-as="date" format="dmy">10-12-2016</say-as> |
формат день-месяц-год |
| Число | <say-as interpret-as="cardinal">10</say-as> |
количественное числительное |
| Аббревиатура | <sub alias="о тэ ка">ОТК</sub> |
подменяет произношение |
Документация Azure отмечает: значение interpret-as="duration" элемента say-as поддержано только для английского и испанского. Теги phoneme и lexicon требуют проверки сносок в таблице поддержки языков для нужного locale. Английский пример произношения нельзя переносить на русский: набор фонем у каждого locale свой, и при нераспознанной фонеме сервис вернёт ошибку 400.
Карта переноса: Google Cloud TTS
Google Cloud TTS поддерживает ru-RU в каталоге голосов: Standard (ru-RU-Standard-A … ru-RU-Standard-E), Wavenet (ru-RU-Wavenet-A … ru-RU-Wavenet-E) и Chirp 3: HD (ru-RU-Chirp3-HD-Aoede, ru-RU-Chirp3-HD-Charon, ru-RU-Chirp3-HD-Fenrir, ru-RU-Chirp3-HD-Kore, ru-RU-Chirp3-HD-Leda, ru-RU-Chirp3-HD-Orus, ru-RU-Chirp3-HD-Puck, ru-RU-Chirp3-HD-Zephyr).
Разметка SSML в Google Cloud TTS:
| Поле | SSML | Что делает |
|---|---|---|
| Номер заявки | <say-as interpret-as="characters">4821</say-as> |
по буквам и цифрам |
| Дата | <say-as interpret-as="date" format="dmy">10-12-2016</say-as> |
формат день-месяц-год |
| Число | <say-as interpret-as="cardinal">10</say-as> |
количественное |
| Сумма 10,50 ₽ | <sub alias="десять рублей пятьдесят копеек">10,50 ₽</sub> |
явное чтение рублей и копеек |
| Аббревиатура | <sub alias="о тэ ка">ОТК</sub> |
подмена произношения |
Ключевое ограничение: SSML subset действует в synchronous-запросах. В streaming-запросах SSML-теги не поддерживаются. Для Chirp 3: HD документация перечисляет поддерживаемые теги: <speak>, <say-as>, <p>, <s>, <phoneme>, <sub>, <break>, <audio>, <prosody>, <voice>. Тег <say-as interpret-as="expletive"> не поддержан. Паузы задаются тегами [pause short], [pause long], [pause] в поле markup, не в поле text.
Карточка параметров: поле → маршрут
| Поле уведомления | Cartesia Sonic 3.6 | Azure Speech | Google Cloud TTS |
|---|---|---|---|
| Номер заявки по цифрам | «четыре восемь два один» в полностью подготовленном тексте, normalization: "off". |
say-as number_digit. |
say-as characters. |
| Дата | normalization: "ru-RU" |
say-as date format=dmy |
say-as date format=dmy |
| Время | normalization: "ru-RU" |
say-as time format=hms24 |
say-as time format=hms24 |
| Диапазон | писать «от … до» вручную | say-as cardinal для каждого числа |
say-as cardinal для каждого числа |
| Сумма 10,50 ₽ | «десять рублей пятьдесят копеек» в полностью подготовленном тексте, normalization: "off". |
sub alias="десять рублей пятьдесят копеек". |
sub alias="десять рублей пятьдесят копеек". |
| Аббревиатура | преднормализация или словарь произношений | sub alias |
sub alias |
| Длинный текст | разбивать на запросы | batch synthesis API | разбивать на запросы |
Что не поддерживается: у Cartesia диапазоны дат, дроби и необычные единицы не нормализуются автоматически; у Azure значение interpret-as="duration" элемента say-as работает только для EN/ES, а phoneme/lexicon требуют проверки сносок locale; у Google Cloud TTS SSML-теги не работают в streaming-запросах.
Ручная преднормализация: request-level
У Cartesia normalization: "off" действует на весь запрос. Документация прямо говорит: если большая часть транскрипта должна нормализоваться, а один фрагмент — нет, выпишите этот фрагмент так, как он должен звучать, вместе с другими письменными формами, которые нуждались бы в нормализации, и отправьте запрос с normalization: "off". Если в одном транскрипте нужны разные конвенции чтения, документация Cartesia советует разбить транскрипт и отправить два запроса с разными значениями normalization и одним голосом, а затем склеить аудио на стороне клиента. При normalization: "off" продолжают работать SSML-теги, словари произношений и буферизация транскрипта.
Готовый промпт для проверки произношения
Промпт, чтобы получить от модели контрольную словесную запись полей уведомления до отправки в API:
Ты — лингвист-нормализатор русского текста для синтеза речи.
Ниже русское уведомление. Запиши словами каждое неоднозначное поле
так, как его должен произнести диктор.
Правила:
- номер заявки — по цифрам: 4821 → «четыре восемь два один»;
- дата — «десятое декабря две тысячи шестнадцатого»;
- время — «двенадцать тридцать пять»;
- диапазон 3–5 → «от трёх до пяти»;
- сумма 10,50 ₽ → «десять рублей пятьдесят копеек»;
- аббревиатура ОТК → «о тэ ка».
Верни таблицу: поле | исходный текст | словесная запись.
Не добавляй пояснений.
Уведомление:
[вставьте ваш русский текст уведомления]
В промпте меняйте [вставьте ваш русский текст уведомления] на свой текст. Вариации той же задачи: заменить правила на английские конвенции чтения; добавить поле «телефон» с чтением по цифрам; добавить поле «адрес»; запросить два варианта — для normalization: auto и для normalization: off; запросить разбивку длинного текста на сегменты с указанием стыков.
Протокол переноса одного уведомления по карте
Этот протокол — практическая последовательность действий для читателя, у которого уже есть карта «поле → параметр». Он помогает перенести одно конкретное русское уведомление так, чтобы каждое неоднозначное поле звучало предсказуемо, а лишние параметры не попали в запрос. Пример ниже учебный; исходное уведомление из статьи сохраняется без изменений.
Шаг 1. Выберите только те поля, которые требуют решения
Сохраняйте уведомление целиком. Внутри него отметьте поля, для которых нужно явно задать правило чтения:
| Поле в тексте | Что решаем |
|---|---|
| № 4821 | читать по цифрам |
| 10-12-2016 | порядок день-месяц-год |
| 12:35 | 24-часовое чтение |
| 3–5 | развёрнутая форма «от… до» |
| 10,50 ₽ | словами, не символом |
| ОТК | «о тэ ка» |
Остальное (например, «Заявка принята», «Срок — рабочие дни») оставляйте в нейтральной формулировке: оно не создаёт расхождений.
Шаг 2. Сохраните три эталона рядом с запросом
Заведите одну строку журнала на перенос. В ней должно быть три независимых артефакта:
- Исходник — точная русская фраза без правок (
Заявка № 4821 принята 10-12-2016 в 12:35. Срок — 3–5 рабочих дней. Оплата: 10,50 ₽. Отдел — ОТК.). - Словесный эталон — таблица из шага 1: как диктор должен произнести каждое неоднозначное поле.
- Параметры версии и канала — модель, датированный снапшот (если есть), язык/локаль, sync или streaming.
Сохраняйте параметры версии и канала для повторного сравнения. Выбор другого снапшота Cartesia меняет версию модели, а переход с synchronous на streaming у Google Cloud TTS меняет поддержку SSML.
Шаг 3. Соберите body fragments без лишних полей
Фрагменты тела запроса должны содержать только те поля, которые реально влияют на произношение выбранных полей уведомления. Не добавляйте endpoint, порты, ключи или параметры из соседнего раздела — они не проверяются этим протоколом.
Для Cartesia Sonic 3.6 это locale: "ru-RU" плюс normalization со значением auto, off или конкретным кодом локали. Для Azure Speech — SSML с say-as и sub. Для Google Cloud TTS — SSML subset в synchronous-запросе; в streaming SSML-теги не поддерживаются.
Один важный нюанс Cartesia: normalization: "off" действует на весь запрос. Если большая часть фразы должна нормализоваться, а одно поле — нет, выпишите это поле так, как оно должно звучать, и отправьте запрос с выключенной нормализацией целиком. Смена locale на ru-RU сама по себе не гарантирует, что ID будет прочитан по цифрам — это отдельное решение.
Шаг 4. Проверяйте значение и интерпретацию отдельно
Для каждого поля из шага 1 зафиксируйте два независимых вопроса:
- Значение — совпадает ли числовое или словесное содержание с исходником (день, месяц, год; часы и минуты; номер).
- Интерпретация — соответствует ли чтение выбранному правилу (по цифрам; «от трёх до пяти»; «десять рублей пятьдесят копеек»).
До отправки сверьте тело запроса со словесным эталоном. После синтеза прослушайте полученное аудио и отметьте фактическое чтение каждого поля. Текст запроса и лог параметров сами по себе не доказывают произношение.
Три типовых несовпадения
1. Диапазон читается слитно. Документация Cartesia отдельно предупреждает о диапазонах дат и годов вроде 1999-2000. Для нашего «3–5 рабочих дней» задайте требуемую форму «от трёх до пяти» в полностью подготовленном тексте с normalization: "off". В Azure и Google Cloud TTS можно сохранить слова «от» и «до», разметив каждое число отдельным say-as cardinal.
2. Номер заявки читается как число. Для требуемого русского чтения выпишите «четыре восемь два один» и используйте normalization: "off" для всего подготовленного текста. Не считайте смену locale или английский пример normalization доказанным способом получить русские названия цифр.
3. Аббревиатура читается как слово. «ОТК» при нейтральной нормализации может прозвучать как слитное «отк». В Azure используйте <sub alias="о тэ ка">ОТК</sub>, в Google Cloud TTS — тот же <sub>, в Cartesia — преднормализацию или словарь произношений.
Шаг 5. Разбирайте несовпадения по изменяемому полю
Когда проверка выявила расхождение, меняйте ровно одно поле за итерацию:
- если «поехал» диапазон — сначала перепишите его словами в исходнике;
- если «поехал» номер — выпишите цифры русскими словами и проверьте, что весь подготовленный текст отправляется с
normalization: "off"; - если «поехала» аббревиатура — сначала добавьте
sub alias, потом проверяйте словарь.
Смена двух полей сразу делает причину расхождения неопределяемой.
Шаг 6. Остановите итерации
Останавливайтесь, когда все поля из шага 1 одновременно совпадают со словесным эталоном при неизменных параметрах версии и канала. Если этого не происходит при одной правке за раз — задача выходит за рамки преднормализации, и её нужно передавать разработчику с логом из шага 2: исходник, словесный эталон, параметры версии и канала, список проверенных изменений.
Перед сравнением сохраните копию текста вместе с символами разделителей. Если вход между запусками изменился, сначала подготовьте эталон заново. Отмечайте исправления в копии уведомления: это поможет повторить тот же маршрут для следующей заявки и отделить изменение входных данных от изменения настроек синтеза.
Частые вопросы
Чем заменить ElevenLabs для русского текста в API?
Три маршрута: Cartesia Sonic 3.6 с locale: "ru-RU", Azure Speech с ru-RU и SSML say-as, Google Cloud TTS с ru-RU и SSML subset. Каждый поддерживает русский язык в своём каталоге голосов. Выбор зависит от того, какой канал нужен: synchronous-запрос или streaming.
Как заставить API прочитать номер заявки по цифрам?
В Azure используйте <say-as interpret-as="number_digit">4821</say-as>. В Google Cloud TTS — <say-as interpret-as="characters">4821</say-as>. В Cartesia выпишите номер русскими словами «четыре восемь два один» и отправьте полностью подготовленный текст с normalization: "off" для всего запроса.
Почему диапазон дат читается неправильно?
Документация Cartesia прямо называет это ограничением: диапазоны вида 1999-2000 не нормализуются автоматически ни в одном языке. Решение — писать диапазон словом: «от 1999 до 2000». В Azure и Google Cloud TTS диапазон разбивается на два отдельных тега say-as cardinal.
Работает ли SSML в streaming-запросах Google Cloud TTS?
Нет. Документация Chirp 3: HD указывает, что SSML-теги поддерживаются для synchronous-запросов, а в streaming-запросах не поддерживаются. Для streaming используйте текстовые приёмы: пунктуацию, разбивку на короткие предложения, теги паузы в поле markup.
Можно ли отключить нормализацию только для одного фрагмента?
У Cartesia normalization: "off" действует на весь запрос. Документация советует выписать нужный фрагмент так, как он должен звучать, и отправить запрос с normalization: "off", либо разбить транскрипт на два запроса с разными значениями normalization и склеить аудио.
