Замена короткой фразы в аудио¶
Audio Edit позволяет распознать реплики со спикерами и таймкодами, выбрать одну короткую реплику, клонировать голос её спикера и встроить новый текст в исходную дорожку. Общая длительность записи сохраняется, а результат возвращается в mono WAV.
Функция состоит из двух независимых запросов:
POST /api/tts/v1/audio-edit/analyzeраспознаёт и размечает аудио, после чего возвращает реплики и подписанный токен анализа.POST /api/tts/v1/audio-edit/renderпринимает тот же исходный файл, токен, идентификатор одной реплики и новый текст, затем возвращает готовый WAV.
Оба метода требуют авторизации так же, как основной TTS API v1.
Право на использование голоса
Перед обоими запросами вызывающая сторона обязана подтвердить, что имеет право
клонировать голоса из записи. Используйте функцию только для собственного голоса
либо с явного согласия говорящего. Поле confirm_voice_rights=true является
подтверждением со стороны клиента; сервер не устанавливает наличие прав
самостоятельно.
Конфиденциальность и срок действия анализа¶
Исходный файл и созданный voice clone не сохраняются в архиве продукта. Во время
обработки загрузка может временно находиться на сервере и удаляется после завершения
запроса. Ответ анализа содержит analysis_token, действительный 15 минут
(analysis_expires_in_seconds: 900). Токен привязан одновременно:
- к SHA-256 байтов исходного файла;
- к пользователю, выполнившему анализ;
- к найденным репликам, их таймкодам и индивидуальным лимитам нового текста.
При рендере нужно заново отправить байт-в-байт тот же файл и использовать ту же учётную запись. Перекодирование, повторный экспорт или любое изменение файла меняет SHA-256, поэтому токен будет отклонён. После истечения 15 минут выполните анализ снова.
Токен подписан, но его следует считать чувствительными данными: не публикуйте его и не записывайте вместе с расшифровкой в общедоступные логи.
Анализ аудио¶
POST /api/tts/v1/audio-edit/analyze
Authorization: Api-Key <API_KEY>
Content-Type: multipart/form-data
Поля multipart-формы¶
| Поле | Тип | Обязательное | По умолчанию | Описание |
|---|---|---|---|---|
audio |
file | да | — | Исходный mono- или stereo-аудиофайл: до 30 минут, не более 96 MiB и 48 кГц. Если общий лимит загрузки API ниже, применяется он |
lang |
string | нет | ru-RU |
Язык распознавания. Региональная часть нормализуется, например ru-RU → ru |
max_speakers |
integer | нет | 4 |
Максимальное число спикеров для диаризации, от 1 до 20 |
confirm_voice_rights |
boolean | да по смыслу | false |
Должно быть true; подтверждает право использовать голоса из записи |
Поддерживаются записи с одним или двумя каналами; исходники с частотой выше 48 кГц отклоняются. Stereo равновесно сводится в mono тем же способом, что и в mono-режиме основного STT: каждый выходной сэмпл является средним значением левого и правого каналов. Для анализа результат сразу приводится к PCM16 mono 16 кГц. Все записи после нормализации проходят распознавание, определение спикеров и разметку таймкодов слов.
При рендере сервер повторно декодирует исходник с его частотой дискретизации, выполняет тот же stereo-to-mono downmix, заменяет только выбранное короткое окно и возвращает mono WAV. Ограничение 96 MiB относится к загружаемому файлу отдельно от длительности: 30-минутные сжатые M4A/MP3 обычно проходят, а несжатый WAV может превысить лимит размера.
Слова собираются в короткие кандидаты по концу предложения, паузе от 650 мс или
жёсткому пределу 12 секунд. Поле timing_estimated показывает, были ли границы
реплик рассчитаны приблизительно.
На загрузку файла отводится до пяти минут; при превышении этого времени сервер
возвращает 408. При большом числе одновременных запросов возможен ответ 429.
Ответ анализа¶
{
"source_sha256": "7a63...e91c",
"duration_ms": 18420,
"timing_estimated": false,
"channel_mode": "mono",
"channel_count": 1,
"source_channel_count": 2,
"downmixed_to_mono": true,
"analysis_token": "<SIGNED_ANALYSIS_TOKEN>",
"analysis_expires_in_seconds": 900,
"speakers": [
{
"speaker": 1,
"utterance_count": 3,
"reference_duration_ms": 9340,
"clone_available": true
}
],
"utterances": [
{
"id": "phrase-1-1-520-2410",
"speaker": 1,
"start_ms": 520,
"end_ms": 2410,
"duration_ms": 1890,
"text": "Встречу перенесли на вторник.",
"max_replacement_characters": 53,
"replaceable": true,
"reason": null
}
],
"limits": {
"min_phrase_duration_ms": 350,
"max_phrase_duration_ms": 12000,
"max_replacement_characters": 240,
"max_crossfade_ms": 120,
"max_source_channels": 2,
"max_source_duration_ms": 1800000,
"output_format": "wav"
},
"privacy": {
"source_persisted": false,
"voice_clone_persisted": false,
"upload_may_use_temporary_storage": true,
"temporary_upload_lifetime": "request",
"client_must_resubmit_source": true
}
}
utterances[].replaceable показывает, можно ли выбрать реплику для рендера.
Причина отказа находится в reason. Реплика доступна для замены, если её
длительность составляет от 350 мс до 12 секунд, а суммарно у этого спикера найдено
не менее 3 секунд речи без заметного перекрытия с другими голосами для voice clone.
channel_mode равен mono, а channel_count — 1: это параметры нормализованного
аудио, используемого для анализа и рендера, даже если исходный файл был stereo.
source_channel_count сообщает исходное число каналов (1 или 2). Реплики
привязаны к найденным спикерам, а не к физическим каналам исходника.
downmixed_to_mono равен true только для исходного stereo-файла.
utterances[].max_replacement_characters — точный лимит нового текста для конкретной
реплики после удаления пробелов по краям. Он вычисляется как
min(240, max(12, ceil(duration_ms × 28 / 1000))), включается в подписанный
analysis_token и повторно проверяется при рендере. Поэтому клиенту нужно брать
лимит именно из выбранной реплики. limits.max_replacement_characters равен 240
и задаёт только абсолютный предел API для любого кандидата.
speakers[].reference_duration_ms — суммарная длительность чистых распознанных
реплик спикера без заметного перекрытия, а clone_available показывает выполнение
минимального порога. При самом рендере сервер собирает эфемерный референс целевой
длительностью около 12 секунд и не более 19 секунд.
Рендер замены¶
POST /api/tts/v1/audio-edit/render
Authorization: Api-Key <API_KEY>
Content-Type: multipart/form-data
Поля multipart-формы¶
| Поле | Тип | Обязательное | По умолчанию | Описание |
|---|---|---|---|---|
audio |
file | да | — | Тот же исходный файл, который был передан в /analyze |
analysis_token |
string | да | — | Подписанный токен из ответа анализа |
target_id |
string | да | — | id одной реплики с replaceable: true |
replacement_text |
string | да | — | Новый текст после удаления пробелов по краям: от 1 до utterances[].max_replacement_characters выбранной реплики и в любом случае не более 240 символов |
crossfade_ms |
integer | нет | 45 |
Длительность склейки, от 0 до 120 мс; для короткого фрагмента сервер дополнительно уменьшит её |
confirm_voice_rights |
boolean | да по смыслу | false |
Должно быть true |
За один запрос можно заменить только один сформированный сервером короткий кандидат,
выбранный по target_id. Произвольные клиентские таймкоды API не принимает: границы
кандидата основаны на подписанных таймкодах слов и границах реплики спикера.
Референс голоса, подгонка громкости и склейка выполняются в нормализованной
mono-дорожке.
TTS-разметка в replacement_text не поддерживается: запрещены любые угловые скобки
< / >, служебные токены и ударение в форме +гласная. Если
синтезированная фраза заметно длиннее исходной, сервер вернёт ошибку и предложит
сократить текст. Более короткая речь умеренно замедляется, а оставшееся место
заполняется тишиной; громкость синтеза подгоняется под исходную реплику.
Ответ рендера¶
При успехе сервер возвращает бинарный WAV:
HTTP/1.1 200 OK
Content-Type: audio/wav
Content-Disposition: attachment; filename="audio-with-replacement.wav"
Cache-Control: no-store
X-Audio-Edit-Target-Duration-Ms: 1890
X-Audio-Edit-Synthesized-Duration-Ms: 1760
X-Audio-Edit-Tempo-Ratio: 0.9312
X-Audio-Edit-Reference-Duration-Ms: 9340
X-Audio-Edit-Channel-Count: 1
| Заголовок | Значение |
|---|---|
X-Audio-Edit-Target-Duration-Ms |
Длительность заменённой исходной реплики |
X-Audio-Edit-Synthesized-Duration-Ms |
Длительность TTS до подгонки |
X-Audio-Edit-Tempo-Ratio |
Коэффициент tempo-фильтра: больше 1 ускоряет, меньше 1 замедляет синтез |
X-Audio-Edit-Reference-Duration-Ms |
Длительность референса, использованного для клонирования |
X-Audio-Edit-Channel-Count |
Количество каналов в итоговом WAV; всегда 1 |
Независимо от формата исходника результат имеет формат mono WAV. Сервер подгоняет новую реплику под исходное окно и сохраняет частоту дискретизации, общую длительность и последующие таймкоды записи. Stereo-исходник в итоговом файле уже сведён в mono.
Пример полного процесса с cURL¶
В примере используются только placeholders. Не сохраняйте настоящий API-ключ в репозитории или shell history.
1. Получить реплики и токен¶
API_BASE="https://api.speech.example.com"
API_KEY="<API_KEY>"
SOURCE_FILE="./dialog.wav"
curl --fail-with-body -X POST "$API_BASE/api/tts/v1/audio-edit/analyze" \
-H "Authorization: Api-Key $API_KEY" \
--form "audio=@$SOURCE_FILE" \
--form-string "lang=ru-RU" \
--form-string "max_speakers=4" \
--form-string "confirm_voice_rights=true" \
--output analysis.json
Посмотреть доступные реплики:
jq '.utterances[] | {id, speaker, start_ms, end_ms, text, max_replacement_characters, replaceable, reason}' analysis.json
2. Заменить выбранную реплику¶
ANALYSIS_TOKEN="$(jq -r '.analysis_token' analysis.json)"
TARGET_ID="phrase-1-1-520-2410"
curl --fail-with-body -X POST "$API_BASE/api/tts/v1/audio-edit/render" \
-H "Authorization: Api-Key $API_KEY" \
--form "audio=@$SOURCE_FILE" \
--form-string "analysis_token=$ANALYSIS_TOKEN" \
--form-string "target_id=$TARGET_ID" \
--form-string "replacement_text=Встречу перенесли на среду." \
--form-string "crossfade_ms=45" \
--form-string "confirm_voice_rights=true" \
--dump-header render-headers.txt \
--output audio-with-replacement.wav
Биллинг¶
Этапы учитываются отдельно. /analyze тарифицируется по длительности всей записи
после успешного распознавания, включая stereo после сведения в mono. Если
распознавание уже завершено, последующая ошибка формирования ответа не отменяет
его стоимость.
Для /render стоимость рассчитывается по фактической длительности
сгенерированной речи. Ошибка до завершения STT или TTS не списывает стоимость
этого этапа; ошибка при последующей склейке не отменяет уже выполненный синтез.
Повторный анализ после истечения токена является новым STT-запросом. Повторный рендер также является новым TTS-запросом. Актуальные тарифы и остаток средств показываются в кабинете.
Ограничения качества¶
Voice clone и склейка лучше всего работают на чистой записи одного голоса без фоновой музыки и сильной реверберации. Учитывайте следующие ограничения:
- реплика с заметным перекрытием голосов блокируется; короткое перекрытие, которое не обнаружила диаризация, всё ещё может ухудшить клонирование;
- музыка, постоянный шум, эхо и компрессия исходника становятся заметны на границе чистого TTS-фрагмента;
- очень короткий или эмоционально неоднородный референс хуже передаёт тембр и манеру речи;
- значительно более длинный новый текст требует неестественного ускорения и может быть отклонён;
- при stereo-to-mono downmix сигналы складываются с одинаковым весом. Сильные различия фаз могут ослабить голос, а шум или музыка из любого канала попадут в итоговую mono-дорожку и могут ухудшить распознавание и voice clone;
- API заменяет один короткий word-aligned кандидат и поддерживает одну замену за рендер.
Для лучшего результата выбирайте реплику с паузами по краям, оставляйте новый текст близким по длине к исходному и обеспечьте спикеру хотя бы 3–10 секунд чистой речи в других частях записи.
Ошибки¶
| HTTP | Когда возвращается |
|---|---|
400 |
Не подтверждены права на использование голоса |
401 / 403 |
Нет действующей авторизации или доступа к вычислительному API |
402 |
До запуска STT/TTS недостаточно кредитов для атомарного резерва |
408 |
Клиент не успел загрузить тело audio-edit запроса за пять минут |
413 |
Файл превышает 96 MiB или общий лимит загрузки API |
429 |
Слишком много одновременных запросов Audio Edit |
422 |
Файл пустой/не декодируется, запись длиннее 30 минут, содержит больше двух каналов, имеет частоту выше 48 кГц или в ней не найдена речь с достоверными таймкодами; также сюда относятся неверные параметры, токен/файл/целевая реплика и текст, который нельзя естественно подогнать |
502 |
Сервис распознавания или синтеза временно недоступен либо вернул некорректный ответ |
503 |
Сервис обработки аудио или проверки токена временно недоступен |
500 |
Непредвиденная ошибка анализа или монтажа |
Текст причины возвращается в стандартном поле detail, например: